blob: 00c7fd61fc20fc019ef9773f44b59f3d772e214a [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
kjellander1afca732016-02-07 20:46:45 -08002 * Copyright (c) 2004 The WebRTC project authors. All Rights Reserved.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003 *
kjellander1afca732016-02-07 20:46:45 -08004 * 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.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00009 */
10
henrike@webrtc.org28e20752013-07-10 00:45:36 +000011#ifdef HAVE_WEBRTC_VOICE
12
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020013#include "media/engine/webrtcvoiceengine.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000014
15#include <algorithm>
16#include <cstdio>
ossuc54071d2016-08-17 02:45:41 -070017#include <functional>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000018#include <string>
19#include <vector>
20
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020021#include "api/call/audio_sink.h"
22#include "media/base/audiosource.h"
23#include "media/base/mediaconstants.h"
24#include "media/base/streamparams.h"
25#include "media/engine/adm_helpers.h"
26#include "media/engine/apm_helpers.h"
27#include "media/engine/payload_type_mapper.h"
28#include "media/engine/webrtcmediaengine.h"
29#include "media/engine/webrtcvoe.h"
30#include "modules/audio_mixer/audio_mixer_impl.h"
31#include "modules/audio_processing/aec_dump/aec_dump_factory.h"
32#include "modules/audio_processing/include/audio_processing.h"
33#include "rtc_base/arraysize.h"
34#include "rtc_base/base64.h"
35#include "rtc_base/byteorder.h"
36#include "rtc_base/constructormagic.h"
37#include "rtc_base/helpers.h"
38#include "rtc_base/logging.h"
39#include "rtc_base/race_checker.h"
40#include "rtc_base/stringencode.h"
41#include "rtc_base/stringutils.h"
42#include "rtc_base/trace_event.h"
43#include "system_wrappers/include/field_trial.h"
44#include "system_wrappers/include/metrics.h"
45#include "system_wrappers/include/trace.h"
46#include "voice_engine/transmit_mixer.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000047
henrike@webrtc.org28e20752013-07-10 00:45:36 +000048namespace cricket {
solenbergd97ec302015-10-07 01:40:33 -070049namespace {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000050
solenberg418b7d32017-06-13 00:38:27 -070051constexpr size_t kMaxUnsignaledRecvStreams = 4;
solenberg2100c0b2017-03-01 11:29:29 -080052
solenbergbd138382015-11-20 16:08:07 -080053const int kDefaultTraceFilter = webrtc::kTraceNone | webrtc::kTraceTerseInfo |
54 webrtc::kTraceWarning | webrtc::kTraceError |
55 webrtc::kTraceCritical;
56const int kElevatedTraceFilter = kDefaultTraceFilter | webrtc::kTraceStateInfo |
57 webrtc::kTraceInfo;
58
solenberg971cab02016-06-14 10:02:41 -070059constexpr int kNackRtpHistoryMs = 5000;
minyue@webrtc.org2dc6f312014-10-31 05:33:10 +000060
peah1bcfce52016-08-26 07:16:04 -070061// Check to verify that the define for the intelligibility enhancer is properly
62// set.
63#if !defined(WEBRTC_INTELLIGIBILITY_ENHANCER) || \
64 (WEBRTC_INTELLIGIBILITY_ENHANCER != 0 && \
65 WEBRTC_INTELLIGIBILITY_ENHANCER != 1)
66#error "Set WEBRTC_INTELLIGIBILITY_ENHANCER to either 0 or 1"
67#endif
68
ossu20a4b3f2017-04-27 02:08:52 -070069// For SendSideBwe, Opus bitrate should be in the range between 6000 and 32000.
minyue10cbb462016-11-07 09:29:22 -080070const int kOpusMinBitrateBps = 6000;
ossu20a4b3f2017-04-27 02:08:52 -070071const int kOpusBitrateFbBps = 32000;
deadbeef80346142016-04-27 14:17:10 -070072
wu@webrtc.orgde305012013-10-31 15:40:38 +000073// Default audio dscp value.
74// See http://tools.ietf.org/html/rfc2474 for details.
75// See also http://tools.ietf.org/html/draft-jennings-rtcweb-qos-00
solenbergd97ec302015-10-07 01:40:33 -070076const rtc::DiffServCodePoint kAudioDscpValue = rtc::DSCP_EF;
henrike@webrtc.org1e09a712013-07-26 19:17:59 +000077
Fredrik Solenbergb5727682015-12-04 15:22:19 +010078// Constants from voice_engine_defines.h.
79const int kMinTelephoneEventCode = 0; // RFC4733 (Section 2.3.1)
80const int kMaxTelephoneEventCode = 255;
Fredrik Solenbergb5727682015-12-04 15:22:19 +010081
solenberg31642aa2016-03-14 08:00:37 -070082const int kMinPayloadType = 0;
83const int kMaxPayloadType = 127;
84
deadbeef884f5852016-01-15 09:20:04 -080085class ProxySink : public webrtc::AudioSinkInterface {
86 public:
87 ProxySink(AudioSinkInterface* sink) : sink_(sink) { RTC_DCHECK(sink); }
88
89 void OnData(const Data& audio) override { sink_->OnData(audio); }
90
91 private:
92 webrtc::AudioSinkInterface* sink_;
93};
94
solenberg0b675462015-10-09 01:37:09 -070095bool ValidateStreamParams(const StreamParams& sp) {
96 if (sp.ssrcs.empty()) {
97 LOG(LS_ERROR) << "No SSRCs in stream parameters: " << sp.ToString();
98 return false;
99 }
100 if (sp.ssrcs.size() > 1) {
101 LOG(LS_ERROR) << "Multiple SSRCs in stream parameters: " << sp.ToString();
102 return false;
103 }
104 return true;
105}
106
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000107// Dumps an AudioCodec in RFC 2327-ish format.
solenbergd97ec302015-10-07 01:40:33 -0700108std::string ToString(const AudioCodec& codec) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000109 std::stringstream ss;
ossu20a4b3f2017-04-27 02:08:52 -0700110 ss << codec.name << "/" << codec.clockrate << "/" << codec.channels;
111 if (!codec.params.empty()) {
112 ss << " {";
113 for (const auto& param : codec.params) {
114 ss << " " << param.first << "=" << param.second;
115 }
116 ss << " }";
117 }
118 ss << " (" << codec.id << ")";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000119 return ss.str();
120}
Minyue Li7100dcd2015-03-27 05:05:59 +0100121
solenbergd97ec302015-10-07 01:40:33 -0700122bool IsCodec(const AudioCodec& codec, const char* ref_name) {
Minyue Li7100dcd2015-03-27 05:05:59 +0100123 return (_stricmp(codec.name.c_str(), ref_name) == 0);
124}
125
solenbergd97ec302015-10-07 01:40:33 -0700126bool FindCodec(const std::vector<AudioCodec>& codecs,
solenberg26c8c912015-11-27 04:00:25 -0800127 const AudioCodec& codec,
128 AudioCodec* found_codec) {
Fredrik Solenbergaf9fb212015-08-26 10:45:53 +0200129 for (const AudioCodec& c : codecs) {
130 if (c.Matches(codec)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000131 if (found_codec != NULL) {
Fredrik Solenbergaf9fb212015-08-26 10:45:53 +0200132 *found_codec = c;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000133 }
134 return true;
135 }
136 }
137 return false;
138}
wu@webrtc.org1d1ffc92013-10-16 18:12:02 +0000139
solenberg0b675462015-10-09 01:37:09 -0700140bool VerifyUniquePayloadTypes(const std::vector<AudioCodec>& codecs) {
141 if (codecs.empty()) {
142 return true;
143 }
144 std::vector<int> payload_types;
145 for (const AudioCodec& codec : codecs) {
146 payload_types.push_back(codec.id);
147 }
148 std::sort(payload_types.begin(), payload_types.end());
149 auto it = std::unique(payload_types.begin(), payload_types.end());
150 return it == payload_types.end();
151}
152
minyue6b825df2016-10-31 04:08:32 -0700153rtc::Optional<std::string> GetAudioNetworkAdaptorConfig(
154 const AudioOptions& options) {
155 if (options.audio_network_adaptor && *options.audio_network_adaptor &&
156 options.audio_network_adaptor_config) {
157 // Turn on audio network adaptor only when |options_.audio_network_adaptor|
158 // equals true and |options_.audio_network_adaptor_config| has a value.
159 return options.audio_network_adaptor_config;
160 }
161 return rtc::Optional<std::string>();
162}
163
gyzhou95aa9642016-12-13 14:06:26 -0800164webrtc::AudioState::Config MakeAudioStateConfig(
165 VoEWrapper* voe_wrapper,
peaha9cc40b2017-06-29 08:32:09 -0700166 rtc::scoped_refptr<webrtc::AudioMixer> audio_mixer,
167 rtc::scoped_refptr<webrtc::AudioProcessing> audio_processing) {
solenberg566ef242015-11-06 15:34:49 -0800168 webrtc::AudioState::Config config;
169 config.voice_engine = voe_wrapper->engine();
gyzhou95aa9642016-12-13 14:06:26 -0800170 if (audio_mixer) {
171 config.audio_mixer = audio_mixer;
172 } else {
173 config.audio_mixer = webrtc::AudioMixerImpl::Create();
174 }
peaha9cc40b2017-06-29 08:32:09 -0700175 config.audio_processing = audio_processing;
solenberg566ef242015-11-06 15:34:49 -0800176 return config;
177}
178
deadbeefe702b302017-02-04 12:09:01 -0800179// |max_send_bitrate_bps| is the bitrate from "b=" in SDP.
180// |rtp_max_bitrate_bps| is the bitrate from RtpSender::SetParameters.
minyue7a973442016-10-20 03:27:12 -0700181rtc::Optional<int> ComputeSendBitrate(int max_send_bitrate_bps,
deadbeefe702b302017-02-04 12:09:01 -0800182 rtc::Optional<int> rtp_max_bitrate_bps,
ossu20a4b3f2017-04-27 02:08:52 -0700183 const webrtc::AudioCodecSpec& spec) {
deadbeefe702b302017-02-04 12:09:01 -0800184 // If application-configured bitrate is set, take minimum of that and SDP
185 // bitrate.
zsteina5e0df62017-06-14 11:41:48 -0700186 const int bps =
187 rtp_max_bitrate_bps
188 ? webrtc::MinPositive(max_send_bitrate_bps, *rtp_max_bitrate_bps)
189 : max_send_bitrate_bps;
minyue7a973442016-10-20 03:27:12 -0700190 if (bps <= 0) {
ossu20a4b3f2017-04-27 02:08:52 -0700191 return rtc::Optional<int>(spec.info.default_bitrate_bps);
solenberg971cab02016-06-14 10:02:41 -0700192 }
minyue7a973442016-10-20 03:27:12 -0700193
ossu20a4b3f2017-04-27 02:08:52 -0700194 if (bps < spec.info.min_bitrate_bps) {
minyue7a973442016-10-20 03:27:12 -0700195 // If codec is not multi-rate and |bps| is less than the fixed bitrate then
196 // fail. If codec is not multi-rate and |bps| exceeds or equal the fixed
197 // bitrate then ignore.
ossu20a4b3f2017-04-27 02:08:52 -0700198 LOG(LS_ERROR) << "Failed to set codec " << spec.format.name
minyue7a973442016-10-20 03:27:12 -0700199 << " to bitrate " << bps << " bps"
ossu20a4b3f2017-04-27 02:08:52 -0700200 << ", requires at least " << spec.info.min_bitrate_bps
201 << " bps.";
minyue7a973442016-10-20 03:27:12 -0700202 return rtc::Optional<int>();
solenberg971cab02016-06-14 10:02:41 -0700203 }
ossu20a4b3f2017-04-27 02:08:52 -0700204
205 if (spec.info.HasFixedBitrate()) {
206 return rtc::Optional<int>(spec.info.default_bitrate_bps);
207 } else {
208 // If codec is multi-rate then just set the bitrate.
209 return rtc::Optional<int>(std::min(bps, spec.info.max_bitrate_bps));
210 }
solenberg971cab02016-06-14 10:02:41 -0700211}
212
solenberg76377c52017-02-21 00:54:31 -0800213} // namespace
solenberg971cab02016-06-14 10:02:41 -0700214
ossu29b1a8d2016-06-13 07:34:51 -0700215WebRtcVoiceEngine::WebRtcVoiceEngine(
216 webrtc::AudioDeviceModule* adm,
ossueb1fde42017-05-02 06:46:30 -0700217 const rtc::scoped_refptr<webrtc::AudioEncoderFactory>& encoder_factory,
gyzhou95aa9642016-12-13 14:06:26 -0800218 const rtc::scoped_refptr<webrtc::AudioDecoderFactory>& decoder_factory,
peaha9cc40b2017-06-29 08:32:09 -0700219 rtc::scoped_refptr<webrtc::AudioMixer> audio_mixer,
220 rtc::scoped_refptr<webrtc::AudioProcessing> audio_processing)
ossueb1fde42017-05-02 06:46:30 -0700221 : WebRtcVoiceEngine(adm,
222 encoder_factory,
223 decoder_factory,
224 audio_mixer,
peaha9cc40b2017-06-29 08:32:09 -0700225 audio_processing,
deadbeefeb02c032017-06-15 08:29:25 -0700226 nullptr) {}
solenberg26c8c912015-11-27 04:00:25 -0800227
ossu29b1a8d2016-06-13 07:34:51 -0700228WebRtcVoiceEngine::WebRtcVoiceEngine(
229 webrtc::AudioDeviceModule* adm,
ossueb1fde42017-05-02 06:46:30 -0700230 const rtc::scoped_refptr<webrtc::AudioEncoderFactory>& encoder_factory,
ossu29b1a8d2016-06-13 07:34:51 -0700231 const rtc::scoped_refptr<webrtc::AudioDecoderFactory>& decoder_factory,
gyzhou95aa9642016-12-13 14:06:26 -0800232 rtc::scoped_refptr<webrtc::AudioMixer> audio_mixer,
peaha9cc40b2017-06-29 08:32:09 -0700233 rtc::scoped_refptr<webrtc::AudioProcessing> audio_processing,
ossu29b1a8d2016-06-13 07:34:51 -0700234 VoEWrapper* voe_wrapper)
deadbeefeb02c032017-06-15 08:29:25 -0700235 : adm_(adm),
ossueb1fde42017-05-02 06:46:30 -0700236 encoder_factory_(encoder_factory),
ossu20a4b3f2017-04-27 02:08:52 -0700237 decoder_factory_(decoder_factory),
deadbeefeb02c032017-06-15 08:29:25 -0700238 audio_mixer_(audio_mixer),
peaha9cc40b2017-06-29 08:32:09 -0700239 apm_(audio_processing),
ossu20a4b3f2017-04-27 02:08:52 -0700240 voe_wrapper_(voe_wrapper) {
deadbeefeb02c032017-06-15 08:29:25 -0700241 // This may be called from any thread, so detach thread checkers.
242 worker_thread_checker_.DetachFromThread();
solenberg26c8c912015-11-27 04:00:25 -0800243 signal_thread_checker_.DetachFromThread();
deadbeefeb02c032017-06-15 08:29:25 -0700244 LOG(LS_INFO) << "WebRtcVoiceEngine::WebRtcVoiceEngine";
245 RTC_DCHECK(decoder_factory);
246 RTC_DCHECK(encoder_factory);
peaha9cc40b2017-06-29 08:32:09 -0700247 RTC_DCHECK(audio_processing);
deadbeefeb02c032017-06-15 08:29:25 -0700248 // The rest of our initialization will happen in Init.
249}
250
251WebRtcVoiceEngine::~WebRtcVoiceEngine() {
252 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
253 LOG(LS_INFO) << "WebRtcVoiceEngine::~WebRtcVoiceEngine";
254 if (initialized_) {
255 StopAecDump();
256 voe_wrapper_->base()->Terminate();
257 webrtc::Trace::SetTraceCallback(nullptr);
258 }
259}
260
261void WebRtcVoiceEngine::Init() {
262 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
263 LOG(LS_INFO) << "WebRtcVoiceEngine::Init";
264
265 // TaskQueue expects to be created/destroyed on the same thread.
266 low_priority_worker_queue_.reset(
267 new rtc::TaskQueue("rtc-low-prio", rtc::TaskQueue::Priority::LOW));
268
269 // VoEWrapper needs to be created on the worker thread. It's expected to be
270 // null here unless it's being injected for testing.
271 if (!voe_wrapper_) {
272 voe_wrapper_.reset(new VoEWrapper());
273 }
solenberg26c8c912015-11-27 04:00:25 -0800274
ossueb1fde42017-05-02 06:46:30 -0700275 // Load our audio codec lists.
ossuc54071d2016-08-17 02:45:41 -0700276 LOG(LS_INFO) << "Supported send codecs in order of preference:";
ossu20a4b3f2017-04-27 02:08:52 -0700277 send_codecs_ = CollectCodecs(encoder_factory_->GetSupportedEncoders());
ossuc54071d2016-08-17 02:45:41 -0700278 for (const AudioCodec& codec : send_codecs_) {
279 LOG(LS_INFO) << ToString(codec);
280 }
281
282 LOG(LS_INFO) << "Supported recv codecs in order of preference:";
ossu20a4b3f2017-04-27 02:08:52 -0700283 recv_codecs_ = CollectCodecs(decoder_factory_->GetSupportedDecoders());
ossuc54071d2016-08-17 02:45:41 -0700284 for (const AudioCodec& codec : recv_codecs_) {
solenbergff976312016-03-30 23:28:51 -0700285 LOG(LS_INFO) << ToString(codec);
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000286 }
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000287
solenberg88499ec2016-09-07 07:34:41 -0700288 channel_config_.enable_voice_pacing = true;
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000289
solenbergff976312016-03-30 23:28:51 -0700290 // Temporarily turn logging level up for the Init() call.
291 webrtc::Trace::SetTraceCallback(this);
solenbergbd138382015-11-20 16:08:07 -0800292 webrtc::Trace::set_level_filter(kElevatedTraceFilter);
peaha9cc40b2017-06-29 08:32:09 -0700293 RTC_CHECK_EQ(0,
294 voe_wrapper_->base()->Init(adm_.get(), apm(), decoder_factory_));
solenbergbd138382015-11-20 16:08:07 -0800295 webrtc::Trace::set_level_filter(kDefaultTraceFilter);
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000296
solenbergff976312016-03-30 23:28:51 -0700297 // No ADM supplied? Get the default one from VoE.
298 if (!adm_) {
299 adm_ = voe_wrapper_->base()->audio_device_module();
300 }
301 RTC_DCHECK(adm_);
302
solenberg76377c52017-02-21 00:54:31 -0800303 transmit_mixer_ = voe_wrapper_->base()->transmit_mixer();
304 RTC_DCHECK(transmit_mixer_);
305
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000306 // Save the default AGC configuration settings. This must happen before
solenberg246b8172015-12-08 09:50:23 -0800307 // calling ApplyOptions or the default will be overwritten.
peaha9cc40b2017-06-29 08:32:09 -0700308 default_agc_config_ = webrtc::apm_helpers::GetAgcConfig(apm());
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000309
solenberg0f7d2932016-01-15 01:40:39 -0800310 // Set default engine options.
311 {
312 AudioOptions options;
313 options.echo_cancellation = rtc::Optional<bool>(true);
314 options.auto_gain_control = rtc::Optional<bool>(true);
315 options.noise_suppression = rtc::Optional<bool>(true);
316 options.highpass_filter = rtc::Optional<bool>(true);
317 options.stereo_swapping = rtc::Optional<bool>(false);
318 options.audio_jitter_buffer_max_packets = rtc::Optional<int>(50);
319 options.audio_jitter_buffer_fast_accelerate = rtc::Optional<bool>(false);
320 options.typing_detection = rtc::Optional<bool>(true);
321 options.adjust_agc_delta = rtc::Optional<int>(0);
322 options.experimental_agc = rtc::Optional<bool>(false);
323 options.extended_filter_aec = rtc::Optional<bool>(false);
324 options.delay_agnostic_aec = rtc::Optional<bool>(false);
325 options.experimental_ns = rtc::Optional<bool>(false);
Alejandro Luebsc9b0c262016-05-16 15:32:38 -0700326 options.intelligibility_enhancer = rtc::Optional<bool>(false);
peaha3333bf2016-06-30 00:02:34 -0700327 options.level_control = rtc::Optional<bool>(false);
ivocb829d9f2016-11-15 02:34:47 -0800328 options.residual_echo_detector = rtc::Optional<bool>(true);
solenbergff976312016-03-30 23:28:51 -0700329 bool error = ApplyOptions(options);
330 RTC_DCHECK(error);
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000331 }
332
solenberg9a5f032222017-03-15 06:14:12 -0700333 // Set default audio devices.
334#if !defined(WEBRTC_IOS)
335 webrtc::adm_helpers::SetRecordingDevice(adm_);
336 apm()->Initialize();
337 webrtc::adm_helpers::SetPlayoutDevice(adm_);
338#endif // !WEBRTC_IOS
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000339
deadbeefeb02c032017-06-15 08:29:25 -0700340 // May be null for VoE injected for testing.
341 if (voe()->engine()) {
peaha9cc40b2017-06-29 08:32:09 -0700342 audio_state_ = webrtc::AudioState::Create(
343 MakeAudioStateConfig(voe(), audio_mixer_, apm_));
deadbeefeb02c032017-06-15 08:29:25 -0700344 }
345
346 initialized_ = true;
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000347}
348
solenberg566ef242015-11-06 15:34:49 -0800349rtc::scoped_refptr<webrtc::AudioState>
350 WebRtcVoiceEngine::GetAudioState() const {
351 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
352 return audio_state_;
353}
354
nisse51542be2016-02-12 02:27:06 -0800355VoiceMediaChannel* WebRtcVoiceEngine::CreateChannel(
356 webrtc::Call* call,
357 const MediaConfig& config,
Jelena Marusicc28a8962015-05-29 15:05:44 +0200358 const AudioOptions& options) {
solenberg566ef242015-11-06 15:34:49 -0800359 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
nisse51542be2016-02-12 02:27:06 -0800360 return new WebRtcVoiceMediaChannel(this, config, options, call);
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000361}
362
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000363bool WebRtcVoiceEngine::ApplyOptions(const AudioOptions& options_in) {
solenberg566ef242015-11-06 15:34:49 -0800364 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenbergff976312016-03-30 23:28:51 -0700365 LOG(LS_INFO) << "WebRtcVoiceEngine::ApplyOptions: " << options_in.ToString();
solenberg0f7d2932016-01-15 01:40:39 -0800366 AudioOptions options = options_in; // The options are modified below.
solenberg246b8172015-12-08 09:50:23 -0800367
peah8a8ebd92017-05-22 15:48:47 -0700368 // Set and adjust echo canceller options.
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000369 // kEcConference is AEC with high suppression.
370 webrtc::EcModes ec_mode = webrtc::kEcConference;
kwiberg102c6a62015-10-30 02:47:38 -0700371 if (options.aecm_generate_comfort_noise) {
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000372 LOG(LS_VERBOSE) << "Comfort noise explicitly set to "
kwiberg102c6a62015-10-30 02:47:38 -0700373 << *options.aecm_generate_comfort_noise
374 << " (default is false).";
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000375 }
376
kjellanderfcfc8042016-01-14 11:01:09 -0800377#if defined(WEBRTC_IOS)
peah8a8ebd92017-05-22 15:48:47 -0700378 // On iOS, VPIO provides built-in EC.
Karl Wibergbe579832015-11-10 22:34:18 +0100379 options.echo_cancellation = rtc::Optional<bool>(false);
peah8a8ebd92017-05-22 15:48:47 -0700380 options.extended_filter_aec = rtc::Optional<bool>(false);
381 LOG(LS_INFO) << "Always disable AEC on iOS. Use built-in instead.";
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000382#elif defined(ANDROID)
383 ec_mode = webrtc::kEcAecm;
Karl Wibergbe579832015-11-10 22:34:18 +0100384 options.extended_filter_aec = rtc::Optional<bool>(false);
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000385#endif
386
Bjorn Volckerbf395c12015-03-25 22:45:56 +0100387 // Delay Agnostic AEC automatically turns on EC if not set except on iOS
388 // where the feature is not supported.
389 bool use_delay_agnostic_aec = false;
kjellanderfcfc8042016-01-14 11:01:09 -0800390#if !defined(WEBRTC_IOS)
kwiberg102c6a62015-10-30 02:47:38 -0700391 if (options.delay_agnostic_aec) {
392 use_delay_agnostic_aec = *options.delay_agnostic_aec;
Bjorn Volckerbf395c12015-03-25 22:45:56 +0100393 if (use_delay_agnostic_aec) {
Karl Wibergbe579832015-11-10 22:34:18 +0100394 options.echo_cancellation = rtc::Optional<bool>(true);
395 options.extended_filter_aec = rtc::Optional<bool>(true);
Bjorn Volckerbf395c12015-03-25 22:45:56 +0100396 ec_mode = webrtc::kEcConference;
397 }
398 }
399#endif
400
peah8a8ebd92017-05-22 15:48:47 -0700401// Set and adjust noise suppressor options.
402#if defined(WEBRTC_IOS)
403 // On iOS, VPIO provides built-in NS.
404 options.noise_suppression = rtc::Optional<bool>(false);
405 options.typing_detection = rtc::Optional<bool>(false);
406 options.experimental_ns = rtc::Optional<bool>(false);
407 LOG(LS_INFO) << "Always disable NS on iOS. Use built-in instead.";
408#elif defined(ANDROID)
409 options.typing_detection = rtc::Optional<bool>(false);
410 options.experimental_ns = rtc::Optional<bool>(false);
411#endif
412
413// Set and adjust gain control options.
414#if defined(WEBRTC_IOS)
415 // On iOS, VPIO provides built-in AGC.
416 options.auto_gain_control = rtc::Optional<bool>(false);
417 options.experimental_agc = rtc::Optional<bool>(false);
418 LOG(LS_INFO) << "Always disable AGC on iOS. Use built-in instead.";
419#elif defined(ANDROID)
420 options.experimental_agc = rtc::Optional<bool>(false);
421#endif
422
423#if defined(WEBRTC_IOS) || defined(WEBRTC_ANDROID)
424 // Turn off the gain control if specified by the field trial. The purpose of the field trial is to reduce the amount of resampling performed inside the audio processing module on mobile platforms by whenever possible turning off the fixed AGC mode and the high-pass filter. (https://bugs.chromium.org/p/webrtc/issues/detail?id=6181).
425 if (webrtc::field_trial::IsEnabled(
426 "WebRTC-Audio-MinimizeResamplingOnMobile")) {
427 options.auto_gain_control = rtc::Optional<bool>(false);
428 LOG(LS_INFO) << "Disable AGC according to field trial.";
429 if (!(options.noise_suppression.value_or(false) or
430 options.echo_cancellation.value_or(false))) {
431 // If possible, turn off the high-pass filter.
432 LOG(LS_INFO) << "Disable high-pass filter in response to field trial.";
433 options.highpass_filter = rtc::Optional<bool>(false);
434 }
435 }
436#endif
437
peah1bcfce52016-08-26 07:16:04 -0700438#if (WEBRTC_INTELLIGIBILITY_ENHANCER == 0)
439 // Hardcode the intelligibility enhancer to be off.
440 options.intelligibility_enhancer = rtc::Optional<bool>(false);
441#endif
442
kwiberg102c6a62015-10-30 02:47:38 -0700443 if (options.echo_cancellation) {
henrika@webrtc.orga954c072014-12-09 16:22:09 +0000444 // Check if platform supports built-in EC. Currently only supported on
445 // Android and in combination with Java based audio layer.
446 // TODO(henrika): investigate possibility to support built-in EC also
447 // in combination with Open SL ES audio.
solenberg5b5129a2016-04-08 05:35:48 -0700448 const bool built_in_aec = adm()->BuiltInAECIsAvailable();
Bjorn Volcker73f72102015-06-03 14:50:15 +0200449 if (built_in_aec) {
Bjorn Volckerccfc9392015-05-07 07:43:17 +0200450 // Built-in EC exists on this device and use_delay_agnostic_aec is not
451 // overriding it. Enable/Disable it according to the echo_cancellation
452 // audio option.
Bjorn Volcker73f72102015-06-03 14:50:15 +0200453 const bool enable_built_in_aec =
kwiberg102c6a62015-10-30 02:47:38 -0700454 *options.echo_cancellation && !use_delay_agnostic_aec;
solenberg5b5129a2016-04-08 05:35:48 -0700455 if (adm()->EnableBuiltInAEC(enable_built_in_aec) == 0 &&
Bjorn Volcker73f72102015-06-03 14:50:15 +0200456 enable_built_in_aec) {
Bjorn Volckerbf395c12015-03-25 22:45:56 +0100457 // Disable internal software EC if built-in EC is enabled,
henrika@webrtc.orga954c072014-12-09 16:22:09 +0000458 // i.e., replace the software EC with the built-in EC.
Karl Wibergbe579832015-11-10 22:34:18 +0100459 options.echo_cancellation = rtc::Optional<bool>(false);
henrika@webrtc.orga954c072014-12-09 16:22:09 +0000460 LOG(LS_INFO) << "Disabling EC since built-in EC will be used instead";
461 }
462 }
solenberg76377c52017-02-21 00:54:31 -0800463 webrtc::apm_helpers::SetEcStatus(
464 apm(), *options.echo_cancellation, ec_mode);
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000465#if !defined(ANDROID)
solenberg76377c52017-02-21 00:54:31 -0800466 webrtc::apm_helpers::SetEcMetricsStatus(apm(), *options.echo_cancellation);
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000467#endif
468 if (ec_mode == webrtc::kEcAecm) {
kwiberg102c6a62015-10-30 02:47:38 -0700469 bool cn = options.aecm_generate_comfort_noise.value_or(false);
solenberg76377c52017-02-21 00:54:31 -0800470 webrtc::apm_helpers::SetAecmMode(apm(), cn);
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000471 }
472 }
473
kwiberg102c6a62015-10-30 02:47:38 -0700474 if (options.auto_gain_control) {
peah72a56452016-08-22 12:08:55 -0700475 bool built_in_agc_avaliable = adm()->BuiltInAGCIsAvailable();
476 if (built_in_agc_avaliable) {
solenberg5b5129a2016-04-08 05:35:48 -0700477 if (adm()->EnableBuiltInAGC(*options.auto_gain_control) == 0 &&
kwiberg102c6a62015-10-30 02:47:38 -0700478 *options.auto_gain_control) {
henrikac14f5ff2015-09-23 14:08:33 +0200479 // Disable internal software AGC if built-in AGC is enabled,
480 // i.e., replace the software AGC with the built-in AGC.
Karl Wibergbe579832015-11-10 22:34:18 +0100481 options.auto_gain_control = rtc::Optional<bool>(false);
henrikac14f5ff2015-09-23 14:08:33 +0200482 LOG(LS_INFO) << "Disabling AGC since built-in AGC will be used instead";
483 }
484 }
solenberg22818a52017-03-16 01:20:23 -0700485 webrtc::apm_helpers::SetAgcStatus(apm(), adm(), *options.auto_gain_control);
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000486 }
487
kwiberg102c6a62015-10-30 02:47:38 -0700488 if (options.tx_agc_target_dbov || options.tx_agc_digital_compression_gain ||
solenberg76377c52017-02-21 00:54:31 -0800489 options.tx_agc_limiter || options.adjust_agc_delta) {
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000490 // Override default_agc_config_. Generally, an unset option means "leave
491 // the VoE bits alone" in this function, so we want whatever is set to be
492 // stored as the new "default". If we didn't, then setting e.g.
493 // tx_agc_target_dbov would reset digital compression gain and limiter
494 // settings.
495 // Also, if we don't update default_agc_config_, then adjust_agc_delta
496 // would be an offset from the original values, and not whatever was set
497 // explicitly.
kwiberg102c6a62015-10-30 02:47:38 -0700498 default_agc_config_.targetLeveldBOv = options.tx_agc_target_dbov.value_or(
499 default_agc_config_.targetLeveldBOv);
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000500 default_agc_config_.digitalCompressionGaindB =
kwiberg102c6a62015-10-30 02:47:38 -0700501 options.tx_agc_digital_compression_gain.value_or(
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000502 default_agc_config_.digitalCompressionGaindB);
503 default_agc_config_.limiterEnable =
kwiberg102c6a62015-10-30 02:47:38 -0700504 options.tx_agc_limiter.value_or(default_agc_config_.limiterEnable);
solenberg76377c52017-02-21 00:54:31 -0800505
506 webrtc::AgcConfig config = default_agc_config_;
507 if (options.adjust_agc_delta) {
508 config.targetLeveldBOv -= *options.adjust_agc_delta;
509 LOG(LS_INFO) << "Adjusting AGC level from default -"
510 << default_agc_config_.targetLeveldBOv << "dB to -"
511 << config.targetLeveldBOv << "dB";
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000512 }
peaha9cc40b2017-06-29 08:32:09 -0700513 webrtc::apm_helpers::SetAgcConfig(apm(), config);
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000514 }
515
Alejandro Luebsc9b0c262016-05-16 15:32:38 -0700516 if (options.intelligibility_enhancer) {
517 intelligibility_enhancer_ = options.intelligibility_enhancer;
518 }
519 if (intelligibility_enhancer_ && *intelligibility_enhancer_) {
520 LOG(LS_INFO) << "Enabling NS when Intelligibility Enhancer is active.";
521 options.noise_suppression = intelligibility_enhancer_;
522 }
523
kwiberg102c6a62015-10-30 02:47:38 -0700524 if (options.noise_suppression) {
Alejandro Luebsc9b0c262016-05-16 15:32:38 -0700525 if (adm()->BuiltInNSIsAvailable()) {
526 bool builtin_ns =
527 *options.noise_suppression &&
528 !(intelligibility_enhancer_ && *intelligibility_enhancer_);
529 if (adm()->EnableBuiltInNS(builtin_ns) == 0 && builtin_ns) {
henrikac14f5ff2015-09-23 14:08:33 +0200530 // Disable internal software NS if built-in NS is enabled,
531 // i.e., replace the software NS with the built-in NS.
Karl Wibergbe579832015-11-10 22:34:18 +0100532 options.noise_suppression = rtc::Optional<bool>(false);
henrikac14f5ff2015-09-23 14:08:33 +0200533 LOG(LS_INFO) << "Disabling NS since built-in NS will be used instead";
534 }
535 }
solenberg76377c52017-02-21 00:54:31 -0800536 webrtc::apm_helpers::SetNsStatus(apm(), *options.noise_suppression);
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000537 }
538
kwiberg102c6a62015-10-30 02:47:38 -0700539 if (options.stereo_swapping) {
540 LOG(LS_INFO) << "Stereo swapping enabled? " << *options.stereo_swapping;
solenberg76377c52017-02-21 00:54:31 -0800541 transmit_mixer()->EnableStereoChannelSwapping(*options.stereo_swapping);
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000542 }
543
kwiberg102c6a62015-10-30 02:47:38 -0700544 if (options.audio_jitter_buffer_max_packets) {
545 LOG(LS_INFO) << "NetEq capacity is "
546 << *options.audio_jitter_buffer_max_packets;
solenberg88499ec2016-09-07 07:34:41 -0700547 channel_config_.acm_config.neteq_config.max_packets_in_buffer =
548 std::max(20, *options.audio_jitter_buffer_max_packets);
Henrik Lundin64dad832015-05-11 12:44:23 +0200549 }
kwiberg102c6a62015-10-30 02:47:38 -0700550 if (options.audio_jitter_buffer_fast_accelerate) {
551 LOG(LS_INFO) << "NetEq fast mode? "
552 << *options.audio_jitter_buffer_fast_accelerate;
solenberg88499ec2016-09-07 07:34:41 -0700553 channel_config_.acm_config.neteq_config.enable_fast_accelerate =
554 *options.audio_jitter_buffer_fast_accelerate;
Henrik Lundin5263b3c2015-06-01 10:29:41 +0200555 }
556
kwiberg102c6a62015-10-30 02:47:38 -0700557 if (options.typing_detection) {
558 LOG(LS_INFO) << "Typing detection is enabled? "
559 << *options.typing_detection;
solenberg76377c52017-02-21 00:54:31 -0800560 webrtc::apm_helpers::SetTypingDetectionStatus(
561 apm(), *options.typing_detection);
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000562 }
563
buildbot@webrtc.org1f8a2372014-08-28 10:52:44 +0000564 webrtc::Config config;
565
kwiberg102c6a62015-10-30 02:47:38 -0700566 if (options.delay_agnostic_aec)
567 delay_agnostic_aec_ = options.delay_agnostic_aec;
568 if (delay_agnostic_aec_) {
569 LOG(LS_INFO) << "Delay agnostic aec is enabled? " << *delay_agnostic_aec_;
henrik.lundin0f133b92015-07-02 00:17:55 -0700570 config.Set<webrtc::DelayAgnostic>(
kwiberg102c6a62015-10-30 02:47:38 -0700571 new webrtc::DelayAgnostic(*delay_agnostic_aec_));
Bjorn Volckerbf395c12015-03-25 22:45:56 +0100572 }
573
kwiberg102c6a62015-10-30 02:47:38 -0700574 if (options.extended_filter_aec) {
575 extended_filter_aec_ = options.extended_filter_aec;
576 }
577 if (extended_filter_aec_) {
578 LOG(LS_INFO) << "Extended filter aec is enabled? " << *extended_filter_aec_;
Henrik Lundin441f6342015-06-09 16:03:13 +0200579 config.Set<webrtc::ExtendedFilter>(
kwiberg102c6a62015-10-30 02:47:38 -0700580 new webrtc::ExtendedFilter(*extended_filter_aec_));
buildbot@webrtc.org1f8a2372014-08-28 10:52:44 +0000581 }
582
kwiberg102c6a62015-10-30 02:47:38 -0700583 if (options.experimental_ns) {
584 experimental_ns_ = options.experimental_ns;
585 }
586 if (experimental_ns_) {
587 LOG(LS_INFO) << "Experimental ns is enabled? " << *experimental_ns_;
buildbot@webrtc.org1f8a2372014-08-28 10:52:44 +0000588 config.Set<webrtc::ExperimentalNs>(
kwiberg102c6a62015-10-30 02:47:38 -0700589 new webrtc::ExperimentalNs(*experimental_ns_));
buildbot@webrtc.org1f8a2372014-08-28 10:52:44 +0000590 }
buildbot@webrtc.org1f8a2372014-08-28 10:52:44 +0000591
Alejandro Luebsc9b0c262016-05-16 15:32:38 -0700592 if (intelligibility_enhancer_) {
593 LOG(LS_INFO) << "Intelligibility Enhancer is enabled? "
594 << *intelligibility_enhancer_;
595 config.Set<webrtc::Intelligibility>(
596 new webrtc::Intelligibility(*intelligibility_enhancer_));
597 }
598
peaha3333bf2016-06-30 00:02:34 -0700599 if (options.level_control) {
600 level_control_ = options.level_control;
601 }
602
peahb1c9d1d2017-07-25 15:45:24 -0700603 webrtc::AudioProcessing::Config apm_config = apm()->GetConfig();
604
peaha3333bf2016-06-30 00:02:34 -0700605 LOG(LS_INFO) << "Level control: "
606 << (!!level_control_ ? *level_control_ : -1);
607 if (level_control_) {
peahb1c9d1d2017-07-25 15:45:24 -0700608 apm_config.level_controller.enabled = *level_control_;
aleloie33c5d92016-10-20 01:53:27 -0700609 if (options.level_control_initial_peak_level_dbfs) {
peahb1c9d1d2017-07-25 15:45:24 -0700610 apm_config.level_controller.initial_peak_level_dbfs =
aleloie33c5d92016-10-20 01:53:27 -0700611 *options.level_control_initial_peak_level_dbfs;
612 }
peaha3333bf2016-06-30 00:02:34 -0700613 }
614
peah8271d042016-11-22 07:24:52 -0800615 if (options.highpass_filter) {
peahb1c9d1d2017-07-25 15:45:24 -0700616 apm_config.high_pass_filter.enabled = *options.highpass_filter;
peah8271d042016-11-22 07:24:52 -0800617 }
618
ivoc4ca18692017-02-10 05:11:09 -0800619 if (options.residual_echo_detector) {
peahb1c9d1d2017-07-25 15:45:24 -0700620 apm_config.residual_echo_detector.enabled = *options.residual_echo_detector;
ivoc4ca18692017-02-10 05:11:09 -0800621 }
622
solenberg059fb442016-10-26 05:12:24 -0700623 apm()->SetExtraOptions(config);
peahb1c9d1d2017-07-25 15:45:24 -0700624 apm()->ApplyConfig(apm_config);
buildbot@webrtc.org1f8a2372014-08-28 10:52:44 +0000625
kwiberg102c6a62015-10-30 02:47:38 -0700626 if (options.recording_sample_rate) {
627 LOG(LS_INFO) << "Recording sample rate is "
628 << *options.recording_sample_rate;
solenberg5b5129a2016-04-08 05:35:48 -0700629 if (adm()->SetRecordingSampleRate(*options.recording_sample_rate)) {
solenberg35dee812017-09-18 01:57:01 -0700630 LOG(LS_WARNING) << "SetRecordingSampleRate("
631 << *options.recording_sample_rate << ") failed, err="
632 << adm()->LastError();
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000633 }
634 }
635
kwiberg102c6a62015-10-30 02:47:38 -0700636 if (options.playout_sample_rate) {
637 LOG(LS_INFO) << "Playout sample rate is " << *options.playout_sample_rate;
solenberg5b5129a2016-04-08 05:35:48 -0700638 if (adm()->SetPlayoutSampleRate(*options.playout_sample_rate)) {
solenberg35dee812017-09-18 01:57:01 -0700639 LOG(LS_WARNING) << "SetPlayoutSampleRate("
640 << *options.playout_sample_rate << ") failed, err="
641 << adm()->LastError();
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000642 }
643 }
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000644 return true;
645}
646
solenberg796b8f92017-03-01 17:02:23 -0800647// TODO(solenberg): Remove, once AudioMonitor is gone.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000648int WebRtcVoiceEngine::GetInputLevel() {
solenberg566ef242015-11-06 15:34:49 -0800649 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenberg796b8f92017-03-01 17:02:23 -0800650 int8_t level = transmit_mixer()->AudioLevel();
651 RTC_DCHECK_LE(0, level);
652 return level;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000653}
654
ossudedfd282016-06-14 07:12:39 -0700655const std::vector<AudioCodec>& WebRtcVoiceEngine::send_codecs() const {
656 RTC_DCHECK(signal_thread_checker_.CalledOnValidThread());
ossuc54071d2016-08-17 02:45:41 -0700657 return send_codecs_;
ossudedfd282016-06-14 07:12:39 -0700658}
659
660const std::vector<AudioCodec>& WebRtcVoiceEngine::recv_codecs() const {
solenberg566ef242015-11-06 15:34:49 -0800661 RTC_DCHECK(signal_thread_checker_.CalledOnValidThread());
ossuc54071d2016-08-17 02:45:41 -0700662 return recv_codecs_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000663}
664
Stefan Holmer9d69c3f2015-12-07 10:45:43 +0100665RtpCapabilities WebRtcVoiceEngine::GetCapabilities() const {
solenberg566ef242015-11-06 15:34:49 -0800666 RTC_DCHECK(signal_thread_checker_.CalledOnValidThread());
Stefan Holmer9d69c3f2015-12-07 10:45:43 +0100667 RtpCapabilities capabilities;
Stefan Holmer9d69c3f2015-12-07 10:45:43 +0100668 capabilities.header_extensions.push_back(
isheriff6f8d6862016-05-26 11:24:55 -0700669 webrtc::RtpExtension(webrtc::RtpExtension::kAudioLevelUri,
670 webrtc::RtpExtension::kAudioLevelDefaultId));
sprangc1b57a12017-02-28 08:50:47 -0800671 if (webrtc::field_trial::IsEnabled("WebRTC-Audio-SendSideBwe")) {
isheriff6f8d6862016-05-26 11:24:55 -0700672 capabilities.header_extensions.push_back(webrtc::RtpExtension(
673 webrtc::RtpExtension::kTransportSequenceNumberUri,
674 webrtc::RtpExtension::kTransportSequenceNumberDefaultId));
stefanba4c0e42016-02-04 04:12:24 -0800675 }
Stefan Holmer9d69c3f2015-12-07 10:45:43 +0100676 return capabilities;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000677}
678
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000679void WebRtcVoiceEngine::Print(webrtc::TraceLevel level, const char* trace,
680 int length) {
solenberg566ef242015-11-06 15:34:49 -0800681 // Note: This callback can happen on any thread!
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000682 rtc::LoggingSeverity sev = rtc::LS_VERBOSE;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000683 if (level == webrtc::kTraceError || level == webrtc::kTraceCritical)
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000684 sev = rtc::LS_ERROR;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000685 else if (level == webrtc::kTraceWarning)
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000686 sev = rtc::LS_WARNING;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000687 else if (level == webrtc::kTraceStateInfo || level == webrtc::kTraceInfo)
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000688 sev = rtc::LS_INFO;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000689 else if (level == webrtc::kTraceTerseInfo)
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000690 sev = rtc::LS_INFO;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000691
solenberg72e29d22016-03-08 06:35:16 -0800692 // Skip past boilerplate prefix text.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000693 if (length < 72) {
694 std::string msg(trace, length);
695 LOG(LS_ERROR) << "Malformed webrtc log message: ";
696 LOG_V(sev) << msg;
697 } else {
698 std::string msg(trace + 71, length - 72);
Peter Boströmd5c75b12015-09-23 13:24:32 +0200699 LOG_V(sev) << "webrtc: " << msg;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000700 }
701}
702
solenberg63b34542015-09-29 06:06:31 -0700703void WebRtcVoiceEngine::RegisterChannel(WebRtcVoiceMediaChannel* channel) {
solenberg566ef242015-11-06 15:34:49 -0800704 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
705 RTC_DCHECK(channel);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000706 channels_.push_back(channel);
707}
708
solenberg63b34542015-09-29 06:06:31 -0700709void WebRtcVoiceEngine::UnregisterChannel(WebRtcVoiceMediaChannel* channel) {
solenberg566ef242015-11-06 15:34:49 -0800710 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenberg63b34542015-09-29 06:06:31 -0700711 auto it = std::find(channels_.begin(), channels_.end(), channel);
solenberg566ef242015-11-06 15:34:49 -0800712 RTC_DCHECK(it != channels_.end());
713 channels_.erase(it);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000714}
715
ivocd66b44d2016-01-15 03:06:36 -0800716bool WebRtcVoiceEngine::StartAecDump(rtc::PlatformFile file,
717 int64_t max_size_bytes) {
solenberg566ef242015-11-06 15:34:49 -0800718 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
deadbeefeb02c032017-06-15 08:29:25 -0700719 auto aec_dump = webrtc::AecDumpFactory::Create(
720 file, max_size_bytes, low_priority_worker_queue_.get());
aleloi048cbdd2017-05-29 02:56:27 -0700721 if (!aec_dump) {
wu@webrtc.orga8910d22014-01-23 22:12:45 +0000722 return false;
723 }
aleloi048cbdd2017-05-29 02:56:27 -0700724 apm()->AttachAecDump(std::move(aec_dump));
wu@webrtc.orga9890802013-12-13 00:21:03 +0000725 return true;
wu@webrtc.orga9890802013-12-13 00:21:03 +0000726}
727
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000728void WebRtcVoiceEngine::StartAecDump(const std::string& filename) {
solenberg566ef242015-11-06 15:34:49 -0800729 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
aleloi048cbdd2017-05-29 02:56:27 -0700730
deadbeefeb02c032017-06-15 08:29:25 -0700731 auto aec_dump = webrtc::AecDumpFactory::Create(
732 filename, -1, low_priority_worker_queue_.get());
aleloi048cbdd2017-05-29 02:56:27 -0700733 if (aec_dump) {
734 apm()->AttachAecDump(std::move(aec_dump));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000735 }
736}
737
738void WebRtcVoiceEngine::StopAecDump() {
solenberg566ef242015-11-06 15:34:49 -0800739 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
aleloi048cbdd2017-05-29 02:56:27 -0700740 apm()->DetachAecDump();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000741}
742
solenberg0a617e22015-10-20 15:49:38 -0700743int WebRtcVoiceEngine::CreateVoEChannel() {
solenberg566ef242015-11-06 15:34:49 -0800744 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenberg88499ec2016-09-07 07:34:41 -0700745 return voe_wrapper_->base()->CreateChannel(channel_config_);
sergeyu@chromium.org5bc25c42013-12-05 00:24:06 +0000746}
747
solenberg5b5129a2016-04-08 05:35:48 -0700748webrtc::AudioDeviceModule* WebRtcVoiceEngine::adm() {
749 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
750 RTC_DCHECK(adm_);
751 return adm_;
752}
753
peahb1c9d1d2017-07-25 15:45:24 -0700754webrtc::AudioProcessing* WebRtcVoiceEngine::apm() const {
solenberg059fb442016-10-26 05:12:24 -0700755 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
peaha9cc40b2017-06-29 08:32:09 -0700756 return apm_.get();
solenberg059fb442016-10-26 05:12:24 -0700757}
758
solenberg76377c52017-02-21 00:54:31 -0800759webrtc::voe::TransmitMixer* WebRtcVoiceEngine::transmit_mixer() {
760 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
761 RTC_DCHECK(transmit_mixer_);
762 return transmit_mixer_;
763}
764
ossu20a4b3f2017-04-27 02:08:52 -0700765AudioCodecs WebRtcVoiceEngine::CollectCodecs(
766 const std::vector<webrtc::AudioCodecSpec>& specs) const {
ossuc54071d2016-08-17 02:45:41 -0700767 PayloadTypeMapper mapper;
768 AudioCodecs out;
ossuc54071d2016-08-17 02:45:41 -0700769
solenberg2779bab2016-11-17 04:45:19 -0800770 // Only generate CN payload types for these clockrates:
ossuc54071d2016-08-17 02:45:41 -0700771 std::map<int, bool, std::greater<int>> generate_cn = {{ 8000, false },
772 { 16000, false },
773 { 32000, false }};
solenberg2779bab2016-11-17 04:45:19 -0800774 // Only generate telephone-event payload types for these clockrates:
775 std::map<int, bool, std::greater<int>> generate_dtmf = {{ 8000, false },
776 { 16000, false },
777 { 32000, false },
778 { 48000, false }};
ossuc54071d2016-08-17 02:45:41 -0700779
ossu9def8002017-02-09 05:14:32 -0800780 auto map_format = [&mapper](const webrtc::SdpAudioFormat& format,
781 AudioCodecs* out) {
ossuc54071d2016-08-17 02:45:41 -0700782 rtc::Optional<AudioCodec> opt_codec = mapper.ToAudioCodec(format);
ossu9def8002017-02-09 05:14:32 -0800783 if (opt_codec) {
784 if (out) {
785 out->push_back(*opt_codec);
786 }
787 } else {
ossuc54071d2016-08-17 02:45:41 -0700788 LOG(LS_ERROR) << "Unable to assign payload type to format: " << format;
ossuc54071d2016-08-17 02:45:41 -0700789 }
790
ossu9def8002017-02-09 05:14:32 -0800791 return opt_codec;
ossuc54071d2016-08-17 02:45:41 -0700792 };
793
ossud4e9f622016-08-18 02:01:17 -0700794 for (const auto& spec : specs) {
ossu9def8002017-02-09 05:14:32 -0800795 // We need to do some extra stuff before adding the main codecs to out.
796 rtc::Optional<AudioCodec> opt_codec = map_format(spec.format, nullptr);
797 if (opt_codec) {
798 AudioCodec& codec = *opt_codec;
ossua1a040a2017-04-06 10:03:21 -0700799 if (spec.info.supports_network_adaption) {
ossu9def8002017-02-09 05:14:32 -0800800 codec.AddFeedbackParam(
801 FeedbackParam(kRtcpFbParamTransportCc, kParamValueEmpty));
802 }
803
ossua1a040a2017-04-06 10:03:21 -0700804 if (spec.info.allow_comfort_noise) {
solenberg2779bab2016-11-17 04:45:19 -0800805 // Generate a CN entry if the decoder allows it and we support the
806 // clockrate.
807 auto cn = generate_cn.find(spec.format.clockrate_hz);
808 if (cn != generate_cn.end()) {
809 cn->second = true;
810 }
811 }
812
813 // Generate a telephone-event entry if we support the clockrate.
814 auto dtmf = generate_dtmf.find(spec.format.clockrate_hz);
815 if (dtmf != generate_dtmf.end()) {
816 dtmf->second = true;
ossuc54071d2016-08-17 02:45:41 -0700817 }
ossu9def8002017-02-09 05:14:32 -0800818
819 out.push_back(codec);
ossuc54071d2016-08-17 02:45:41 -0700820 }
821 }
822
solenberg2779bab2016-11-17 04:45:19 -0800823 // Add CN codecs after "proper" audio codecs.
ossuc54071d2016-08-17 02:45:41 -0700824 for (const auto& cn : generate_cn) {
825 if (cn.second) {
ossu9def8002017-02-09 05:14:32 -0800826 map_format({kCnCodecName, cn.first, 1}, &out);
ossuc54071d2016-08-17 02:45:41 -0700827 }
828 }
829
solenberg2779bab2016-11-17 04:45:19 -0800830 // Add telephone-event codecs last.
831 for (const auto& dtmf : generate_dtmf) {
832 if (dtmf.second) {
ossu9def8002017-02-09 05:14:32 -0800833 map_format({kDtmfCodecName, dtmf.first, 1}, &out);
solenberg2779bab2016-11-17 04:45:19 -0800834 }
835 }
ossuc54071d2016-08-17 02:45:41 -0700836
837 return out;
838}
839
solenbergc96df772015-10-21 13:01:53 -0700840class WebRtcVoiceMediaChannel::WebRtcAudioSendStream
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -0800841 : public AudioSource::Sink {
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +0000842 public:
minyue7a973442016-10-20 03:27:12 -0700843 WebRtcAudioSendStream(
844 int ch,
845 webrtc::AudioTransport* voe_audio_transport,
846 uint32_t ssrc,
847 const std::string& c_name,
ossu20a4b3f2017-04-27 02:08:52 -0700848 const rtc::Optional<webrtc::AudioSendStream::Config::SendCodecSpec>&
849 send_codec_spec,
minyue7a973442016-10-20 03:27:12 -0700850 const std::vector<webrtc::RtpExtension>& extensions,
851 int max_send_bitrate_bps,
minyue6b825df2016-10-31 04:08:32 -0700852 const rtc::Optional<std::string>& audio_network_adaptor_config,
minyue7a973442016-10-20 03:27:12 -0700853 webrtc::Call* call,
ossu20a4b3f2017-04-27 02:08:52 -0700854 webrtc::Transport* send_transport,
855 const rtc::scoped_refptr<webrtc::AudioEncoderFactory>& encoder_factory)
solenberg7add0582015-11-20 09:59:34 -0800856 : voe_audio_transport_(voe_audio_transport),
solenberg3a941542015-11-16 07:34:50 -0800857 call_(call),
mflodman3d7db262016-04-29 00:57:13 -0700858 config_(send_transport),
sprangc1b57a12017-02-28 08:50:47 -0800859 send_side_bwe_with_overhead_(
860 webrtc::field_trial::IsEnabled("WebRTC-SendSideBwe-WithOverhead")),
minyue7a973442016-10-20 03:27:12 -0700861 max_send_bitrate_bps_(max_send_bitrate_bps),
skvlade0d46372016-04-07 22:59:22 -0700862 rtp_parameters_(CreateRtpParametersWithOneEncoding()) {
solenberg85a04962015-10-27 03:35:21 -0700863 RTC_DCHECK_GE(ch, 0);
864 // TODO(solenberg): Once we're not using FakeWebRtcVoiceEngine anymore:
865 // RTC_DCHECK(voe_audio_transport);
solenbergc96df772015-10-21 13:01:53 -0700866 RTC_DCHECK(call);
ossu20a4b3f2017-04-27 02:08:52 -0700867 RTC_DCHECK(encoder_factory);
solenberg3a941542015-11-16 07:34:50 -0800868 config_.rtp.ssrc = ssrc;
869 config_.rtp.c_name = c_name;
870 config_.voe_channel_id = ch;
solenberg971cab02016-06-14 10:02:41 -0700871 config_.rtp.extensions = extensions;
minyue6b825df2016-10-31 04:08:32 -0700872 config_.audio_network_adaptor_config = audio_network_adaptor_config;
ossu20a4b3f2017-04-27 02:08:52 -0700873 config_.encoder_factory = encoder_factory;
deadbeefcb443432016-12-12 11:12:36 -0800874 rtp_parameters_.encodings[0].ssrc = rtc::Optional<uint32_t>(ssrc);
ossu20a4b3f2017-04-27 02:08:52 -0700875
876 if (send_codec_spec) {
877 UpdateSendCodecSpec(*send_codec_spec);
878 }
879
880 stream_ = call_->CreateAudioSendStream(config_);
solenbergc96df772015-10-21 13:01:53 -0700881 }
solenberg3a941542015-11-16 07:34:50 -0800882
solenbergc96df772015-10-21 13:01:53 -0700883 ~WebRtcAudioSendStream() override {
solenberg566ef242015-11-06 15:34:49 -0800884 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -0800885 ClearSource();
solenbergc96df772015-10-21 13:01:53 -0700886 call_->DestroyAudioSendStream(stream_);
887 }
henrike@webrtc.org1e09a712013-07-26 19:17:59 +0000888
ossu20a4b3f2017-04-27 02:08:52 -0700889 void SetSendCodecSpec(
minyue7a973442016-10-20 03:27:12 -0700890 const webrtc::AudioSendStream::Config::SendCodecSpec& send_codec_spec) {
ossu20a4b3f2017-04-27 02:08:52 -0700891 UpdateSendCodecSpec(send_codec_spec);
892 ReconfigureAudioSendStream();
solenberg971cab02016-06-14 10:02:41 -0700893 }
894
ossu20a4b3f2017-04-27 02:08:52 -0700895 void SetRtpExtensions(const std::vector<webrtc::RtpExtension>& extensions) {
solenberg3a941542015-11-16 07:34:50 -0800896 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenberg3a941542015-11-16 07:34:50 -0800897 config_.rtp.extensions = extensions;
ossu20a4b3f2017-04-27 02:08:52 -0700898 ReconfigureAudioSendStream();
solenberg3a941542015-11-16 07:34:50 -0800899 }
900
ossu20a4b3f2017-04-27 02:08:52 -0700901 void SetAudioNetworkAdaptorConfig(
minyue6b825df2016-10-31 04:08:32 -0700902 const rtc::Optional<std::string>& audio_network_adaptor_config) {
903 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
904 if (config_.audio_network_adaptor_config == audio_network_adaptor_config) {
905 return;
906 }
907 config_.audio_network_adaptor_config = audio_network_adaptor_config;
ossu20a4b3f2017-04-27 02:08:52 -0700908 UpdateAllowedBitrateRange();
909 ReconfigureAudioSendStream();
minyue6b825df2016-10-31 04:08:32 -0700910 }
911
minyue7a973442016-10-20 03:27:12 -0700912 bool SetMaxSendBitrate(int bps) {
913 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
ossu20a4b3f2017-04-27 02:08:52 -0700914 RTC_DCHECK(config_.send_codec_spec);
915 RTC_DCHECK(audio_codec_spec_);
916 auto send_rate = ComputeSendBitrate(
917 bps, rtp_parameters_.encodings[0].max_bitrate_bps, *audio_codec_spec_);
918
minyue7a973442016-10-20 03:27:12 -0700919 if (!send_rate) {
920 return false;
921 }
922
923 max_send_bitrate_bps_ = bps;
924
ossu20a4b3f2017-04-27 02:08:52 -0700925 if (send_rate != config_.send_codec_spec->target_bitrate_bps) {
926 config_.send_codec_spec->target_bitrate_bps = send_rate;
927 ReconfigureAudioSendStream();
minyue7a973442016-10-20 03:27:12 -0700928 }
929 return true;
930 }
931
solenbergffbbcac2016-11-17 05:25:37 -0800932 bool SendTelephoneEvent(int payload_type, int payload_freq, int event,
933 int duration_ms) {
Fredrik Solenbergb5727682015-12-04 15:22:19 +0100934 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
935 RTC_DCHECK(stream_);
solenbergffbbcac2016-11-17 05:25:37 -0800936 return stream_->SendTelephoneEvent(payload_type, payload_freq, event,
937 duration_ms);
Fredrik Solenbergb5727682015-12-04 15:22:19 +0100938 }
939
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -0800940 void SetSend(bool send) {
941 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
942 send_ = send;
943 UpdateSendState();
944 }
945
solenberg94218532016-06-16 10:53:22 -0700946 void SetMuted(bool muted) {
947 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
948 RTC_DCHECK(stream_);
949 stream_->SetMuted(muted);
950 muted_ = muted;
951 }
952
953 bool muted() const {
954 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
955 return muted_;
956 }
957
solenberg3a941542015-11-16 07:34:50 -0800958 webrtc::AudioSendStream::Stats GetStats() const {
959 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
960 RTC_DCHECK(stream_);
961 return stream_->GetStats();
962 }
963
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -0800964 // Starts the sending by setting ourselves as a sink to the AudioSource to
965 // get data callbacks.
henrike@webrtc.orga7b98182014-02-21 15:51:43 +0000966 // This method is called on the libjingle worker thread.
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +0000967 // TODO(xians): Make sure Start() is called only once.
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -0800968 void SetSource(AudioSource* source) {
solenberg566ef242015-11-06 15:34:49 -0800969 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -0800970 RTC_DCHECK(source);
971 if (source_) {
972 RTC_DCHECK(source_ == source);
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +0000973 return;
974 }
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -0800975 source->SetSink(this);
976 source_ = source;
977 UpdateSendState();
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +0000978 }
979
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -0800980 // Stops sending by setting the sink of the AudioSource to nullptr. No data
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +0000981 // callback will be received after this method.
henrike@webrtc.orga7b98182014-02-21 15:51:43 +0000982 // This method is called on the libjingle worker thread.
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -0800983 void ClearSource() {
solenberg566ef242015-11-06 15:34:49 -0800984 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -0800985 if (source_) {
986 source_->SetSink(nullptr);
987 source_ = nullptr;
solenberg98c68862015-10-09 03:27:14 -0700988 }
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -0800989 UpdateSendState();
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +0000990 }
991
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -0800992 // AudioSource::Sink implementation.
henrike@webrtc.orga7b98182014-02-21 15:51:43 +0000993 // This method is called on the audio thread.
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +0000994 void OnData(const void* audio_data,
995 int bits_per_sample,
996 int sample_rate,
Peter Kasting69558702016-01-12 16:26:35 -0800997 size_t number_of_channels,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700998 size_t number_of_frames) override {
solenberg347ec5c2016-09-23 04:21:47 -0700999 RTC_CHECK_RUNS_SERIALIZED(&audio_capture_race_checker_);
solenbergc96df772015-10-21 13:01:53 -07001000 RTC_DCHECK(voe_audio_transport_);
maxmorin1aee0b52016-08-15 11:46:19 -07001001 voe_audio_transport_->PushCaptureData(config_.voe_channel_id, audio_data,
1002 bits_per_sample, sample_rate,
1003 number_of_channels, number_of_frames);
henrike@webrtc.orga7b98182014-02-21 15:51:43 +00001004 }
1005
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -08001006 // Callback from the |source_| when it is going away. In case Start() has
henrike@webrtc.orga7b98182014-02-21 15:51:43 +00001007 // never been called, this callback won't be triggered.
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +00001008 void OnClose() override {
solenberg566ef242015-11-06 15:34:49 -08001009 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -08001010 // Set |source_| to nullptr to make sure no more callback will get into
1011 // the source.
1012 source_ = nullptr;
1013 UpdateSendState();
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +00001014 }
1015
1016 // Accessor to the VoE channel ID.
solenberg85a04962015-10-27 03:35:21 -07001017 int channel() const {
solenberg566ef242015-11-06 15:34:49 -08001018 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenberg7add0582015-11-20 09:59:34 -08001019 return config_.voe_channel_id;
solenberg85a04962015-10-27 03:35:21 -07001020 }
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +00001021
skvlade0d46372016-04-07 22:59:22 -07001022 const webrtc::RtpParameters& rtp_parameters() const {
1023 return rtp_parameters_;
1024 }
1025
deadbeeffb2aced2017-01-06 23:05:37 -08001026 bool ValidateRtpParameters(const webrtc::RtpParameters& rtp_parameters) {
1027 if (rtp_parameters.encodings.size() != 1) {
1028 LOG(LS_ERROR)
1029 << "Attempted to set RtpParameters without exactly one encoding";
1030 return false;
1031 }
1032 if (rtp_parameters.encodings[0].ssrc != rtp_parameters_.encodings[0].ssrc) {
1033 LOG(LS_ERROR) << "Attempted to set RtpParameters with modified SSRC";
1034 return false;
1035 }
1036 return true;
1037 }
1038
minyue7a973442016-10-20 03:27:12 -07001039 bool SetRtpParameters(const webrtc::RtpParameters& parameters) {
deadbeeffb2aced2017-01-06 23:05:37 -08001040 if (!ValidateRtpParameters(parameters)) {
1041 return false;
1042 }
ossu20a4b3f2017-04-27 02:08:52 -07001043
1044 rtc::Optional<int> send_rate;
1045 if (audio_codec_spec_) {
1046 send_rate = ComputeSendBitrate(max_send_bitrate_bps_,
1047 parameters.encodings[0].max_bitrate_bps,
1048 *audio_codec_spec_);
1049 if (!send_rate) {
1050 return false;
1051 }
minyue7a973442016-10-20 03:27:12 -07001052 }
1053
minyuececec102017-03-27 13:04:25 -07001054 const rtc::Optional<int> old_rtp_max_bitrate =
1055 rtp_parameters_.encodings[0].max_bitrate_bps;
1056
skvlade0d46372016-04-07 22:59:22 -07001057 rtp_parameters_ = parameters;
minyue7a973442016-10-20 03:27:12 -07001058
minyuececec102017-03-27 13:04:25 -07001059 if (rtp_parameters_.encodings[0].max_bitrate_bps != old_rtp_max_bitrate) {
ossu20a4b3f2017-04-27 02:08:52 -07001060 // Reconfigure AudioSendStream with new bit rate.
1061 if (send_rate) {
1062 config_.send_codec_spec->target_bitrate_bps = send_rate;
1063 }
1064 UpdateAllowedBitrateRange();
1065 ReconfigureAudioSendStream();
minyue7a973442016-10-20 03:27:12 -07001066 } else {
1067 // parameters.encodings[0].active could have changed.
1068 UpdateSendState();
1069 }
1070 return true;
skvlade0d46372016-04-07 22:59:22 -07001071 }
1072
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +00001073 private:
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -08001074 void UpdateSendState() {
1075 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
1076 RTC_DCHECK(stream_);
Taylor Brandstetter55dd7082016-05-03 13:50:11 -07001077 RTC_DCHECK_EQ(1UL, rtp_parameters_.encodings.size());
1078 if (send_ && source_ != nullptr && rtp_parameters_.encodings[0].active) {
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -08001079 stream_->Start();
1080 } else { // !send || source_ = nullptr
1081 stream_->Stop();
1082 }
1083 }
1084
ossu20a4b3f2017-04-27 02:08:52 -07001085 void UpdateAllowedBitrateRange() {
michaelt53fe19d2016-10-18 09:39:22 -07001086 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
ossu20a4b3f2017-04-27 02:08:52 -07001087 const bool is_opus =
1088 config_.send_codec_spec &&
1089 !STR_CASE_CMP(config_.send_codec_spec->format.name.c_str(),
1090 kOpusCodecName);
1091 if (is_opus && webrtc::field_trial::IsEnabled("WebRTC-Audio-SendSideBwe")) {
stefane9f36d52017-01-24 08:18:45 -08001092 config_.min_bitrate_bps = kOpusMinBitrateBps;
minyuececec102017-03-27 13:04:25 -07001093
1094 // This means that when RtpParameters is reset, we may change the
ossu20a4b3f2017-04-27 02:08:52 -07001095 // encoder's bit rate immediately (through ReconfigureAudioSendStream()),
minyuececec102017-03-27 13:04:25 -07001096 // meanwhile change the cap to the output of BWE.
1097 config_.max_bitrate_bps =
1098 rtp_parameters_.encodings[0].max_bitrate_bps
1099 ? *rtp_parameters_.encodings[0].max_bitrate_bps
1100 : kOpusBitrateFbBps;
1101
michaelt53fe19d2016-10-18 09:39:22 -07001102 // TODO(mflodman): Keep testing this and set proper values.
1103 // Note: This is an early experiment currently only supported by Opus.
elad.alon0fe12162017-01-31 05:48:37 -08001104 if (send_side_bwe_with_overhead_) {
ossu20a4b3f2017-04-27 02:08:52 -07001105 const int max_packet_size_ms =
1106 WEBRTC_OPUS_SUPPORT_120MS_PTIME ? 120 : 60;
michaelt6672b262017-01-11 10:17:59 -08001107
ossu20a4b3f2017-04-27 02:08:52 -07001108 // OverheadPerPacket = Ipv4(20B) + UDP(8B) + SRTP(10B) + RTP(12)
1109 constexpr int kOverheadPerPacket = 20 + 8 + 10 + 12;
michaelt6672b262017-01-11 10:17:59 -08001110
ossu20a4b3f2017-04-27 02:08:52 -07001111 int min_overhead_bps =
1112 kOverheadPerPacket * 8 * 1000 / max_packet_size_ms;
michaelt6672b262017-01-11 10:17:59 -08001113
ossu20a4b3f2017-04-27 02:08:52 -07001114 // We assume that |config_.max_bitrate_bps| before the next line is
1115 // a hard limit on the payload bitrate, so we add min_overhead_bps to
1116 // it to ensure that, when overhead is deducted, the payload rate
1117 // never goes beyond the limit.
1118 // Note: this also means that if a higher overhead is forced, we
1119 // cannot reach the limit.
1120 // TODO(minyue): Reconsider this when the signaling to BWE is done
1121 // through a dedicated API.
1122 config_.max_bitrate_bps += min_overhead_bps;
michaelt6672b262017-01-11 10:17:59 -08001123
ossu20a4b3f2017-04-27 02:08:52 -07001124 // In contrast to max_bitrate_bps, we let min_bitrate_bps always be
1125 // reachable.
1126 config_.min_bitrate_bps += min_overhead_bps;
michaelt6672b262017-01-11 10:17:59 -08001127 }
michaelt53fe19d2016-10-18 09:39:22 -07001128 }
ossu20a4b3f2017-04-27 02:08:52 -07001129 }
1130
1131 void UpdateSendCodecSpec(
1132 const webrtc::AudioSendStream::Config::SendCodecSpec& send_codec_spec) {
1133 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
1134 config_.rtp.nack.rtp_history_ms =
1135 send_codec_spec.nack_enabled ? kNackRtpHistoryMs : 0;
1136 config_.send_codec_spec =
1137 rtc::Optional<webrtc::AudioSendStream::Config::SendCodecSpec>(
1138 send_codec_spec);
1139 auto info =
1140 config_.encoder_factory->QueryAudioEncoder(send_codec_spec.format);
1141 RTC_DCHECK(info);
1142 // If a specific target bitrate has been set for the stream, use that as
1143 // the new default bitrate when computing send bitrate.
1144 if (send_codec_spec.target_bitrate_bps) {
1145 info->default_bitrate_bps = std::max(
1146 info->min_bitrate_bps,
1147 std::min(info->max_bitrate_bps, *send_codec_spec.target_bitrate_bps));
1148 }
1149
1150 audio_codec_spec_.emplace(
1151 webrtc::AudioCodecSpec{send_codec_spec.format, *info});
1152
1153 config_.send_codec_spec->target_bitrate_bps = ComputeSendBitrate(
1154 max_send_bitrate_bps_, rtp_parameters_.encodings[0].max_bitrate_bps,
1155 *audio_codec_spec_);
1156
1157 UpdateAllowedBitrateRange();
1158 }
1159
1160 void ReconfigureAudioSendStream() {
1161 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
1162 RTC_DCHECK(stream_);
1163 stream_->Reconfigure(config_);
michaelt53fe19d2016-10-18 09:39:22 -07001164 }
1165
solenberg566ef242015-11-06 15:34:49 -08001166 rtc::ThreadChecker worker_thread_checker_;
solenberg347ec5c2016-09-23 04:21:47 -07001167 rtc::RaceChecker audio_capture_race_checker_;
solenbergc96df772015-10-21 13:01:53 -07001168 webrtc::AudioTransport* const voe_audio_transport_ = nullptr;
1169 webrtc::Call* call_ = nullptr;
solenberg3a941542015-11-16 07:34:50 -08001170 webrtc::AudioSendStream::Config config_;
elad.alon0fe12162017-01-31 05:48:37 -08001171 const bool send_side_bwe_with_overhead_;
solenberg3a941542015-11-16 07:34:50 -08001172 // The stream is owned by WebRtcAudioSendStream and may be reallocated if
1173 // configuration changes.
solenbergc96df772015-10-21 13:01:53 -07001174 webrtc::AudioSendStream* stream_ = nullptr;
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +00001175
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -08001176 // Raw pointer to AudioSource owned by LocalAudioTrackHandler.
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +00001177 // PeerConnection will make sure invalidating the pointer before the object
1178 // goes away.
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -08001179 AudioSource* source_ = nullptr;
1180 bool send_ = false;
solenberg94218532016-06-16 10:53:22 -07001181 bool muted_ = false;
minyue7a973442016-10-20 03:27:12 -07001182 int max_send_bitrate_bps_;
skvlade0d46372016-04-07 22:59:22 -07001183 webrtc::RtpParameters rtp_parameters_;
ossu20a4b3f2017-04-27 02:08:52 -07001184 rtc::Optional<webrtc::AudioCodecSpec> audio_codec_spec_;
henrike@webrtc.orga7b98182014-02-21 15:51:43 +00001185
solenbergc96df772015-10-21 13:01:53 -07001186 RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(WebRtcAudioSendStream);
1187};
1188
1189class WebRtcVoiceMediaChannel::WebRtcAudioReceiveStream {
1190 public:
ossu29b1a8d2016-06-13 07:34:51 -07001191 WebRtcAudioReceiveStream(
1192 int ch,
1193 uint32_t remote_ssrc,
1194 uint32_t local_ssrc,
1195 bool use_transport_cc,
solenberg8189b022016-06-14 12:13:00 -07001196 bool use_nack,
ossu29b1a8d2016-06-13 07:34:51 -07001197 const std::string& sync_group,
1198 const std::vector<webrtc::RtpExtension>& extensions,
1199 webrtc::Call* call,
1200 webrtc::Transport* rtcp_send_transport,
kwiberg1c07c702017-03-27 07:15:49 -07001201 const rtc::scoped_refptr<webrtc::AudioDecoderFactory>& decoder_factory,
1202 const std::map<int, webrtc::SdpAudioFormat>& decoder_map)
stefanba4c0e42016-02-04 04:12:24 -08001203 : call_(call), config_() {
solenberg7add0582015-11-20 09:59:34 -08001204 RTC_DCHECK_GE(ch, 0);
1205 RTC_DCHECK(call);
1206 config_.rtp.remote_ssrc = remote_ssrc;
kwibergd32bf752017-01-19 07:03:59 -08001207 config_.rtp.local_ssrc = local_ssrc;
1208 config_.rtp.transport_cc = use_transport_cc;
1209 config_.rtp.nack.rtp_history_ms = use_nack ? kNackRtpHistoryMs : 0;
1210 config_.rtp.extensions = extensions;
solenberg31fec402016-05-06 02:13:12 -07001211 config_.rtcp_send_transport = rtcp_send_transport;
solenberg7add0582015-11-20 09:59:34 -08001212 config_.voe_channel_id = ch;
1213 config_.sync_group = sync_group;
ossu29b1a8d2016-06-13 07:34:51 -07001214 config_.decoder_factory = decoder_factory;
kwiberg1c07c702017-03-27 07:15:49 -07001215 config_.decoder_map = decoder_map;
kwibergd32bf752017-01-19 07:03:59 -08001216 RecreateAudioReceiveStream();
solenberg7add0582015-11-20 09:59:34 -08001217 }
solenbergc96df772015-10-21 13:01:53 -07001218
solenberg7add0582015-11-20 09:59:34 -08001219 ~WebRtcAudioReceiveStream() {
1220 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
1221 call_->DestroyAudioReceiveStream(stream_);
1222 }
1223
solenberg4a0f7b52016-06-16 13:07:33 -07001224 void RecreateAudioReceiveStream(uint32_t local_ssrc) {
solenberg7add0582015-11-20 09:59:34 -08001225 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
kwibergd32bf752017-01-19 07:03:59 -08001226 config_.rtp.local_ssrc = local_ssrc;
1227 RecreateAudioReceiveStream();
solenberg7add0582015-11-20 09:59:34 -08001228 }
solenberg8189b022016-06-14 12:13:00 -07001229
1230 void RecreateAudioReceiveStream(bool use_transport_cc, bool use_nack) {
solenberg7add0582015-11-20 09:59:34 -08001231 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
kwibergd32bf752017-01-19 07:03:59 -08001232 config_.rtp.transport_cc = use_transport_cc;
1233 config_.rtp.nack.rtp_history_ms = use_nack ? kNackRtpHistoryMs : 0;
1234 RecreateAudioReceiveStream();
solenberg7add0582015-11-20 09:59:34 -08001235 }
1236
solenberg4a0f7b52016-06-16 13:07:33 -07001237 void RecreateAudioReceiveStream(
1238 const std::vector<webrtc::RtpExtension>& extensions) {
1239 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
kwibergd32bf752017-01-19 07:03:59 -08001240 config_.rtp.extensions = extensions;
1241 RecreateAudioReceiveStream();
1242 }
1243
deadbeefcb383672017-04-26 16:28:42 -07001244 // Set a new payload type -> decoder map.
kwibergd32bf752017-01-19 07:03:59 -08001245 void RecreateAudioReceiveStream(
1246 const std::map<int, webrtc::SdpAudioFormat>& decoder_map) {
1247 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
kwibergd32bf752017-01-19 07:03:59 -08001248 config_.decoder_map = decoder_map;
1249 RecreateAudioReceiveStream();
solenberg4a0f7b52016-06-16 13:07:33 -07001250 }
1251
solenberg4904fb62017-02-17 12:01:14 -08001252 void MaybeRecreateAudioReceiveStream(const std::string& sync_group) {
1253 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
1254 if (config_.sync_group != sync_group) {
1255 config_.sync_group = sync_group;
1256 RecreateAudioReceiveStream();
1257 }
1258 }
1259
solenberg7add0582015-11-20 09:59:34 -08001260 webrtc::AudioReceiveStream::Stats GetStats() const {
1261 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
1262 RTC_DCHECK(stream_);
1263 return stream_->GetStats();
1264 }
1265
solenberg796b8f92017-03-01 17:02:23 -08001266 int GetOutputLevel() const {
1267 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
1268 RTC_DCHECK(stream_);
1269 return stream_->GetOutputLevel();
1270 }
1271
solenberg7add0582015-11-20 09:59:34 -08001272 int channel() const {
1273 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
1274 return config_.voe_channel_id;
1275 }
solenbergc96df772015-10-21 13:01:53 -07001276
kwiberg686a8ef2016-02-26 03:00:35 -08001277 void SetRawAudioSink(std::unique_ptr<webrtc::AudioSinkInterface> sink) {
Tommif888bb52015-12-12 01:37:01 +01001278 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
kwiberg686a8ef2016-02-26 03:00:35 -08001279 stream_->SetSink(std::move(sink));
Tommif888bb52015-12-12 01:37:01 +01001280 }
1281
solenberg217fb662016-06-17 08:30:54 -07001282 void SetOutputVolume(double volume) {
1283 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
1284 stream_->SetGain(volume);
1285 }
1286
aleloi84ef6152016-08-04 05:28:21 -07001287 void SetPlayout(bool playout) {
1288 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
1289 RTC_DCHECK(stream_);
1290 if (playout) {
1291 LOG(LS_INFO) << "Starting playout for channel #" << channel();
1292 stream_->Start();
1293 } else {
1294 LOG(LS_INFO) << "Stopping playout for channel #" << channel();
1295 stream_->Stop();
1296 }
aleloi18e0b672016-10-04 02:45:47 -07001297 playout_ = playout;
aleloi84ef6152016-08-04 05:28:21 -07001298 }
1299
hbos8d609f62017-04-10 07:39:05 -07001300 std::vector<webrtc::RtpSource> GetSources() {
1301 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
1302 RTC_DCHECK(stream_);
1303 return stream_->GetSources();
1304 }
1305
solenbergc96df772015-10-21 13:01:53 -07001306 private:
kwibergd32bf752017-01-19 07:03:59 -08001307 void RecreateAudioReceiveStream() {
solenberg7add0582015-11-20 09:59:34 -08001308 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
1309 if (stream_) {
1310 call_->DestroyAudioReceiveStream(stream_);
solenberg7add0582015-11-20 09:59:34 -08001311 }
solenberg7add0582015-11-20 09:59:34 -08001312 stream_ = call_->CreateAudioReceiveStream(config_);
1313 RTC_CHECK(stream_);
aleloi18e0b672016-10-04 02:45:47 -07001314 SetPlayout(playout_);
solenberg7add0582015-11-20 09:59:34 -08001315 }
1316
1317 rtc::ThreadChecker worker_thread_checker_;
1318 webrtc::Call* call_ = nullptr;
1319 webrtc::AudioReceiveStream::Config config_;
1320 // The stream is owned by WebRtcAudioReceiveStream and may be reallocated if
1321 // configuration changes.
1322 webrtc::AudioReceiveStream* stream_ = nullptr;
aleloi18e0b672016-10-04 02:45:47 -07001323 bool playout_ = false;
solenbergc96df772015-10-21 13:01:53 -07001324
1325 RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(WebRtcAudioReceiveStream);
henrike@webrtc.org1e09a712013-07-26 19:17:59 +00001326};
1327
Fredrik Solenberg709ed672015-09-15 12:26:33 +02001328WebRtcVoiceMediaChannel::WebRtcVoiceMediaChannel(WebRtcVoiceEngine* engine,
nisse51542be2016-02-12 02:27:06 -08001329 const MediaConfig& config,
Fredrik Solenbergb071a192015-09-17 16:42:56 +02001330 const AudioOptions& options,
Fredrik Solenberg709ed672015-09-15 12:26:33 +02001331 webrtc::Call* call)
nisse51542be2016-02-12 02:27:06 -08001332 : VoiceMediaChannel(config), engine_(engine), call_(call) {
solenberg0a617e22015-10-20 15:49:38 -07001333 LOG(LS_VERBOSE) << "WebRtcVoiceMediaChannel::WebRtcVoiceMediaChannel";
solenberg566ef242015-11-06 15:34:49 -08001334 RTC_DCHECK(call);
solenberg0a617e22015-10-20 15:49:38 -07001335 engine->RegisterChannel(this);
Fredrik Solenbergb071a192015-09-17 16:42:56 +02001336 SetOptions(options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001337}
1338
1339WebRtcVoiceMediaChannel::~WebRtcVoiceMediaChannel() {
solenberg566ef242015-11-06 15:34:49 -08001340 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenberg0a617e22015-10-20 15:49:38 -07001341 LOG(LS_VERBOSE) << "WebRtcVoiceMediaChannel::~WebRtcVoiceMediaChannel";
solenberg7add0582015-11-20 09:59:34 -08001342 // TODO(solenberg): Should be able to delete the streams directly, without
1343 // going through RemoveNnStream(), once stream objects handle
1344 // all (de)configuration.
solenbergc96df772015-10-21 13:01:53 -07001345 while (!send_streams_.empty()) {
1346 RemoveSendStream(send_streams_.begin()->first);
solenbergd97ec302015-10-07 01:40:33 -07001347 }
solenberg7add0582015-11-20 09:59:34 -08001348 while (!recv_streams_.empty()) {
1349 RemoveRecvStream(recv_streams_.begin()->first);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001350 }
solenberg0a617e22015-10-20 15:49:38 -07001351 engine()->UnregisterChannel(this);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001352}
1353
nisse51542be2016-02-12 02:27:06 -08001354rtc::DiffServCodePoint WebRtcVoiceMediaChannel::PreferredDscp() const {
1355 return kAudioDscpValue;
1356}
1357
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001358bool WebRtcVoiceMediaChannel::SetSendParameters(
1359 const AudioSendParameters& params) {
Peter Boströmca8b4042016-03-08 14:24:13 -08001360 TRACE_EVENT0("webrtc", "WebRtcVoiceMediaChannel::SetSendParameters");
solenberg566ef242015-11-06 15:34:49 -08001361 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenberg7e4e01a2015-12-02 08:05:01 -08001362 LOG(LS_INFO) << "WebRtcVoiceMediaChannel::SetSendParameters: "
1363 << params.ToString();
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001364 // TODO(pthatcher): Refactor this to be more clean now that we have
1365 // all the information at once.
solenberg3a941542015-11-16 07:34:50 -08001366
1367 if (!SetSendCodecs(params.codecs)) {
1368 return false;
1369 }
1370
solenberg7e4e01a2015-12-02 08:05:01 -08001371 if (!ValidateRtpExtensions(params.extensions)) {
1372 return false;
1373 }
1374 std::vector<webrtc::RtpExtension> filtered_extensions =
1375 FilterRtpExtensions(params.extensions,
1376 webrtc::RtpExtension::IsSupportedForAudio, true);
1377 if (send_rtp_extensions_ != filtered_extensions) {
1378 send_rtp_extensions_.swap(filtered_extensions);
solenberg3a941542015-11-16 07:34:50 -08001379 for (auto& it : send_streams_) {
ossu20a4b3f2017-04-27 02:08:52 -07001380 it.second->SetRtpExtensions(send_rtp_extensions_);
solenberg3a941542015-11-16 07:34:50 -08001381 }
1382 }
1383
deadbeef80346142016-04-27 14:17:10 -07001384 if (!SetMaxSendBitrate(params.max_bandwidth_bps)) {
solenberg3a941542015-11-16 07:34:50 -08001385 return false;
1386 }
1387 return SetOptions(params.options);
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001388}
1389
1390bool WebRtcVoiceMediaChannel::SetRecvParameters(
1391 const AudioRecvParameters& params) {
Peter Boströmca8b4042016-03-08 14:24:13 -08001392 TRACE_EVENT0("webrtc", "WebRtcVoiceMediaChannel::SetRecvParameters");
solenberg566ef242015-11-06 15:34:49 -08001393 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenberg7e4e01a2015-12-02 08:05:01 -08001394 LOG(LS_INFO) << "WebRtcVoiceMediaChannel::SetRecvParameters: "
1395 << params.ToString();
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001396 // TODO(pthatcher): Refactor this to be more clean now that we have
1397 // all the information at once.
solenberg7add0582015-11-20 09:59:34 -08001398
1399 if (!SetRecvCodecs(params.codecs)) {
1400 return false;
1401 }
1402
solenberg7e4e01a2015-12-02 08:05:01 -08001403 if (!ValidateRtpExtensions(params.extensions)) {
1404 return false;
1405 }
1406 std::vector<webrtc::RtpExtension> filtered_extensions =
1407 FilterRtpExtensions(params.extensions,
1408 webrtc::RtpExtension::IsSupportedForAudio, false);
1409 if (recv_rtp_extensions_ != filtered_extensions) {
1410 recv_rtp_extensions_.swap(filtered_extensions);
solenberg7add0582015-11-20 09:59:34 -08001411 for (auto& it : recv_streams_) {
1412 it.second->RecreateAudioReceiveStream(recv_rtp_extensions_);
1413 }
1414 }
solenberg7add0582015-11-20 09:59:34 -08001415 return true;
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001416}
1417
Taylor Brandstetterdb0cd9e2016-05-16 11:40:30 -07001418webrtc::RtpParameters WebRtcVoiceMediaChannel::GetRtpSendParameters(
skvlade0d46372016-04-07 22:59:22 -07001419 uint32_t ssrc) const {
1420 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
1421 auto it = send_streams_.find(ssrc);
1422 if (it == send_streams_.end()) {
Taylor Brandstetterdb0cd9e2016-05-16 11:40:30 -07001423 LOG(LS_WARNING) << "Attempting to get RTP send parameters for stream "
1424 << "with ssrc " << ssrc << " which doesn't exist.";
skvlade0d46372016-04-07 22:59:22 -07001425 return webrtc::RtpParameters();
1426 }
1427
Taylor Brandstetter0cd086b2016-04-20 16:23:10 -07001428 webrtc::RtpParameters rtp_params = it->second->rtp_parameters();
1429 // Need to add the common list of codecs to the send stream-specific
1430 // RTP parameters.
1431 for (const AudioCodec& codec : send_codecs_) {
1432 rtp_params.codecs.push_back(codec.ToCodecParameters());
1433 }
1434 return rtp_params;
skvlade0d46372016-04-07 22:59:22 -07001435}
1436
Taylor Brandstetterdb0cd9e2016-05-16 11:40:30 -07001437bool WebRtcVoiceMediaChannel::SetRtpSendParameters(
skvlade0d46372016-04-07 22:59:22 -07001438 uint32_t ssrc,
1439 const webrtc::RtpParameters& parameters) {
1440 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
skvlade0d46372016-04-07 22:59:22 -07001441 auto it = send_streams_.find(ssrc);
1442 if (it == send_streams_.end()) {
Taylor Brandstetterdb0cd9e2016-05-16 11:40:30 -07001443 LOG(LS_WARNING) << "Attempting to set RTP send parameters for stream "
1444 << "with ssrc " << ssrc << " which doesn't exist.";
skvlade0d46372016-04-07 22:59:22 -07001445 return false;
1446 }
1447
Taylor Brandstetterdb0cd9e2016-05-16 11:40:30 -07001448 // TODO(deadbeef): Handle setting parameters with a list of codecs in a
1449 // different order (which should change the send codec).
1450 webrtc::RtpParameters current_parameters = GetRtpSendParameters(ssrc);
1451 if (current_parameters.codecs != parameters.codecs) {
1452 LOG(LS_ERROR) << "Using SetParameters to change the set of codecs "
1453 << "is not currently supported.";
1454 return false;
1455 }
1456
minyue7a973442016-10-20 03:27:12 -07001457 // TODO(minyue): The following legacy actions go into
1458 // |WebRtcAudioSendStream::SetRtpParameters()| which is called at the end,
1459 // though there are two difference:
1460 // 1. |WebRtcVoiceMediaChannel::SetChannelSendParameters()| only calls
1461 // |SetSendCodec| while |WebRtcAudioSendStream::SetRtpParameters()| calls
1462 // |SetSendCodecs|. The outcome should be the same.
1463 // 2. AudioSendStream can be recreated.
1464
Taylor Brandstetter0cd086b2016-04-20 16:23:10 -07001465 // Codecs are handled at the WebRtcVoiceMediaChannel level.
1466 webrtc::RtpParameters reduced_params = parameters;
1467 reduced_params.codecs.clear();
minyue7a973442016-10-20 03:27:12 -07001468 return it->second->SetRtpParameters(reduced_params);
skvlade0d46372016-04-07 22:59:22 -07001469}
1470
Taylor Brandstetterdb0cd9e2016-05-16 11:40:30 -07001471webrtc::RtpParameters WebRtcVoiceMediaChannel::GetRtpReceiveParameters(
1472 uint32_t ssrc) const {
1473 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
deadbeef3bc15102017-04-20 19:25:07 -07001474 webrtc::RtpParameters rtp_params;
1475 // SSRC of 0 represents the default receive stream.
1476 if (ssrc == 0) {
1477 if (!default_sink_) {
1478 LOG(LS_WARNING) << "Attempting to get RTP parameters for the default, "
1479 "unsignaled audio receive stream, but not yet "
1480 "configured to receive such a stream.";
1481 return rtp_params;
1482 }
1483 rtp_params.encodings.emplace_back();
1484 } else {
1485 auto it = recv_streams_.find(ssrc);
1486 if (it == recv_streams_.end()) {
1487 LOG(LS_WARNING) << "Attempting to get RTP receive parameters for stream "
1488 << "with ssrc " << ssrc << " which doesn't exist.";
1489 return webrtc::RtpParameters();
1490 }
1491 rtp_params.encodings.emplace_back();
1492 // TODO(deadbeef): Return stream-specific parameters.
1493 rtp_params.encodings[0].ssrc = rtc::Optional<uint32_t>(ssrc);
Taylor Brandstetterdb0cd9e2016-05-16 11:40:30 -07001494 }
1495
Taylor Brandstetterdb0cd9e2016-05-16 11:40:30 -07001496 for (const AudioCodec& codec : recv_codecs_) {
1497 rtp_params.codecs.push_back(codec.ToCodecParameters());
1498 }
1499 return rtp_params;
1500}
1501
1502bool WebRtcVoiceMediaChannel::SetRtpReceiveParameters(
1503 uint32_t ssrc,
1504 const webrtc::RtpParameters& parameters) {
1505 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
deadbeef3bc15102017-04-20 19:25:07 -07001506 // SSRC of 0 represents the default receive stream.
1507 if (ssrc == 0) {
1508 if (!default_sink_) {
1509 LOG(LS_WARNING) << "Attempting to set RTP parameters for the default, "
1510 "unsignaled audio receive stream, but not yet "
1511 "configured to receive such a stream.";
1512 return false;
1513 }
1514 } else {
1515 auto it = recv_streams_.find(ssrc);
1516 if (it == recv_streams_.end()) {
1517 LOG(LS_WARNING) << "Attempting to set RTP receive parameters for stream "
1518 << "with ssrc " << ssrc << " which doesn't exist.";
1519 return false;
1520 }
Taylor Brandstetterdb0cd9e2016-05-16 11:40:30 -07001521 }
1522
1523 webrtc::RtpParameters current_parameters = GetRtpReceiveParameters(ssrc);
1524 if (current_parameters != parameters) {
1525 LOG(LS_ERROR) << "Changing the RTP receive parameters is currently "
1526 << "unsupported.";
1527 return false;
1528 }
1529 return true;
1530}
1531
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001532bool WebRtcVoiceMediaChannel::SetOptions(const AudioOptions& options) {
solenberg566ef242015-11-06 15:34:49 -08001533 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001534 LOG(LS_INFO) << "Setting voice channel options: "
1535 << options.ToString();
1536
1537 // We retain all of the existing options, and apply the given ones
1538 // on top. This means there is no way to "clear" options such that
1539 // they go back to the engine default.
1540 options_.SetAll(options);
solenberg246b8172015-12-08 09:50:23 -08001541 if (!engine()->ApplyOptions(options_)) {
1542 LOG(LS_WARNING) <<
1543 "Failed to apply engine options during channel SetOptions.";
1544 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001545 }
minyue6b825df2016-10-31 04:08:32 -07001546
ossu20a4b3f2017-04-27 02:08:52 -07001547 rtc::Optional<std::string> audio_network_adaptor_config =
minyue6b825df2016-10-31 04:08:32 -07001548 GetAudioNetworkAdaptorConfig(options_);
1549 for (auto& it : send_streams_) {
ossu20a4b3f2017-04-27 02:08:52 -07001550 it.second->SetAudioNetworkAdaptorConfig(audio_network_adaptor_config);
minyue6b825df2016-10-31 04:08:32 -07001551 }
1552
solenberg76377c52017-02-21 00:54:31 -08001553 LOG(LS_INFO) << "Set voice channel options. Current options: "
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001554 << options_.ToString();
1555 return true;
1556}
1557
1558bool WebRtcVoiceMediaChannel::SetRecvCodecs(
1559 const std::vector<AudioCodec>& codecs) {
solenberg566ef242015-11-06 15:34:49 -08001560 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenberg8fb30c32015-10-13 03:06:58 -07001561
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001562 // Set the payload types to be used for incoming media.
solenberg0b675462015-10-09 01:37:09 -07001563 LOG(LS_INFO) << "Setting receive voice codecs.";
solenberg0b675462015-10-09 01:37:09 -07001564
1565 if (!VerifyUniquePayloadTypes(codecs)) {
1566 LOG(LS_ERROR) << "Codec payload types overlap.";
1567 return false;
1568 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001569
kwibergd32bf752017-01-19 07:03:59 -08001570 // Create a payload type -> SdpAudioFormat map with all the decoders. Fail
1571 // unless the factory claims to support all decoders.
1572 std::map<int, webrtc::SdpAudioFormat> decoder_map;
1573 for (const AudioCodec& codec : codecs) {
deadbeefcb383672017-04-26 16:28:42 -07001574 // Log a warning if a codec's payload type is changing. This used to be
1575 // treated as an error. It's abnormal, but not really illegal.
1576 AudioCodec old_codec;
1577 if (FindCodec(recv_codecs_, codec, &old_codec) &&
1578 old_codec.id != codec.id) {
1579 LOG(LS_WARNING) << codec.name << " mapped to a second payload type ("
1580 << codec.id << ", was already mapped to " << old_codec.id
1581 << ")";
1582 }
kwibergd32bf752017-01-19 07:03:59 -08001583 auto format = AudioCodecToSdpAudioFormat(codec);
1584 if (!IsCodec(codec, "cn") && !IsCodec(codec, "telephone-event") &&
1585 !engine()->decoder_factory_->IsSupportedDecoder(format)) {
1586 LOG(LS_ERROR) << "Unsupported codec: " << format;
1587 return false;
1588 }
deadbeefcb383672017-04-26 16:28:42 -07001589 // We allow adding new codecs but don't allow changing the payload type of
1590 // codecs that are already configured since we might already be receiving
1591 // packets with that payload type. See RFC3264, Section 8.3.2.
1592 // TODO(deadbeef): Also need to check for clashes with previously mapped
1593 // payload types, and not just currently mapped ones. For example, this
1594 // should be illegal:
1595 // 1. {100: opus/48000/2, 101: ISAC/16000}
1596 // 2. {100: opus/48000/2}
1597 // 3. {100: opus/48000/2, 101: ISAC/32000}
1598 // Though this check really should happen at a higher level, since this
1599 // conflict could happen between audio and video codecs.
1600 auto existing = decoder_map_.find(codec.id);
1601 if (existing != decoder_map_.end() && !existing->second.Matches(format)) {
1602 LOG(LS_ERROR) << "Attempting to use payload type " << codec.id << " for "
1603 << codec.name << ", but it is already used for "
1604 << existing->second.name;
1605 return false;
1606 }
kwibergd32bf752017-01-19 07:03:59 -08001607 decoder_map.insert({codec.id, std::move(format)});
1608 }
1609
deadbeefcb383672017-04-26 16:28:42 -07001610 if (decoder_map == decoder_map_) {
1611 // There's nothing new to configure.
1612 return true;
1613 }
1614
kwiberg37b8b112016-11-03 02:46:53 -07001615 if (playout_) {
1616 // Receive codecs can not be changed while playing. So we temporarily
1617 // pause playout.
1618 ChangePlayout(false);
1619 }
1620
kwiberg1c07c702017-03-27 07:15:49 -07001621 decoder_map_ = std::move(decoder_map);
kwibergd32bf752017-01-19 07:03:59 -08001622 for (auto& kv : recv_streams_) {
kwiberg1c07c702017-03-27 07:15:49 -07001623 kv.second->RecreateAudioReceiveStream(decoder_map_);
solenberg26c8c912015-11-27 04:00:25 -08001624 }
kwibergd32bf752017-01-19 07:03:59 -08001625 recv_codecs_ = codecs;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001626
kwiberg37b8b112016-11-03 02:46:53 -07001627 if (desired_playout_ && !playout_) {
1628 ChangePlayout(desired_playout_);
1629 }
kwibergd32bf752017-01-19 07:03:59 -08001630 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001631}
1632
solenberg72e29d22016-03-08 06:35:16 -08001633// Utility function called from SetSendParameters() to extract current send
1634// codec settings from the given list of codecs (originally from SDP). Both send
1635// and receive streams may be reconfigured based on the new settings.
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00001636bool WebRtcVoiceMediaChannel::SetSendCodecs(
1637 const std::vector<AudioCodec>& codecs) {
solenberg566ef242015-11-06 15:34:49 -08001638 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
Fredrik Solenbergb5727682015-12-04 15:22:19 +01001639 dtmf_payload_type_ = rtc::Optional<int>();
solenbergffbbcac2016-11-17 05:25:37 -08001640 dtmf_payload_freq_ = -1;
1641
1642 // Validate supplied codecs list.
1643 for (const AudioCodec& codec : codecs) {
1644 // TODO(solenberg): Validate more aspects of input - that payload types
1645 // don't overlap, remove redundant/unsupported codecs etc -
1646 // the same way it is done for RtpHeaderExtensions.
1647 if (codec.id < kMinPayloadType || codec.id > kMaxPayloadType) {
1648 LOG(LS_WARNING) << "Codec payload type out of range: " << ToString(codec);
1649 return false;
1650 }
1651 }
1652
1653 // Find PT of telephone-event codec with lowest clockrate, as a fallback, in
1654 // case we don't have a DTMF codec with a rate matching the send codec's, or
1655 // if this function returns early.
1656 std::vector<AudioCodec> dtmf_codecs;
Fredrik Solenbergaf9fb212015-08-26 10:45:53 +02001657 for (const AudioCodec& codec : codecs) {
Fredrik Solenbergaf9fb212015-08-26 10:45:53 +02001658 if (IsCodec(codec, kDtmfCodecName)) {
solenbergffbbcac2016-11-17 05:25:37 -08001659 dtmf_codecs.push_back(codec);
1660 if (!dtmf_payload_type_ || codec.clockrate < dtmf_payload_freq_) {
1661 dtmf_payload_type_ = rtc::Optional<int>(codec.id);
1662 dtmf_payload_freq_ = codec.clockrate;
solenberg31642aa2016-03-14 08:00:37 -07001663 }
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00001664 }
1665 }
1666
ossu20a4b3f2017-04-27 02:08:52 -07001667 // Scan through the list to figure out the codec to use for sending.
1668 rtc::Optional<webrtc::AudioSendStream::Config::SendCodecSpec> send_codec_spec;
stefan1ccf73f2017-03-27 03:51:18 -07001669 webrtc::Call::Config::BitrateConfig bitrate_config;
ossu20a4b3f2017-04-27 02:08:52 -07001670 rtc::Optional<webrtc::AudioCodecInfo> voice_codec_info;
1671 for (const AudioCodec& voice_codec : codecs) {
1672 if (!(IsCodec(voice_codec, kCnCodecName) ||
1673 IsCodec(voice_codec, kDtmfCodecName) ||
1674 IsCodec(voice_codec, kRedCodecName))) {
1675 webrtc::SdpAudioFormat format(voice_codec.name, voice_codec.clockrate,
1676 voice_codec.channels, voice_codec.params);
solenberg72e29d22016-03-08 06:35:16 -08001677
ossu20a4b3f2017-04-27 02:08:52 -07001678 voice_codec_info = engine()->encoder_factory_->QueryAudioEncoder(format);
1679 if (!voice_codec_info) {
1680 LOG(LS_WARNING) << "Unknown codec " << ToString(voice_codec);
solenberg72e29d22016-03-08 06:35:16 -08001681 continue;
1682 }
1683
ossu20a4b3f2017-04-27 02:08:52 -07001684 send_codec_spec =
1685 rtc::Optional<webrtc::AudioSendStream::Config::SendCodecSpec>(
1686 {voice_codec.id, format});
1687 if (voice_codec.bitrate > 0) {
1688 send_codec_spec->target_bitrate_bps =
1689 rtc::Optional<int>(voice_codec.bitrate);
1690 }
1691 send_codec_spec->transport_cc_enabled = HasTransportCc(voice_codec);
1692 send_codec_spec->nack_enabled = HasNack(voice_codec);
1693 bitrate_config = GetBitrateConfigForCodec(voice_codec);
1694 break;
1695 }
1696 }
1697
1698 if (!send_codec_spec) {
1699 return false;
1700 }
1701
1702 RTC_DCHECK(voice_codec_info);
1703 if (voice_codec_info->allow_comfort_noise) {
1704 // Loop through the codecs list again to find the CN codec.
1705 // TODO(solenberg): Break out into a separate function?
1706 for (const AudioCodec& cn_codec : codecs) {
ossu0c4b8492017-03-02 11:03:25 -08001707 if (IsCodec(cn_codec, kCnCodecName) &&
ossu20a4b3f2017-04-27 02:08:52 -07001708 cn_codec.clockrate == send_codec_spec->format.clockrate_hz) {
ossu0c4b8492017-03-02 11:03:25 -08001709 switch (cn_codec.clockrate) {
solenberg72e29d22016-03-08 06:35:16 -08001710 case 8000:
1711 case 16000:
1712 case 32000:
ossu20a4b3f2017-04-27 02:08:52 -07001713 send_codec_spec->cng_payload_type = rtc::Optional<int>(cn_codec.id);
solenberg72e29d22016-03-08 06:35:16 -08001714 break;
1715 default:
ossu0c4b8492017-03-02 11:03:25 -08001716 LOG(LS_WARNING) << "CN frequency " << cn_codec.clockrate
solenberg72e29d22016-03-08 06:35:16 -08001717 << " not supported.";
ossu20a4b3f2017-04-27 02:08:52 -07001718 break;
solenberg72e29d22016-03-08 06:35:16 -08001719 }
solenberg72e29d22016-03-08 06:35:16 -08001720 break;
1721 }
1722 }
solenbergffbbcac2016-11-17 05:25:37 -08001723
1724 // Find the telephone-event PT exactly matching the preferred send codec.
1725 for (const AudioCodec& dtmf_codec : dtmf_codecs) {
ossu20a4b3f2017-04-27 02:08:52 -07001726 if (dtmf_codec.clockrate == send_codec_spec->format.clockrate_hz) {
solenbergffbbcac2016-11-17 05:25:37 -08001727 dtmf_payload_type_ = rtc::Optional<int>(dtmf_codec.id);
1728 dtmf_payload_freq_ = dtmf_codec.clockrate;
1729 break;
1730 }
1731 }
solenberg72e29d22016-03-08 06:35:16 -08001732 }
1733
solenberg971cab02016-06-14 10:02:41 -07001734 if (send_codec_spec_ != send_codec_spec) {
1735 send_codec_spec_ = std::move(send_codec_spec);
stefan13f1a0a2016-11-30 07:22:58 -08001736 // Apply new settings to all streams.
solenberg971cab02016-06-14 10:02:41 -07001737 for (const auto& kv : send_streams_) {
ossu20a4b3f2017-04-27 02:08:52 -07001738 kv.second->SetSendCodecSpec(*send_codec_spec_);
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00001739 }
stefan13f1a0a2016-11-30 07:22:58 -08001740 } else {
1741 // If the codec isn't changing, set the start bitrate to -1 which means
1742 // "unchanged" so that BWE isn't affected.
stefan1ccf73f2017-03-27 03:51:18 -07001743 bitrate_config.start_bitrate_bps = -1;
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00001744 }
stefan1ccf73f2017-03-27 03:51:18 -07001745 call_->SetBitrateConfig(bitrate_config);
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00001746
solenberg8189b022016-06-14 12:13:00 -07001747 // Check if the transport cc feedback or NACK status has changed on the
1748 // preferred send codec, and in that case reconfigure all receive streams.
ossu20a4b3f2017-04-27 02:08:52 -07001749 if (recv_transport_cc_enabled_ != send_codec_spec_->transport_cc_enabled ||
1750 recv_nack_enabled_ != send_codec_spec_->nack_enabled) {
solenberg72e29d22016-03-08 06:35:16 -08001751 LOG(LS_INFO) << "Recreate all the receive streams because the send "
1752 "codec has changed.";
ossu20a4b3f2017-04-27 02:08:52 -07001753 recv_transport_cc_enabled_ = send_codec_spec_->transport_cc_enabled;
1754 recv_nack_enabled_ = send_codec_spec_->nack_enabled;
solenberg72e29d22016-03-08 06:35:16 -08001755 for (auto& kv : recv_streams_) {
solenberg8189b022016-06-14 12:13:00 -07001756 kv.second->RecreateAudioReceiveStream(recv_transport_cc_enabled_,
1757 recv_nack_enabled_);
solenberg72e29d22016-03-08 06:35:16 -08001758 }
1759 }
1760
Taylor Brandstetter0cd086b2016-04-20 16:23:10 -07001761 send_codecs_ = codecs;
solenberg72e29d22016-03-08 06:35:16 -08001762 return true;
1763}
1764
aleloi84ef6152016-08-04 05:28:21 -07001765void WebRtcVoiceMediaChannel::SetPlayout(bool playout) {
kwiberg37b8b112016-11-03 02:46:53 -07001766 desired_playout_ = playout;
1767 return ChangePlayout(desired_playout_);
1768}
1769
1770void WebRtcVoiceMediaChannel::ChangePlayout(bool playout) {
1771 TRACE_EVENT0("webrtc", "WebRtcVoiceMediaChannel::ChangePlayout");
solenberg566ef242015-11-06 15:34:49 -08001772 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001773 if (playout_ == playout) {
aleloi84ef6152016-08-04 05:28:21 -07001774 return;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001775 }
1776
aleloi84ef6152016-08-04 05:28:21 -07001777 for (const auto& kv : recv_streams_) {
1778 kv.second->SetPlayout(playout);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001779 }
solenberg1ac56142015-10-13 03:58:19 -07001780 playout_ = playout;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001781}
1782
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -08001783void WebRtcVoiceMediaChannel::SetSend(bool send) {
Peter Boströmca8b4042016-03-08 14:24:13 -08001784 TRACE_EVENT0("webrtc", "WebRtcVoiceMediaChannel::SetSend");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001785 if (send_ == send) {
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -08001786 return;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001787 }
1788
solenbergd53a3f92016-04-14 13:56:37 -07001789 // Apply channel specific options, and initialize the ADM for recording (this
1790 // may take time on some platforms, e.g. Android).
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -08001791 if (send) {
solenberg63b34542015-09-29 06:06:31 -07001792 engine()->ApplyOptions(options_);
solenbergd53a3f92016-04-14 13:56:37 -07001793
1794 // InitRecording() may return an error if the ADM is already recording.
1795 if (!engine()->adm()->RecordingIsInitialized() &&
1796 !engine()->adm()->Recording()) {
1797 if (engine()->adm()->InitRecording() != 0) {
1798 LOG(LS_WARNING) << "Failed to initialize recording";
1799 }
1800 }
solenberg63b34542015-09-29 06:06:31 -07001801 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001802
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001803 // Change the settings on each send channel.
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -08001804 for (auto& kv : send_streams_) {
1805 kv.second->SetSend(send);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001806 }
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001807
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001808 send_ = send;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001809}
1810
Peter Boström0c4e06b2015-10-07 12:23:21 +02001811bool WebRtcVoiceMediaChannel::SetAudioSend(uint32_t ssrc,
1812 bool enable,
solenberg1dd98f32015-09-10 01:57:14 -07001813 const AudioOptions* options,
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -08001814 AudioSource* source) {
solenberg566ef242015-11-06 15:34:49 -08001815 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenberg1dd98f32015-09-10 01:57:14 -07001816 // TODO(solenberg): The state change should be fully rolled back if any one of
1817 // these calls fail.
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -08001818 if (!SetLocalSource(ssrc, source)) {
solenberg1dd98f32015-09-10 01:57:14 -07001819 return false;
1820 }
solenbergdfc8f4f2015-10-01 02:31:10 -07001821 if (!MuteStream(ssrc, !enable)) {
solenberg1dd98f32015-09-10 01:57:14 -07001822 return false;
1823 }
solenbergdfc8f4f2015-10-01 02:31:10 -07001824 if (enable && options) {
solenberg1dd98f32015-09-10 01:57:14 -07001825 return SetOptions(*options);
1826 }
1827 return true;
1828}
1829
solenberg0a617e22015-10-20 15:49:38 -07001830int WebRtcVoiceMediaChannel::CreateVoEChannel() {
1831 int id = engine()->CreateVoEChannel();
1832 if (id == -1) {
solenberg35dee812017-09-18 01:57:01 -07001833 LOG(LS_WARNING) << "CreateVoEChannel() failed.";
solenberg0a617e22015-10-20 15:49:38 -07001834 return -1;
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001835 }
mflodman3d7db262016-04-29 00:57:13 -07001836
solenberg0a617e22015-10-20 15:49:38 -07001837 return id;
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001838}
1839
solenberg7add0582015-11-20 09:59:34 -08001840bool WebRtcVoiceMediaChannel::DeleteVoEChannel(int channel) {
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001841 if (engine()->voe()->base()->DeleteChannel(channel) == -1) {
solenberg35dee812017-09-18 01:57:01 -07001842 LOG(LS_WARNING) << "DeleteChannel(" << channel << ") failed.";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001843 return false;
1844 }
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001845 return true;
1846}
henrike@webrtc.org1e09a712013-07-26 19:17:59 +00001847
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001848bool WebRtcVoiceMediaChannel::AddSendStream(const StreamParams& sp) {
Peter Boströmca8b4042016-03-08 14:24:13 -08001849 TRACE_EVENT0("webrtc", "WebRtcVoiceMediaChannel::AddSendStream");
solenberg566ef242015-11-06 15:34:49 -08001850 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenberg0a617e22015-10-20 15:49:38 -07001851 LOG(LS_INFO) << "AddSendStream: " << sp.ToString();
1852
1853 uint32_t ssrc = sp.first_ssrc();
1854 RTC_DCHECK(0 != ssrc);
1855
1856 if (GetSendChannelId(ssrc) != -1) {
1857 LOG(LS_ERROR) << "Stream already exists with ssrc " << ssrc;
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001858 return false;
1859 }
1860
solenberg0a617e22015-10-20 15:49:38 -07001861 // Create a new channel for sending audio data.
1862 int channel = CreateVoEChannel();
1863 if (channel == -1) {
1864 return false;
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001865 }
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001866
solenbergc96df772015-10-21 13:01:53 -07001867 // Save the channel to send_streams_, so that RemoveSendStream() can still
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001868 // delete the channel in case failure happens below.
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +00001869 webrtc::AudioTransport* audio_transport =
1870 engine()->voe()->base()->audio_transport();
mflodman3d7db262016-04-29 00:57:13 -07001871
minyue6b825df2016-10-31 04:08:32 -07001872 rtc::Optional<std::string> audio_network_adaptor_config =
1873 GetAudioNetworkAdaptorConfig(options_);
skvlade0d46372016-04-07 22:59:22 -07001874 WebRtcAudioSendStream* stream = new WebRtcAudioSendStream(
solenberg971cab02016-06-14 10:02:41 -07001875 channel, audio_transport, ssrc, sp.cname, send_codec_spec_,
minyue6b825df2016-10-31 04:08:32 -07001876 send_rtp_extensions_, max_send_bitrate_bps_, audio_network_adaptor_config,
ossu20a4b3f2017-04-27 02:08:52 -07001877 call_, this, engine()->encoder_factory_);
skvlade0d46372016-04-07 22:59:22 -07001878 send_streams_.insert(std::make_pair(ssrc, stream));
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001879
solenberg4a0f7b52016-06-16 13:07:33 -07001880 // At this point the stream's local SSRC has been updated. If it is the first
1881 // send stream, make sure that all the receive streams are updated with the
1882 // same SSRC in order to send receiver reports.
solenbergc96df772015-10-21 13:01:53 -07001883 if (send_streams_.size() == 1) {
solenberg0a617e22015-10-20 15:49:38 -07001884 receiver_reports_ssrc_ = ssrc;
solenberg4a0f7b52016-06-16 13:07:33 -07001885 for (const auto& kv : recv_streams_) {
1886 // TODO(solenberg): Allow applications to set the RTCP SSRC of receive
1887 // streams instead, so we can avoid recreating the streams here.
1888 kv.second->RecreateAudioReceiveStream(ssrc);
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001889 }
1890 }
1891
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -08001892 send_streams_[ssrc]->SetSend(send_);
1893 return true;
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001894}
1895
Peter Boström0c4e06b2015-10-07 12:23:21 +02001896bool WebRtcVoiceMediaChannel::RemoveSendStream(uint32_t ssrc) {
Peter Boströmca8b4042016-03-08 14:24:13 -08001897 TRACE_EVENT0("webrtc", "WebRtcVoiceMediaChannel::RemoveSendStream");
solenberg566ef242015-11-06 15:34:49 -08001898 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenberg3a941542015-11-16 07:34:50 -08001899 LOG(LS_INFO) << "RemoveSendStream: " << ssrc;
1900
solenbergc96df772015-10-21 13:01:53 -07001901 auto it = send_streams_.find(ssrc);
1902 if (it == send_streams_.end()) {
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001903 LOG(LS_WARNING) << "Try to remove stream with ssrc " << ssrc
1904 << " which doesn't exist.";
1905 return false;
1906 }
1907
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -08001908 it->second->SetSend(false);
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001909
solenberg7602aab2016-11-14 11:30:07 -08001910 // TODO(solenberg): If we're removing the receiver_reports_ssrc_ stream, find
1911 // the first active send stream and use that instead, reassociating receive
1912 // streams.
1913
solenberg7add0582015-11-20 09:59:34 -08001914 // Clean up and delete the send stream+channel.
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -08001915 int channel = it->second->channel();
solenberg0a617e22015-10-20 15:49:38 -07001916 LOG(LS_INFO) << "Removing audio send stream " << ssrc
1917 << " with VoiceEngine channel #" << channel << ".";
solenberg7add0582015-11-20 09:59:34 -08001918 delete it->second;
1919 send_streams_.erase(it);
1920 if (!DeleteVoEChannel(channel)) {
solenberg0a617e22015-10-20 15:49:38 -07001921 return false;
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001922 }
solenbergc96df772015-10-21 13:01:53 -07001923 if (send_streams_.empty()) {
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -08001924 SetSend(false);
solenberg0a617e22015-10-20 15:49:38 -07001925 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001926 return true;
1927}
1928
1929bool WebRtcVoiceMediaChannel::AddRecvStream(const StreamParams& sp) {
Peter Boströmca8b4042016-03-08 14:24:13 -08001930 TRACE_EVENT0("webrtc", "WebRtcVoiceMediaChannel::AddRecvStream");
solenberg566ef242015-11-06 15:34:49 -08001931 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenbergd97ec302015-10-07 01:40:33 -07001932 LOG(LS_INFO) << "AddRecvStream: " << sp.ToString();
1933
solenberg0b675462015-10-09 01:37:09 -07001934 if (!ValidateStreamParams(sp)) {
wu@webrtc.org78187522013-10-07 23:32:02 +00001935 return false;
1936 }
1937
solenberg7add0582015-11-20 09:59:34 -08001938 const uint32_t ssrc = sp.first_ssrc();
solenberg0b675462015-10-09 01:37:09 -07001939 if (ssrc == 0) {
1940 LOG(LS_WARNING) << "AddRecvStream with ssrc==0 is not supported.";
1941 return false;
1942 }
1943
solenberg2100c0b2017-03-01 11:29:29 -08001944 // If this stream was previously received unsignaled, we promote it, possibly
1945 // recreating the AudioReceiveStream, if sync_label has changed.
1946 if (MaybeDeregisterUnsignaledRecvStream(ssrc)) {
solenberg4904fb62017-02-17 12:01:14 -08001947 recv_streams_[ssrc]->MaybeRecreateAudioReceiveStream(sp.sync_label);
solenberg4904fb62017-02-17 12:01:14 -08001948 return true;
solenberg1ac56142015-10-13 03:58:19 -07001949 }
solenberg0b675462015-10-09 01:37:09 -07001950
solenberg7add0582015-11-20 09:59:34 -08001951 if (GetReceiveChannelId(ssrc) != -1) {
henrike@webrtc.org1e09a712013-07-26 19:17:59 +00001952 LOG(LS_ERROR) << "Stream already exists with ssrc " << ssrc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001953 return false;
1954 }
Fredrik Solenberg4b60c732015-05-07 14:07:48 +02001955
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001956 // Create a new channel for receiving audio data.
solenberg7add0582015-11-20 09:59:34 -08001957 const int channel = CreateVoEChannel();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001958 if (channel == -1) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001959 return false;
1960 }
Minyue2013aec2015-05-13 14:14:42 +02001961
stefanba4c0e42016-02-04 04:12:24 -08001962 recv_streams_.insert(std::make_pair(
kwiberg1c07c702017-03-27 07:15:49 -07001963 ssrc,
1964 new WebRtcAudioReceiveStream(
1965 channel, ssrc, receiver_reports_ssrc_, recv_transport_cc_enabled_,
1966 recv_nack_enabled_, sp.sync_label, recv_rtp_extensions_, call_, this,
1967 engine()->decoder_factory_, decoder_map_)));
aleloi84ef6152016-08-04 05:28:21 -07001968 recv_streams_[ssrc]->SetPlayout(playout_);
solenberg7add0582015-11-20 09:59:34 -08001969
solenberg1ac56142015-10-13 03:58:19 -07001970 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001971}
1972
Peter Boström0c4e06b2015-10-07 12:23:21 +02001973bool WebRtcVoiceMediaChannel::RemoveRecvStream(uint32_t ssrc) {
Peter Boströmca8b4042016-03-08 14:24:13 -08001974 TRACE_EVENT0("webrtc", "WebRtcVoiceMediaChannel::RemoveRecvStream");
solenberg566ef242015-11-06 15:34:49 -08001975 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenbergd97ec302015-10-07 01:40:33 -07001976 LOG(LS_INFO) << "RemoveRecvStream: " << ssrc;
1977
solenberg7add0582015-11-20 09:59:34 -08001978 const auto it = recv_streams_.find(ssrc);
1979 if (it == recv_streams_.end()) {
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001980 LOG(LS_WARNING) << "Try to remove stream with ssrc " << ssrc
1981 << " which doesn't exist.";
henrike@webrtc.org1e09a712013-07-26 19:17:59 +00001982 return false;
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001983 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001984
solenberg2100c0b2017-03-01 11:29:29 -08001985 MaybeDeregisterUnsignaledRecvStream(ssrc);
henrike@webrtc.org1e09a712013-07-26 19:17:59 +00001986
solenberg7add0582015-11-20 09:59:34 -08001987 const int channel = it->second->channel();
1988
1989 // Clean up and delete the receive stream+channel.
1990 LOG(LS_INFO) << "Removing audio receive stream " << ssrc
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +00001991 << " with VoiceEngine channel #" << channel << ".";
Tommif888bb52015-12-12 01:37:01 +01001992 it->second->SetRawAudioSink(nullptr);
solenberg7add0582015-11-20 09:59:34 -08001993 delete it->second;
1994 recv_streams_.erase(it);
1995 return DeleteVoEChannel(channel);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001996}
1997
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -08001998bool WebRtcVoiceMediaChannel::SetLocalSource(uint32_t ssrc,
1999 AudioSource* source) {
solenbergc96df772015-10-21 13:01:53 -07002000 auto it = send_streams_.find(ssrc);
2001 if (it == send_streams_.end()) {
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -08002002 if (source) {
2003 // Return an error if trying to set a valid source with an invalid ssrc.
2004 LOG(LS_ERROR) << "SetLocalSource failed with ssrc " << ssrc;
wu@webrtc.org9dba5252013-08-05 20:36:57 +00002005 return false;
2006 }
2007
2008 // The channel likely has gone away, do nothing.
henrike@webrtc.org1e09a712013-07-26 19:17:59 +00002009 return true;
henrike@webrtc.org1e09a712013-07-26 19:17:59 +00002010 }
2011
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -08002012 if (source) {
2013 it->second->SetSource(source);
solenberg1ac56142015-10-13 03:58:19 -07002014 } else {
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -08002015 it->second->ClearSource();
solenberg1ac56142015-10-13 03:58:19 -07002016 }
henrike@webrtc.org1e09a712013-07-26 19:17:59 +00002017
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002018 return true;
2019}
2020
solenberg796b8f92017-03-01 17:02:23 -08002021// TODO(solenberg): Remove, once AudioMonitor is gone.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002022bool WebRtcVoiceMediaChannel::GetActiveStreams(
2023 AudioInfo::StreamList* actives) {
solenberg566ef242015-11-06 15:34:49 -08002024 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002025 actives->clear();
solenberg7add0582015-11-20 09:59:34 -08002026 for (const auto& ch : recv_streams_) {
solenberg796b8f92017-03-01 17:02:23 -08002027 int level = ch.second->GetOutputLevel();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002028 if (level > 0) {
Fredrik Solenbergaf9fb212015-08-26 10:45:53 +02002029 actives->push_back(std::make_pair(ch.first, level));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002030 }
2031 }
2032 return true;
2033}
2034
solenberg796b8f92017-03-01 17:02:23 -08002035// TODO(solenberg): Remove, once AudioMonitor is gone.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002036int WebRtcVoiceMediaChannel::GetOutputLevel() {
solenberg566ef242015-11-06 15:34:49 -08002037 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenberg1ac56142015-10-13 03:58:19 -07002038 int highest = 0;
solenberg7add0582015-11-20 09:59:34 -08002039 for (const auto& ch : recv_streams_) {
solenberg796b8f92017-03-01 17:02:23 -08002040 highest = std::max(ch.second->GetOutputLevel(), highest);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002041 }
2042 return highest;
2043}
2044
solenberg4bac9c52015-10-09 02:32:53 -07002045bool WebRtcVoiceMediaChannel::SetOutputVolume(uint32_t ssrc, double volume) {
solenberg566ef242015-11-06 15:34:49 -08002046 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenberg2100c0b2017-03-01 11:29:29 -08002047 std::vector<uint32_t> ssrcs(1, ssrc);
deadbeef3bc15102017-04-20 19:25:07 -07002048 // SSRC of 0 represents the default receive stream.
solenberg1ac56142015-10-13 03:58:19 -07002049 if (ssrc == 0) {
2050 default_recv_volume_ = volume;
solenberg2100c0b2017-03-01 11:29:29 -08002051 ssrcs = unsignaled_recv_ssrcs_;
2052 }
2053 for (uint32_t ssrc : ssrcs) {
2054 const auto it = recv_streams_.find(ssrc);
2055 if (it == recv_streams_.end()) {
2056 LOG(LS_WARNING) << "SetOutputVolume: no recv stream " << ssrc;
2057 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002058 }
solenberg2100c0b2017-03-01 11:29:29 -08002059 it->second->SetOutputVolume(volume);
2060 LOG(LS_INFO) << "SetOutputVolume() to " << volume
2061 << " for recv stream with ssrc " << ssrc;
solenberg1ac56142015-10-13 03:58:19 -07002062 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002063 return true;
2064}
2065
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002066bool WebRtcVoiceMediaChannel::CanInsertDtmf() {
Fredrik Solenbergb5727682015-12-04 15:22:19 +01002067 return dtmf_payload_type_ ? true : false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002068}
2069
solenberg1d63dd02015-12-02 12:35:09 -08002070bool WebRtcVoiceMediaChannel::InsertDtmf(uint32_t ssrc, int event,
2071 int duration) {
solenberg566ef242015-11-06 15:34:49 -08002072 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
Fredrik Solenbergb5727682015-12-04 15:22:19 +01002073 LOG(LS_INFO) << "WebRtcVoiceMediaChannel::InsertDtmf";
2074 if (!dtmf_payload_type_) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002075 return false;
2076 }
2077
Fredrik Solenbergb5727682015-12-04 15:22:19 +01002078 // Figure out which WebRtcAudioSendStream to send the event on.
2079 auto it = ssrc != 0 ? send_streams_.find(ssrc) : send_streams_.begin();
2080 if (it == send_streams_.end()) {
2081 LOG(LS_WARNING) << "The specified ssrc " << ssrc << " is not in use.";
solenberg1d63dd02015-12-02 12:35:09 -08002082 return false;
2083 }
Fredrik Solenbergb5727682015-12-04 15:22:19 +01002084 if (event < kMinTelephoneEventCode ||
2085 event > kMaxTelephoneEventCode) {
2086 LOG(LS_WARNING) << "DTMF event code " << event << " out of range.";
solenberg1d63dd02015-12-02 12:35:09 -08002087 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002088 }
solenbergffbbcac2016-11-17 05:25:37 -08002089 RTC_DCHECK_NE(-1, dtmf_payload_freq_);
2090 return it->second->SendTelephoneEvent(*dtmf_payload_type_, dtmf_payload_freq_,
2091 event, duration);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002092}
2093
wu@webrtc.orga9890802013-12-13 00:21:03 +00002094void WebRtcVoiceMediaChannel::OnPacketReceived(
jbaucheec21bd2016-03-20 06:15:43 -07002095 rtc::CopyOnWriteBuffer* packet, const rtc::PacketTime& packet_time) {
solenberg566ef242015-11-06 15:34:49 -08002096 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
Fredrik Solenberg4b60c732015-05-07 14:07:48 +02002097
mflodman3d7db262016-04-29 00:57:13 -07002098 const webrtc::PacketTime webrtc_packet_time(packet_time.timestamp,
2099 packet_time.not_before);
2100 webrtc::PacketReceiver::DeliveryStatus delivery_result =
2101 call_->Receiver()->DeliverPacket(webrtc::MediaType::AUDIO,
2102 packet->cdata(), packet->size(),
2103 webrtc_packet_time);
mflodman3d7db262016-04-29 00:57:13 -07002104 if (delivery_result != webrtc::PacketReceiver::DELIVERY_UNKNOWN_SSRC) {
2105 return;
2106 }
2107
solenberg2100c0b2017-03-01 11:29:29 -08002108 // Create an unsignaled receive stream for this previously not received ssrc.
2109 // If there already is N unsignaled receive streams, delete the oldest.
mflodman3d7db262016-04-29 00:57:13 -07002110 // See: https://bugs.chromium.org/p/webrtc/issues/detail?id=5208
solenberg1ac56142015-10-13 03:58:19 -07002111 uint32_t ssrc = 0;
jbaucheec21bd2016-03-20 06:15:43 -07002112 if (!GetRtpSsrc(packet->cdata(), packet->size(), &ssrc)) {
solenberg1ac56142015-10-13 03:58:19 -07002113 return;
2114 }
solenberg2100c0b2017-03-01 11:29:29 -08002115 RTC_DCHECK(std::find(unsignaled_recv_ssrcs_.begin(),
2116 unsignaled_recv_ssrcs_.end(), ssrc) == unsignaled_recv_ssrcs_.end());
solenberg1ac56142015-10-13 03:58:19 -07002117
solenberg2100c0b2017-03-01 11:29:29 -08002118 // Add new stream.
mflodman3d7db262016-04-29 00:57:13 -07002119 StreamParams sp;
2120 sp.ssrcs.push_back(ssrc);
solenberg2100c0b2017-03-01 11:29:29 -08002121 LOG(LS_INFO) << "Creating unsignaled receive stream for SSRC=" << ssrc;
mflodman3d7db262016-04-29 00:57:13 -07002122 if (!AddRecvStream(sp)) {
solenberg2100c0b2017-03-01 11:29:29 -08002123 LOG(LS_WARNING) << "Could not create unsignaled receive stream.";
mflodman3d7db262016-04-29 00:57:13 -07002124 return;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002125 }
solenberg2100c0b2017-03-01 11:29:29 -08002126 unsignaled_recv_ssrcs_.push_back(ssrc);
2127 RTC_HISTOGRAM_COUNTS_LINEAR(
2128 "WebRTC.Audio.NumOfUnsignaledStreams", unsignaled_recv_ssrcs_.size(), 1,
2129 100, 101);
solenbergf748ca42017-02-06 13:03:19 -08002130
solenberg2100c0b2017-03-01 11:29:29 -08002131 // Remove oldest unsignaled stream, if we have too many.
2132 if (unsignaled_recv_ssrcs_.size() > kMaxUnsignaledRecvStreams) {
2133 uint32_t remove_ssrc = unsignaled_recv_ssrcs_.front();
2134 LOG(LS_INFO) << "Removing unsignaled receive stream with SSRC="
2135 << remove_ssrc;
2136 RemoveRecvStream(remove_ssrc);
2137 }
2138 RTC_DCHECK_GE(kMaxUnsignaledRecvStreams, unsignaled_recv_ssrcs_.size());
2139
2140 SetOutputVolume(ssrc, default_recv_volume_);
2141
2142 // The default sink can only be attached to one stream at a time, so we hook
2143 // it up to the *latest* unsignaled stream we've seen, in order to support the
2144 // case where the SSRC of one unsignaled stream changes.
mflodman3d7db262016-04-29 00:57:13 -07002145 if (default_sink_) {
solenberg2100c0b2017-03-01 11:29:29 -08002146 for (uint32_t drop_ssrc : unsignaled_recv_ssrcs_) {
2147 auto it = recv_streams_.find(drop_ssrc);
2148 it->second->SetRawAudioSink(nullptr);
2149 }
mflodman3d7db262016-04-29 00:57:13 -07002150 std::unique_ptr<webrtc::AudioSinkInterface> proxy_sink(
2151 new ProxySink(default_sink_.get()));
solenberg2100c0b2017-03-01 11:29:29 -08002152 SetRawAudioSink(ssrc, std::move(proxy_sink));
mflodman3d7db262016-04-29 00:57:13 -07002153 }
solenberg2100c0b2017-03-01 11:29:29 -08002154
mflodman3d7db262016-04-29 00:57:13 -07002155 delivery_result = call_->Receiver()->DeliverPacket(webrtc::MediaType::AUDIO,
2156 packet->cdata(),
2157 packet->size(),
2158 webrtc_packet_time);
2159 RTC_DCHECK_NE(webrtc::PacketReceiver::DELIVERY_UNKNOWN_SSRC, delivery_result);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002160}
2161
wu@webrtc.orga9890802013-12-13 00:21:03 +00002162void WebRtcVoiceMediaChannel::OnRtcpReceived(
jbaucheec21bd2016-03-20 06:15:43 -07002163 rtc::CopyOnWriteBuffer* packet, const rtc::PacketTime& packet_time) {
solenberg566ef242015-11-06 15:34:49 -08002164 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
Fredrik Solenberg4b60c732015-05-07 14:07:48 +02002165
Fredrik Solenberg709ed672015-09-15 12:26:33 +02002166 // Forward packet to Call as well.
2167 const webrtc::PacketTime webrtc_packet_time(packet_time.timestamp,
2168 packet_time.not_before);
2169 call_->Receiver()->DeliverPacket(webrtc::MediaType::AUDIO,
jbaucheec21bd2016-03-20 06:15:43 -07002170 packet->cdata(), packet->size(), webrtc_packet_time);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002171}
2172
Honghai Zhangcc411c02016-03-29 17:27:21 -07002173void WebRtcVoiceMediaChannel::OnNetworkRouteChanged(
2174 const std::string& transport_name,
Honghai Zhang0e533ef2016-04-19 15:41:36 -07002175 const rtc::NetworkRoute& network_route) {
2176 call_->OnNetworkRouteChanged(transport_name, network_route);
Honghai Zhangcc411c02016-03-29 17:27:21 -07002177}
2178
Peter Boström0c4e06b2015-10-07 12:23:21 +02002179bool WebRtcVoiceMediaChannel::MuteStream(uint32_t ssrc, bool muted) {
solenberg566ef242015-11-06 15:34:49 -08002180 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenberg94218532016-06-16 10:53:22 -07002181 const auto it = send_streams_.find(ssrc);
2182 if (it == send_streams_.end()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002183 LOG(LS_WARNING) << "The specified ssrc " << ssrc << " is not in use.";
2184 return false;
2185 }
solenberg94218532016-06-16 10:53:22 -07002186 it->second->SetMuted(muted);
2187
2188 // TODO(solenberg):
buildbot@webrtc.org6b21b712014-07-31 15:08:53 +00002189 // We set the AGC to mute state only when all the channels are muted.
2190 // This implementation is not ideal, instead we should signal the AGC when
2191 // the mic channel is muted/unmuted. We can't do it today because there
2192 // is no good way to know which stream is mapping to the mic channel.
2193 bool all_muted = muted;
solenberg94218532016-06-16 10:53:22 -07002194 for (const auto& kv : send_streams_) {
2195 all_muted = all_muted && kv.second->muted();
buildbot@webrtc.org6b21b712014-07-31 15:08:53 +00002196 }
solenberg059fb442016-10-26 05:12:24 -07002197 engine()->apm()->set_output_will_be_muted(all_muted);
buildbot@webrtc.org6b21b712014-07-31 15:08:53 +00002198
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002199 return true;
2200}
2201
deadbeef80346142016-04-27 14:17:10 -07002202bool WebRtcVoiceMediaChannel::SetMaxSendBitrate(int bps) {
2203 LOG(LS_INFO) << "WebRtcVoiceMediaChannel::SetMaxSendBitrate.";
2204 max_send_bitrate_bps_ = bps;
minyue7a973442016-10-20 03:27:12 -07002205 bool success = true;
skvlade0d46372016-04-07 22:59:22 -07002206 for (const auto& kv : send_streams_) {
minyue7a973442016-10-20 03:27:12 -07002207 if (!kv.second->SetMaxSendBitrate(max_send_bitrate_bps_)) {
2208 success = false;
skvlade0d46372016-04-07 22:59:22 -07002209 }
2210 }
minyue7a973442016-10-20 03:27:12 -07002211 return success;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002212}
2213
skvlad7a43d252016-03-22 15:32:27 -07002214void WebRtcVoiceMediaChannel::OnReadyToSend(bool ready) {
2215 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
2216 LOG(LS_VERBOSE) << "OnReadyToSend: " << (ready ? "Ready." : "Not ready.");
2217 call_->SignalChannelNetworkState(
2218 webrtc::MediaType::AUDIO,
2219 ready ? webrtc::kNetworkUp : webrtc::kNetworkDown);
2220}
2221
michaelt79e05882016-11-08 02:50:09 -08002222void WebRtcVoiceMediaChannel::OnTransportOverheadChanged(
2223 int transport_overhead_per_packet) {
2224 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
2225 call_->OnTransportOverheadChanged(webrtc::MediaType::AUDIO,
2226 transport_overhead_per_packet);
2227}
2228
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002229bool WebRtcVoiceMediaChannel::GetStats(VoiceMediaInfo* info) {
Peter Boströmca8b4042016-03-08 14:24:13 -08002230 TRACE_EVENT0("webrtc", "WebRtcVoiceMediaChannel::GetStats");
solenberg566ef242015-11-06 15:34:49 -08002231 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenberg85a04962015-10-27 03:35:21 -07002232 RTC_DCHECK(info);
solenbergd97ec302015-10-07 01:40:33 -07002233
solenberg85a04962015-10-27 03:35:21 -07002234 // Get SSRC and stats for each sender.
hbos1acfbd22016-11-17 23:43:29 -08002235 RTC_DCHECK_EQ(info->senders.size(), 0U);
solenberg85a04962015-10-27 03:35:21 -07002236 for (const auto& stream : send_streams_) {
2237 webrtc::AudioSendStream::Stats stats = stream.second->GetStats();
wu@webrtc.org9dba5252013-08-05 20:36:57 +00002238 VoiceSenderInfo sinfo;
solenberg85a04962015-10-27 03:35:21 -07002239 sinfo.add_ssrc(stats.local_ssrc);
2240 sinfo.bytes_sent = stats.bytes_sent;
2241 sinfo.packets_sent = stats.packets_sent;
2242 sinfo.packets_lost = stats.packets_lost;
2243 sinfo.fraction_lost = stats.fraction_lost;
2244 sinfo.codec_name = stats.codec_name;
hbos1acfbd22016-11-17 23:43:29 -08002245 sinfo.codec_payload_type = stats.codec_payload_type;
solenberg85a04962015-10-27 03:35:21 -07002246 sinfo.ext_seqnum = stats.ext_seqnum;
2247 sinfo.jitter_ms = stats.jitter_ms;
2248 sinfo.rtt_ms = stats.rtt_ms;
2249 sinfo.audio_level = stats.audio_level;
zsteine76bd3a2017-07-14 12:17:49 -07002250 sinfo.total_input_energy = stats.total_input_energy;
2251 sinfo.total_input_duration = stats.total_input_duration;
solenberg85a04962015-10-27 03:35:21 -07002252 sinfo.aec_quality_min = stats.aec_quality_min;
2253 sinfo.echo_delay_median_ms = stats.echo_delay_median_ms;
2254 sinfo.echo_delay_std_ms = stats.echo_delay_std_ms;
2255 sinfo.echo_return_loss = stats.echo_return_loss;
2256 sinfo.echo_return_loss_enhancement = stats.echo_return_loss_enhancement;
ivoc8c63a822016-10-21 04:10:03 -07002257 sinfo.residual_echo_likelihood = stats.residual_echo_likelihood;
ivoc4e477a12017-01-15 08:29:46 -08002258 sinfo.residual_echo_likelihood_recent_max =
2259 stats.residual_echo_likelihood_recent_max;
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -08002260 sinfo.typing_noise_detected = (send_ ? stats.typing_noise_detected : false);
ivoce1198e02017-09-08 08:13:19 -07002261 sinfo.ana_statistics = stats.ana_statistics;
wu@webrtc.org9dba5252013-08-05 20:36:57 +00002262 info->senders.push_back(sinfo);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002263 }
2264
solenberg85a04962015-10-27 03:35:21 -07002265 // Get SSRC and stats for each receiver.
hbos1acfbd22016-11-17 23:43:29 -08002266 RTC_DCHECK_EQ(info->receivers.size(), 0U);
solenberg7add0582015-11-20 09:59:34 -08002267 for (const auto& stream : recv_streams_) {
Fredrik Solenberg4f4ec0a2015-10-22 10:49:27 +02002268 webrtc::AudioReceiveStream::Stats stats = stream.second->GetStats();
2269 VoiceReceiverInfo rinfo;
2270 rinfo.add_ssrc(stats.remote_ssrc);
2271 rinfo.bytes_rcvd = stats.bytes_rcvd;
2272 rinfo.packets_rcvd = stats.packets_rcvd;
2273 rinfo.packets_lost = stats.packets_lost;
2274 rinfo.fraction_lost = stats.fraction_lost;
2275 rinfo.codec_name = stats.codec_name;
hbos1acfbd22016-11-17 23:43:29 -08002276 rinfo.codec_payload_type = stats.codec_payload_type;
Fredrik Solenberg4f4ec0a2015-10-22 10:49:27 +02002277 rinfo.ext_seqnum = stats.ext_seqnum;
2278 rinfo.jitter_ms = stats.jitter_ms;
2279 rinfo.jitter_buffer_ms = stats.jitter_buffer_ms;
2280 rinfo.jitter_buffer_preferred_ms = stats.jitter_buffer_preferred_ms;
2281 rinfo.delay_estimate_ms = stats.delay_estimate_ms;
2282 rinfo.audio_level = stats.audio_level;
zsteine76bd3a2017-07-14 12:17:49 -07002283 rinfo.total_output_energy = stats.total_output_energy;
Steve Anton2dbc69f2017-08-24 17:15:13 -07002284 rinfo.total_samples_received = stats.total_samples_received;
zsteine76bd3a2017-07-14 12:17:49 -07002285 rinfo.total_output_duration = stats.total_output_duration;
Steve Anton2dbc69f2017-08-24 17:15:13 -07002286 rinfo.concealed_samples = stats.concealed_samples;
Gustaf Ullberg9a2e9062017-09-18 09:28:20 +02002287 rinfo.concealment_events = stats.concealment_events;
Fredrik Solenberg4f4ec0a2015-10-22 10:49:27 +02002288 rinfo.expand_rate = stats.expand_rate;
2289 rinfo.speech_expand_rate = stats.speech_expand_rate;
2290 rinfo.secondary_decoded_rate = stats.secondary_decoded_rate;
minyue-webrtc0e320ec2017-08-28 13:51:27 +02002291 rinfo.secondary_discarded_rate = stats.secondary_discarded_rate;
Fredrik Solenberg4f4ec0a2015-10-22 10:49:27 +02002292 rinfo.accelerate_rate = stats.accelerate_rate;
2293 rinfo.preemptive_expand_rate = stats.preemptive_expand_rate;
2294 rinfo.decoding_calls_to_silence_generator =
2295 stats.decoding_calls_to_silence_generator;
2296 rinfo.decoding_calls_to_neteq = stats.decoding_calls_to_neteq;
2297 rinfo.decoding_normal = stats.decoding_normal;
2298 rinfo.decoding_plc = stats.decoding_plc;
2299 rinfo.decoding_cng = stats.decoding_cng;
2300 rinfo.decoding_plc_cng = stats.decoding_plc_cng;
henrik.lundin63489782016-09-20 01:47:12 -07002301 rinfo.decoding_muted_output = stats.decoding_muted_output;
Fredrik Solenberg4f4ec0a2015-10-22 10:49:27 +02002302 rinfo.capture_start_ntp_time_ms = stats.capture_start_ntp_time_ms;
2303 info->receivers.push_back(rinfo);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002304 }
2305
hbos1acfbd22016-11-17 23:43:29 -08002306 // Get codec info
2307 for (const AudioCodec& codec : send_codecs_) {
2308 webrtc::RtpCodecParameters codec_params = codec.ToCodecParameters();
2309 info->send_codecs.insert(
2310 std::make_pair(codec_params.payload_type, std::move(codec_params)));
2311 }
2312 for (const AudioCodec& codec : recv_codecs_) {
2313 webrtc::RtpCodecParameters codec_params = codec.ToCodecParameters();
2314 info->receive_codecs.insert(
2315 std::make_pair(codec_params.payload_type, std::move(codec_params)));
2316 }
2317
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002318 return true;
2319}
2320
Tommif888bb52015-12-12 01:37:01 +01002321void WebRtcVoiceMediaChannel::SetRawAudioSink(
2322 uint32_t ssrc,
kwiberg686a8ef2016-02-26 03:00:35 -08002323 std::unique_ptr<webrtc::AudioSinkInterface> sink) {
Tommif888bb52015-12-12 01:37:01 +01002324 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
deadbeef884f5852016-01-15 09:20:04 -08002325 LOG(LS_VERBOSE) << "WebRtcVoiceMediaChannel::SetRawAudioSink: ssrc:" << ssrc
2326 << " " << (sink ? "(ptr)" : "NULL");
2327 if (ssrc == 0) {
solenberg2100c0b2017-03-01 11:29:29 -08002328 if (!unsignaled_recv_ssrcs_.empty()) {
kwiberg686a8ef2016-02-26 03:00:35 -08002329 std::unique_ptr<webrtc::AudioSinkInterface> proxy_sink(
deadbeef884f5852016-01-15 09:20:04 -08002330 sink ? new ProxySink(sink.get()) : nullptr);
solenberg2100c0b2017-03-01 11:29:29 -08002331 SetRawAudioSink(unsignaled_recv_ssrcs_.back(), std::move(proxy_sink));
deadbeef884f5852016-01-15 09:20:04 -08002332 }
2333 default_sink_ = std::move(sink);
2334 return;
2335 }
Tommif888bb52015-12-12 01:37:01 +01002336 const auto it = recv_streams_.find(ssrc);
2337 if (it == recv_streams_.end()) {
solenberg2100c0b2017-03-01 11:29:29 -08002338 LOG(LS_WARNING) << "SetRawAudioSink: no recv stream " << ssrc;
Tommif888bb52015-12-12 01:37:01 +01002339 return;
2340 }
deadbeef2d110be2016-01-13 12:00:26 -08002341 it->second->SetRawAudioSink(std::move(sink));
Tommif888bb52015-12-12 01:37:01 +01002342}
2343
hbos8d609f62017-04-10 07:39:05 -07002344std::vector<webrtc::RtpSource> WebRtcVoiceMediaChannel::GetSources(
2345 uint32_t ssrc) const {
2346 auto it = recv_streams_.find(ssrc);
2347 RTC_DCHECK(it != recv_streams_.end())
2348 << "Attempting to get contributing sources for SSRC:" << ssrc
2349 << " which doesn't exist.";
2350 return it->second->GetSources();
2351}
2352
Peter Boström0c4e06b2015-10-07 12:23:21 +02002353int WebRtcVoiceMediaChannel::GetReceiveChannelId(uint32_t ssrc) const {
solenberg566ef242015-11-06 15:34:49 -08002354 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenberg7add0582015-11-20 09:59:34 -08002355 const auto it = recv_streams_.find(ssrc);
2356 if (it != recv_streams_.end()) {
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +00002357 return it->second->channel();
solenberg8fb30c32015-10-13 03:06:58 -07002358 }
solenberg1ac56142015-10-13 03:58:19 -07002359 return -1;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002360}
2361
Peter Boström0c4e06b2015-10-07 12:23:21 +02002362int WebRtcVoiceMediaChannel::GetSendChannelId(uint32_t ssrc) const {
solenberg566ef242015-11-06 15:34:49 -08002363 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenbergc96df772015-10-21 13:01:53 -07002364 const auto it = send_streams_.find(ssrc);
2365 if (it != send_streams_.end()) {
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +00002366 return it->second->channel();
solenberg8fb30c32015-10-13 03:06:58 -07002367 }
wu@webrtc.org9dba5252013-08-05 20:36:57 +00002368 return -1;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002369}
solenberg2100c0b2017-03-01 11:29:29 -08002370
2371bool WebRtcVoiceMediaChannel::
2372 MaybeDeregisterUnsignaledRecvStream(uint32_t ssrc) {
2373 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
2374 auto it = std::find(unsignaled_recv_ssrcs_.begin(),
2375 unsignaled_recv_ssrcs_.end(),
2376 ssrc);
2377 if (it != unsignaled_recv_ssrcs_.end()) {
2378 unsignaled_recv_ssrcs_.erase(it);
2379 return true;
2380 }
2381 return false;
2382}
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002383} // namespace cricket
2384
2385#endif // HAVE_WEBRTC_VOICE