• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "call/rtp_packet_sink_interface.h"
14 #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"
18 #include "rtc_base/strings/string_builder.h"
19 
20 namespace webrtc {
21 namespace {
22 
23 template <typename Container, typename Value>
RemoveFromMultimapByValue(Container * multimap,const Value & value)24 size_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 
37 template <typename Map, typename Value>
RemoveFromMapByValue(Map * map,const Value & value)38 size_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 
51 }  // namespace
52 
53 RtpDemuxerCriteria::RtpDemuxerCriteria() = default;
54 RtpDemuxerCriteria::~RtpDemuxerCriteria() = default;
55 
ToString() const56 std::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 
75 // static
DescribePacket(const RtpPacketReceived & packet)76 std::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 
94 RtpDemuxer::RtpDemuxer() = default;
95 
~RtpDemuxer()96 RtpDemuxer::~RtpDemuxer() {
97   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());
102 }
103 
AddSink(const RtpDemuxerCriteria & criteria,RtpPacketSinkInterface * sink)104 bool 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());
108   RTC_DCHECK(criteria.mid.empty() || IsLegalMidName(criteria.mid));
109   RTC_DCHECK(criteria.rsid.empty() || IsLegalRsidName(criteria.rsid));
110   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)) {
116     RTC_LOG(LS_ERROR) << "Unable to add sink = " << sink
117                       << " due conflicting criteria " << criteria.ToString();
118     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 
144   RTC_LOG(LS_INFO) << "Added sink = " << sink << " for criteria "
145                    << criteria.ToString();
146 
147   return true;
148 }
149 
CriteriaWouldConflict(const RtpDemuxerCriteria & criteria) const150 bool 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()) {
160         RTC_LOG(LS_INFO) << criteria.ToString()
161                          << " would conflict with known mid";
162         return true;
163       }
164     } else {
165       // If the exact rule already exists, then reject this duplicate.
166       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";
173         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.
178       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";
183         return true;
184       }
185     }
186   }
187 
188   for (uint32_t ssrc : criteria.ssrcs) {
189     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;
194       return true;
195     }
196   }
197 
198   // TODO(steveanton): May also sanity check payload types.
199 
200   return false;
201 }
202 
RefreshKnownMids()203 void 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   }
215 }
216 
AddSink(uint32_t ssrc,RtpPacketSinkInterface * sink)217 bool RtpDemuxer::AddSink(uint32_t ssrc, RtpPacketSinkInterface* sink) {
218   RtpDemuxerCriteria criteria;
219   criteria.ssrcs.insert(ssrc);
220   return AddSink(criteria, sink);
221 }
222 
AddSink(const std::string & rsid,RtpPacketSinkInterface * sink)223 void RtpDemuxer::AddSink(const std::string& rsid,
224                          RtpPacketSinkInterface* sink) {
225   RtpDemuxerCriteria criteria;
226   criteria.rsid = rsid;
227   AddSink(criteria, sink);
228 }
229 
RemoveSink(const RtpPacketSinkInterface * sink)230 bool RtpDemuxer::RemoveSink(const RtpPacketSinkInterface* sink) {
231   RTC_DCHECK(sink);
232   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);
237   RefreshKnownMids();
238   bool removed = num_removed > 0;
239   if (removed) {
240     RTC_LOG(LS_INFO) << "Removed sink = " << sink << " bindings";
241   }
242   return removed;
243 }
244 
OnRtpPacket(const RtpPacketReceived & packet)245 bool RtpDemuxer::OnRtpPacket(const RtpPacketReceived& packet) {
246   RtpPacketSinkInterface* sink = ResolveSink(packet);
247   if (sink != nullptr) {
248     sink->OnRtpPacket(packet);
249     return true;
250   }
251   return false;
252 }
253 
ResolveSink(const RtpPacketReceived & packet)254 RtpPacketSinkInterface* 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;
262   bool has_mid = use_mid_ && packet.GetExtension<RtpMid>(&packet_mid);
263   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 
ResolveSinkByMid(const std::string & mid,uint32_t ssrc)353 RtpPacketSinkInterface* 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;
358     AddSsrcSinkBinding(ssrc, sink);
359     return sink;
360   }
361   return nullptr;
362 }
363 
ResolveSinkByMidRsid(const std::string & mid,const std::string & rsid,uint32_t ssrc)364 RtpPacketSinkInterface* 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;
371     AddSsrcSinkBinding(ssrc, sink);
372     return sink;
373   }
374   return nullptr;
375 }
376 
ResolveSinkByRsid(const std::string & rsid,uint32_t ssrc)377 RtpPacketSinkInterface* 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;
382     AddSsrcSinkBinding(ssrc, sink);
383     return sink;
384   }
385   return nullptr;
386 }
387 
ResolveSinkByPayloadType(uint8_t payload_type,uint32_t ssrc)388 RtpPacketSinkInterface* 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;
397       AddSsrcSinkBinding(ssrc, sink);
398       return sink;
399     }
400   }
401   return nullptr;
402 }
403 
AddSsrcSinkBinding(uint32_t ssrc,RtpPacketSinkInterface * sink)404 void RtpDemuxer::AddSsrcSinkBinding(uint32_t ssrc,
405                                     RtpPacketSinkInterface* sink) {
406   if (sink_by_ssrc_.size() >= kMaxSsrcBindings) {
407     RTC_LOG(LS_WARNING) << "New SSRC=" << ssrc
408                         << " sink binding ignored; limit of" << kMaxSsrcBindings
409                         << " bindings has been reached.";
410     return;
411   }
412 
413   auto result = sink_by_ssrc_.emplace(ssrc, sink);
414   auto it = result.first;
415   bool inserted = result.second;
416   if (inserted) {
417     RTC_LOG(LS_INFO) << "Added sink = " << sink
418                      << " binding with SSRC=" << ssrc;
419   } else if (it->second != sink) {
420     RTC_LOG(LS_INFO) << "Updated sink = " << sink
421                      << " binding with SSRC=" << ssrc;
422     it->second = sink;
423   }
424 }
425 
426 }  // namespace webrtc
427