blob: 14725cf023d697aa392207015c03a5a7bb6c1380 [file] [log] [blame]
nissee4bcd6d2017-05-16 04:47:04 -07001/*
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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "call/rtp_demuxer.h"
eladalondea075c2017-06-13 07:57:31 -070012
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020013#include "call/rtp_packet_sink_interface.h"
14#include "call/rtp_rtcp_demuxer_helper.h"
15#include "call/ssrc_binding_observer.h"
16#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
17#include "modules/rtp_rtcp/source/rtp_packet_received.h"
18#include "rtc_base/checks.h"
19#include "rtc_base/logging.h"
Steve Anton884adca2019-04-15 16:52:27 -070020#include "rtc_base/strings/string_builder.h"
nissee4bcd6d2017-05-16 04:47:04 -070021
22namespace webrtc {
23
Steve Anton53c7ba62017-08-18 10:05:47 -070024RtpDemuxerCriteria::RtpDemuxerCriteria() = default;
25RtpDemuxerCriteria::~RtpDemuxerCriteria() = default;
26
Steve Anton884adca2019-04-15 16:52:27 -070027// static
28std::string RtpDemuxer::DescribePacket(const RtpPacketReceived& packet) {
29 rtc::StringBuilder sb;
30 sb << "PT=" << packet.PayloadType() << " SSRC=" << packet.Ssrc();
31 std::string mid;
32 if (packet.GetExtension<RtpMid>(&mid)) {
33 sb << " MID=" << mid;
34 }
35 std::string rsid;
36 if (packet.GetExtension<RtpStreamId>(&rsid)) {
37 sb << " RSID=" << rsid;
38 }
39 std::string rrsid;
40 if (packet.GetExtension<RepairedRtpStreamId>(&rrsid)) {
41 sb << " RRSID=" << rrsid;
42 }
43 return sb.Release();
44}
45
eladalona52722f2017-06-26 11:23:54 -070046RtpDemuxer::RtpDemuxer() = default;
nissee4bcd6d2017-05-16 04:47:04 -070047
48RtpDemuxer::~RtpDemuxer() {
Steve Anton53c7ba62017-08-18 10:05:47 -070049 RTC_DCHECK(sink_by_mid_.empty());
50 RTC_DCHECK(sink_by_ssrc_.empty());
51 RTC_DCHECK(sinks_by_pt_.empty());
52 RTC_DCHECK(sink_by_mid_and_rsid_.empty());
53 RTC_DCHECK(sink_by_rsid_.empty());
54 RTC_DCHECK(ssrc_binding_observers_.empty());
55}
56
57bool RtpDemuxer::AddSink(const RtpDemuxerCriteria& criteria,
58 RtpPacketSinkInterface* sink) {
59 RTC_DCHECK(!criteria.payload_types.empty() || !criteria.ssrcs.empty() ||
60 !criteria.mid.empty() || !criteria.rsid.empty());
Niels Möllera7de6982019-03-21 15:48:49 +010061 RTC_DCHECK(criteria.mid.empty() || IsLegalMidName(criteria.mid));
62 RTC_DCHECK(criteria.rsid.empty() || IsLegalRsidName(criteria.rsid));
Steve Anton53c7ba62017-08-18 10:05:47 -070063 RTC_DCHECK(sink);
64
65 // We return false instead of DCHECKing for logical conflicts with the new
66 // criteria because new sinks are created according to user-specified SDP and
67 // we do not want to crash due to a data validation error.
68 if (CriteriaWouldConflict(criteria)) {
69 return false;
70 }
71
72 if (!criteria.mid.empty()) {
73 if (criteria.rsid.empty()) {
74 sink_by_mid_.emplace(criteria.mid, sink);
75 } else {
76 sink_by_mid_and_rsid_.emplace(std::make_pair(criteria.mid, criteria.rsid),
77 sink);
78 }
79 } else {
80 if (!criteria.rsid.empty()) {
81 sink_by_rsid_.emplace(criteria.rsid, sink);
82 }
83 }
84
85 for (uint32_t ssrc : criteria.ssrcs) {
86 sink_by_ssrc_.emplace(ssrc, sink);
87 }
88
89 for (uint8_t payload_type : criteria.payload_types) {
90 sinks_by_pt_.emplace(payload_type, sink);
91 }
92
93 RefreshKnownMids();
94
95 return true;
96}
97
98bool RtpDemuxer::CriteriaWouldConflict(
99 const RtpDemuxerCriteria& criteria) const {
100 if (!criteria.mid.empty()) {
101 if (criteria.rsid.empty()) {
102 // If the MID is in the known_mids_ set, then there is already a sink
103 // added for this MID directly, or there is a sink already added with a
104 // MID, RSID pair for our MID and some RSID.
105 // Adding this criteria would cause one of these rules to be shadowed, so
106 // reject this new criteria.
107 if (known_mids_.find(criteria.mid) != known_mids_.end()) {
108 return true;
109 }
110 } else {
111 // If the exact rule already exists, then reject this duplicate.
112 if (sink_by_mid_and_rsid_.find(std::make_pair(
113 criteria.mid, criteria.rsid)) != sink_by_mid_and_rsid_.end()) {
114 return true;
115 }
116 // If there is already a sink registered for the bare MID, then this
117 // criteria will never receive any packets because they will just be
118 // directed to that MID sink, so reject this new criteria.
119 if (sink_by_mid_.find(criteria.mid) != sink_by_mid_.end()) {
120 return true;
121 }
122 }
123 }
124
125 for (uint32_t ssrc : criteria.ssrcs) {
126 if (sink_by_ssrc_.find(ssrc) != sink_by_ssrc_.end()) {
127 return true;
128 }
129 }
130
131 // TODO(steveanton): May also sanity check payload types.
132
133 return false;
134}
135
136void RtpDemuxer::RefreshKnownMids() {
137 known_mids_.clear();
138
139 for (auto const& item : sink_by_mid_) {
140 const std::string& mid = item.first;
141 known_mids_.insert(mid);
142 }
143
144 for (auto const& item : sink_by_mid_and_rsid_) {
145 const std::string& mid = item.first.first;
146 known_mids_.insert(mid);
147 }
nissee4bcd6d2017-05-16 04:47:04 -0700148}
149
eladalon5daecca2017-08-04 06:34:54 -0700150bool RtpDemuxer::AddSink(uint32_t ssrc, RtpPacketSinkInterface* sink) {
Steve Anton53c7ba62017-08-18 10:05:47 -0700151 RtpDemuxerCriteria criteria;
152 criteria.ssrcs.insert(ssrc);
153 return AddSink(criteria, sink);
nissee4bcd6d2017-05-16 04:47:04 -0700154}
155
eladalond0244c22017-06-08 04:19:13 -0700156void RtpDemuxer::AddSink(const std::string& rsid,
157 RtpPacketSinkInterface* sink) {
Steve Anton53c7ba62017-08-18 10:05:47 -0700158 RtpDemuxerCriteria criteria;
159 criteria.rsid = rsid;
160 AddSink(criteria, sink);
eladalond0244c22017-06-08 04:19:13 -0700161}
162
163bool RtpDemuxer::RemoveSink(const RtpPacketSinkInterface* sink) {
164 RTC_DCHECK(sink);
Steve Antonc0cde562017-08-21 09:18:26 -0700165 size_t num_removed = RemoveFromMapByValue(&sink_by_mid_, sink) +
166 RemoveFromMapByValue(&sink_by_ssrc_, sink) +
167 RemoveFromMultimapByValue(&sinks_by_pt_, sink) +
168 RemoveFromMapByValue(&sink_by_mid_and_rsid_, sink) +
169 RemoveFromMapByValue(&sink_by_rsid_, sink);
Steve Anton53c7ba62017-08-18 10:05:47 -0700170 RefreshKnownMids();
171 return num_removed > 0;
nissee4bcd6d2017-05-16 04:47:04 -0700172}
173
174bool RtpDemuxer::OnRtpPacket(const RtpPacketReceived& packet) {
Steve Anton53c7ba62017-08-18 10:05:47 -0700175 RtpPacketSinkInterface* sink = ResolveSink(packet);
176 if (sink != nullptr) {
177 sink->OnRtpPacket(packet);
178 return true;
nissee4bcd6d2017-05-16 04:47:04 -0700179 }
Steve Anton53c7ba62017-08-18 10:05:47 -0700180 return false;
181}
182
183RtpPacketSinkInterface* RtpDemuxer::ResolveSink(
184 const RtpPacketReceived& packet) {
185 // See the BUNDLE spec for high level reference to this algorithm:
186 // https://tools.ietf.org/html/draft-ietf-mmusic-sdp-bundle-negotiation-38#section-10.2
187
188 // RSID and RRID are routed to the same sinks. If an RSID is specified on a
189 // repair packet, it should be ignored and the RRID should be used.
190 std::string packet_mid, packet_rsid;
Steve Antoned09dc62018-03-29 12:59:17 -0700191 bool has_mid = use_mid_ && packet.GetExtension<RtpMid>(&packet_mid);
Steve Anton53c7ba62017-08-18 10:05:47 -0700192 bool has_rsid = packet.GetExtension<RepairedRtpStreamId>(&packet_rsid);
193 if (!has_rsid) {
194 has_rsid = packet.GetExtension<RtpStreamId>(&packet_rsid);
195 }
196 uint32_t ssrc = packet.Ssrc();
197
198 // The BUNDLE spec says to drop any packets with unknown MIDs, even if the
199 // SSRC is known/latched.
200 if (has_mid && known_mids_.find(packet_mid) == known_mids_.end()) {
201 return nullptr;
202 }
203
204 // Cache information we learn about SSRCs and IDs. We need to do this even if
205 // there isn't a rule/sink yet because we might add an MID/RSID rule after
206 // learning an MID/RSID<->SSRC association.
207
208 std::string* mid = nullptr;
209 if (has_mid) {
210 mid_by_ssrc_[ssrc] = packet_mid;
211 mid = &packet_mid;
212 } else {
213 // If the packet does not include a MID header extension, check if there is
214 // a latched MID for the SSRC.
215 const auto it = mid_by_ssrc_.find(ssrc);
216 if (it != mid_by_ssrc_.end()) {
217 mid = &it->second;
218 }
219 }
220
221 std::string* rsid = nullptr;
222 if (has_rsid) {
223 rsid_by_ssrc_[ssrc] = packet_rsid;
224 rsid = &packet_rsid;
225 } else {
226 // If the packet does not include an RRID/RSID header extension, check if
227 // there is a latched RSID for the SSRC.
228 const auto it = rsid_by_ssrc_.find(ssrc);
229 if (it != rsid_by_ssrc_.end()) {
230 rsid = &it->second;
231 }
232 }
233
234 // If MID and/or RSID is specified, prioritize that for demuxing the packet.
235 // The motivation behind the BUNDLE algorithm is that we trust these are used
236 // deliberately by senders and are more likely to be correct than SSRC/payload
237 // type which are included with every packet.
238 // TODO(steveanton): According to the BUNDLE spec, new SSRC mappings are only
239 // accepted if the packet's extended sequence number is
240 // greater than that of the last SSRC mapping update.
241 // https://tools.ietf.org/html/rfc7941#section-4.2.6
242 if (mid != nullptr) {
243 RtpPacketSinkInterface* sink_by_mid = ResolveSinkByMid(*mid, ssrc);
244 if (sink_by_mid != nullptr) {
245 return sink_by_mid;
246 }
247
248 // RSID is scoped to a given MID if both are included.
249 if (rsid != nullptr) {
250 RtpPacketSinkInterface* sink_by_mid_rsid =
251 ResolveSinkByMidRsid(*mid, *rsid, ssrc);
252 if (sink_by_mid_rsid != nullptr) {
253 return sink_by_mid_rsid;
254 }
255 }
256
257 // At this point, there is at least one sink added for this MID and an RSID
258 // but either the packet does not have an RSID or it is for a different
259 // RSID. This falls outside the BUNDLE spec so drop the packet.
260 return nullptr;
261 }
262
263 // RSID can be used without MID as long as they are unique.
264 if (rsid != nullptr) {
265 RtpPacketSinkInterface* sink_by_rsid = ResolveSinkByRsid(*rsid, ssrc);
266 if (sink_by_rsid != nullptr) {
267 return sink_by_rsid;
268 }
269 }
270
271 // We trust signaled SSRC more than payload type which is likely to conflict
272 // between streams.
273 const auto ssrc_sink_it = sink_by_ssrc_.find(ssrc);
274 if (ssrc_sink_it != sink_by_ssrc_.end()) {
275 return ssrc_sink_it->second;
276 }
277
278 // Legacy senders will only signal payload type, support that as last resort.
279 return ResolveSinkByPayloadType(packet.PayloadType(), ssrc);
280}
281
282RtpPacketSinkInterface* RtpDemuxer::ResolveSinkByMid(const std::string& mid,
283 uint32_t ssrc) {
284 const auto it = sink_by_mid_.find(mid);
285 if (it != sink_by_mid_.end()) {
286 RtpPacketSinkInterface* sink = it->second;
287 bool notify = AddSsrcSinkBinding(ssrc, sink);
288 if (notify) {
289 for (auto* observer : ssrc_binding_observers_) {
290 observer->OnSsrcBoundToMid(mid, ssrc);
291 }
292 }
293 return sink;
294 }
295 return nullptr;
296}
297
298RtpPacketSinkInterface* RtpDemuxer::ResolveSinkByMidRsid(
299 const std::string& mid,
300 const std::string& rsid,
301 uint32_t ssrc) {
302 const auto it = sink_by_mid_and_rsid_.find(std::make_pair(mid, rsid));
303 if (it != sink_by_mid_and_rsid_.end()) {
304 RtpPacketSinkInterface* sink = it->second;
305 bool notify = AddSsrcSinkBinding(ssrc, sink);
306 if (notify) {
307 for (auto* observer : ssrc_binding_observers_) {
308 observer->OnSsrcBoundToMidRsid(mid, rsid, ssrc);
309 }
310 }
311 return sink;
312 }
313 return nullptr;
314}
315void RtpDemuxer::RegisterRsidResolutionObserver(SsrcBindingObserver* observer) {
316 RegisterSsrcBindingObserver(observer);
317}
318
319RtpPacketSinkInterface* RtpDemuxer::ResolveSinkByRsid(const std::string& rsid,
320 uint32_t ssrc) {
321 const auto it = sink_by_rsid_.find(rsid);
322 if (it != sink_by_rsid_.end()) {
323 RtpPacketSinkInterface* sink = it->second;
324 bool notify = AddSsrcSinkBinding(ssrc, sink);
325 if (notify) {
326 for (auto* observer : ssrc_binding_observers_) {
327 observer->OnSsrcBoundToRsid(rsid, ssrc);
328 }
329 }
330 return sink;
331 }
332 return nullptr;
333}
334void RtpDemuxer::DeregisterRsidResolutionObserver(
335 const SsrcBindingObserver* observer) {
336 DeregisterSsrcBindingObserver(observer);
337}
338
339RtpPacketSinkInterface* RtpDemuxer::ResolveSinkByPayloadType(
340 uint8_t payload_type,
341 uint32_t ssrc) {
342 const auto range = sinks_by_pt_.equal_range(payload_type);
343 if (range.first != range.second) {
344 auto it = range.first;
345 const auto end = range.second;
346 if (std::next(it) == end) {
347 RtpPacketSinkInterface* sink = it->second;
348 bool notify = AddSsrcSinkBinding(ssrc, sink);
349 if (notify) {
350 for (auto* observer : ssrc_binding_observers_) {
351 observer->OnSsrcBoundToPayloadType(payload_type, ssrc);
352 }
353 }
354 return sink;
355 }
356 }
357 return nullptr;
358}
359
360bool RtpDemuxer::AddSsrcSinkBinding(uint32_t ssrc,
361 RtpPacketSinkInterface* sink) {
362 if (sink_by_ssrc_.size() >= kMaxSsrcBindings) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100363 RTC_LOG(LS_WARNING) << "New SSRC=" << ssrc
364 << " sink binding ignored; limit of" << kMaxSsrcBindings
365 << " bindings has been reached.";
Steve Anton53c7ba62017-08-18 10:05:47 -0700366 return false;
367 }
368
369 auto result = sink_by_ssrc_.emplace(ssrc, sink);
370 auto it = result.first;
371 bool inserted = result.second;
372 if (inserted) {
373 return true;
374 }
375 if (it->second != sink) {
376 it->second = sink;
377 return true;
378 }
379 return false;
eladalond0244c22017-06-08 04:19:13 -0700380}
381
Steve Antonb3329172017-08-17 15:23:51 -0700382void RtpDemuxer::RegisterSsrcBindingObserver(SsrcBindingObserver* observer) {
eladalona52722f2017-06-26 11:23:54 -0700383 RTC_DCHECK(observer);
Steve Antonb3329172017-08-17 15:23:51 -0700384 RTC_DCHECK(!ContainerHasKey(ssrc_binding_observers_, observer));
eladalona52722f2017-06-26 11:23:54 -0700385
Steve Antonb3329172017-08-17 15:23:51 -0700386 ssrc_binding_observers_.push_back(observer);
387}
eladalona52722f2017-06-26 11:23:54 -0700388
Steve Antonb3329172017-08-17 15:23:51 -0700389void RtpDemuxer::DeregisterSsrcBindingObserver(
390 const SsrcBindingObserver* observer) {
eladalona52722f2017-06-26 11:23:54 -0700391 RTC_DCHECK(observer);
Steve Antonb3329172017-08-17 15:23:51 -0700392 auto it = std::find(ssrc_binding_observers_.begin(),
393 ssrc_binding_observers_.end(), observer);
394 RTC_DCHECK(it != ssrc_binding_observers_.end());
395 ssrc_binding_observers_.erase(it);
396}
nissee4bcd6d2017-05-16 04:47:04 -0700397
398} // namespace webrtc