blob: b4c2b7a98313216392888b49676dc403a01fd69f [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
solenberg13725082015-11-25 08:16:52 -080044void VoEBaseImpl::OnErrorIsReported(const ErrorCode error) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +020045 if (error == AudioDeviceObserver::kRecordingError) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +020046 LOG_F(LS_ERROR) << "VE_RUNTIME_REC_ERROR";
47 } else if (error == AudioDeviceObserver::kPlayoutError) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +020048 LOG_F(LS_ERROR) << "VE_RUNTIME_PLAY_ERROR";
49 }
niklase@google.com470e71d2011-07-07 08:21:25 +000050}
51
solenberg13725082015-11-25 08:16:52 -080052void VoEBaseImpl::OnWarningIsReported(const WarningCode warning) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +020053 if (warning == AudioDeviceObserver::kRecordingWarning) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +020054 LOG_F(LS_WARNING) << "VE_RUNTIME_REC_WARNING";
55 } else if (warning == AudioDeviceObserver::kPlayoutWarning) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +020056 LOG_F(LS_WARNING) << "VE_RUNTIME_PLAY_WARNING";
57 }
niklase@google.com470e71d2011-07-07 08:21:25 +000058}
59
henrikaec6fbd22017-03-31 05:43:36 -070060int32_t VoEBaseImpl::RecordedDataIsAvailable(
61 const void* audio_data,
62 const size_t number_of_frames,
63 const size_t bytes_per_sample,
64 const size_t number_of_channels,
65 const uint32_t sample_rate,
66 const uint32_t audio_delay_milliseconds,
67 const int32_t clock_drift,
68 const uint32_t volume,
69 const bool key_pressed,
70 uint32_t& new_mic_volume) {
71 RTC_DCHECK_EQ(2 * number_of_channels, bytes_per_sample);
72 RTC_DCHECK(shared_->transmit_mixer() != nullptr);
73 RTC_DCHECK(shared_->audio_device() != nullptr);
74
75 uint32_t max_volume = 0;
76 uint16_t voe_mic_level = 0;
77 // Check for zero to skip this calculation; the consumer may use this to
78 // indicate no volume is available.
79 if (volume != 0) {
80 // Scale from ADM to VoE level range
81 if (shared_->audio_device()->MaxMicrophoneVolume(&max_volume) == 0) {
82 if (max_volume) {
83 voe_mic_level = static_cast<uint16_t>(
84 (volume * kMaxVolumeLevel + static_cast<int>(max_volume / 2)) /
85 max_volume);
86 }
87 }
88 // We learned that on certain systems (e.g Linux) the voe_mic_level
89 // can be greater than the maxVolumeLevel therefore
90 // we are going to cap the voe_mic_level to the maxVolumeLevel
91 // and change the maxVolume to volume if it turns out that
92 // the voe_mic_level is indeed greater than the maxVolumeLevel.
93 if (voe_mic_level > kMaxVolumeLevel) {
94 voe_mic_level = kMaxVolumeLevel;
95 max_volume = volume;
96 }
97 }
98
99 // Perform channel-independent operations
100 // (APM, mix with file, record to file, mute, etc.)
101 shared_->transmit_mixer()->PrepareDemux(
102 audio_data, number_of_frames, number_of_channels, sample_rate,
103 static_cast<uint16_t>(audio_delay_milliseconds), clock_drift,
104 voe_mic_level, key_pressed);
105
106 // Copy the audio frame to each sending channel and perform
107 // channel-dependent operations (file mixing, mute, etc.), encode and
108 // packetize+transmit the RTP packet.
109 shared_->transmit_mixer()->ProcessAndEncodeAudio();
110
111 // Scale from VoE to ADM level range.
112 uint32_t new_voe_mic_level = shared_->transmit_mixer()->CaptureLevel();
113 if (new_voe_mic_level != voe_mic_level) {
114 // Return the new volume if AGC has changed the volume.
115 return static_cast<int>((new_voe_mic_level * max_volume +
116 static_cast<int>(kMaxVolumeLevel / 2)) /
117 kMaxVolumeLevel);
118 }
119
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200120 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000121}
122
solenberg13725082015-11-25 08:16:52 -0800123int32_t VoEBaseImpl::NeedMorePlayData(const size_t nSamples,
124 const size_t nBytesPerSample,
Peter Kasting69558702016-01-12 16:26:35 -0800125 const size_t nChannels,
solenberg13725082015-11-25 08:16:52 -0800126 const uint32_t samplesPerSec,
127 void* audioSamples,
128 size_t& nSamplesOut,
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200129 int64_t* elapsed_time_ms,
130 int64_t* ntp_time_ms) {
solenberg2397b9a2017-09-22 06:48:10 -0700131 RTC_NOTREACHED();
xians@webrtc.org56925312014-04-14 10:50:37 +0000132 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000133}
134
xians@webrtc.org56925312014-04-14 10:50:37 +0000135void VoEBaseImpl::PushCaptureData(int voe_channel, const void* audio_data,
136 int bits_per_sample, 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 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(voe_channel);
henrikaec6fbd22017-03-31 05:43:36 -0700140 voe::Channel* channel = ch.channel();
141 if (!channel)
142 return;
143 if (channel->Sending()) {
144 // Send the audio to each channel directly without using the APM in the
145 // transmit mixer.
146 channel->ProcessAndEncodeAudio(static_cast<const int16_t*>(audio_data),
147 sample_rate, number_of_frames,
148 number_of_channels);
xians@webrtc.org07e51962014-01-29 13:54:02 +0000149 }
150}
151
Peter Kastingdce40cf2015-08-24 14:52:23 -0700152void VoEBaseImpl::PullRenderData(int bits_per_sample,
153 int sample_rate,
Peter Kasting69558702016-01-12 16:26:35 -0800154 size_t number_of_channels,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700155 size_t number_of_frames,
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200156 void* audio_data, int64_t* elapsed_time_ms,
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000157 int64_t* ntp_time_ms) {
solenberg2397b9a2017-09-22 06:48:10 -0700158 RTC_NOTREACHED();
xians@webrtc.org56925312014-04-14 10:50:37 +0000159}
160
ossu5f7cfa52016-05-30 08:11:28 -0700161int VoEBaseImpl::Init(
162 AudioDeviceModule* external_adm,
peahe67bedb2017-07-07 04:25:11 -0700163 AudioProcessing* audio_processing,
ossu5f7cfa52016-05-30 08:11:28 -0700164 const rtc::scoped_refptr<AudioDecoderFactory>& decoder_factory) {
peahe67bedb2017-07-07 04:25:11 -0700165 RTC_DCHECK(audio_processing);
tommi31fc21f2016-01-21 10:37:37 -0800166 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200167 WebRtcSpl_Init();
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200168 if (shared_->process_thread()) {
169 shared_->process_thread()->Start();
170 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000171
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200172 // Create an internal ADM if the user has not added an external
173 // ADM implementation as input to Init().
174 if (external_adm == nullptr) {
Tommi931e6582015-05-20 09:44:38 +0200175#if !defined(WEBRTC_INCLUDE_INTERNAL_AUDIO_DEVICE)
176 return -1;
177#else
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200178 // Create the internal ADM implementation.
Peter Boström4adbbcf2016-05-03 15:51:26 -0400179 shared_->set_audio_device(AudioDeviceModule::Create(
solenberg5b3e49a2017-03-15 08:08:07 -0700180 VoEId(shared_->instance_id(), -1),
181 AudioDeviceModule::kPlatformDefaultAudio));
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200182 if (shared_->audio_device() == nullptr) {
solenberg1c239d42017-09-29 06:00:28 -0700183 LOG(LS_ERROR) << "Init() failed to create the ADM";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200184 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000185 }
Tommi931e6582015-05-20 09:44:38 +0200186#endif // WEBRTC_INCLUDE_INTERNAL_AUDIO_DEVICE
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200187 } else {
188 // Use the already existing external ADM implementation.
189 shared_->set_audio_device(external_adm);
190 LOG_F(LS_INFO)
191 << "An external ADM implementation will be used in VoiceEngine";
192 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000193
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200194 // Register the ADM to the process thread, which will drive the error
195 // callback mechanism
196 if (shared_->process_thread()) {
tommidea489f2017-03-03 03:20:24 -0800197 shared_->process_thread()->RegisterModule(shared_->audio_device(),
198 RTC_FROM_HERE);
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 bool available = false;
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000202
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200203 // --------------------
204 // Reinitialize the ADM
henrika@google.com73d65512011-09-07 15:11:18 +0000205
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200206 // Register the AudioObserver implementation
207 if (shared_->audio_device()->RegisterEventObserver(this) != 0) {
solenberg1c239d42017-09-29 06:00:28 -0700208 LOG(LS_ERROR) << "Init() failed to register event observer for the ADM";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200209 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000210
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200211 // Register the AudioTransport implementation
212 if (shared_->audio_device()->RegisterAudioCallback(this) != 0) {
solenberg1c239d42017-09-29 06:00:28 -0700213 LOG(LS_ERROR) << "Init() failed to register audio callback for the ADM";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200214 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000215
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200216 // ADM initialization
217 if (shared_->audio_device()->Init() != 0) {
solenberg1c239d42017-09-29 06:00:28 -0700218 LOG(LS_ERROR) << "Init() failed to initialize the ADM";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200219 return -1;
220 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000221
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200222 // Initialize the default speaker
223 if (shared_->audio_device()->SetPlayoutDevice(
224 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0) {
solenberg1c239d42017-09-29 06:00:28 -0700225 LOG(LS_ERROR) << "Init() failed to set the default output device";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200226 }
227 if (shared_->audio_device()->InitSpeaker() != 0) {
solenberg1c239d42017-09-29 06:00:28 -0700228 LOG(LS_ERROR) << "Init() failed to initialize the speaker";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200229 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000230
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200231 // Initialize the default microphone
232 if (shared_->audio_device()->SetRecordingDevice(
233 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0) {
solenberg1c239d42017-09-29 06:00:28 -0700234 LOG(LS_ERROR) << "Init() failed to set the default input device";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200235 }
236 if (shared_->audio_device()->InitMicrophone() != 0) {
solenberg1c239d42017-09-29 06:00:28 -0700237 LOG(LS_ERROR) << "Init() failed to initialize the microphone";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200238 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000239
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200240 // Set number of channels
241 if (shared_->audio_device()->StereoPlayoutIsAvailable(&available) != 0) {
solenberg1c239d42017-09-29 06:00:28 -0700242 LOG(LS_ERROR) << "Init() failed to query stereo playout mode";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200243 }
244 if (shared_->audio_device()->SetStereoPlayout(available) != 0) {
solenberg1c239d42017-09-29 06:00:28 -0700245 LOG(LS_ERROR) << "Init() failed to set mono/stereo playout mode";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200246 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000247
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200248 // TODO(andrew): These functions don't tell us whether stereo recording
249 // is truly available. We simply set the AudioProcessing input to stereo
250 // here, because we have to wait until receiving the first frame to
251 // determine the actual number of channels anyway.
252 //
253 // These functions may be changed; tracked here:
254 // http://code.google.com/p/webrtc/issues/detail?id=204
255 shared_->audio_device()->StereoRecordingIsAvailable(&available);
256 if (shared_->audio_device()->SetStereoRecording(available) != 0) {
solenberg1c239d42017-09-29 06:00:28 -0700257 LOG(LS_ERROR) << "Init() failed to set mono/stereo recording mode";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200258 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000259
peahe67bedb2017-07-07 04:25:11 -0700260 shared_->set_audio_processing(audio_processing);
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000261
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200262 // Configure AudioProcessing components.
peaha9cc40b2017-06-29 08:32:09 -0700263 // TODO(peah): Move this initialization to webrtcvoiceengine.cc.
peahe67bedb2017-07-07 04:25:11 -0700264 if (audio_processing->high_pass_filter()->Enable(true) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200265 LOG_F(LS_ERROR) << "Failed to enable high pass filter.";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200266 return -1;
267 }
peahe67bedb2017-07-07 04:25:11 -0700268 if (audio_processing->echo_cancellation()->enable_drift_compensation(false) !=
269 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200270 LOG_F(LS_ERROR) << "Failed to disable drift compensation.";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200271 return -1;
272 }
peahe67bedb2017-07-07 04:25:11 -0700273 if (audio_processing->noise_suppression()->set_level(kDefaultNsMode) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200274 LOG_F(LS_ERROR) << "Failed to set noise suppression level: "
275 << kDefaultNsMode;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200276 return -1;
277 }
peahe67bedb2017-07-07 04:25:11 -0700278 GainControl* agc = audio_processing->gain_control();
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200279 if (agc->set_analog_level_limits(kMinVolumeLevel, kMaxVolumeLevel) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200280 LOG_F(LS_ERROR) << "Failed to set analog level limits with minimum: "
281 << kMinVolumeLevel << " and maximum: " << kMaxVolumeLevel;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200282 return -1;
283 }
284 if (agc->set_mode(kDefaultAgcMode) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200285 LOG_F(LS_ERROR) << "Failed to set mode: " << kDefaultAgcMode;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200286 return -1;
287 }
288 if (agc->Enable(kDefaultAgcState) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200289 LOG_F(LS_ERROR) << "Failed to set agc state: " << kDefaultAgcState;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200290 return -1;
291 }
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000292
niklase@google.com470e71d2011-07-07 08:21:25 +0000293#ifdef WEBRTC_VOICE_ENGINE_AGC
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200294 bool agc_enabled =
295 agc->mode() == GainControl::kAdaptiveAnalog && agc->is_enabled();
296 if (shared_->audio_device()->SetAGC(agc_enabled) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200297 LOG_F(LS_ERROR) << "Failed to set agc to enabled: " << agc_enabled;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200298 // TODO(ajm): No error return here due to
299 // https://code.google.com/p/webrtc/issues/detail?id=1464
300 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000301#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000302
ossu5f7cfa52016-05-30 08:11:28 -0700303 if (decoder_factory)
304 decoder_factory_ = decoder_factory;
305 else
306 decoder_factory_ = CreateBuiltinAudioDecoderFactory();
307
solenberg1c239d42017-09-29 06:00:28 -0700308 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000309}
310
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200311int VoEBaseImpl::Terminate() {
tommi31fc21f2016-01-21 10:37:37 -0800312 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200313 return TerminateInternal();
niklase@google.com470e71d2011-07-07 08:21:25 +0000314}
315
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000316int VoEBaseImpl::CreateChannel() {
solenberg88499ec2016-09-07 07:34:41 -0700317 return CreateChannel(ChannelConfig());
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000318}
319
solenberg88499ec2016-09-07 07:34:41 -0700320int VoEBaseImpl::CreateChannel(const ChannelConfig& config) {
tommi31fc21f2016-01-21 10:37:37 -0800321 rtc::CritScope cs(shared_->crit_sec());
solenberg88499ec2016-09-07 07:34:41 -0700322 ChannelConfig config_copy(config);
323 config_copy.acm_config.decoder_factory = decoder_factory_;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200324 voe::ChannelOwner channel_owner =
solenberg88499ec2016-09-07 07:34:41 -0700325 shared_->channel_manager().CreateChannel(config_copy);
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000326 return InitializeChannel(&channel_owner);
327}
328
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200329int VoEBaseImpl::InitializeChannel(voe::ChannelOwner* channel_owner) {
330 if (channel_owner->channel()->SetEngineInformation(
solenberg796b8f92017-03-01 17:02:23 -0800331 *shared_->process_thread(), *shared_->audio_device(),
solenberg1c239d42017-09-29 06:00:28 -0700332 shared_->encoder_queue()) != 0) {
333 LOG(LS_ERROR) << "CreateChannel() failed to associate engine and channel."
334 " Destroying channel.";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200335 shared_->channel_manager().DestroyChannel(
336 channel_owner->channel()->ChannelId());
337 return -1;
338 } else if (channel_owner->channel()->Init() != 0) {
solenberg1c239d42017-09-29 06:00:28 -0700339 LOG(LS_ERROR) << "CreateChannel() failed to initialize channel. Destroying"
340 " channel.";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200341 shared_->channel_manager().DestroyChannel(
342 channel_owner->channel()->ChannelId());
343 return -1;
344 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200345 return channel_owner->channel()->ChannelId();
niklase@google.com470e71d2011-07-07 08:21:25 +0000346}
347
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200348int VoEBaseImpl::DeleteChannel(int channel) {
tommi31fc21f2016-01-21 10:37:37 -0800349 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200350 {
351 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
352 voe::Channel* channelPtr = ch.channel();
353 if (channelPtr == nullptr) {
solenberg1c239d42017-09-29 06:00:28 -0700354 LOG(LS_ERROR) << "DeleteChannel() failed to locate channel";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200355 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000356 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200357 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000358
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200359 shared_->channel_manager().DestroyChannel(channel);
360 if (StopSend() != 0) {
361 return -1;
362 }
363 if (StopPlayout() != 0) {
364 return -1;
365 }
366 return 0;
367}
niklase@google.com470e71d2011-07-07 08:21:25 +0000368
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200369int VoEBaseImpl::StartPlayout(int channel) {
tommi31fc21f2016-01-21 10:37:37 -0800370 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200371 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
372 voe::Channel* channelPtr = ch.channel();
373 if (channelPtr == nullptr) {
solenberg1c239d42017-09-29 06:00:28 -0700374 LOG(LS_ERROR) << "StartPlayout() failed to locate channel";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200375 return -1;
376 }
377 if (channelPtr->Playing()) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000378 return 0;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200379 }
380 if (StartPlayout() != 0) {
solenberg1c239d42017-09-29 06:00:28 -0700381 LOG(LS_ERROR) << "StartPlayout() failed to start playout";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200382 return -1;
383 }
384 return channelPtr->StartPlayout();
niklase@google.com470e71d2011-07-07 08:21:25 +0000385}
386
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200387int VoEBaseImpl::StopPlayout(int channel) {
tommi31fc21f2016-01-21 10:37:37 -0800388 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200389 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
390 voe::Channel* channelPtr = ch.channel();
391 if (channelPtr == nullptr) {
solenberg1c239d42017-09-29 06:00:28 -0700392 LOG(LS_ERROR) << "StopPlayout() failed to locate channel";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200393 return -1;
394 }
395 if (channelPtr->StopPlayout() != 0) {
396 LOG_F(LS_WARNING) << "StopPlayout() failed to stop playout for channel "
397 << channel;
398 }
399 return StopPlayout();
niklase@google.com470e71d2011-07-07 08:21:25 +0000400}
401
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200402int VoEBaseImpl::StartSend(int channel) {
tommi31fc21f2016-01-21 10:37:37 -0800403 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200404 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
405 voe::Channel* channelPtr = ch.channel();
406 if (channelPtr == nullptr) {
solenberg1c239d42017-09-29 06:00:28 -0700407 LOG(LS_ERROR) << "StartSend() failed to locate channel";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200408 return -1;
409 }
410 if (channelPtr->Sending()) {
411 return 0;
412 }
413 if (StartSend() != 0) {
solenberg1c239d42017-09-29 06:00:28 -0700414 LOG(LS_ERROR) << "StartSend() failed to start recording";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200415 return -1;
416 }
417 return channelPtr->StartSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000418}
419
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200420int VoEBaseImpl::StopSend(int channel) {
tommi31fc21f2016-01-21 10:37:37 -0800421 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200422 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
423 voe::Channel* channelPtr = ch.channel();
424 if (channelPtr == nullptr) {
solenberg1c239d42017-09-29 06:00:28 -0700425 LOG(LS_ERROR) << "StopSend() failed to locate channel";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200426 return -1;
427 }
henrikaec6fbd22017-03-31 05:43:36 -0700428 channelPtr->StopSend();
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200429 return StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000430}
431
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200432int32_t VoEBaseImpl::StartPlayout() {
solenberge313e022015-09-08 02:16:04 -0700433 if (!shared_->audio_device()->Playing()) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200434 if (shared_->audio_device()->InitPlayout() != 0) {
435 LOG_F(LS_ERROR) << "Failed to initialize playout";
436 return -1;
437 }
438 if (shared_->audio_device()->StartPlayout() != 0) {
439 LOG_F(LS_ERROR) << "Failed to start playout";
440 return -1;
441 }
442 }
443 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000444}
445
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000446int32_t VoEBaseImpl::StopPlayout() {
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000447 // Stop audio-device playing if no channel is playing out
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200448 if (shared_->NumOfPlayingChannels() == 0) {
449 if (shared_->audio_device()->StopPlayout() != 0) {
solenberg1c239d42017-09-29 06:00:28 -0700450 LOG(LS_ERROR) << "StopPlayout() failed to stop playout";
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000451 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000452 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000453 }
454 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000455}
456
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200457int32_t VoEBaseImpl::StartSend() {
solenbergd53a3f92016-04-14 13:56:37 -0700458 if (!shared_->audio_device()->RecordingIsInitialized() &&
459 !shared_->audio_device()->Recording()) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200460 if (shared_->audio_device()->InitRecording() != 0) {
461 LOG_F(LS_ERROR) << "Failed to initialize recording";
462 return -1;
463 }
solenbergd53a3f92016-04-14 13:56:37 -0700464 }
465 if (!shared_->audio_device()->Recording()) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200466 if (shared_->audio_device()->StartRecording() != 0) {
467 LOG_F(LS_ERROR) << "Failed to start recording";
468 return -1;
469 }
470 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200471 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000472}
473
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200474int32_t VoEBaseImpl::StopSend() {
solenbergb63310a2017-09-18 03:04:12 -0700475 if (shared_->NumOfSendingChannels() == 0) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200476 // Stop audio-device recording if no channel is recording
477 if (shared_->audio_device()->StopRecording() != 0) {
solenberg1c239d42017-09-29 06:00:28 -0700478 LOG(LS_ERROR) << "StopSend() failed to stop recording";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200479 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000480 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200481 shared_->transmit_mixer()->StopSend();
482 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000483
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200484 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000485}
486
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200487int32_t VoEBaseImpl::TerminateInternal() {
488 // Delete any remaining channel objects
489 shared_->channel_manager().DestroyAllChannels();
niklase@google.com470e71d2011-07-07 08:21:25 +0000490
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200491 if (shared_->process_thread()) {
492 if (shared_->audio_device()) {
493 shared_->process_thread()->DeRegisterModule(shared_->audio_device());
niklase@google.com470e71d2011-07-07 08:21:25 +0000494 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200495 shared_->process_thread()->Stop();
496 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000497
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200498 if (shared_->audio_device()) {
499 if (shared_->audio_device()->StopPlayout() != 0) {
solenberg1c239d42017-09-29 06:00:28 -0700500 LOG(LS_ERROR) << "TerminateInternal() failed to stop playout";
niklase@google.com470e71d2011-07-07 08:21:25 +0000501 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200502 if (shared_->audio_device()->StopRecording() != 0) {
solenberg1c239d42017-09-29 06:00:28 -0700503 LOG(LS_ERROR) << "TerminateInternal() failed to stop recording";
niklase@google.com470e71d2011-07-07 08:21:25 +0000504 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200505 if (shared_->audio_device()->RegisterEventObserver(nullptr) != 0) {
solenberg1c239d42017-09-29 06:00:28 -0700506 LOG(LS_ERROR) << "TerminateInternal() failed to de-register event "
507 "observer for the ADM";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200508 }
509 if (shared_->audio_device()->RegisterAudioCallback(nullptr) != 0) {
solenberg1c239d42017-09-29 06:00:28 -0700510 LOG(LS_ERROR) << "TerminateInternal() failed to de-register audio "
511 "callback for the ADM";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200512 }
513 if (shared_->audio_device()->Terminate() != 0) {
solenberg1c239d42017-09-29 06:00:28 -0700514 LOG(LS_ERROR) << "TerminateInternal() failed to terminate the ADM";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200515 }
516 shared_->set_audio_device(nullptr);
517 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000518
peaha9cc40b2017-06-29 08:32:09 -0700519 shared_->set_audio_processing(nullptr);
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200520
solenberg1c239d42017-09-29 06:00:28 -0700521 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000522}
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000523} // namespace webrtc