blob: c2e310a311a633962eff0f09d5bf24a8071b4f4b [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"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020045#include "voice_engine/transmit_mixer.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000046
henrike@webrtc.org28e20752013-07-10 00:45:36 +000047namespace cricket {
solenbergd97ec302015-10-07 01:40:33 -070048namespace {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000049
solenberg418b7d32017-06-13 00:38:27 -070050constexpr size_t kMaxUnsignaledRecvStreams = 4;
solenberg2100c0b2017-03-01 11:29:29 -080051
solenberg971cab02016-06-14 10:02:41 -070052constexpr int kNackRtpHistoryMs = 5000;
minyue@webrtc.org2dc6f312014-10-31 05:33:10 +000053
peah1bcfce52016-08-26 07:16:04 -070054// Check to verify that the define for the intelligibility enhancer is properly
55// set.
56#if !defined(WEBRTC_INTELLIGIBILITY_ENHANCER) || \
57 (WEBRTC_INTELLIGIBILITY_ENHANCER != 0 && \
58 WEBRTC_INTELLIGIBILITY_ENHANCER != 1)
59#error "Set WEBRTC_INTELLIGIBILITY_ENHANCER to either 0 or 1"
60#endif
61
ossu20a4b3f2017-04-27 02:08:52 -070062// For SendSideBwe, Opus bitrate should be in the range between 6000 and 32000.
minyue10cbb462016-11-07 09:29:22 -080063const int kOpusMinBitrateBps = 6000;
ossu20a4b3f2017-04-27 02:08:52 -070064const int kOpusBitrateFbBps = 32000;
deadbeef80346142016-04-27 14:17:10 -070065
wu@webrtc.orgde305012013-10-31 15:40:38 +000066// Default audio dscp value.
67// See http://tools.ietf.org/html/rfc2474 for details.
68// See also http://tools.ietf.org/html/draft-jennings-rtcweb-qos-00
solenbergd97ec302015-10-07 01:40:33 -070069const rtc::DiffServCodePoint kAudioDscpValue = rtc::DSCP_EF;
henrike@webrtc.org1e09a712013-07-26 19:17:59 +000070
Fredrik Solenbergb5727682015-12-04 15:22:19 +010071// Constants from voice_engine_defines.h.
72const int kMinTelephoneEventCode = 0; // RFC4733 (Section 2.3.1)
73const int kMaxTelephoneEventCode = 255;
Fredrik Solenbergb5727682015-12-04 15:22:19 +010074
solenberg31642aa2016-03-14 08:00:37 -070075const int kMinPayloadType = 0;
76const int kMaxPayloadType = 127;
77
deadbeef884f5852016-01-15 09:20:04 -080078class ProxySink : public webrtc::AudioSinkInterface {
79 public:
80 ProxySink(AudioSinkInterface* sink) : sink_(sink) { RTC_DCHECK(sink); }
81
82 void OnData(const Data& audio) override { sink_->OnData(audio); }
83
84 private:
85 webrtc::AudioSinkInterface* sink_;
86};
87
solenberg0b675462015-10-09 01:37:09 -070088bool ValidateStreamParams(const StreamParams& sp) {
89 if (sp.ssrcs.empty()) {
90 LOG(LS_ERROR) << "No SSRCs in stream parameters: " << sp.ToString();
91 return false;
92 }
93 if (sp.ssrcs.size() > 1) {
94 LOG(LS_ERROR) << "Multiple SSRCs in stream parameters: " << sp.ToString();
95 return false;
96 }
97 return true;
98}
99
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000100// Dumps an AudioCodec in RFC 2327-ish format.
solenbergd97ec302015-10-07 01:40:33 -0700101std::string ToString(const AudioCodec& codec) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000102 std::stringstream ss;
ossu20a4b3f2017-04-27 02:08:52 -0700103 ss << codec.name << "/" << codec.clockrate << "/" << codec.channels;
104 if (!codec.params.empty()) {
105 ss << " {";
106 for (const auto& param : codec.params) {
107 ss << " " << param.first << "=" << param.second;
108 }
109 ss << " }";
110 }
111 ss << " (" << codec.id << ")";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000112 return ss.str();
113}
Minyue Li7100dcd2015-03-27 05:05:59 +0100114
solenbergd97ec302015-10-07 01:40:33 -0700115bool IsCodec(const AudioCodec& codec, const char* ref_name) {
Minyue Li7100dcd2015-03-27 05:05:59 +0100116 return (_stricmp(codec.name.c_str(), ref_name) == 0);
117}
118
solenbergd97ec302015-10-07 01:40:33 -0700119bool FindCodec(const std::vector<AudioCodec>& codecs,
solenberg26c8c912015-11-27 04:00:25 -0800120 const AudioCodec& codec,
121 AudioCodec* found_codec) {
Fredrik Solenbergaf9fb212015-08-26 10:45:53 +0200122 for (const AudioCodec& c : codecs) {
123 if (c.Matches(codec)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000124 if (found_codec != NULL) {
Fredrik Solenbergaf9fb212015-08-26 10:45:53 +0200125 *found_codec = c;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000126 }
127 return true;
128 }
129 }
130 return false;
131}
wu@webrtc.org1d1ffc92013-10-16 18:12:02 +0000132
solenberg0b675462015-10-09 01:37:09 -0700133bool VerifyUniquePayloadTypes(const std::vector<AudioCodec>& codecs) {
134 if (codecs.empty()) {
135 return true;
136 }
137 std::vector<int> payload_types;
138 for (const AudioCodec& codec : codecs) {
139 payload_types.push_back(codec.id);
140 }
141 std::sort(payload_types.begin(), payload_types.end());
142 auto it = std::unique(payload_types.begin(), payload_types.end());
143 return it == payload_types.end();
144}
145
minyue6b825df2016-10-31 04:08:32 -0700146rtc::Optional<std::string> GetAudioNetworkAdaptorConfig(
147 const AudioOptions& options) {
148 if (options.audio_network_adaptor && *options.audio_network_adaptor &&
149 options.audio_network_adaptor_config) {
150 // Turn on audio network adaptor only when |options_.audio_network_adaptor|
151 // equals true and |options_.audio_network_adaptor_config| has a value.
152 return options.audio_network_adaptor_config;
153 }
154 return rtc::Optional<std::string>();
155}
156
gyzhou95aa9642016-12-13 14:06:26 -0800157webrtc::AudioState::Config MakeAudioStateConfig(
158 VoEWrapper* voe_wrapper,
peaha9cc40b2017-06-29 08:32:09 -0700159 rtc::scoped_refptr<webrtc::AudioMixer> audio_mixer,
160 rtc::scoped_refptr<webrtc::AudioProcessing> audio_processing) {
solenberg566ef242015-11-06 15:34:49 -0800161 webrtc::AudioState::Config config;
162 config.voice_engine = voe_wrapper->engine();
gyzhou95aa9642016-12-13 14:06:26 -0800163 if (audio_mixer) {
164 config.audio_mixer = audio_mixer;
165 } else {
166 config.audio_mixer = webrtc::AudioMixerImpl::Create();
167 }
peaha9cc40b2017-06-29 08:32:09 -0700168 config.audio_processing = audio_processing;
solenberg566ef242015-11-06 15:34:49 -0800169 return config;
170}
171
deadbeefe702b302017-02-04 12:09:01 -0800172// |max_send_bitrate_bps| is the bitrate from "b=" in SDP.
173// |rtp_max_bitrate_bps| is the bitrate from RtpSender::SetParameters.
minyue7a973442016-10-20 03:27:12 -0700174rtc::Optional<int> ComputeSendBitrate(int max_send_bitrate_bps,
deadbeefe702b302017-02-04 12:09:01 -0800175 rtc::Optional<int> rtp_max_bitrate_bps,
ossu20a4b3f2017-04-27 02:08:52 -0700176 const webrtc::AudioCodecSpec& spec) {
deadbeefe702b302017-02-04 12:09:01 -0800177 // If application-configured bitrate is set, take minimum of that and SDP
178 // bitrate.
zsteina5e0df62017-06-14 11:41:48 -0700179 const int bps =
180 rtp_max_bitrate_bps
181 ? webrtc::MinPositive(max_send_bitrate_bps, *rtp_max_bitrate_bps)
182 : max_send_bitrate_bps;
minyue7a973442016-10-20 03:27:12 -0700183 if (bps <= 0) {
ossu20a4b3f2017-04-27 02:08:52 -0700184 return rtc::Optional<int>(spec.info.default_bitrate_bps);
solenberg971cab02016-06-14 10:02:41 -0700185 }
minyue7a973442016-10-20 03:27:12 -0700186
ossu20a4b3f2017-04-27 02:08:52 -0700187 if (bps < spec.info.min_bitrate_bps) {
minyue7a973442016-10-20 03:27:12 -0700188 // If codec is not multi-rate and |bps| is less than the fixed bitrate then
189 // fail. If codec is not multi-rate and |bps| exceeds or equal the fixed
190 // bitrate then ignore.
ossu20a4b3f2017-04-27 02:08:52 -0700191 LOG(LS_ERROR) << "Failed to set codec " << spec.format.name
minyue7a973442016-10-20 03:27:12 -0700192 << " to bitrate " << bps << " bps"
ossu20a4b3f2017-04-27 02:08:52 -0700193 << ", requires at least " << spec.info.min_bitrate_bps
194 << " bps.";
minyue7a973442016-10-20 03:27:12 -0700195 return rtc::Optional<int>();
solenberg971cab02016-06-14 10:02:41 -0700196 }
ossu20a4b3f2017-04-27 02:08:52 -0700197
198 if (spec.info.HasFixedBitrate()) {
199 return rtc::Optional<int>(spec.info.default_bitrate_bps);
200 } else {
201 // If codec is multi-rate then just set the bitrate.
202 return rtc::Optional<int>(std::min(bps, spec.info.max_bitrate_bps));
203 }
solenberg971cab02016-06-14 10:02:41 -0700204}
205
solenberg76377c52017-02-21 00:54:31 -0800206} // namespace
solenberg971cab02016-06-14 10:02:41 -0700207
ossu29b1a8d2016-06-13 07:34:51 -0700208WebRtcVoiceEngine::WebRtcVoiceEngine(
209 webrtc::AudioDeviceModule* adm,
ossueb1fde42017-05-02 06:46:30 -0700210 const rtc::scoped_refptr<webrtc::AudioEncoderFactory>& encoder_factory,
gyzhou95aa9642016-12-13 14:06:26 -0800211 const rtc::scoped_refptr<webrtc::AudioDecoderFactory>& decoder_factory,
peaha9cc40b2017-06-29 08:32:09 -0700212 rtc::scoped_refptr<webrtc::AudioMixer> audio_mixer,
213 rtc::scoped_refptr<webrtc::AudioProcessing> audio_processing)
ossueb1fde42017-05-02 06:46:30 -0700214 : WebRtcVoiceEngine(adm,
215 encoder_factory,
216 decoder_factory,
217 audio_mixer,
peaha9cc40b2017-06-29 08:32:09 -0700218 audio_processing,
deadbeefeb02c032017-06-15 08:29:25 -0700219 nullptr) {}
solenberg26c8c912015-11-27 04:00:25 -0800220
ossu29b1a8d2016-06-13 07:34:51 -0700221WebRtcVoiceEngine::WebRtcVoiceEngine(
222 webrtc::AudioDeviceModule* adm,
ossueb1fde42017-05-02 06:46:30 -0700223 const rtc::scoped_refptr<webrtc::AudioEncoderFactory>& encoder_factory,
ossu29b1a8d2016-06-13 07:34:51 -0700224 const rtc::scoped_refptr<webrtc::AudioDecoderFactory>& decoder_factory,
gyzhou95aa9642016-12-13 14:06:26 -0800225 rtc::scoped_refptr<webrtc::AudioMixer> audio_mixer,
peaha9cc40b2017-06-29 08:32:09 -0700226 rtc::scoped_refptr<webrtc::AudioProcessing> audio_processing,
ossu29b1a8d2016-06-13 07:34:51 -0700227 VoEWrapper* voe_wrapper)
deadbeefeb02c032017-06-15 08:29:25 -0700228 : adm_(adm),
ossueb1fde42017-05-02 06:46:30 -0700229 encoder_factory_(encoder_factory),
ossu20a4b3f2017-04-27 02:08:52 -0700230 decoder_factory_(decoder_factory),
deadbeefeb02c032017-06-15 08:29:25 -0700231 audio_mixer_(audio_mixer),
peaha9cc40b2017-06-29 08:32:09 -0700232 apm_(audio_processing),
ossu20a4b3f2017-04-27 02:08:52 -0700233 voe_wrapper_(voe_wrapper) {
deadbeefeb02c032017-06-15 08:29:25 -0700234 // This may be called from any thread, so detach thread checkers.
235 worker_thread_checker_.DetachFromThread();
solenberg26c8c912015-11-27 04:00:25 -0800236 signal_thread_checker_.DetachFromThread();
deadbeefeb02c032017-06-15 08:29:25 -0700237 LOG(LS_INFO) << "WebRtcVoiceEngine::WebRtcVoiceEngine";
238 RTC_DCHECK(decoder_factory);
239 RTC_DCHECK(encoder_factory);
peaha9cc40b2017-06-29 08:32:09 -0700240 RTC_DCHECK(audio_processing);
deadbeefeb02c032017-06-15 08:29:25 -0700241 // The rest of our initialization will happen in Init.
242}
243
244WebRtcVoiceEngine::~WebRtcVoiceEngine() {
245 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
246 LOG(LS_INFO) << "WebRtcVoiceEngine::~WebRtcVoiceEngine";
247 if (initialized_) {
248 StopAecDump();
249 voe_wrapper_->base()->Terminate();
deadbeefeb02c032017-06-15 08:29:25 -0700250 }
251}
252
253void WebRtcVoiceEngine::Init() {
254 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
255 LOG(LS_INFO) << "WebRtcVoiceEngine::Init";
256
257 // TaskQueue expects to be created/destroyed on the same thread.
258 low_priority_worker_queue_.reset(
259 new rtc::TaskQueue("rtc-low-prio", rtc::TaskQueue::Priority::LOW));
260
261 // VoEWrapper needs to be created on the worker thread. It's expected to be
262 // null here unless it's being injected for testing.
263 if (!voe_wrapper_) {
264 voe_wrapper_.reset(new VoEWrapper());
265 }
solenberg26c8c912015-11-27 04:00:25 -0800266
ossueb1fde42017-05-02 06:46:30 -0700267 // Load our audio codec lists.
ossuc54071d2016-08-17 02:45:41 -0700268 LOG(LS_INFO) << "Supported send codecs in order of preference:";
ossu20a4b3f2017-04-27 02:08:52 -0700269 send_codecs_ = CollectCodecs(encoder_factory_->GetSupportedEncoders());
ossuc54071d2016-08-17 02:45:41 -0700270 for (const AudioCodec& codec : send_codecs_) {
271 LOG(LS_INFO) << ToString(codec);
272 }
273
274 LOG(LS_INFO) << "Supported recv codecs in order of preference:";
ossu20a4b3f2017-04-27 02:08:52 -0700275 recv_codecs_ = CollectCodecs(decoder_factory_->GetSupportedDecoders());
ossuc54071d2016-08-17 02:45:41 -0700276 for (const AudioCodec& codec : recv_codecs_) {
solenbergff976312016-03-30 23:28:51 -0700277 LOG(LS_INFO) << ToString(codec);
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000278 }
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000279
solenberg88499ec2016-09-07 07:34:41 -0700280 channel_config_.enable_voice_pacing = true;
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000281
peaha9cc40b2017-06-29 08:32:09 -0700282 RTC_CHECK_EQ(0,
283 voe_wrapper_->base()->Init(adm_.get(), apm(), decoder_factory_));
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000284
solenbergff976312016-03-30 23:28:51 -0700285 // No ADM supplied? Get the default one from VoE.
286 if (!adm_) {
287 adm_ = voe_wrapper_->base()->audio_device_module();
288 }
289 RTC_DCHECK(adm_);
290
solenberg76377c52017-02-21 00:54:31 -0800291 transmit_mixer_ = voe_wrapper_->base()->transmit_mixer();
292 RTC_DCHECK(transmit_mixer_);
293
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000294 // Save the default AGC configuration settings. This must happen before
solenberg246b8172015-12-08 09:50:23 -0800295 // calling ApplyOptions or the default will be overwritten.
peaha9cc40b2017-06-29 08:32:09 -0700296 default_agc_config_ = webrtc::apm_helpers::GetAgcConfig(apm());
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000297
solenberg0f7d2932016-01-15 01:40:39 -0800298 // Set default engine options.
299 {
300 AudioOptions options;
301 options.echo_cancellation = rtc::Optional<bool>(true);
302 options.auto_gain_control = rtc::Optional<bool>(true);
303 options.noise_suppression = rtc::Optional<bool>(true);
304 options.highpass_filter = rtc::Optional<bool>(true);
305 options.stereo_swapping = rtc::Optional<bool>(false);
306 options.audio_jitter_buffer_max_packets = rtc::Optional<int>(50);
307 options.audio_jitter_buffer_fast_accelerate = rtc::Optional<bool>(false);
308 options.typing_detection = rtc::Optional<bool>(true);
309 options.adjust_agc_delta = rtc::Optional<int>(0);
310 options.experimental_agc = rtc::Optional<bool>(false);
311 options.extended_filter_aec = rtc::Optional<bool>(false);
312 options.delay_agnostic_aec = rtc::Optional<bool>(false);
313 options.experimental_ns = rtc::Optional<bool>(false);
Alejandro Luebsc9b0c262016-05-16 15:32:38 -0700314 options.intelligibility_enhancer = rtc::Optional<bool>(false);
peaha3333bf2016-06-30 00:02:34 -0700315 options.level_control = rtc::Optional<bool>(false);
ivocb829d9f2016-11-15 02:34:47 -0800316 options.residual_echo_detector = rtc::Optional<bool>(true);
solenbergff976312016-03-30 23:28:51 -0700317 bool error = ApplyOptions(options);
318 RTC_DCHECK(error);
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000319 }
320
solenberg9a5f032222017-03-15 06:14:12 -0700321 // Set default audio devices.
322#if !defined(WEBRTC_IOS)
323 webrtc::adm_helpers::SetRecordingDevice(adm_);
324 apm()->Initialize();
325 webrtc::adm_helpers::SetPlayoutDevice(adm_);
326#endif // !WEBRTC_IOS
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000327
deadbeefeb02c032017-06-15 08:29:25 -0700328 // May be null for VoE injected for testing.
329 if (voe()->engine()) {
peaha9cc40b2017-06-29 08:32:09 -0700330 audio_state_ = webrtc::AudioState::Create(
331 MakeAudioStateConfig(voe(), audio_mixer_, apm_));
deadbeefeb02c032017-06-15 08:29:25 -0700332 }
333
334 initialized_ = true;
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000335}
336
solenberg566ef242015-11-06 15:34:49 -0800337rtc::scoped_refptr<webrtc::AudioState>
338 WebRtcVoiceEngine::GetAudioState() const {
339 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
340 return audio_state_;
341}
342
nisse51542be2016-02-12 02:27:06 -0800343VoiceMediaChannel* WebRtcVoiceEngine::CreateChannel(
344 webrtc::Call* call,
345 const MediaConfig& config,
Jelena Marusicc28a8962015-05-29 15:05:44 +0200346 const AudioOptions& options) {
solenberg566ef242015-11-06 15:34:49 -0800347 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
nisse51542be2016-02-12 02:27:06 -0800348 return new WebRtcVoiceMediaChannel(this, config, options, call);
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000349}
350
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000351bool WebRtcVoiceEngine::ApplyOptions(const AudioOptions& options_in) {
solenberg566ef242015-11-06 15:34:49 -0800352 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenbergff976312016-03-30 23:28:51 -0700353 LOG(LS_INFO) << "WebRtcVoiceEngine::ApplyOptions: " << options_in.ToString();
solenberg0f7d2932016-01-15 01:40:39 -0800354 AudioOptions options = options_in; // The options are modified below.
solenberg246b8172015-12-08 09:50:23 -0800355
peah8a8ebd92017-05-22 15:48:47 -0700356 // Set and adjust echo canceller options.
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000357 // kEcConference is AEC with high suppression.
358 webrtc::EcModes ec_mode = webrtc::kEcConference;
kwiberg102c6a62015-10-30 02:47:38 -0700359 if (options.aecm_generate_comfort_noise) {
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000360 LOG(LS_VERBOSE) << "Comfort noise explicitly set to "
kwiberg102c6a62015-10-30 02:47:38 -0700361 << *options.aecm_generate_comfort_noise
362 << " (default is false).";
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000363 }
364
kjellanderfcfc8042016-01-14 11:01:09 -0800365#if defined(WEBRTC_IOS)
peah8a8ebd92017-05-22 15:48:47 -0700366 // On iOS, VPIO provides built-in EC.
Karl Wibergbe579832015-11-10 22:34:18 +0100367 options.echo_cancellation = rtc::Optional<bool>(false);
peah8a8ebd92017-05-22 15:48:47 -0700368 options.extended_filter_aec = rtc::Optional<bool>(false);
369 LOG(LS_INFO) << "Always disable AEC on iOS. Use built-in instead.";
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000370#elif defined(ANDROID)
371 ec_mode = webrtc::kEcAecm;
Karl Wibergbe579832015-11-10 22:34:18 +0100372 options.extended_filter_aec = rtc::Optional<bool>(false);
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000373#endif
374
Bjorn Volckerbf395c12015-03-25 22:45:56 +0100375 // Delay Agnostic AEC automatically turns on EC if not set except on iOS
376 // where the feature is not supported.
377 bool use_delay_agnostic_aec = false;
kjellanderfcfc8042016-01-14 11:01:09 -0800378#if !defined(WEBRTC_IOS)
kwiberg102c6a62015-10-30 02:47:38 -0700379 if (options.delay_agnostic_aec) {
380 use_delay_agnostic_aec = *options.delay_agnostic_aec;
Bjorn Volckerbf395c12015-03-25 22:45:56 +0100381 if (use_delay_agnostic_aec) {
Karl Wibergbe579832015-11-10 22:34:18 +0100382 options.echo_cancellation = rtc::Optional<bool>(true);
383 options.extended_filter_aec = rtc::Optional<bool>(true);
Bjorn Volckerbf395c12015-03-25 22:45:56 +0100384 ec_mode = webrtc::kEcConference;
385 }
386 }
387#endif
388
peah8a8ebd92017-05-22 15:48:47 -0700389// Set and adjust noise suppressor options.
390#if defined(WEBRTC_IOS)
391 // On iOS, VPIO provides built-in NS.
392 options.noise_suppression = rtc::Optional<bool>(false);
393 options.typing_detection = rtc::Optional<bool>(false);
394 options.experimental_ns = rtc::Optional<bool>(false);
395 LOG(LS_INFO) << "Always disable NS on iOS. Use built-in instead.";
396#elif defined(ANDROID)
397 options.typing_detection = rtc::Optional<bool>(false);
398 options.experimental_ns = rtc::Optional<bool>(false);
399#endif
400
401// Set and adjust gain control options.
402#if defined(WEBRTC_IOS)
403 // On iOS, VPIO provides built-in AGC.
404 options.auto_gain_control = rtc::Optional<bool>(false);
405 options.experimental_agc = rtc::Optional<bool>(false);
406 LOG(LS_INFO) << "Always disable AGC on iOS. Use built-in instead.";
407#elif defined(ANDROID)
408 options.experimental_agc = rtc::Optional<bool>(false);
409#endif
410
411#if defined(WEBRTC_IOS) || defined(WEBRTC_ANDROID)
412 // 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).
413 if (webrtc::field_trial::IsEnabled(
414 "WebRTC-Audio-MinimizeResamplingOnMobile")) {
415 options.auto_gain_control = rtc::Optional<bool>(false);
416 LOG(LS_INFO) << "Disable AGC according to field trial.";
417 if (!(options.noise_suppression.value_or(false) or
418 options.echo_cancellation.value_or(false))) {
419 // If possible, turn off the high-pass filter.
420 LOG(LS_INFO) << "Disable high-pass filter in response to field trial.";
421 options.highpass_filter = rtc::Optional<bool>(false);
422 }
423 }
424#endif
425
peah1bcfce52016-08-26 07:16:04 -0700426#if (WEBRTC_INTELLIGIBILITY_ENHANCER == 0)
427 // Hardcode the intelligibility enhancer to be off.
428 options.intelligibility_enhancer = rtc::Optional<bool>(false);
429#endif
430
kwiberg102c6a62015-10-30 02:47:38 -0700431 if (options.echo_cancellation) {
henrika@webrtc.orga954c072014-12-09 16:22:09 +0000432 // Check if platform supports built-in EC. Currently only supported on
433 // Android and in combination with Java based audio layer.
434 // TODO(henrika): investigate possibility to support built-in EC also
435 // in combination with Open SL ES audio.
solenberg5b5129a2016-04-08 05:35:48 -0700436 const bool built_in_aec = adm()->BuiltInAECIsAvailable();
Bjorn Volcker73f72102015-06-03 14:50:15 +0200437 if (built_in_aec) {
Bjorn Volckerccfc9392015-05-07 07:43:17 +0200438 // Built-in EC exists on this device and use_delay_agnostic_aec is not
439 // overriding it. Enable/Disable it according to the echo_cancellation
440 // audio option.
Bjorn Volcker73f72102015-06-03 14:50:15 +0200441 const bool enable_built_in_aec =
kwiberg102c6a62015-10-30 02:47:38 -0700442 *options.echo_cancellation && !use_delay_agnostic_aec;
solenberg5b5129a2016-04-08 05:35:48 -0700443 if (adm()->EnableBuiltInAEC(enable_built_in_aec) == 0 &&
Bjorn Volcker73f72102015-06-03 14:50:15 +0200444 enable_built_in_aec) {
Bjorn Volckerbf395c12015-03-25 22:45:56 +0100445 // Disable internal software EC if built-in EC is enabled,
henrika@webrtc.orga954c072014-12-09 16:22:09 +0000446 // i.e., replace the software EC with the built-in EC.
Karl Wibergbe579832015-11-10 22:34:18 +0100447 options.echo_cancellation = rtc::Optional<bool>(false);
henrika@webrtc.orga954c072014-12-09 16:22:09 +0000448 LOG(LS_INFO) << "Disabling EC since built-in EC will be used instead";
449 }
450 }
solenberg76377c52017-02-21 00:54:31 -0800451 webrtc::apm_helpers::SetEcStatus(
452 apm(), *options.echo_cancellation, ec_mode);
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000453#if !defined(ANDROID)
solenberg76377c52017-02-21 00:54:31 -0800454 webrtc::apm_helpers::SetEcMetricsStatus(apm(), *options.echo_cancellation);
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000455#endif
456 if (ec_mode == webrtc::kEcAecm) {
kwiberg102c6a62015-10-30 02:47:38 -0700457 bool cn = options.aecm_generate_comfort_noise.value_or(false);
solenberg76377c52017-02-21 00:54:31 -0800458 webrtc::apm_helpers::SetAecmMode(apm(), cn);
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000459 }
460 }
461
kwiberg102c6a62015-10-30 02:47:38 -0700462 if (options.auto_gain_control) {
peah72a56452016-08-22 12:08:55 -0700463 bool built_in_agc_avaliable = adm()->BuiltInAGCIsAvailable();
464 if (built_in_agc_avaliable) {
solenberg5b5129a2016-04-08 05:35:48 -0700465 if (adm()->EnableBuiltInAGC(*options.auto_gain_control) == 0 &&
kwiberg102c6a62015-10-30 02:47:38 -0700466 *options.auto_gain_control) {
henrikac14f5ff2015-09-23 14:08:33 +0200467 // Disable internal software AGC if built-in AGC is enabled,
468 // i.e., replace the software AGC with the built-in AGC.
Karl Wibergbe579832015-11-10 22:34:18 +0100469 options.auto_gain_control = rtc::Optional<bool>(false);
henrikac14f5ff2015-09-23 14:08:33 +0200470 LOG(LS_INFO) << "Disabling AGC since built-in AGC will be used instead";
471 }
472 }
solenberg22818a52017-03-16 01:20:23 -0700473 webrtc::apm_helpers::SetAgcStatus(apm(), adm(), *options.auto_gain_control);
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000474 }
475
kwiberg102c6a62015-10-30 02:47:38 -0700476 if (options.tx_agc_target_dbov || options.tx_agc_digital_compression_gain ||
solenberg76377c52017-02-21 00:54:31 -0800477 options.tx_agc_limiter || options.adjust_agc_delta) {
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000478 // Override default_agc_config_. Generally, an unset option means "leave
479 // the VoE bits alone" in this function, so we want whatever is set to be
480 // stored as the new "default". If we didn't, then setting e.g.
481 // tx_agc_target_dbov would reset digital compression gain and limiter
482 // settings.
483 // Also, if we don't update default_agc_config_, then adjust_agc_delta
484 // would be an offset from the original values, and not whatever was set
485 // explicitly.
kwiberg102c6a62015-10-30 02:47:38 -0700486 default_agc_config_.targetLeveldBOv = options.tx_agc_target_dbov.value_or(
487 default_agc_config_.targetLeveldBOv);
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000488 default_agc_config_.digitalCompressionGaindB =
kwiberg102c6a62015-10-30 02:47:38 -0700489 options.tx_agc_digital_compression_gain.value_or(
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000490 default_agc_config_.digitalCompressionGaindB);
491 default_agc_config_.limiterEnable =
kwiberg102c6a62015-10-30 02:47:38 -0700492 options.tx_agc_limiter.value_or(default_agc_config_.limiterEnable);
solenberg76377c52017-02-21 00:54:31 -0800493
494 webrtc::AgcConfig config = default_agc_config_;
495 if (options.adjust_agc_delta) {
496 config.targetLeveldBOv -= *options.adjust_agc_delta;
497 LOG(LS_INFO) << "Adjusting AGC level from default -"
498 << default_agc_config_.targetLeveldBOv << "dB to -"
499 << config.targetLeveldBOv << "dB";
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000500 }
peaha9cc40b2017-06-29 08:32:09 -0700501 webrtc::apm_helpers::SetAgcConfig(apm(), config);
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000502 }
503
Alejandro Luebsc9b0c262016-05-16 15:32:38 -0700504 if (options.intelligibility_enhancer) {
505 intelligibility_enhancer_ = options.intelligibility_enhancer;
506 }
507 if (intelligibility_enhancer_ && *intelligibility_enhancer_) {
508 LOG(LS_INFO) << "Enabling NS when Intelligibility Enhancer is active.";
509 options.noise_suppression = intelligibility_enhancer_;
510 }
511
kwiberg102c6a62015-10-30 02:47:38 -0700512 if (options.noise_suppression) {
Alejandro Luebsc9b0c262016-05-16 15:32:38 -0700513 if (adm()->BuiltInNSIsAvailable()) {
514 bool builtin_ns =
515 *options.noise_suppression &&
516 !(intelligibility_enhancer_ && *intelligibility_enhancer_);
517 if (adm()->EnableBuiltInNS(builtin_ns) == 0 && builtin_ns) {
henrikac14f5ff2015-09-23 14:08:33 +0200518 // Disable internal software NS if built-in NS is enabled,
519 // i.e., replace the software NS with the built-in NS.
Karl Wibergbe579832015-11-10 22:34:18 +0100520 options.noise_suppression = rtc::Optional<bool>(false);
henrikac14f5ff2015-09-23 14:08:33 +0200521 LOG(LS_INFO) << "Disabling NS since built-in NS will be used instead";
522 }
523 }
solenberg76377c52017-02-21 00:54:31 -0800524 webrtc::apm_helpers::SetNsStatus(apm(), *options.noise_suppression);
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000525 }
526
kwiberg102c6a62015-10-30 02:47:38 -0700527 if (options.stereo_swapping) {
528 LOG(LS_INFO) << "Stereo swapping enabled? " << *options.stereo_swapping;
solenberg76377c52017-02-21 00:54:31 -0800529 transmit_mixer()->EnableStereoChannelSwapping(*options.stereo_swapping);
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000530 }
531
kwiberg102c6a62015-10-30 02:47:38 -0700532 if (options.audio_jitter_buffer_max_packets) {
533 LOG(LS_INFO) << "NetEq capacity is "
534 << *options.audio_jitter_buffer_max_packets;
solenberg88499ec2016-09-07 07:34:41 -0700535 channel_config_.acm_config.neteq_config.max_packets_in_buffer =
536 std::max(20, *options.audio_jitter_buffer_max_packets);
Henrik Lundin64dad832015-05-11 12:44:23 +0200537 }
kwiberg102c6a62015-10-30 02:47:38 -0700538 if (options.audio_jitter_buffer_fast_accelerate) {
539 LOG(LS_INFO) << "NetEq fast mode? "
540 << *options.audio_jitter_buffer_fast_accelerate;
solenberg88499ec2016-09-07 07:34:41 -0700541 channel_config_.acm_config.neteq_config.enable_fast_accelerate =
542 *options.audio_jitter_buffer_fast_accelerate;
Henrik Lundin5263b3c2015-06-01 10:29:41 +0200543 }
544
kwiberg102c6a62015-10-30 02:47:38 -0700545 if (options.typing_detection) {
546 LOG(LS_INFO) << "Typing detection is enabled? "
547 << *options.typing_detection;
solenberg76377c52017-02-21 00:54:31 -0800548 webrtc::apm_helpers::SetTypingDetectionStatus(
549 apm(), *options.typing_detection);
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000550 }
551
buildbot@webrtc.org1f8a2372014-08-28 10:52:44 +0000552 webrtc::Config config;
553
kwiberg102c6a62015-10-30 02:47:38 -0700554 if (options.delay_agnostic_aec)
555 delay_agnostic_aec_ = options.delay_agnostic_aec;
556 if (delay_agnostic_aec_) {
557 LOG(LS_INFO) << "Delay agnostic aec is enabled? " << *delay_agnostic_aec_;
henrik.lundin0f133b92015-07-02 00:17:55 -0700558 config.Set<webrtc::DelayAgnostic>(
kwiberg102c6a62015-10-30 02:47:38 -0700559 new webrtc::DelayAgnostic(*delay_agnostic_aec_));
Bjorn Volckerbf395c12015-03-25 22:45:56 +0100560 }
561
kwiberg102c6a62015-10-30 02:47:38 -0700562 if (options.extended_filter_aec) {
563 extended_filter_aec_ = options.extended_filter_aec;
564 }
565 if (extended_filter_aec_) {
566 LOG(LS_INFO) << "Extended filter aec is enabled? " << *extended_filter_aec_;
Henrik Lundin441f6342015-06-09 16:03:13 +0200567 config.Set<webrtc::ExtendedFilter>(
kwiberg102c6a62015-10-30 02:47:38 -0700568 new webrtc::ExtendedFilter(*extended_filter_aec_));
buildbot@webrtc.org1f8a2372014-08-28 10:52:44 +0000569 }
570
kwiberg102c6a62015-10-30 02:47:38 -0700571 if (options.experimental_ns) {
572 experimental_ns_ = options.experimental_ns;
573 }
574 if (experimental_ns_) {
575 LOG(LS_INFO) << "Experimental ns is enabled? " << *experimental_ns_;
buildbot@webrtc.org1f8a2372014-08-28 10:52:44 +0000576 config.Set<webrtc::ExperimentalNs>(
kwiberg102c6a62015-10-30 02:47:38 -0700577 new webrtc::ExperimentalNs(*experimental_ns_));
buildbot@webrtc.org1f8a2372014-08-28 10:52:44 +0000578 }
buildbot@webrtc.org1f8a2372014-08-28 10:52:44 +0000579
Alejandro Luebsc9b0c262016-05-16 15:32:38 -0700580 if (intelligibility_enhancer_) {
581 LOG(LS_INFO) << "Intelligibility Enhancer is enabled? "
582 << *intelligibility_enhancer_;
583 config.Set<webrtc::Intelligibility>(
584 new webrtc::Intelligibility(*intelligibility_enhancer_));
585 }
586
peaha3333bf2016-06-30 00:02:34 -0700587 if (options.level_control) {
588 level_control_ = options.level_control;
589 }
590
peahb1c9d1d2017-07-25 15:45:24 -0700591 webrtc::AudioProcessing::Config apm_config = apm()->GetConfig();
592
peaha3333bf2016-06-30 00:02:34 -0700593 LOG(LS_INFO) << "Level control: "
594 << (!!level_control_ ? *level_control_ : -1);
595 if (level_control_) {
peahb1c9d1d2017-07-25 15:45:24 -0700596 apm_config.level_controller.enabled = *level_control_;
aleloie33c5d92016-10-20 01:53:27 -0700597 if (options.level_control_initial_peak_level_dbfs) {
peahb1c9d1d2017-07-25 15:45:24 -0700598 apm_config.level_controller.initial_peak_level_dbfs =
aleloie33c5d92016-10-20 01:53:27 -0700599 *options.level_control_initial_peak_level_dbfs;
600 }
peaha3333bf2016-06-30 00:02:34 -0700601 }
602
peah8271d042016-11-22 07:24:52 -0800603 if (options.highpass_filter) {
peahb1c9d1d2017-07-25 15:45:24 -0700604 apm_config.high_pass_filter.enabled = *options.highpass_filter;
peah8271d042016-11-22 07:24:52 -0800605 }
606
ivoc4ca18692017-02-10 05:11:09 -0800607 if (options.residual_echo_detector) {
peahb1c9d1d2017-07-25 15:45:24 -0700608 apm_config.residual_echo_detector.enabled = *options.residual_echo_detector;
ivoc4ca18692017-02-10 05:11:09 -0800609 }
610
solenberg059fb442016-10-26 05:12:24 -0700611 apm()->SetExtraOptions(config);
peahb1c9d1d2017-07-25 15:45:24 -0700612 apm()->ApplyConfig(apm_config);
buildbot@webrtc.org1f8a2372014-08-28 10:52:44 +0000613
kwiberg102c6a62015-10-30 02:47:38 -0700614 if (options.recording_sample_rate) {
615 LOG(LS_INFO) << "Recording sample rate is "
616 << *options.recording_sample_rate;
solenberg5b5129a2016-04-08 05:35:48 -0700617 if (adm()->SetRecordingSampleRate(*options.recording_sample_rate)) {
solenberg35dee812017-09-18 01:57:01 -0700618 LOG(LS_WARNING) << "SetRecordingSampleRate("
619 << *options.recording_sample_rate << ") failed, err="
620 << adm()->LastError();
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000621 }
622 }
623
kwiberg102c6a62015-10-30 02:47:38 -0700624 if (options.playout_sample_rate) {
625 LOG(LS_INFO) << "Playout sample rate is " << *options.playout_sample_rate;
solenberg5b5129a2016-04-08 05:35:48 -0700626 if (adm()->SetPlayoutSampleRate(*options.playout_sample_rate)) {
solenberg35dee812017-09-18 01:57:01 -0700627 LOG(LS_WARNING) << "SetPlayoutSampleRate("
628 << *options.playout_sample_rate << ") failed, err="
629 << adm()->LastError();
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000630 }
631 }
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000632 return true;
633}
634
solenberg796b8f92017-03-01 17:02:23 -0800635// TODO(solenberg): Remove, once AudioMonitor is gone.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000636int WebRtcVoiceEngine::GetInputLevel() {
solenberg566ef242015-11-06 15:34:49 -0800637 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenberg796b8f92017-03-01 17:02:23 -0800638 int8_t level = transmit_mixer()->AudioLevel();
639 RTC_DCHECK_LE(0, level);
640 return level;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000641}
642
ossudedfd282016-06-14 07:12:39 -0700643const std::vector<AudioCodec>& WebRtcVoiceEngine::send_codecs() const {
644 RTC_DCHECK(signal_thread_checker_.CalledOnValidThread());
ossuc54071d2016-08-17 02:45:41 -0700645 return send_codecs_;
ossudedfd282016-06-14 07:12:39 -0700646}
647
648const std::vector<AudioCodec>& WebRtcVoiceEngine::recv_codecs() const {
solenberg566ef242015-11-06 15:34:49 -0800649 RTC_DCHECK(signal_thread_checker_.CalledOnValidThread());
ossuc54071d2016-08-17 02:45:41 -0700650 return recv_codecs_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000651}
652
Stefan Holmer9d69c3f2015-12-07 10:45:43 +0100653RtpCapabilities WebRtcVoiceEngine::GetCapabilities() const {
solenberg566ef242015-11-06 15:34:49 -0800654 RTC_DCHECK(signal_thread_checker_.CalledOnValidThread());
Stefan Holmer9d69c3f2015-12-07 10:45:43 +0100655 RtpCapabilities capabilities;
Stefan Holmer9d69c3f2015-12-07 10:45:43 +0100656 capabilities.header_extensions.push_back(
isheriff6f8d6862016-05-26 11:24:55 -0700657 webrtc::RtpExtension(webrtc::RtpExtension::kAudioLevelUri,
658 webrtc::RtpExtension::kAudioLevelDefaultId));
sprangc1b57a12017-02-28 08:50:47 -0800659 if (webrtc::field_trial::IsEnabled("WebRTC-Audio-SendSideBwe")) {
isheriff6f8d6862016-05-26 11:24:55 -0700660 capabilities.header_extensions.push_back(webrtc::RtpExtension(
661 webrtc::RtpExtension::kTransportSequenceNumberUri,
662 webrtc::RtpExtension::kTransportSequenceNumberDefaultId));
stefanba4c0e42016-02-04 04:12:24 -0800663 }
Stefan Holmer9d69c3f2015-12-07 10:45:43 +0100664 return capabilities;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000665}
666
solenberg63b34542015-09-29 06:06:31 -0700667void WebRtcVoiceEngine::RegisterChannel(WebRtcVoiceMediaChannel* channel) {
solenberg566ef242015-11-06 15:34:49 -0800668 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
669 RTC_DCHECK(channel);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000670 channels_.push_back(channel);
671}
672
solenberg63b34542015-09-29 06:06:31 -0700673void WebRtcVoiceEngine::UnregisterChannel(WebRtcVoiceMediaChannel* channel) {
solenberg566ef242015-11-06 15:34:49 -0800674 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenberg63b34542015-09-29 06:06:31 -0700675 auto it = std::find(channels_.begin(), channels_.end(), channel);
solenberg566ef242015-11-06 15:34:49 -0800676 RTC_DCHECK(it != channels_.end());
677 channels_.erase(it);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000678}
679
ivocd66b44d2016-01-15 03:06:36 -0800680bool WebRtcVoiceEngine::StartAecDump(rtc::PlatformFile file,
681 int64_t max_size_bytes) {
solenberg566ef242015-11-06 15:34:49 -0800682 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
deadbeefeb02c032017-06-15 08:29:25 -0700683 auto aec_dump = webrtc::AecDumpFactory::Create(
684 file, max_size_bytes, low_priority_worker_queue_.get());
aleloi048cbdd2017-05-29 02:56:27 -0700685 if (!aec_dump) {
wu@webrtc.orga8910d22014-01-23 22:12:45 +0000686 return false;
687 }
aleloi048cbdd2017-05-29 02:56:27 -0700688 apm()->AttachAecDump(std::move(aec_dump));
wu@webrtc.orga9890802013-12-13 00:21:03 +0000689 return true;
wu@webrtc.orga9890802013-12-13 00:21:03 +0000690}
691
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000692void WebRtcVoiceEngine::StartAecDump(const std::string& filename) {
solenberg566ef242015-11-06 15:34:49 -0800693 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
aleloi048cbdd2017-05-29 02:56:27 -0700694
deadbeefeb02c032017-06-15 08:29:25 -0700695 auto aec_dump = webrtc::AecDumpFactory::Create(
696 filename, -1, low_priority_worker_queue_.get());
aleloi048cbdd2017-05-29 02:56:27 -0700697 if (aec_dump) {
698 apm()->AttachAecDump(std::move(aec_dump));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000699 }
700}
701
702void WebRtcVoiceEngine::StopAecDump() {
solenberg566ef242015-11-06 15:34:49 -0800703 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
aleloi048cbdd2017-05-29 02:56:27 -0700704 apm()->DetachAecDump();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000705}
706
solenberg0a617e22015-10-20 15:49:38 -0700707int WebRtcVoiceEngine::CreateVoEChannel() {
solenberg566ef242015-11-06 15:34:49 -0800708 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenberg88499ec2016-09-07 07:34:41 -0700709 return voe_wrapper_->base()->CreateChannel(channel_config_);
sergeyu@chromium.org5bc25c42013-12-05 00:24:06 +0000710}
711
solenberg5b5129a2016-04-08 05:35:48 -0700712webrtc::AudioDeviceModule* WebRtcVoiceEngine::adm() {
713 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
714 RTC_DCHECK(adm_);
715 return adm_;
716}
717
peahb1c9d1d2017-07-25 15:45:24 -0700718webrtc::AudioProcessing* WebRtcVoiceEngine::apm() const {
solenberg059fb442016-10-26 05:12:24 -0700719 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
peaha9cc40b2017-06-29 08:32:09 -0700720 return apm_.get();
solenberg059fb442016-10-26 05:12:24 -0700721}
722
solenberg76377c52017-02-21 00:54:31 -0800723webrtc::voe::TransmitMixer* WebRtcVoiceEngine::transmit_mixer() {
724 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
725 RTC_DCHECK(transmit_mixer_);
726 return transmit_mixer_;
727}
728
ossu20a4b3f2017-04-27 02:08:52 -0700729AudioCodecs WebRtcVoiceEngine::CollectCodecs(
730 const std::vector<webrtc::AudioCodecSpec>& specs) const {
ossuc54071d2016-08-17 02:45:41 -0700731 PayloadTypeMapper mapper;
732 AudioCodecs out;
ossuc54071d2016-08-17 02:45:41 -0700733
solenberg2779bab2016-11-17 04:45:19 -0800734 // Only generate CN payload types for these clockrates:
ossuc54071d2016-08-17 02:45:41 -0700735 std::map<int, bool, std::greater<int>> generate_cn = {{ 8000, false },
736 { 16000, false },
737 { 32000, false }};
solenberg2779bab2016-11-17 04:45:19 -0800738 // Only generate telephone-event payload types for these clockrates:
739 std::map<int, bool, std::greater<int>> generate_dtmf = {{ 8000, false },
740 { 16000, false },
741 { 32000, false },
742 { 48000, false }};
ossuc54071d2016-08-17 02:45:41 -0700743
ossu9def8002017-02-09 05:14:32 -0800744 auto map_format = [&mapper](const webrtc::SdpAudioFormat& format,
745 AudioCodecs* out) {
ossuc54071d2016-08-17 02:45:41 -0700746 rtc::Optional<AudioCodec> opt_codec = mapper.ToAudioCodec(format);
ossu9def8002017-02-09 05:14:32 -0800747 if (opt_codec) {
748 if (out) {
749 out->push_back(*opt_codec);
750 }
751 } else {
ossuc54071d2016-08-17 02:45:41 -0700752 LOG(LS_ERROR) << "Unable to assign payload type to format: " << format;
ossuc54071d2016-08-17 02:45:41 -0700753 }
754
ossu9def8002017-02-09 05:14:32 -0800755 return opt_codec;
ossuc54071d2016-08-17 02:45:41 -0700756 };
757
ossud4e9f622016-08-18 02:01:17 -0700758 for (const auto& spec : specs) {
ossu9def8002017-02-09 05:14:32 -0800759 // We need to do some extra stuff before adding the main codecs to out.
760 rtc::Optional<AudioCodec> opt_codec = map_format(spec.format, nullptr);
761 if (opt_codec) {
762 AudioCodec& codec = *opt_codec;
ossua1a040a2017-04-06 10:03:21 -0700763 if (spec.info.supports_network_adaption) {
ossu9def8002017-02-09 05:14:32 -0800764 codec.AddFeedbackParam(
765 FeedbackParam(kRtcpFbParamTransportCc, kParamValueEmpty));
766 }
767
ossua1a040a2017-04-06 10:03:21 -0700768 if (spec.info.allow_comfort_noise) {
solenberg2779bab2016-11-17 04:45:19 -0800769 // Generate a CN entry if the decoder allows it and we support the
770 // clockrate.
771 auto cn = generate_cn.find(spec.format.clockrate_hz);
772 if (cn != generate_cn.end()) {
773 cn->second = true;
774 }
775 }
776
777 // Generate a telephone-event entry if we support the clockrate.
778 auto dtmf = generate_dtmf.find(spec.format.clockrate_hz);
779 if (dtmf != generate_dtmf.end()) {
780 dtmf->second = true;
ossuc54071d2016-08-17 02:45:41 -0700781 }
ossu9def8002017-02-09 05:14:32 -0800782
783 out.push_back(codec);
ossuc54071d2016-08-17 02:45:41 -0700784 }
785 }
786
solenberg2779bab2016-11-17 04:45:19 -0800787 // Add CN codecs after "proper" audio codecs.
ossuc54071d2016-08-17 02:45:41 -0700788 for (const auto& cn : generate_cn) {
789 if (cn.second) {
ossu9def8002017-02-09 05:14:32 -0800790 map_format({kCnCodecName, cn.first, 1}, &out);
ossuc54071d2016-08-17 02:45:41 -0700791 }
792 }
793
solenberg2779bab2016-11-17 04:45:19 -0800794 // Add telephone-event codecs last.
795 for (const auto& dtmf : generate_dtmf) {
796 if (dtmf.second) {
ossu9def8002017-02-09 05:14:32 -0800797 map_format({kDtmfCodecName, dtmf.first, 1}, &out);
solenberg2779bab2016-11-17 04:45:19 -0800798 }
799 }
ossuc54071d2016-08-17 02:45:41 -0700800
801 return out;
802}
803
solenbergc96df772015-10-21 13:01:53 -0700804class WebRtcVoiceMediaChannel::WebRtcAudioSendStream
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -0800805 : public AudioSource::Sink {
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +0000806 public:
minyue7a973442016-10-20 03:27:12 -0700807 WebRtcAudioSendStream(
808 int ch,
809 webrtc::AudioTransport* voe_audio_transport,
810 uint32_t ssrc,
811 const std::string& c_name,
Alex Narestb3944f02017-10-13 14:56:18 +0200812 const std::string track_id,
ossu20a4b3f2017-04-27 02:08:52 -0700813 const rtc::Optional<webrtc::AudioSendStream::Config::SendCodecSpec>&
814 send_codec_spec,
minyue7a973442016-10-20 03:27:12 -0700815 const std::vector<webrtc::RtpExtension>& extensions,
816 int max_send_bitrate_bps,
minyue6b825df2016-10-31 04:08:32 -0700817 const rtc::Optional<std::string>& audio_network_adaptor_config,
minyue7a973442016-10-20 03:27:12 -0700818 webrtc::Call* call,
ossu20a4b3f2017-04-27 02:08:52 -0700819 webrtc::Transport* send_transport,
820 const rtc::scoped_refptr<webrtc::AudioEncoderFactory>& encoder_factory)
solenberg7add0582015-11-20 09:59:34 -0800821 : voe_audio_transport_(voe_audio_transport),
solenberg3a941542015-11-16 07:34:50 -0800822 call_(call),
mflodman3d7db262016-04-29 00:57:13 -0700823 config_(send_transport),
sprangc1b57a12017-02-28 08:50:47 -0800824 send_side_bwe_with_overhead_(
825 webrtc::field_trial::IsEnabled("WebRTC-SendSideBwe-WithOverhead")),
minyue7a973442016-10-20 03:27:12 -0700826 max_send_bitrate_bps_(max_send_bitrate_bps),
skvlade0d46372016-04-07 22:59:22 -0700827 rtp_parameters_(CreateRtpParametersWithOneEncoding()) {
solenberg85a04962015-10-27 03:35:21 -0700828 RTC_DCHECK_GE(ch, 0);
829 // TODO(solenberg): Once we're not using FakeWebRtcVoiceEngine anymore:
830 // RTC_DCHECK(voe_audio_transport);
solenbergc96df772015-10-21 13:01:53 -0700831 RTC_DCHECK(call);
ossu20a4b3f2017-04-27 02:08:52 -0700832 RTC_DCHECK(encoder_factory);
solenberg3a941542015-11-16 07:34:50 -0800833 config_.rtp.ssrc = ssrc;
834 config_.rtp.c_name = c_name;
835 config_.voe_channel_id = ch;
solenberg971cab02016-06-14 10:02:41 -0700836 config_.rtp.extensions = extensions;
minyue6b825df2016-10-31 04:08:32 -0700837 config_.audio_network_adaptor_config = audio_network_adaptor_config;
ossu20a4b3f2017-04-27 02:08:52 -0700838 config_.encoder_factory = encoder_factory;
Alex Narestb3944f02017-10-13 14:56:18 +0200839 config_.track_id = track_id;
deadbeefcb443432016-12-12 11:12:36 -0800840 rtp_parameters_.encodings[0].ssrc = rtc::Optional<uint32_t>(ssrc);
ossu20a4b3f2017-04-27 02:08:52 -0700841
842 if (send_codec_spec) {
843 UpdateSendCodecSpec(*send_codec_spec);
844 }
845
846 stream_ = call_->CreateAudioSendStream(config_);
solenbergc96df772015-10-21 13:01:53 -0700847 }
solenberg3a941542015-11-16 07:34:50 -0800848
solenbergc96df772015-10-21 13:01:53 -0700849 ~WebRtcAudioSendStream() override {
solenberg566ef242015-11-06 15:34:49 -0800850 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -0800851 ClearSource();
solenbergc96df772015-10-21 13:01:53 -0700852 call_->DestroyAudioSendStream(stream_);
853 }
henrike@webrtc.org1e09a712013-07-26 19:17:59 +0000854
ossu20a4b3f2017-04-27 02:08:52 -0700855 void SetSendCodecSpec(
minyue7a973442016-10-20 03:27:12 -0700856 const webrtc::AudioSendStream::Config::SendCodecSpec& send_codec_spec) {
ossu20a4b3f2017-04-27 02:08:52 -0700857 UpdateSendCodecSpec(send_codec_spec);
858 ReconfigureAudioSendStream();
solenberg971cab02016-06-14 10:02:41 -0700859 }
860
ossu20a4b3f2017-04-27 02:08:52 -0700861 void SetRtpExtensions(const std::vector<webrtc::RtpExtension>& extensions) {
solenberg3a941542015-11-16 07:34:50 -0800862 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenberg3a941542015-11-16 07:34:50 -0800863 config_.rtp.extensions = extensions;
ossu20a4b3f2017-04-27 02:08:52 -0700864 ReconfigureAudioSendStream();
solenberg3a941542015-11-16 07:34:50 -0800865 }
866
ossu20a4b3f2017-04-27 02:08:52 -0700867 void SetAudioNetworkAdaptorConfig(
minyue6b825df2016-10-31 04:08:32 -0700868 const rtc::Optional<std::string>& audio_network_adaptor_config) {
869 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
870 if (config_.audio_network_adaptor_config == audio_network_adaptor_config) {
871 return;
872 }
873 config_.audio_network_adaptor_config = audio_network_adaptor_config;
ossu20a4b3f2017-04-27 02:08:52 -0700874 UpdateAllowedBitrateRange();
875 ReconfigureAudioSendStream();
minyue6b825df2016-10-31 04:08:32 -0700876 }
877
minyue7a973442016-10-20 03:27:12 -0700878 bool SetMaxSendBitrate(int bps) {
879 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
ossu20a4b3f2017-04-27 02:08:52 -0700880 RTC_DCHECK(config_.send_codec_spec);
881 RTC_DCHECK(audio_codec_spec_);
882 auto send_rate = ComputeSendBitrate(
883 bps, rtp_parameters_.encodings[0].max_bitrate_bps, *audio_codec_spec_);
884
minyue7a973442016-10-20 03:27:12 -0700885 if (!send_rate) {
886 return false;
887 }
888
889 max_send_bitrate_bps_ = bps;
890
ossu20a4b3f2017-04-27 02:08:52 -0700891 if (send_rate != config_.send_codec_spec->target_bitrate_bps) {
892 config_.send_codec_spec->target_bitrate_bps = send_rate;
893 ReconfigureAudioSendStream();
minyue7a973442016-10-20 03:27:12 -0700894 }
895 return true;
896 }
897
solenbergffbbcac2016-11-17 05:25:37 -0800898 bool SendTelephoneEvent(int payload_type, int payload_freq, int event,
899 int duration_ms) {
Fredrik Solenbergb5727682015-12-04 15:22:19 +0100900 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
901 RTC_DCHECK(stream_);
solenbergffbbcac2016-11-17 05:25:37 -0800902 return stream_->SendTelephoneEvent(payload_type, payload_freq, event,
903 duration_ms);
Fredrik Solenbergb5727682015-12-04 15:22:19 +0100904 }
905
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -0800906 void SetSend(bool send) {
907 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
908 send_ = send;
909 UpdateSendState();
910 }
911
solenberg94218532016-06-16 10:53:22 -0700912 void SetMuted(bool muted) {
913 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
914 RTC_DCHECK(stream_);
915 stream_->SetMuted(muted);
916 muted_ = muted;
917 }
918
919 bool muted() const {
920 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
921 return muted_;
922 }
923
solenberg3a941542015-11-16 07:34:50 -0800924 webrtc::AudioSendStream::Stats GetStats() const {
925 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
926 RTC_DCHECK(stream_);
927 return stream_->GetStats();
928 }
929
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -0800930 // Starts the sending by setting ourselves as a sink to the AudioSource to
931 // get data callbacks.
henrike@webrtc.orga7b98182014-02-21 15:51:43 +0000932 // This method is called on the libjingle worker thread.
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +0000933 // TODO(xians): Make sure Start() is called only once.
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -0800934 void SetSource(AudioSource* source) {
solenberg566ef242015-11-06 15:34:49 -0800935 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -0800936 RTC_DCHECK(source);
937 if (source_) {
938 RTC_DCHECK(source_ == source);
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +0000939 return;
940 }
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -0800941 source->SetSink(this);
942 source_ = source;
943 UpdateSendState();
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +0000944 }
945
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -0800946 // Stops sending by setting the sink of the AudioSource to nullptr. No data
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +0000947 // callback will be received after this method.
henrike@webrtc.orga7b98182014-02-21 15:51:43 +0000948 // This method is called on the libjingle worker thread.
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -0800949 void ClearSource() {
solenberg566ef242015-11-06 15:34:49 -0800950 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -0800951 if (source_) {
952 source_->SetSink(nullptr);
953 source_ = nullptr;
solenberg98c68862015-10-09 03:27:14 -0700954 }
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -0800955 UpdateSendState();
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +0000956 }
957
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -0800958 // AudioSource::Sink implementation.
henrike@webrtc.orga7b98182014-02-21 15:51:43 +0000959 // This method is called on the audio thread.
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +0000960 void OnData(const void* audio_data,
961 int bits_per_sample,
962 int sample_rate,
Peter Kasting69558702016-01-12 16:26:35 -0800963 size_t number_of_channels,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700964 size_t number_of_frames) override {
solenberg347ec5c2016-09-23 04:21:47 -0700965 RTC_CHECK_RUNS_SERIALIZED(&audio_capture_race_checker_);
solenbergc96df772015-10-21 13:01:53 -0700966 RTC_DCHECK(voe_audio_transport_);
maxmorin1aee0b52016-08-15 11:46:19 -0700967 voe_audio_transport_->PushCaptureData(config_.voe_channel_id, audio_data,
968 bits_per_sample, sample_rate,
969 number_of_channels, number_of_frames);
henrike@webrtc.orga7b98182014-02-21 15:51:43 +0000970 }
971
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -0800972 // Callback from the |source_| when it is going away. In case Start() has
henrike@webrtc.orga7b98182014-02-21 15:51:43 +0000973 // never been called, this callback won't be triggered.
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +0000974 void OnClose() override {
solenberg566ef242015-11-06 15:34:49 -0800975 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -0800976 // Set |source_| to nullptr to make sure no more callback will get into
977 // the source.
978 source_ = nullptr;
979 UpdateSendState();
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +0000980 }
981
982 // Accessor to the VoE channel ID.
solenberg85a04962015-10-27 03:35:21 -0700983 int channel() const {
solenberg566ef242015-11-06 15:34:49 -0800984 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenberg7add0582015-11-20 09:59:34 -0800985 return config_.voe_channel_id;
solenberg85a04962015-10-27 03:35:21 -0700986 }
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +0000987
skvlade0d46372016-04-07 22:59:22 -0700988 const webrtc::RtpParameters& rtp_parameters() const {
989 return rtp_parameters_;
990 }
991
deadbeeffb2aced2017-01-06 23:05:37 -0800992 bool ValidateRtpParameters(const webrtc::RtpParameters& rtp_parameters) {
993 if (rtp_parameters.encodings.size() != 1) {
994 LOG(LS_ERROR)
995 << "Attempted to set RtpParameters without exactly one encoding";
996 return false;
997 }
998 if (rtp_parameters.encodings[0].ssrc != rtp_parameters_.encodings[0].ssrc) {
999 LOG(LS_ERROR) << "Attempted to set RtpParameters with modified SSRC";
1000 return false;
1001 }
1002 return true;
1003 }
1004
minyue7a973442016-10-20 03:27:12 -07001005 bool SetRtpParameters(const webrtc::RtpParameters& parameters) {
deadbeeffb2aced2017-01-06 23:05:37 -08001006 if (!ValidateRtpParameters(parameters)) {
1007 return false;
1008 }
ossu20a4b3f2017-04-27 02:08:52 -07001009
1010 rtc::Optional<int> send_rate;
1011 if (audio_codec_spec_) {
1012 send_rate = ComputeSendBitrate(max_send_bitrate_bps_,
1013 parameters.encodings[0].max_bitrate_bps,
1014 *audio_codec_spec_);
1015 if (!send_rate) {
1016 return false;
1017 }
minyue7a973442016-10-20 03:27:12 -07001018 }
1019
minyuececec102017-03-27 13:04:25 -07001020 const rtc::Optional<int> old_rtp_max_bitrate =
1021 rtp_parameters_.encodings[0].max_bitrate_bps;
1022
skvlade0d46372016-04-07 22:59:22 -07001023 rtp_parameters_ = parameters;
minyue7a973442016-10-20 03:27:12 -07001024
minyuececec102017-03-27 13:04:25 -07001025 if (rtp_parameters_.encodings[0].max_bitrate_bps != old_rtp_max_bitrate) {
ossu20a4b3f2017-04-27 02:08:52 -07001026 // Reconfigure AudioSendStream with new bit rate.
1027 if (send_rate) {
1028 config_.send_codec_spec->target_bitrate_bps = send_rate;
1029 }
1030 UpdateAllowedBitrateRange();
1031 ReconfigureAudioSendStream();
minyue7a973442016-10-20 03:27:12 -07001032 } else {
1033 // parameters.encodings[0].active could have changed.
1034 UpdateSendState();
1035 }
1036 return true;
skvlade0d46372016-04-07 22:59:22 -07001037 }
1038
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +00001039 private:
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -08001040 void UpdateSendState() {
1041 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
1042 RTC_DCHECK(stream_);
Taylor Brandstetter55dd7082016-05-03 13:50:11 -07001043 RTC_DCHECK_EQ(1UL, rtp_parameters_.encodings.size());
1044 if (send_ && source_ != nullptr && rtp_parameters_.encodings[0].active) {
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -08001045 stream_->Start();
1046 } else { // !send || source_ = nullptr
1047 stream_->Stop();
1048 }
1049 }
1050
ossu20a4b3f2017-04-27 02:08:52 -07001051 void UpdateAllowedBitrateRange() {
michaelt53fe19d2016-10-18 09:39:22 -07001052 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
ossu20a4b3f2017-04-27 02:08:52 -07001053 const bool is_opus =
1054 config_.send_codec_spec &&
1055 !STR_CASE_CMP(config_.send_codec_spec->format.name.c_str(),
1056 kOpusCodecName);
1057 if (is_opus && webrtc::field_trial::IsEnabled("WebRTC-Audio-SendSideBwe")) {
stefane9f36d52017-01-24 08:18:45 -08001058 config_.min_bitrate_bps = kOpusMinBitrateBps;
minyuececec102017-03-27 13:04:25 -07001059
1060 // This means that when RtpParameters is reset, we may change the
ossu20a4b3f2017-04-27 02:08:52 -07001061 // encoder's bit rate immediately (through ReconfigureAudioSendStream()),
minyuececec102017-03-27 13:04:25 -07001062 // meanwhile change the cap to the output of BWE.
1063 config_.max_bitrate_bps =
1064 rtp_parameters_.encodings[0].max_bitrate_bps
1065 ? *rtp_parameters_.encodings[0].max_bitrate_bps
1066 : kOpusBitrateFbBps;
1067
michaelt53fe19d2016-10-18 09:39:22 -07001068 // TODO(mflodman): Keep testing this and set proper values.
1069 // Note: This is an early experiment currently only supported by Opus.
elad.alon0fe12162017-01-31 05:48:37 -08001070 if (send_side_bwe_with_overhead_) {
ossu20a4b3f2017-04-27 02:08:52 -07001071 const int max_packet_size_ms =
1072 WEBRTC_OPUS_SUPPORT_120MS_PTIME ? 120 : 60;
michaelt6672b262017-01-11 10:17:59 -08001073
ossu20a4b3f2017-04-27 02:08:52 -07001074 // OverheadPerPacket = Ipv4(20B) + UDP(8B) + SRTP(10B) + RTP(12)
1075 constexpr int kOverheadPerPacket = 20 + 8 + 10 + 12;
michaelt6672b262017-01-11 10:17:59 -08001076
ossu20a4b3f2017-04-27 02:08:52 -07001077 int min_overhead_bps =
1078 kOverheadPerPacket * 8 * 1000 / max_packet_size_ms;
michaelt6672b262017-01-11 10:17:59 -08001079
ossu20a4b3f2017-04-27 02:08:52 -07001080 // We assume that |config_.max_bitrate_bps| before the next line is
1081 // a hard limit on the payload bitrate, so we add min_overhead_bps to
1082 // it to ensure that, when overhead is deducted, the payload rate
1083 // never goes beyond the limit.
1084 // Note: this also means that if a higher overhead is forced, we
1085 // cannot reach the limit.
1086 // TODO(minyue): Reconsider this when the signaling to BWE is done
1087 // through a dedicated API.
1088 config_.max_bitrate_bps += min_overhead_bps;
michaelt6672b262017-01-11 10:17:59 -08001089
ossu20a4b3f2017-04-27 02:08:52 -07001090 // In contrast to max_bitrate_bps, we let min_bitrate_bps always be
1091 // reachable.
1092 config_.min_bitrate_bps += min_overhead_bps;
michaelt6672b262017-01-11 10:17:59 -08001093 }
michaelt53fe19d2016-10-18 09:39:22 -07001094 }
ossu20a4b3f2017-04-27 02:08:52 -07001095 }
1096
1097 void UpdateSendCodecSpec(
1098 const webrtc::AudioSendStream::Config::SendCodecSpec& send_codec_spec) {
1099 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
1100 config_.rtp.nack.rtp_history_ms =
1101 send_codec_spec.nack_enabled ? kNackRtpHistoryMs : 0;
1102 config_.send_codec_spec =
1103 rtc::Optional<webrtc::AudioSendStream::Config::SendCodecSpec>(
1104 send_codec_spec);
1105 auto info =
1106 config_.encoder_factory->QueryAudioEncoder(send_codec_spec.format);
1107 RTC_DCHECK(info);
1108 // If a specific target bitrate has been set for the stream, use that as
1109 // the new default bitrate when computing send bitrate.
1110 if (send_codec_spec.target_bitrate_bps) {
1111 info->default_bitrate_bps = std::max(
1112 info->min_bitrate_bps,
1113 std::min(info->max_bitrate_bps, *send_codec_spec.target_bitrate_bps));
1114 }
1115
1116 audio_codec_spec_.emplace(
1117 webrtc::AudioCodecSpec{send_codec_spec.format, *info});
1118
1119 config_.send_codec_spec->target_bitrate_bps = ComputeSendBitrate(
1120 max_send_bitrate_bps_, rtp_parameters_.encodings[0].max_bitrate_bps,
1121 *audio_codec_spec_);
1122
1123 UpdateAllowedBitrateRange();
1124 }
1125
1126 void ReconfigureAudioSendStream() {
1127 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
1128 RTC_DCHECK(stream_);
1129 stream_->Reconfigure(config_);
michaelt53fe19d2016-10-18 09:39:22 -07001130 }
1131
solenberg566ef242015-11-06 15:34:49 -08001132 rtc::ThreadChecker worker_thread_checker_;
solenberg347ec5c2016-09-23 04:21:47 -07001133 rtc::RaceChecker audio_capture_race_checker_;
solenbergc96df772015-10-21 13:01:53 -07001134 webrtc::AudioTransport* const voe_audio_transport_ = nullptr;
1135 webrtc::Call* call_ = nullptr;
solenberg3a941542015-11-16 07:34:50 -08001136 webrtc::AudioSendStream::Config config_;
elad.alon0fe12162017-01-31 05:48:37 -08001137 const bool send_side_bwe_with_overhead_;
solenberg3a941542015-11-16 07:34:50 -08001138 // The stream is owned by WebRtcAudioSendStream and may be reallocated if
1139 // configuration changes.
solenbergc96df772015-10-21 13:01:53 -07001140 webrtc::AudioSendStream* stream_ = nullptr;
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +00001141
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -08001142 // Raw pointer to AudioSource owned by LocalAudioTrackHandler.
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +00001143 // PeerConnection will make sure invalidating the pointer before the object
1144 // goes away.
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -08001145 AudioSource* source_ = nullptr;
1146 bool send_ = false;
solenberg94218532016-06-16 10:53:22 -07001147 bool muted_ = false;
minyue7a973442016-10-20 03:27:12 -07001148 int max_send_bitrate_bps_;
skvlade0d46372016-04-07 22:59:22 -07001149 webrtc::RtpParameters rtp_parameters_;
ossu20a4b3f2017-04-27 02:08:52 -07001150 rtc::Optional<webrtc::AudioCodecSpec> audio_codec_spec_;
henrike@webrtc.orga7b98182014-02-21 15:51:43 +00001151
solenbergc96df772015-10-21 13:01:53 -07001152 RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(WebRtcAudioSendStream);
1153};
1154
1155class WebRtcVoiceMediaChannel::WebRtcAudioReceiveStream {
1156 public:
ossu29b1a8d2016-06-13 07:34:51 -07001157 WebRtcAudioReceiveStream(
1158 int ch,
1159 uint32_t remote_ssrc,
1160 uint32_t local_ssrc,
1161 bool use_transport_cc,
solenberg8189b022016-06-14 12:13:00 -07001162 bool use_nack,
ossu29b1a8d2016-06-13 07:34:51 -07001163 const std::string& sync_group,
1164 const std::vector<webrtc::RtpExtension>& extensions,
1165 webrtc::Call* call,
1166 webrtc::Transport* rtcp_send_transport,
kwiberg1c07c702017-03-27 07:15:49 -07001167 const rtc::scoped_refptr<webrtc::AudioDecoderFactory>& decoder_factory,
1168 const std::map<int, webrtc::SdpAudioFormat>& decoder_map)
stefanba4c0e42016-02-04 04:12:24 -08001169 : call_(call), config_() {
solenberg7add0582015-11-20 09:59:34 -08001170 RTC_DCHECK_GE(ch, 0);
1171 RTC_DCHECK(call);
1172 config_.rtp.remote_ssrc = remote_ssrc;
kwibergd32bf752017-01-19 07:03:59 -08001173 config_.rtp.local_ssrc = local_ssrc;
1174 config_.rtp.transport_cc = use_transport_cc;
1175 config_.rtp.nack.rtp_history_ms = use_nack ? kNackRtpHistoryMs : 0;
1176 config_.rtp.extensions = extensions;
solenberg31fec402016-05-06 02:13:12 -07001177 config_.rtcp_send_transport = rtcp_send_transport;
solenberg7add0582015-11-20 09:59:34 -08001178 config_.voe_channel_id = ch;
1179 config_.sync_group = sync_group;
ossu29b1a8d2016-06-13 07:34:51 -07001180 config_.decoder_factory = decoder_factory;
kwiberg1c07c702017-03-27 07:15:49 -07001181 config_.decoder_map = decoder_map;
kwibergd32bf752017-01-19 07:03:59 -08001182 RecreateAudioReceiveStream();
solenberg7add0582015-11-20 09:59:34 -08001183 }
solenbergc96df772015-10-21 13:01:53 -07001184
solenberg7add0582015-11-20 09:59:34 -08001185 ~WebRtcAudioReceiveStream() {
1186 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
1187 call_->DestroyAudioReceiveStream(stream_);
1188 }
1189
solenberg4a0f7b52016-06-16 13:07:33 -07001190 void RecreateAudioReceiveStream(uint32_t local_ssrc) {
solenberg7add0582015-11-20 09:59:34 -08001191 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
kwibergd32bf752017-01-19 07:03:59 -08001192 config_.rtp.local_ssrc = local_ssrc;
1193 RecreateAudioReceiveStream();
solenberg7add0582015-11-20 09:59:34 -08001194 }
solenberg8189b022016-06-14 12:13:00 -07001195
1196 void RecreateAudioReceiveStream(bool use_transport_cc, bool use_nack) {
solenberg7add0582015-11-20 09:59:34 -08001197 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
kwibergd32bf752017-01-19 07:03:59 -08001198 config_.rtp.transport_cc = use_transport_cc;
1199 config_.rtp.nack.rtp_history_ms = use_nack ? kNackRtpHistoryMs : 0;
1200 RecreateAudioReceiveStream();
solenberg7add0582015-11-20 09:59:34 -08001201 }
1202
solenberg4a0f7b52016-06-16 13:07:33 -07001203 void RecreateAudioReceiveStream(
1204 const std::vector<webrtc::RtpExtension>& extensions) {
1205 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
kwibergd32bf752017-01-19 07:03:59 -08001206 config_.rtp.extensions = extensions;
1207 RecreateAudioReceiveStream();
1208 }
1209
deadbeefcb383672017-04-26 16:28:42 -07001210 // Set a new payload type -> decoder map.
kwibergd32bf752017-01-19 07:03:59 -08001211 void RecreateAudioReceiveStream(
1212 const std::map<int, webrtc::SdpAudioFormat>& decoder_map) {
1213 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
kwibergd32bf752017-01-19 07:03:59 -08001214 config_.decoder_map = decoder_map;
1215 RecreateAudioReceiveStream();
solenberg4a0f7b52016-06-16 13:07:33 -07001216 }
1217
solenberg4904fb62017-02-17 12:01:14 -08001218 void MaybeRecreateAudioReceiveStream(const std::string& sync_group) {
1219 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
1220 if (config_.sync_group != sync_group) {
1221 config_.sync_group = sync_group;
1222 RecreateAudioReceiveStream();
1223 }
1224 }
1225
solenberg7add0582015-11-20 09:59:34 -08001226 webrtc::AudioReceiveStream::Stats GetStats() const {
1227 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
1228 RTC_DCHECK(stream_);
1229 return stream_->GetStats();
1230 }
1231
solenberg796b8f92017-03-01 17:02:23 -08001232 int GetOutputLevel() const {
1233 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
1234 RTC_DCHECK(stream_);
1235 return stream_->GetOutputLevel();
1236 }
1237
solenberg7add0582015-11-20 09:59:34 -08001238 int channel() const {
1239 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
1240 return config_.voe_channel_id;
1241 }
solenbergc96df772015-10-21 13:01:53 -07001242
kwiberg686a8ef2016-02-26 03:00:35 -08001243 void SetRawAudioSink(std::unique_ptr<webrtc::AudioSinkInterface> sink) {
Tommif888bb52015-12-12 01:37:01 +01001244 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
kwiberg686a8ef2016-02-26 03:00:35 -08001245 stream_->SetSink(std::move(sink));
Tommif888bb52015-12-12 01:37:01 +01001246 }
1247
solenberg217fb662016-06-17 08:30:54 -07001248 void SetOutputVolume(double volume) {
1249 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
1250 stream_->SetGain(volume);
1251 }
1252
aleloi84ef6152016-08-04 05:28:21 -07001253 void SetPlayout(bool playout) {
1254 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
1255 RTC_DCHECK(stream_);
1256 if (playout) {
1257 LOG(LS_INFO) << "Starting playout for channel #" << channel();
1258 stream_->Start();
1259 } else {
1260 LOG(LS_INFO) << "Stopping playout for channel #" << channel();
1261 stream_->Stop();
1262 }
aleloi18e0b672016-10-04 02:45:47 -07001263 playout_ = playout;
aleloi84ef6152016-08-04 05:28:21 -07001264 }
1265
hbos8d609f62017-04-10 07:39:05 -07001266 std::vector<webrtc::RtpSource> GetSources() {
1267 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
1268 RTC_DCHECK(stream_);
1269 return stream_->GetSources();
1270 }
1271
solenbergc96df772015-10-21 13:01:53 -07001272 private:
kwibergd32bf752017-01-19 07:03:59 -08001273 void RecreateAudioReceiveStream() {
solenberg7add0582015-11-20 09:59:34 -08001274 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
1275 if (stream_) {
1276 call_->DestroyAudioReceiveStream(stream_);
solenberg7add0582015-11-20 09:59:34 -08001277 }
solenberg7add0582015-11-20 09:59:34 -08001278 stream_ = call_->CreateAudioReceiveStream(config_);
1279 RTC_CHECK(stream_);
aleloi18e0b672016-10-04 02:45:47 -07001280 SetPlayout(playout_);
solenberg7add0582015-11-20 09:59:34 -08001281 }
1282
1283 rtc::ThreadChecker worker_thread_checker_;
1284 webrtc::Call* call_ = nullptr;
1285 webrtc::AudioReceiveStream::Config config_;
1286 // The stream is owned by WebRtcAudioReceiveStream and may be reallocated if
1287 // configuration changes.
1288 webrtc::AudioReceiveStream* stream_ = nullptr;
aleloi18e0b672016-10-04 02:45:47 -07001289 bool playout_ = false;
solenbergc96df772015-10-21 13:01:53 -07001290
1291 RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(WebRtcAudioReceiveStream);
henrike@webrtc.org1e09a712013-07-26 19:17:59 +00001292};
1293
Fredrik Solenberg709ed672015-09-15 12:26:33 +02001294WebRtcVoiceMediaChannel::WebRtcVoiceMediaChannel(WebRtcVoiceEngine* engine,
nisse51542be2016-02-12 02:27:06 -08001295 const MediaConfig& config,
Fredrik Solenbergb071a192015-09-17 16:42:56 +02001296 const AudioOptions& options,
Fredrik Solenberg709ed672015-09-15 12:26:33 +02001297 webrtc::Call* call)
nisse51542be2016-02-12 02:27:06 -08001298 : VoiceMediaChannel(config), engine_(engine), call_(call) {
solenberg0a617e22015-10-20 15:49:38 -07001299 LOG(LS_VERBOSE) << "WebRtcVoiceMediaChannel::WebRtcVoiceMediaChannel";
solenberg566ef242015-11-06 15:34:49 -08001300 RTC_DCHECK(call);
solenberg0a617e22015-10-20 15:49:38 -07001301 engine->RegisterChannel(this);
Fredrik Solenbergb071a192015-09-17 16:42:56 +02001302 SetOptions(options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001303}
1304
1305WebRtcVoiceMediaChannel::~WebRtcVoiceMediaChannel() {
solenberg566ef242015-11-06 15:34:49 -08001306 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenberg0a617e22015-10-20 15:49:38 -07001307 LOG(LS_VERBOSE) << "WebRtcVoiceMediaChannel::~WebRtcVoiceMediaChannel";
solenberg7add0582015-11-20 09:59:34 -08001308 // TODO(solenberg): Should be able to delete the streams directly, without
1309 // going through RemoveNnStream(), once stream objects handle
1310 // all (de)configuration.
solenbergc96df772015-10-21 13:01:53 -07001311 while (!send_streams_.empty()) {
1312 RemoveSendStream(send_streams_.begin()->first);
solenbergd97ec302015-10-07 01:40:33 -07001313 }
solenberg7add0582015-11-20 09:59:34 -08001314 while (!recv_streams_.empty()) {
1315 RemoveRecvStream(recv_streams_.begin()->first);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001316 }
solenberg0a617e22015-10-20 15:49:38 -07001317 engine()->UnregisterChannel(this);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001318}
1319
nisse51542be2016-02-12 02:27:06 -08001320rtc::DiffServCodePoint WebRtcVoiceMediaChannel::PreferredDscp() const {
1321 return kAudioDscpValue;
1322}
1323
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001324bool WebRtcVoiceMediaChannel::SetSendParameters(
1325 const AudioSendParameters& params) {
Peter Boströmca8b4042016-03-08 14:24:13 -08001326 TRACE_EVENT0("webrtc", "WebRtcVoiceMediaChannel::SetSendParameters");
solenberg566ef242015-11-06 15:34:49 -08001327 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenberg7e4e01a2015-12-02 08:05:01 -08001328 LOG(LS_INFO) << "WebRtcVoiceMediaChannel::SetSendParameters: "
1329 << params.ToString();
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001330 // TODO(pthatcher): Refactor this to be more clean now that we have
1331 // all the information at once.
solenberg3a941542015-11-16 07:34:50 -08001332
1333 if (!SetSendCodecs(params.codecs)) {
1334 return false;
1335 }
1336
solenberg7e4e01a2015-12-02 08:05:01 -08001337 if (!ValidateRtpExtensions(params.extensions)) {
1338 return false;
1339 }
1340 std::vector<webrtc::RtpExtension> filtered_extensions =
1341 FilterRtpExtensions(params.extensions,
1342 webrtc::RtpExtension::IsSupportedForAudio, true);
1343 if (send_rtp_extensions_ != filtered_extensions) {
1344 send_rtp_extensions_.swap(filtered_extensions);
solenberg3a941542015-11-16 07:34:50 -08001345 for (auto& it : send_streams_) {
ossu20a4b3f2017-04-27 02:08:52 -07001346 it.second->SetRtpExtensions(send_rtp_extensions_);
solenberg3a941542015-11-16 07:34:50 -08001347 }
1348 }
1349
deadbeef80346142016-04-27 14:17:10 -07001350 if (!SetMaxSendBitrate(params.max_bandwidth_bps)) {
solenberg3a941542015-11-16 07:34:50 -08001351 return false;
1352 }
1353 return SetOptions(params.options);
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001354}
1355
1356bool WebRtcVoiceMediaChannel::SetRecvParameters(
1357 const AudioRecvParameters& params) {
Peter Boströmca8b4042016-03-08 14:24:13 -08001358 TRACE_EVENT0("webrtc", "WebRtcVoiceMediaChannel::SetRecvParameters");
solenberg566ef242015-11-06 15:34:49 -08001359 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenberg7e4e01a2015-12-02 08:05:01 -08001360 LOG(LS_INFO) << "WebRtcVoiceMediaChannel::SetRecvParameters: "
1361 << params.ToString();
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001362 // TODO(pthatcher): Refactor this to be more clean now that we have
1363 // all the information at once.
solenberg7add0582015-11-20 09:59:34 -08001364
1365 if (!SetRecvCodecs(params.codecs)) {
1366 return false;
1367 }
1368
solenberg7e4e01a2015-12-02 08:05:01 -08001369 if (!ValidateRtpExtensions(params.extensions)) {
1370 return false;
1371 }
1372 std::vector<webrtc::RtpExtension> filtered_extensions =
1373 FilterRtpExtensions(params.extensions,
1374 webrtc::RtpExtension::IsSupportedForAudio, false);
1375 if (recv_rtp_extensions_ != filtered_extensions) {
1376 recv_rtp_extensions_.swap(filtered_extensions);
solenberg7add0582015-11-20 09:59:34 -08001377 for (auto& it : recv_streams_) {
1378 it.second->RecreateAudioReceiveStream(recv_rtp_extensions_);
1379 }
1380 }
solenberg7add0582015-11-20 09:59:34 -08001381 return true;
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001382}
1383
Taylor Brandstetterdb0cd9e2016-05-16 11:40:30 -07001384webrtc::RtpParameters WebRtcVoiceMediaChannel::GetRtpSendParameters(
skvlade0d46372016-04-07 22:59:22 -07001385 uint32_t ssrc) const {
1386 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
1387 auto it = send_streams_.find(ssrc);
1388 if (it == send_streams_.end()) {
Taylor Brandstetterdb0cd9e2016-05-16 11:40:30 -07001389 LOG(LS_WARNING) << "Attempting to get RTP send parameters for stream "
1390 << "with ssrc " << ssrc << " which doesn't exist.";
skvlade0d46372016-04-07 22:59:22 -07001391 return webrtc::RtpParameters();
1392 }
1393
Taylor Brandstetter0cd086b2016-04-20 16:23:10 -07001394 webrtc::RtpParameters rtp_params = it->second->rtp_parameters();
1395 // Need to add the common list of codecs to the send stream-specific
1396 // RTP parameters.
1397 for (const AudioCodec& codec : send_codecs_) {
1398 rtp_params.codecs.push_back(codec.ToCodecParameters());
1399 }
1400 return rtp_params;
skvlade0d46372016-04-07 22:59:22 -07001401}
1402
Taylor Brandstetterdb0cd9e2016-05-16 11:40:30 -07001403bool WebRtcVoiceMediaChannel::SetRtpSendParameters(
skvlade0d46372016-04-07 22:59:22 -07001404 uint32_t ssrc,
1405 const webrtc::RtpParameters& parameters) {
1406 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
skvlade0d46372016-04-07 22:59:22 -07001407 auto it = send_streams_.find(ssrc);
1408 if (it == send_streams_.end()) {
Taylor Brandstetterdb0cd9e2016-05-16 11:40:30 -07001409 LOG(LS_WARNING) << "Attempting to set RTP send parameters for stream "
1410 << "with ssrc " << ssrc << " which doesn't exist.";
skvlade0d46372016-04-07 22:59:22 -07001411 return false;
1412 }
1413
Taylor Brandstetterdb0cd9e2016-05-16 11:40:30 -07001414 // TODO(deadbeef): Handle setting parameters with a list of codecs in a
1415 // different order (which should change the send codec).
1416 webrtc::RtpParameters current_parameters = GetRtpSendParameters(ssrc);
1417 if (current_parameters.codecs != parameters.codecs) {
1418 LOG(LS_ERROR) << "Using SetParameters to change the set of codecs "
1419 << "is not currently supported.";
1420 return false;
1421 }
1422
minyue7a973442016-10-20 03:27:12 -07001423 // TODO(minyue): The following legacy actions go into
1424 // |WebRtcAudioSendStream::SetRtpParameters()| which is called at the end,
1425 // though there are two difference:
1426 // 1. |WebRtcVoiceMediaChannel::SetChannelSendParameters()| only calls
1427 // |SetSendCodec| while |WebRtcAudioSendStream::SetRtpParameters()| calls
1428 // |SetSendCodecs|. The outcome should be the same.
1429 // 2. AudioSendStream can be recreated.
1430
Taylor Brandstetter0cd086b2016-04-20 16:23:10 -07001431 // Codecs are handled at the WebRtcVoiceMediaChannel level.
1432 webrtc::RtpParameters reduced_params = parameters;
1433 reduced_params.codecs.clear();
minyue7a973442016-10-20 03:27:12 -07001434 return it->second->SetRtpParameters(reduced_params);
skvlade0d46372016-04-07 22:59:22 -07001435}
1436
Taylor Brandstetterdb0cd9e2016-05-16 11:40:30 -07001437webrtc::RtpParameters WebRtcVoiceMediaChannel::GetRtpReceiveParameters(
1438 uint32_t ssrc) const {
1439 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
deadbeef3bc15102017-04-20 19:25:07 -07001440 webrtc::RtpParameters rtp_params;
1441 // SSRC of 0 represents the default receive stream.
1442 if (ssrc == 0) {
1443 if (!default_sink_) {
1444 LOG(LS_WARNING) << "Attempting to get RTP parameters for the default, "
1445 "unsignaled audio receive stream, but not yet "
1446 "configured to receive such a stream.";
1447 return rtp_params;
1448 }
1449 rtp_params.encodings.emplace_back();
1450 } else {
1451 auto it = recv_streams_.find(ssrc);
1452 if (it == recv_streams_.end()) {
1453 LOG(LS_WARNING) << "Attempting to get RTP receive parameters for stream "
1454 << "with ssrc " << ssrc << " which doesn't exist.";
1455 return webrtc::RtpParameters();
1456 }
1457 rtp_params.encodings.emplace_back();
1458 // TODO(deadbeef): Return stream-specific parameters.
1459 rtp_params.encodings[0].ssrc = rtc::Optional<uint32_t>(ssrc);
Taylor Brandstetterdb0cd9e2016-05-16 11:40:30 -07001460 }
1461
Taylor Brandstetterdb0cd9e2016-05-16 11:40:30 -07001462 for (const AudioCodec& codec : recv_codecs_) {
1463 rtp_params.codecs.push_back(codec.ToCodecParameters());
1464 }
1465 return rtp_params;
1466}
1467
1468bool WebRtcVoiceMediaChannel::SetRtpReceiveParameters(
1469 uint32_t ssrc,
1470 const webrtc::RtpParameters& parameters) {
1471 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
deadbeef3bc15102017-04-20 19:25:07 -07001472 // SSRC of 0 represents the default receive stream.
1473 if (ssrc == 0) {
1474 if (!default_sink_) {
1475 LOG(LS_WARNING) << "Attempting to set RTP parameters for the default, "
1476 "unsignaled audio receive stream, but not yet "
1477 "configured to receive such a stream.";
1478 return false;
1479 }
1480 } else {
1481 auto it = recv_streams_.find(ssrc);
1482 if (it == recv_streams_.end()) {
1483 LOG(LS_WARNING) << "Attempting to set RTP receive parameters for stream "
1484 << "with ssrc " << ssrc << " which doesn't exist.";
1485 return false;
1486 }
Taylor Brandstetterdb0cd9e2016-05-16 11:40:30 -07001487 }
1488
1489 webrtc::RtpParameters current_parameters = GetRtpReceiveParameters(ssrc);
1490 if (current_parameters != parameters) {
1491 LOG(LS_ERROR) << "Changing the RTP receive parameters is currently "
1492 << "unsupported.";
1493 return false;
1494 }
1495 return true;
1496}
1497
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001498bool WebRtcVoiceMediaChannel::SetOptions(const AudioOptions& options) {
solenberg566ef242015-11-06 15:34:49 -08001499 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001500 LOG(LS_INFO) << "Setting voice channel options: "
1501 << options.ToString();
1502
1503 // We retain all of the existing options, and apply the given ones
1504 // on top. This means there is no way to "clear" options such that
1505 // they go back to the engine default.
1506 options_.SetAll(options);
solenberg246b8172015-12-08 09:50:23 -08001507 if (!engine()->ApplyOptions(options_)) {
1508 LOG(LS_WARNING) <<
1509 "Failed to apply engine options during channel SetOptions.";
1510 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001511 }
minyue6b825df2016-10-31 04:08:32 -07001512
ossu20a4b3f2017-04-27 02:08:52 -07001513 rtc::Optional<std::string> audio_network_adaptor_config =
minyue6b825df2016-10-31 04:08:32 -07001514 GetAudioNetworkAdaptorConfig(options_);
1515 for (auto& it : send_streams_) {
ossu20a4b3f2017-04-27 02:08:52 -07001516 it.second->SetAudioNetworkAdaptorConfig(audio_network_adaptor_config);
minyue6b825df2016-10-31 04:08:32 -07001517 }
1518
solenberg76377c52017-02-21 00:54:31 -08001519 LOG(LS_INFO) << "Set voice channel options. Current options: "
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001520 << options_.ToString();
1521 return true;
1522}
1523
1524bool WebRtcVoiceMediaChannel::SetRecvCodecs(
1525 const std::vector<AudioCodec>& codecs) {
solenberg566ef242015-11-06 15:34:49 -08001526 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenberg8fb30c32015-10-13 03:06:58 -07001527
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001528 // Set the payload types to be used for incoming media.
solenberg0b675462015-10-09 01:37:09 -07001529 LOG(LS_INFO) << "Setting receive voice codecs.";
solenberg0b675462015-10-09 01:37:09 -07001530
1531 if (!VerifyUniquePayloadTypes(codecs)) {
1532 LOG(LS_ERROR) << "Codec payload types overlap.";
1533 return false;
1534 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001535
kwibergd32bf752017-01-19 07:03:59 -08001536 // Create a payload type -> SdpAudioFormat map with all the decoders. Fail
1537 // unless the factory claims to support all decoders.
1538 std::map<int, webrtc::SdpAudioFormat> decoder_map;
1539 for (const AudioCodec& codec : codecs) {
deadbeefcb383672017-04-26 16:28:42 -07001540 // Log a warning if a codec's payload type is changing. This used to be
1541 // treated as an error. It's abnormal, but not really illegal.
1542 AudioCodec old_codec;
1543 if (FindCodec(recv_codecs_, codec, &old_codec) &&
1544 old_codec.id != codec.id) {
1545 LOG(LS_WARNING) << codec.name << " mapped to a second payload type ("
1546 << codec.id << ", was already mapped to " << old_codec.id
1547 << ")";
1548 }
kwibergd32bf752017-01-19 07:03:59 -08001549 auto format = AudioCodecToSdpAudioFormat(codec);
1550 if (!IsCodec(codec, "cn") && !IsCodec(codec, "telephone-event") &&
1551 !engine()->decoder_factory_->IsSupportedDecoder(format)) {
1552 LOG(LS_ERROR) << "Unsupported codec: " << format;
1553 return false;
1554 }
deadbeefcb383672017-04-26 16:28:42 -07001555 // We allow adding new codecs but don't allow changing the payload type of
1556 // codecs that are already configured since we might already be receiving
1557 // packets with that payload type. See RFC3264, Section 8.3.2.
1558 // TODO(deadbeef): Also need to check for clashes with previously mapped
1559 // payload types, and not just currently mapped ones. For example, this
1560 // should be illegal:
1561 // 1. {100: opus/48000/2, 101: ISAC/16000}
1562 // 2. {100: opus/48000/2}
1563 // 3. {100: opus/48000/2, 101: ISAC/32000}
1564 // Though this check really should happen at a higher level, since this
1565 // conflict could happen between audio and video codecs.
1566 auto existing = decoder_map_.find(codec.id);
1567 if (existing != decoder_map_.end() && !existing->second.Matches(format)) {
1568 LOG(LS_ERROR) << "Attempting to use payload type " << codec.id << " for "
1569 << codec.name << ", but it is already used for "
1570 << existing->second.name;
1571 return false;
1572 }
kwibergd32bf752017-01-19 07:03:59 -08001573 decoder_map.insert({codec.id, std::move(format)});
1574 }
1575
deadbeefcb383672017-04-26 16:28:42 -07001576 if (decoder_map == decoder_map_) {
1577 // There's nothing new to configure.
1578 return true;
1579 }
1580
kwiberg37b8b112016-11-03 02:46:53 -07001581 if (playout_) {
1582 // Receive codecs can not be changed while playing. So we temporarily
1583 // pause playout.
1584 ChangePlayout(false);
1585 }
1586
kwiberg1c07c702017-03-27 07:15:49 -07001587 decoder_map_ = std::move(decoder_map);
kwibergd32bf752017-01-19 07:03:59 -08001588 for (auto& kv : recv_streams_) {
kwiberg1c07c702017-03-27 07:15:49 -07001589 kv.second->RecreateAudioReceiveStream(decoder_map_);
solenberg26c8c912015-11-27 04:00:25 -08001590 }
kwibergd32bf752017-01-19 07:03:59 -08001591 recv_codecs_ = codecs;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001592
kwiberg37b8b112016-11-03 02:46:53 -07001593 if (desired_playout_ && !playout_) {
1594 ChangePlayout(desired_playout_);
1595 }
kwibergd32bf752017-01-19 07:03:59 -08001596 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001597}
1598
solenberg72e29d22016-03-08 06:35:16 -08001599// Utility function called from SetSendParameters() to extract current send
1600// codec settings from the given list of codecs (originally from SDP). Both send
1601// and receive streams may be reconfigured based on the new settings.
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00001602bool WebRtcVoiceMediaChannel::SetSendCodecs(
1603 const std::vector<AudioCodec>& codecs) {
solenberg566ef242015-11-06 15:34:49 -08001604 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
Fredrik Solenbergb5727682015-12-04 15:22:19 +01001605 dtmf_payload_type_ = rtc::Optional<int>();
solenbergffbbcac2016-11-17 05:25:37 -08001606 dtmf_payload_freq_ = -1;
1607
1608 // Validate supplied codecs list.
1609 for (const AudioCodec& codec : codecs) {
1610 // TODO(solenberg): Validate more aspects of input - that payload types
1611 // don't overlap, remove redundant/unsupported codecs etc -
1612 // the same way it is done for RtpHeaderExtensions.
1613 if (codec.id < kMinPayloadType || codec.id > kMaxPayloadType) {
1614 LOG(LS_WARNING) << "Codec payload type out of range: " << ToString(codec);
1615 return false;
1616 }
1617 }
1618
1619 // Find PT of telephone-event codec with lowest clockrate, as a fallback, in
1620 // case we don't have a DTMF codec with a rate matching the send codec's, or
1621 // if this function returns early.
1622 std::vector<AudioCodec> dtmf_codecs;
Fredrik Solenbergaf9fb212015-08-26 10:45:53 +02001623 for (const AudioCodec& codec : codecs) {
Fredrik Solenbergaf9fb212015-08-26 10:45:53 +02001624 if (IsCodec(codec, kDtmfCodecName)) {
solenbergffbbcac2016-11-17 05:25:37 -08001625 dtmf_codecs.push_back(codec);
1626 if (!dtmf_payload_type_ || codec.clockrate < dtmf_payload_freq_) {
1627 dtmf_payload_type_ = rtc::Optional<int>(codec.id);
1628 dtmf_payload_freq_ = codec.clockrate;
solenberg31642aa2016-03-14 08:00:37 -07001629 }
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00001630 }
1631 }
1632
ossu20a4b3f2017-04-27 02:08:52 -07001633 // Scan through the list to figure out the codec to use for sending.
1634 rtc::Optional<webrtc::AudioSendStream::Config::SendCodecSpec> send_codec_spec;
stefan1ccf73f2017-03-27 03:51:18 -07001635 webrtc::Call::Config::BitrateConfig bitrate_config;
ossu20a4b3f2017-04-27 02:08:52 -07001636 rtc::Optional<webrtc::AudioCodecInfo> voice_codec_info;
1637 for (const AudioCodec& voice_codec : codecs) {
1638 if (!(IsCodec(voice_codec, kCnCodecName) ||
1639 IsCodec(voice_codec, kDtmfCodecName) ||
1640 IsCodec(voice_codec, kRedCodecName))) {
1641 webrtc::SdpAudioFormat format(voice_codec.name, voice_codec.clockrate,
1642 voice_codec.channels, voice_codec.params);
solenberg72e29d22016-03-08 06:35:16 -08001643
ossu20a4b3f2017-04-27 02:08:52 -07001644 voice_codec_info = engine()->encoder_factory_->QueryAudioEncoder(format);
1645 if (!voice_codec_info) {
1646 LOG(LS_WARNING) << "Unknown codec " << ToString(voice_codec);
solenberg72e29d22016-03-08 06:35:16 -08001647 continue;
1648 }
1649
ossu20a4b3f2017-04-27 02:08:52 -07001650 send_codec_spec =
1651 rtc::Optional<webrtc::AudioSendStream::Config::SendCodecSpec>(
1652 {voice_codec.id, format});
1653 if (voice_codec.bitrate > 0) {
1654 send_codec_spec->target_bitrate_bps =
1655 rtc::Optional<int>(voice_codec.bitrate);
1656 }
1657 send_codec_spec->transport_cc_enabled = HasTransportCc(voice_codec);
1658 send_codec_spec->nack_enabled = HasNack(voice_codec);
1659 bitrate_config = GetBitrateConfigForCodec(voice_codec);
1660 break;
1661 }
1662 }
1663
1664 if (!send_codec_spec) {
1665 return false;
1666 }
1667
1668 RTC_DCHECK(voice_codec_info);
1669 if (voice_codec_info->allow_comfort_noise) {
1670 // Loop through the codecs list again to find the CN codec.
1671 // TODO(solenberg): Break out into a separate function?
1672 for (const AudioCodec& cn_codec : codecs) {
ossu0c4b8492017-03-02 11:03:25 -08001673 if (IsCodec(cn_codec, kCnCodecName) &&
ossu20a4b3f2017-04-27 02:08:52 -07001674 cn_codec.clockrate == send_codec_spec->format.clockrate_hz) {
ossu0c4b8492017-03-02 11:03:25 -08001675 switch (cn_codec.clockrate) {
solenberg72e29d22016-03-08 06:35:16 -08001676 case 8000:
1677 case 16000:
1678 case 32000:
ossu20a4b3f2017-04-27 02:08:52 -07001679 send_codec_spec->cng_payload_type = rtc::Optional<int>(cn_codec.id);
solenberg72e29d22016-03-08 06:35:16 -08001680 break;
1681 default:
ossu0c4b8492017-03-02 11:03:25 -08001682 LOG(LS_WARNING) << "CN frequency " << cn_codec.clockrate
solenberg72e29d22016-03-08 06:35:16 -08001683 << " not supported.";
ossu20a4b3f2017-04-27 02:08:52 -07001684 break;
solenberg72e29d22016-03-08 06:35:16 -08001685 }
solenberg72e29d22016-03-08 06:35:16 -08001686 break;
1687 }
1688 }
solenbergffbbcac2016-11-17 05:25:37 -08001689
1690 // Find the telephone-event PT exactly matching the preferred send codec.
1691 for (const AudioCodec& dtmf_codec : dtmf_codecs) {
ossu20a4b3f2017-04-27 02:08:52 -07001692 if (dtmf_codec.clockrate == send_codec_spec->format.clockrate_hz) {
solenbergffbbcac2016-11-17 05:25:37 -08001693 dtmf_payload_type_ = rtc::Optional<int>(dtmf_codec.id);
1694 dtmf_payload_freq_ = dtmf_codec.clockrate;
1695 break;
1696 }
1697 }
solenberg72e29d22016-03-08 06:35:16 -08001698 }
1699
solenberg971cab02016-06-14 10:02:41 -07001700 if (send_codec_spec_ != send_codec_spec) {
1701 send_codec_spec_ = std::move(send_codec_spec);
stefan13f1a0a2016-11-30 07:22:58 -08001702 // Apply new settings to all streams.
solenberg971cab02016-06-14 10:02:41 -07001703 for (const auto& kv : send_streams_) {
ossu20a4b3f2017-04-27 02:08:52 -07001704 kv.second->SetSendCodecSpec(*send_codec_spec_);
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00001705 }
stefan13f1a0a2016-11-30 07:22:58 -08001706 } else {
1707 // If the codec isn't changing, set the start bitrate to -1 which means
1708 // "unchanged" so that BWE isn't affected.
stefan1ccf73f2017-03-27 03:51:18 -07001709 bitrate_config.start_bitrate_bps = -1;
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00001710 }
stefan1ccf73f2017-03-27 03:51:18 -07001711 call_->SetBitrateConfig(bitrate_config);
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00001712
solenberg8189b022016-06-14 12:13:00 -07001713 // Check if the transport cc feedback or NACK status has changed on the
1714 // preferred send codec, and in that case reconfigure all receive streams.
ossu20a4b3f2017-04-27 02:08:52 -07001715 if (recv_transport_cc_enabled_ != send_codec_spec_->transport_cc_enabled ||
1716 recv_nack_enabled_ != send_codec_spec_->nack_enabled) {
solenberg72e29d22016-03-08 06:35:16 -08001717 LOG(LS_INFO) << "Recreate all the receive streams because the send "
1718 "codec has changed.";
ossu20a4b3f2017-04-27 02:08:52 -07001719 recv_transport_cc_enabled_ = send_codec_spec_->transport_cc_enabled;
1720 recv_nack_enabled_ = send_codec_spec_->nack_enabled;
solenberg72e29d22016-03-08 06:35:16 -08001721 for (auto& kv : recv_streams_) {
solenberg8189b022016-06-14 12:13:00 -07001722 kv.second->RecreateAudioReceiveStream(recv_transport_cc_enabled_,
1723 recv_nack_enabled_);
solenberg72e29d22016-03-08 06:35:16 -08001724 }
1725 }
1726
Taylor Brandstetter0cd086b2016-04-20 16:23:10 -07001727 send_codecs_ = codecs;
solenberg72e29d22016-03-08 06:35:16 -08001728 return true;
1729}
1730
aleloi84ef6152016-08-04 05:28:21 -07001731void WebRtcVoiceMediaChannel::SetPlayout(bool playout) {
kwiberg37b8b112016-11-03 02:46:53 -07001732 desired_playout_ = playout;
1733 return ChangePlayout(desired_playout_);
1734}
1735
1736void WebRtcVoiceMediaChannel::ChangePlayout(bool playout) {
1737 TRACE_EVENT0("webrtc", "WebRtcVoiceMediaChannel::ChangePlayout");
solenberg566ef242015-11-06 15:34:49 -08001738 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001739 if (playout_ == playout) {
aleloi84ef6152016-08-04 05:28:21 -07001740 return;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001741 }
1742
aleloi84ef6152016-08-04 05:28:21 -07001743 for (const auto& kv : recv_streams_) {
1744 kv.second->SetPlayout(playout);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001745 }
solenberg1ac56142015-10-13 03:58:19 -07001746 playout_ = playout;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001747}
1748
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -08001749void WebRtcVoiceMediaChannel::SetSend(bool send) {
Peter Boströmca8b4042016-03-08 14:24:13 -08001750 TRACE_EVENT0("webrtc", "WebRtcVoiceMediaChannel::SetSend");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001751 if (send_ == send) {
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -08001752 return;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001753 }
1754
solenbergd53a3f92016-04-14 13:56:37 -07001755 // Apply channel specific options, and initialize the ADM for recording (this
1756 // may take time on some platforms, e.g. Android).
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -08001757 if (send) {
solenberg63b34542015-09-29 06:06:31 -07001758 engine()->ApplyOptions(options_);
solenbergd53a3f92016-04-14 13:56:37 -07001759
1760 // InitRecording() may return an error if the ADM is already recording.
1761 if (!engine()->adm()->RecordingIsInitialized() &&
1762 !engine()->adm()->Recording()) {
1763 if (engine()->adm()->InitRecording() != 0) {
1764 LOG(LS_WARNING) << "Failed to initialize recording";
1765 }
1766 }
solenberg63b34542015-09-29 06:06:31 -07001767 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001768
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001769 // Change the settings on each send channel.
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -08001770 for (auto& kv : send_streams_) {
1771 kv.second->SetSend(send);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001772 }
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001773
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001774 send_ = send;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001775}
1776
Peter Boström0c4e06b2015-10-07 12:23:21 +02001777bool WebRtcVoiceMediaChannel::SetAudioSend(uint32_t ssrc,
1778 bool enable,
solenberg1dd98f32015-09-10 01:57:14 -07001779 const AudioOptions* options,
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -08001780 AudioSource* source) {
solenberg566ef242015-11-06 15:34:49 -08001781 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenberg1dd98f32015-09-10 01:57:14 -07001782 // TODO(solenberg): The state change should be fully rolled back if any one of
1783 // these calls fail.
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -08001784 if (!SetLocalSource(ssrc, source)) {
solenberg1dd98f32015-09-10 01:57:14 -07001785 return false;
1786 }
solenbergdfc8f4f2015-10-01 02:31:10 -07001787 if (!MuteStream(ssrc, !enable)) {
solenberg1dd98f32015-09-10 01:57:14 -07001788 return false;
1789 }
solenbergdfc8f4f2015-10-01 02:31:10 -07001790 if (enable && options) {
solenberg1dd98f32015-09-10 01:57:14 -07001791 return SetOptions(*options);
1792 }
1793 return true;
1794}
1795
solenberg0a617e22015-10-20 15:49:38 -07001796int WebRtcVoiceMediaChannel::CreateVoEChannel() {
1797 int id = engine()->CreateVoEChannel();
1798 if (id == -1) {
solenberg35dee812017-09-18 01:57:01 -07001799 LOG(LS_WARNING) << "CreateVoEChannel() failed.";
solenberg0a617e22015-10-20 15:49:38 -07001800 return -1;
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001801 }
mflodman3d7db262016-04-29 00:57:13 -07001802
solenberg0a617e22015-10-20 15:49:38 -07001803 return id;
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001804}
1805
solenberg7add0582015-11-20 09:59:34 -08001806bool WebRtcVoiceMediaChannel::DeleteVoEChannel(int channel) {
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001807 if (engine()->voe()->base()->DeleteChannel(channel) == -1) {
solenberg35dee812017-09-18 01:57:01 -07001808 LOG(LS_WARNING) << "DeleteChannel(" << channel << ") failed.";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001809 return false;
1810 }
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001811 return true;
1812}
henrike@webrtc.org1e09a712013-07-26 19:17:59 +00001813
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001814bool WebRtcVoiceMediaChannel::AddSendStream(const StreamParams& sp) {
Peter Boströmca8b4042016-03-08 14:24:13 -08001815 TRACE_EVENT0("webrtc", "WebRtcVoiceMediaChannel::AddSendStream");
solenberg566ef242015-11-06 15:34:49 -08001816 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenberg0a617e22015-10-20 15:49:38 -07001817 LOG(LS_INFO) << "AddSendStream: " << sp.ToString();
1818
1819 uint32_t ssrc = sp.first_ssrc();
1820 RTC_DCHECK(0 != ssrc);
1821
1822 if (GetSendChannelId(ssrc) != -1) {
1823 LOG(LS_ERROR) << "Stream already exists with ssrc " << ssrc;
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001824 return false;
1825 }
1826
solenberg0a617e22015-10-20 15:49:38 -07001827 // Create a new channel for sending audio data.
1828 int channel = CreateVoEChannel();
1829 if (channel == -1) {
1830 return false;
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001831 }
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001832
solenbergc96df772015-10-21 13:01:53 -07001833 // Save the channel to send_streams_, so that RemoveSendStream() can still
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001834 // delete the channel in case failure happens below.
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +00001835 webrtc::AudioTransport* audio_transport =
1836 engine()->voe()->base()->audio_transport();
mflodman3d7db262016-04-29 00:57:13 -07001837
minyue6b825df2016-10-31 04:08:32 -07001838 rtc::Optional<std::string> audio_network_adaptor_config =
1839 GetAudioNetworkAdaptorConfig(options_);
skvlade0d46372016-04-07 22:59:22 -07001840 WebRtcAudioSendStream* stream = new WebRtcAudioSendStream(
Alex Narestb3944f02017-10-13 14:56:18 +02001841 channel, audio_transport, ssrc, sp.cname, sp.id, send_codec_spec_,
minyue6b825df2016-10-31 04:08:32 -07001842 send_rtp_extensions_, max_send_bitrate_bps_, audio_network_adaptor_config,
ossu20a4b3f2017-04-27 02:08:52 -07001843 call_, this, engine()->encoder_factory_);
skvlade0d46372016-04-07 22:59:22 -07001844 send_streams_.insert(std::make_pair(ssrc, stream));
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001845
solenberg4a0f7b52016-06-16 13:07:33 -07001846 // At this point the stream's local SSRC has been updated. If it is the first
1847 // send stream, make sure that all the receive streams are updated with the
1848 // same SSRC in order to send receiver reports.
solenbergc96df772015-10-21 13:01:53 -07001849 if (send_streams_.size() == 1) {
solenberg0a617e22015-10-20 15:49:38 -07001850 receiver_reports_ssrc_ = ssrc;
solenberg4a0f7b52016-06-16 13:07:33 -07001851 for (const auto& kv : recv_streams_) {
1852 // TODO(solenberg): Allow applications to set the RTCP SSRC of receive
1853 // streams instead, so we can avoid recreating the streams here.
1854 kv.second->RecreateAudioReceiveStream(ssrc);
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001855 }
1856 }
1857
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -08001858 send_streams_[ssrc]->SetSend(send_);
1859 return true;
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001860}
1861
Peter Boström0c4e06b2015-10-07 12:23:21 +02001862bool WebRtcVoiceMediaChannel::RemoveSendStream(uint32_t ssrc) {
Peter Boströmca8b4042016-03-08 14:24:13 -08001863 TRACE_EVENT0("webrtc", "WebRtcVoiceMediaChannel::RemoveSendStream");
solenberg566ef242015-11-06 15:34:49 -08001864 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenberg3a941542015-11-16 07:34:50 -08001865 LOG(LS_INFO) << "RemoveSendStream: " << ssrc;
1866
solenbergc96df772015-10-21 13:01:53 -07001867 auto it = send_streams_.find(ssrc);
1868 if (it == send_streams_.end()) {
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001869 LOG(LS_WARNING) << "Try to remove stream with ssrc " << ssrc
1870 << " which doesn't exist.";
1871 return false;
1872 }
1873
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -08001874 it->second->SetSend(false);
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001875
solenberg7602aab2016-11-14 11:30:07 -08001876 // TODO(solenberg): If we're removing the receiver_reports_ssrc_ stream, find
1877 // the first active send stream and use that instead, reassociating receive
1878 // streams.
1879
solenberg7add0582015-11-20 09:59:34 -08001880 // Clean up and delete the send stream+channel.
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -08001881 int channel = it->second->channel();
solenberg0a617e22015-10-20 15:49:38 -07001882 LOG(LS_INFO) << "Removing audio send stream " << ssrc
1883 << " with VoiceEngine channel #" << channel << ".";
solenberg7add0582015-11-20 09:59:34 -08001884 delete it->second;
1885 send_streams_.erase(it);
1886 if (!DeleteVoEChannel(channel)) {
solenberg0a617e22015-10-20 15:49:38 -07001887 return false;
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001888 }
solenbergc96df772015-10-21 13:01:53 -07001889 if (send_streams_.empty()) {
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -08001890 SetSend(false);
solenberg0a617e22015-10-20 15:49:38 -07001891 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001892 return true;
1893}
1894
1895bool WebRtcVoiceMediaChannel::AddRecvStream(const StreamParams& sp) {
Peter Boströmca8b4042016-03-08 14:24:13 -08001896 TRACE_EVENT0("webrtc", "WebRtcVoiceMediaChannel::AddRecvStream");
solenberg566ef242015-11-06 15:34:49 -08001897 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenbergd97ec302015-10-07 01:40:33 -07001898 LOG(LS_INFO) << "AddRecvStream: " << sp.ToString();
1899
solenberg0b675462015-10-09 01:37:09 -07001900 if (!ValidateStreamParams(sp)) {
wu@webrtc.org78187522013-10-07 23:32:02 +00001901 return false;
1902 }
1903
solenberg7add0582015-11-20 09:59:34 -08001904 const uint32_t ssrc = sp.first_ssrc();
solenberg0b675462015-10-09 01:37:09 -07001905 if (ssrc == 0) {
1906 LOG(LS_WARNING) << "AddRecvStream with ssrc==0 is not supported.";
1907 return false;
1908 }
1909
solenberg2100c0b2017-03-01 11:29:29 -08001910 // If this stream was previously received unsignaled, we promote it, possibly
1911 // recreating the AudioReceiveStream, if sync_label has changed.
1912 if (MaybeDeregisterUnsignaledRecvStream(ssrc)) {
solenberg4904fb62017-02-17 12:01:14 -08001913 recv_streams_[ssrc]->MaybeRecreateAudioReceiveStream(sp.sync_label);
solenberg4904fb62017-02-17 12:01:14 -08001914 return true;
solenberg1ac56142015-10-13 03:58:19 -07001915 }
solenberg0b675462015-10-09 01:37:09 -07001916
solenberg7add0582015-11-20 09:59:34 -08001917 if (GetReceiveChannelId(ssrc) != -1) {
henrike@webrtc.org1e09a712013-07-26 19:17:59 +00001918 LOG(LS_ERROR) << "Stream already exists with ssrc " << ssrc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001919 return false;
1920 }
Fredrik Solenberg4b60c732015-05-07 14:07:48 +02001921
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001922 // Create a new channel for receiving audio data.
solenberg7add0582015-11-20 09:59:34 -08001923 const int channel = CreateVoEChannel();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001924 if (channel == -1) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001925 return false;
1926 }
Minyue2013aec2015-05-13 14:14:42 +02001927
stefanba4c0e42016-02-04 04:12:24 -08001928 recv_streams_.insert(std::make_pair(
kwiberg1c07c702017-03-27 07:15:49 -07001929 ssrc,
1930 new WebRtcAudioReceiveStream(
1931 channel, ssrc, receiver_reports_ssrc_, recv_transport_cc_enabled_,
1932 recv_nack_enabled_, sp.sync_label, recv_rtp_extensions_, call_, this,
1933 engine()->decoder_factory_, decoder_map_)));
aleloi84ef6152016-08-04 05:28:21 -07001934 recv_streams_[ssrc]->SetPlayout(playout_);
solenberg7add0582015-11-20 09:59:34 -08001935
solenberg1ac56142015-10-13 03:58:19 -07001936 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001937}
1938
Peter Boström0c4e06b2015-10-07 12:23:21 +02001939bool WebRtcVoiceMediaChannel::RemoveRecvStream(uint32_t ssrc) {
Peter Boströmca8b4042016-03-08 14:24:13 -08001940 TRACE_EVENT0("webrtc", "WebRtcVoiceMediaChannel::RemoveRecvStream");
solenberg566ef242015-11-06 15:34:49 -08001941 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenbergd97ec302015-10-07 01:40:33 -07001942 LOG(LS_INFO) << "RemoveRecvStream: " << ssrc;
1943
solenberg7add0582015-11-20 09:59:34 -08001944 const auto it = recv_streams_.find(ssrc);
1945 if (it == recv_streams_.end()) {
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001946 LOG(LS_WARNING) << "Try to remove stream with ssrc " << ssrc
1947 << " which doesn't exist.";
henrike@webrtc.org1e09a712013-07-26 19:17:59 +00001948 return false;
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001949 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001950
solenberg2100c0b2017-03-01 11:29:29 -08001951 MaybeDeregisterUnsignaledRecvStream(ssrc);
henrike@webrtc.org1e09a712013-07-26 19:17:59 +00001952
solenberg7add0582015-11-20 09:59:34 -08001953 const int channel = it->second->channel();
1954
1955 // Clean up and delete the receive stream+channel.
1956 LOG(LS_INFO) << "Removing audio receive stream " << ssrc
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +00001957 << " with VoiceEngine channel #" << channel << ".";
Tommif888bb52015-12-12 01:37:01 +01001958 it->second->SetRawAudioSink(nullptr);
solenberg7add0582015-11-20 09:59:34 -08001959 delete it->second;
1960 recv_streams_.erase(it);
1961 return DeleteVoEChannel(channel);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001962}
1963
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -08001964bool WebRtcVoiceMediaChannel::SetLocalSource(uint32_t ssrc,
1965 AudioSource* source) {
solenbergc96df772015-10-21 13:01:53 -07001966 auto it = send_streams_.find(ssrc);
1967 if (it == send_streams_.end()) {
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -08001968 if (source) {
1969 // Return an error if trying to set a valid source with an invalid ssrc.
1970 LOG(LS_ERROR) << "SetLocalSource failed with ssrc " << ssrc;
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001971 return false;
1972 }
1973
1974 // The channel likely has gone away, do nothing.
henrike@webrtc.org1e09a712013-07-26 19:17:59 +00001975 return true;
henrike@webrtc.org1e09a712013-07-26 19:17:59 +00001976 }
1977
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -08001978 if (source) {
1979 it->second->SetSource(source);
solenberg1ac56142015-10-13 03:58:19 -07001980 } else {
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -08001981 it->second->ClearSource();
solenberg1ac56142015-10-13 03:58:19 -07001982 }
henrike@webrtc.org1e09a712013-07-26 19:17:59 +00001983
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001984 return true;
1985}
1986
solenberg796b8f92017-03-01 17:02:23 -08001987// TODO(solenberg): Remove, once AudioMonitor is gone.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001988bool WebRtcVoiceMediaChannel::GetActiveStreams(
1989 AudioInfo::StreamList* actives) {
solenberg566ef242015-11-06 15:34:49 -08001990 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001991 actives->clear();
solenberg7add0582015-11-20 09:59:34 -08001992 for (const auto& ch : recv_streams_) {
solenberg796b8f92017-03-01 17:02:23 -08001993 int level = ch.second->GetOutputLevel();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001994 if (level > 0) {
Fredrik Solenbergaf9fb212015-08-26 10:45:53 +02001995 actives->push_back(std::make_pair(ch.first, level));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001996 }
1997 }
1998 return true;
1999}
2000
solenberg796b8f92017-03-01 17:02:23 -08002001// TODO(solenberg): Remove, once AudioMonitor is gone.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002002int WebRtcVoiceMediaChannel::GetOutputLevel() {
solenberg566ef242015-11-06 15:34:49 -08002003 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenberg1ac56142015-10-13 03:58:19 -07002004 int highest = 0;
solenberg7add0582015-11-20 09:59:34 -08002005 for (const auto& ch : recv_streams_) {
solenberg796b8f92017-03-01 17:02:23 -08002006 highest = std::max(ch.second->GetOutputLevel(), highest);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002007 }
2008 return highest;
2009}
2010
solenberg4bac9c52015-10-09 02:32:53 -07002011bool WebRtcVoiceMediaChannel::SetOutputVolume(uint32_t ssrc, double volume) {
solenberg566ef242015-11-06 15:34:49 -08002012 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenberg2100c0b2017-03-01 11:29:29 -08002013 std::vector<uint32_t> ssrcs(1, ssrc);
deadbeef3bc15102017-04-20 19:25:07 -07002014 // SSRC of 0 represents the default receive stream.
solenberg1ac56142015-10-13 03:58:19 -07002015 if (ssrc == 0) {
2016 default_recv_volume_ = volume;
solenberg2100c0b2017-03-01 11:29:29 -08002017 ssrcs = unsignaled_recv_ssrcs_;
2018 }
2019 for (uint32_t ssrc : ssrcs) {
2020 const auto it = recv_streams_.find(ssrc);
2021 if (it == recv_streams_.end()) {
2022 LOG(LS_WARNING) << "SetOutputVolume: no recv stream " << ssrc;
2023 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002024 }
solenberg2100c0b2017-03-01 11:29:29 -08002025 it->second->SetOutputVolume(volume);
2026 LOG(LS_INFO) << "SetOutputVolume() to " << volume
2027 << " for recv stream with ssrc " << ssrc;
solenberg1ac56142015-10-13 03:58:19 -07002028 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002029 return true;
2030}
2031
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002032bool WebRtcVoiceMediaChannel::CanInsertDtmf() {
Fredrik Solenbergb5727682015-12-04 15:22:19 +01002033 return dtmf_payload_type_ ? true : false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002034}
2035
solenberg1d63dd02015-12-02 12:35:09 -08002036bool WebRtcVoiceMediaChannel::InsertDtmf(uint32_t ssrc, int event,
2037 int duration) {
solenberg566ef242015-11-06 15:34:49 -08002038 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
Fredrik Solenbergb5727682015-12-04 15:22:19 +01002039 LOG(LS_INFO) << "WebRtcVoiceMediaChannel::InsertDtmf";
2040 if (!dtmf_payload_type_) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002041 return false;
2042 }
2043
Fredrik Solenbergb5727682015-12-04 15:22:19 +01002044 // Figure out which WebRtcAudioSendStream to send the event on.
2045 auto it = ssrc != 0 ? send_streams_.find(ssrc) : send_streams_.begin();
2046 if (it == send_streams_.end()) {
2047 LOG(LS_WARNING) << "The specified ssrc " << ssrc << " is not in use.";
solenberg1d63dd02015-12-02 12:35:09 -08002048 return false;
2049 }
Fredrik Solenbergb5727682015-12-04 15:22:19 +01002050 if (event < kMinTelephoneEventCode ||
2051 event > kMaxTelephoneEventCode) {
2052 LOG(LS_WARNING) << "DTMF event code " << event << " out of range.";
solenberg1d63dd02015-12-02 12:35:09 -08002053 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002054 }
solenbergffbbcac2016-11-17 05:25:37 -08002055 RTC_DCHECK_NE(-1, dtmf_payload_freq_);
2056 return it->second->SendTelephoneEvent(*dtmf_payload_type_, dtmf_payload_freq_,
2057 event, duration);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002058}
2059
wu@webrtc.orga9890802013-12-13 00:21:03 +00002060void WebRtcVoiceMediaChannel::OnPacketReceived(
jbaucheec21bd2016-03-20 06:15:43 -07002061 rtc::CopyOnWriteBuffer* packet, const rtc::PacketTime& packet_time) {
solenberg566ef242015-11-06 15:34:49 -08002062 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
Fredrik Solenberg4b60c732015-05-07 14:07:48 +02002063
mflodman3d7db262016-04-29 00:57:13 -07002064 const webrtc::PacketTime webrtc_packet_time(packet_time.timestamp,
2065 packet_time.not_before);
2066 webrtc::PacketReceiver::DeliveryStatus delivery_result =
2067 call_->Receiver()->DeliverPacket(webrtc::MediaType::AUDIO,
2068 packet->cdata(), packet->size(),
2069 webrtc_packet_time);
mflodman3d7db262016-04-29 00:57:13 -07002070 if (delivery_result != webrtc::PacketReceiver::DELIVERY_UNKNOWN_SSRC) {
2071 return;
2072 }
2073
solenberg2100c0b2017-03-01 11:29:29 -08002074 // Create an unsignaled receive stream for this previously not received ssrc.
2075 // If there already is N unsignaled receive streams, delete the oldest.
mflodman3d7db262016-04-29 00:57:13 -07002076 // See: https://bugs.chromium.org/p/webrtc/issues/detail?id=5208
solenberg1ac56142015-10-13 03:58:19 -07002077 uint32_t ssrc = 0;
jbaucheec21bd2016-03-20 06:15:43 -07002078 if (!GetRtpSsrc(packet->cdata(), packet->size(), &ssrc)) {
solenberg1ac56142015-10-13 03:58:19 -07002079 return;
2080 }
solenberg2100c0b2017-03-01 11:29:29 -08002081 RTC_DCHECK(std::find(unsignaled_recv_ssrcs_.begin(),
2082 unsignaled_recv_ssrcs_.end(), ssrc) == unsignaled_recv_ssrcs_.end());
solenberg1ac56142015-10-13 03:58:19 -07002083
solenberg2100c0b2017-03-01 11:29:29 -08002084 // Add new stream.
mflodman3d7db262016-04-29 00:57:13 -07002085 StreamParams sp;
2086 sp.ssrcs.push_back(ssrc);
solenberg2100c0b2017-03-01 11:29:29 -08002087 LOG(LS_INFO) << "Creating unsignaled receive stream for SSRC=" << ssrc;
mflodman3d7db262016-04-29 00:57:13 -07002088 if (!AddRecvStream(sp)) {
solenberg2100c0b2017-03-01 11:29:29 -08002089 LOG(LS_WARNING) << "Could not create unsignaled receive stream.";
mflodman3d7db262016-04-29 00:57:13 -07002090 return;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002091 }
solenberg2100c0b2017-03-01 11:29:29 -08002092 unsignaled_recv_ssrcs_.push_back(ssrc);
2093 RTC_HISTOGRAM_COUNTS_LINEAR(
2094 "WebRTC.Audio.NumOfUnsignaledStreams", unsignaled_recv_ssrcs_.size(), 1,
2095 100, 101);
solenbergf748ca42017-02-06 13:03:19 -08002096
solenberg2100c0b2017-03-01 11:29:29 -08002097 // Remove oldest unsignaled stream, if we have too many.
2098 if (unsignaled_recv_ssrcs_.size() > kMaxUnsignaledRecvStreams) {
2099 uint32_t remove_ssrc = unsignaled_recv_ssrcs_.front();
2100 LOG(LS_INFO) << "Removing unsignaled receive stream with SSRC="
2101 << remove_ssrc;
2102 RemoveRecvStream(remove_ssrc);
2103 }
2104 RTC_DCHECK_GE(kMaxUnsignaledRecvStreams, unsignaled_recv_ssrcs_.size());
2105
2106 SetOutputVolume(ssrc, default_recv_volume_);
2107
2108 // The default sink can only be attached to one stream at a time, so we hook
2109 // it up to the *latest* unsignaled stream we've seen, in order to support the
2110 // case where the SSRC of one unsignaled stream changes.
mflodman3d7db262016-04-29 00:57:13 -07002111 if (default_sink_) {
solenberg2100c0b2017-03-01 11:29:29 -08002112 for (uint32_t drop_ssrc : unsignaled_recv_ssrcs_) {
2113 auto it = recv_streams_.find(drop_ssrc);
2114 it->second->SetRawAudioSink(nullptr);
2115 }
mflodman3d7db262016-04-29 00:57:13 -07002116 std::unique_ptr<webrtc::AudioSinkInterface> proxy_sink(
2117 new ProxySink(default_sink_.get()));
solenberg2100c0b2017-03-01 11:29:29 -08002118 SetRawAudioSink(ssrc, std::move(proxy_sink));
mflodman3d7db262016-04-29 00:57:13 -07002119 }
solenberg2100c0b2017-03-01 11:29:29 -08002120
mflodman3d7db262016-04-29 00:57:13 -07002121 delivery_result = call_->Receiver()->DeliverPacket(webrtc::MediaType::AUDIO,
2122 packet->cdata(),
2123 packet->size(),
2124 webrtc_packet_time);
2125 RTC_DCHECK_NE(webrtc::PacketReceiver::DELIVERY_UNKNOWN_SSRC, delivery_result);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002126}
2127
wu@webrtc.orga9890802013-12-13 00:21:03 +00002128void WebRtcVoiceMediaChannel::OnRtcpReceived(
jbaucheec21bd2016-03-20 06:15:43 -07002129 rtc::CopyOnWriteBuffer* packet, const rtc::PacketTime& packet_time) {
solenberg566ef242015-11-06 15:34:49 -08002130 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
Fredrik Solenberg4b60c732015-05-07 14:07:48 +02002131
Fredrik Solenberg709ed672015-09-15 12:26:33 +02002132 // Forward packet to Call as well.
2133 const webrtc::PacketTime webrtc_packet_time(packet_time.timestamp,
2134 packet_time.not_before);
2135 call_->Receiver()->DeliverPacket(webrtc::MediaType::AUDIO,
jbaucheec21bd2016-03-20 06:15:43 -07002136 packet->cdata(), packet->size(), webrtc_packet_time);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002137}
2138
Honghai Zhangcc411c02016-03-29 17:27:21 -07002139void WebRtcVoiceMediaChannel::OnNetworkRouteChanged(
2140 const std::string& transport_name,
Honghai Zhang0e533ef2016-04-19 15:41:36 -07002141 const rtc::NetworkRoute& network_route) {
2142 call_->OnNetworkRouteChanged(transport_name, network_route);
Honghai Zhangcc411c02016-03-29 17:27:21 -07002143}
2144
Peter Boström0c4e06b2015-10-07 12:23:21 +02002145bool WebRtcVoiceMediaChannel::MuteStream(uint32_t ssrc, bool muted) {
solenberg566ef242015-11-06 15:34:49 -08002146 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenberg94218532016-06-16 10:53:22 -07002147 const auto it = send_streams_.find(ssrc);
2148 if (it == send_streams_.end()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002149 LOG(LS_WARNING) << "The specified ssrc " << ssrc << " is not in use.";
2150 return false;
2151 }
solenberg94218532016-06-16 10:53:22 -07002152 it->second->SetMuted(muted);
2153
2154 // TODO(solenberg):
buildbot@webrtc.org6b21b712014-07-31 15:08:53 +00002155 // We set the AGC to mute state only when all the channels are muted.
2156 // This implementation is not ideal, instead we should signal the AGC when
2157 // the mic channel is muted/unmuted. We can't do it today because there
2158 // is no good way to know which stream is mapping to the mic channel.
2159 bool all_muted = muted;
solenberg94218532016-06-16 10:53:22 -07002160 for (const auto& kv : send_streams_) {
2161 all_muted = all_muted && kv.second->muted();
buildbot@webrtc.org6b21b712014-07-31 15:08:53 +00002162 }
solenberg059fb442016-10-26 05:12:24 -07002163 engine()->apm()->set_output_will_be_muted(all_muted);
buildbot@webrtc.org6b21b712014-07-31 15:08:53 +00002164
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002165 return true;
2166}
2167
deadbeef80346142016-04-27 14:17:10 -07002168bool WebRtcVoiceMediaChannel::SetMaxSendBitrate(int bps) {
2169 LOG(LS_INFO) << "WebRtcVoiceMediaChannel::SetMaxSendBitrate.";
2170 max_send_bitrate_bps_ = bps;
minyue7a973442016-10-20 03:27:12 -07002171 bool success = true;
skvlade0d46372016-04-07 22:59:22 -07002172 for (const auto& kv : send_streams_) {
minyue7a973442016-10-20 03:27:12 -07002173 if (!kv.second->SetMaxSendBitrate(max_send_bitrate_bps_)) {
2174 success = false;
skvlade0d46372016-04-07 22:59:22 -07002175 }
2176 }
minyue7a973442016-10-20 03:27:12 -07002177 return success;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002178}
2179
skvlad7a43d252016-03-22 15:32:27 -07002180void WebRtcVoiceMediaChannel::OnReadyToSend(bool ready) {
2181 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
2182 LOG(LS_VERBOSE) << "OnReadyToSend: " << (ready ? "Ready." : "Not ready.");
2183 call_->SignalChannelNetworkState(
2184 webrtc::MediaType::AUDIO,
2185 ready ? webrtc::kNetworkUp : webrtc::kNetworkDown);
2186}
2187
michaelt79e05882016-11-08 02:50:09 -08002188void WebRtcVoiceMediaChannel::OnTransportOverheadChanged(
2189 int transport_overhead_per_packet) {
2190 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
2191 call_->OnTransportOverheadChanged(webrtc::MediaType::AUDIO,
2192 transport_overhead_per_packet);
2193}
2194
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002195bool WebRtcVoiceMediaChannel::GetStats(VoiceMediaInfo* info) {
Peter Boströmca8b4042016-03-08 14:24:13 -08002196 TRACE_EVENT0("webrtc", "WebRtcVoiceMediaChannel::GetStats");
solenberg566ef242015-11-06 15:34:49 -08002197 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenberg85a04962015-10-27 03:35:21 -07002198 RTC_DCHECK(info);
solenbergd97ec302015-10-07 01:40:33 -07002199
solenberg85a04962015-10-27 03:35:21 -07002200 // Get SSRC and stats for each sender.
hbos1acfbd22016-11-17 23:43:29 -08002201 RTC_DCHECK_EQ(info->senders.size(), 0U);
solenberg85a04962015-10-27 03:35:21 -07002202 for (const auto& stream : send_streams_) {
2203 webrtc::AudioSendStream::Stats stats = stream.second->GetStats();
wu@webrtc.org9dba5252013-08-05 20:36:57 +00002204 VoiceSenderInfo sinfo;
solenberg85a04962015-10-27 03:35:21 -07002205 sinfo.add_ssrc(stats.local_ssrc);
2206 sinfo.bytes_sent = stats.bytes_sent;
2207 sinfo.packets_sent = stats.packets_sent;
2208 sinfo.packets_lost = stats.packets_lost;
2209 sinfo.fraction_lost = stats.fraction_lost;
2210 sinfo.codec_name = stats.codec_name;
hbos1acfbd22016-11-17 23:43:29 -08002211 sinfo.codec_payload_type = stats.codec_payload_type;
solenberg85a04962015-10-27 03:35:21 -07002212 sinfo.ext_seqnum = stats.ext_seqnum;
2213 sinfo.jitter_ms = stats.jitter_ms;
2214 sinfo.rtt_ms = stats.rtt_ms;
2215 sinfo.audio_level = stats.audio_level;
zsteine76bd3a2017-07-14 12:17:49 -07002216 sinfo.total_input_energy = stats.total_input_energy;
2217 sinfo.total_input_duration = stats.total_input_duration;
solenberg85a04962015-10-27 03:35:21 -07002218 sinfo.aec_quality_min = stats.aec_quality_min;
2219 sinfo.echo_delay_median_ms = stats.echo_delay_median_ms;
2220 sinfo.echo_delay_std_ms = stats.echo_delay_std_ms;
2221 sinfo.echo_return_loss = stats.echo_return_loss;
2222 sinfo.echo_return_loss_enhancement = stats.echo_return_loss_enhancement;
ivoc8c63a822016-10-21 04:10:03 -07002223 sinfo.residual_echo_likelihood = stats.residual_echo_likelihood;
ivoc4e477a12017-01-15 08:29:46 -08002224 sinfo.residual_echo_likelihood_recent_max =
2225 stats.residual_echo_likelihood_recent_max;
Taylor Brandstetter1a018dc2016-03-08 12:37:39 -08002226 sinfo.typing_noise_detected = (send_ ? stats.typing_noise_detected : false);
ivoce1198e02017-09-08 08:13:19 -07002227 sinfo.ana_statistics = stats.ana_statistics;
wu@webrtc.org9dba5252013-08-05 20:36:57 +00002228 info->senders.push_back(sinfo);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002229 }
2230
solenberg85a04962015-10-27 03:35:21 -07002231 // Get SSRC and stats for each receiver.
hbos1acfbd22016-11-17 23:43:29 -08002232 RTC_DCHECK_EQ(info->receivers.size(), 0U);
solenberg7add0582015-11-20 09:59:34 -08002233 for (const auto& stream : recv_streams_) {
deadbeef4e2deab2017-09-20 13:56:21 -07002234 uint32_t ssrc = stream.first;
2235 // When SSRCs are unsignaled, there's only one audio MediaStreamTrack, but
2236 // multiple RTP streams can be received over time (if the SSRC changes for
2237 // whatever reason). We only want the RTCMediaStreamTrackStats to represent
2238 // the stats for the most recent stream (the one whose audio is actually
2239 // routed to the MediaStreamTrack), so here we ignore any unsignaled SSRCs
2240 // except for the most recent one (last in the vector). This is somewhat of
2241 // a hack, and means you don't get *any* stats for these inactive streams,
2242 // but it's slightly better than the previous behavior, which was "highest
2243 // SSRC wins".
2244 // See: https://bugs.chromium.org/p/webrtc/issues/detail?id=8158
2245 if (!unsignaled_recv_ssrcs_.empty()) {
2246 auto end_it = --unsignaled_recv_ssrcs_.end();
2247 if (std::find(unsignaled_recv_ssrcs_.begin(), end_it, ssrc) != end_it) {
2248 continue;
2249 }
2250 }
Fredrik Solenberg4f4ec0a2015-10-22 10:49:27 +02002251 webrtc::AudioReceiveStream::Stats stats = stream.second->GetStats();
2252 VoiceReceiverInfo rinfo;
2253 rinfo.add_ssrc(stats.remote_ssrc);
2254 rinfo.bytes_rcvd = stats.bytes_rcvd;
2255 rinfo.packets_rcvd = stats.packets_rcvd;
2256 rinfo.packets_lost = stats.packets_lost;
2257 rinfo.fraction_lost = stats.fraction_lost;
2258 rinfo.codec_name = stats.codec_name;
hbos1acfbd22016-11-17 23:43:29 -08002259 rinfo.codec_payload_type = stats.codec_payload_type;
Fredrik Solenberg4f4ec0a2015-10-22 10:49:27 +02002260 rinfo.ext_seqnum = stats.ext_seqnum;
2261 rinfo.jitter_ms = stats.jitter_ms;
2262 rinfo.jitter_buffer_ms = stats.jitter_buffer_ms;
2263 rinfo.jitter_buffer_preferred_ms = stats.jitter_buffer_preferred_ms;
2264 rinfo.delay_estimate_ms = stats.delay_estimate_ms;
2265 rinfo.audio_level = stats.audio_level;
zsteine76bd3a2017-07-14 12:17:49 -07002266 rinfo.total_output_energy = stats.total_output_energy;
Steve Anton2dbc69f2017-08-24 17:15:13 -07002267 rinfo.total_samples_received = stats.total_samples_received;
zsteine76bd3a2017-07-14 12:17:49 -07002268 rinfo.total_output_duration = stats.total_output_duration;
Steve Anton2dbc69f2017-08-24 17:15:13 -07002269 rinfo.concealed_samples = stats.concealed_samples;
Gustaf Ullberg9a2e9062017-09-18 09:28:20 +02002270 rinfo.concealment_events = stats.concealment_events;
Gustaf Ullbergb0a02072017-10-02 12:00:34 +02002271 rinfo.jitter_buffer_delay_seconds = stats.jitter_buffer_delay_seconds;
Fredrik Solenberg4f4ec0a2015-10-22 10:49:27 +02002272 rinfo.expand_rate = stats.expand_rate;
2273 rinfo.speech_expand_rate = stats.speech_expand_rate;
2274 rinfo.secondary_decoded_rate = stats.secondary_decoded_rate;
minyue-webrtc0e320ec2017-08-28 13:51:27 +02002275 rinfo.secondary_discarded_rate = stats.secondary_discarded_rate;
Fredrik Solenberg4f4ec0a2015-10-22 10:49:27 +02002276 rinfo.accelerate_rate = stats.accelerate_rate;
2277 rinfo.preemptive_expand_rate = stats.preemptive_expand_rate;
2278 rinfo.decoding_calls_to_silence_generator =
2279 stats.decoding_calls_to_silence_generator;
2280 rinfo.decoding_calls_to_neteq = stats.decoding_calls_to_neteq;
2281 rinfo.decoding_normal = stats.decoding_normal;
2282 rinfo.decoding_plc = stats.decoding_plc;
2283 rinfo.decoding_cng = stats.decoding_cng;
2284 rinfo.decoding_plc_cng = stats.decoding_plc_cng;
henrik.lundin63489782016-09-20 01:47:12 -07002285 rinfo.decoding_muted_output = stats.decoding_muted_output;
Fredrik Solenberg4f4ec0a2015-10-22 10:49:27 +02002286 rinfo.capture_start_ntp_time_ms = stats.capture_start_ntp_time_ms;
2287 info->receivers.push_back(rinfo);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002288 }
2289
hbos1acfbd22016-11-17 23:43:29 -08002290 // Get codec info
2291 for (const AudioCodec& codec : send_codecs_) {
2292 webrtc::RtpCodecParameters codec_params = codec.ToCodecParameters();
2293 info->send_codecs.insert(
2294 std::make_pair(codec_params.payload_type, std::move(codec_params)));
2295 }
2296 for (const AudioCodec& codec : recv_codecs_) {
2297 webrtc::RtpCodecParameters codec_params = codec.ToCodecParameters();
2298 info->receive_codecs.insert(
2299 std::make_pair(codec_params.payload_type, std::move(codec_params)));
2300 }
2301
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002302 return true;
2303}
2304
Tommif888bb52015-12-12 01:37:01 +01002305void WebRtcVoiceMediaChannel::SetRawAudioSink(
2306 uint32_t ssrc,
kwiberg686a8ef2016-02-26 03:00:35 -08002307 std::unique_ptr<webrtc::AudioSinkInterface> sink) {
Tommif888bb52015-12-12 01:37:01 +01002308 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
deadbeef884f5852016-01-15 09:20:04 -08002309 LOG(LS_VERBOSE) << "WebRtcVoiceMediaChannel::SetRawAudioSink: ssrc:" << ssrc
2310 << " " << (sink ? "(ptr)" : "NULL");
2311 if (ssrc == 0) {
solenberg2100c0b2017-03-01 11:29:29 -08002312 if (!unsignaled_recv_ssrcs_.empty()) {
kwiberg686a8ef2016-02-26 03:00:35 -08002313 std::unique_ptr<webrtc::AudioSinkInterface> proxy_sink(
deadbeef884f5852016-01-15 09:20:04 -08002314 sink ? new ProxySink(sink.get()) : nullptr);
solenberg2100c0b2017-03-01 11:29:29 -08002315 SetRawAudioSink(unsignaled_recv_ssrcs_.back(), std::move(proxy_sink));
deadbeef884f5852016-01-15 09:20:04 -08002316 }
2317 default_sink_ = std::move(sink);
2318 return;
2319 }
Tommif888bb52015-12-12 01:37:01 +01002320 const auto it = recv_streams_.find(ssrc);
2321 if (it == recv_streams_.end()) {
solenberg2100c0b2017-03-01 11:29:29 -08002322 LOG(LS_WARNING) << "SetRawAudioSink: no recv stream " << ssrc;
Tommif888bb52015-12-12 01:37:01 +01002323 return;
2324 }
deadbeef2d110be2016-01-13 12:00:26 -08002325 it->second->SetRawAudioSink(std::move(sink));
Tommif888bb52015-12-12 01:37:01 +01002326}
2327
hbos8d609f62017-04-10 07:39:05 -07002328std::vector<webrtc::RtpSource> WebRtcVoiceMediaChannel::GetSources(
2329 uint32_t ssrc) const {
2330 auto it = recv_streams_.find(ssrc);
2331 RTC_DCHECK(it != recv_streams_.end())
2332 << "Attempting to get contributing sources for SSRC:" << ssrc
2333 << " which doesn't exist.";
2334 return it->second->GetSources();
2335}
2336
Peter Boström0c4e06b2015-10-07 12:23:21 +02002337int WebRtcVoiceMediaChannel::GetReceiveChannelId(uint32_t ssrc) const {
solenberg566ef242015-11-06 15:34:49 -08002338 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenberg7add0582015-11-20 09:59:34 -08002339 const auto it = recv_streams_.find(ssrc);
2340 if (it != recv_streams_.end()) {
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +00002341 return it->second->channel();
solenberg8fb30c32015-10-13 03:06:58 -07002342 }
solenberg1ac56142015-10-13 03:58:19 -07002343 return -1;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002344}
2345
Peter Boström0c4e06b2015-10-07 12:23:21 +02002346int WebRtcVoiceMediaChannel::GetSendChannelId(uint32_t ssrc) const {
solenberg566ef242015-11-06 15:34:49 -08002347 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenbergc96df772015-10-21 13:01:53 -07002348 const auto it = send_streams_.find(ssrc);
2349 if (it != send_streams_.end()) {
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +00002350 return it->second->channel();
solenberg8fb30c32015-10-13 03:06:58 -07002351 }
wu@webrtc.org9dba5252013-08-05 20:36:57 +00002352 return -1;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002353}
solenberg2100c0b2017-03-01 11:29:29 -08002354
2355bool WebRtcVoiceMediaChannel::
2356 MaybeDeregisterUnsignaledRecvStream(uint32_t ssrc) {
2357 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
2358 auto it = std::find(unsignaled_recv_ssrcs_.begin(),
2359 unsignaled_recv_ssrcs_.end(),
2360 ssrc);
2361 if (it != unsignaled_recv_ssrcs_.end()) {
2362 unsignaled_recv_ssrcs_.erase(it);
2363 return true;
2364 }
2365 return false;
2366}
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002367} // namespace cricket
2368
2369#endif // HAVE_WEBRTC_VOICE