Bug Summary

File:root/firefox-clang/obj-x86_64-pc-linux-gnu/third_party/libwebrtc/call/rtp_receiver_gn/./../../../../../third_party/libwebrtc/call/rtp_demuxer.cc
Warning:line 355, column 5
Value stored to 'has_rsid' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -O2 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name Unified_cpp_rtp_receiver_gn0.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/third_party/libwebrtc/call/rtp_receiver_gn -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/third_party/libwebrtc/call/rtp_receiver_gn -resource-dir /usr/lib/llvm-23/lib/clang/23 -include /root/firefox-clang/config/gcc_hidden.h -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -D _GLIBCXX_ASSERTIONS=1 -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D ABSL_ALLOCATOR_NOTHROW=1 -D PROTOBUF_ENABLE_DEBUG_LOGGING_MAY_LEAK_PII=0 -D RTC_DAV1D_IN_INTERNAL_DECODER_FACTORY -D RTC_ENABLE_VP9 -D WEBRTC_DEPRECATE_PLAN_B -D WEBRTC_ENABLE_PROTOBUF=0 -D WEBRTC_ENCODER_PSNR_STATS -D WEBRTC_LIBRARY_IMPL -D WEBRTC_MOZILLA_BUILD -D WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS=0 -D WEBRTC_STRICT_FIELD_TRIALS=0 -D WEBRTC_WITHOUT_RUST -D DYNAMIC_ANNOTATIONS_ENABLED=1 -D USE_AURA=1 -D USE_GLIB=1 -D USE_OZONE=1 -D USE_UDEV -D WEBRTC_LINUX -D WEBRTC_POSIX -D _FILE_OFFSET_BITS=64 -D _LARGEFILE64_SOURCE -D _LARGEFILE_SOURCE -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D WEBRTC_ENABLE_AVX2 -D _DEBUG -D _GNU_SOURCE -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D MOZ_SUPPORT_LEAKCHECKING -D STATIC_EXPORTABLE_JS_API -I /root/firefox-clang/third_party/libwebrtc/call/rtp_receiver_gn -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/third_party/libwebrtc/call/rtp_receiver_gn -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/libwebrtc_overrides -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/ipc/ipdl/_ipdlheaders -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/third_party/libwebrtc/gen -I /root/firefox-clang/ipc/chromium/src -I /root/firefox-clang/third_party/abseil-cpp -I /root/firefox-clang/third_party/libwebrtc -I /root/firefox-clang/tools/profiler/public -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include -D MOZILLA_CLIENT -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/x86_64-linux-gnu/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16/backward -internal-isystem /usr/lib/llvm-23/lib/clang/23/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-error=pessimizing-move -Wno-error=large-by-value-copy=128 -Wno-error=implicit-int-float-conversion -Wno-error=thread-safety-analysis -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -Wno-character-conversion -std=gnu++20 -fdeprecated-macro -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fno-implicit-modules -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -fdiagnostics-absolute-paths -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -mllvm -dwarf-linkage-names=Abstract -faddrsig -fdwarf2-cfi-asm -o /tmp/scan-build-2026-10-17-231001-351276-1 -x c++ Unified_cpp_rtp_receiver_gn0.cpp
1/*
2 * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "call/rtp_demuxer.h"
12
13#include <cstddef>
14#include <cstdint>
15#include <iterator>
16#include <string>
17#include <utility>
18
19#include "absl/base/nullability.h"
20#include "absl/strings/string_view.h"
21#include "call/rtp_packet_sink_interface.h"
22#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
23#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
24#include "modules/rtp_rtcp/source/rtp_packet_received.h"
25#include "rtc_base/checks.h"
26#include "rtc_base/containers/flat_set.h"
27#include "rtc_base/logging.h"
28#include "rtc_base/strings/string_builder.h"
29
30namespace webrtc {
31namespace {
32
33template <typename Container, typename Value>
34size_t RemoveFromMultimapByValue(Container* multimap, const Value& value) {
35 size_t count = 0;
36 for (auto it = multimap->begin(); it != multimap->end();) {
37 if (it->second == value) {
38 it = multimap->erase(it);
39 ++count;
40 } else {
41 ++it;
42 }
43 }
44 return count;
45}
46
47template <typename Map, typename Value>
48size_t RemoveFromMapByValue(Map* map, const Value& value) {
49 return EraseIf(*map, [&](const auto& elem) { return elem.second == value; });
50}
51
52} // namespace
53
54RtpDemuxerCriteria::RtpDemuxerCriteria(
55 absl::string_view mid,
56 absl::string_view rsid /*= absl::string_view()*/)
57 : mid_(mid), rsid_(rsid) {
58}
59
60RtpDemuxerCriteria::RtpDemuxerCriteria() = default;
61
62RtpDemuxerCriteria::RtpDemuxerCriteria(bool match_any)
63 : match_any_(match_any) {}
64
65RtpDemuxerCriteria::~RtpDemuxerCriteria() = default;
66
67std::string RtpDemuxerCriteria::ToString() const {
68 if (match_any_) {
69 return "{any}";
70 }
71 StringBuilder sb;
72 sb << "{mid: " << (mid_.empty() ? "<empty>" : mid_)
73 << ", rsid: " << (rsid_.empty() ? "<empty>" : rsid_) << ", ssrcs: [";
74
75 for (auto ssrc : ssrcs_) {
76 sb << ssrc << ", ";
77 }
78
79 sb << "], payload_types = [";
80
81 for (auto pt : payload_types_) {
82 sb << pt << ", ";
83 }
84
85 sb << "]}";
86 return sb.Release();
87}
88
89bool RtpDemuxerCriteria::IsValid() const {
90 if (!match_any() && payload_types().empty() && ssrcs().empty() &&
91 mid().empty() && rsid().empty()) {
92 // Criteria is not valid because can't match anything.
93 return false;
94 }
95 if (mid().size() > BaseRtpStringExtension::kMaxValueSizeBytes ||
96 rsid().size() > BaseRtpStringExtension::kMaxValueSizeBytes) {
97 return false;
98 }
99
100 if (!mid().empty() && !IsLegalMidName(mid())) {
101 return false;
102 }
103 if (!rsid().empty() && !IsLegalRsidName(rsid())) {
104 return false;
105 }
106
107 return true;
108}
109
110// static
111std::string RtpDemuxer::DescribePacket(const RtpPacketReceived& packet) {
112 StringBuilder sb;
113 sb << "PT=" << packet.PayloadType() << " SSRC=" << packet.Ssrc();
114 std::string mid;
115 if (packet.GetExtension<RtpMid>(&mid)) {
116 sb << " MID=" << mid;
117 }
118 std::string rsid;
119 if (packet.GetExtension<RtpStreamId>(&rsid)) {
120 sb << " RSID=" << rsid;
121 }
122 std::string rrsid;
123 if (packet.GetExtension<RepairedRtpStreamId>(&rrsid)) {
124 sb << " RRSID=" << rrsid;
125 }
126 return sb.Release();
127}
128
129RtpDemuxer::RtpDemuxer(bool use_mid /* = true*/) : use_mid_(use_mid) {}
130
131RtpDemuxer::~RtpDemuxer() {
132 RTC_DCHECK(sink_by_mid_.empty())(sink_by_mid_.empty()) ? static_cast<void>(0) : ::webrtc
::webrtc_checks_impl::FatalLogCall<false>( "./../../../../../third_party/libwebrtc/call/rtp_demuxer.cc"
, 132, "sink_by_mid_.empty()") & ::webrtc::webrtc_checks_impl
::LogStreamer<>()
;
133 RTC_DCHECK(sink_by_ssrc_.empty())(sink_by_ssrc_.empty()) ? static_cast<void>(0) : ::webrtc
::webrtc_checks_impl::FatalLogCall<false>( "./../../../../../third_party/libwebrtc/call/rtp_demuxer.cc"
, 133, "sink_by_ssrc_.empty()") & ::webrtc::webrtc_checks_impl
::LogStreamer<>()
;
134 RTC_DCHECK(sinks_by_pt_.empty())(sinks_by_pt_.empty()) ? static_cast<void>(0) : ::webrtc
::webrtc_checks_impl::FatalLogCall<false>( "./../../../../../third_party/libwebrtc/call/rtp_demuxer.cc"
, 134, "sinks_by_pt_.empty()") & ::webrtc::webrtc_checks_impl
::LogStreamer<>()
;
135 RTC_DCHECK(sink_by_mid_and_rsid_.empty())(sink_by_mid_and_rsid_.empty()) ? static_cast<void>(0) :
::webrtc::webrtc_checks_impl::FatalLogCall<false>( "./../../../../../third_party/libwebrtc/call/rtp_demuxer.cc"
, 135, "sink_by_mid_and_rsid_.empty()") & ::webrtc::webrtc_checks_impl
::LogStreamer<>()
;
136 RTC_DCHECK(sink_by_rsid_.empty())(sink_by_rsid_.empty()) ? static_cast<void>(0) : ::webrtc
::webrtc_checks_impl::FatalLogCall<false>( "./../../../../../third_party/libwebrtc/call/rtp_demuxer.cc"
, 136, "sink_by_rsid_.empty()") & ::webrtc::webrtc_checks_impl
::LogStreamer<>()
;
137}
138
139bool RtpDemuxer::IsEmpty() const {
140 return sink_by_mid_.empty() && sink_by_ssrc_.empty() &&
141 sinks_by_pt_.empty() && sink_by_mid_and_rsid_.empty() &&
142 sink_by_rsid_.empty() && match_any_sink_ == nullptr;
143}
144
145bool RtpDemuxer::AddSink(const RtpDemuxerCriteria& criteria,
146 RtpPacketSinkInterface* absl_nonnull sink) {
147 RTC_DCHECK(sink != nullptr)(sink != nullptr) ? static_cast<void>(0) : ::webrtc::webrtc_checks_impl
::FatalLogCall<false>( "./../../../../../third_party/libwebrtc/call/rtp_demuxer.cc"
, 147, "sink != nullptr") & ::webrtc::webrtc_checks_impl::
LogStreamer<>()
;
148
149 if (!criteria.IsValid()) {
150 RTC_LOG(LS_ERROR)!::webrtc::LogMessage::IsNoop<::webrtc::LS_ERROR>() &&
::webrtc::webrtc_logging_impl::LogCall() & ::webrtc::webrtc_logging_impl
::LogStreamer<>() << ::webrtc::webrtc_logging_impl
::LogMetadata("./../../../../../third_party/libwebrtc/call/rtp_demuxer.cc"
, 150, ::webrtc::LS_ERROR)
<< "Unable to add sink=" << sink
151 << " due to invalid criteria " << criteria;
152 return false;
153 }
154
155 // We return false instead of DCHECKing for logical conflicts with the new
156 // criteria because new sinks are created according to user-specified SDP and
157 // we do not want to crash due to a data validation error.
158 if (CriteriaWouldConflict(criteria)) {
159 RTC_LOG(LS_ERROR)!::webrtc::LogMessage::IsNoop<::webrtc::LS_ERROR>() &&
::webrtc::webrtc_logging_impl::LogCall() & ::webrtc::webrtc_logging_impl
::LogStreamer<>() << ::webrtc::webrtc_logging_impl
::LogMetadata("./../../../../../third_party/libwebrtc/call/rtp_demuxer.cc"
, 159, ::webrtc::LS_ERROR)
<< "Unable to add sink=" << sink
160 << " due to conflicting criteria " << criteria;
161 return false;
162 }
163
164 if (criteria.match_any()) {
165 match_any_sink_ = sink;
166 }
167
168 if (!criteria.mid().empty()) {
169 if (criteria.rsid().empty()) {
170 sink_by_mid_.emplace(criteria.mid(), sink);
171 } else {
172 sink_by_mid_and_rsid_.emplace(
173 std::make_pair(criteria.mid(), criteria.rsid()), sink);
174 }
175 } else {
176 if (!criteria.rsid().empty()) {
177 sink_by_rsid_.emplace(criteria.rsid(), sink);
178 }
179 }
180
181 for (uint32_t ssrc : criteria.ssrcs()) {
182 auto result = sink_by_ssrc_.emplace(ssrc, sink);
183 if (!result.second) {
184 if (signaled_ssrcs_.find(ssrc) == signaled_ssrcs_.end()) {
185 result.first->second = sink;
186 }
187 }
188 signaled_ssrcs_.insert(ssrc);
189 }
190
191 for (uint8_t payload_type : criteria.payload_types()) {
192 sinks_by_pt_.emplace(payload_type, sink);
193 }
194
195 RefreshKnownMids();
196
197 RTC_DLOG(LS_INFO)!::webrtc::LogMessage::IsNoop<::webrtc::LS_INFO>() &&
::webrtc::webrtc_logging_impl::LogCall() & ::webrtc::webrtc_logging_impl
::LogStreamer<>() << ::webrtc::webrtc_logging_impl
::LogMetadata("./../../../../../third_party/libwebrtc/call/rtp_demuxer.cc"
, 197, ::webrtc::LS_INFO)
<< "Added sink = " << sink << " for criteria " << criteria;
198
199 return true;
200}
201
202bool RtpDemuxer::CriteriaWouldConflict(
203 const RtpDemuxerCriteria& criteria) const {
204 if (match_any_sink_) {
205 // If we already have a sink matching all packets, any new criteria would
206 // conflict.
207 return true;
208 }
209
210 if (criteria.match_any()) {
211 // A match_all criteria conflicts if and only if we have another sink
212 // already registered.
213 return !IsEmpty();
214 }
215
216 if (!criteria.mid().empty()) {
217 if (criteria.rsid().empty()) {
218 // If the MID is in the known_mids_ set, then there is already a sink
219 // added for this MID directly, or there is a sink already added with a
220 // MID, RSID pair for our MID and some RSID.
221 // Adding this criteria would cause one of these rules to be shadowed, so
222 // reject this new criteria.
223 if (known_mids_.find(criteria.mid()) != known_mids_.end()) {
224 RTC_LOG(LS_INFO)!::webrtc::LogMessage::IsNoop<::webrtc::LS_INFO>() &&
::webrtc::webrtc_logging_impl::LogCall() & ::webrtc::webrtc_logging_impl
::LogStreamer<>() << ::webrtc::webrtc_logging_impl
::LogMetadata("./../../../../../third_party/libwebrtc/call/rtp_demuxer.cc"
, 224, ::webrtc::LS_INFO)
<< criteria << " would conflict with known mid";
225 return true;
226 }
227 } else {
228 // If the exact rule already exists, then reject this duplicate.
229 const auto sink_by_mid_and_rsid = sink_by_mid_and_rsid_.find(
230 std::make_pair(criteria.mid(), criteria.rsid()));
231 if (sink_by_mid_and_rsid != sink_by_mid_and_rsid_.end()) {
232 RTC_LOG(LS_INFO)!::webrtc::LogMessage::IsNoop<::webrtc::LS_INFO>() &&
::webrtc::webrtc_logging_impl::LogCall() & ::webrtc::webrtc_logging_impl
::LogStreamer<>() << ::webrtc::webrtc_logging_impl
::LogMetadata("./../../../../../third_party/libwebrtc/call/rtp_demuxer.cc"
, 232, ::webrtc::LS_INFO)
<< criteria << " would conflict with existing sink = "
233 << sink_by_mid_and_rsid->second
234 << " by mid+rsid binding";
235 return true;
236 }
237 // If there is already a sink registered for the bare MID, then this
238 // criteria will never receive any packets because they will just be
239 // directed to that MID sink, so reject this new criteria.
240 const auto sink_by_mid = sink_by_mid_.find(criteria.mid());
241 if (sink_by_mid != sink_by_mid_.end()) {
242 RTC_LOG(LS_INFO)!::webrtc::LogMessage::IsNoop<::webrtc::LS_INFO>() &&
::webrtc::webrtc_logging_impl::LogCall() & ::webrtc::webrtc_logging_impl
::LogStreamer<>() << ::webrtc::webrtc_logging_impl
::LogMetadata("./../../../../../third_party/libwebrtc/call/rtp_demuxer.cc"
, 242, ::webrtc::LS_INFO)
<< criteria << " would conflict with existing sink = "
243 << sink_by_mid->second << " by mid binding";
244 return true;
245 }
246 }
247 }
248
249 for (uint32_t ssrc : criteria.ssrcs()) {
250 const auto sink_by_ssrc = sink_by_ssrc_.find(ssrc);
251 if (sink_by_ssrc != sink_by_ssrc_.end()) {
252 if (signaled_ssrcs_.find(ssrc) != signaled_ssrcs_.end()) {
253 RTC_LOG(LS_INFO)!::webrtc::LogMessage::IsNoop<::webrtc::LS_INFO>() &&
::webrtc::webrtc_logging_impl::LogCall() & ::webrtc::webrtc_logging_impl
::LogStreamer<>() << ::webrtc::webrtc_logging_impl
::LogMetadata("./../../../../../third_party/libwebrtc/call/rtp_demuxer.cc"
, 253, ::webrtc::LS_INFO)
<< criteria << " would conflict with existing sink = "
254 << sink_by_ssrc->second << " binding by SSRC=" << ssrc;
255 return true;
256 }
257 }
258 }
259
260 // TODO(steveanton): May also sanity check payload types.
261
262 return false;
263}
264
265void RtpDemuxer::RefreshKnownMids() {
266 known_mids_.clear();
267
268 for (auto const& item : sink_by_mid_) {
269 const std::string& mid = item.first;
270 known_mids_.insert(mid);
271 }
272
273 for (auto const& item : sink_by_mid_and_rsid_) {
274 const std::string& mid = item.first.first;
275 known_mids_.insert(mid);
276 }
277}
278
279bool RtpDemuxer::AddSink(uint32_t ssrc,
280 RtpPacketSinkInterface* absl_nonnull sink) {
281 RtpDemuxerCriteria criteria;
282 criteria.ssrcs().insert(ssrc);
283 return AddSink(criteria, sink);
284}
285
286void RtpDemuxer::AddSink(absl::string_view rsid,
287 RtpPacketSinkInterface* absl_nonnull sink) {
288 RtpDemuxerCriteria criteria(absl::string_view() /* mid */, rsid);
289 AddSink(criteria, sink);
290}
291
292void RtpDemuxer::RemoveAllSinks() {
293 sink_by_mid_.clear();
294 sink_by_ssrc_.clear();
295 sinks_by_pt_.clear();
296 sink_by_mid_and_rsid_.clear();
297 sink_by_rsid_.clear();
298 signaled_ssrcs_.clear();
299 known_mids_.clear();
300 match_any_sink_ = nullptr;
301 mid_by_ssrc_.clear();
302 rsid_by_ssrc_.clear();
303}
304
305bool RtpDemuxer::RemoveSink(const RtpPacketSinkInterface* absl_nonnull sink) {
306 RTC_DCHECK(sink)(sink) ? static_cast<void>(0) : ::webrtc::webrtc_checks_impl
::FatalLogCall<false>( "./../../../../../third_party/libwebrtc/call/rtp_demuxer.cc"
, 306, "sink") & ::webrtc::webrtc_checks_impl::LogStreamer
<>()
;
307 flat_set<uint32_t> ssrcs = GetSsrcsForSink(sink);
308 for (uint32_t ssrc : ssrcs) {
309 signaled_ssrcs_.erase(ssrc);
310 }
311 size_t num_removed = RemoveFromMapByValue(&sink_by_mid_, sink) +
312 RemoveFromMapByValue(&sink_by_ssrc_, sink) +
313 RemoveFromMultimapByValue(&sinks_by_pt_, sink) +
314 RemoveFromMapByValue(&sink_by_mid_and_rsid_, sink) +
315 RemoveFromMapByValue(&sink_by_rsid_, sink);
316 RefreshKnownMids();
317 return num_removed > 0;
318}
319
320flat_set<uint32_t> RtpDemuxer::GetSsrcsForSink(
321 const RtpPacketSinkInterface* absl_nonnull sink) const {
322 flat_set<uint32_t> ssrcs;
323 for (const auto& [ssrc, stored_sink] : sink_by_ssrc_) {
324 if (stored_sink == sink) {
325 ssrcs.insert(ssrc);
326 }
327 }
328 return ssrcs;
329}
330
331bool RtpDemuxer::OnRtpPacket(const RtpPacketReceived& packet) {
332 RtpPacketSinkInterface* sink = ResolveSink(packet);
333 if (sink != nullptr) {
334 sink->OnRtpPacket(packet);
335 return true;
336 }
337 return false;
338}
339
340RtpPacketSinkInterface* absl_nullable RtpDemuxer::ResolveSink(
341 const RtpPacketReceived& packet) {
342 if (match_any_sink_) {
343 return match_any_sink_;
344 }
345
346 // See the BUNDLE spec for high level reference to this algorithm:
347 // https://www.rfc-editor.org/rfc/rfc8843.html#name-associating-rtp-rtcp-stream
348
349 // RSID and RRID are routed to the same sinks. If an RSID is specified on a
350 // repair packet, it should be ignored and the RRID should be used.
351 std::string packet_mid, packet_rsid;
352 //bool has_mid = use_mid_ && packet.GetExtension<RtpMid>(&packet_mid);
353 bool has_rsid = packet.GetExtension<RepairedRtpStreamId>(&packet_rsid);
354 if (!has_rsid) {
355 has_rsid = packet.GetExtension<RtpStreamId>(&packet_rsid);
Value stored to 'has_rsid' is never read
356 }
357 uint32_t ssrc = packet.Ssrc();
358
359 // Mid support is half-baked in branch 64. RtpStreamReceiverController only
360 // supports adding sinks by ssrc, so our mids will never show up in
361 // known_mids_, causing us to drop packets here.
362#if 0
363 // The BUNDLE spec says to drop any packets with unknown MIDs, even if the
364 // SSRC is known/latched.
365 if (has_mid && known_mids_.find(packet_mid) == known_mids_.end()) {
366 return nullptr;
367 }
368
369 // Cache information we learn about SSRCs and IDs. We need to do this even if
370 // there isn't a rule/sink yet because we might add an MID/RSID rule after
371 // learning an MID/RSID<->SSRC association.
372
373 std::string* mid = nullptr;
374 if (has_mid) {
375 mid_by_ssrc_[ssrc] = packet_mid;
376 mid = &packet_mid;
377 } else {
378 // If the packet does not include a MID header extension, check if there is
379 // a latched MID for the SSRC.
380 const auto it = mid_by_ssrc_.find(ssrc);
381 if (it != mid_by_ssrc_.end()) {
382 mid = &it->second;
383 }
384 }
385
386 std::string* rsid = nullptr;
387 if (has_rsid) {
388 rsid_by_ssrc_[ssrc] = packet_rsid;
389 rsid = &packet_rsid;
390 } else {
391 // If the packet does not include an RRID/RSID header extension, check if
392 // there is a latched RSID for the SSRC.
393 const auto it = rsid_by_ssrc_.find(ssrc);
394 if (it != rsid_by_ssrc_.end()) {
395 rsid = &it->second;
396 }
397 }
398
399 // If MID and/or RSID is specified, prioritize that for demuxing the packet.
400 // The motivation behind the BUNDLE algorithm is that we trust these are used
401 // deliberately by senders and are more likely to be correct than SSRC/payload
402 // type which are included with every packet.
403 // TODO(steveanton): According to the BUNDLE spec, new SSRC mappings are only
404 // accepted if the packet's extended sequence number is
405 // greater than that of the last SSRC mapping update.
406 // https://tools.ietf.org/html/rfc7941#section-4.2.6
407 if (mid != nullptr) {
408 RtpPacketSinkInterface* sink_by_mid = ResolveSinkByMid(*mid, ssrc);
409 if (sink_by_mid != nullptr) {
410 return sink_by_mid;
411 }
412
413 // RSID is scoped to a given MID if both are included.
414 if (rsid != nullptr) {
415 RtpPacketSinkInterface* sink_by_mid_rsid =
416 ResolveSinkByMidRsid(*mid, *rsid, ssrc);
417 if (sink_by_mid_rsid != nullptr) {
418 return sink_by_mid_rsid;
419 }
420 }
421
422 // At this point, there is at least one sink added for this MID and an RSID
423 // but either the packet does not have an RSID or it is for a different
424 // RSID. This falls outside the BUNDLE spec so drop the packet.
425 return nullptr;
426 }
427
428 // RSID can be used without MID as long as they are unique.
429 if (rsid != nullptr) {
430 RtpPacketSinkInterface* sink_by_rsid = ResolveSinkByRsid(*rsid, ssrc);
431 if (sink_by_rsid != nullptr) {
432 return sink_by_rsid;
433 }
434 }
435
436#endif
437 // We trust signaled SSRC more than payload type which is likely to conflict
438 // between streams.
439 const auto ssrc_sink_it = sink_by_ssrc_.find(ssrc);
440 if (ssrc_sink_it != sink_by_ssrc_.end()) {
441 return ssrc_sink_it->second;
442 }
443
444 if (use_payload_type_demuxing_) {
445 // Legacy senders will only signal payload type.
446 // Support that as a last resort.
447 return ResolveSinkByPayloadType(packet.PayloadType(), ssrc);
448 }
449
450 return nullptr;
451}
452
453RtpPacketSinkInterface* absl_nullable RtpDemuxer::ResolveSinkByMid(
454 absl::string_view mid,
455 uint32_t ssrc) {
456 const auto it = sink_by_mid_.find(mid);
457 if (it != sink_by_mid_.end()) {
458 RtpPacketSinkInterface* sink = it->second;
459 AddSsrcSinkBinding(ssrc, sink);
460 return sink;
461 }
462 return nullptr;
463}
464
465RtpPacketSinkInterface* absl_nullable RtpDemuxer::ResolveSinkByMidRsid(
466 absl::string_view mid,
467 absl::string_view rsid,
468 uint32_t ssrc) {
469 const auto it = sink_by_mid_and_rsid_.find(
470 std::make_pair(std::string(mid), std::string(rsid)));
471 if (it != sink_by_mid_and_rsid_.end()) {
472 RtpPacketSinkInterface* sink = it->second;
473 AddSsrcSinkBinding(ssrc, sink);
474 return sink;
475 }
476 return nullptr;
477}
478
479RtpPacketSinkInterface* absl_nullable RtpDemuxer::ResolveSinkByRsid(
480 absl::string_view rsid,
481 uint32_t ssrc) {
482 const auto it = sink_by_rsid_.find(rsid);
483 if (it != sink_by_rsid_.end()) {
484 RtpPacketSinkInterface* sink = it->second;
485 AddSsrcSinkBinding(ssrc, sink);
486 return sink;
487 }
488 return nullptr;
489}
490
491RtpPacketSinkInterface* absl_nullable RtpDemuxer::ResolveSinkByPayloadType(
492 uint8_t payload_type,
493 uint32_t ssrc) {
494 const auto range = sinks_by_pt_.equal_range(payload_type);
495 if (range.first != range.second) {
496 auto it = range.first;
497 const auto end = range.second;
498 if (std::next(it) == end) {
499 RtpPacketSinkInterface* sink = it->second;
500 AddSsrcSinkBinding(ssrc, sink);
501 return sink;
502 }
503 }
504 return nullptr;
505}
506
507void RtpDemuxer::AddSsrcSinkBinding(uint32_t ssrc,
508 RtpPacketSinkInterface* absl_nonnull sink) {
509 if (sink_by_ssrc_.size() >= kMaxSsrcBindings) {
510 RTC_LOG(LS_WARNING)!::webrtc::LogMessage::IsNoop<::webrtc::LS_WARNING>() &&
::webrtc::webrtc_logging_impl::LogCall() & ::webrtc::webrtc_logging_impl
::LogStreamer<>() << ::webrtc::webrtc_logging_impl
::LogMetadata("./../../../../../third_party/libwebrtc/call/rtp_demuxer.cc"
, 510, ::webrtc::LS_WARNING)
<< "New SSRC=" << ssrc
511 << " sink binding ignored; limit of" << kMaxSsrcBindings
512 << " bindings has been reached.";
513 return;
514 }
515
516 auto result = sink_by_ssrc_.emplace(ssrc, sink);
517 auto it = result.first;
518 bool inserted = result.second;
519 if (inserted) {
520 RTC_DLOG(LS_INFO)!::webrtc::LogMessage::IsNoop<::webrtc::LS_INFO>() &&
::webrtc::webrtc_logging_impl::LogCall() & ::webrtc::webrtc_logging_impl
::LogStreamer<>() << ::webrtc::webrtc_logging_impl
::LogMetadata("./../../../../../third_party/libwebrtc/call/rtp_demuxer.cc"
, 520, ::webrtc::LS_INFO)
<< "Added sink = " << sink
521 << " binding with SSRC=" << ssrc;
522 } else if (it->second != sink) {
523 RTC_DLOG(LS_INFO)!::webrtc::LogMessage::IsNoop<::webrtc::LS_INFO>() &&
::webrtc::webrtc_logging_impl::LogCall() & ::webrtc::webrtc_logging_impl
::LogStreamer<>() << ::webrtc::webrtc_logging_impl
::LogMetadata("./../../../../../third_party/libwebrtc/call/rtp_demuxer.cc"
, 523, ::webrtc::LS_INFO)
<< "Updated sink = " << sink
524 << " binding with SSRC=" << ssrc;
525 it->second = sink;
526 }
527}
528
529} // namespace webrtc