rtp_config.cc (8289B)
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_config.h" 12 13 #include <algorithm> 14 #include <cstddef> 15 #include <cstdint> 16 #include <iterator> 17 #include <optional> 18 #include <string> 19 #include <vector> 20 21 #include "absl/algorithm/container.h" 22 #include "api/array_view.h" 23 #include "api/rtp_headers.h" 24 #include "rtc_base/checks.h" 25 #include "rtc_base/strings/string_builder.h" 26 27 namespace webrtc { 28 29 namespace { 30 31 uint32_t FindAssociatedSsrc(uint32_t ssrc, 32 const std::vector<uint32_t>& ssrcs, 33 const std::vector<uint32_t>& associated_ssrcs) { 34 RTC_DCHECK_EQ(ssrcs.size(), associated_ssrcs.size()); 35 for (size_t i = 0; i < ssrcs.size(); ++i) { 36 if (ssrcs[i] == ssrc) 37 return associated_ssrcs[i]; 38 } 39 RTC_DCHECK_NOTREACHED(); 40 return 0; 41 } 42 43 } // namespace 44 45 std::string LntfConfig::ToString() const { 46 return enabled ? "{enabled: true}" : "{enabled: false}"; 47 } 48 49 std::string NackConfig::ToString() const { 50 char buf[1024]; 51 SimpleStringBuilder ss(buf); 52 ss << "{rtp_history_ms: " << rtp_history_ms; 53 ss << '}'; 54 return ss.str(); 55 } 56 57 std::string UlpfecConfig::ToString() const { 58 char buf[1024]; 59 SimpleStringBuilder ss(buf); 60 ss << "{ulpfec_payload_type: " << ulpfec_payload_type; 61 ss << ", red_payload_type: " << red_payload_type; 62 ss << ", red_rtx_payload_type: " << red_rtx_payload_type; 63 ss << '}'; 64 return ss.str(); 65 } 66 67 bool UlpfecConfig::operator==(const UlpfecConfig& other) const { 68 return ulpfec_payload_type == other.ulpfec_payload_type && 69 red_payload_type == other.red_payload_type && 70 red_rtx_payload_type == other.red_rtx_payload_type; 71 } 72 73 std::string RtpStreamConfig::ToString() const { 74 char buf[1024]; 75 SimpleStringBuilder ss(buf); 76 ss << "{ssrc: " << ssrc; 77 ss << ", rid: " << rid; 78 ss << ", payload_name: " << payload_name; 79 ss << ", payload_type: " << payload_type; 80 ss << ", raw_payload: " << (raw_payload ? "true" : "false"); 81 if (rtx.has_value()) { 82 ss << ", rtx: " << rtx->ToString(); 83 } 84 ss << '}'; 85 return ss.str(); 86 } 87 88 std::string RtpStreamConfig::Rtx::ToString() const { 89 char buf[1024]; 90 SimpleStringBuilder ss(buf); 91 ss << "{ssrc: " << ssrc; 92 ss << ", payload_type: " << payload_type; 93 ss << '}'; 94 return ss.str(); 95 } 96 97 RtpConfig::RtpConfig() = default; 98 RtpConfig::RtpConfig(const RtpConfig&) = default; 99 RtpConfig::~RtpConfig() = default; 100 101 RtpConfig::Flexfec::Flexfec() = default; 102 RtpConfig::Flexfec::Flexfec(const Flexfec&) = default; 103 RtpConfig::Flexfec::~Flexfec() = default; 104 105 std::string RtpConfig::ToString() const { 106 char buf[2 * 1024]; 107 SimpleStringBuilder ss(buf); 108 ss << "{ssrcs: ["; 109 for (size_t i = 0; i < ssrcs.size(); ++i) { 110 ss << ssrcs[i]; 111 if (i != ssrcs.size() - 1) 112 ss << ", "; 113 } 114 ss << "], rids: ["; 115 for (size_t i = 0; i < rids.size(); ++i) { 116 ss << rids[i]; 117 if (i != rids.size() - 1) 118 ss << ", "; 119 } 120 ss << "], mid: '" << mid << "'"; 121 ss << ", rtcp_mode: " 122 << (rtcp_mode == RtcpMode::kCompound ? "RtcpMode::kCompound" 123 : "RtcpMode::kReducedSize"); 124 ss << ", max_packet_size: " << max_packet_size; 125 ss << ", extmap-allow-mixed: " << (extmap_allow_mixed ? "true" : "false"); 126 ss << ", extensions: ["; 127 for (size_t i = 0; i < extensions.size(); ++i) { 128 ss << extensions[i].ToString(); 129 if (i != extensions.size() - 1) 130 ss << ", "; 131 } 132 ss << ']'; 133 134 ss << ", lntf: " << lntf.ToString(); 135 ss << ", nack: {rtp_history_ms: " << nack.rtp_history_ms << '}'; 136 ss << ", ulpfec: " << ulpfec.ToString(); 137 ss << ", payload_name: " << payload_name; 138 ss << ", payload_type: " << payload_type; 139 ss << ", raw_payload: " << (raw_payload ? "true" : "false"); 140 141 ss << ", stream_configs: ["; 142 for (size_t i = 0; i < stream_configs.size(); ++i) { 143 ss << stream_configs[i].ToString(); 144 if (i != stream_configs.size() - 1) 145 ss << ", "; 146 } 147 ss << ']'; 148 149 ss << ", flexfec: {payload_type: " << flexfec.payload_type; 150 ss << ", ssrc: " << flexfec.ssrc; 151 ss << ", protected_media_ssrcs: ["; 152 for (size_t i = 0; i < flexfec.protected_media_ssrcs.size(); ++i) { 153 ss << flexfec.protected_media_ssrcs[i]; 154 if (i != flexfec.protected_media_ssrcs.size() - 1) 155 ss << ", "; 156 } 157 ss << "]}"; 158 159 ss << ", rtx: " << rtx.ToString(); 160 ss << ", c_name: " << c_name; 161 ss << '}'; 162 return ss.str(); 163 } 164 165 RtpConfig::Rtx::Rtx() = default; 166 RtpConfig::Rtx::Rtx(const Rtx&) = default; 167 RtpConfig::Rtx::~Rtx() = default; 168 169 std::string RtpConfig::Rtx::ToString() const { 170 char buf[1024]; 171 SimpleStringBuilder ss(buf); 172 ss << "{ssrcs: ["; 173 for (size_t i = 0; i < ssrcs.size(); ++i) { 174 ss << ssrcs[i]; 175 if (i != ssrcs.size() - 1) 176 ss << ", "; 177 } 178 ss << ']'; 179 180 ss << ", payload_type: " << payload_type; 181 ss << '}'; 182 return ss.str(); 183 } 184 185 bool RtpConfig::IsMediaSsrc(uint32_t ssrc) const { 186 return absl::c_linear_search(ssrcs, ssrc); 187 } 188 189 bool RtpConfig::IsRtxSsrc(uint32_t ssrc) const { 190 return absl::c_linear_search(rtx.ssrcs, ssrc); 191 } 192 193 bool RtpConfig::IsFlexfecSsrc(uint32_t ssrc) const { 194 return flexfec.payload_type != -1 && ssrc == flexfec.ssrc; 195 } 196 197 std::optional<uint32_t> RtpConfig::GetRtxSsrcAssociatedWithMediaSsrc( 198 uint32_t media_ssrc) const { 199 RTC_DCHECK(IsMediaSsrc(media_ssrc)); 200 // If we don't use RTX there is no association. 201 if (rtx.ssrcs.empty()) 202 return std::nullopt; 203 // If we use RTX there MUST be an association ssrcs[i] <-> rtx.ssrcs[i]. 204 RTC_DCHECK_EQ(ssrcs.size(), rtx.ssrcs.size()); 205 return FindAssociatedSsrc(media_ssrc, ssrcs, rtx.ssrcs); 206 } 207 208 uint32_t RtpConfig::GetMediaSsrcAssociatedWithRtxSsrc(uint32_t rtx_ssrc) const { 209 RTC_DCHECK(IsRtxSsrc(rtx_ssrc)); 210 // If we use RTX there MUST be an association ssrcs[i] <-> rtx.ssrcs[i]. 211 RTC_DCHECK_EQ(ssrcs.size(), rtx.ssrcs.size()); 212 return FindAssociatedSsrc(rtx_ssrc, rtx.ssrcs, ssrcs); 213 } 214 215 uint32_t RtpConfig::GetMediaSsrcAssociatedWithFlexfecSsrc( 216 uint32_t flexfec_ssrc) const { 217 RTC_DCHECK(IsFlexfecSsrc(flexfec_ssrc)); 218 // If we use FlexFEC there MUST be an associated media ssrc. 219 // 220 // TODO(brandtr/hbos): The current implementation only supports an association 221 // with a single media ssrc. If multiple ssrcs are to be supported in the 222 // future, in order not to break GetStats()'s packet and byte counters, we 223 // must be able to tell how many packets and bytes have contributed to which 224 // SSRC. 225 RTC_DCHECK_EQ(1u, flexfec.protected_media_ssrcs.size()); 226 uint32_t media_ssrc = flexfec.protected_media_ssrcs[0]; 227 RTC_DCHECK(IsMediaSsrc(media_ssrc)); 228 return media_ssrc; 229 } 230 231 std::optional<std::string> RtpConfig::GetRidForSsrc(uint32_t ssrc) const { 232 auto it = std::find(ssrcs.begin(), ssrcs.end(), ssrc); 233 if (it != ssrcs.end()) { 234 size_t ssrc_index = std::distance(ssrcs.begin(), it); 235 if (ssrc_index < rids.size()) { 236 return rids[ssrc_index]; 237 } 238 } 239 return std::nullopt; 240 } 241 242 RtpStreamConfig RtpConfig::GetStreamConfig(size_t index) const { 243 // GetStreamConfig function usually returns stream_configs[index], but if 244 // stream_configs is not initialized (i.e., index >= stream_configs.size()), 245 // it creates and returns an RtpStreamConfig using fields such as ssrcs, rids, 246 // payload_name, and payload_type from RtpConfig. 247 RTC_DCHECK_LT(index, ssrcs.size()); 248 if (index < stream_configs.size()) { 249 return stream_configs[index]; 250 } 251 RtpStreamConfig stream_config; 252 stream_config.ssrc = ssrcs[index]; 253 if (index < rids.size()) { 254 stream_config.rid = rids[index]; 255 } 256 stream_config.payload_name = payload_name; 257 stream_config.payload_type = payload_type; 258 stream_config.raw_payload = raw_payload; 259 if (!rtx.ssrcs.empty()) { 260 RTC_DCHECK_EQ(ssrcs.size(), rtx.ssrcs.size()); 261 auto& stream_config_rtx = stream_config.rtx.emplace(RtpStreamConfig::Rtx()); 262 stream_config_rtx.ssrc = rtx.ssrcs[index]; 263 stream_config_rtx.payload_type = rtx.payload_type; 264 } 265 266 return stream_config; 267 } 268 269 } // namespace webrtc