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