blob: 9e7a5f46f97ae7fa95f2d50800585a04a54971af [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
xians@webrtc.org79af7342012-01-31 12:22:14 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "voice_engine/voe_base_impl.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000012
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020013#include "api/audio_codecs/builtin_audio_decoder_factory.h"
14#include "common_audio/signal_processing/include/signal_processing_library.h"
15#include "modules/audio_coding/include/audio_coding_module.h"
16#include "modules/audio_device/audio_device_impl.h"
17#include "modules/audio_processing/include/audio_processing.h"
18#include "rtc_base/format_macros.h"
19#include "rtc_base/location.h"
20#include "rtc_base/logging.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020021#include "voice_engine/channel.h"
22#include "voice_engine/include/voe_errors.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020023#include "voice_engine/transmit_mixer.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020024#include "voice_engine/voice_engine_impl.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000025
Jelena Marusic2dd6a272015-04-14 09:47:00 +020026namespace webrtc {
niklase@google.com470e71d2011-07-07 08:21:25 +000027
Jelena Marusic2dd6a272015-04-14 09:47:00 +020028VoEBase* VoEBase::GetInterface(VoiceEngine* voiceEngine) {
29 if (nullptr == voiceEngine) {
30 return nullptr;
31 }
32 VoiceEngineImpl* s = static_cast<VoiceEngineImpl*>(voiceEngine);
33 s->AddRef();
34 return s;
niklase@google.com470e71d2011-07-07 08:21:25 +000035}
36
Jelena Marusic2dd6a272015-04-14 09:47:00 +020037VoEBaseImpl::VoEBaseImpl(voe::SharedData* shared)
solenbergfc3a2e32017-09-26 09:35:01 -070038 : shared_(shared) {}
Jelena Marusic2dd6a272015-04-14 09:47:00 +020039
40VoEBaseImpl::~VoEBaseImpl() {
41 TerminateInternal();
niklase@google.com470e71d2011-07-07 08:21:25 +000042}
43
henrikaec6fbd22017-03-31 05:43:36 -070044int32_t VoEBaseImpl::RecordedDataIsAvailable(
45 const void* audio_data,
46 const size_t number_of_frames,
47 const size_t bytes_per_sample,
48 const size_t number_of_channels,
49 const uint32_t sample_rate,
50 const uint32_t audio_delay_milliseconds,
51 const int32_t clock_drift,
52 const uint32_t volume,
53 const bool key_pressed,
54 uint32_t& new_mic_volume) {
55 RTC_DCHECK_EQ(2 * number_of_channels, bytes_per_sample);
56 RTC_DCHECK(shared_->transmit_mixer() != nullptr);
57 RTC_DCHECK(shared_->audio_device() != nullptr);
58
59 uint32_t max_volume = 0;
60 uint16_t voe_mic_level = 0;
61 // Check for zero to skip this calculation; the consumer may use this to
62 // indicate no volume is available.
63 if (volume != 0) {
64 // Scale from ADM to VoE level range
65 if (shared_->audio_device()->MaxMicrophoneVolume(&max_volume) == 0) {
66 if (max_volume) {
67 voe_mic_level = static_cast<uint16_t>(
68 (volume * kMaxVolumeLevel + static_cast<int>(max_volume / 2)) /
69 max_volume);
70 }
71 }
72 // We learned that on certain systems (e.g Linux) the voe_mic_level
73 // can be greater than the maxVolumeLevel therefore
74 // we are going to cap the voe_mic_level to the maxVolumeLevel
75 // and change the maxVolume to volume if it turns out that
76 // the voe_mic_level is indeed greater than the maxVolumeLevel.
77 if (voe_mic_level > kMaxVolumeLevel) {
78 voe_mic_level = kMaxVolumeLevel;
79 max_volume = volume;
80 }
81 }
82
83 // Perform channel-independent operations
84 // (APM, mix with file, record to file, mute, etc.)
85 shared_->transmit_mixer()->PrepareDemux(
86 audio_data, number_of_frames, number_of_channels, sample_rate,
87 static_cast<uint16_t>(audio_delay_milliseconds), clock_drift,
88 voe_mic_level, key_pressed);
89
90 // Copy the audio frame to each sending channel and perform
91 // channel-dependent operations (file mixing, mute, etc.), encode and
92 // packetize+transmit the RTP packet.
93 shared_->transmit_mixer()->ProcessAndEncodeAudio();
94
95 // Scale from VoE to ADM level range.
96 uint32_t new_voe_mic_level = shared_->transmit_mixer()->CaptureLevel();
97 if (new_voe_mic_level != voe_mic_level) {
98 // Return the new volume if AGC has changed the volume.
99 return static_cast<int>((new_voe_mic_level * max_volume +
100 static_cast<int>(kMaxVolumeLevel / 2)) /
101 kMaxVolumeLevel);
102 }
103
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200104 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000105}
106
solenberg13725082015-11-25 08:16:52 -0800107int32_t VoEBaseImpl::NeedMorePlayData(const size_t nSamples,
108 const size_t nBytesPerSample,
Peter Kasting69558702016-01-12 16:26:35 -0800109 const size_t nChannels,
solenberg13725082015-11-25 08:16:52 -0800110 const uint32_t samplesPerSec,
111 void* audioSamples,
112 size_t& nSamplesOut,
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200113 int64_t* elapsed_time_ms,
114 int64_t* ntp_time_ms) {
solenberg2397b9a2017-09-22 06:48:10 -0700115 RTC_NOTREACHED();
xians@webrtc.org56925312014-04-14 10:50:37 +0000116 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000117}
118
xians@webrtc.org56925312014-04-14 10:50:37 +0000119void VoEBaseImpl::PushCaptureData(int voe_channel, const void* audio_data,
120 int bits_per_sample, int sample_rate,
Peter Kasting69558702016-01-12 16:26:35 -0800121 size_t number_of_channels,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700122 size_t number_of_frames) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200123 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(voe_channel);
henrikaec6fbd22017-03-31 05:43:36 -0700124 voe::Channel* channel = ch.channel();
125 if (!channel)
126 return;
127 if (channel->Sending()) {
128 // Send the audio to each channel directly without using the APM in the
129 // transmit mixer.
130 channel->ProcessAndEncodeAudio(static_cast<const int16_t*>(audio_data),
131 sample_rate, number_of_frames,
132 number_of_channels);
xians@webrtc.org07e51962014-01-29 13:54:02 +0000133 }
134}
135
Peter Kastingdce40cf2015-08-24 14:52:23 -0700136void VoEBaseImpl::PullRenderData(int bits_per_sample,
137 int sample_rate,
Peter Kasting69558702016-01-12 16:26:35 -0800138 size_t number_of_channels,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700139 size_t number_of_frames,
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200140 void* audio_data, int64_t* elapsed_time_ms,
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000141 int64_t* ntp_time_ms) {
solenberg2397b9a2017-09-22 06:48:10 -0700142 RTC_NOTREACHED();
xians@webrtc.org56925312014-04-14 10:50:37 +0000143}
144
ossu5f7cfa52016-05-30 08:11:28 -0700145int VoEBaseImpl::Init(
146 AudioDeviceModule* external_adm,
peahe67bedb2017-07-07 04:25:11 -0700147 AudioProcessing* audio_processing,
ossu5f7cfa52016-05-30 08:11:28 -0700148 const rtc::scoped_refptr<AudioDecoderFactory>& decoder_factory) {
peahe67bedb2017-07-07 04:25:11 -0700149 RTC_DCHECK(audio_processing);
tommi31fc21f2016-01-21 10:37:37 -0800150 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200151 WebRtcSpl_Init();
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200152 if (shared_->process_thread()) {
153 shared_->process_thread()->Start();
154 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000155
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200156 // Create an internal ADM if the user has not added an external
157 // ADM implementation as input to Init().
158 if (external_adm == nullptr) {
Tommi931e6582015-05-20 09:44:38 +0200159#if !defined(WEBRTC_INCLUDE_INTERNAL_AUDIO_DEVICE)
160 return -1;
161#else
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200162 // Create the internal ADM implementation.
Peter Boström4adbbcf2016-05-03 15:51:26 -0400163 shared_->set_audio_device(AudioDeviceModule::Create(
solenberg5b3e49a2017-03-15 08:08:07 -0700164 VoEId(shared_->instance_id(), -1),
165 AudioDeviceModule::kPlatformDefaultAudio));
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200166 if (shared_->audio_device() == nullptr) {
solenberg1c239d42017-09-29 06:00:28 -0700167 LOG(LS_ERROR) << "Init() failed to create the ADM";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200168 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000169 }
Tommi931e6582015-05-20 09:44:38 +0200170#endif // WEBRTC_INCLUDE_INTERNAL_AUDIO_DEVICE
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200171 } else {
172 // Use the already existing external ADM implementation.
173 shared_->set_audio_device(external_adm);
174 LOG_F(LS_INFO)
175 << "An external ADM implementation will be used in VoiceEngine";
176 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000177
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200178 bool available = false;
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000179
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200180 // --------------------
181 // Reinitialize the ADM
henrika@google.com73d65512011-09-07 15:11:18 +0000182
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200183 // Register the AudioTransport implementation
184 if (shared_->audio_device()->RegisterAudioCallback(this) != 0) {
solenberg1c239d42017-09-29 06:00:28 -0700185 LOG(LS_ERROR) << "Init() failed to register audio callback for the ADM";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200186 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000187
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200188 // ADM initialization
189 if (shared_->audio_device()->Init() != 0) {
solenberg1c239d42017-09-29 06:00:28 -0700190 LOG(LS_ERROR) << "Init() failed to initialize the ADM";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200191 return -1;
192 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000193
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200194 // Initialize the default speaker
195 if (shared_->audio_device()->SetPlayoutDevice(
196 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0) {
solenberg1c239d42017-09-29 06:00:28 -0700197 LOG(LS_ERROR) << "Init() failed to set the default output device";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200198 }
199 if (shared_->audio_device()->InitSpeaker() != 0) {
solenberg1c239d42017-09-29 06:00:28 -0700200 LOG(LS_ERROR) << "Init() failed to initialize the speaker";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200201 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000202
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200203 // Initialize the default microphone
204 if (shared_->audio_device()->SetRecordingDevice(
205 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0) {
solenberg1c239d42017-09-29 06:00:28 -0700206 LOG(LS_ERROR) << "Init() failed to set the default input device";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200207 }
208 if (shared_->audio_device()->InitMicrophone() != 0) {
solenberg1c239d42017-09-29 06:00:28 -0700209 LOG(LS_ERROR) << "Init() failed to initialize the microphone";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200210 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000211
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200212 // Set number of channels
213 if (shared_->audio_device()->StereoPlayoutIsAvailable(&available) != 0) {
solenberg1c239d42017-09-29 06:00:28 -0700214 LOG(LS_ERROR) << "Init() failed to query stereo playout mode";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200215 }
216 if (shared_->audio_device()->SetStereoPlayout(available) != 0) {
solenberg1c239d42017-09-29 06:00:28 -0700217 LOG(LS_ERROR) << "Init() failed to set mono/stereo playout mode";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200218 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000219
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200220 // TODO(andrew): These functions don't tell us whether stereo recording
221 // is truly available. We simply set the AudioProcessing input to stereo
222 // here, because we have to wait until receiving the first frame to
223 // determine the actual number of channels anyway.
224 //
225 // These functions may be changed; tracked here:
226 // http://code.google.com/p/webrtc/issues/detail?id=204
227 shared_->audio_device()->StereoRecordingIsAvailable(&available);
228 if (shared_->audio_device()->SetStereoRecording(available) != 0) {
solenberg1c239d42017-09-29 06:00:28 -0700229 LOG(LS_ERROR) << "Init() failed to set mono/stereo recording mode";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200230 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000231
peahe67bedb2017-07-07 04:25:11 -0700232 shared_->set_audio_processing(audio_processing);
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000233
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200234 // Configure AudioProcessing components.
peaha9cc40b2017-06-29 08:32:09 -0700235 // TODO(peah): Move this initialization to webrtcvoiceengine.cc.
peahe67bedb2017-07-07 04:25:11 -0700236 if (audio_processing->high_pass_filter()->Enable(true) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200237 LOG_F(LS_ERROR) << "Failed to enable high pass filter.";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200238 return -1;
239 }
peahe67bedb2017-07-07 04:25:11 -0700240 if (audio_processing->echo_cancellation()->enable_drift_compensation(false) !=
241 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200242 LOG_F(LS_ERROR) << "Failed to disable drift compensation.";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200243 return -1;
244 }
peahe67bedb2017-07-07 04:25:11 -0700245 if (audio_processing->noise_suppression()->set_level(kDefaultNsMode) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200246 LOG_F(LS_ERROR) << "Failed to set noise suppression level: "
247 << kDefaultNsMode;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200248 return -1;
249 }
peahe67bedb2017-07-07 04:25:11 -0700250 GainControl* agc = audio_processing->gain_control();
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200251 if (agc->set_analog_level_limits(kMinVolumeLevel, kMaxVolumeLevel) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200252 LOG_F(LS_ERROR) << "Failed to set analog level limits with minimum: "
253 << kMinVolumeLevel << " and maximum: " << kMaxVolumeLevel;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200254 return -1;
255 }
256 if (agc->set_mode(kDefaultAgcMode) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200257 LOG_F(LS_ERROR) << "Failed to set mode: " << kDefaultAgcMode;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200258 return -1;
259 }
260 if (agc->Enable(kDefaultAgcState) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200261 LOG_F(LS_ERROR) << "Failed to set agc state: " << kDefaultAgcState;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200262 return -1;
263 }
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000264
niklase@google.com470e71d2011-07-07 08:21:25 +0000265#ifdef WEBRTC_VOICE_ENGINE_AGC
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200266 bool agc_enabled =
267 agc->mode() == GainControl::kAdaptiveAnalog && agc->is_enabled();
268 if (shared_->audio_device()->SetAGC(agc_enabled) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200269 LOG_F(LS_ERROR) << "Failed to set agc to enabled: " << agc_enabled;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200270 // TODO(ajm): No error return here due to
271 // https://code.google.com/p/webrtc/issues/detail?id=1464
272 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000273#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000274
ossu5f7cfa52016-05-30 08:11:28 -0700275 if (decoder_factory)
276 decoder_factory_ = decoder_factory;
277 else
278 decoder_factory_ = CreateBuiltinAudioDecoderFactory();
279
solenberg1c239d42017-09-29 06:00:28 -0700280 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000281}
282
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200283int VoEBaseImpl::Terminate() {
tommi31fc21f2016-01-21 10:37:37 -0800284 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200285 return TerminateInternal();
niklase@google.com470e71d2011-07-07 08:21:25 +0000286}
287
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000288int VoEBaseImpl::CreateChannel() {
solenberg88499ec2016-09-07 07:34:41 -0700289 return CreateChannel(ChannelConfig());
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000290}
291
solenberg88499ec2016-09-07 07:34:41 -0700292int VoEBaseImpl::CreateChannel(const ChannelConfig& config) {
tommi31fc21f2016-01-21 10:37:37 -0800293 rtc::CritScope cs(shared_->crit_sec());
solenberg88499ec2016-09-07 07:34:41 -0700294 ChannelConfig config_copy(config);
295 config_copy.acm_config.decoder_factory = decoder_factory_;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200296 voe::ChannelOwner channel_owner =
solenberg88499ec2016-09-07 07:34:41 -0700297 shared_->channel_manager().CreateChannel(config_copy);
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000298 return InitializeChannel(&channel_owner);
299}
300
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200301int VoEBaseImpl::InitializeChannel(voe::ChannelOwner* channel_owner) {
302 if (channel_owner->channel()->SetEngineInformation(
solenberg796b8f92017-03-01 17:02:23 -0800303 *shared_->process_thread(), *shared_->audio_device(),
solenberg1c239d42017-09-29 06:00:28 -0700304 shared_->encoder_queue()) != 0) {
305 LOG(LS_ERROR) << "CreateChannel() failed to associate engine and channel."
306 " Destroying channel.";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200307 shared_->channel_manager().DestroyChannel(
308 channel_owner->channel()->ChannelId());
309 return -1;
310 } else if (channel_owner->channel()->Init() != 0) {
solenberg1c239d42017-09-29 06:00:28 -0700311 LOG(LS_ERROR) << "CreateChannel() failed to initialize channel. Destroying"
312 " channel.";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200313 shared_->channel_manager().DestroyChannel(
314 channel_owner->channel()->ChannelId());
315 return -1;
316 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200317 return channel_owner->channel()->ChannelId();
niklase@google.com470e71d2011-07-07 08:21:25 +0000318}
319
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200320int VoEBaseImpl::DeleteChannel(int channel) {
tommi31fc21f2016-01-21 10:37:37 -0800321 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200322 {
323 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
324 voe::Channel* channelPtr = ch.channel();
325 if (channelPtr == nullptr) {
solenberg1c239d42017-09-29 06:00:28 -0700326 LOG(LS_ERROR) << "DeleteChannel() failed to locate channel";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200327 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000328 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200329 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000330
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200331 shared_->channel_manager().DestroyChannel(channel);
332 if (StopSend() != 0) {
333 return -1;
334 }
335 if (StopPlayout() != 0) {
336 return -1;
337 }
338 return 0;
339}
niklase@google.com470e71d2011-07-07 08:21:25 +0000340
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200341int VoEBaseImpl::StartPlayout(int channel) {
tommi31fc21f2016-01-21 10:37:37 -0800342 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200343 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
344 voe::Channel* channelPtr = ch.channel();
345 if (channelPtr == nullptr) {
solenberg1c239d42017-09-29 06:00:28 -0700346 LOG(LS_ERROR) << "StartPlayout() failed to locate channel";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200347 return -1;
348 }
349 if (channelPtr->Playing()) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000350 return 0;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200351 }
352 if (StartPlayout() != 0) {
solenberg1c239d42017-09-29 06:00:28 -0700353 LOG(LS_ERROR) << "StartPlayout() failed to start playout";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200354 return -1;
355 }
356 return channelPtr->StartPlayout();
niklase@google.com470e71d2011-07-07 08:21:25 +0000357}
358
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200359int VoEBaseImpl::StopPlayout(int channel) {
tommi31fc21f2016-01-21 10:37:37 -0800360 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200361 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
362 voe::Channel* channelPtr = ch.channel();
363 if (channelPtr == nullptr) {
solenberg1c239d42017-09-29 06:00:28 -0700364 LOG(LS_ERROR) << "StopPlayout() failed to locate channel";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200365 return -1;
366 }
367 if (channelPtr->StopPlayout() != 0) {
368 LOG_F(LS_WARNING) << "StopPlayout() failed to stop playout for channel "
369 << channel;
370 }
371 return StopPlayout();
niklase@google.com470e71d2011-07-07 08:21:25 +0000372}
373
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200374int VoEBaseImpl::StartSend(int channel) {
tommi31fc21f2016-01-21 10:37:37 -0800375 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200376 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
377 voe::Channel* channelPtr = ch.channel();
378 if (channelPtr == nullptr) {
solenberg1c239d42017-09-29 06:00:28 -0700379 LOG(LS_ERROR) << "StartSend() failed to locate channel";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200380 return -1;
381 }
382 if (channelPtr->Sending()) {
383 return 0;
384 }
385 if (StartSend() != 0) {
solenberg1c239d42017-09-29 06:00:28 -0700386 LOG(LS_ERROR) << "StartSend() failed to start recording";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200387 return -1;
388 }
389 return channelPtr->StartSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000390}
391
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200392int VoEBaseImpl::StopSend(int channel) {
tommi31fc21f2016-01-21 10:37:37 -0800393 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200394 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
395 voe::Channel* channelPtr = ch.channel();
396 if (channelPtr == nullptr) {
solenberg1c239d42017-09-29 06:00:28 -0700397 LOG(LS_ERROR) << "StopSend() failed to locate channel";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200398 return -1;
399 }
henrikaec6fbd22017-03-31 05:43:36 -0700400 channelPtr->StopSend();
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200401 return StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000402}
403
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200404int32_t VoEBaseImpl::StartPlayout() {
solenberge313e022015-09-08 02:16:04 -0700405 if (!shared_->audio_device()->Playing()) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200406 if (shared_->audio_device()->InitPlayout() != 0) {
407 LOG_F(LS_ERROR) << "Failed to initialize playout";
408 return -1;
409 }
henrika90bace02017-10-31 12:53:48 +0100410 if (playout_enabled_ && shared_->audio_device()->StartPlayout() != 0) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200411 LOG_F(LS_ERROR) << "Failed to start playout";
412 return -1;
413 }
414 }
415 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000416}
417
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000418int32_t VoEBaseImpl::StopPlayout() {
henrika90bace02017-10-31 12:53:48 +0100419 if (!playout_enabled_) {
420 return 0;
421 }
422 // Stop audio-device playing if no channel is playing out.
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200423 if (shared_->NumOfPlayingChannels() == 0) {
424 if (shared_->audio_device()->StopPlayout() != 0) {
solenberg1c239d42017-09-29 06:00:28 -0700425 LOG(LS_ERROR) << "StopPlayout() failed to stop playout";
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000426 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000427 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000428 }
429 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000430}
431
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200432int32_t VoEBaseImpl::StartSend() {
henrika90bace02017-10-31 12:53:48 +0100433 if (!shared_->audio_device()->Recording()) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200434 if (shared_->audio_device()->InitRecording() != 0) {
435 LOG_F(LS_ERROR) << "Failed to initialize recording";
436 return -1;
437 }
henrika90bace02017-10-31 12:53:48 +0100438 if (recording_enabled_ && shared_->audio_device()->StartRecording() != 0) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200439 LOG_F(LS_ERROR) << "Failed to start recording";
440 return -1;
441 }
442 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200443 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000444}
445
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200446int32_t VoEBaseImpl::StopSend() {
henrika90bace02017-10-31 12:53:48 +0100447 if (!recording_enabled_) {
448 return 0;
449 }
450 // Stop audio-device recording if no channel is recording.
solenbergb63310a2017-09-18 03:04:12 -0700451 if (shared_->NumOfSendingChannels() == 0) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200452 if (shared_->audio_device()->StopRecording() != 0) {
solenberg1c239d42017-09-29 06:00:28 -0700453 LOG(LS_ERROR) << "StopSend() failed to stop recording";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200454 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000455 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200456 shared_->transmit_mixer()->StopSend();
457 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000458
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200459 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000460}
461
henrika90bace02017-10-31 12:53:48 +0100462int32_t VoEBaseImpl::SetPlayout(bool enabled) {
463 LOG(INFO) << "SetPlayout(" << enabled << ")";
464 if (playout_enabled_ == enabled) {
465 return 0;
466 }
467 playout_enabled_ = enabled;
468 if (shared_->NumOfPlayingChannels() == 0) {
469 // If there are no channels attempting to play out yet, there's nothing to
470 // be done; we should be in a "not playing out" state either way.
471 return 0;
472 }
473 int32_t ret;
474 if (enabled) {
475 ret = shared_->audio_device()->StartPlayout();
476 if (ret != 0) {
477 LOG(LS_ERROR) << "SetPlayout(true) failed to start playout";
478 }
479 } else {
480 ret = shared_->audio_device()->StopPlayout();
481 if (ret != 0) {
482 LOG(LS_ERROR) << "SetPlayout(false) failed to stop playout";
483 }
484 }
485 return ret;
486}
487
488int32_t VoEBaseImpl::SetRecording(bool enabled) {
489 LOG(INFO) << "SetRecording(" << enabled << ")";
490 if (recording_enabled_ == enabled) {
491 return 0;
492 }
493 recording_enabled_ = enabled;
494 if (shared_->NumOfSendingChannels() == 0) {
495 // If there are no channels attempting to record out yet, there's nothing to
496 // be done; we should be in a "not recording" state either way.
497 return 0;
498 }
499 int32_t ret;
500 if (enabled) {
501 ret = shared_->audio_device()->StartRecording();
502 if (ret != 0) {
503 LOG(LS_ERROR) << "SetRecording(true) failed to start recording";
504 }
505 } else {
506 ret = shared_->audio_device()->StopRecording();
507 if (ret != 0) {
508 LOG(LS_ERROR) << "SetRecording(false) failed to stop recording";
509 }
510 }
511 return ret;
512}
513
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200514int32_t VoEBaseImpl::TerminateInternal() {
515 // Delete any remaining channel objects
516 shared_->channel_manager().DestroyAllChannels();
niklase@google.com470e71d2011-07-07 08:21:25 +0000517
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200518 if (shared_->process_thread()) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200519 shared_->process_thread()->Stop();
520 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000521
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200522 if (shared_->audio_device()) {
523 if (shared_->audio_device()->StopPlayout() != 0) {
solenberg1c239d42017-09-29 06:00:28 -0700524 LOG(LS_ERROR) << "TerminateInternal() failed to stop playout";
niklase@google.com470e71d2011-07-07 08:21:25 +0000525 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200526 if (shared_->audio_device()->StopRecording() != 0) {
solenberg1c239d42017-09-29 06:00:28 -0700527 LOG(LS_ERROR) << "TerminateInternal() failed to stop recording";
niklase@google.com470e71d2011-07-07 08:21:25 +0000528 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200529 if (shared_->audio_device()->RegisterAudioCallback(nullptr) != 0) {
solenberg1c239d42017-09-29 06:00:28 -0700530 LOG(LS_ERROR) << "TerminateInternal() failed to de-register audio "
531 "callback for the ADM";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200532 }
533 if (shared_->audio_device()->Terminate() != 0) {
solenberg1c239d42017-09-29 06:00:28 -0700534 LOG(LS_ERROR) << "TerminateInternal() failed to terminate the ADM";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200535 }
536 shared_->set_audio_device(nullptr);
537 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000538
peaha9cc40b2017-06-29 08:32:09 -0700539 shared_->set_audio_processing(nullptr);
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200540
solenberg1c239d42017-09-29 06:00:28 -0700541 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000542}
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000543} // namespace webrtc