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 348, 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 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-09-01-224014-2642839-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/strings/string_view.h"
20#include "call/rtp_packet_sink_interface.h"
21#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
22#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
23#include "modules/rtp_rtcp/source/rtp_packet_received.h"
24#include "rtc_base/checks.h"
25#include "rtc_base/containers/flat_set.h"
26#include "rtc_base/logging.h"
27#include "rtc_base/strings/string_builder.h"
28
29namespace webrtc {
30namespace {
31
32template <typename Container, typename Value>
33size_t RemoveFromMultimapByValue(Container* multimap, const Value& value) {
34 size_t count = 0;
35 for (auto it = multimap->begin(); it != multimap->end();) {
36 if (it->second == value) {
37 it = multimap->erase(it);
38 ++count;
39 } else {
40 ++it;
41 }
42 }
43 return count;
44}
45
46template <typename Map, typename Value>
47size_t RemoveFromMapByValue(Map* map, const Value& value) {
48 return EraseIf(*map, [&](const auto& elem) { return elem.second == value; });
49}
50
51} // namespace
52
53RtpDemuxerCriteria::RtpDemuxerCriteria(
54 absl::string_view mid,
55 absl::string_view rsid /*= absl::string_view()*/)
56 : mid_(mid), rsid_(rsid) {
57 RTC_DCHECK(mid.length() <= BaseRtpStringExtension::kMaxValueSizeBytes)(mid.length() <= BaseRtpStringExtension::kMaxValueSizeBytes
) ? static_cast<void>(0) : ::webrtc::webrtc_checks_impl
::FatalLogCall<false>( "./../../../../../third_party/libwebrtc/call/rtp_demuxer.cc"
, 57, "mid.length() <= BaseRtpStringExtension::kMaxValueSizeBytes"
) & ::webrtc::webrtc_checks_impl::LogStreamer<>()
;
58}
59
60RtpDemuxerCriteria::RtpDemuxerCriteria() = default;
61
62RtpDemuxerCriteria::RtpDemuxerCriteria(bool match_any)
63 : match_any_(match_any) {}
64
65RtpDemuxerCriteria::~RtpDemuxerCriteria() = default;
66
67bool RtpDemuxerCriteria::operator==(const RtpDemuxerCriteria& other) const {
68 return match_any_ == other.match_any_ && mid_ == other.mid_ &&
69 rsid_ == other.rsid_ && ssrcs_ == other.ssrcs_ &&
70 payload_types_ == other.payload_types_;
71}
72
73bool RtpDemuxerCriteria::operator!=(const RtpDemuxerCriteria& other) const {
74 return !(*this == other);
75}
76
77std::string RtpDemuxerCriteria::ToString() const {
78 if (match_any_) {
79 return "{any}";
80 }
81 StringBuilder sb;
82 sb << "{mid: " << (mid_.empty() ? "<empty>" : mid_)
83 << ", rsid: " << (rsid_.empty() ? "<empty>" : rsid_) << ", ssrcs: [";
84
85 for (auto ssrc : ssrcs_) {
86 sb << ssrc << ", ";
87 }
88
89 sb << "], payload_types = [";
90
91 for (auto pt : payload_types_) {
92 sb << pt << ", ";
93 }
94
95 sb << "]}";
96 return sb.Release();
97}
98
99// static
100std::string RtpDemuxer::DescribePacket(const RtpPacketReceived& packet) {
101 StringBuilder sb;
102 sb << "PT=" << packet.PayloadType() << " SSRC=" << packet.Ssrc();
103 std::string mid;
104 if (packet.GetExtension<RtpMid>(&mid)) {
105 sb << " MID=" << mid;
106 }
107 std::string rsid;
108 if (packet.GetExtension<RtpStreamId>(&rsid)) {
109 sb << " RSID=" << rsid;
110 }
111 std::string rrsid;
112 if (packet.GetExtension<RepairedRtpStreamId>(&rrsid)) {
113 sb << " RRSID=" << rrsid;
114 }
115 return sb.Release();
116}
117
118RtpDemuxer::RtpDemuxer(bool use_mid /* = true*/) : use_mid_(use_mid) {}
119
120RtpDemuxer::~RtpDemuxer() {
121 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"
, 121, "sink_by_mid_.empty()") & ::webrtc::webrtc_checks_impl
::LogStreamer<>()
;
122 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"
, 122, "sink_by_ssrc_.empty()") & ::webrtc::webrtc_checks_impl
::LogStreamer<>()
;
123 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"
, 123, "sinks_by_pt_.empty()") & ::webrtc::webrtc_checks_impl
::LogStreamer<>()
;
124 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"
, 124, "sink_by_mid_and_rsid_.empty()") & ::webrtc::webrtc_checks_impl
::LogStreamer<>()
;
125 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"
, 125, "sink_by_rsid_.empty()") & ::webrtc::webrtc_checks_impl
::LogStreamer<>()
;
126}
127
128bool RtpDemuxer::IsEmpty() const {
129 return sink_by_mid_.empty() && sink_by_ssrc_.empty() &&
130 sinks_by_pt_.empty() && sink_by_mid_and_rsid_.empty() &&
131 sink_by_rsid_.empty() && match_any_sink_ == nullptr;
132}
133
134bool RtpDemuxer::AddSink(const RtpDemuxerCriteria& criteria,
135 RtpPacketSinkInterface* sink) {
136 RTC_DCHECK(criteria.match_any() || !criteria.payload_types().empty() ||(criteria.match_any() || !criteria.payload_types().empty() ||
!criteria.ssrcs().empty() || !criteria.mid().empty() || !criteria
.rsid().empty()) ? static_cast<void>(0) : ::webrtc::webrtc_checks_impl
::FatalLogCall<false>( "./../../../../../third_party/libwebrtc/call/rtp_demuxer.cc"
, 138, "criteria.match_any() || !criteria.payload_types().empty() || !criteria.ssrcs().empty() || !criteria.mid().empty() || !criteria.rsid().empty()"
) & ::webrtc::webrtc_checks_impl::LogStreamer<>()
137 !criteria.ssrcs().empty() || !criteria.mid().empty() ||(criteria.match_any() || !criteria.payload_types().empty() ||
!criteria.ssrcs().empty() || !criteria.mid().empty() || !criteria
.rsid().empty()) ? static_cast<void>(0) : ::webrtc::webrtc_checks_impl
::FatalLogCall<false>( "./../../../../../third_party/libwebrtc/call/rtp_demuxer.cc"
, 138, "criteria.match_any() || !criteria.payload_types().empty() || !criteria.ssrcs().empty() || !criteria.mid().empty() || !criteria.rsid().empty()"
) & ::webrtc::webrtc_checks_impl::LogStreamer<>()
138 !criteria.rsid().empty())(criteria.match_any() || !criteria.payload_types().empty() ||
!criteria.ssrcs().empty() || !criteria.mid().empty() || !criteria
.rsid().empty()) ? static_cast<void>(0) : ::webrtc::webrtc_checks_impl
::FatalLogCall<false>( "./../../../../../third_party/libwebrtc/call/rtp_demuxer.cc"
, 138, "criteria.match_any() || !criteria.payload_types().empty() || !criteria.ssrcs().empty() || !criteria.mid().empty() || !criteria.rsid().empty()"
) & ::webrtc::webrtc_checks_impl::LogStreamer<>()
;
139 RTC_DCHECK(criteria.mid().empty() || IsLegalMidName(criteria.mid()))(criteria.mid().empty() || IsLegalMidName(criteria.mid())) ? static_cast
<void>(0) : ::webrtc::webrtc_checks_impl::FatalLogCall<
false>( "./../../../../../third_party/libwebrtc/call/rtp_demuxer.cc"
, 139, "criteria.mid().empty() || IsLegalMidName(criteria.mid())"
) & ::webrtc::webrtc_checks_impl::LogStreamer<>()
;
140 RTC_DCHECK(criteria.rsid().empty() || IsLegalRsidName(criteria.rsid()))(criteria.rsid().empty() || IsLegalRsidName(criteria.rsid()))
? static_cast<void>(0) : ::webrtc::webrtc_checks_impl::
FatalLogCall<false>( "./../../../../../third_party/libwebrtc/call/rtp_demuxer.cc"
, 140, "criteria.rsid().empty() || IsLegalRsidName(criteria.rsid())"
) & ::webrtc::webrtc_checks_impl::LogStreamer<>()
;
141 RTC_DCHECK(sink)(sink) ? static_cast<void>(0) : ::webrtc::webrtc_checks_impl
::FatalLogCall<false>( "./../../../../../third_party/libwebrtc/call/rtp_demuxer.cc"
, 141, "sink") & ::webrtc::webrtc_checks_impl::LogStreamer
<>()
;
142
143 // We return false instead of DCHECKing for logical conflicts with the new
144 // criteria because new sinks are created according to user-specified SDP and
145 // we do not want to crash due to a data validation error.
146 if (CriteriaWouldConflict(criteria)) {
147 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"
, 147, ::webrtc::LS_ERROR)
<< "Unable to add sink=" << sink
148 << " due to conflicting criteria " << criteria.ToString();
149 return false;
150 }
151
152 if (criteria.match_any()) {
153 match_any_sink_ = sink;
154 }
155
156 if (!criteria.mid().empty()) {
157 if (criteria.rsid().empty()) {
158 sink_by_mid_.emplace(criteria.mid(), sink);
159 } else {
160 sink_by_mid_and_rsid_.emplace(
161 std::make_pair(criteria.mid(), criteria.rsid()), sink);
162 }
163 } else {
164 if (!criteria.rsid().empty()) {
165 sink_by_rsid_.emplace(criteria.rsid(), sink);
166 }
167 }
168
169 for (uint32_t ssrc : criteria.ssrcs()) {
170 auto result = sink_by_ssrc_.emplace(ssrc, sink);
171 if (!result.second) {
172 if (signaled_ssrcs_.find(ssrc) == signaled_ssrcs_.end()) {
173 result.first->second = sink;
174 }
175 }
176 signaled_ssrcs_.insert(ssrc);
177 }
178
179 for (uint8_t payload_type : criteria.payload_types()) {
180 sinks_by_pt_.emplace(payload_type, sink);
181 }
182
183 RefreshKnownMids();
184
185 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"
, 185, ::webrtc::LS_INFO)
<< "Added sink = " << sink << " for criteria "
186 << criteria.ToString();
187
188 return true;
189}
190
191bool RtpDemuxer::CriteriaWouldConflict(
192 const RtpDemuxerCriteria& criteria) const {
193 if (match_any_sink_) {
194 // If we already have a sink matching all packets, any new criteria would
195 // conflict.
196 return true;
197 }
198
199 if (criteria.match_any()) {
200 // A match_all criteria conflicts if and only if we have another sink
201 // already registered.
202 return !IsEmpty();
203 }
204
205 if (!criteria.mid().empty()) {
206 if (criteria.rsid().empty()) {
207 // If the MID is in the known_mids_ set, then there is already a sink
208 // added for this MID directly, or there is a sink already added with a
209 // MID, RSID pair for our MID and some RSID.
210 // Adding this criteria would cause one of these rules to be shadowed, so
211 // reject this new criteria.
212 if (known_mids_.find(criteria.mid()) != known_mids_.end()) {
213 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"
, 213, ::webrtc::LS_INFO)
<< criteria.ToString()
214 << " would conflict with known mid";
215 return true;
216 }
217 } else {
218 // If the exact rule already exists, then reject this duplicate.
219 const auto sink_by_mid_and_rsid = sink_by_mid_and_rsid_.find(
220 std::make_pair(criteria.mid(), criteria.rsid()));
221 if (sink_by_mid_and_rsid != sink_by_mid_and_rsid_.end()) {
222 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"
, 222, ::webrtc::LS_INFO)
<< criteria.ToString()
223 << " would conflict with existing sink = "
224 << sink_by_mid_and_rsid->second
225 << " by mid+rsid binding";
226 return true;
227 }
228 // If there is already a sink registered for the bare MID, then this
229 // criteria will never receive any packets because they will just be
230 // directed to that MID sink, so reject this new criteria.
231 const auto sink_by_mid = sink_by_mid_.find(criteria.mid());
232 if (sink_by_mid != sink_by_mid_.end()) {
233 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"
, 233, ::webrtc::LS_INFO)
<< criteria.ToString()
234 << " would conflict with existing sink = "
235 << sink_by_mid->second << " by mid binding";
236 return true;
237 }
238 }
239 }
240
241 for (uint32_t ssrc : criteria.ssrcs()) {
242 const auto sink_by_ssrc = sink_by_ssrc_.find(ssrc);
243 if (sink_by_ssrc != sink_by_ssrc_.end()) {
244 if (signaled_ssrcs_.find(ssrc) != signaled_ssrcs_.end()) {
245 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"
, 245, ::webrtc::LS_INFO)
<< criteria.ToString()
246 << " would conflict with existing sink = "
247 << sink_by_ssrc->second << " binding by SSRC=" << ssrc;
248 return true;
249 }
250 }
251 }
252
253 // TODO(steveanton): May also sanity check payload types.
254
255 return false;
256}
257
258void RtpDemuxer::RefreshKnownMids() {
259 known_mids_.clear();
260
261 for (auto const& item : sink_by_mid_) {
262 const std::string& mid = item.first;
263 known_mids_.insert(mid);
264 }
265
266 for (auto const& item : sink_by_mid_and_rsid_) {
267 const std::string& mid = item.first.first;
268 known_mids_.insert(mid);
269 }
270}
271
272bool RtpDemuxer::AddSink(uint32_t ssrc, RtpPacketSinkInterface* sink) {
273 RtpDemuxerCriteria criteria;
274 criteria.ssrcs().insert(ssrc);
275 return AddSink(criteria, sink);
276}
277
278void RtpDemuxer::AddSink(absl::string_view rsid, RtpPacketSinkInterface* sink) {
279 RtpDemuxerCriteria criteria(absl::string_view() /* mid */, rsid);
280 AddSink(criteria, sink);
281}
282
283void RtpDemuxer::RemoveAllSinks() {
284 sink_by_mid_.clear();
285 sink_by_ssrc_.clear();
286 sinks_by_pt_.clear();
287 sink_by_mid_and_rsid_.clear();
288 sink_by_rsid_.clear();
289 signaled_ssrcs_.clear();
290 known_mids_.clear();
291 match_any_sink_ = nullptr;
292 mid_by_ssrc_.clear();
293 rsid_by_ssrc_.clear();
294}
295
296bool RtpDemuxer::RemoveSink(const RtpPacketSinkInterface* sink) {
297 RTC_DCHECK(sink)(sink) ? static_cast<void>(0) : ::webrtc::webrtc_checks_impl
::FatalLogCall<false>( "./../../../../../third_party/libwebrtc/call/rtp_demuxer.cc"
, 297, "sink") & ::webrtc::webrtc_checks_impl::LogStreamer
<>()
;
298 flat_set<uint32_t> ssrcs = GetSsrcsForSink(sink);
299 for (uint32_t ssrc : ssrcs) {
300 signaled_ssrcs_.erase(ssrc);
301 }
302 size_t num_removed = RemoveFromMapByValue(&sink_by_mid_, sink) +
303 RemoveFromMapByValue(&sink_by_ssrc_, sink) +
304 RemoveFromMultimapByValue(&sinks_by_pt_, sink) +
305 RemoveFromMapByValue(&sink_by_mid_and_rsid_, sink) +
306 RemoveFromMapByValue(&sink_by_rsid_, sink);
307 RefreshKnownMids();
308 return num_removed > 0;
309}
310
311flat_set<uint32_t> RtpDemuxer::GetSsrcsForSink(
312 const RtpPacketSinkInterface* sink) const {
313 flat_set<uint32_t> ssrcs;
314 if (sink) {
315 for (const auto& it : sink_by_ssrc_) {
316 if (it.second == sink) {
317 ssrcs.insert(it.first);
318 }
319 }
320 }
321 return ssrcs;
322}
323
324bool RtpDemuxer::OnRtpPacket(const RtpPacketReceived& packet) {
325 RtpPacketSinkInterface* sink = ResolveSink(packet);
326 if (sink != nullptr) {
327 sink->OnRtpPacket(packet);
328 return true;
329 }
330 return false;
331}
332
333RtpPacketSinkInterface* RtpDemuxer::ResolveSink(
334 const RtpPacketReceived& packet) {
335 if (match_any_sink_) {
336 return match_any_sink_;
337 }
338
339 // See the BUNDLE spec for high level reference to this algorithm:
340 // https://www.rfc-editor.org/rfc/rfc8843.html#name-associating-rtp-rtcp-stream
341
342 // RSID and RRID are routed to the same sinks. If an RSID is specified on a
343 // repair packet, it should be ignored and the RRID should be used.
344 std::string packet_mid, packet_rsid;
345 //bool has_mid = use_mid_ && packet.GetExtension<RtpMid>(&packet_mid);
346 bool has_rsid = packet.GetExtension<RepairedRtpStreamId>(&packet_rsid);
347 if (!has_rsid) {
348 has_rsid = packet.GetExtension<RtpStreamId>(&packet_rsid);
Value stored to 'has_rsid' is never read
349 }
350 uint32_t ssrc = packet.Ssrc();
351
352 // Mid support is half-baked in branch 64. RtpStreamReceiverController only
353 // supports adding sinks by ssrc, so our mids will never show up in
354 // known_mids_, causing us to drop packets here.
355#if 0
356 // The BUNDLE spec says to drop any packets with unknown MIDs, even if the
357 // SSRC is known/latched.
358 if (has_mid && known_mids_.find(packet_mid) == known_mids_.end()) {
359 return nullptr;
360 }
361
362 // Cache information we learn about SSRCs and IDs. We need to do this even if
363 // there isn't a rule/sink yet because we might add an MID/RSID rule after
364 // learning an MID/RSID<->SSRC association.
365
366 std::string* mid = nullptr;
367 if (has_mid) {
368 mid_by_ssrc_[ssrc] = packet_mid;
369 mid = &packet_mid;
370 } else {
371 // If the packet does not include a MID header extension, check if there is
372 // a latched MID for the SSRC.
373 const auto it = mid_by_ssrc_.find(ssrc);
374 if (it != mid_by_ssrc_.end()) {
375 mid = &it->second;
376 }
377 }
378
379 std::string* rsid = nullptr;
380 if (has_rsid) {
381 rsid_by_ssrc_[ssrc] = packet_rsid;
382 rsid = &packet_rsid;
383 } else {
384 // If the packet does not include an RRID/RSID header extension, check if
385 // there is a latched RSID for the SSRC.
386 const auto it = rsid_by_ssrc_.find(ssrc);
387 if (it != rsid_by_ssrc_.end()) {
388 rsid = &it->second;
389 }
390 }
391
392 // If MID and/or RSID is specified, prioritize that for demuxing the packet.
393 // The motivation behind the BUNDLE algorithm is that we trust these are used
394 // deliberately by senders and are more likely to be correct than SSRC/payload
395 // type which are included with every packet.
396 // TODO(steveanton): According to the BUNDLE spec, new SSRC mappings are only
397 // accepted if the packet's extended sequence number is
398 // greater than that of the last SSRC mapping update.
399 // https://tools.ietf.org/html/rfc7941#section-4.2.6
400 if (mid != nullptr) {
401 RtpPacketSinkInterface* sink_by_mid = ResolveSinkByMid(*mid, ssrc);
402 if (sink_by_mid != nullptr) {
403 return sink_by_mid;
404 }
405
406 // RSID is scoped to a given MID if both are included.
407 if (rsid != nullptr) {
408 RtpPacketSinkInterface* sink_by_mid_rsid =
409 ResolveSinkByMidRsid(*mid, *rsid, ssrc);
410 if (sink_by_mid_rsid != nullptr) {
411 return sink_by_mid_rsid;
412 }
413 }
414
415 // At this point, there is at least one sink added for this MID and an RSID
416 // but either the packet does not have an RSID or it is for a different
417 // RSID. This falls outside the BUNDLE spec so drop the packet.
418 return nullptr;
419 }
420
421 // RSID can be used without MID as long as they are unique.
422 if (rsid != nullptr) {
423 RtpPacketSinkInterface* sink_by_rsid = ResolveSinkByRsid(*rsid, ssrc);
424 if (sink_by_rsid != nullptr) {
425 return sink_by_rsid;
426 }
427 }
428
429#endif
430 // We trust signaled SSRC more than payload type which is likely to conflict
431 // between streams.
432 const auto ssrc_sink_it = sink_by_ssrc_.find(ssrc);
433 if (ssrc_sink_it != sink_by_ssrc_.end()) {
434 return ssrc_sink_it->second;
435 }
436
437 if (use_payload_type_demuxing_) {
438 // Legacy senders will only signal payload type.
439 // Support that as a last resort.
440 return ResolveSinkByPayloadType(packet.PayloadType(), ssrc);
441 }
442
443 return nullptr;
444}
445
446RtpPacketSinkInterface* RtpDemuxer::ResolveSinkByMid(absl::string_view mid,
447 uint32_t ssrc) {
448 const auto it = sink_by_mid_.find(mid);
449 if (it != sink_by_mid_.end()) {
450 RtpPacketSinkInterface* sink = it->second;
451 AddSsrcSinkBinding(ssrc, sink);
452 return sink;
453 }
454 return nullptr;
455}
456
457RtpPacketSinkInterface* RtpDemuxer::ResolveSinkByMidRsid(absl::string_view mid,
458 absl::string_view rsid,
459 uint32_t ssrc) {
460 const auto it = sink_by_mid_and_rsid_.find(
461 std::make_pair(std::string(mid), std::string(rsid)));
462 if (it != sink_by_mid_and_rsid_.end()) {
463 RtpPacketSinkInterface* sink = it->second;
464 AddSsrcSinkBinding(ssrc, sink);
465 return sink;
466 }
467 return nullptr;
468}
469
470RtpPacketSinkInterface* RtpDemuxer::ResolveSinkByRsid(absl::string_view rsid,
471 uint32_t ssrc) {
472 const auto it = sink_by_rsid_.find(rsid);
473 if (it != sink_by_rsid_.end()) {
474 RtpPacketSinkInterface* sink = it->second;
475 AddSsrcSinkBinding(ssrc, sink);
476 return sink;
477 }
478 return nullptr;
479}
480
481RtpPacketSinkInterface* RtpDemuxer::ResolveSinkByPayloadType(
482 uint8_t payload_type,
483 uint32_t ssrc) {
484 const auto range = sinks_by_pt_.equal_range(payload_type);
485 if (range.first != range.second) {
486 auto it = range.first;
487 const auto end = range.second;
488 if (std::next(it) == end) {
489 RtpPacketSinkInterface* sink = it->second;
490 AddSsrcSinkBinding(ssrc, sink);
491 return sink;
492 }
493 }
494 return nullptr;
495}
496
497void RtpDemuxer::AddSsrcSinkBinding(uint32_t ssrc,
498 RtpPacketSinkInterface* sink) {
499 if (sink_by_ssrc_.size() >= kMaxSsrcBindings) {
500 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"
, 500, ::webrtc::LS_WARNING)
<< "New SSRC=" << ssrc
501 << " sink binding ignored; limit of" << kMaxSsrcBindings
502 << " bindings has been reached.";
503 return;
504 }
505
506 auto result = sink_by_ssrc_.emplace(ssrc, sink);
507 auto it = result.first;
508 bool inserted = result.second;
509 if (inserted) {
510 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"
, 510, ::webrtc::LS_INFO)
<< "Added sink = " << sink
511 << " binding with SSRC=" << ssrc;
512 } else if (it->second != sink) {
513 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"
, 513, ::webrtc::LS_INFO)
<< "Updated sink = " << sink
514 << " binding with SSRC=" << ssrc;
515 it->second = sink;
516 }
517}
518
519} // namespace webrtc