blob: 9fc4ba1c16421f9d429f0b9f7fe10e73cf3d4708 [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"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020014#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
15#include "modules/rtp_rtcp/source/rtp_packet_received.h"
16#include "rtc_base/checks.h"
17#include "rtc_base/logging.h"
Steve Anton884adca2019-04-15 16:52:27 -070018#include "rtc_base/strings/string_builder.h"
nissee4bcd6d2017-05-16 04:47:04 -070019
20namespace webrtc {
Danil Chapovalovc1b27122020-06-30 17:51:55 +020021namespace {
22
23template <typename Container, typename Value>
24size_t RemoveFromMultimapByValue(Container* multimap, const Value& value) {
25 size_t count = 0;
26 for (auto it = multimap->begin(); it != multimap->end();) {
27 if (it->second == value) {
28 it = multimap->erase(it);
29 ++count;
30 } else {
31 ++it;
32 }
33 }
34 return count;
35}
36
37template <typename Map, typename Value>
38size_t RemoveFromMapByValue(Map* map, const Value& value) {
39 size_t count = 0;
40 for (auto it = map->begin(); it != map->end();) {
41 if (it->second == value) {
42 it = map->erase(it);
43 ++count;
44 } else {
45 ++it;
46 }
47 }
48 return count;
49}
50
Danil Chapovalovc1b27122020-06-30 17:51:55 +020051} // namespace
nissee4bcd6d2017-05-16 04:47:04 -070052
Steve Anton53c7ba62017-08-18 10:05:47 -070053RtpDemuxerCriteria::RtpDemuxerCriteria() = default;
54RtpDemuxerCriteria::~RtpDemuxerCriteria() = default;
55
Yura Yaroshevich49a5e3e2020-05-16 14:30:59 +030056std::string RtpDemuxerCriteria::ToString() const {
57 rtc::StringBuilder sb;
58 sb << "{mid: " << (mid.empty() ? "<empty>" : mid)
59 << ", rsid: " << (rsid.empty() ? "<empty>" : rsid) << ", ssrcs: [";
60
61 for (auto ssrc : ssrcs) {
62 sb << ssrc << ", ";
63 }
64
65 sb << "], payload_types = [";
66
67 for (auto pt : payload_types) {
68 sb << pt << ", ";
69 }
70
71 sb << "]}";
72 return sb.Release();
73}
74
Steve Anton884adca2019-04-15 16:52:27 -070075// static
76std::string RtpDemuxer::DescribePacket(const RtpPacketReceived& packet) {
77 rtc::StringBuilder sb;
78 sb << "PT=" << packet.PayloadType() << " SSRC=" << packet.Ssrc();
79 std::string mid;
80 if (packet.GetExtension<RtpMid>(&mid)) {
81 sb << " MID=" << mid;
82 }
83 std::string rsid;
84 if (packet.GetExtension<RtpStreamId>(&rsid)) {
85 sb << " RSID=" << rsid;
86 }
87 std::string rrsid;
88 if (packet.GetExtension<RepairedRtpStreamId>(&rrsid)) {
89 sb << " RRSID=" << rrsid;
90 }
91 return sb.Release();
92}
93
eladalona52722f2017-06-26 11:23:54 -070094RtpDemuxer::RtpDemuxer() = default;
nissee4bcd6d2017-05-16 04:47:04 -070095
96RtpDemuxer::~RtpDemuxer() {
Steve Anton53c7ba62017-08-18 10:05:47 -070097 RTC_DCHECK(sink_by_mid_.empty());
98 RTC_DCHECK(sink_by_ssrc_.empty());
99 RTC_DCHECK(sinks_by_pt_.empty());
100 RTC_DCHECK(sink_by_mid_and_rsid_.empty());
101 RTC_DCHECK(sink_by_rsid_.empty());
Steve Anton53c7ba62017-08-18 10:05:47 -0700102}
103
104bool RtpDemuxer::AddSink(const RtpDemuxerCriteria& criteria,
105 RtpPacketSinkInterface* sink) {
106 RTC_DCHECK(!criteria.payload_types.empty() || !criteria.ssrcs.empty() ||
107 !criteria.mid.empty() || !criteria.rsid.empty());
Niels Möllera7de6982019-03-21 15:48:49 +0100108 RTC_DCHECK(criteria.mid.empty() || IsLegalMidName(criteria.mid));
109 RTC_DCHECK(criteria.rsid.empty() || IsLegalRsidName(criteria.rsid));
Steve Anton53c7ba62017-08-18 10:05:47 -0700110 RTC_DCHECK(sink);
111
112 // We return false instead of DCHECKing for logical conflicts with the new
113 // criteria because new sinks are created according to user-specified SDP and
114 // we do not want to crash due to a data validation error.
115 if (CriteriaWouldConflict(criteria)) {
Yura Yaroshevich49a5e3e2020-05-16 14:30:59 +0300116 RTC_LOG(LS_ERROR) << "Unable to add sink = " << sink
117 << " due conflicting criteria " << criteria.ToString();
Steve Anton53c7ba62017-08-18 10:05:47 -0700118 return false;
119 }
120
121 if (!criteria.mid.empty()) {
122 if (criteria.rsid.empty()) {
123 sink_by_mid_.emplace(criteria.mid, sink);
124 } else {
125 sink_by_mid_and_rsid_.emplace(std::make_pair(criteria.mid, criteria.rsid),
126 sink);
127 }
128 } else {
129 if (!criteria.rsid.empty()) {
130 sink_by_rsid_.emplace(criteria.rsid, sink);
131 }
132 }
133
134 for (uint32_t ssrc : criteria.ssrcs) {
135 sink_by_ssrc_.emplace(ssrc, sink);
136 }
137
138 for (uint8_t payload_type : criteria.payload_types) {
139 sinks_by_pt_.emplace(payload_type, sink);
140 }
141
142 RefreshKnownMids();
143
Yura Yaroshevich49a5e3e2020-05-16 14:30:59 +0300144 RTC_LOG(LS_INFO) << "Added sink = " << sink << " for criteria "
145 << criteria.ToString();
146
Steve Anton53c7ba62017-08-18 10:05:47 -0700147 return true;
148}
149
150bool RtpDemuxer::CriteriaWouldConflict(
151 const RtpDemuxerCriteria& criteria) const {
152 if (!criteria.mid.empty()) {
153 if (criteria.rsid.empty()) {
154 // If the MID is in the known_mids_ set, then there is already a sink
155 // added for this MID directly, or there is a sink already added with a
156 // MID, RSID pair for our MID and some RSID.
157 // Adding this criteria would cause one of these rules to be shadowed, so
158 // reject this new criteria.
159 if (known_mids_.find(criteria.mid) != known_mids_.end()) {
Yura Yaroshevich49a5e3e2020-05-16 14:30:59 +0300160 RTC_LOG(LS_INFO) << criteria.ToString()
161 << " would conflict with known mid";
Steve Anton53c7ba62017-08-18 10:05:47 -0700162 return true;
163 }
164 } else {
165 // If the exact rule already exists, then reject this duplicate.
Yura Yaroshevich49a5e3e2020-05-16 14:30:59 +0300166 const auto sink_by_mid_and_rsid = sink_by_mid_and_rsid_.find(
167 std::make_pair(criteria.mid, criteria.rsid));
168 if (sink_by_mid_and_rsid != sink_by_mid_and_rsid_.end()) {
169 RTC_LOG(LS_INFO) << criteria.ToString()
170 << " would conflict with existing sink = "
171 << sink_by_mid_and_rsid->second
172 << " by mid+rsid binding";
Steve Anton53c7ba62017-08-18 10:05:47 -0700173 return true;
174 }
175 // If there is already a sink registered for the bare MID, then this
176 // criteria will never receive any packets because they will just be
177 // directed to that MID sink, so reject this new criteria.
Yura Yaroshevich49a5e3e2020-05-16 14:30:59 +0300178 const auto sink_by_mid = sink_by_mid_.find(criteria.mid);
179 if (sink_by_mid != sink_by_mid_.end()) {
180 RTC_LOG(LS_INFO) << criteria.ToString()
181 << " would conflict with existing sink = "
182 << sink_by_mid->second << " by mid binding";
Steve Anton53c7ba62017-08-18 10:05:47 -0700183 return true;
184 }
185 }
186 }
187
188 for (uint32_t ssrc : criteria.ssrcs) {
Yura Yaroshevich49a5e3e2020-05-16 14:30:59 +0300189 const auto sink_by_ssrc = sink_by_ssrc_.find(ssrc);
190 if (sink_by_ssrc != sink_by_ssrc_.end()) {
191 RTC_LOG(LS_INFO) << criteria.ToString()
192 << " would conflict with existing sink = "
193 << sink_by_ssrc->second << " binding by SSRC=" << ssrc;
Steve Anton53c7ba62017-08-18 10:05:47 -0700194 return true;
195 }
196 }
197
198 // TODO(steveanton): May also sanity check payload types.
199
200 return false;
201}
202
203void RtpDemuxer::RefreshKnownMids() {
204 known_mids_.clear();
205
206 for (auto const& item : sink_by_mid_) {
207 const std::string& mid = item.first;
208 known_mids_.insert(mid);
209 }
210
211 for (auto const& item : sink_by_mid_and_rsid_) {
212 const std::string& mid = item.first.first;
213 known_mids_.insert(mid);
214 }
nissee4bcd6d2017-05-16 04:47:04 -0700215}
216
eladalon5daecca2017-08-04 06:34:54 -0700217bool RtpDemuxer::AddSink(uint32_t ssrc, RtpPacketSinkInterface* sink) {
Steve Anton53c7ba62017-08-18 10:05:47 -0700218 RtpDemuxerCriteria criteria;
219 criteria.ssrcs.insert(ssrc);
220 return AddSink(criteria, sink);
nissee4bcd6d2017-05-16 04:47:04 -0700221}
222
eladalond0244c22017-06-08 04:19:13 -0700223void RtpDemuxer::AddSink(const std::string& rsid,
224 RtpPacketSinkInterface* sink) {
Steve Anton53c7ba62017-08-18 10:05:47 -0700225 RtpDemuxerCriteria criteria;
226 criteria.rsid = rsid;
227 AddSink(criteria, sink);
eladalond0244c22017-06-08 04:19:13 -0700228}
229
230bool RtpDemuxer::RemoveSink(const RtpPacketSinkInterface* sink) {
231 RTC_DCHECK(sink);
Steve Antonc0cde562017-08-21 09:18:26 -0700232 size_t num_removed = RemoveFromMapByValue(&sink_by_mid_, sink) +
233 RemoveFromMapByValue(&sink_by_ssrc_, sink) +
234 RemoveFromMultimapByValue(&sinks_by_pt_, sink) +
235 RemoveFromMapByValue(&sink_by_mid_and_rsid_, sink) +
236 RemoveFromMapByValue(&sink_by_rsid_, sink);
Steve Anton53c7ba62017-08-18 10:05:47 -0700237 RefreshKnownMids();
Yura Yaroshevich49a5e3e2020-05-16 14:30:59 +0300238 bool removed = num_removed > 0;
239 if (removed) {
240 RTC_LOG(LS_INFO) << "Removed sink = " << sink << " bindings";
241 }
242 return removed;
nissee4bcd6d2017-05-16 04:47:04 -0700243}
244
245bool RtpDemuxer::OnRtpPacket(const RtpPacketReceived& packet) {
Steve Anton53c7ba62017-08-18 10:05:47 -0700246 RtpPacketSinkInterface* sink = ResolveSink(packet);
247 if (sink != nullptr) {
248 sink->OnRtpPacket(packet);
249 return true;
nissee4bcd6d2017-05-16 04:47:04 -0700250 }
Steve Anton53c7ba62017-08-18 10:05:47 -0700251 return false;
252}
253
254RtpPacketSinkInterface* RtpDemuxer::ResolveSink(
255 const RtpPacketReceived& packet) {
256 // See the BUNDLE spec for high level reference to this algorithm:
257 // https://tools.ietf.org/html/draft-ietf-mmusic-sdp-bundle-negotiation-38#section-10.2
258
259 // RSID and RRID are routed to the same sinks. If an RSID is specified on a
260 // repair packet, it should be ignored and the RRID should be used.
261 std::string packet_mid, packet_rsid;
Steve Antoned09dc62018-03-29 12:59:17 -0700262 bool has_mid = use_mid_ && packet.GetExtension<RtpMid>(&packet_mid);
Steve Anton53c7ba62017-08-18 10:05:47 -0700263 bool has_rsid = packet.GetExtension<RepairedRtpStreamId>(&packet_rsid);
264 if (!has_rsid) {
265 has_rsid = packet.GetExtension<RtpStreamId>(&packet_rsid);
266 }
267 uint32_t ssrc = packet.Ssrc();
268
269 // The BUNDLE spec says to drop any packets with unknown MIDs, even if the
270 // SSRC is known/latched.
271 if (has_mid && known_mids_.find(packet_mid) == known_mids_.end()) {
272 return nullptr;
273 }
274
275 // Cache information we learn about SSRCs and IDs. We need to do this even if
276 // there isn't a rule/sink yet because we might add an MID/RSID rule after
277 // learning an MID/RSID<->SSRC association.
278
279 std::string* mid = nullptr;
280 if (has_mid) {
281 mid_by_ssrc_[ssrc] = packet_mid;
282 mid = &packet_mid;
283 } else {
284 // If the packet does not include a MID header extension, check if there is
285 // a latched MID for the SSRC.
286 const auto it = mid_by_ssrc_.find(ssrc);
287 if (it != mid_by_ssrc_.end()) {
288 mid = &it->second;
289 }
290 }
291
292 std::string* rsid = nullptr;
293 if (has_rsid) {
294 rsid_by_ssrc_[ssrc] = packet_rsid;
295 rsid = &packet_rsid;
296 } else {
297 // If the packet does not include an RRID/RSID header extension, check if
298 // there is a latched RSID for the SSRC.
299 const auto it = rsid_by_ssrc_.find(ssrc);
300 if (it != rsid_by_ssrc_.end()) {
301 rsid = &it->second;
302 }
303 }
304
305 // If MID and/or RSID is specified, prioritize that for demuxing the packet.
306 // The motivation behind the BUNDLE algorithm is that we trust these are used
307 // deliberately by senders and are more likely to be correct than SSRC/payload
308 // type which are included with every packet.
309 // TODO(steveanton): According to the BUNDLE spec, new SSRC mappings are only
310 // accepted if the packet's extended sequence number is
311 // greater than that of the last SSRC mapping update.
312 // https://tools.ietf.org/html/rfc7941#section-4.2.6
313 if (mid != nullptr) {
314 RtpPacketSinkInterface* sink_by_mid = ResolveSinkByMid(*mid, ssrc);
315 if (sink_by_mid != nullptr) {
316 return sink_by_mid;
317 }
318
319 // RSID is scoped to a given MID if both are included.
320 if (rsid != nullptr) {
321 RtpPacketSinkInterface* sink_by_mid_rsid =
322 ResolveSinkByMidRsid(*mid, *rsid, ssrc);
323 if (sink_by_mid_rsid != nullptr) {
324 return sink_by_mid_rsid;
325 }
326 }
327
328 // At this point, there is at least one sink added for this MID and an RSID
329 // but either the packet does not have an RSID or it is for a different
330 // RSID. This falls outside the BUNDLE spec so drop the packet.
331 return nullptr;
332 }
333
334 // RSID can be used without MID as long as they are unique.
335 if (rsid != nullptr) {
336 RtpPacketSinkInterface* sink_by_rsid = ResolveSinkByRsid(*rsid, ssrc);
337 if (sink_by_rsid != nullptr) {
338 return sink_by_rsid;
339 }
340 }
341
342 // We trust signaled SSRC more than payload type which is likely to conflict
343 // between streams.
344 const auto ssrc_sink_it = sink_by_ssrc_.find(ssrc);
345 if (ssrc_sink_it != sink_by_ssrc_.end()) {
346 return ssrc_sink_it->second;
347 }
348
349 // Legacy senders will only signal payload type, support that as last resort.
350 return ResolveSinkByPayloadType(packet.PayloadType(), ssrc);
351}
352
353RtpPacketSinkInterface* RtpDemuxer::ResolveSinkByMid(const std::string& mid,
354 uint32_t ssrc) {
355 const auto it = sink_by_mid_.find(mid);
356 if (it != sink_by_mid_.end()) {
357 RtpPacketSinkInterface* sink = it->second;
Danil Chapovalov8fddf1f2020-07-08 18:32:52 +0200358 AddSsrcSinkBinding(ssrc, sink);
Steve Anton53c7ba62017-08-18 10:05:47 -0700359 return sink;
360 }
361 return nullptr;
362}
363
364RtpPacketSinkInterface* RtpDemuxer::ResolveSinkByMidRsid(
365 const std::string& mid,
366 const std::string& rsid,
367 uint32_t ssrc) {
368 const auto it = sink_by_mid_and_rsid_.find(std::make_pair(mid, rsid));
369 if (it != sink_by_mid_and_rsid_.end()) {
370 RtpPacketSinkInterface* sink = it->second;
Danil Chapovalov8fddf1f2020-07-08 18:32:52 +0200371 AddSsrcSinkBinding(ssrc, sink);
Steve Anton53c7ba62017-08-18 10:05:47 -0700372 return sink;
373 }
374 return nullptr;
375}
Steve Anton53c7ba62017-08-18 10:05:47 -0700376
377RtpPacketSinkInterface* RtpDemuxer::ResolveSinkByRsid(const std::string& rsid,
378 uint32_t ssrc) {
379 const auto it = sink_by_rsid_.find(rsid);
380 if (it != sink_by_rsid_.end()) {
381 RtpPacketSinkInterface* sink = it->second;
Danil Chapovalov8fddf1f2020-07-08 18:32:52 +0200382 AddSsrcSinkBinding(ssrc, sink);
Steve Anton53c7ba62017-08-18 10:05:47 -0700383 return sink;
384 }
385 return nullptr;
386}
Steve Anton53c7ba62017-08-18 10:05:47 -0700387
388RtpPacketSinkInterface* RtpDemuxer::ResolveSinkByPayloadType(
389 uint8_t payload_type,
390 uint32_t ssrc) {
391 const auto range = sinks_by_pt_.equal_range(payload_type);
392 if (range.first != range.second) {
393 auto it = range.first;
394 const auto end = range.second;
395 if (std::next(it) == end) {
396 RtpPacketSinkInterface* sink = it->second;
Danil Chapovalov8fddf1f2020-07-08 18:32:52 +0200397 AddSsrcSinkBinding(ssrc, sink);
Steve Anton53c7ba62017-08-18 10:05:47 -0700398 return sink;
399 }
400 }
401 return nullptr;
402}
403
Danil Chapovalov8fddf1f2020-07-08 18:32:52 +0200404void RtpDemuxer::AddSsrcSinkBinding(uint32_t ssrc,
Steve Anton53c7ba62017-08-18 10:05:47 -0700405 RtpPacketSinkInterface* sink) {
406 if (sink_by_ssrc_.size() >= kMaxSsrcBindings) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100407 RTC_LOG(LS_WARNING) << "New SSRC=" << ssrc
408 << " sink binding ignored; limit of" << kMaxSsrcBindings
409 << " bindings has been reached.";
Danil Chapovalov8fddf1f2020-07-08 18:32:52 +0200410 return;
Steve Anton53c7ba62017-08-18 10:05:47 -0700411 }
412
413 auto result = sink_by_ssrc_.emplace(ssrc, sink);
414 auto it = result.first;
415 bool inserted = result.second;
416 if (inserted) {
Yura Yaroshevich49a5e3e2020-05-16 14:30:59 +0300417 RTC_LOG(LS_INFO) << "Added sink = " << sink
418 << " binding with SSRC=" << ssrc;
Danil Chapovalov8fddf1f2020-07-08 18:32:52 +0200419 } else if (it->second != sink) {
Yura Yaroshevich49a5e3e2020-05-16 14:30:59 +0300420 RTC_LOG(LS_INFO) << "Updated sink = " << sink
421 << " binding with SSRC=" << ssrc;
Steve Anton53c7ba62017-08-18 10:05:47 -0700422 it->second = sink;
Steve Anton53c7ba62017-08-18 10:05:47 -0700423 }
Steve Antonb3329172017-08-17 15:23:51 -0700424}
nissee4bcd6d2017-05-16 04:47:04 -0700425
426} // namespace webrtc