blob: 3b7a193cce6db8231c47328c6dbb5cd2ac59e968 [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
pbos@webrtc.org956aa7e2013-05-21 13:52:32 +000013#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
14#include "webrtc/modules/audio_coding/main/interface/audio_coding_module.h"
15#include "webrtc/modules/audio_device/audio_device_impl.h"
16#include "webrtc/modules/audio_processing/include/audio_processing.h"
17#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
18#include "webrtc/system_wrappers/interface/file_wrapper.h"
19#include "webrtc/system_wrappers/interface/trace.h"
20#include "webrtc/voice_engine/channel.h"
21#include "webrtc/voice_engine/include/voe_errors.h"
22#include "webrtc/voice_engine/output_mixer.h"
23#include "webrtc/voice_engine/transmit_mixer.h"
24#include "webrtc/voice_engine/utility.h"
25#include "webrtc/voice_engine/voice_engine_impl.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000026
27#if (defined(_WIN32) && defined(_DLL) && (_MSC_VER == 1400))
28// Fix for VS 2005 MD/MDd link problem
29#include <stdio.h>
30extern "C"
31 { FILE _iob[3] = { __iob_func()[0], __iob_func()[1], __iob_func()[2]}; }
32#endif
33
34namespace webrtc
35{
36
37VoEBase* VoEBase::GetInterface(VoiceEngine* voiceEngine)
38{
39 if (NULL == voiceEngine)
40 {
41 return NULL;
42 }
tommi@webrtc.org0989fb72013-02-15 15:07:32 +000043 VoiceEngineImpl* s = static_cast<VoiceEngineImpl*>(voiceEngine);
tommi@webrtc.orga990e122012-04-26 15:28:22 +000044 s->AddRef();
45 return s;
niklase@google.com470e71d2011-07-07 08:21:25 +000046}
47
tommi@webrtc.org851becd2012-04-04 14:57:19 +000048VoEBaseImpl::VoEBaseImpl(voe::SharedData* shared) :
niklase@google.com470e71d2011-07-07 08:21:25 +000049 _voiceEngineObserverPtr(NULL),
50 _callbackCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
tommi@webrtc.org851becd2012-04-04 14:57:19 +000051 _voiceEngineObserver(false), _oldVoEMicLevel(0), _oldMicLevel(0),
52 _shared(shared)
niklase@google.com470e71d2011-07-07 08:21:25 +000053{
tommi@webrtc.org851becd2012-04-04 14:57:19 +000054 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +000055 "VoEBaseImpl() - ctor");
56}
57
58VoEBaseImpl::~VoEBaseImpl()
59{
tommi@webrtc.org851becd2012-04-04 14:57:19 +000060 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +000061 "~VoEBaseImpl() - dtor");
62
63 TerminateInternal();
64
65 delete &_callbackCritSect;
66}
67
pbos@webrtc.org92135212013-05-14 08:31:39 +000068void VoEBaseImpl::OnErrorIsReported(ErrorCode error)
niklase@google.com470e71d2011-07-07 08:21:25 +000069{
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +000070 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +000071 if (_voiceEngineObserver)
72 {
73 if (_voiceEngineObserverPtr)
74 {
75 int errCode(0);
76 if (error == AudioDeviceObserver::kRecordingError)
77 {
78 errCode = VE_RUNTIME_REC_ERROR;
tommi@webrtc.org851becd2012-04-04 14:57:19 +000079 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
80 VoEId(_shared->instance_id(), -1),
81 "VoEBaseImpl::OnErrorIsReported() => VE_RUNTIME_REC_ERROR");
niklase@google.com470e71d2011-07-07 08:21:25 +000082 }
83 else if (error == AudioDeviceObserver::kPlayoutError)
84 {
85 errCode = VE_RUNTIME_PLAY_ERROR;
tommi@webrtc.org851becd2012-04-04 14:57:19 +000086 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
87 VoEId(_shared->instance_id(), -1),
88 "VoEBaseImpl::OnErrorIsReported() => "
89 "VE_RUNTIME_PLAY_ERROR");
niklase@google.com470e71d2011-07-07 08:21:25 +000090 }
91 // Deliver callback (-1 <=> no channel dependency)
92 _voiceEngineObserverPtr->CallbackOnError(-1, errCode);
93 }
94 }
95}
96
pbos@webrtc.org92135212013-05-14 08:31:39 +000097void VoEBaseImpl::OnWarningIsReported(WarningCode warning)
niklase@google.com470e71d2011-07-07 08:21:25 +000098{
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +000099 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000100 if (_voiceEngineObserver)
101 {
102 if (_voiceEngineObserverPtr)
103 {
104 int warningCode(0);
105 if (warning == AudioDeviceObserver::kRecordingWarning)
106 {
107 warningCode = VE_RUNTIME_REC_WARNING;
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000108 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
109 VoEId(_shared->instance_id(), -1),
110 "VoEBaseImpl::OnErrorIsReported() => "
111 "VE_RUNTIME_REC_WARNING");
niklase@google.com470e71d2011-07-07 08:21:25 +0000112 }
113 else if (warning == AudioDeviceObserver::kPlayoutWarning)
114 {
115 warningCode = VE_RUNTIME_PLAY_WARNING;
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000116 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
117 VoEId(_shared->instance_id(), -1),
118 "VoEBaseImpl::OnErrorIsReported() => "
119 "VE_RUNTIME_PLAY_WARNING");
niklase@google.com470e71d2011-07-07 08:21:25 +0000120 }
121 // Deliver callback (-1 <=> no channel dependency)
122 _voiceEngineObserverPtr->CallbackOnError(-1, warningCode);
123 }
124 }
125}
126
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000127int32_t VoEBaseImpl::RecordedDataIsAvailable(
henrika@webrtc.org907bc552012-03-09 08:59:19 +0000128 const void* audioSamples,
pbos@webrtc.org92135212013-05-14 08:31:39 +0000129 uint32_t nSamples,
130 uint8_t nBytesPerSample,
131 uint8_t nChannels,
132 uint32_t samplesPerSec,
133 uint32_t totalDelayMS,
134 int32_t clockDrift,
135 uint32_t currentMicLevel,
136 bool keyPressed,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000137 uint32_t& newMicLevel)
niklase@google.com470e71d2011-07-07 08:21:25 +0000138{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000139 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000140 "VoEBaseImpl::RecordedDataIsAvailable(nSamples=%u, "
141 "nBytesPerSample=%u, nChannels=%u, samplesPerSec=%u, "
142 "totalDelayMS=%u, clockDrift=%d, currentMicLevel=%u)",
143 nSamples, nBytesPerSample, nChannels, samplesPerSec,
144 totalDelayMS, clockDrift, currentMicLevel);
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000145 newMicLevel = static_cast<uint32_t>(ProcessRecordedDataWithAPM(
146 NULL, 0, audioSamples, samplesPerSec, nChannels, nSamples,
147 totalDelayMS, clockDrift, currentMicLevel, keyPressed));
niklase@google.com470e71d2011-07-07 08:21:25 +0000148
149 return 0;
150}
151
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000152int32_t VoEBaseImpl::NeedMorePlayData(
pbos@webrtc.org92135212013-05-14 08:31:39 +0000153 uint32_t nSamples,
154 uint8_t nBytesPerSample,
155 uint8_t nChannels,
156 uint32_t samplesPerSec,
henrika@webrtc.org907bc552012-03-09 08:59:19 +0000157 void* audioSamples,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000158 uint32_t& nSamplesOut)
niklase@google.com470e71d2011-07-07 08:21:25 +0000159{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000160 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000161 "VoEBaseImpl::NeedMorePlayData(nSamples=%u, "
162 "nBytesPerSample=%d, nChannels=%d, samplesPerSec=%u)",
163 nSamples, nBytesPerSample, nChannels, samplesPerSec);
164
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000165 assert(_shared->output_mixer() != NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000166
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +0000167 // TODO(andrew): if the device is running in mono, we should tell the mixer
168 // here so that it will only request mono from AudioCodingModule.
niklase@google.com470e71d2011-07-07 08:21:25 +0000169 // Perform mixing of all active participants (channel-based mixing)
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000170 _shared->output_mixer()->MixActiveChannels();
niklase@google.com470e71d2011-07-07 08:21:25 +0000171
172 // Additional operations on the combined signal
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000173 _shared->output_mixer()->DoOperationsOnCombinedSignal();
niklase@google.com470e71d2011-07-07 08:21:25 +0000174
175 // Retrieve the final output mix (resampled to match the ADM)
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000176 _shared->output_mixer()->GetMixedAudio(samplesPerSec, nChannels,
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +0000177 &_audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000178
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +0000179 assert(static_cast<int>(nSamples) == _audioFrame.samples_per_channel_);
xians@google.com0b0665a2011-08-08 08:18:44 +0000180 assert(samplesPerSec ==
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000181 static_cast<uint32_t>(_audioFrame.sample_rate_hz_));
niklase@google.com470e71d2011-07-07 08:21:25 +0000182
183 // Deliver audio (PCM) samples to the ADM
184 memcpy(
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000185 (int16_t*) audioSamples,
186 (const int16_t*) _audioFrame.data_,
187 sizeof(int16_t) * (_audioFrame.samples_per_channel_
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000188 * _audioFrame.num_channels_));
niklase@google.com470e71d2011-07-07 08:21:25 +0000189
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000190 nSamplesOut = _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000191
192 return 0;
193}
194
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000195int VoEBaseImpl::OnDataAvailable(const int voe_channels[],
xians@webrtc.org2f84afa2013-07-31 16:23:37 +0000196 int number_of_voe_channels,
197 const int16_t* audio_data,
198 int sample_rate,
199 int number_of_channels,
200 int number_of_frames,
201 int audio_delay_milliseconds,
202 int current_volume,
203 bool key_pressed,
204 bool need_audio_processing) {
205 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_shared->instance_id(), -1),
206 "VoEBaseImpl::OnDataAvailable(number_of_voe_channels=%d, "
207 "sample_rate=%d, number_of_channels=%d, number_of_frames=%d, "
208 "audio_delay_milliseconds=%d, current_volume=%d, "
209 "key_pressed=%d, need_audio_processing=%d)",
210 number_of_voe_channels, sample_rate, number_of_channels,
211 number_of_frames, audio_delay_milliseconds, current_volume,
212 key_pressed, need_audio_processing);
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000213 if (number_of_voe_channels == 0)
214 return 0;
xians@webrtc.org2f84afa2013-07-31 16:23:37 +0000215
216 if (need_audio_processing) {
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000217 return ProcessRecordedDataWithAPM(
218 voe_channels, number_of_voe_channels, audio_data, sample_rate,
219 number_of_channels, number_of_frames, audio_delay_milliseconds,
220 0, current_volume, key_pressed);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +0000221 }
222
223 // No need to go through the APM, demultiplex the data to each VoE channel,
224 // encode and send to the network.
225 for (int i = 0; i < number_of_voe_channels; ++i) {
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000226 voe::ChannelOwner ch =
227 _shared->channel_manager().GetChannel(voe_channels[i]);
228 voe::Channel* channel_ptr = ch.channel();
xians@webrtc.org2f84afa2013-07-31 16:23:37 +0000229 if (!channel_ptr)
230 continue;
231
232 if (channel_ptr->InputIsOnHold()) {
233 channel_ptr->UpdateLocalTimeStamp();
234 } else if (channel_ptr->Sending()) {
235 channel_ptr->Demultiplex(audio_data, sample_rate, number_of_frames,
236 number_of_channels);
237 channel_ptr->PrepareEncodeAndSend(sample_rate);
238 channel_ptr->EncodeAndSend();
239 }
240 }
241
242 // Return 0 to indicate no need to change the volume.
243 return 0;
244}
245
niklase@google.com470e71d2011-07-07 08:21:25 +0000246int VoEBaseImpl::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
247{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000248 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000249 "RegisterVoiceEngineObserver(observer=0x%d)", &observer);
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000250 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000251 if (_voiceEngineObserverPtr)
252 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000253 _shared->SetLastError(VE_INVALID_OPERATION, kTraceError,
254 "RegisterVoiceEngineObserver() observer already enabled");
niklase@google.com470e71d2011-07-07 08:21:25 +0000255 return -1;
256 }
257
258 // Register the observer in all active channels
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000259 for (voe::ChannelManager::Iterator it(&_shared->channel_manager());
260 it.IsValid();
261 it.Increment()) {
262 it.GetChannel()->RegisterVoiceEngineObserver(observer);
niklase@google.com470e71d2011-07-07 08:21:25 +0000263 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000264
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000265 _shared->transmit_mixer()->RegisterVoiceEngineObserver(observer);
niklase@google.com470e71d2011-07-07 08:21:25 +0000266
267 _voiceEngineObserverPtr = &observer;
268 _voiceEngineObserver = true;
269
270 return 0;
271}
272
273int VoEBaseImpl::DeRegisterVoiceEngineObserver()
274{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000275 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000276 "DeRegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000277 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000278 if (!_voiceEngineObserverPtr)
279 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000280 _shared->SetLastError(VE_INVALID_OPERATION, kTraceError,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000281 "DeRegisterVoiceEngineObserver() observer already disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +0000282 return 0;
283 }
284
285 _voiceEngineObserver = false;
286 _voiceEngineObserverPtr = NULL;
287
288 // Deregister the observer in all active channels
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000289 for (voe::ChannelManager::Iterator it(&_shared->channel_manager());
290 it.IsValid();
291 it.Increment()) {
292 it.GetChannel()->DeRegisterVoiceEngineObserver();
niklase@google.com470e71d2011-07-07 08:21:25 +0000293 }
294
295 return 0;
296}
297
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000298int VoEBaseImpl::Init(AudioDeviceModule* external_adm,
299 AudioProcessing* audioproc)
niklase@google.com470e71d2011-07-07 08:21:25 +0000300{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000301 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
henrika@google.com73d65512011-09-07 15:11:18 +0000302 "Init(external_adm=0x%p)", external_adm);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000303 CriticalSectionScoped cs(_shared->crit_sec());
niklase@google.com470e71d2011-07-07 08:21:25 +0000304
kma@webrtc.org0221b782012-09-08 00:09:26 +0000305 WebRtcSpl_Init();
306
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000307 if (_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000308 {
309 return 0;
310 }
311
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000312 if (_shared->process_thread())
niklase@google.com470e71d2011-07-07 08:21:25 +0000313 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000314 if (_shared->process_thread()->Start() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000315 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000316 _shared->SetLastError(VE_THREAD_ERROR, kTraceError,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000317 "Init() failed to start module process thread");
niklase@google.com470e71d2011-07-07 08:21:25 +0000318 return -1;
319 }
320 }
321
andrew@webrtc.org3192d652011-12-21 18:00:59 +0000322 // Create an internal ADM if the user has not added an external
henrika@google.com73d65512011-09-07 15:11:18 +0000323 // ADM implementation as input to Init().
324 if (external_adm == NULL)
niklase@google.com470e71d2011-07-07 08:21:25 +0000325 {
henrika@google.com73d65512011-09-07 15:11:18 +0000326 // Create the internal ADM implementation.
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000327 _shared->set_audio_device(AudioDeviceModuleImpl::Create(
328 VoEId(_shared->instance_id(), -1), _shared->audio_device_layer()));
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000329
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000330 if (_shared->audio_device() == NULL)
niklase@google.com470e71d2011-07-07 08:21:25 +0000331 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000332 _shared->SetLastError(VE_NO_MEMORY, kTraceCritical,
333 "Init() failed to create the ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +0000334 return -1;
335 }
336 }
henrika@google.com73d65512011-09-07 15:11:18 +0000337 else
338 {
339 // Use the already existing external ADM implementation.
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000340 _shared->set_audio_device(external_adm);
341 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
henrika@google.com73d65512011-09-07 15:11:18 +0000342 "An external ADM implementation will be used in VoiceEngine");
343 }
344
niklase@google.com470e71d2011-07-07 08:21:25 +0000345 // Register the ADM to the process thread, which will drive the error
346 // callback mechanism
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000347 if (_shared->process_thread() &&
348 _shared->process_thread()->RegisterModule(_shared->audio_device()) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000349 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000350 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
351 "Init() failed to register the ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +0000352 return -1;
353 }
354
355 bool available(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000356
357 // --------------------
358 // Reinitialize the ADM
359
360 // Register the AudioObserver implementation
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000361 if (_shared->audio_device()->RegisterEventObserver(this) != 0) {
362 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
363 "Init() failed to register event observer for the ADM");
xians@webrtc.org79af7342012-01-31 12:22:14 +0000364 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000365
366 // Register the AudioTransport implementation
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000367 if (_shared->audio_device()->RegisterAudioCallback(this) != 0) {
368 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
369 "Init() failed to register audio callback for the ADM");
xians@webrtc.org79af7342012-01-31 12:22:14 +0000370 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000371
372 // ADM initialization
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000373 if (_shared->audio_device()->Init() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000374 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000375 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
376 "Init() failed to initialize the ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +0000377 return -1;
378 }
379
380 // Initialize the default speaker
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000381 if (_shared->audio_device()->SetPlayoutDevice(
382 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000383 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000384 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000385 "Init() failed to set the default output device");
niklase@google.com470e71d2011-07-07 08:21:25 +0000386 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000387 if (_shared->audio_device()->SpeakerIsAvailable(&available) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000388 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000389 _shared->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000390 "Init() failed to check speaker availability, trying to "
391 "initialize speaker anyway");
niklase@google.com470e71d2011-07-07 08:21:25 +0000392 }
393 else if (!available)
394 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000395 _shared->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000396 "Init() speaker not available, trying to initialize speaker "
397 "anyway");
niklase@google.com470e71d2011-07-07 08:21:25 +0000398 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000399 if (_shared->audio_device()->InitSpeaker() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000400 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000401 _shared->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000402 "Init() failed to initialize the speaker");
niklase@google.com470e71d2011-07-07 08:21:25 +0000403 }
404
405 // Initialize the default microphone
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000406 if (_shared->audio_device()->SetRecordingDevice(
407 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000408 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000409 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000410 "Init() failed to set the default input device");
niklase@google.com470e71d2011-07-07 08:21:25 +0000411 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000412 if (_shared->audio_device()->MicrophoneIsAvailable(&available) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000413 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000414 _shared->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000415 "Init() failed to check microphone availability, trying to "
416 "initialize microphone anyway");
niklase@google.com470e71d2011-07-07 08:21:25 +0000417 }
418 else if (!available)
419 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000420 _shared->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000421 "Init() microphone not available, trying to initialize "
422 "microphone anyway");
niklase@google.com470e71d2011-07-07 08:21:25 +0000423 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000424 if (_shared->audio_device()->InitMicrophone() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000425 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000426 _shared->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000427 "Init() failed to initialize the microphone");
niklase@google.com470e71d2011-07-07 08:21:25 +0000428 }
429
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000430 // Set number of channels
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000431 if (_shared->audio_device()->StereoPlayoutIsAvailable(&available) != 0) {
432 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
433 "Init() failed to query stereo playout mode");
xians@webrtc.org79af7342012-01-31 12:22:14 +0000434 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000435 if (_shared->audio_device()->SetStereoPlayout(available) != 0)
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000436 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000437 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000438 "Init() failed to set mono/stereo playout mode");
439 }
andrew@webrtc.org3192d652011-12-21 18:00:59 +0000440
441 // TODO(andrew): These functions don't tell us whether stereo recording
442 // is truly available. We simply set the AudioProcessing input to stereo
443 // here, because we have to wait until receiving the first frame to
444 // determine the actual number of channels anyway.
445 //
446 // These functions may be changed; tracked here:
447 // http://code.google.com/p/webrtc/issues/detail?id=204
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000448 _shared->audio_device()->StereoRecordingIsAvailable(&available);
449 if (_shared->audio_device()->SetStereoRecording(available) != 0)
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000450 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000451 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000452 "Init() failed to set mono/stereo recording mode");
453 }
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000454
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000455 if (!audioproc) {
456 audioproc = AudioProcessing::Create(VoEId(_shared->instance_id(), -1));
457 if (!audioproc) {
458 LOG(LS_ERROR) << "Failed to create AudioProcessing.";
459 _shared->SetLastError(VE_NO_MEMORY);
460 return -1;
461 }
462 }
463 _shared->set_audio_processing(audioproc);
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000464
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000465 // Set the error state for any failures in this block.
466 _shared->SetLastError(VE_APM_ERROR);
467 if (audioproc->echo_cancellation()->set_device_sample_rate_hz(48000)) {
468 LOG_FERR1(LS_ERROR, set_device_sample_rate_hz, 48000);
469 return -1;
470 }
471 // Assume 16 kHz mono until the audio frames are received from the capture
472 // device, at which point this can be updated.
473 if (audioproc->set_sample_rate_hz(16000)) {
474 LOG_FERR1(LS_ERROR, set_sample_rate_hz, 16000);
475 return -1;
476 }
477 if (audioproc->set_num_channels(1, 1) != 0) {
478 LOG_FERR2(LS_ERROR, set_num_channels, 1, 1);
479 return -1;
480 }
481 if (audioproc->set_num_reverse_channels(1) != 0) {
482 LOG_FERR1(LS_ERROR, set_num_reverse_channels, 1);
483 return -1;
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000484 }
485
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000486 // Configure AudioProcessing components. All are disabled by default.
487 if (audioproc->high_pass_filter()->Enable(true) != 0) {
488 LOG_FERR1(LS_ERROR, high_pass_filter()->Enable, true);
489 return -1;
490 }
491 if (audioproc->echo_cancellation()->enable_drift_compensation(false) != 0) {
492 LOG_FERR1(LS_ERROR, enable_drift_compensation, false);
493 return -1;
494 }
495 if (audioproc->noise_suppression()->set_level(kDefaultNsMode) != 0) {
496 LOG_FERR1(LS_ERROR, noise_suppression()->set_level, kDefaultNsMode);
497 return -1;
498 }
499 GainControl* agc = audioproc->gain_control();
500 if (agc->set_analog_level_limits(kMinVolumeLevel, kMaxVolumeLevel) != 0) {
501 LOG_FERR2(LS_ERROR, agc->set_analog_level_limits, kMinVolumeLevel,
502 kMaxVolumeLevel);
503 return -1;
504 }
505 if (agc->set_mode(kDefaultAgcMode) != 0) {
506 LOG_FERR1(LS_ERROR, agc->set_mode, kDefaultAgcMode);
507 return -1;
508 }
509 if (agc->Enable(kDefaultAgcState) != 0) {
510 LOG_FERR1(LS_ERROR, agc->Enable, kDefaultAgcState);
511 return -1;
512 }
513 _shared->SetLastError(0); // Clear error state.
514
niklase@google.com470e71d2011-07-07 08:21:25 +0000515#ifdef WEBRTC_VOICE_ENGINE_AGC
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000516 bool agc_enabled = agc->mode() == GainControl::kAdaptiveAnalog &&
517 agc->is_enabled();
518 if (_shared->audio_device()->SetAGC(agc_enabled) != 0) {
519 LOG_FERR1(LS_ERROR, audio_device()->SetAGC, agc_enabled);
520 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR);
andrew@webrtc.orga9a1df02013-03-05 23:36:10 +0000521 // TODO(ajm): No error return here due to
522 // https://code.google.com/p/webrtc/issues/detail?id=1464
niklase@google.com470e71d2011-07-07 08:21:25 +0000523 }
524#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000525
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000526 return _shared->statistics().SetInitialized();
niklase@google.com470e71d2011-07-07 08:21:25 +0000527}
528
529int VoEBaseImpl::Terminate()
530{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000531 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000532 "Terminate()");
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000533 CriticalSectionScoped cs(_shared->crit_sec());
niklase@google.com470e71d2011-07-07 08:21:25 +0000534 return TerminateInternal();
535}
536
niklase@google.com470e71d2011-07-07 08:21:25 +0000537int VoEBaseImpl::CreateChannel()
538{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000539 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000540 "CreateChannel()");
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000541 CriticalSectionScoped cs(_shared->crit_sec());
niklase@google.com470e71d2011-07-07 08:21:25 +0000542
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000543 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000544 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000545 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000546 return -1;
547 }
548
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000549 voe::ChannelOwner channel_owner =
550 _shared->channel_manager().CreateChannel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000551
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000552 if (channel_owner.channel()->SetEngineInformation(
553 _shared->statistics(),
554 *_shared->output_mixer(),
555 *_shared->transmit_mixer(),
556 *_shared->process_thread(),
557 *_shared->audio_device(),
558 _voiceEngineObserverPtr,
559 &_callbackCritSect) != 0) {
560 _shared->SetLastError(
561 VE_CHANNEL_NOT_CREATED,
562 kTraceError,
563 "CreateChannel() failed to associate engine and channel."
564 " Destroying channel.");
565 _shared->channel_manager()
566 .DestroyChannel(channel_owner.channel()->ChannelId());
567 return -1;
568 } else if (channel_owner.channel()->Init() != 0) {
569 _shared->SetLastError(
570 VE_CHANNEL_NOT_CREATED,
571 kTraceError,
572 "CreateChannel() failed to initialize channel. Destroying"
573 " channel.");
574 _shared->channel_manager()
575 .DestroyChannel(channel_owner.channel()->ChannelId());
576 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000577 }
578
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000579 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
580 VoEId(_shared->instance_id(), -1),
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000581 "CreateChannel() => %d", channel_owner.channel()->ChannelId());
582 return channel_owner.channel()->ChannelId();
niklase@google.com470e71d2011-07-07 08:21:25 +0000583}
584
585int VoEBaseImpl::DeleteChannel(int channel)
586{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000587 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000588 "DeleteChannel(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000589 CriticalSectionScoped cs(_shared->crit_sec());
niklase@google.com470e71d2011-07-07 08:21:25 +0000590
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000591 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000592 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000593 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000594 return -1;
595 }
596
597 {
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000598 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
599 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000600 if (channelPtr == NULL)
601 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000602 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
603 "DeleteChannel() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000604 return -1;
605 }
606 }
607
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000608 _shared->channel_manager().DestroyChannel(channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000609
610 if (StopSend() != 0)
611 {
612 return -1;
613 }
614
615 if (StopPlayout() != 0)
616 {
617 return -1;
618 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +0000619
niklase@google.com470e71d2011-07-07 08:21:25 +0000620 return 0;
621}
622
niklase@google.com470e71d2011-07-07 08:21:25 +0000623int VoEBaseImpl::StartReceive(int channel)
624{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000625 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000626 "StartReceive(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000627 CriticalSectionScoped cs(_shared->crit_sec());
628 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000629 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000630 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000631 return -1;
632 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000633 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
634 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000635 if (channelPtr == NULL)
636 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000637 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
638 "StartReceive() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000639 return -1;
640 }
641 return channelPtr->StartReceiving();
642}
643
644int VoEBaseImpl::StopReceive(int channel)
645{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000646 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000647 "StopListen(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000648 CriticalSectionScoped cs(_shared->crit_sec());
649 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000650 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000651 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000652 return -1;
653 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000654 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
655 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000656 if (channelPtr == NULL)
657 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000658 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
659 "SetLocalReceiver() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000660 return -1;
661 }
662 return channelPtr->StopReceiving();
663}
664
665int VoEBaseImpl::StartPlayout(int channel)
666{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000667 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000668 "StartPlayout(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000669 CriticalSectionScoped cs(_shared->crit_sec());
670 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000671 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000672 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000673 return -1;
674 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000675 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
676 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000677 if (channelPtr == NULL)
678 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000679 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
680 "StartPlayout() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000681 return -1;
682 }
683 if (channelPtr->Playing())
684 {
685 return 0;
686 }
687 if (StartPlayout() != 0)
688 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000689 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
690 "StartPlayout() failed to start playout");
niklase@google.com470e71d2011-07-07 08:21:25 +0000691 return -1;
692 }
693 return channelPtr->StartPlayout();
694}
695
696int VoEBaseImpl::StopPlayout(int channel)
697{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000698 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000699 "StopPlayout(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000700 CriticalSectionScoped cs(_shared->crit_sec());
701 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000702 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000703 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000704 return -1;
705 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000706 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
707 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000708 if (channelPtr == NULL)
709 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000710 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
711 "StopPlayout() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000712 return -1;
713 }
714 if (channelPtr->StopPlayout() != 0)
715 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000716 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
717 VoEId(_shared->instance_id(), -1),
718 "StopPlayout() failed to stop playout for channel %d", channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000719 }
720 return StopPlayout();
721}
722
723int VoEBaseImpl::StartSend(int channel)
724{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000725 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000726 "StartSend(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000727 CriticalSectionScoped cs(_shared->crit_sec());
728 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000729 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000730 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000731 return -1;
732 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000733 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
734 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000735 if (channelPtr == NULL)
736 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000737 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
738 "StartSend() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000739 return -1;
740 }
741 if (channelPtr->Sending())
742 {
743 return 0;
744 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000745 if (StartSend() != 0)
746 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000747 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
748 "StartSend() failed to start recording");
niklase@google.com470e71d2011-07-07 08:21:25 +0000749 return -1;
750 }
751 return channelPtr->StartSend();
752}
753
754int VoEBaseImpl::StopSend(int channel)
755{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000756 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000757 "StopSend(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000758 CriticalSectionScoped cs(_shared->crit_sec());
759 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000760 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000761 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000762 return -1;
763 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000764 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
765 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000766 if (channelPtr == NULL)
767 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000768 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
769 "StopSend() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000770 return -1;
771 }
772 if (channelPtr->StopSend() != 0)
773 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000774 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
775 VoEId(_shared->instance_id(), -1),
776 "StopSend() failed to stop sending for channel %d", channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000777 }
778 return StopSend();
779}
780
781int VoEBaseImpl::GetVersion(char version[1024])
782{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000783 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000784 "GetVersion(version=?)");
785 assert(kVoiceEngineVersionMaxMessageSize == 1024);
786
787 if (version == NULL)
788 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000789 _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000790 return (-1);
791 }
792
793 char versionBuf[kVoiceEngineVersionMaxMessageSize];
794 char* versionPtr = versionBuf;
795
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000796 int32_t len = 0;
797 int32_t accLen = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000798
799 len = AddVoEVersion(versionPtr);
800 if (len == -1)
801 {
802 return -1;
803 }
804 versionPtr += len;
805 accLen += len;
806 assert(accLen < kVoiceEngineVersionMaxMessageSize);
807
808 len = AddBuildInfo(versionPtr);
809 if (len == -1)
810 {
811 return -1;
812 }
813 versionPtr += len;
814 accLen += len;
815 assert(accLen < kVoiceEngineVersionMaxMessageSize);
816
pwestin@webrtc.org684f0572013-03-13 23:20:57 +0000817#ifdef WEBRTC_EXTERNAL_TRANSPORT
818 len = AddExternalTransportBuild(versionPtr);
819 if (len == -1)
820 {
821 return -1;
822 }
823 versionPtr += len;
824 accLen += len;
825 assert(accLen < kVoiceEngineVersionMaxMessageSize);
826#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000827#ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT
828 len = AddExternalRecAndPlayoutBuild(versionPtr);
829 if (len == -1)
830 {
831 return -1;
832 }
833 versionPtr += len;
834 accLen += len;
835 assert(accLen < kVoiceEngineVersionMaxMessageSize);
pwestin@webrtc.orgc450a192012-01-04 15:00:12 +0000836 #endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000837
838 memcpy(version, versionBuf, accLen);
839 version[accLen] = '\0';
840
841 // to avoid the truncation in the trace, split the string into parts
842 char partOfVersion[256];
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000843 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
844 VoEId(_shared->instance_id(), -1), "GetVersion() =>");
niklase@google.com470e71d2011-07-07 08:21:25 +0000845 for (int partStart = 0; partStart < accLen;)
846 {
847 memset(partOfVersion, 0, sizeof(partOfVersion));
848 int partEnd = partStart + 180;
849 while (version[partEnd] != '\n' && version[partEnd] != '\0')
850 {
851 partEnd--;
852 }
853 if (partEnd < accLen)
854 {
855 memcpy(partOfVersion, &version[partStart], partEnd - partStart);
856 }
857 else
858 {
859 memcpy(partOfVersion, &version[partStart], accLen - partStart);
860 }
861 partStart = partEnd;
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000862 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
863 VoEId(_shared->instance_id(), -1), "%s", partOfVersion);
niklase@google.com470e71d2011-07-07 08:21:25 +0000864 }
865
866 return 0;
867}
868
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000869int32_t VoEBaseImpl::AddBuildInfo(char* str) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000870{
leozwang@webrtc.org48a5df62012-04-24 14:50:50 +0000871 return sprintf(str, "Build: svn:%s %s\n", WEBRTC_SVNREVISION, BUILDINFO);
niklase@google.com470e71d2011-07-07 08:21:25 +0000872}
873
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000874int32_t VoEBaseImpl::AddVoEVersion(char* str) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000875{
876 return sprintf(str, "VoiceEngine 4.1.0\n");
877}
878
pwestin@webrtc.org684f0572013-03-13 23:20:57 +0000879#ifdef WEBRTC_EXTERNAL_TRANSPORT
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000880int32_t VoEBaseImpl::AddExternalTransportBuild(char* str) const
pwestin@webrtc.org684f0572013-03-13 23:20:57 +0000881{
882 return sprintf(str, "External transport build\n");
883}
884#endif
885
niklase@google.com470e71d2011-07-07 08:21:25 +0000886#ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000887int32_t VoEBaseImpl::AddExternalRecAndPlayoutBuild(char* str) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000888{
889 return sprintf(str, "External recording and playout build\n");
890}
891#endif
892
niklase@google.com470e71d2011-07-07 08:21:25 +0000893int VoEBaseImpl::LastError()
894{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000895 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000896 "LastError()");
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000897 return (_shared->statistics().LastError());
niklase@google.com470e71d2011-07-07 08:21:25 +0000898}
899
900
901int VoEBaseImpl::SetNetEQPlayoutMode(int channel, NetEqModes mode)
902{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000903 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000904 "SetNetEQPlayoutMode(channel=%i, mode=%i)", channel, mode);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000905 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000906 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000907 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000908 return -1;
909 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000910 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
911 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000912 if (channelPtr == NULL)
913 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000914 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
915 "SetNetEQPlayoutMode() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000916 return -1;
917 }
918 return channelPtr->SetNetEQPlayoutMode(mode);
919}
920
921int VoEBaseImpl::GetNetEQPlayoutMode(int channel, NetEqModes& mode)
922{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000923 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000924 "GetNetEQPlayoutMode(channel=%i, mode=?)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000925 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000926 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000927 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000928 return -1;
929 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000930 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
931 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000932 if (channelPtr == NULL)
933 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000934 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
935 "GetNetEQPlayoutMode() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000936 return -1;
937 }
938 return channelPtr->GetNetEQPlayoutMode(mode);
939}
940
niklase@google.com470e71d2011-07-07 08:21:25 +0000941int VoEBaseImpl::SetOnHoldStatus(int channel, bool enable, OnHoldModes mode)
942{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000943 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000944 "SetOnHoldStatus(channel=%d, enable=%d, mode=%d)", channel,
945 enable, mode);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000946 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000947 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000948 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000949 return -1;
950 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000951 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
952 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000953 if (channelPtr == NULL)
954 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000955 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
956 "SetOnHoldStatus() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000957 return -1;
958 }
959 return channelPtr->SetOnHoldStatus(enable, mode);
960}
961
962int VoEBaseImpl::GetOnHoldStatus(int channel, bool& enabled, OnHoldModes& mode)
963{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000964 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000965 "GetOnHoldStatus(channel=%d, enabled=?, mode=?)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000966 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000967 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000968 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000969 return -1;
970 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000971 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
972 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000973 if (channelPtr == NULL)
974 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000975 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
976 "GetOnHoldStatus() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000977 return -1;
978 }
979 return channelPtr->GetOnHoldStatus(enabled, mode);
980}
981
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000982int32_t VoEBaseImpl::StartPlayout()
niklase@google.com470e71d2011-07-07 08:21:25 +0000983{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000984 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000985 "VoEBaseImpl::StartPlayout()");
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000986 if (_shared->audio_device()->Playing())
niklase@google.com470e71d2011-07-07 08:21:25 +0000987 {
988 return 0;
989 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000990 if (!_shared->ext_playout())
niklase@google.com470e71d2011-07-07 08:21:25 +0000991 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000992 if (_shared->audio_device()->InitPlayout() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000993 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000994 WEBRTC_TRACE(kTraceError, kTraceVoice,
995 VoEId(_shared->instance_id(), -1),
996 "StartPlayout() failed to initialize playout");
niklase@google.com470e71d2011-07-07 08:21:25 +0000997 return -1;
998 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000999 if (_shared->audio_device()->StartPlayout() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001000 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001001 WEBRTC_TRACE(kTraceError, kTraceVoice,
1002 VoEId(_shared->instance_id(), -1),
1003 "StartPlayout() failed to start playout");
niklase@google.com470e71d2011-07-07 08:21:25 +00001004 return -1;
1005 }
1006 }
1007 return 0;
1008}
1009
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +00001010int32_t VoEBaseImpl::StopPlayout() {
1011 WEBRTC_TRACE(kTraceInfo,
1012 kTraceVoice,
1013 VoEId(_shared->instance_id(), -1),
1014 "VoEBaseImpl::StopPlayout()");
1015 // Stop audio-device playing if no channel is playing out
1016 if (_shared->NumOfSendingChannels() == 0) {
1017 if (_shared->audio_device()->StopPlayout() != 0) {
1018 _shared->SetLastError(VE_CANNOT_STOP_PLAYOUT,
1019 kTraceError,
1020 "StopPlayout() failed to stop playout");
1021 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001022 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +00001023 }
1024 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001025}
1026
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001027int32_t VoEBaseImpl::StartSend()
niklase@google.com470e71d2011-07-07 08:21:25 +00001028{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001029 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001030 "VoEBaseImpl::StartSend()");
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001031 if (_shared->audio_device()->Recording())
niklase@google.com470e71d2011-07-07 08:21:25 +00001032 {
1033 return 0;
1034 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001035 if (!_shared->ext_recording())
niklase@google.com470e71d2011-07-07 08:21:25 +00001036 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001037 if (_shared->audio_device()->InitRecording() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001038 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001039 WEBRTC_TRACE(kTraceError, kTraceVoice,
1040 VoEId(_shared->instance_id(), -1),
1041 "StartSend() failed to initialize recording");
niklase@google.com470e71d2011-07-07 08:21:25 +00001042 return -1;
1043 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001044 if (_shared->audio_device()->StartRecording() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001045 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001046 WEBRTC_TRACE(kTraceError, kTraceVoice,
1047 VoEId(_shared->instance_id(), -1),
1048 "StartSend() failed to start recording");
niklase@google.com470e71d2011-07-07 08:21:25 +00001049 return -1;
1050 }
1051 }
1052
1053 return 0;
1054}
1055
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001056int32_t VoEBaseImpl::StopSend()
niklase@google.com470e71d2011-07-07 08:21:25 +00001057{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001058 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001059 "VoEBaseImpl::StopSend()");
1060
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001061 if (_shared->NumOfSendingChannels() == 0 &&
1062 !_shared->transmit_mixer()->IsRecordingMic())
niklase@google.com470e71d2011-07-07 08:21:25 +00001063 {
1064 // Stop audio-device recording if no channel is recording
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001065 if (_shared->audio_device()->StopRecording() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001066 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001067 _shared->SetLastError(VE_CANNOT_STOP_RECORDING, kTraceError,
1068 "StopSend() failed to stop recording");
niklase@google.com470e71d2011-07-07 08:21:25 +00001069 return -1;
1070 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001071 _shared->transmit_mixer()->StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +00001072 }
1073
1074 return 0;
1075}
1076
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001077int32_t VoEBaseImpl::TerminateInternal()
niklase@google.com470e71d2011-07-07 08:21:25 +00001078{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001079 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001080 "VoEBaseImpl::TerminateInternal()");
1081
1082 // Delete any remaining channel objects
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +00001083 _shared->channel_manager().DestroyAllChannels();
niklase@google.com470e71d2011-07-07 08:21:25 +00001084
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001085 if (_shared->process_thread())
niklase@google.com470e71d2011-07-07 08:21:25 +00001086 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001087 if (_shared->audio_device())
niklase@google.com470e71d2011-07-07 08:21:25 +00001088 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001089 if (_shared->process_thread()->
1090 DeRegisterModule(_shared->audio_device()) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001091 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001092 _shared->SetLastError(VE_THREAD_ERROR, kTraceError,
1093 "TerminateInternal() failed to deregister ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +00001094 }
1095 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001096 if (_shared->process_thread()->Stop() != 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 stop module process thread");
niklase@google.com470e71d2011-07-07 08:21:25 +00001100 }
1101 }
1102
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +00001103 if (_shared->audio_device())
niklase@google.com470e71d2011-07-07 08:21:25 +00001104 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001105 if (_shared->audio_device()->StopPlayout() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001106 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001107 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
1108 "TerminateInternal() failed to stop playout");
niklase@google.com470e71d2011-07-07 08:21:25 +00001109 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001110 if (_shared->audio_device()->StopRecording() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001111 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001112 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
1113 "TerminateInternal() failed to stop recording");
niklase@google.com470e71d2011-07-07 08:21:25 +00001114 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001115 if (_shared->audio_device()->RegisterEventObserver(NULL) != 0) {
1116 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
1117 "TerminateInternal() failed to de-register event observer "
1118 "for the ADM");
xians@webrtc.org79af7342012-01-31 12:22:14 +00001119 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001120 if (_shared->audio_device()->RegisterAudioCallback(NULL) != 0) {
1121 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
1122 "TerminateInternal() failed to de-register audio callback "
1123 "for the ADM");
xians@webrtc.org79af7342012-01-31 12:22:14 +00001124 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001125 if (_shared->audio_device()->Terminate() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001126 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001127 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
1128 "TerminateInternal() failed to terminate the ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +00001129 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001130 _shared->set_audio_device(NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +00001131 }
1132
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +00001133 if (_shared->audio_processing()) {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001134 _shared->set_audio_processing(NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +00001135 }
1136
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001137 return _shared->statistics().SetUnInitialized();
niklase@google.com470e71d2011-07-07 08:21:25 +00001138}
1139
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00001140int VoEBaseImpl::ProcessRecordedDataWithAPM(
1141 const int voe_channels[],
1142 int number_of_voe_channels,
1143 const void* audio_data,
1144 uint32_t sample_rate,
1145 uint8_t number_of_channels,
1146 uint32_t number_of_frames,
1147 uint32_t audio_delay_milliseconds,
1148 int32_t clock_drift,
1149 uint32_t current_volume,
1150 bool key_pressed) {
1151 assert(_shared->transmit_mixer() != NULL);
1152 assert(_shared->audio_device() != NULL);
1153
1154 bool is_analog_agc(false);
1155 if (_shared->audio_processing() &&
1156 _shared->audio_processing()->gain_control()->mode() ==
1157 GainControl::kAdaptiveAnalog) {
1158 is_analog_agc = true;
1159 }
1160
1161 // Only deal with the volume in adaptive analog mode.
1162 uint32_t max_volume = 0;
1163 uint16_t current_voe_mic_level = 0;
1164 if (is_analog_agc) {
1165 // 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
1213 if (!is_analog_agc)
1214 return 0;
1215
1216 // Scale from VoE to ADM level range.
1217 uint32_t new_voe_mic_level = _shared->transmit_mixer()->CaptureLevel();
1218
1219 // Keep track of the value AGC returns.
1220 _oldVoEMicLevel = new_voe_mic_level;
1221 _oldMicLevel = current_volume;
1222
1223 if (new_voe_mic_level != current_voe_mic_level) {
1224 // Return the new volume if AGC has changed the volume.
1225 return static_cast<int>(
1226 (new_voe_mic_level * max_volume +
1227 static_cast<int>(kMaxVolumeLevel / 2)) / kMaxVolumeLevel);
1228 }
1229
1230 // Return 0 to indicate no change on the volume.
1231 return 0;
1232}
1233
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00001234} // namespace webrtc