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