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 #ifndef CALL_RTP_DEMUXER_H_ 12 #define CALL_RTP_DEMUXER_H_ 13 14 #include <map> 15 #include <string> 16 #include <utility> 17 #include <vector> 18 19 #include "absl/strings/string_view.h" 20 #include "rtc_base/containers/flat_map.h" 21 #include "rtc_base/containers/flat_set.h" 22 23 namespace webrtc { 24 25 class RtpPacketReceived; 26 class RtpPacketSinkInterface; 27 28 // This struct describes the criteria that will be used to match packets to a 29 // specific sink. 30 class RtpDemuxerCriteria { 31 public: 32 explicit RtpDemuxerCriteria(absl::string_view mid, 33 absl::string_view rsid = absl::string_view()); 34 RtpDemuxerCriteria(); 35 ~RtpDemuxerCriteria(); 36 37 bool operator==(const RtpDemuxerCriteria& other) const; 38 bool operator!=(const RtpDemuxerCriteria& other) const; 39 40 // If not the empty string, will match packets with this MID. mid()41 const std::string& mid() const { return mid_; } 42 43 // Return string representation of demux criteria to facilitate logging 44 std::string ToString() const; 45 46 // If not the empty string, will match packets with this as their RTP stream 47 // ID or repaired RTP stream ID. 48 // Note that if both MID and RSID are specified, this will only match packets 49 // that have both specified (either through RTP header extensions, SSRC 50 // latching or RTCP). rsid()51 const std::string& rsid() const { return rsid_; } 52 53 // The criteria will match packets with any of these SSRCs. ssrcs()54 const flat_set<uint32_t>& ssrcs() const { return ssrcs_; } 55 56 // Writable accessor for directly modifying the list of ssrcs. ssrcs()57 flat_set<uint32_t>& ssrcs() { return ssrcs_; } 58 59 // The criteria will match packets with any of these payload types. payload_types()60 const flat_set<uint8_t>& payload_types() const { return payload_types_; } 61 62 // Writable accessor for directly modifying the list of payload types. payload_types()63 flat_set<uint8_t>& payload_types() { return payload_types_; } 64 65 private: 66 // Intentionally private member variables to encourage specifying them via the 67 // constructor and consider them to be const as much as possible. 68 const std::string mid_; 69 const std::string rsid_; 70 flat_set<uint32_t> ssrcs_; 71 flat_set<uint8_t> payload_types_; 72 }; 73 74 // This class represents the RTP demuxing, for a single RTP session (i.e., one 75 // SSRC space, see RFC 7656). It isn't thread aware, leaving responsibility of 76 // multithreading issues to the user of this class. 77 // The demuxing algorithm follows the sketch given in the BUNDLE draft: 78 // https://tools.ietf.org/html/draft-ietf-mmusic-sdp-bundle-negotiation-38#section-10.2 79 // with modifications to support RTP stream IDs also. 80 // 81 // When a packet is received, the RtpDemuxer will route according to the 82 // following rules: 83 // 1. If the packet contains the MID header extension, and no sink has been 84 // added with that MID as a criteria, the packet is not routed. 85 // 2. If the packet has the MID header extension, but no RSID or RRID extension, 86 // and the MID is bound to a sink, then bind its SSRC to the same sink and 87 // forward the packet to that sink. Note that rebinding to the same sink is 88 // not an error. (Later packets with that SSRC would therefore be forwarded 89 // to the same sink, whether they have the MID header extension or not.) 90 // 3. If the packet has the MID header extension and either the RSID or RRID 91 // extension, and the MID, RSID (or RRID) pair is bound to a sink, then bind 92 // its SSRC to the same sink and forward the packet to that sink. Later 93 // packets with that SSRC will be forwarded to the same sink. 94 // 4. If the packet has the RSID or RRID header extension, but no MID extension, 95 // and the RSID or RRID is bound to an RSID sink, then bind its SSRC to the 96 // same sink and forward the packet to that sink. Later packets with that 97 // SSRC will be forwarded to the same sink. 98 // 5. If the packet's SSRC is bound to an SSRC through a previous call to 99 // AddSink, then forward the packet to that sink. Note that the RtpDemuxer 100 // will not verify the payload type even if included in the sink's criteria. 101 // The sink is expected to do the check in its handler. 102 // 6. If the packet's payload type is bound to exactly one payload type sink 103 // through an earlier call to AddSink, then forward the packet to that sink. 104 // 7. Otherwise, the packet is not routed. 105 // 106 // In summary, the routing algorithm will always try to first match MID and RSID 107 // (including through SSRC binding), match SSRC directly as needed, and use 108 // payload types only if all else fails. 109 class RtpDemuxer { 110 public: 111 // Maximum number of unique SSRC bindings allowed. This limit is to prevent 112 // memory overuse attacks due to a malicious peer sending many packets with 113 // different SSRCs. 114 static constexpr int kMaxSsrcBindings = 1000; 115 116 // Returns a string that contains all the attributes of the given packet 117 // relevant for demuxing. 118 static std::string DescribePacket(const RtpPacketReceived& packet); 119 120 explicit RtpDemuxer(bool use_mid = true); 121 ~RtpDemuxer(); 122 123 RtpDemuxer(const RtpDemuxer&) = delete; 124 void operator=(const RtpDemuxer&) = delete; 125 126 // Registers a sink that will be notified when RTP packets match its given 127 // criteria according to the algorithm described in the class description. 128 // Returns true if the sink was successfully added. 129 // Returns false in the following situations: 130 // - Only MID is specified and the MID is already registered. 131 // - Only RSID is specified and the RSID is already registered. 132 // - Both MID and RSID is specified and the (MID, RSID) pair is already 133 // registered. 134 // - Any of the criteria SSRCs are already registered. 135 // If false is returned, no changes are made to the demuxer state. 136 bool AddSink(const RtpDemuxerCriteria& criteria, 137 RtpPacketSinkInterface* sink); 138 139 // Registers a sink. Multiple SSRCs may be mapped to the same sink, but 140 // each SSRC may only be mapped to one sink. The return value reports 141 // whether the association has been recorded or rejected. Rejection may occur 142 // if the SSRC has already been associated with a sink. The previously added 143 // sink is *not* forgotten. 144 bool AddSink(uint32_t ssrc, RtpPacketSinkInterface* sink); 145 146 // Registers a sink's association to an RSID. Only one sink may be associated 147 // with a given RSID. Null pointer is not allowed. 148 void AddSink(absl::string_view rsid, RtpPacketSinkInterface* sink); 149 150 // Removes a sink. Return value reports if anything was actually removed. 151 // Null pointer is not allowed. 152 bool RemoveSink(const RtpPacketSinkInterface* sink); 153 154 // Demuxes the given packet and forwards it to the chosen sink. Returns true 155 // if the packet was forwarded and false if the packet was dropped. 156 bool OnRtpPacket(const RtpPacketReceived& packet); 157 158 private: 159 // Returns true if adding a sink with the given criteria would cause conflicts 160 // with the existing criteria and should be rejected. 161 bool CriteriaWouldConflict(const RtpDemuxerCriteria& criteria) const; 162 163 // Runs the demux algorithm on the given packet and returns the sink that 164 // should receive the packet. 165 // Will record any SSRC<->ID associations along the way. 166 // If the packet should be dropped, this method returns null. 167 RtpPacketSinkInterface* ResolveSink(const RtpPacketReceived& packet); 168 169 // Used by the ResolveSink algorithm. 170 RtpPacketSinkInterface* ResolveSinkByMid(absl::string_view mid, 171 uint32_t ssrc); 172 RtpPacketSinkInterface* ResolveSinkByMidRsid(absl::string_view mid, 173 absl::string_view rsid, 174 uint32_t ssrc); 175 RtpPacketSinkInterface* ResolveSinkByRsid(absl::string_view rsid, 176 uint32_t ssrc); 177 RtpPacketSinkInterface* ResolveSinkByPayloadType(uint8_t payload_type, 178 uint32_t ssrc); 179 180 // Regenerate the known_mids_ set from information in the sink_by_mid_ and 181 // sink_by_mid_and_rsid_ maps. 182 void RefreshKnownMids(); 183 184 // Map each sink by its component attributes to facilitate quick lookups. 185 // Payload Type mapping is a multimap because if two sinks register for the 186 // same payload type, both AddSinks succeed but we must know not to demux on 187 // that attribute since it is ambiguous. 188 // Note: Mappings are only modified by AddSink/RemoveSink (except for 189 // SSRC mapping which receives all MID, payload type, or RSID to SSRC bindings 190 // discovered when demuxing packets). 191 flat_map<std::string, RtpPacketSinkInterface*> sink_by_mid_; 192 flat_map<uint32_t, RtpPacketSinkInterface*> sink_by_ssrc_; 193 std::multimap<uint8_t, RtpPacketSinkInterface*> sinks_by_pt_; 194 flat_map<std::pair<std::string, std::string>, RtpPacketSinkInterface*> 195 sink_by_mid_and_rsid_; 196 flat_map<std::string, RtpPacketSinkInterface*> sink_by_rsid_; 197 198 // Tracks all the MIDs that have been identified in added criteria. Used to 199 // determine if a packet should be dropped right away because the MID is 200 // unknown. 201 flat_set<std::string> known_mids_; 202 203 // Records learned mappings of MID --> SSRC and RSID --> SSRC as packets are 204 // received. 205 // This is stored separately from the sink mappings because if a sink is 206 // removed we want to still remember these associations. 207 flat_map<uint32_t, std::string> mid_by_ssrc_; 208 flat_map<uint32_t, std::string> rsid_by_ssrc_; 209 210 // Adds a binding from the SSRC to the given sink. 211 void AddSsrcSinkBinding(uint32_t ssrc, RtpPacketSinkInterface* sink); 212 213 const bool use_mid_; 214 }; 215 216 } // namespace webrtc 217 218 #endif // CALL_RTP_DEMUXER_H_ 219