blob: a84d0c1052de3f91f4adaa595ab12f22a9e60fe2 [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
pbos@webrtc.org956aa7e2013-05-21 13:52:32 +000011#include "webrtc/voice_engine/voe_base_impl.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000012
turaj@webrtc.org03f33702013-11-13 00:02:48 +000013#include "webrtc/common.h"
pbos@webrtc.org956aa7e2013-05-21 13:52:32 +000014#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
15#include "webrtc/modules/audio_coding/main/interface/audio_coding_module.h"
16#include "webrtc/modules/audio_device/audio_device_impl.h"
17#include "webrtc/modules/audio_processing/include/audio_processing.h"
18#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
19#include "webrtc/system_wrappers/interface/file_wrapper.h"
20#include "webrtc/system_wrappers/interface/trace.h"
21#include "webrtc/voice_engine/channel.h"
22#include "webrtc/voice_engine/include/voe_errors.h"
23#include "webrtc/voice_engine/output_mixer.h"
24#include "webrtc/voice_engine/transmit_mixer.h"
25#include "webrtc/voice_engine/utility.h"
26#include "webrtc/voice_engine/voice_engine_impl.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000027
28#if (defined(_WIN32) && defined(_DLL) && (_MSC_VER == 1400))
29// Fix for VS 2005 MD/MDd link problem
30#include <stdio.h>
31extern "C"
32 { FILE _iob[3] = { __iob_func()[0], __iob_func()[1], __iob_func()[2]}; }
33#endif
34
35namespace webrtc
36{
37
38VoEBase* VoEBase::GetInterface(VoiceEngine* voiceEngine)
39{
40 if (NULL == voiceEngine)
41 {
42 return NULL;
43 }
tommi@webrtc.org0989fb72013-02-15 15:07:32 +000044 VoiceEngineImpl* s = static_cast<VoiceEngineImpl*>(voiceEngine);
tommi@webrtc.orga990e122012-04-26 15:28:22 +000045 s->AddRef();
46 return s;
niklase@google.com470e71d2011-07-07 08:21:25 +000047}
48
tommi@webrtc.org851becd2012-04-04 14:57:19 +000049VoEBaseImpl::VoEBaseImpl(voe::SharedData* shared) :
niklase@google.com470e71d2011-07-07 08:21:25 +000050 _voiceEngineObserverPtr(NULL),
51 _callbackCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
tommi@webrtc.org851becd2012-04-04 14:57:19 +000052 _voiceEngineObserver(false), _oldVoEMicLevel(0), _oldMicLevel(0),
53 _shared(shared)
niklase@google.com470e71d2011-07-07 08:21:25 +000054{
tommi@webrtc.org851becd2012-04-04 14:57:19 +000055 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +000056 "VoEBaseImpl() - ctor");
57}
58
59VoEBaseImpl::~VoEBaseImpl()
60{
tommi@webrtc.org851becd2012-04-04 14:57:19 +000061 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +000062 "~VoEBaseImpl() - dtor");
63
64 TerminateInternal();
65
66 delete &_callbackCritSect;
67}
68
pbos@webrtc.org92135212013-05-14 08:31:39 +000069void VoEBaseImpl::OnErrorIsReported(ErrorCode error)
niklase@google.com470e71d2011-07-07 08:21:25 +000070{
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +000071 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +000072 if (_voiceEngineObserver)
73 {
74 if (_voiceEngineObserverPtr)
75 {
76 int errCode(0);
77 if (error == AudioDeviceObserver::kRecordingError)
78 {
79 errCode = VE_RUNTIME_REC_ERROR;
tommi@webrtc.org851becd2012-04-04 14:57:19 +000080 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
81 VoEId(_shared->instance_id(), -1),
82 "VoEBaseImpl::OnErrorIsReported() => VE_RUNTIME_REC_ERROR");
niklase@google.com470e71d2011-07-07 08:21:25 +000083 }
84 else if (error == AudioDeviceObserver::kPlayoutError)
85 {
86 errCode = VE_RUNTIME_PLAY_ERROR;
tommi@webrtc.org851becd2012-04-04 14:57:19 +000087 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
88 VoEId(_shared->instance_id(), -1),
89 "VoEBaseImpl::OnErrorIsReported() => "
90 "VE_RUNTIME_PLAY_ERROR");
niklase@google.com470e71d2011-07-07 08:21:25 +000091 }
92 // Deliver callback (-1 <=> no channel dependency)
93 _voiceEngineObserverPtr->CallbackOnError(-1, errCode);
94 }
95 }
96}
97
pbos@webrtc.org92135212013-05-14 08:31:39 +000098void VoEBaseImpl::OnWarningIsReported(WarningCode warning)
niklase@google.com470e71d2011-07-07 08:21:25 +000099{
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000100 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000101 if (_voiceEngineObserver)
102 {
103 if (_voiceEngineObserverPtr)
104 {
105 int warningCode(0);
106 if (warning == AudioDeviceObserver::kRecordingWarning)
107 {
108 warningCode = VE_RUNTIME_REC_WARNING;
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000109 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
110 VoEId(_shared->instance_id(), -1),
111 "VoEBaseImpl::OnErrorIsReported() => "
112 "VE_RUNTIME_REC_WARNING");
niklase@google.com470e71d2011-07-07 08:21:25 +0000113 }
114 else if (warning == AudioDeviceObserver::kPlayoutWarning)
115 {
116 warningCode = VE_RUNTIME_PLAY_WARNING;
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000117 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
118 VoEId(_shared->instance_id(), -1),
119 "VoEBaseImpl::OnErrorIsReported() => "
120 "VE_RUNTIME_PLAY_WARNING");
niklase@google.com470e71d2011-07-07 08:21:25 +0000121 }
122 // Deliver callback (-1 <=> no channel dependency)
123 _voiceEngineObserverPtr->CallbackOnError(-1, warningCode);
124 }
125 }
126}
127
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000128int32_t VoEBaseImpl::RecordedDataIsAvailable(
henrika@webrtc.org907bc552012-03-09 08:59:19 +0000129 const void* audioSamples,
pbos@webrtc.org92135212013-05-14 08:31:39 +0000130 uint32_t nSamples,
131 uint8_t nBytesPerSample,
132 uint8_t nChannels,
133 uint32_t samplesPerSec,
134 uint32_t totalDelayMS,
135 int32_t clockDrift,
136 uint32_t currentMicLevel,
137 bool keyPressed,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000138 uint32_t& newMicLevel)
niklase@google.com470e71d2011-07-07 08:21:25 +0000139{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000140 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000141 "VoEBaseImpl::RecordedDataIsAvailable(nSamples=%u, "
142 "nBytesPerSample=%u, nChannels=%u, samplesPerSec=%u, "
143 "totalDelayMS=%u, clockDrift=%d, currentMicLevel=%u)",
144 nSamples, nBytesPerSample, nChannels, samplesPerSec,
145 totalDelayMS, clockDrift, currentMicLevel);
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000146 newMicLevel = static_cast<uint32_t>(ProcessRecordedDataWithAPM(
147 NULL, 0, audioSamples, samplesPerSec, nChannels, nSamples,
148 totalDelayMS, clockDrift, currentMicLevel, keyPressed));
niklase@google.com470e71d2011-07-07 08:21:25 +0000149
150 return 0;
151}
152
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000153int32_t VoEBaseImpl::NeedMorePlayData(
pbos@webrtc.org92135212013-05-14 08:31:39 +0000154 uint32_t nSamples,
155 uint8_t nBytesPerSample,
156 uint8_t nChannels,
157 uint32_t samplesPerSec,
henrika@webrtc.org907bc552012-03-09 08:59:19 +0000158 void* audioSamples,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000159 uint32_t& nSamplesOut)
niklase@google.com470e71d2011-07-07 08:21:25 +0000160{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000161 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000162 "VoEBaseImpl::NeedMorePlayData(nSamples=%u, "
163 "nBytesPerSample=%d, nChannels=%d, samplesPerSec=%u)",
164 nSamples, nBytesPerSample, nChannels, samplesPerSec);
165
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000166 assert(_shared->output_mixer() != NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000167
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +0000168 // TODO(andrew): if the device is running in mono, we should tell the mixer
169 // here so that it will only request mono from AudioCodingModule.
niklase@google.com470e71d2011-07-07 08:21:25 +0000170 // Perform mixing of all active participants (channel-based mixing)
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000171 _shared->output_mixer()->MixActiveChannels();
niklase@google.com470e71d2011-07-07 08:21:25 +0000172
173 // Additional operations on the combined signal
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000174 _shared->output_mixer()->DoOperationsOnCombinedSignal();
niklase@google.com470e71d2011-07-07 08:21:25 +0000175
176 // Retrieve the final output mix (resampled to match the ADM)
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000177 _shared->output_mixer()->GetMixedAudio(samplesPerSec, nChannels,
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +0000178 &_audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000179
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +0000180 assert(static_cast<int>(nSamples) == _audioFrame.samples_per_channel_);
xians@google.com0b0665a2011-08-08 08:18:44 +0000181 assert(samplesPerSec ==
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000182 static_cast<uint32_t>(_audioFrame.sample_rate_hz_));
niklase@google.com470e71d2011-07-07 08:21:25 +0000183
184 // Deliver audio (PCM) samples to the ADM
185 memcpy(
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000186 (int16_t*) audioSamples,
187 (const int16_t*) _audioFrame.data_,
188 sizeof(int16_t) * (_audioFrame.samples_per_channel_
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000189 * _audioFrame.num_channels_));
niklase@google.com470e71d2011-07-07 08:21:25 +0000190
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000191 nSamplesOut = _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000192
193 return 0;
194}
195
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000196int VoEBaseImpl::OnDataAvailable(const int voe_channels[],
xians@webrtc.org2f84afa2013-07-31 16:23:37 +0000197 int number_of_voe_channels,
198 const int16_t* audio_data,
199 int sample_rate,
200 int number_of_channels,
201 int number_of_frames,
202 int audio_delay_milliseconds,
203 int current_volume,
204 bool key_pressed,
205 bool need_audio_processing) {
206 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_shared->instance_id(), -1),
207 "VoEBaseImpl::OnDataAvailable(number_of_voe_channels=%d, "
208 "sample_rate=%d, number_of_channels=%d, number_of_frames=%d, "
209 "audio_delay_milliseconds=%d, current_volume=%d, "
210 "key_pressed=%d, need_audio_processing=%d)",
211 number_of_voe_channels, sample_rate, number_of_channels,
212 number_of_frames, audio_delay_milliseconds, current_volume,
213 key_pressed, need_audio_processing);
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000214 if (number_of_voe_channels == 0)
215 return 0;
xians@webrtc.org2f84afa2013-07-31 16:23:37 +0000216
217 if (need_audio_processing) {
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000218 return ProcessRecordedDataWithAPM(
219 voe_channels, number_of_voe_channels, audio_data, sample_rate,
220 number_of_channels, number_of_frames, audio_delay_milliseconds,
221 0, current_volume, key_pressed);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +0000222 }
223
224 // No need to go through the APM, demultiplex the data to each VoE channel,
225 // encode and send to the network.
226 for (int i = 0; i < number_of_voe_channels; ++i) {
xians@webrtc.org07e51962014-01-29 13:54:02 +0000227 CaptureCallback(voe_channels[i], audio_data, 16, sample_rate,
228 number_of_channels, number_of_frames);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +0000229 }
230
231 // Return 0 to indicate no need to change the volume.
232 return 0;
233}
234
xians@webrtc.org07e51962014-01-29 13:54:02 +0000235void VoEBaseImpl::CaptureCallback(int voe_channel, const void* audio_data,
236 int bits_per_sample, int sample_rate,
237 int number_of_channels,
238 int number_of_frames) {
239 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(voe_channel);
240 voe::Channel* channel_ptr = ch.channel();
241 if (!channel_ptr)
242 return;
243
244 if (channel_ptr->InputIsOnHold()) {
245 channel_ptr->UpdateLocalTimeStamp();
246 } else if (channel_ptr->Sending()) {
247 channel_ptr->Demultiplex(static_cast<const int16_t*>(audio_data),
248 sample_rate, number_of_frames, number_of_channels);
249 channel_ptr->PrepareEncodeAndSend(sample_rate);
250 channel_ptr->EncodeAndSend();
251 }
252}
253
niklase@google.com470e71d2011-07-07 08:21:25 +0000254int VoEBaseImpl::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
255{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000256 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000257 "RegisterVoiceEngineObserver(observer=0x%d)", &observer);
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000258 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000259 if (_voiceEngineObserverPtr)
260 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000261 _shared->SetLastError(VE_INVALID_OPERATION, kTraceError,
262 "RegisterVoiceEngineObserver() observer already enabled");
niklase@google.com470e71d2011-07-07 08:21:25 +0000263 return -1;
264 }
265
266 // Register the observer in all active channels
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000267 for (voe::ChannelManager::Iterator it(&_shared->channel_manager());
268 it.IsValid();
269 it.Increment()) {
270 it.GetChannel()->RegisterVoiceEngineObserver(observer);
niklase@google.com470e71d2011-07-07 08:21:25 +0000271 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000272
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000273 _shared->transmit_mixer()->RegisterVoiceEngineObserver(observer);
niklase@google.com470e71d2011-07-07 08:21:25 +0000274
275 _voiceEngineObserverPtr = &observer;
276 _voiceEngineObserver = true;
277
278 return 0;
279}
280
281int VoEBaseImpl::DeRegisterVoiceEngineObserver()
282{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000283 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000284 "DeRegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000285 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000286 if (!_voiceEngineObserverPtr)
287 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000288 _shared->SetLastError(VE_INVALID_OPERATION, kTraceError,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000289 "DeRegisterVoiceEngineObserver() observer already disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +0000290 return 0;
291 }
292
293 _voiceEngineObserver = false;
294 _voiceEngineObserverPtr = NULL;
295
296 // Deregister the observer in all active channels
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000297 for (voe::ChannelManager::Iterator it(&_shared->channel_manager());
298 it.IsValid();
299 it.Increment()) {
300 it.GetChannel()->DeRegisterVoiceEngineObserver();
niklase@google.com470e71d2011-07-07 08:21:25 +0000301 }
302
303 return 0;
304}
305
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000306int VoEBaseImpl::Init(AudioDeviceModule* external_adm,
307 AudioProcessing* audioproc)
niklase@google.com470e71d2011-07-07 08:21:25 +0000308{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000309 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
henrika@google.com73d65512011-09-07 15:11:18 +0000310 "Init(external_adm=0x%p)", external_adm);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000311 CriticalSectionScoped cs(_shared->crit_sec());
niklase@google.com470e71d2011-07-07 08:21:25 +0000312
kma@webrtc.org0221b782012-09-08 00:09:26 +0000313 WebRtcSpl_Init();
314
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000315 if (_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000316 {
317 return 0;
318 }
319
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000320 if (_shared->process_thread())
niklase@google.com470e71d2011-07-07 08:21:25 +0000321 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000322 if (_shared->process_thread()->Start() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000323 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000324 _shared->SetLastError(VE_THREAD_ERROR, kTraceError,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000325 "Init() failed to start module process thread");
niklase@google.com470e71d2011-07-07 08:21:25 +0000326 return -1;
327 }
328 }
329
andrew@webrtc.org3192d652011-12-21 18:00:59 +0000330 // Create an internal ADM if the user has not added an external
henrika@google.com73d65512011-09-07 15:11:18 +0000331 // ADM implementation as input to Init().
332 if (external_adm == NULL)
niklase@google.com470e71d2011-07-07 08:21:25 +0000333 {
henrika@google.com73d65512011-09-07 15:11:18 +0000334 // Create the internal ADM implementation.
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000335 _shared->set_audio_device(AudioDeviceModuleImpl::Create(
336 VoEId(_shared->instance_id(), -1), _shared->audio_device_layer()));
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000337
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000338 if (_shared->audio_device() == NULL)
niklase@google.com470e71d2011-07-07 08:21:25 +0000339 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000340 _shared->SetLastError(VE_NO_MEMORY, kTraceCritical,
341 "Init() failed to create the ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +0000342 return -1;
343 }
344 }
henrika@google.com73d65512011-09-07 15:11:18 +0000345 else
346 {
347 // Use the already existing external ADM implementation.
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000348 _shared->set_audio_device(external_adm);
349 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
henrika@google.com73d65512011-09-07 15:11:18 +0000350 "An external ADM implementation will be used in VoiceEngine");
351 }
352
niklase@google.com470e71d2011-07-07 08:21:25 +0000353 // Register the ADM to the process thread, which will drive the error
354 // callback mechanism
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000355 if (_shared->process_thread() &&
356 _shared->process_thread()->RegisterModule(_shared->audio_device()) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000357 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000358 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
359 "Init() failed to register the ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +0000360 return -1;
361 }
362
363 bool available(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000364
365 // --------------------
366 // Reinitialize the ADM
367
368 // Register the AudioObserver implementation
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000369 if (_shared->audio_device()->RegisterEventObserver(this) != 0) {
370 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
371 "Init() failed to register event observer for the ADM");
xians@webrtc.org79af7342012-01-31 12:22:14 +0000372 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000373
374 // Register the AudioTransport implementation
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000375 if (_shared->audio_device()->RegisterAudioCallback(this) != 0) {
376 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
377 "Init() failed to register audio callback for the ADM");
xians@webrtc.org79af7342012-01-31 12:22:14 +0000378 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000379
380 // ADM initialization
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000381 if (_shared->audio_device()->Init() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000382 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000383 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
384 "Init() failed to initialize the ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +0000385 return -1;
386 }
387
388 // Initialize the default speaker
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000389 if (_shared->audio_device()->SetPlayoutDevice(
390 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000391 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000392 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000393 "Init() failed to set the default output device");
niklase@google.com470e71d2011-07-07 08:21:25 +0000394 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000395 if (_shared->audio_device()->SpeakerIsAvailable(&available) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000396 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000397 _shared->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000398 "Init() failed to check speaker availability, trying to "
399 "initialize speaker anyway");
niklase@google.com470e71d2011-07-07 08:21:25 +0000400 }
401 else if (!available)
402 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000403 _shared->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000404 "Init() speaker not available, trying to initialize speaker "
405 "anyway");
niklase@google.com470e71d2011-07-07 08:21:25 +0000406 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000407 if (_shared->audio_device()->InitSpeaker() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000408 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000409 _shared->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000410 "Init() failed to initialize the speaker");
niklase@google.com470e71d2011-07-07 08:21:25 +0000411 }
412
413 // Initialize the default microphone
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000414 if (_shared->audio_device()->SetRecordingDevice(
415 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000416 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000417 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000418 "Init() failed to set the default input device");
niklase@google.com470e71d2011-07-07 08:21:25 +0000419 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000420 if (_shared->audio_device()->MicrophoneIsAvailable(&available) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000421 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000422 _shared->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000423 "Init() failed to check microphone availability, trying to "
424 "initialize microphone anyway");
niklase@google.com470e71d2011-07-07 08:21:25 +0000425 }
426 else if (!available)
427 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000428 _shared->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000429 "Init() microphone not available, trying to initialize "
430 "microphone anyway");
niklase@google.com470e71d2011-07-07 08:21:25 +0000431 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000432 if (_shared->audio_device()->InitMicrophone() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000433 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000434 _shared->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000435 "Init() failed to initialize the microphone");
niklase@google.com470e71d2011-07-07 08:21:25 +0000436 }
437
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000438 // Set number of channels
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000439 if (_shared->audio_device()->StereoPlayoutIsAvailable(&available) != 0) {
440 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
441 "Init() failed to query stereo playout mode");
xians@webrtc.org79af7342012-01-31 12:22:14 +0000442 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000443 if (_shared->audio_device()->SetStereoPlayout(available) != 0)
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000444 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000445 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000446 "Init() failed to set mono/stereo playout mode");
447 }
andrew@webrtc.org3192d652011-12-21 18:00:59 +0000448
449 // TODO(andrew): These functions don't tell us whether stereo recording
450 // is truly available. We simply set the AudioProcessing input to stereo
451 // here, because we have to wait until receiving the first frame to
452 // determine the actual number of channels anyway.
453 //
454 // These functions may be changed; tracked here:
455 // http://code.google.com/p/webrtc/issues/detail?id=204
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000456 _shared->audio_device()->StereoRecordingIsAvailable(&available);
457 if (_shared->audio_device()->SetStereoRecording(available) != 0)
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000458 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000459 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000460 "Init() failed to set mono/stereo recording mode");
461 }
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000462
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000463 if (!audioproc) {
464 audioproc = AudioProcessing::Create(VoEId(_shared->instance_id(), -1));
465 if (!audioproc) {
466 LOG(LS_ERROR) << "Failed to create AudioProcessing.";
467 _shared->SetLastError(VE_NO_MEMORY);
468 return -1;
469 }
470 }
471 _shared->set_audio_processing(audioproc);
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000472
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000473 // Set the error state for any failures in this block.
474 _shared->SetLastError(VE_APM_ERROR);
475 if (audioproc->echo_cancellation()->set_device_sample_rate_hz(48000)) {
476 LOG_FERR1(LS_ERROR, set_device_sample_rate_hz, 48000);
477 return -1;
478 }
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000479
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +0000480 // Configure AudioProcessing components.
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000481 if (audioproc->high_pass_filter()->Enable(true) != 0) {
482 LOG_FERR1(LS_ERROR, high_pass_filter()->Enable, true);
483 return -1;
484 }
485 if (audioproc->echo_cancellation()->enable_drift_compensation(false) != 0) {
486 LOG_FERR1(LS_ERROR, enable_drift_compensation, false);
487 return -1;
488 }
489 if (audioproc->noise_suppression()->set_level(kDefaultNsMode) != 0) {
490 LOG_FERR1(LS_ERROR, noise_suppression()->set_level, kDefaultNsMode);
491 return -1;
492 }
493 GainControl* agc = audioproc->gain_control();
494 if (agc->set_analog_level_limits(kMinVolumeLevel, kMaxVolumeLevel) != 0) {
495 LOG_FERR2(LS_ERROR, agc->set_analog_level_limits, kMinVolumeLevel,
496 kMaxVolumeLevel);
497 return -1;
498 }
499 if (agc->set_mode(kDefaultAgcMode) != 0) {
500 LOG_FERR1(LS_ERROR, agc->set_mode, kDefaultAgcMode);
501 return -1;
502 }
503 if (agc->Enable(kDefaultAgcState) != 0) {
504 LOG_FERR1(LS_ERROR, agc->Enable, kDefaultAgcState);
505 return -1;
506 }
507 _shared->SetLastError(0); // Clear error state.
508
niklase@google.com470e71d2011-07-07 08:21:25 +0000509#ifdef WEBRTC_VOICE_ENGINE_AGC
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000510 bool agc_enabled = agc->mode() == GainControl::kAdaptiveAnalog &&
511 agc->is_enabled();
512 if (_shared->audio_device()->SetAGC(agc_enabled) != 0) {
513 LOG_FERR1(LS_ERROR, audio_device()->SetAGC, agc_enabled);
514 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR);
andrew@webrtc.orga9a1df02013-03-05 23:36:10 +0000515 // TODO(ajm): No error return here due to
516 // https://code.google.com/p/webrtc/issues/detail?id=1464
niklase@google.com470e71d2011-07-07 08:21:25 +0000517 }
518#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000519
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000520 return _shared->statistics().SetInitialized();
niklase@google.com470e71d2011-07-07 08:21:25 +0000521}
522
523int VoEBaseImpl::Terminate()
524{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000525 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000526 "Terminate()");
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000527 CriticalSectionScoped cs(_shared->crit_sec());
niklase@google.com470e71d2011-07-07 08:21:25 +0000528 return TerminateInternal();
529}
530
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000531int VoEBaseImpl::CreateChannel() {
532 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
533 "CreateChannel()");
534 CriticalSectionScoped cs(_shared->crit_sec());
535 if (!_shared->statistics().Initialized()) {
536 _shared->SetLastError(VE_NOT_INITED, kTraceError);
537 return -1;
538 }
539
540 voe::ChannelOwner channel_owner = _shared->channel_manager().CreateChannel();
541
542 return InitializeChannel(&channel_owner);
543}
544
545int VoEBaseImpl::CreateChannel(const Config& config) {
546 CriticalSectionScoped cs(_shared->crit_sec());
547 if (!_shared->statistics().Initialized()) {
548 _shared->SetLastError(VE_NOT_INITED, kTraceError);
549 return -1;
550 }
551 voe::ChannelOwner channel_owner = _shared->channel_manager().CreateChannel(
552 config);
553 return InitializeChannel(&channel_owner);
554}
555
556int VoEBaseImpl::InitializeChannel(voe::ChannelOwner* channel_owner)
niklase@google.com470e71d2011-07-07 08:21:25 +0000557{
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000558 if (channel_owner->channel()->SetEngineInformation(
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000559 _shared->statistics(),
560 *_shared->output_mixer(),
561 *_shared->transmit_mixer(),
562 *_shared->process_thread(),
563 *_shared->audio_device(),
564 _voiceEngineObserverPtr,
565 &_callbackCritSect) != 0) {
566 _shared->SetLastError(
567 VE_CHANNEL_NOT_CREATED,
568 kTraceError,
569 "CreateChannel() failed to associate engine and channel."
570 " Destroying channel.");
571 _shared->channel_manager()
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000572 .DestroyChannel(channel_owner->channel()->ChannelId());
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000573 return -1;
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000574 } else if (channel_owner->channel()->Init() != 0) {
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000575 _shared->SetLastError(
576 VE_CHANNEL_NOT_CREATED,
577 kTraceError,
578 "CreateChannel() failed to initialize channel. Destroying"
579 " channel.");
580 _shared->channel_manager()
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000581 .DestroyChannel(channel_owner->channel()->ChannelId());
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000582 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000583 }
584
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000585 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
586 VoEId(_shared->instance_id(), -1),
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000587 "CreateChannel() => %d", channel_owner->channel()->ChannelId());
588 return channel_owner->channel()->ChannelId();
niklase@google.com470e71d2011-07-07 08:21:25 +0000589}
590
591int VoEBaseImpl::DeleteChannel(int channel)
592{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000593 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000594 "DeleteChannel(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000595 CriticalSectionScoped cs(_shared->crit_sec());
niklase@google.com470e71d2011-07-07 08:21:25 +0000596
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000597 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000598 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000599 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000600 return -1;
601 }
602
603 {
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000604 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
605 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000606 if (channelPtr == NULL)
607 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000608 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
609 "DeleteChannel() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000610 return -1;
611 }
612 }
613
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000614 _shared->channel_manager().DestroyChannel(channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000615
616 if (StopSend() != 0)
617 {
618 return -1;
619 }
620
621 if (StopPlayout() != 0)
622 {
623 return -1;
624 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +0000625
niklase@google.com470e71d2011-07-07 08:21:25 +0000626 return 0;
627}
628
niklase@google.com470e71d2011-07-07 08:21:25 +0000629int VoEBaseImpl::StartReceive(int channel)
630{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000631 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000632 "StartReceive(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000633 CriticalSectionScoped cs(_shared->crit_sec());
634 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000635 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000636 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000637 return -1;
638 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000639 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
640 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000641 if (channelPtr == NULL)
642 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000643 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
644 "StartReceive() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000645 return -1;
646 }
647 return channelPtr->StartReceiving();
648}
649
650int VoEBaseImpl::StopReceive(int channel)
651{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000652 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000653 "StopListen(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000654 CriticalSectionScoped cs(_shared->crit_sec());
655 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000656 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000657 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000658 return -1;
659 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000660 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
661 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000662 if (channelPtr == NULL)
663 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000664 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
665 "SetLocalReceiver() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000666 return -1;
667 }
668 return channelPtr->StopReceiving();
669}
670
671int VoEBaseImpl::StartPlayout(int channel)
672{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000673 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000674 "StartPlayout(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000675 CriticalSectionScoped cs(_shared->crit_sec());
676 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000677 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000678 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000679 return -1;
680 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000681 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
682 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000683 if (channelPtr == NULL)
684 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000685 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
686 "StartPlayout() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000687 return -1;
688 }
689 if (channelPtr->Playing())
690 {
691 return 0;
692 }
693 if (StartPlayout() != 0)
694 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000695 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
696 "StartPlayout() failed to start playout");
niklase@google.com470e71d2011-07-07 08:21:25 +0000697 return -1;
698 }
699 return channelPtr->StartPlayout();
700}
701
702int VoEBaseImpl::StopPlayout(int channel)
703{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000704 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000705 "StopPlayout(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000706 CriticalSectionScoped cs(_shared->crit_sec());
707 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000708 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000709 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000710 return -1;
711 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000712 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
713 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000714 if (channelPtr == NULL)
715 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000716 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
717 "StopPlayout() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000718 return -1;
719 }
720 if (channelPtr->StopPlayout() != 0)
721 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000722 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
723 VoEId(_shared->instance_id(), -1),
724 "StopPlayout() failed to stop playout for channel %d", channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000725 }
726 return StopPlayout();
727}
728
729int VoEBaseImpl::StartSend(int channel)
730{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000731 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000732 "StartSend(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000733 CriticalSectionScoped cs(_shared->crit_sec());
734 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000735 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000736 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000737 return -1;
738 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000739 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
740 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000741 if (channelPtr == NULL)
742 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000743 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
744 "StartSend() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000745 return -1;
746 }
747 if (channelPtr->Sending())
748 {
749 return 0;
750 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000751 if (StartSend() != 0)
752 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000753 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
754 "StartSend() failed to start recording");
niklase@google.com470e71d2011-07-07 08:21:25 +0000755 return -1;
756 }
757 return channelPtr->StartSend();
758}
759
760int VoEBaseImpl::StopSend(int channel)
761{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000762 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000763 "StopSend(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000764 CriticalSectionScoped cs(_shared->crit_sec());
765 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000766 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000767 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000768 return -1;
769 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000770 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
771 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000772 if (channelPtr == NULL)
773 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000774 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
775 "StopSend() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000776 return -1;
777 }
778 if (channelPtr->StopSend() != 0)
779 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000780 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
781 VoEId(_shared->instance_id(), -1),
782 "StopSend() failed to stop sending for channel %d", channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000783 }
784 return StopSend();
785}
786
787int VoEBaseImpl::GetVersion(char version[1024])
788{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000789 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000790 "GetVersion(version=?)");
791 assert(kVoiceEngineVersionMaxMessageSize == 1024);
792
793 if (version == NULL)
794 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000795 _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000796 return (-1);
797 }
798
799 char versionBuf[kVoiceEngineVersionMaxMessageSize];
800 char* versionPtr = versionBuf;
801
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000802 int32_t len = 0;
803 int32_t accLen = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000804
805 len = AddVoEVersion(versionPtr);
806 if (len == -1)
807 {
808 return -1;
809 }
810 versionPtr += len;
811 accLen += len;
812 assert(accLen < kVoiceEngineVersionMaxMessageSize);
813
814 len = AddBuildInfo(versionPtr);
815 if (len == -1)
816 {
817 return -1;
818 }
819 versionPtr += len;
820 accLen += len;
821 assert(accLen < kVoiceEngineVersionMaxMessageSize);
822
pwestin@webrtc.org684f0572013-03-13 23:20:57 +0000823#ifdef WEBRTC_EXTERNAL_TRANSPORT
824 len = AddExternalTransportBuild(versionPtr);
825 if (len == -1)
826 {
827 return -1;
828 }
829 versionPtr += len;
830 accLen += len;
831 assert(accLen < kVoiceEngineVersionMaxMessageSize);
832#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000833#ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT
834 len = AddExternalRecAndPlayoutBuild(versionPtr);
835 if (len == -1)
836 {
837 return -1;
838 }
839 versionPtr += len;
840 accLen += len;
841 assert(accLen < kVoiceEngineVersionMaxMessageSize);
pwestin@webrtc.orgc450a192012-01-04 15:00:12 +0000842 #endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000843
844 memcpy(version, versionBuf, accLen);
845 version[accLen] = '\0';
846
847 // to avoid the truncation in the trace, split the string into parts
848 char partOfVersion[256];
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000849 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
850 VoEId(_shared->instance_id(), -1), "GetVersion() =>");
niklase@google.com470e71d2011-07-07 08:21:25 +0000851 for (int partStart = 0; partStart < accLen;)
852 {
853 memset(partOfVersion, 0, sizeof(partOfVersion));
854 int partEnd = partStart + 180;
855 while (version[partEnd] != '\n' && version[partEnd] != '\0')
856 {
857 partEnd--;
858 }
859 if (partEnd < accLen)
860 {
861 memcpy(partOfVersion, &version[partStart], partEnd - partStart);
862 }
863 else
864 {
865 memcpy(partOfVersion, &version[partStart], accLen - partStart);
866 }
867 partStart = partEnd;
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000868 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
869 VoEId(_shared->instance_id(), -1), "%s", partOfVersion);
niklase@google.com470e71d2011-07-07 08:21:25 +0000870 }
871
872 return 0;
873}
874
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000875int32_t VoEBaseImpl::AddBuildInfo(char* str) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000876{
andrew@webrtc.org3054ba62013-12-04 17:00:44 +0000877 return sprintf(str, "Build: %s\n", BUILDINFO);
niklase@google.com470e71d2011-07-07 08:21:25 +0000878}
879
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000880int32_t VoEBaseImpl::AddVoEVersion(char* str) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000881{
882 return sprintf(str, "VoiceEngine 4.1.0\n");
883}
884
pwestin@webrtc.org684f0572013-03-13 23:20:57 +0000885#ifdef WEBRTC_EXTERNAL_TRANSPORT
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000886int32_t VoEBaseImpl::AddExternalTransportBuild(char* str) const
pwestin@webrtc.org684f0572013-03-13 23:20:57 +0000887{
888 return sprintf(str, "External transport build\n");
889}
890#endif
891
niklase@google.com470e71d2011-07-07 08:21:25 +0000892#ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000893int32_t VoEBaseImpl::AddExternalRecAndPlayoutBuild(char* str) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000894{
895 return sprintf(str, "External recording and playout build\n");
896}
897#endif
898
niklase@google.com470e71d2011-07-07 08:21:25 +0000899int VoEBaseImpl::LastError()
900{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000901 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000902 "LastError()");
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000903 return (_shared->statistics().LastError());
niklase@google.com470e71d2011-07-07 08:21:25 +0000904}
905
906
907int VoEBaseImpl::SetNetEQPlayoutMode(int channel, NetEqModes mode)
908{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000909 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000910 "SetNetEQPlayoutMode(channel=%i, mode=%i)", channel, mode);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000911 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000912 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000913 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000914 return -1;
915 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000916 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
917 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000918 if (channelPtr == NULL)
919 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000920 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
921 "SetNetEQPlayoutMode() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000922 return -1;
923 }
924 return channelPtr->SetNetEQPlayoutMode(mode);
925}
926
927int VoEBaseImpl::GetNetEQPlayoutMode(int channel, NetEqModes& mode)
928{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000929 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000930 "GetNetEQPlayoutMode(channel=%i, mode=?)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000931 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000932 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000933 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000934 return -1;
935 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000936 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
937 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000938 if (channelPtr == NULL)
939 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000940 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
941 "GetNetEQPlayoutMode() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000942 return -1;
943 }
944 return channelPtr->GetNetEQPlayoutMode(mode);
945}
946
niklase@google.com470e71d2011-07-07 08:21:25 +0000947int VoEBaseImpl::SetOnHoldStatus(int channel, bool enable, OnHoldModes mode)
948{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000949 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000950 "SetOnHoldStatus(channel=%d, enable=%d, mode=%d)", channel,
951 enable, mode);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000952 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000953 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000954 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000955 return -1;
956 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000957 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
958 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000959 if (channelPtr == NULL)
960 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000961 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
962 "SetOnHoldStatus() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000963 return -1;
964 }
965 return channelPtr->SetOnHoldStatus(enable, mode);
966}
967
968int VoEBaseImpl::GetOnHoldStatus(int channel, bool& enabled, OnHoldModes& mode)
969{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000970 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000971 "GetOnHoldStatus(channel=%d, enabled=?, mode=?)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000972 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000973 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000974 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000975 return -1;
976 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000977 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
978 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000979 if (channelPtr == NULL)
980 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000981 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
982 "GetOnHoldStatus() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000983 return -1;
984 }
985 return channelPtr->GetOnHoldStatus(enabled, mode);
986}
987
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000988int32_t VoEBaseImpl::StartPlayout()
niklase@google.com470e71d2011-07-07 08:21:25 +0000989{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000990 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000991 "VoEBaseImpl::StartPlayout()");
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000992 if (_shared->audio_device()->Playing())
niklase@google.com470e71d2011-07-07 08:21:25 +0000993 {
994 return 0;
995 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000996 if (!_shared->ext_playout())
niklase@google.com470e71d2011-07-07 08:21:25 +0000997 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000998 if (_shared->audio_device()->InitPlayout() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000999 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001000 WEBRTC_TRACE(kTraceError, kTraceVoice,
1001 VoEId(_shared->instance_id(), -1),
1002 "StartPlayout() failed to initialize playout");
niklase@google.com470e71d2011-07-07 08:21:25 +00001003 return -1;
1004 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001005 if (_shared->audio_device()->StartPlayout() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001006 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001007 WEBRTC_TRACE(kTraceError, kTraceVoice,
1008 VoEId(_shared->instance_id(), -1),
1009 "StartPlayout() failed to start playout");
niklase@google.com470e71d2011-07-07 08:21:25 +00001010 return -1;
1011 }
1012 }
1013 return 0;
1014}
1015
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +00001016int32_t VoEBaseImpl::StopPlayout() {
1017 WEBRTC_TRACE(kTraceInfo,
1018 kTraceVoice,
1019 VoEId(_shared->instance_id(), -1),
1020 "VoEBaseImpl::StopPlayout()");
1021 // Stop audio-device playing if no channel is playing out
xians@webrtc.org675e2602013-10-17 16:15:34 +00001022 if (_shared->NumOfPlayingChannels() == 0) {
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +00001023 if (_shared->audio_device()->StopPlayout() != 0) {
1024 _shared->SetLastError(VE_CANNOT_STOP_PLAYOUT,
1025 kTraceError,
1026 "StopPlayout() failed to stop playout");
1027 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001028 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +00001029 }
1030 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001031}
1032
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001033int32_t VoEBaseImpl::StartSend()
niklase@google.com470e71d2011-07-07 08:21:25 +00001034{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001035 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001036 "VoEBaseImpl::StartSend()");
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001037 if (_shared->audio_device()->Recording())
niklase@google.com470e71d2011-07-07 08:21:25 +00001038 {
1039 return 0;
1040 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001041 if (!_shared->ext_recording())
niklase@google.com470e71d2011-07-07 08:21:25 +00001042 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001043 if (_shared->audio_device()->InitRecording() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001044 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001045 WEBRTC_TRACE(kTraceError, kTraceVoice,
1046 VoEId(_shared->instance_id(), -1),
1047 "StartSend() failed to initialize recording");
niklase@google.com470e71d2011-07-07 08:21:25 +00001048 return -1;
1049 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001050 if (_shared->audio_device()->StartRecording() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001051 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001052 WEBRTC_TRACE(kTraceError, kTraceVoice,
1053 VoEId(_shared->instance_id(), -1),
1054 "StartSend() failed to start recording");
niklase@google.com470e71d2011-07-07 08:21:25 +00001055 return -1;
1056 }
1057 }
1058
1059 return 0;
1060}
1061
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001062int32_t VoEBaseImpl::StopSend()
niklase@google.com470e71d2011-07-07 08:21:25 +00001063{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001064 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001065 "VoEBaseImpl::StopSend()");
1066
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001067 if (_shared->NumOfSendingChannels() == 0 &&
1068 !_shared->transmit_mixer()->IsRecordingMic())
niklase@google.com470e71d2011-07-07 08:21:25 +00001069 {
1070 // Stop audio-device recording if no channel is recording
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001071 if (_shared->audio_device()->StopRecording() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001072 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001073 _shared->SetLastError(VE_CANNOT_STOP_RECORDING, kTraceError,
1074 "StopSend() failed to stop recording");
niklase@google.com470e71d2011-07-07 08:21:25 +00001075 return -1;
1076 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001077 _shared->transmit_mixer()->StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +00001078 }
1079
1080 return 0;
1081}
1082
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001083int32_t VoEBaseImpl::TerminateInternal()
niklase@google.com470e71d2011-07-07 08:21:25 +00001084{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001085 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001086 "VoEBaseImpl::TerminateInternal()");
1087
1088 // Delete any remaining channel objects
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +00001089 _shared->channel_manager().DestroyAllChannels();
niklase@google.com470e71d2011-07-07 08:21:25 +00001090
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001091 if (_shared->process_thread())
niklase@google.com470e71d2011-07-07 08:21:25 +00001092 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001093 if (_shared->audio_device())
niklase@google.com470e71d2011-07-07 08:21:25 +00001094 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001095 if (_shared->process_thread()->
1096 DeRegisterModule(_shared->audio_device()) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001097 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001098 _shared->SetLastError(VE_THREAD_ERROR, kTraceError,
1099 "TerminateInternal() failed to deregister ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +00001100 }
1101 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001102 if (_shared->process_thread()->Stop() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001103 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001104 _shared->SetLastError(VE_THREAD_ERROR, kTraceError,
1105 "TerminateInternal() failed to stop module process thread");
niklase@google.com470e71d2011-07-07 08:21:25 +00001106 }
1107 }
1108
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +00001109 if (_shared->audio_device())
niklase@google.com470e71d2011-07-07 08:21:25 +00001110 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001111 if (_shared->audio_device()->StopPlayout() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001112 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001113 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
1114 "TerminateInternal() failed to stop playout");
niklase@google.com470e71d2011-07-07 08:21:25 +00001115 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001116 if (_shared->audio_device()->StopRecording() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001117 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001118 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
1119 "TerminateInternal() failed to stop recording");
niklase@google.com470e71d2011-07-07 08:21:25 +00001120 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001121 if (_shared->audio_device()->RegisterEventObserver(NULL) != 0) {
1122 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
1123 "TerminateInternal() failed to de-register event observer "
1124 "for the ADM");
xians@webrtc.org79af7342012-01-31 12:22:14 +00001125 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001126 if (_shared->audio_device()->RegisterAudioCallback(NULL) != 0) {
1127 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
1128 "TerminateInternal() failed to de-register audio callback "
1129 "for the ADM");
xians@webrtc.org79af7342012-01-31 12:22:14 +00001130 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001131 if (_shared->audio_device()->Terminate() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001132 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001133 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
1134 "TerminateInternal() failed to terminate the ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +00001135 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001136 _shared->set_audio_device(NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +00001137 }
1138
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +00001139 if (_shared->audio_processing()) {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001140 _shared->set_audio_processing(NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +00001141 }
1142
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001143 return _shared->statistics().SetUnInitialized();
niklase@google.com470e71d2011-07-07 08:21:25 +00001144}
1145
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00001146int VoEBaseImpl::ProcessRecordedDataWithAPM(
1147 const int voe_channels[],
1148 int number_of_voe_channels,
1149 const void* audio_data,
1150 uint32_t sample_rate,
1151 uint8_t number_of_channels,
1152 uint32_t number_of_frames,
1153 uint32_t audio_delay_milliseconds,
1154 int32_t clock_drift,
1155 uint32_t current_volume,
1156 bool key_pressed) {
1157 assert(_shared->transmit_mixer() != NULL);
1158 assert(_shared->audio_device() != NULL);
1159
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00001160 uint32_t max_volume = 0;
1161 uint16_t current_voe_mic_level = 0;
andrew@webrtc.org023cc5a2014-01-11 01:25:53 +00001162 // Check for zero to skip this calculation; the consumer may use this to
1163 // indicate no volume is available.
1164 if (current_volume != 0) {
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00001165 // Scale from ADM to VoE level range
1166 if (_shared->audio_device()->MaxMicrophoneVolume(&max_volume) == 0) {
1167 if (max_volume) {
1168 current_voe_mic_level = static_cast<uint16_t>(
1169 (current_volume * kMaxVolumeLevel +
1170 static_cast<int>(max_volume / 2)) / max_volume);
1171 }
1172 }
1173 // We learned that on certain systems (e.g Linux) the current_voe_mic_level
1174 // can be greater than the maxVolumeLevel therefore
1175 // we are going to cap the current_voe_mic_level to the maxVolumeLevel
1176 // and change the maxVolume to current_volume if it turns out that
1177 // the current_voe_mic_level is indeed greater than the maxVolumeLevel.
1178 if (current_voe_mic_level > kMaxVolumeLevel) {
1179 current_voe_mic_level = kMaxVolumeLevel;
1180 max_volume = current_volume;
1181 }
1182 }
1183
1184 // Keep track if the MicLevel has been changed by the AGC, if not,
1185 // use the old value AGC returns to let AGC continue its trend,
1186 // so eventually the AGC is able to change the mic level. This handles
1187 // issues with truncation introduced by the scaling.
1188 if (_oldMicLevel == current_volume)
1189 current_voe_mic_level = static_cast<uint16_t>(_oldVoEMicLevel);
1190
1191 // Perform channel-independent operations
1192 // (APM, mix with file, record to file, mute, etc.)
1193 _shared->transmit_mixer()->PrepareDemux(
1194 audio_data, number_of_frames, number_of_channels, sample_rate,
1195 static_cast<uint16_t>(audio_delay_milliseconds), clock_drift,
1196 current_voe_mic_level, key_pressed);
1197
1198 // Copy the audio frame to each sending channel and perform
1199 // channel-dependent operations (file mixing, mute, etc.), encode and
1200 // packetize+transmit the RTP packet. When |number_of_voe_channels| == 0,
1201 // do the operations on all the existing VoE channels; otherwise the
1202 // operations will be done on specific channels.
1203 if (number_of_voe_channels == 0) {
1204 _shared->transmit_mixer()->DemuxAndMix();
1205 _shared->transmit_mixer()->EncodeAndSend();
1206 } else {
1207 _shared->transmit_mixer()->DemuxAndMix(voe_channels,
1208 number_of_voe_channels);
1209 _shared->transmit_mixer()->EncodeAndSend(voe_channels,
1210 number_of_voe_channels);
1211 }
1212
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00001213 // Scale from VoE to ADM level range.
1214 uint32_t new_voe_mic_level = _shared->transmit_mixer()->CaptureLevel();
1215
1216 // Keep track of the value AGC returns.
1217 _oldVoEMicLevel = new_voe_mic_level;
1218 _oldMicLevel = current_volume;
1219
1220 if (new_voe_mic_level != current_voe_mic_level) {
1221 // Return the new volume if AGC has changed the volume.
1222 return static_cast<int>(
1223 (new_voe_mic_level * max_volume +
1224 static_cast<int>(kMaxVolumeLevel / 2)) / kMaxVolumeLevel);
1225 }
1226
1227 // Return 0 to indicate no change on the volume.
1228 return 0;
1229}
1230
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00001231} // namespace webrtc