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