nisse | e4bcd6d | 2017-05-16 11:47:04 | [diff] [blame] | 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 | */ |
eladalon | d0244c2 | 2017-06-08 11:19:13 | [diff] [blame] | 10 | |
Mirko Bonadei | 92ea95e | 2017-09-15 04:47:31 | [diff] [blame] | 11 | #ifndef CALL_RTP_DEMUXER_H_ |
| 12 | #define CALL_RTP_DEMUXER_H_ |
nisse | e4bcd6d | 2017-05-16 11:47:04 | [diff] [blame] | 13 | |
| 14 | #include <map> |
eladalon | d0244c2 | 2017-06-08 11:19:13 | [diff] [blame] | 15 | #include <string> |
Steve Anton | 53c7ba6 | 2017-08-18 17:05:47 | [diff] [blame] | 16 | #include <utility> |
eladalon | a52722f | 2017-06-26 18:23:54 | [diff] [blame] | 17 | #include <vector> |
nisse | e4bcd6d | 2017-05-16 11:47:04 | [diff] [blame] | 18 | |
Tomas Gunnarsson | c3795ff | 2022-01-03 13:04:51 | [diff] [blame] | 19 | #include "absl/strings/string_view.h" |
Victor Boivie | ac5f2e7 | 2021-07-01 19:42:02 | [diff] [blame] | 20 | #include "rtc_base/containers/flat_map.h" |
| 21 | #include "rtc_base/containers/flat_set.h" |
| 22 | |
nisse | e4bcd6d | 2017-05-16 11:47:04 | [diff] [blame] | 23 | namespace webrtc { |
| 24 | |
| 25 | class RtpPacketReceived; |
nisse | d76b7b2 | 2017-06-01 11:02:35 | [diff] [blame] | 26 | class RtpPacketSinkInterface; |
nisse | e4bcd6d | 2017-05-16 11:47:04 | [diff] [blame] | 27 | |
Steve Anton | 53c7ba6 | 2017-08-18 17:05:47 | [diff] [blame] | 28 | // This struct describes the criteria that will be used to match packets to a |
| 29 | // specific sink. |
Tomas Gunnarsson | 8a5ac16 | 2022-01-03 14:16:46 | [diff] [blame] | 30 | class RtpDemuxerCriteria { |
| 31 | public: |
Tomas Gunnarsson | c3795ff | 2022-01-03 13:04:51 | [diff] [blame] | 32 | explicit RtpDemuxerCriteria(absl::string_view mid, |
| 33 | absl::string_view rsid = absl::string_view()); |
Steve Anton | 53c7ba6 | 2017-08-18 17:05:47 | [diff] [blame] | 34 | RtpDemuxerCriteria(); |
| 35 | ~RtpDemuxerCriteria(); |
| 36 | |
Henrik Boström | 15e078c | 2021-04-16 07:54:18 | [diff] [blame] | 37 | bool operator==(const RtpDemuxerCriteria& other) const; |
| 38 | bool operator!=(const RtpDemuxerCriteria& other) const; |
| 39 | |
Steve Anton | 53c7ba6 | 2017-08-18 17:05:47 | [diff] [blame] | 40 | // If not the empty string, will match packets with this MID. |
Tomas Gunnarsson | 8a5ac16 | 2022-01-03 14:16:46 | [diff] [blame] | 41 | const std::string& mid() const { return mid_; } |
| 42 | |
| 43 | // Return string representation of demux criteria to facilitate logging |
| 44 | std::string ToString() const; |
Steve Anton | 53c7ba6 | 2017-08-18 17:05:47 | [diff] [blame] | 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). |
Tomas Gunnarsson | 8a5ac16 | 2022-01-03 14:16:46 | [diff] [blame] | 51 | const std::string& rsid() const { return rsid_; } |
Steve Anton | 53c7ba6 | 2017-08-18 17:05:47 | [diff] [blame] | 52 | |
Tomas Gunnarsson | 8a5ac16 | 2022-01-03 14:16:46 | [diff] [blame] | 53 | // The criteria will match packets with any of these SSRCs. |
| 54 | const flat_set<uint32_t>& ssrcs() const { return ssrcs_; } |
Steve Anton | 53c7ba6 | 2017-08-18 17:05:47 | [diff] [blame] | 55 | |
Tomas Gunnarsson | 8a5ac16 | 2022-01-03 14:16:46 | [diff] [blame] | 56 | // Writable accessor for directly modifying the list of ssrcs. |
| 57 | flat_set<uint32_t>& ssrcs() { return ssrcs_; } |
Yura Yaroshevich | 49a5e3e | 2020-05-16 11:30:59 | [diff] [blame] | 58 | |
Tomas Gunnarsson | 8a5ac16 | 2022-01-03 14:16:46 | [diff] [blame] | 59 | // The criteria will match packets with any of these 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. |
| 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. |
Tomas Gunnarsson | 9abd74d | 2022-01-04 17:21:54 | [diff] [blame] | 68 | const std::string mid_; |
| 69 | const std::string rsid_; |
Tomas Gunnarsson | 8a5ac16 | 2022-01-03 14:16:46 | [diff] [blame] | 70 | flat_set<uint32_t> ssrcs_; |
| 71 | flat_set<uint8_t> payload_types_; |
Steve Anton | 53c7ba6 | 2017-08-18 17:05:47 | [diff] [blame] | 72 | }; |
| 73 | |
nisse | e4bcd6d | 2017-05-16 11:47:04 | [diff] [blame] | 74 | // This class represents the RTP demuxing, for a single RTP session (i.e., one |
Steve Anton | 53c7ba6 | 2017-08-18 17:05:47 | [diff] [blame] | 75 | // SSRC space, see RFC 7656). It isn't thread aware, leaving responsibility of |
nisse | e4bcd6d | 2017-05-16 11:47:04 | [diff] [blame] | 76 | // multithreading issues to the user of this class. |
Steve Anton | 53c7ba6 | 2017-08-18 17:05:47 | [diff] [blame] | 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. |
nisse | e4bcd6d | 2017-05-16 11:47:04 | [diff] [blame] | 109 | class RtpDemuxer { |
| 110 | public: |
Steve Anton | 53c7ba6 | 2017-08-18 17:05:47 | [diff] [blame] | 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 | |
Steve Anton | 884adca | 2019-04-15 23:52:27 | [diff] [blame] | 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 | |
Tomas Gunnarsson | e091fd2 | 2021-01-17 15:14:52 | [diff] [blame] | 120 | explicit RtpDemuxer(bool use_mid = true); |
nisse | e4bcd6d | 2017-05-16 11:47:04 | [diff] [blame] | 121 | ~RtpDemuxer(); |
| 122 | |
Steve Anton | 53c7ba6 | 2017-08-18 17:05:47 | [diff] [blame] | 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 | |
eladalon | 5daecca | 2017-08-04 13:34:54 | [diff] [blame] | 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); |
eladalon | d0244c2 | 2017-06-08 11:19:13 | [diff] [blame] | 145 | |
eladalon | 5daecca | 2017-08-04 13:34:54 | [diff] [blame] | 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. |
Ali Tofigh | 641a1b1 | 2022-05-17 09:48:46 | [diff] [blame] | 148 | void AddSink(absl::string_view rsid, RtpPacketSinkInterface* sink); |
eladalon | d0244c2 | 2017-06-08 11:19:13 | [diff] [blame] | 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); |
nisse | e4bcd6d | 2017-05-16 11:47:04 | [diff] [blame] | 153 | |
Philipp Hancke | 977b56c | 2023-11-08 09:20:51 | [diff] [blame] | 154 | // Returns the set of SSRCs associated with a sink. |
| 155 | flat_set<uint32_t> GetSsrcsForSink(const RtpPacketSinkInterface* sink) const; |
| 156 | |
Steve Anton | 53c7ba6 | 2017-08-18 17:05:47 | [diff] [blame] | 157 | // Demuxes the given packet and forwards it to the chosen sink. Returns true |
| 158 | // if the packet was forwarded and false if the packet was dropped. |
nisse | e4bcd6d | 2017-05-16 11:47:04 | [diff] [blame] | 159 | bool OnRtpPacket(const RtpPacketReceived& packet); |
| 160 | |
| 161 | private: |
Steve Anton | 53c7ba6 | 2017-08-18 17:05:47 | [diff] [blame] | 162 | // Returns true if adding a sink with the given criteria would cause conflicts |
| 163 | // with the existing criteria and should be rejected. |
| 164 | bool CriteriaWouldConflict(const RtpDemuxerCriteria& criteria) const; |
eladalon | a52722f | 2017-06-26 18:23:54 | [diff] [blame] | 165 | |
Steve Anton | 53c7ba6 | 2017-08-18 17:05:47 | [diff] [blame] | 166 | // Runs the demux algorithm on the given packet and returns the sink that |
| 167 | // should receive the packet. |
| 168 | // Will record any SSRC<->ID associations along the way. |
| 169 | // If the packet should be dropped, this method returns null. |
| 170 | RtpPacketSinkInterface* ResolveSink(const RtpPacketReceived& packet); |
eladalon | d0244c2 | 2017-06-08 11:19:13 | [diff] [blame] | 171 | |
Steve Anton | 53c7ba6 | 2017-08-18 17:05:47 | [diff] [blame] | 172 | // Used by the ResolveSink algorithm. |
Ali Tofigh | 641a1b1 | 2022-05-17 09:48:46 | [diff] [blame] | 173 | RtpPacketSinkInterface* ResolveSinkByMid(absl::string_view mid, |
Steve Anton | 53c7ba6 | 2017-08-18 17:05:47 | [diff] [blame] | 174 | uint32_t ssrc); |
Ali Tofigh | 641a1b1 | 2022-05-17 09:48:46 | [diff] [blame] | 175 | RtpPacketSinkInterface* ResolveSinkByMidRsid(absl::string_view mid, |
| 176 | absl::string_view rsid, |
Steve Anton | 53c7ba6 | 2017-08-18 17:05:47 | [diff] [blame] | 177 | uint32_t ssrc); |
Ali Tofigh | 641a1b1 | 2022-05-17 09:48:46 | [diff] [blame] | 178 | RtpPacketSinkInterface* ResolveSinkByRsid(absl::string_view rsid, |
Steve Anton | 53c7ba6 | 2017-08-18 17:05:47 | [diff] [blame] | 179 | uint32_t ssrc); |
| 180 | RtpPacketSinkInterface* ResolveSinkByPayloadType(uint8_t payload_type, |
| 181 | uint32_t ssrc); |
eladalon | d0244c2 | 2017-06-08 11:19:13 | [diff] [blame] | 182 | |
Steve Anton | 53c7ba6 | 2017-08-18 17:05:47 | [diff] [blame] | 183 | // Regenerate the known_mids_ set from information in the sink_by_mid_ and |
| 184 | // sink_by_mid_and_rsid_ maps. |
| 185 | void RefreshKnownMids(); |
| 186 | |
| 187 | // Map each sink by its component attributes to facilitate quick lookups. |
| 188 | // Payload Type mapping is a multimap because if two sinks register for the |
| 189 | // same payload type, both AddSinks succeed but we must know not to demux on |
| 190 | // that attribute since it is ambiguous. |
| 191 | // Note: Mappings are only modified by AddSink/RemoveSink (except for |
| 192 | // SSRC mapping which receives all MID, payload type, or RSID to SSRC bindings |
| 193 | // discovered when demuxing packets). |
Victor Boivie | ac5f2e7 | 2021-07-01 19:42:02 | [diff] [blame] | 194 | flat_map<std::string, RtpPacketSinkInterface*> sink_by_mid_; |
| 195 | flat_map<uint32_t, RtpPacketSinkInterface*> sink_by_ssrc_; |
Victor Boivie | fade919 | 2021-05-25 11:34:07 | [diff] [blame] | 196 | std::multimap<uint8_t, RtpPacketSinkInterface*> sinks_by_pt_; |
Victor Boivie | ac5f2e7 | 2021-07-01 19:42:02 | [diff] [blame] | 197 | flat_map<std::pair<std::string, std::string>, RtpPacketSinkInterface*> |
Steve Anton | 53c7ba6 | 2017-08-18 17:05:47 | [diff] [blame] | 198 | sink_by_mid_and_rsid_; |
Victor Boivie | ac5f2e7 | 2021-07-01 19:42:02 | [diff] [blame] | 199 | flat_map<std::string, RtpPacketSinkInterface*> sink_by_rsid_; |
Steve Anton | 53c7ba6 | 2017-08-18 17:05:47 | [diff] [blame] | 200 | |
| 201 | // Tracks all the MIDs that have been identified in added criteria. Used to |
| 202 | // determine if a packet should be dropped right away because the MID is |
| 203 | // unknown. |
Victor Boivie | ac5f2e7 | 2021-07-01 19:42:02 | [diff] [blame] | 204 | flat_set<std::string> known_mids_; |
Steve Anton | 53c7ba6 | 2017-08-18 17:05:47 | [diff] [blame] | 205 | |
| 206 | // Records learned mappings of MID --> SSRC and RSID --> SSRC as packets are |
| 207 | // received. |
| 208 | // This is stored separately from the sink mappings because if a sink is |
| 209 | // removed we want to still remember these associations. |
Victor Boivie | ac5f2e7 | 2021-07-01 19:42:02 | [diff] [blame] | 210 | flat_map<uint32_t, std::string> mid_by_ssrc_; |
| 211 | flat_map<uint32_t, std::string> rsid_by_ssrc_; |
Steve Anton | 53c7ba6 | 2017-08-18 17:05:47 | [diff] [blame] | 212 | |
Danil Chapovalov | 8fddf1f | 2020-07-08 16:32:52 | [diff] [blame] | 213 | // Adds a binding from the SSRC to the given sink. |
| 214 | void AddSsrcSinkBinding(uint32_t ssrc, RtpPacketSinkInterface* sink); |
Steve Anton | ed09dc6 | 2018-03-29 19:59:17 | [diff] [blame] | 215 | |
Tomas Gunnarsson | e091fd2 | 2021-01-17 15:14:52 | [diff] [blame] | 216 | const bool use_mid_; |
nisse | e4bcd6d | 2017-05-16 11:47:04 | [diff] [blame] | 217 | }; |
| 218 | |
| 219 | } // namespace webrtc |
| 220 | |
Mirko Bonadei | 92ea95e | 2017-09-15 04:47:31 | [diff] [blame] | 221 | #endif // CALL_RTP_DEMUXER_H_ |