blob: 76dd55a0c44e06ed63bc9ac6c2d0e1e1b276ccb4 [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)
38 : voiceEngineObserverPtr_(nullptr),
Jelena Marusic2dd6a272015-04-14 09:47:00 +020039 shared_(shared) {}
40
41VoEBaseImpl::~VoEBaseImpl() {
42 TerminateInternal();
niklase@google.com470e71d2011-07-07 08:21:25 +000043}
44
solenberg13725082015-11-25 08:16:52 -080045void VoEBaseImpl::OnErrorIsReported(const ErrorCode error) {
tommi31fc21f2016-01-21 10:37:37 -080046 rtc::CritScope cs(&callbackCritSect_);
Jelena Marusic2dd6a272015-04-14 09:47:00 +020047 int errCode = 0;
48 if (error == AudioDeviceObserver::kRecordingError) {
49 errCode = VE_RUNTIME_REC_ERROR;
50 LOG_F(LS_ERROR) << "VE_RUNTIME_REC_ERROR";
51 } else if (error == AudioDeviceObserver::kPlayoutError) {
52 errCode = VE_RUNTIME_PLAY_ERROR;
53 LOG_F(LS_ERROR) << "VE_RUNTIME_PLAY_ERROR";
54 }
55 if (voiceEngineObserverPtr_) {
56 // Deliver callback (-1 <=> no channel dependency)
57 voiceEngineObserverPtr_->CallbackOnError(-1, errCode);
58 }
niklase@google.com470e71d2011-07-07 08:21:25 +000059}
60
solenberg13725082015-11-25 08:16:52 -080061void VoEBaseImpl::OnWarningIsReported(const WarningCode warning) {
tommi31fc21f2016-01-21 10:37:37 -080062 rtc::CritScope cs(&callbackCritSect_);
Jelena Marusic2dd6a272015-04-14 09:47:00 +020063 int warningCode = 0;
64 if (warning == AudioDeviceObserver::kRecordingWarning) {
65 warningCode = VE_RUNTIME_REC_WARNING;
66 LOG_F(LS_WARNING) << "VE_RUNTIME_REC_WARNING";
67 } else if (warning == AudioDeviceObserver::kPlayoutWarning) {
68 warningCode = VE_RUNTIME_PLAY_WARNING;
69 LOG_F(LS_WARNING) << "VE_RUNTIME_PLAY_WARNING";
70 }
71 if (voiceEngineObserverPtr_) {
72 // Deliver callback (-1 <=> no channel dependency)
73 voiceEngineObserverPtr_->CallbackOnError(-1, warningCode);
74 }
niklase@google.com470e71d2011-07-07 08:21:25 +000075}
76
henrikaec6fbd22017-03-31 05:43:36 -070077int32_t VoEBaseImpl::RecordedDataIsAvailable(
78 const void* audio_data,
79 const size_t number_of_frames,
80 const size_t bytes_per_sample,
81 const size_t number_of_channels,
82 const uint32_t sample_rate,
83 const uint32_t audio_delay_milliseconds,
84 const int32_t clock_drift,
85 const uint32_t volume,
86 const bool key_pressed,
87 uint32_t& new_mic_volume) {
88 RTC_DCHECK_EQ(2 * number_of_channels, bytes_per_sample);
89 RTC_DCHECK(shared_->transmit_mixer() != nullptr);
90 RTC_DCHECK(shared_->audio_device() != nullptr);
91
92 uint32_t max_volume = 0;
93 uint16_t voe_mic_level = 0;
94 // Check for zero to skip this calculation; the consumer may use this to
95 // indicate no volume is available.
96 if (volume != 0) {
97 // Scale from ADM to VoE level range
98 if (shared_->audio_device()->MaxMicrophoneVolume(&max_volume) == 0) {
99 if (max_volume) {
100 voe_mic_level = static_cast<uint16_t>(
101 (volume * kMaxVolumeLevel + static_cast<int>(max_volume / 2)) /
102 max_volume);
103 }
104 }
105 // We learned that on certain systems (e.g Linux) the voe_mic_level
106 // can be greater than the maxVolumeLevel therefore
107 // we are going to cap the voe_mic_level to the maxVolumeLevel
108 // and change the maxVolume to volume if it turns out that
109 // the voe_mic_level is indeed greater than the maxVolumeLevel.
110 if (voe_mic_level > kMaxVolumeLevel) {
111 voe_mic_level = kMaxVolumeLevel;
112 max_volume = volume;
113 }
114 }
115
116 // Perform channel-independent operations
117 // (APM, mix with file, record to file, mute, etc.)
118 shared_->transmit_mixer()->PrepareDemux(
119 audio_data, number_of_frames, number_of_channels, sample_rate,
120 static_cast<uint16_t>(audio_delay_milliseconds), clock_drift,
121 voe_mic_level, key_pressed);
122
123 // Copy the audio frame to each sending channel and perform
124 // channel-dependent operations (file mixing, mute, etc.), encode and
125 // packetize+transmit the RTP packet.
126 shared_->transmit_mixer()->ProcessAndEncodeAudio();
127
128 // Scale from VoE to ADM level range.
129 uint32_t new_voe_mic_level = shared_->transmit_mixer()->CaptureLevel();
130 if (new_voe_mic_level != voe_mic_level) {
131 // Return the new volume if AGC has changed the volume.
132 return static_cast<int>((new_voe_mic_level * max_volume +
133 static_cast<int>(kMaxVolumeLevel / 2)) /
134 kMaxVolumeLevel);
135 }
136
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200137 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000138}
139
solenberg13725082015-11-25 08:16:52 -0800140int32_t VoEBaseImpl::NeedMorePlayData(const size_t nSamples,
141 const size_t nBytesPerSample,
Peter Kasting69558702016-01-12 16:26:35 -0800142 const size_t nChannels,
solenberg13725082015-11-25 08:16:52 -0800143 const uint32_t samplesPerSec,
144 void* audioSamples,
145 size_t& nSamplesOut,
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200146 int64_t* elapsed_time_ms,
147 int64_t* ntp_time_ms) {
solenberg2397b9a2017-09-22 06:48:10 -0700148 RTC_NOTREACHED();
xians@webrtc.org56925312014-04-14 10:50:37 +0000149 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000150}
151
xians@webrtc.org56925312014-04-14 10:50:37 +0000152void VoEBaseImpl::PushCaptureData(int voe_channel, const void* audio_data,
153 int bits_per_sample, 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 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(voe_channel);
henrikaec6fbd22017-03-31 05:43:36 -0700157 voe::Channel* channel = ch.channel();
158 if (!channel)
159 return;
160 if (channel->Sending()) {
161 // Send the audio to each channel directly without using the APM in the
162 // transmit mixer.
163 channel->ProcessAndEncodeAudio(static_cast<const int16_t*>(audio_data),
164 sample_rate, number_of_frames,
165 number_of_channels);
xians@webrtc.org07e51962014-01-29 13:54:02 +0000166 }
167}
168
Peter Kastingdce40cf2015-08-24 14:52:23 -0700169void VoEBaseImpl::PullRenderData(int bits_per_sample,
170 int sample_rate,
Peter Kasting69558702016-01-12 16:26:35 -0800171 size_t number_of_channels,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700172 size_t number_of_frames,
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200173 void* audio_data, int64_t* elapsed_time_ms,
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000174 int64_t* ntp_time_ms) {
solenberg2397b9a2017-09-22 06:48:10 -0700175 RTC_NOTREACHED();
xians@webrtc.org56925312014-04-14 10:50:37 +0000176}
177
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200178int VoEBaseImpl::RegisterVoiceEngineObserver(VoiceEngineObserver& observer) {
tommi31fc21f2016-01-21 10:37:37 -0800179 rtc::CritScope cs(&callbackCritSect_);
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200180 if (voiceEngineObserverPtr_) {
181 shared_->SetLastError(
182 VE_INVALID_OPERATION, kTraceError,
183 "RegisterVoiceEngineObserver() observer already enabled");
184 return -1;
185 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000186
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200187 // Register the observer in all active channels
188 for (voe::ChannelManager::Iterator it(&shared_->channel_manager());
189 it.IsValid(); it.Increment()) {
190 it.GetChannel()->RegisterVoiceEngineObserver(observer);
191 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000192
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200193 shared_->transmit_mixer()->RegisterVoiceEngineObserver(observer);
194 voiceEngineObserverPtr_ = &observer;
195 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000196}
197
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200198int VoEBaseImpl::DeRegisterVoiceEngineObserver() {
tommi31fc21f2016-01-21 10:37:37 -0800199 rtc::CritScope cs(&callbackCritSect_);
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200200 if (!voiceEngineObserverPtr_) {
201 shared_->SetLastError(
202 VE_INVALID_OPERATION, kTraceError,
203 "DeRegisterVoiceEngineObserver() observer already disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +0000204 return 0;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200205 }
206 voiceEngineObserverPtr_ = nullptr;
207
208 // Deregister the observer in all active channels
209 for (voe::ChannelManager::Iterator it(&shared_->channel_manager());
210 it.IsValid(); it.Increment()) {
211 it.GetChannel()->DeRegisterVoiceEngineObserver();
212 }
213
214 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000215}
216
ossu5f7cfa52016-05-30 08:11:28 -0700217int VoEBaseImpl::Init(
218 AudioDeviceModule* external_adm,
peahe67bedb2017-07-07 04:25:11 -0700219 AudioProcessing* audio_processing,
ossu5f7cfa52016-05-30 08:11:28 -0700220 const rtc::scoped_refptr<AudioDecoderFactory>& decoder_factory) {
peahe67bedb2017-07-07 04:25:11 -0700221 RTC_DCHECK(audio_processing);
tommi31fc21f2016-01-21 10:37:37 -0800222 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200223 WebRtcSpl_Init();
224 if (shared_->statistics().Initialized()) {
225 return 0;
226 }
227 if (shared_->process_thread()) {
228 shared_->process_thread()->Start();
229 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000230
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200231 // Create an internal ADM if the user has not added an external
232 // ADM implementation as input to Init().
233 if (external_adm == nullptr) {
Tommi931e6582015-05-20 09:44:38 +0200234#if !defined(WEBRTC_INCLUDE_INTERNAL_AUDIO_DEVICE)
235 return -1;
236#else
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200237 // Create the internal ADM implementation.
Peter Boström4adbbcf2016-05-03 15:51:26 -0400238 shared_->set_audio_device(AudioDeviceModule::Create(
solenberg5b3e49a2017-03-15 08:08:07 -0700239 VoEId(shared_->instance_id(), -1),
240 AudioDeviceModule::kPlatformDefaultAudio));
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200241 if (shared_->audio_device() == nullptr) {
242 shared_->SetLastError(VE_NO_MEMORY, kTraceCritical,
243 "Init() failed to create the ADM");
244 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000245 }
Tommi931e6582015-05-20 09:44:38 +0200246#endif // WEBRTC_INCLUDE_INTERNAL_AUDIO_DEVICE
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200247 } else {
248 // Use the already existing external ADM implementation.
249 shared_->set_audio_device(external_adm);
250 LOG_F(LS_INFO)
251 << "An external ADM implementation will be used in VoiceEngine";
252 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000253
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200254 // Register the ADM to the process thread, which will drive the error
255 // callback mechanism
256 if (shared_->process_thread()) {
tommidea489f2017-03-03 03:20:24 -0800257 shared_->process_thread()->RegisterModule(shared_->audio_device(),
258 RTC_FROM_HERE);
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200259 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000260
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200261 bool available = false;
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000262
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200263 // --------------------
264 // Reinitialize the ADM
henrika@google.com73d65512011-09-07 15:11:18 +0000265
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200266 // Register the AudioObserver implementation
267 if (shared_->audio_device()->RegisterEventObserver(this) != 0) {
268 shared_->SetLastError(
269 VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
270 "Init() failed to register event observer for the ADM");
271 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000272
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200273 // Register the AudioTransport implementation
274 if (shared_->audio_device()->RegisterAudioCallback(this) != 0) {
275 shared_->SetLastError(
276 VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
277 "Init() failed to register audio callback for the ADM");
278 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000279
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200280 // ADM initialization
281 if (shared_->audio_device()->Init() != 0) {
282 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
283 "Init() failed to initialize the ADM");
284 return -1;
285 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000286
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200287 // Initialize the default speaker
288 if (shared_->audio_device()->SetPlayoutDevice(
289 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0) {
290 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceInfo,
291 "Init() failed to set the default output device");
292 }
293 if (shared_->audio_device()->InitSpeaker() != 0) {
294 shared_->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceInfo,
295 "Init() failed to initialize the speaker");
296 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000297
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200298 // Initialize the default microphone
299 if (shared_->audio_device()->SetRecordingDevice(
300 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0) {
301 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceInfo,
302 "Init() failed to set the default input device");
303 }
304 if (shared_->audio_device()->InitMicrophone() != 0) {
305 shared_->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceInfo,
306 "Init() failed to initialize the microphone");
307 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000308
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200309 // Set number of channels
310 if (shared_->audio_device()->StereoPlayoutIsAvailable(&available) != 0) {
311 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
312 "Init() failed to query stereo playout mode");
313 }
314 if (shared_->audio_device()->SetStereoPlayout(available) != 0) {
315 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
316 "Init() failed to set mono/stereo playout mode");
317 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000318
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200319 // TODO(andrew): These functions don't tell us whether stereo recording
320 // is truly available. We simply set the AudioProcessing input to stereo
321 // here, because we have to wait until receiving the first frame to
322 // determine the actual number of channels anyway.
323 //
324 // These functions may be changed; tracked here:
325 // http://code.google.com/p/webrtc/issues/detail?id=204
326 shared_->audio_device()->StereoRecordingIsAvailable(&available);
327 if (shared_->audio_device()->SetStereoRecording(available) != 0) {
328 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
329 "Init() failed to set mono/stereo recording mode");
330 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000331
peahe67bedb2017-07-07 04:25:11 -0700332 shared_->set_audio_processing(audio_processing);
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000333
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200334 // Set the error state for any failures in this block.
335 shared_->SetLastError(VE_APM_ERROR);
336 // Configure AudioProcessing components.
peaha9cc40b2017-06-29 08:32:09 -0700337 // TODO(peah): Move this initialization to webrtcvoiceengine.cc.
peahe67bedb2017-07-07 04:25:11 -0700338 if (audio_processing->high_pass_filter()->Enable(true) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200339 LOG_F(LS_ERROR) << "Failed to enable high pass filter.";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200340 return -1;
341 }
peahe67bedb2017-07-07 04:25:11 -0700342 if (audio_processing->echo_cancellation()->enable_drift_compensation(false) !=
343 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200344 LOG_F(LS_ERROR) << "Failed to disable drift compensation.";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200345 return -1;
346 }
peahe67bedb2017-07-07 04:25:11 -0700347 if (audio_processing->noise_suppression()->set_level(kDefaultNsMode) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200348 LOG_F(LS_ERROR) << "Failed to set noise suppression level: "
349 << kDefaultNsMode;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200350 return -1;
351 }
peahe67bedb2017-07-07 04:25:11 -0700352 GainControl* agc = audio_processing->gain_control();
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200353 if (agc->set_analog_level_limits(kMinVolumeLevel, kMaxVolumeLevel) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200354 LOG_F(LS_ERROR) << "Failed to set analog level limits with minimum: "
355 << kMinVolumeLevel << " and maximum: " << kMaxVolumeLevel;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200356 return -1;
357 }
358 if (agc->set_mode(kDefaultAgcMode) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200359 LOG_F(LS_ERROR) << "Failed to set mode: " << kDefaultAgcMode;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200360 return -1;
361 }
362 if (agc->Enable(kDefaultAgcState) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200363 LOG_F(LS_ERROR) << "Failed to set agc state: " << kDefaultAgcState;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200364 return -1;
365 }
366 shared_->SetLastError(0); // Clear error state.
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000367
niklase@google.com470e71d2011-07-07 08:21:25 +0000368#ifdef WEBRTC_VOICE_ENGINE_AGC
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200369 bool agc_enabled =
370 agc->mode() == GainControl::kAdaptiveAnalog && agc->is_enabled();
371 if (shared_->audio_device()->SetAGC(agc_enabled) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200372 LOG_F(LS_ERROR) << "Failed to set agc to enabled: " << agc_enabled;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200373 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR);
374 // TODO(ajm): No error return here due to
375 // https://code.google.com/p/webrtc/issues/detail?id=1464
376 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000377#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000378
ossu5f7cfa52016-05-30 08:11:28 -0700379 if (decoder_factory)
380 decoder_factory_ = decoder_factory;
381 else
382 decoder_factory_ = CreateBuiltinAudioDecoderFactory();
383
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200384 return shared_->statistics().SetInitialized();
niklase@google.com470e71d2011-07-07 08:21:25 +0000385}
386
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200387int VoEBaseImpl::Terminate() {
tommi31fc21f2016-01-21 10:37:37 -0800388 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200389 return TerminateInternal();
niklase@google.com470e71d2011-07-07 08:21:25 +0000390}
391
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000392int VoEBaseImpl::CreateChannel() {
solenberg88499ec2016-09-07 07:34:41 -0700393 return CreateChannel(ChannelConfig());
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000394}
395
solenberg88499ec2016-09-07 07:34:41 -0700396int VoEBaseImpl::CreateChannel(const ChannelConfig& config) {
tommi31fc21f2016-01-21 10:37:37 -0800397 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200398 if (!shared_->statistics().Initialized()) {
399 shared_->SetLastError(VE_NOT_INITED, kTraceError);
400 return -1;
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000401 }
solenberg88499ec2016-09-07 07:34:41 -0700402
403 ChannelConfig config_copy(config);
404 config_copy.acm_config.decoder_factory = decoder_factory_;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200405 voe::ChannelOwner channel_owner =
solenberg88499ec2016-09-07 07:34:41 -0700406 shared_->channel_manager().CreateChannel(config_copy);
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000407 return InitializeChannel(&channel_owner);
408}
409
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200410int VoEBaseImpl::InitializeChannel(voe::ChannelOwner* channel_owner) {
411 if (channel_owner->channel()->SetEngineInformation(
solenberg2397b9a2017-09-22 06:48:10 -0700412 shared_->statistics(),
solenberg796b8f92017-03-01 17:02:23 -0800413 *shared_->process_thread(), *shared_->audio_device(),
henrikaec6fbd22017-03-31 05:43:36 -0700414 voiceEngineObserverPtr_, &callbackCritSect_,
415 shared_->encoder_queue()) != 0) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200416 shared_->SetLastError(
417 VE_CHANNEL_NOT_CREATED, kTraceError,
418 "CreateChannel() failed to associate engine and channel."
419 " Destroying channel.");
420 shared_->channel_manager().DestroyChannel(
421 channel_owner->channel()->ChannelId());
422 return -1;
423 } else if (channel_owner->channel()->Init() != 0) {
424 shared_->SetLastError(
425 VE_CHANNEL_NOT_CREATED, kTraceError,
426 "CreateChannel() failed to initialize channel. Destroying"
427 " channel.");
428 shared_->channel_manager().DestroyChannel(
429 channel_owner->channel()->ChannelId());
430 return -1;
431 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200432 return channel_owner->channel()->ChannelId();
niklase@google.com470e71d2011-07-07 08:21:25 +0000433}
434
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200435int VoEBaseImpl::DeleteChannel(int channel) {
tommi31fc21f2016-01-21 10:37:37 -0800436 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200437 if (!shared_->statistics().Initialized()) {
438 shared_->SetLastError(VE_NOT_INITED, kTraceError);
439 return -1;
440 }
441
442 {
443 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
444 voe::Channel* channelPtr = ch.channel();
445 if (channelPtr == nullptr) {
446 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
447 "DeleteChannel() failed to locate channel");
448 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000449 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200450 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000451
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200452 shared_->channel_manager().DestroyChannel(channel);
453 if (StopSend() != 0) {
454 return -1;
455 }
456 if (StopPlayout() != 0) {
457 return -1;
458 }
459 return 0;
460}
niklase@google.com470e71d2011-07-07 08:21:25 +0000461
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200462int VoEBaseImpl::StartPlayout(int channel) {
tommi31fc21f2016-01-21 10:37:37 -0800463 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200464 if (!shared_->statistics().Initialized()) {
465 shared_->SetLastError(VE_NOT_INITED, kTraceError);
466 return -1;
467 }
468 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
469 voe::Channel* channelPtr = ch.channel();
470 if (channelPtr == nullptr) {
471 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
472 "StartPlayout() failed to locate channel");
473 return -1;
474 }
475 if (channelPtr->Playing()) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000476 return 0;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200477 }
478 if (StartPlayout() != 0) {
479 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
480 "StartPlayout() failed to start playout");
481 return -1;
482 }
483 return channelPtr->StartPlayout();
niklase@google.com470e71d2011-07-07 08:21:25 +0000484}
485
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200486int VoEBaseImpl::StopPlayout(int channel) {
tommi31fc21f2016-01-21 10:37:37 -0800487 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200488 if (!shared_->statistics().Initialized()) {
489 shared_->SetLastError(VE_NOT_INITED, kTraceError);
490 return -1;
491 }
492 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
493 voe::Channel* channelPtr = ch.channel();
494 if (channelPtr == nullptr) {
495 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
496 "StopPlayout() failed to locate channel");
497 return -1;
498 }
499 if (channelPtr->StopPlayout() != 0) {
500 LOG_F(LS_WARNING) << "StopPlayout() failed to stop playout for channel "
501 << channel;
502 }
503 return StopPlayout();
niklase@google.com470e71d2011-07-07 08:21:25 +0000504}
505
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200506int VoEBaseImpl::StartSend(int channel) {
tommi31fc21f2016-01-21 10:37:37 -0800507 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200508 if (!shared_->statistics().Initialized()) {
509 shared_->SetLastError(VE_NOT_INITED, kTraceError);
510 return -1;
511 }
512 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
513 voe::Channel* channelPtr = ch.channel();
514 if (channelPtr == nullptr) {
515 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
516 "StartSend() failed to locate channel");
517 return -1;
518 }
519 if (channelPtr->Sending()) {
520 return 0;
521 }
522 if (StartSend() != 0) {
523 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
524 "StartSend() failed to start recording");
525 return -1;
526 }
527 return channelPtr->StartSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000528}
529
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200530int VoEBaseImpl::StopSend(int channel) {
tommi31fc21f2016-01-21 10:37:37 -0800531 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200532 if (!shared_->statistics().Initialized()) {
533 shared_->SetLastError(VE_NOT_INITED, kTraceError);
534 return -1;
535 }
536 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
537 voe::Channel* channelPtr = ch.channel();
538 if (channelPtr == nullptr) {
539 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
540 "StopSend() failed to locate channel");
541 return -1;
542 }
henrikaec6fbd22017-03-31 05:43:36 -0700543 channelPtr->StopSend();
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200544 return StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000545}
546
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200547int32_t VoEBaseImpl::StartPlayout() {
solenberge313e022015-09-08 02:16:04 -0700548 if (!shared_->audio_device()->Playing()) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200549 if (shared_->audio_device()->InitPlayout() != 0) {
550 LOG_F(LS_ERROR) << "Failed to initialize playout";
551 return -1;
552 }
553 if (shared_->audio_device()->StartPlayout() != 0) {
554 LOG_F(LS_ERROR) << "Failed to start playout";
555 return -1;
556 }
557 }
558 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000559}
560
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000561int32_t VoEBaseImpl::StopPlayout() {
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000562 // Stop audio-device playing if no channel is playing out
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200563 if (shared_->NumOfPlayingChannels() == 0) {
564 if (shared_->audio_device()->StopPlayout() != 0) {
565 shared_->SetLastError(VE_CANNOT_STOP_PLAYOUT, kTraceError,
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000566 "StopPlayout() failed to stop playout");
567 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000568 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000569 }
570 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000571}
572
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200573int32_t VoEBaseImpl::StartSend() {
solenbergd53a3f92016-04-14 13:56:37 -0700574 if (!shared_->audio_device()->RecordingIsInitialized() &&
575 !shared_->audio_device()->Recording()) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200576 if (shared_->audio_device()->InitRecording() != 0) {
577 LOG_F(LS_ERROR) << "Failed to initialize recording";
578 return -1;
579 }
solenbergd53a3f92016-04-14 13:56:37 -0700580 }
581 if (!shared_->audio_device()->Recording()) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200582 if (shared_->audio_device()->StartRecording() != 0) {
583 LOG_F(LS_ERROR) << "Failed to start recording";
584 return -1;
585 }
586 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200587 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000588}
589
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200590int32_t VoEBaseImpl::StopSend() {
solenbergb63310a2017-09-18 03:04:12 -0700591 if (shared_->NumOfSendingChannels() == 0) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200592 // Stop audio-device recording if no channel is recording
593 if (shared_->audio_device()->StopRecording() != 0) {
594 shared_->SetLastError(VE_CANNOT_STOP_RECORDING, kTraceError,
595 "StopSend() failed to stop recording");
596 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000597 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200598 shared_->transmit_mixer()->StopSend();
599 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000600
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200601 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000602}
603
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200604int32_t VoEBaseImpl::TerminateInternal() {
605 // Delete any remaining channel objects
606 shared_->channel_manager().DestroyAllChannels();
niklase@google.com470e71d2011-07-07 08:21:25 +0000607
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200608 if (shared_->process_thread()) {
609 if (shared_->audio_device()) {
610 shared_->process_thread()->DeRegisterModule(shared_->audio_device());
niklase@google.com470e71d2011-07-07 08:21:25 +0000611 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200612 shared_->process_thread()->Stop();
613 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000614
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200615 if (shared_->audio_device()) {
616 if (shared_->audio_device()->StopPlayout() != 0) {
617 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
618 "TerminateInternal() failed to stop playout");
niklase@google.com470e71d2011-07-07 08:21:25 +0000619 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200620 if (shared_->audio_device()->StopRecording() != 0) {
621 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
622 "TerminateInternal() failed to stop recording");
niklase@google.com470e71d2011-07-07 08:21:25 +0000623 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200624 if (shared_->audio_device()->RegisterEventObserver(nullptr) != 0) {
625 shared_->SetLastError(
626 VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
627 "TerminateInternal() failed to de-register event observer "
628 "for the ADM");
629 }
630 if (shared_->audio_device()->RegisterAudioCallback(nullptr) != 0) {
631 shared_->SetLastError(
632 VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
633 "TerminateInternal() failed to de-register audio callback "
634 "for the ADM");
635 }
636 if (shared_->audio_device()->Terminate() != 0) {
637 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
638 "TerminateInternal() failed to terminate the ADM");
639 }
640 shared_->set_audio_device(nullptr);
641 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000642
peaha9cc40b2017-06-29 08:32:09 -0700643 shared_->set_audio_processing(nullptr);
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200644
645 return shared_->statistics().SetUnInitialized();
niklase@google.com470e71d2011-07-07 08:21:25 +0000646}
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000647} // namespace webrtc