1 /*
2 * Copyright (c) 2014 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/engine/webrtc_media_engine.h"
12
13 #include <algorithm>
14 #include <map>
15 #include <memory>
16 #include <string>
17 #include <utility>
18
19 #include "absl/algorithm/container.h"
20 #include "absl/strings/match.h"
21 #include "api/transport/field_trial_based_config.h"
22 #include "media/base/media_constants.h"
23 #include "media/engine/webrtc_voice_engine.h"
24 #include "rtc_base/checks.h"
25 #include "rtc_base/logging.h"
26
27 #ifdef HAVE_WEBRTC_VIDEO
28 #include "media/engine/webrtc_video_engine.h"
29 #else
30 #include "media/engine/null_webrtc_video_engine.h"
31 #endif
32
33 namespace cricket {
34
CreateMediaEngine(MediaEngineDependencies dependencies)35 std::unique_ptr<MediaEngineInterface> CreateMediaEngine(
36 MediaEngineDependencies dependencies) {
37 // TODO(sprang): Make populating `dependencies.trials` mandatory and remove
38 // these fallbacks.
39 std::unique_ptr<webrtc::FieldTrialsView> fallback_trials(
40 dependencies.trials ? nullptr : new webrtc::FieldTrialBasedConfig());
41 const webrtc::FieldTrialsView& trials =
42 dependencies.trials ? *dependencies.trials : *fallback_trials;
43 auto audio_engine = std::make_unique<WebRtcVoiceEngine>(
44 dependencies.task_queue_factory, dependencies.adm.get(),
45 std::move(dependencies.audio_encoder_factory),
46 std::move(dependencies.audio_decoder_factory),
47 std::move(dependencies.audio_mixer),
48 std::move(dependencies.audio_processing),
49 dependencies.audio_frame_processor, trials);
50 #ifdef HAVE_WEBRTC_VIDEO
51 auto video_engine = std::make_unique<WebRtcVideoEngine>(
52 std::move(dependencies.video_encoder_factory),
53 std::move(dependencies.video_decoder_factory), trials);
54 #else
55 auto video_engine = std::make_unique<NullWebRtcVideoEngine>();
56 #endif
57 return std::make_unique<CompositeMediaEngine>(std::move(fallback_trials),
58 std::move(audio_engine),
59 std::move(video_engine));
60 }
61
62 namespace {
63 // Remove mutually exclusive extensions with lower priority.
DiscardRedundantExtensions(std::vector<webrtc::RtpExtension> * extensions,rtc::ArrayView<const char * const> extensions_decreasing_prio)64 void DiscardRedundantExtensions(
65 std::vector<webrtc::RtpExtension>* extensions,
66 rtc::ArrayView<const char* const> extensions_decreasing_prio) {
67 RTC_DCHECK(extensions);
68 bool found = false;
69 for (const char* uri : extensions_decreasing_prio) {
70 auto it = absl::c_find_if(
71 *extensions,
72 [uri](const webrtc::RtpExtension& rhs) { return rhs.uri == uri; });
73 if (it != extensions->end()) {
74 if (found) {
75 extensions->erase(it);
76 }
77 found = true;
78 }
79 }
80 }
81 } // namespace
82
ValidateRtpExtensions(rtc::ArrayView<const webrtc::RtpExtension> extensions,rtc::ArrayView<const webrtc::RtpExtension> old_extensions)83 bool ValidateRtpExtensions(
84 rtc::ArrayView<const webrtc::RtpExtension> extensions,
85 rtc::ArrayView<const webrtc::RtpExtension> old_extensions) {
86 bool id_used[1 + webrtc::RtpExtension::kMaxId] = {false};
87 for (const auto& extension : extensions) {
88 if (extension.id < webrtc::RtpExtension::kMinId ||
89 extension.id > webrtc::RtpExtension::kMaxId) {
90 RTC_LOG(LS_ERROR) << "Bad RTP extension ID: " << extension.ToString();
91 return false;
92 }
93 if (id_used[extension.id]) {
94 RTC_LOG(LS_ERROR) << "Duplicate RTP extension ID: "
95 << extension.ToString();
96 return false;
97 }
98 id_used[extension.id] = true;
99 }
100 // Validate the extension list against the already negotiated extensions.
101 // Re-registering is OK, re-mapping (either same URL at new ID or same
102 // ID used with new URL) is an illegal remap.
103
104 // This is required in order to avoid a crash when registering an
105 // extension. A better structure would use the registered extensions
106 // in the RTPSender. This requires spinning through:
107 //
108 // WebRtcVoiceMediaChannel::::WebRtcAudioSendStream::stream_ (pointer)
109 // AudioSendStream::rtp_rtcp_module_ (pointer)
110 // ModuleRtpRtcpImpl2::rtp_sender_ (pointer)
111 // RtpSenderContext::packet_generator (struct member)
112 // RTPSender::rtp_header_extension_map_ (class member)
113 //
114 // Getting at this seems like a hard slog.
115 if (!old_extensions.empty()) {
116 absl::string_view urimap[1 + webrtc::RtpExtension::kMaxId];
117 std::map<absl::string_view, int> idmap;
118 for (const auto& old_extension : old_extensions) {
119 urimap[old_extension.id] = old_extension.uri;
120 idmap[old_extension.uri] = old_extension.id;
121 }
122 for (const auto& extension : extensions) {
123 if (!urimap[extension.id].empty() &&
124 urimap[extension.id] != extension.uri) {
125 RTC_LOG(LS_ERROR) << "Extension negotiation failure: " << extension.id
126 << " was mapped to " << urimap[extension.id]
127 << " but is proposed changed to " << extension.uri;
128 return false;
129 }
130 const auto& it = idmap.find(extension.uri);
131 if (it != idmap.end() && it->second != extension.id) {
132 RTC_LOG(LS_ERROR) << "Extension negotation failure: " << extension.uri
133 << " was identified by " << it->second
134 << " but is proposed changed to " << extension.id;
135 return false;
136 }
137 }
138 }
139 return true;
140 }
141
FilterRtpExtensions(const std::vector<webrtc::RtpExtension> & extensions,bool (* supported)(absl::string_view),bool filter_redundant_extensions,const webrtc::FieldTrialsView & trials)142 std::vector<webrtc::RtpExtension> FilterRtpExtensions(
143 const std::vector<webrtc::RtpExtension>& extensions,
144 bool (*supported)(absl::string_view),
145 bool filter_redundant_extensions,
146 const webrtc::FieldTrialsView& trials) {
147 // Don't check against old parameters; this should have been done earlier.
148 RTC_DCHECK(ValidateRtpExtensions(extensions, {}));
149 RTC_DCHECK(supported);
150 std::vector<webrtc::RtpExtension> result;
151
152 // Ignore any extensions that we don't recognize.
153 for (const auto& extension : extensions) {
154 if (supported(extension.uri)) {
155 result.push_back(extension);
156 } else {
157 RTC_LOG(LS_WARNING) << "Unsupported RTP extension: "
158 << extension.ToString();
159 }
160 }
161
162 // Sort by name, ascending (prioritise encryption), so that we don't reset
163 // extensions if they were specified in a different order (also allows us
164 // to use std::unique below).
165 absl::c_sort(result, [](const webrtc::RtpExtension& rhs,
166 const webrtc::RtpExtension& lhs) {
167 return rhs.encrypt == lhs.encrypt ? rhs.uri < lhs.uri
168 : rhs.encrypt > lhs.encrypt;
169 });
170
171 // Remove unnecessary extensions (used on send side).
172 if (filter_redundant_extensions) {
173 auto it = std::unique(
174 result.begin(), result.end(),
175 [](const webrtc::RtpExtension& rhs, const webrtc::RtpExtension& lhs) {
176 return rhs.uri == lhs.uri && rhs.encrypt == lhs.encrypt;
177 });
178 result.erase(it, result.end());
179
180 // Keep just the highest priority extension of any in the following lists.
181 if (absl::StartsWith(trials.Lookup("WebRTC-FilterAbsSendTimeExtension"),
182 "Enabled")) {
183 static const char* const kBweExtensionPriorities[] = {
184 webrtc::RtpExtension::kTransportSequenceNumberUri,
185 webrtc::RtpExtension::kAbsSendTimeUri,
186 webrtc::RtpExtension::kTimestampOffsetUri};
187 DiscardRedundantExtensions(&result, kBweExtensionPriorities);
188 } else {
189 static const char* const kBweExtensionPriorities[] = {
190 webrtc::RtpExtension::kAbsSendTimeUri,
191 webrtc::RtpExtension::kTimestampOffsetUri};
192 DiscardRedundantExtensions(&result, kBweExtensionPriorities);
193 }
194 }
195 return result;
196 }
197
GetBitrateConfigForCodec(const Codec & codec)198 webrtc::BitrateConstraints GetBitrateConfigForCodec(const Codec& codec) {
199 webrtc::BitrateConstraints config;
200 int bitrate_kbps = 0;
201 if (codec.GetParam(kCodecParamMinBitrate, &bitrate_kbps) &&
202 bitrate_kbps > 0) {
203 config.min_bitrate_bps = bitrate_kbps * 1000;
204 } else {
205 config.min_bitrate_bps = 0;
206 }
207 if (codec.GetParam(kCodecParamStartBitrate, &bitrate_kbps) &&
208 bitrate_kbps > 0) {
209 config.start_bitrate_bps = bitrate_kbps * 1000;
210 } else {
211 // Do not reconfigure start bitrate unless it's specified and positive.
212 config.start_bitrate_bps = -1;
213 }
214 if (codec.GetParam(kCodecParamMaxBitrate, &bitrate_kbps) &&
215 bitrate_kbps > 0) {
216 config.max_bitrate_bps = bitrate_kbps * 1000;
217 } else {
218 config.max_bitrate_bps = -1;
219 }
220 return config;
221 }
222 } // namespace cricket
223