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 <stddef.h>
14
15 #include <cstdint>
16 #include <string>
17 #include <utility>
18
19 #include "absl/algorithm/container.h"
20 #include "api/video/video_bitrate_allocation.h"
21 #include "rtc_base/checks.h"
22 #include "rtc_base/string_encode.h"
23
24 namespace cricket {
25
26 RtpCapabilities::RtpCapabilities() = default;
27 RtpCapabilities::~RtpCapabilities() = default;
28
CreateRtpParametersWithOneEncoding()29 webrtc::RtpParameters CreateRtpParametersWithOneEncoding() {
30 webrtc::RtpParameters parameters;
31 webrtc::RtpEncodingParameters encoding;
32 parameters.encodings.push_back(encoding);
33 return parameters;
34 }
35
CreateRtpParametersWithEncodings(StreamParams sp)36 webrtc::RtpParameters CreateRtpParametersWithEncodings(StreamParams sp) {
37 std::vector<uint32_t> primary_ssrcs;
38 sp.GetPrimarySsrcs(&primary_ssrcs);
39 size_t encoding_count = primary_ssrcs.size();
40
41 std::vector<webrtc::RtpEncodingParameters> encodings(encoding_count);
42 for (size_t i = 0; i < encodings.size(); ++i) {
43 encodings[i].ssrc = primary_ssrcs[i];
44 }
45
46 const std::vector<RidDescription>& rids = sp.rids();
47 RTC_DCHECK(rids.size() == 0 || rids.size() == encoding_count);
48 for (size_t i = 0; i < rids.size(); ++i) {
49 encodings[i].rid = rids[i].rid;
50 }
51
52 webrtc::RtpParameters parameters;
53 parameters.encodings = encodings;
54 parameters.rtcp.cname = sp.cname;
55 return parameters;
56 }
57
GetDefaultEnabledRtpHeaderExtensions(const RtpHeaderExtensionQueryInterface & query_interface)58 std::vector<webrtc::RtpExtension> GetDefaultEnabledRtpHeaderExtensions(
59 const RtpHeaderExtensionQueryInterface& query_interface) {
60 std::vector<webrtc::RtpExtension> extensions;
61 for (const auto& entry : query_interface.GetRtpHeaderExtensions()) {
62 if (entry.direction != webrtc::RtpTransceiverDirection::kStopped)
63 extensions.emplace_back(entry.uri, *entry.preferred_id);
64 }
65 return extensions;
66 }
67
CheckScalabilityModeValues(const webrtc::RtpParameters & rtp_parameters,rtc::ArrayView<cricket::VideoCodec> codecs)68 webrtc::RTCError CheckScalabilityModeValues(
69 const webrtc::RtpParameters& rtp_parameters,
70 rtc::ArrayView<cricket::VideoCodec> codecs) {
71 using webrtc::RTCErrorType;
72
73 if (codecs.empty()) {
74 // This is an audio sender or an extra check in the stack where the codec
75 // list is not available and we can't check the scalability_mode values.
76 return webrtc::RTCError::OK();
77 }
78
79 for (size_t i = 0; i < rtp_parameters.encodings.size(); ++i) {
80 if (rtp_parameters.encodings[i].scalability_mode) {
81 bool scalabilityModeFound = false;
82 for (const cricket::VideoCodec& codec : codecs) {
83 for (const auto& scalability_mode : codec.scalability_modes) {
84 if (ScalabilityModeToString(scalability_mode) ==
85 *rtp_parameters.encodings[i].scalability_mode) {
86 scalabilityModeFound = true;
87 break;
88 }
89 }
90 if (scalabilityModeFound)
91 break;
92 }
93
94 if (!scalabilityModeFound) {
95 LOG_AND_RETURN_ERROR(RTCErrorType::UNSUPPORTED_OPERATION,
96 "Attempted to set RtpParameters scalabilityMode "
97 "to an unsupported value for the current codecs.");
98 }
99 }
100 }
101
102 return webrtc::RTCError::OK();
103 }
104
CheckRtpParametersValues(const webrtc::RtpParameters & rtp_parameters,rtc::ArrayView<cricket::VideoCodec> codecs)105 webrtc::RTCError CheckRtpParametersValues(
106 const webrtc::RtpParameters& rtp_parameters,
107 rtc::ArrayView<cricket::VideoCodec> codecs) {
108 using webrtc::RTCErrorType;
109
110 for (size_t i = 0; i < rtp_parameters.encodings.size(); ++i) {
111 if (rtp_parameters.encodings[i].bitrate_priority <= 0) {
112 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_RANGE,
113 "Attempted to set RtpParameters bitrate_priority to "
114 "an invalid number. bitrate_priority must be > 0.");
115 }
116 if (rtp_parameters.encodings[i].scale_resolution_down_by &&
117 *rtp_parameters.encodings[i].scale_resolution_down_by < 1.0) {
118 LOG_AND_RETURN_ERROR(
119 RTCErrorType::INVALID_RANGE,
120 "Attempted to set RtpParameters scale_resolution_down_by to an "
121 "invalid value. scale_resolution_down_by must be >= 1.0");
122 }
123 if (rtp_parameters.encodings[i].max_framerate &&
124 *rtp_parameters.encodings[i].max_framerate < 0.0) {
125 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_RANGE,
126 "Attempted to set RtpParameters max_framerate to an "
127 "invalid value. max_framerate must be >= 0.0");
128 }
129 if (rtp_parameters.encodings[i].min_bitrate_bps &&
130 rtp_parameters.encodings[i].max_bitrate_bps) {
131 if (*rtp_parameters.encodings[i].max_bitrate_bps <
132 *rtp_parameters.encodings[i].min_bitrate_bps) {
133 LOG_AND_RETURN_ERROR(webrtc::RTCErrorType::INVALID_RANGE,
134 "Attempted to set RtpParameters min bitrate "
135 "larger than max bitrate.");
136 }
137 }
138 if (rtp_parameters.encodings[i].num_temporal_layers) {
139 if (*rtp_parameters.encodings[i].num_temporal_layers < 1 ||
140 *rtp_parameters.encodings[i].num_temporal_layers >
141 webrtc::kMaxTemporalStreams) {
142 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_RANGE,
143 "Attempted to set RtpParameters "
144 "num_temporal_layers to an invalid number.");
145 }
146 }
147
148 if (rtp_parameters.encodings[i].requested_resolution &&
149 rtp_parameters.encodings[i].scale_resolution_down_by) {
150 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_RANGE,
151 "Attempted to set scale_resolution_down_by and "
152 "requested_resolution simultaniously.");
153 }
154 }
155
156 return CheckScalabilityModeValues(rtp_parameters, codecs);
157 }
158
CheckRtpParametersInvalidModificationAndValues(const webrtc::RtpParameters & old_rtp_parameters,const webrtc::RtpParameters & rtp_parameters)159 webrtc::RTCError CheckRtpParametersInvalidModificationAndValues(
160 const webrtc::RtpParameters& old_rtp_parameters,
161 const webrtc::RtpParameters& rtp_parameters) {
162 return CheckRtpParametersInvalidModificationAndValues(old_rtp_parameters,
163 rtp_parameters, {});
164 }
165
CheckRtpParametersInvalidModificationAndValues(const webrtc::RtpParameters & old_rtp_parameters,const webrtc::RtpParameters & rtp_parameters,rtc::ArrayView<cricket::VideoCodec> codecs)166 webrtc::RTCError CheckRtpParametersInvalidModificationAndValues(
167 const webrtc::RtpParameters& old_rtp_parameters,
168 const webrtc::RtpParameters& rtp_parameters,
169 rtc::ArrayView<cricket::VideoCodec> codecs) {
170 using webrtc::RTCErrorType;
171 if (rtp_parameters.encodings.size() != old_rtp_parameters.encodings.size()) {
172 LOG_AND_RETURN_ERROR(
173 RTCErrorType::INVALID_MODIFICATION,
174 "Attempted to set RtpParameters with different encoding count");
175 }
176 if (rtp_parameters.rtcp != old_rtp_parameters.rtcp) {
177 LOG_AND_RETURN_ERROR(
178 RTCErrorType::INVALID_MODIFICATION,
179 "Attempted to set RtpParameters with modified RTCP parameters");
180 }
181 if (rtp_parameters.header_extensions !=
182 old_rtp_parameters.header_extensions) {
183 LOG_AND_RETURN_ERROR(
184 RTCErrorType::INVALID_MODIFICATION,
185 "Attempted to set RtpParameters with modified header extensions");
186 }
187 if (!absl::c_equal(old_rtp_parameters.encodings, rtp_parameters.encodings,
188 [](const webrtc::RtpEncodingParameters& encoding1,
189 const webrtc::RtpEncodingParameters& encoding2) {
190 return encoding1.rid == encoding2.rid;
191 })) {
192 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_MODIFICATION,
193 "Attempted to change RID values in the encodings.");
194 }
195 if (!absl::c_equal(old_rtp_parameters.encodings, rtp_parameters.encodings,
196 [](const webrtc::RtpEncodingParameters& encoding1,
197 const webrtc::RtpEncodingParameters& encoding2) {
198 return encoding1.ssrc == encoding2.ssrc;
199 })) {
200 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_MODIFICATION,
201 "Attempted to set RtpParameters with modified SSRC");
202 }
203
204 return CheckRtpParametersValues(rtp_parameters, codecs);
205 }
206
CompositeMediaEngine(std::unique_ptr<webrtc::FieldTrialsView> trials,std::unique_ptr<VoiceEngineInterface> audio_engine,std::unique_ptr<VideoEngineInterface> video_engine)207 CompositeMediaEngine::CompositeMediaEngine(
208 std::unique_ptr<webrtc::FieldTrialsView> trials,
209 std::unique_ptr<VoiceEngineInterface> audio_engine,
210 std::unique_ptr<VideoEngineInterface> video_engine)
211 : trials_(std::move(trials)),
212 voice_engine_(std::move(audio_engine)),
213 video_engine_(std::move(video_engine)) {}
214
CompositeMediaEngine(std::unique_ptr<VoiceEngineInterface> audio_engine,std::unique_ptr<VideoEngineInterface> video_engine)215 CompositeMediaEngine::CompositeMediaEngine(
216 std::unique_ptr<VoiceEngineInterface> audio_engine,
217 std::unique_ptr<VideoEngineInterface> video_engine)
218 : CompositeMediaEngine(nullptr,
219 std::move(audio_engine),
220 std::move(video_engine)) {}
221
222 CompositeMediaEngine::~CompositeMediaEngine() = default;
223
Init()224 bool CompositeMediaEngine::Init() {
225 voice().Init();
226 return true;
227 }
228
voice()229 VoiceEngineInterface& CompositeMediaEngine::voice() {
230 return *voice_engine_.get();
231 }
232
video()233 VideoEngineInterface& CompositeMediaEngine::video() {
234 return *video_engine_.get();
235 }
236
voice() const237 const VoiceEngineInterface& CompositeMediaEngine::voice() const {
238 return *voice_engine_.get();
239 }
240
video() const241 const VideoEngineInterface& CompositeMediaEngine::video() const {
242 return *video_engine_.get();
243 }
244
245 } // namespace cricket
246