media_engine.cc (12957B)
1 /* 2 * Copyright (c) 2004 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 "media/base/media_engine.h" 12 13 #include <cstddef> 14 #include <cstdint> 15 #include <memory> 16 #include <optional> 17 #include <string> 18 #include <utility> 19 #include <vector> 20 21 #include "absl/algorithm/container.h" 22 #include "api/array_view.h" 23 #include "api/field_trials_view.h" 24 #include "api/rtc_error.h" 25 #include "api/rtp_headers.h" 26 #include "api/rtp_parameters.h" 27 #include "api/rtp_transceiver_direction.h" 28 #include "api/video/video_codec_constants.h" 29 #include "api/video_codecs/scalability_mode.h" 30 #include "media/base/codec.h" 31 #include "media/base/codec_comparators.h" 32 #include "media/base/rid_description.h" 33 #include "media/base/stream_params.h" 34 #include "rtc_base/checks.h" 35 36 namespace webrtc { 37 namespace { 38 bool SupportsMode(const Codec& codec, 39 std::optional<std::string> scalability_mode) { 40 if (!scalability_mode.has_value()) { 41 return true; 42 } 43 return absl::c_any_of(codec.scalability_modes, [&](ScalabilityMode mode) { 44 return ScalabilityModeToString(mode) == *scalability_mode; 45 }); 46 } 47 48 } // namespace 49 50 RtpParameters CreateRtpParametersWithOneEncoding() { 51 RtpParameters parameters; 52 RtpEncodingParameters encoding; 53 parameters.encodings.push_back(encoding); 54 return parameters; 55 } 56 57 RtpParameters CreateRtpParametersWithEncodings(StreamParams sp) { 58 std::vector<uint32_t> primary_ssrcs; 59 sp.GetPrimarySsrcs(&primary_ssrcs); 60 size_t encoding_count = primary_ssrcs.size(); 61 62 std::vector<RtpEncodingParameters> encodings(encoding_count); 63 for (size_t i = 0; i < encodings.size(); ++i) { 64 encodings[i].ssrc = primary_ssrcs[i]; 65 } 66 67 const std::vector<RidDescription>& rids = sp.rids(); 68 RTC_DCHECK(rids.empty() || rids.size() == encoding_count); 69 for (size_t i = 0; i < rids.size(); ++i) { 70 encodings[i].rid = rids[i].rid; 71 } 72 73 RtpParameters parameters; 74 parameters.encodings = encodings; 75 parameters.rtcp.cname = sp.cname; 76 return parameters; 77 } 78 79 std::vector<RtpExtension> GetDefaultEnabledRtpHeaderExtensions( 80 const RtpHeaderExtensionQueryInterface& query_interface, 81 const webrtc::FieldTrialsView* field_trials) { 82 std::vector<RtpExtension> extensions; 83 for (const auto& entry : 84 query_interface.GetRtpHeaderExtensions(field_trials)) { 85 if (entry.direction != RtpTransceiverDirection::kStopped) 86 extensions.emplace_back(entry.uri, *entry.preferred_id); 87 } 88 return extensions; 89 } 90 91 RTCError CheckScalabilityModeValues(const RtpParameters& rtp_parameters, 92 ArrayView<Codec> send_codecs, 93 std::optional<Codec> send_codec) { 94 if (send_codecs.empty()) { 95 // This is an audio sender or an extra check in the stack where the codec 96 // list is not available and we can't check the scalability_mode values. 97 return RTCError::OK(); 98 } 99 100 for (size_t i = 0; i < rtp_parameters.encodings.size(); ++i) { 101 if (rtp_parameters.encodings[i].codec) { 102 bool codecFound = false; 103 for (const Codec& codec : send_codecs) { 104 if (IsSameRtpCodecIgnoringLevel(codec, 105 *rtp_parameters.encodings[i].codec) && 106 SupportsMode(codec, rtp_parameters.encodings[i].scalability_mode)) { 107 codecFound = true; 108 send_codec = codec; 109 break; 110 } 111 } 112 if (!codecFound) { 113 LOG_AND_RETURN_ERROR( 114 RTCErrorType::INVALID_MODIFICATION, 115 "Attempted to use an unsupported codec for layer " + 116 std::to_string(i)); 117 } 118 } 119 if (rtp_parameters.encodings[i].scalability_mode) { 120 if (!send_codec) { 121 bool scalabilityModeFound = false; 122 for (const Codec& codec : send_codecs) { 123 for (const auto& scalability_mode : codec.scalability_modes) { 124 if (ScalabilityModeToString(scalability_mode) == 125 *rtp_parameters.encodings[i].scalability_mode) { 126 scalabilityModeFound = true; 127 break; 128 } 129 } 130 if (scalabilityModeFound) 131 break; 132 } 133 134 if (!scalabilityModeFound) { 135 LOG_AND_RETURN_ERROR( 136 RTCErrorType::INVALID_MODIFICATION, 137 "Attempted to set RtpParameters scalabilityMode " 138 "to an unsupported value for the current codecs."); 139 } 140 } else { 141 bool scalabilityModeFound = false; 142 for (const auto& scalability_mode : send_codec->scalability_modes) { 143 if (ScalabilityModeToString(scalability_mode) == 144 *rtp_parameters.encodings[i].scalability_mode) { 145 scalabilityModeFound = true; 146 break; 147 } 148 } 149 if (!scalabilityModeFound) { 150 LOG_AND_RETURN_ERROR( 151 RTCErrorType::INVALID_MODIFICATION, 152 "Attempted to set RtpParameters scalabilityMode " 153 "to an unsupported value for the current codecs."); 154 } 155 } 156 } 157 } 158 159 return RTCError::OK(); 160 } 161 162 RTCError CheckRtpParametersValues(const RtpParameters& rtp_parameters, 163 ArrayView<Codec> send_codecs, 164 std::optional<Codec> send_codec, 165 const FieldTrialsView& field_trials) { 166 bool has_scale_resolution_down_to = false; 167 for (size_t i = 0; i < rtp_parameters.encodings.size(); ++i) { 168 if (rtp_parameters.encodings[i].bitrate_priority <= 0) { 169 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_RANGE, 170 "Attempted to set RtpParameters bitrate_priority to " 171 "an invalid number. bitrate_priority must be > 0."); 172 } 173 if (rtp_parameters.encodings[i].scale_resolution_down_by && 174 *rtp_parameters.encodings[i].scale_resolution_down_by < 1.0) { 175 LOG_AND_RETURN_ERROR( 176 RTCErrorType::INVALID_RANGE, 177 "Attempted to set RtpParameters scale_resolution_down_by to an " 178 "invalid value. scale_resolution_down_by must be >= 1.0"); 179 } 180 if (rtp_parameters.encodings[i].max_framerate && 181 *rtp_parameters.encodings[i].max_framerate < 0.0) { 182 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_RANGE, 183 "Attempted to set RtpParameters max_framerate to an " 184 "invalid value. max_framerate must be >= 0.0"); 185 } 186 if (rtp_parameters.encodings[i].min_bitrate_bps && 187 rtp_parameters.encodings[i].max_bitrate_bps) { 188 if (*rtp_parameters.encodings[i].max_bitrate_bps < 189 *rtp_parameters.encodings[i].min_bitrate_bps) { 190 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_RANGE, 191 "Attempted to set RtpParameters min bitrate " 192 "larger than max bitrate."); 193 } 194 } 195 if (rtp_parameters.encodings[i].num_temporal_layers) { 196 if (*rtp_parameters.encodings[i].num_temporal_layers < 1 || 197 *rtp_parameters.encodings[i].num_temporal_layers > 198 kMaxTemporalStreams) { 199 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_RANGE, 200 "Attempted to set RtpParameters " 201 "num_temporal_layers to an invalid number."); 202 } 203 } 204 205 if (rtp_parameters.encodings[i].scale_resolution_down_to.has_value()) { 206 has_scale_resolution_down_to = true; 207 if (rtp_parameters.encodings[i].scale_resolution_down_to->width <= 0 || 208 rtp_parameters.encodings[i].scale_resolution_down_to->height <= 0) { 209 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_MODIFICATION, 210 "The resolution dimensions must be positive."); 211 } 212 } 213 214 if (!field_trials.IsEnabled("WebRTC-MixedCodecSimulcast")) { 215 if (i > 0 && rtp_parameters.encodings[i - 1].codec != 216 rtp_parameters.encodings[i].codec) { 217 LOG_AND_RETURN_ERROR(RTCErrorType::UNSUPPORTED_OPERATION, 218 "Attempted to use different codec values for " 219 "different encodings."); 220 } 221 } 222 223 if (rtp_parameters.encodings[i].csrcs.has_value() && 224 rtp_parameters.encodings[i].csrcs.value().size() > kRtpCsrcSize) { 225 LOG_AND_RETURN_ERROR( 226 RTCErrorType::INVALID_RANGE, 227 "Attempted to set more than the maximum allowed number of CSRCs.") 228 } 229 230 if (i > 0 && rtp_parameters.encodings[i - 1].csrcs != 231 rtp_parameters.encodings[i].csrcs) { 232 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_MODIFICATION, 233 "Attempted to set different CSRCs for different " 234 "encodings."); 235 } 236 } 237 238 if (has_scale_resolution_down_to && 239 absl::c_any_of(rtp_parameters.encodings, 240 [](const RtpEncodingParameters& encoding) { 241 return encoding.active && 242 !encoding.scale_resolution_down_to.has_value(); 243 })) { 244 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_MODIFICATION, 245 "If a resolution is specified on any encoding then " 246 "it must be specified on all encodings."); 247 } 248 249 return CheckScalabilityModeValues(rtp_parameters, send_codecs, send_codec); 250 } 251 252 RTCError CheckRtpParametersInvalidModificationAndValues( 253 const RtpParameters& old_rtp_parameters, 254 const RtpParameters& rtp_parameters, 255 const FieldTrialsView& field_trials) { 256 return CheckRtpParametersInvalidModificationAndValues( 257 old_rtp_parameters, rtp_parameters, {}, std::nullopt, field_trials); 258 } 259 260 RTCError CheckRtpParametersInvalidModificationAndValues( 261 const RtpParameters& old_rtp_parameters, 262 const RtpParameters& rtp_parameters, 263 ArrayView<Codec> send_codecs, 264 std::optional<Codec> send_codec, 265 const FieldTrialsView& field_trials) { 266 if (rtp_parameters.encodings.size() != old_rtp_parameters.encodings.size()) { 267 LOG_AND_RETURN_ERROR( 268 RTCErrorType::INVALID_MODIFICATION, 269 "Attempted to set RtpParameters with different encoding count"); 270 } 271 if (rtp_parameters.rtcp != old_rtp_parameters.rtcp) { 272 LOG_AND_RETURN_ERROR( 273 RTCErrorType::INVALID_MODIFICATION, 274 "Attempted to set RtpParameters with modified RTCP parameters"); 275 } 276 if (rtp_parameters.header_extensions != 277 old_rtp_parameters.header_extensions) { 278 LOG_AND_RETURN_ERROR( 279 RTCErrorType::INVALID_MODIFICATION, 280 "Attempted to set RtpParameters with modified header extensions"); 281 } 282 if (!absl::c_equal(old_rtp_parameters.encodings, rtp_parameters.encodings, 283 [](const RtpEncodingParameters& encoding1, 284 const RtpEncodingParameters& encoding2) { 285 return encoding1.rid == encoding2.rid; 286 })) { 287 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_MODIFICATION, 288 "Attempted to change RID values in the encodings."); 289 } 290 if (!absl::c_equal(old_rtp_parameters.encodings, rtp_parameters.encodings, 291 [](const RtpEncodingParameters& encoding1, 292 const RtpEncodingParameters& encoding2) { 293 return encoding1.ssrc == encoding2.ssrc; 294 })) { 295 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_MODIFICATION, 296 "Attempted to set RtpParameters with modified SSRC"); 297 } 298 299 return CheckRtpParametersValues(rtp_parameters, send_codecs, send_codec, 300 field_trials); 301 } 302 303 CompositeMediaEngine::CompositeMediaEngine( 304 std::unique_ptr<FieldTrialsView> trials, 305 std::unique_ptr<VoiceEngineInterface> audio_engine, 306 std::unique_ptr<VideoEngineInterface> video_engine) 307 : trials_(std::move(trials)), 308 voice_engine_(std::move(audio_engine)), 309 video_engine_(std::move(video_engine)) {} 310 311 CompositeMediaEngine::CompositeMediaEngine( 312 std::unique_ptr<VoiceEngineInterface> audio_engine, 313 std::unique_ptr<VideoEngineInterface> video_engine) 314 : CompositeMediaEngine(nullptr, 315 std::move(audio_engine), 316 std::move(video_engine)) {} 317 318 CompositeMediaEngine::~CompositeMediaEngine() = default; 319 320 bool CompositeMediaEngine::Init() { 321 voice().Init(); 322 return true; 323 } 324 325 VoiceEngineInterface& CompositeMediaEngine::voice() { 326 return *voice_engine_; 327 } 328 329 VideoEngineInterface& CompositeMediaEngine::video() { 330 return *video_engine_; 331 } 332 333 const VoiceEngineInterface& CompositeMediaEngine::voice() const { 334 return *voice_engine_; 335 } 336 337 const VideoEngineInterface& CompositeMediaEngine::video() const { 338 return *video_engine_; 339 } 340 341 } // namespace webrtc