blob: 9848557cbc631d01066631c8131188b0c82a11fc [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 "common_audio/signal_processing/include/signal_processing_library.h"
14#include "modules/audio_coding/include/audio_coding_module.h"
15#include "modules/audio_device/audio_device_impl.h"
16#include "modules/audio_processing/include/audio_processing.h"
17#include "rtc_base/format_macros.h"
18#include "rtc_base/location.h"
19#include "rtc_base/logging.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020020#include "voice_engine/channel.h"
21#include "voice_engine/include/voe_errors.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020022#include "voice_engine/transmit_mixer.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020023#include "voice_engine/voice_engine_impl.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000024
Jelena Marusic2dd6a272015-04-14 09:47:00 +020025namespace webrtc {
niklase@google.com470e71d2011-07-07 08:21:25 +000026
Jelena Marusic2dd6a272015-04-14 09:47:00 +020027VoEBase* VoEBase::GetInterface(VoiceEngine* voiceEngine) {
28 if (nullptr == voiceEngine) {
29 return nullptr;
30 }
31 VoiceEngineImpl* s = static_cast<VoiceEngineImpl*>(voiceEngine);
32 s->AddRef();
33 return s;
niklase@google.com470e71d2011-07-07 08:21:25 +000034}
35
Jelena Marusic2dd6a272015-04-14 09:47:00 +020036VoEBaseImpl::VoEBaseImpl(voe::SharedData* shared)
solenbergfc3a2e32017-09-26 09:35:01 -070037 : shared_(shared) {}
Jelena Marusic2dd6a272015-04-14 09:47:00 +020038
39VoEBaseImpl::~VoEBaseImpl() {
40 TerminateInternal();
niklase@google.com470e71d2011-07-07 08:21:25 +000041}
42
henrikaec6fbd22017-03-31 05:43:36 -070043int32_t VoEBaseImpl::RecordedDataIsAvailable(
44 const void* audio_data,
45 const size_t number_of_frames,
46 const size_t bytes_per_sample,
47 const size_t number_of_channels,
48 const uint32_t sample_rate,
49 const uint32_t audio_delay_milliseconds,
50 const int32_t clock_drift,
51 const uint32_t volume,
52 const bool key_pressed,
53 uint32_t& new_mic_volume) {
54 RTC_DCHECK_EQ(2 * number_of_channels, bytes_per_sample);
55 RTC_DCHECK(shared_->transmit_mixer() != nullptr);
56 RTC_DCHECK(shared_->audio_device() != nullptr);
57
58 uint32_t max_volume = 0;
59 uint16_t voe_mic_level = 0;
60 // Check for zero to skip this calculation; the consumer may use this to
61 // indicate no volume is available.
62 if (volume != 0) {
63 // Scale from ADM to VoE level range
64 if (shared_->audio_device()->MaxMicrophoneVolume(&max_volume) == 0) {
65 if (max_volume) {
66 voe_mic_level = static_cast<uint16_t>(
67 (volume * kMaxVolumeLevel + static_cast<int>(max_volume / 2)) /
68 max_volume);
69 }
70 }
71 // We learned that on certain systems (e.g Linux) the voe_mic_level
72 // can be greater than the maxVolumeLevel therefore
73 // we are going to cap the voe_mic_level to the maxVolumeLevel
74 // and change the maxVolume to volume if it turns out that
75 // the voe_mic_level is indeed greater than the maxVolumeLevel.
76 if (voe_mic_level > kMaxVolumeLevel) {
77 voe_mic_level = kMaxVolumeLevel;
78 max_volume = volume;
79 }
80 }
81
82 // Perform channel-independent operations
83 // (APM, mix with file, record to file, mute, etc.)
84 shared_->transmit_mixer()->PrepareDemux(
85 audio_data, number_of_frames, number_of_channels, sample_rate,
86 static_cast<uint16_t>(audio_delay_milliseconds), clock_drift,
87 voe_mic_level, key_pressed);
88
89 // Copy the audio frame to each sending channel and perform
90 // channel-dependent operations (file mixing, mute, etc.), encode and
91 // packetize+transmit the RTP packet.
92 shared_->transmit_mixer()->ProcessAndEncodeAudio();
93
94 // Scale from VoE to ADM level range.
95 uint32_t new_voe_mic_level = shared_->transmit_mixer()->CaptureLevel();
96 if (new_voe_mic_level != voe_mic_level) {
97 // Return the new volume if AGC has changed the volume.
98 return static_cast<int>((new_voe_mic_level * max_volume +
99 static_cast<int>(kMaxVolumeLevel / 2)) /
100 kMaxVolumeLevel);
101 }
102
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200103 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000104}
105
solenberg13725082015-11-25 08:16:52 -0800106int32_t VoEBaseImpl::NeedMorePlayData(const size_t nSamples,
107 const size_t nBytesPerSample,
Peter Kasting69558702016-01-12 16:26:35 -0800108 const size_t nChannels,
solenberg13725082015-11-25 08:16:52 -0800109 const uint32_t samplesPerSec,
110 void* audioSamples,
111 size_t& nSamplesOut,
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200112 int64_t* elapsed_time_ms,
113 int64_t* ntp_time_ms) {
solenberg2397b9a2017-09-22 06:48:10 -0700114 RTC_NOTREACHED();
xians@webrtc.org56925312014-04-14 10:50:37 +0000115 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000116}
117
xians@webrtc.org56925312014-04-14 10:50:37 +0000118void VoEBaseImpl::PushCaptureData(int voe_channel, const void* audio_data,
119 int bits_per_sample, int sample_rate,
Peter Kasting69558702016-01-12 16:26:35 -0800120 size_t number_of_channels,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700121 size_t number_of_frames) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200122 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(voe_channel);
henrikaec6fbd22017-03-31 05:43:36 -0700123 voe::Channel* channel = ch.channel();
124 if (!channel)
125 return;
126 if (channel->Sending()) {
127 // Send the audio to each channel directly without using the APM in the
128 // transmit mixer.
129 channel->ProcessAndEncodeAudio(static_cast<const int16_t*>(audio_data),
130 sample_rate, number_of_frames,
131 number_of_channels);
xians@webrtc.org07e51962014-01-29 13:54:02 +0000132 }
133}
134
Peter Kastingdce40cf2015-08-24 14:52:23 -0700135void VoEBaseImpl::PullRenderData(int bits_per_sample,
136 int sample_rate,
Peter Kasting69558702016-01-12 16:26:35 -0800137 size_t number_of_channels,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700138 size_t number_of_frames,
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200139 void* audio_data, int64_t* elapsed_time_ms,
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000140 int64_t* ntp_time_ms) {
solenberg2397b9a2017-09-22 06:48:10 -0700141 RTC_NOTREACHED();
xians@webrtc.org56925312014-04-14 10:50:37 +0000142}
143
ossu5f7cfa52016-05-30 08:11:28 -0700144int VoEBaseImpl::Init(
145 AudioDeviceModule* external_adm,
peahe67bedb2017-07-07 04:25:11 -0700146 AudioProcessing* audio_processing,
ossu5f7cfa52016-05-30 08:11:28 -0700147 const rtc::scoped_refptr<AudioDecoderFactory>& decoder_factory) {
peahe67bedb2017-07-07 04:25:11 -0700148 RTC_DCHECK(audio_processing);
tommi31fc21f2016-01-21 10:37:37 -0800149 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200150 WebRtcSpl_Init();
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200151 if (shared_->process_thread()) {
152 shared_->process_thread()->Start();
153 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000154
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200155 // Create an internal ADM if the user has not added an external
156 // ADM implementation as input to Init().
157 if (external_adm == nullptr) {
Tommi931e6582015-05-20 09:44:38 +0200158#if !defined(WEBRTC_INCLUDE_INTERNAL_AUDIO_DEVICE)
159 return -1;
160#else
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200161 // Create the internal ADM implementation.
Peter Boström4adbbcf2016-05-03 15:51:26 -0400162 shared_->set_audio_device(AudioDeviceModule::Create(
solenberg5b3e49a2017-03-15 08:08:07 -0700163 AudioDeviceModule::kPlatformDefaultAudio));
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200164 if (shared_->audio_device() == nullptr) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100165 RTC_LOG(LS_ERROR) << "Init() failed to create the ADM";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200166 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000167 }
Tommi931e6582015-05-20 09:44:38 +0200168#endif // WEBRTC_INCLUDE_INTERNAL_AUDIO_DEVICE
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200169 } else {
170 // Use the already existing external ADM implementation.
171 shared_->set_audio_device(external_adm);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100172 RTC_LOG_F(LS_INFO)
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200173 << "An external ADM implementation will be used in VoiceEngine";
174 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000175
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200176 bool available = false;
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000177
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200178 // --------------------
179 // Reinitialize the ADM
henrika@google.com73d65512011-09-07 15:11:18 +0000180
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200181 // Register the AudioTransport implementation
182 if (shared_->audio_device()->RegisterAudioCallback(this) != 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100183 RTC_LOG(LS_ERROR) << "Init() failed to register audio callback for the ADM";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200184 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000185
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200186 // ADM initialization
187 if (shared_->audio_device()->Init() != 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100188 RTC_LOG(LS_ERROR) << "Init() failed to initialize the ADM";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200189 return -1;
190 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000191
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200192 // Initialize the default speaker
193 if (shared_->audio_device()->SetPlayoutDevice(
194 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100195 RTC_LOG(LS_ERROR) << "Init() failed to set the default output device";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200196 }
197 if (shared_->audio_device()->InitSpeaker() != 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100198 RTC_LOG(LS_ERROR) << "Init() failed to initialize the speaker";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200199 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000200
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200201 // Initialize the default microphone
202 if (shared_->audio_device()->SetRecordingDevice(
203 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100204 RTC_LOG(LS_ERROR) << "Init() failed to set the default input device";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200205 }
206 if (shared_->audio_device()->InitMicrophone() != 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100207 RTC_LOG(LS_ERROR) << "Init() failed to initialize the microphone";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200208 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000209
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200210 // Set number of channels
211 if (shared_->audio_device()->StereoPlayoutIsAvailable(&available) != 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100212 RTC_LOG(LS_ERROR) << "Init() failed to query stereo playout mode";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200213 }
214 if (shared_->audio_device()->SetStereoPlayout(available) != 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100215 RTC_LOG(LS_ERROR) << "Init() failed to set mono/stereo playout mode";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200216 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000217
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200218 // TODO(andrew): These functions don't tell us whether stereo recording
219 // is truly available. We simply set the AudioProcessing input to stereo
220 // here, because we have to wait until receiving the first frame to
221 // determine the actual number of channels anyway.
222 //
223 // These functions may be changed; tracked here:
224 // http://code.google.com/p/webrtc/issues/detail?id=204
225 shared_->audio_device()->StereoRecordingIsAvailable(&available);
226 if (shared_->audio_device()->SetStereoRecording(available) != 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100227 RTC_LOG(LS_ERROR) << "Init() failed to set mono/stereo recording mode";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200228 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000229
peahe67bedb2017-07-07 04:25:11 -0700230 shared_->set_audio_processing(audio_processing);
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000231
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200232 // Configure AudioProcessing components.
peaha9cc40b2017-06-29 08:32:09 -0700233 // TODO(peah): Move this initialization to webrtcvoiceengine.cc.
peahe67bedb2017-07-07 04:25:11 -0700234 if (audio_processing->high_pass_filter()->Enable(true) != 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100235 RTC_LOG_F(LS_ERROR) << "Failed to enable high pass filter.";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200236 return -1;
237 }
peahe67bedb2017-07-07 04:25:11 -0700238 if (audio_processing->echo_cancellation()->enable_drift_compensation(false) !=
239 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100240 RTC_LOG_F(LS_ERROR) << "Failed to disable drift compensation.";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200241 return -1;
242 }
peahe67bedb2017-07-07 04:25:11 -0700243 if (audio_processing->noise_suppression()->set_level(kDefaultNsMode) != 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100244 RTC_LOG_F(LS_ERROR) << "Failed to set noise suppression level: "
245 << kDefaultNsMode;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200246 return -1;
247 }
peahe67bedb2017-07-07 04:25:11 -0700248 GainControl* agc = audio_processing->gain_control();
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200249 if (agc->set_analog_level_limits(kMinVolumeLevel, kMaxVolumeLevel) != 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100250 RTC_LOG_F(LS_ERROR) << "Failed to set analog level limits with minimum: "
251 << kMinVolumeLevel
252 << " and maximum: " << kMaxVolumeLevel;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200253 return -1;
254 }
255 if (agc->set_mode(kDefaultAgcMode) != 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100256 RTC_LOG_F(LS_ERROR) << "Failed to set mode: " << kDefaultAgcMode;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200257 return -1;
258 }
259 if (agc->Enable(kDefaultAgcState) != 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100260 RTC_LOG_F(LS_ERROR) << "Failed to set agc state: " << kDefaultAgcState;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200261 return -1;
262 }
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000263
niklase@google.com470e71d2011-07-07 08:21:25 +0000264#ifdef WEBRTC_VOICE_ENGINE_AGC
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200265 bool agc_enabled =
266 agc->mode() == GainControl::kAdaptiveAnalog && agc->is_enabled();
267 if (shared_->audio_device()->SetAGC(agc_enabled) != 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100268 RTC_LOG_F(LS_ERROR) << "Failed to set agc to enabled: " << agc_enabled;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200269 // TODO(ajm): No error return here due to
270 // https://code.google.com/p/webrtc/issues/detail?id=1464
271 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000272#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000273
Karl Wibergf3850f62017-11-02 13:04:41 +0100274 RTC_DCHECK(decoder_factory);
275 decoder_factory_ = decoder_factory;
ossu5f7cfa52016-05-30 08:11:28 -0700276
solenberg1c239d42017-09-29 06:00:28 -0700277 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000278}
279
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200280int VoEBaseImpl::Terminate() {
tommi31fc21f2016-01-21 10:37:37 -0800281 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200282 return TerminateInternal();
niklase@google.com470e71d2011-07-07 08:21:25 +0000283}
284
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000285int VoEBaseImpl::CreateChannel() {
solenberg88499ec2016-09-07 07:34:41 -0700286 return CreateChannel(ChannelConfig());
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000287}
288
solenberg88499ec2016-09-07 07:34:41 -0700289int VoEBaseImpl::CreateChannel(const ChannelConfig& config) {
tommi31fc21f2016-01-21 10:37:37 -0800290 rtc::CritScope cs(shared_->crit_sec());
solenberg88499ec2016-09-07 07:34:41 -0700291 ChannelConfig config_copy(config);
292 config_copy.acm_config.decoder_factory = decoder_factory_;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200293 voe::ChannelOwner channel_owner =
solenberg88499ec2016-09-07 07:34:41 -0700294 shared_->channel_manager().CreateChannel(config_copy);
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000295 return InitializeChannel(&channel_owner);
296}
297
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200298int VoEBaseImpl::InitializeChannel(voe::ChannelOwner* channel_owner) {
299 if (channel_owner->channel()->SetEngineInformation(
solenberg796b8f92017-03-01 17:02:23 -0800300 *shared_->process_thread(), *shared_->audio_device(),
solenberg1c239d42017-09-29 06:00:28 -0700301 shared_->encoder_queue()) != 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100302 RTC_LOG(LS_ERROR)
303 << "CreateChannel() failed to associate engine and channel."
304 " Destroying channel.";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200305 shared_->channel_manager().DestroyChannel(
306 channel_owner->channel()->ChannelId());
307 return -1;
308 } else if (channel_owner->channel()->Init() != 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100309 RTC_LOG(LS_ERROR)
310 << "CreateChannel() failed to initialize channel. Destroying"
311 " channel.";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200312 shared_->channel_manager().DestroyChannel(
313 channel_owner->channel()->ChannelId());
314 return -1;
315 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200316 return channel_owner->channel()->ChannelId();
niklase@google.com470e71d2011-07-07 08:21:25 +0000317}
318
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200319int VoEBaseImpl::DeleteChannel(int channel) {
tommi31fc21f2016-01-21 10:37:37 -0800320 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200321 {
322 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
323 voe::Channel* channelPtr = ch.channel();
324 if (channelPtr == nullptr) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100325 RTC_LOG(LS_ERROR) << "DeleteChannel() failed to locate channel";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200326 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000327 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200328 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000329
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200330 shared_->channel_manager().DestroyChannel(channel);
331 if (StopSend() != 0) {
332 return -1;
333 }
334 if (StopPlayout() != 0) {
335 return -1;
336 }
337 return 0;
338}
niklase@google.com470e71d2011-07-07 08:21:25 +0000339
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200340int VoEBaseImpl::StartPlayout(int channel) {
tommi31fc21f2016-01-21 10:37:37 -0800341 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200342 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
343 voe::Channel* channelPtr = ch.channel();
344 if (channelPtr == nullptr) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100345 RTC_LOG(LS_ERROR) << "StartPlayout() failed to locate channel";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200346 return -1;
347 }
348 if (channelPtr->Playing()) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000349 return 0;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200350 }
351 if (StartPlayout() != 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100352 RTC_LOG(LS_ERROR) << "StartPlayout() failed to start playout";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200353 return -1;
354 }
355 return channelPtr->StartPlayout();
niklase@google.com470e71d2011-07-07 08:21:25 +0000356}
357
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200358int VoEBaseImpl::StopPlayout(int channel) {
tommi31fc21f2016-01-21 10:37:37 -0800359 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200360 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
361 voe::Channel* channelPtr = ch.channel();
362 if (channelPtr == nullptr) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100363 RTC_LOG(LS_ERROR) << "StopPlayout() failed to locate channel";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200364 return -1;
365 }
366 if (channelPtr->StopPlayout() != 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100367 RTC_LOG_F(LS_WARNING) << "StopPlayout() failed to stop playout for channel "
368 << channel;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200369 }
370 return StopPlayout();
niklase@google.com470e71d2011-07-07 08:21:25 +0000371}
372
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200373int VoEBaseImpl::StartSend(int channel) {
tommi31fc21f2016-01-21 10:37:37 -0800374 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200375 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
376 voe::Channel* channelPtr = ch.channel();
377 if (channelPtr == nullptr) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100378 RTC_LOG(LS_ERROR) << "StartSend() failed to locate channel";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200379 return -1;
380 }
381 if (channelPtr->Sending()) {
382 return 0;
383 }
384 if (StartSend() != 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100385 RTC_LOG(LS_ERROR) << "StartSend() failed to start recording";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200386 return -1;
387 }
388 return channelPtr->StartSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000389}
390
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200391int VoEBaseImpl::StopSend(int channel) {
tommi31fc21f2016-01-21 10:37:37 -0800392 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200393 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
394 voe::Channel* channelPtr = ch.channel();
395 if (channelPtr == nullptr) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100396 RTC_LOG(LS_ERROR) << "StopSend() failed to locate channel";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200397 return -1;
398 }
henrikaec6fbd22017-03-31 05:43:36 -0700399 channelPtr->StopSend();
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200400 return StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000401}
402
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200403int32_t VoEBaseImpl::StartPlayout() {
solenberge313e022015-09-08 02:16:04 -0700404 if (!shared_->audio_device()->Playing()) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200405 if (shared_->audio_device()->InitPlayout() != 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100406 RTC_LOG_F(LS_ERROR) << "Failed to initialize playout";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200407 return -1;
408 }
henrika5f6bf242017-11-01 11:06:56 +0100409 if (playout_enabled_ && shared_->audio_device()->StartPlayout() != 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100410 RTC_LOG_F(LS_ERROR) << "Failed to start playout";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200411 return -1;
412 }
413 }
414 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000415}
416
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000417int32_t VoEBaseImpl::StopPlayout() {
henrika5f6bf242017-11-01 11:06:56 +0100418 if (!playout_enabled_) {
419 return 0;
420 }
421 // Stop audio-device playing if no channel is playing out.
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200422 if (shared_->NumOfPlayingChannels() == 0) {
423 if (shared_->audio_device()->StopPlayout() != 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100424 RTC_LOG(LS_ERROR) << "StopPlayout() failed to stop playout";
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000425 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000426 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000427 }
428 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000429}
430
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200431int32_t VoEBaseImpl::StartSend() {
henrika5f6bf242017-11-01 11:06:56 +0100432 if (!shared_->audio_device()->Recording()) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200433 if (shared_->audio_device()->InitRecording() != 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100434 RTC_LOG_F(LS_ERROR) << "Failed to initialize recording";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200435 return -1;
436 }
henrika5f6bf242017-11-01 11:06:56 +0100437 if (recording_enabled_ && shared_->audio_device()->StartRecording() != 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100438 RTC_LOG_F(LS_ERROR) << "Failed to start recording";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200439 return -1;
440 }
441 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200442 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000443}
444
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200445int32_t VoEBaseImpl::StopSend() {
henrika5f6bf242017-11-01 11:06:56 +0100446 if (!recording_enabled_) {
447 return 0;
448 }
449 // Stop audio-device recording if no channel is recording.
solenbergb63310a2017-09-18 03:04:12 -0700450 if (shared_->NumOfSendingChannels() == 0) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200451 if (shared_->audio_device()->StopRecording() != 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100452 RTC_LOG(LS_ERROR) << "StopSend() failed to stop recording";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200453 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000454 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200455 shared_->transmit_mixer()->StopSend();
456 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000457
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200458 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000459}
460
henrika5f6bf242017-11-01 11:06:56 +0100461int32_t VoEBaseImpl::SetPlayout(bool enabled) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100462 RTC_LOG(INFO) << "SetPlayout(" << enabled << ")";
henrika5f6bf242017-11-01 11:06:56 +0100463 if (playout_enabled_ == enabled) {
464 return 0;
465 }
466 playout_enabled_ = enabled;
467 if (shared_->NumOfPlayingChannels() == 0) {
468 // If there are no channels attempting to play out yet, there's nothing to
469 // be done; we should be in a "not playing out" state either way.
470 return 0;
471 }
472 int32_t ret;
473 if (enabled) {
474 ret = shared_->audio_device()->StartPlayout();
475 if (ret != 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100476 RTC_LOG(LS_ERROR) << "SetPlayout(true) failed to start playout";
henrika5f6bf242017-11-01 11:06:56 +0100477 }
478 } else {
479 ret = shared_->audio_device()->StopPlayout();
480 if (ret != 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100481 RTC_LOG(LS_ERROR) << "SetPlayout(false) failed to stop playout";
henrika5f6bf242017-11-01 11:06:56 +0100482 }
483 }
484 return ret;
485}
486
487int32_t VoEBaseImpl::SetRecording(bool enabled) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100488 RTC_LOG(INFO) << "SetRecording(" << enabled << ")";
henrika5f6bf242017-11-01 11:06:56 +0100489 if (recording_enabled_ == enabled) {
490 return 0;
491 }
492 recording_enabled_ = enabled;
493 if (shared_->NumOfSendingChannels() == 0) {
494 // If there are no channels attempting to record out yet, there's nothing to
495 // be done; we should be in a "not recording" state either way.
496 return 0;
497 }
498 int32_t ret;
499 if (enabled) {
500 ret = shared_->audio_device()->StartRecording();
501 if (ret != 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100502 RTC_LOG(LS_ERROR) << "SetRecording(true) failed to start recording";
henrika5f6bf242017-11-01 11:06:56 +0100503 }
504 } else {
505 ret = shared_->audio_device()->StopRecording();
506 if (ret != 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100507 RTC_LOG(LS_ERROR) << "SetRecording(false) failed to stop recording";
henrika5f6bf242017-11-01 11:06:56 +0100508 }
509 }
510 return ret;
511}
512
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200513int32_t VoEBaseImpl::TerminateInternal() {
514 // Delete any remaining channel objects
515 shared_->channel_manager().DestroyAllChannels();
niklase@google.com470e71d2011-07-07 08:21:25 +0000516
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200517 if (shared_->process_thread()) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200518 shared_->process_thread()->Stop();
519 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000520
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200521 if (shared_->audio_device()) {
522 if (shared_->audio_device()->StopPlayout() != 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100523 RTC_LOG(LS_ERROR) << "TerminateInternal() failed to stop playout";
niklase@google.com470e71d2011-07-07 08:21:25 +0000524 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200525 if (shared_->audio_device()->StopRecording() != 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100526 RTC_LOG(LS_ERROR) << "TerminateInternal() failed to stop recording";
niklase@google.com470e71d2011-07-07 08:21:25 +0000527 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200528 if (shared_->audio_device()->RegisterAudioCallback(nullptr) != 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100529 RTC_LOG(LS_ERROR) << "TerminateInternal() failed to de-register audio "
530 "callback for the ADM";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200531 }
532 if (shared_->audio_device()->Terminate() != 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100533 RTC_LOG(LS_ERROR) << "TerminateInternal() failed to terminate the ADM";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200534 }
535 shared_->set_audio_device(nullptr);
536 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000537
peaha9cc40b2017-06-29 08:32:09 -0700538 shared_->set_audio_processing(nullptr);
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200539
solenberg1c239d42017-09-29 06:00:28 -0700540 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000541}
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000542} // namespace webrtc