blob: 9434863882035c3df2642003a72a3418a984695b [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) {
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000227 voe::ChannelOwner ch =
228 _shared->channel_manager().GetChannel(voe_channels[i]);
229 voe::Channel* channel_ptr = ch.channel();
xians@webrtc.org2f84afa2013-07-31 16:23:37 +0000230 if (!channel_ptr)
231 continue;
232
233 if (channel_ptr->InputIsOnHold()) {
234 channel_ptr->UpdateLocalTimeStamp();
235 } else if (channel_ptr->Sending()) {
236 channel_ptr->Demultiplex(audio_data, sample_rate, number_of_frames,
237 number_of_channels);
238 channel_ptr->PrepareEncodeAndSend(sample_rate);
239 channel_ptr->EncodeAndSend();
240 }
241 }
242
243 // Return 0 to indicate no need to change the volume.
244 return 0;
245}
246
niklase@google.com470e71d2011-07-07 08:21:25 +0000247int VoEBaseImpl::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
248{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000249 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000250 "RegisterVoiceEngineObserver(observer=0x%d)", &observer);
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000251 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000252 if (_voiceEngineObserverPtr)
253 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000254 _shared->SetLastError(VE_INVALID_OPERATION, kTraceError,
255 "RegisterVoiceEngineObserver() observer already enabled");
niklase@google.com470e71d2011-07-07 08:21:25 +0000256 return -1;
257 }
258
259 // Register the observer in all active channels
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000260 for (voe::ChannelManager::Iterator it(&_shared->channel_manager());
261 it.IsValid();
262 it.Increment()) {
263 it.GetChannel()->RegisterVoiceEngineObserver(observer);
niklase@google.com470e71d2011-07-07 08:21:25 +0000264 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000265
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000266 _shared->transmit_mixer()->RegisterVoiceEngineObserver(observer);
niklase@google.com470e71d2011-07-07 08:21:25 +0000267
268 _voiceEngineObserverPtr = &observer;
269 _voiceEngineObserver = true;
270
271 return 0;
272}
273
274int VoEBaseImpl::DeRegisterVoiceEngineObserver()
275{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000276 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000277 "DeRegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000278 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000279 if (!_voiceEngineObserverPtr)
280 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000281 _shared->SetLastError(VE_INVALID_OPERATION, kTraceError,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000282 "DeRegisterVoiceEngineObserver() observer already disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +0000283 return 0;
284 }
285
286 _voiceEngineObserver = false;
287 _voiceEngineObserverPtr = NULL;
288
289 // Deregister the observer in all active channels
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000290 for (voe::ChannelManager::Iterator it(&_shared->channel_manager());
291 it.IsValid();
292 it.Increment()) {
293 it.GetChannel()->DeRegisterVoiceEngineObserver();
niklase@google.com470e71d2011-07-07 08:21:25 +0000294 }
295
296 return 0;
297}
298
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000299int VoEBaseImpl::Init(AudioDeviceModule* external_adm,
300 AudioProcessing* audioproc)
niklase@google.com470e71d2011-07-07 08:21:25 +0000301{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000302 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
henrika@google.com73d65512011-09-07 15:11:18 +0000303 "Init(external_adm=0x%p)", external_adm);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000304 CriticalSectionScoped cs(_shared->crit_sec());
niklase@google.com470e71d2011-07-07 08:21:25 +0000305
kma@webrtc.org0221b782012-09-08 00:09:26 +0000306 WebRtcSpl_Init();
307
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000308 if (_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000309 {
310 return 0;
311 }
312
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000313 if (_shared->process_thread())
niklase@google.com470e71d2011-07-07 08:21:25 +0000314 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000315 if (_shared->process_thread()->Start() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000316 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000317 _shared->SetLastError(VE_THREAD_ERROR, kTraceError,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000318 "Init() failed to start module process thread");
niklase@google.com470e71d2011-07-07 08:21:25 +0000319 return -1;
320 }
321 }
322
andrew@webrtc.org3192d652011-12-21 18:00:59 +0000323 // Create an internal ADM if the user has not added an external
henrika@google.com73d65512011-09-07 15:11:18 +0000324 // ADM implementation as input to Init().
325 if (external_adm == NULL)
niklase@google.com470e71d2011-07-07 08:21:25 +0000326 {
henrika@google.com73d65512011-09-07 15:11:18 +0000327 // Create the internal ADM implementation.
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000328 _shared->set_audio_device(AudioDeviceModuleImpl::Create(
329 VoEId(_shared->instance_id(), -1), _shared->audio_device_layer()));
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000330
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000331 if (_shared->audio_device() == NULL)
niklase@google.com470e71d2011-07-07 08:21:25 +0000332 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000333 _shared->SetLastError(VE_NO_MEMORY, kTraceCritical,
334 "Init() failed to create the ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +0000335 return -1;
336 }
337 }
henrika@google.com73d65512011-09-07 15:11:18 +0000338 else
339 {
340 // Use the already existing external ADM implementation.
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000341 _shared->set_audio_device(external_adm);
342 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
henrika@google.com73d65512011-09-07 15:11:18 +0000343 "An external ADM implementation will be used in VoiceEngine");
344 }
345
niklase@google.com470e71d2011-07-07 08:21:25 +0000346 // Register the ADM to the process thread, which will drive the error
347 // callback mechanism
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000348 if (_shared->process_thread() &&
349 _shared->process_thread()->RegisterModule(_shared->audio_device()) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000350 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000351 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
352 "Init() failed to register the ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +0000353 return -1;
354 }
355
356 bool available(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000357
358 // --------------------
359 // Reinitialize the ADM
360
361 // Register the AudioObserver implementation
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000362 if (_shared->audio_device()->RegisterEventObserver(this) != 0) {
363 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
364 "Init() failed to register event observer for the ADM");
xians@webrtc.org79af7342012-01-31 12:22:14 +0000365 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000366
367 // Register the AudioTransport implementation
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000368 if (_shared->audio_device()->RegisterAudioCallback(this) != 0) {
369 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
370 "Init() failed to register audio callback for the ADM");
xians@webrtc.org79af7342012-01-31 12:22:14 +0000371 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000372
373 // ADM initialization
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000374 if (_shared->audio_device()->Init() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000375 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000376 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
377 "Init() failed to initialize the ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +0000378 return -1;
379 }
380
381 // Initialize the default speaker
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000382 if (_shared->audio_device()->SetPlayoutDevice(
383 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000384 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000385 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000386 "Init() failed to set the default output device");
niklase@google.com470e71d2011-07-07 08:21:25 +0000387 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000388 if (_shared->audio_device()->SpeakerIsAvailable(&available) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000389 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000390 _shared->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000391 "Init() failed to check speaker availability, trying to "
392 "initialize speaker anyway");
niklase@google.com470e71d2011-07-07 08:21:25 +0000393 }
394 else if (!available)
395 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000396 _shared->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000397 "Init() speaker not available, trying to initialize speaker "
398 "anyway");
niklase@google.com470e71d2011-07-07 08:21:25 +0000399 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000400 if (_shared->audio_device()->InitSpeaker() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000401 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000402 _shared->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000403 "Init() failed to initialize the speaker");
niklase@google.com470e71d2011-07-07 08:21:25 +0000404 }
405
406 // Initialize the default microphone
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000407 if (_shared->audio_device()->SetRecordingDevice(
408 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000409 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000410 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000411 "Init() failed to set the default input device");
niklase@google.com470e71d2011-07-07 08:21:25 +0000412 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000413 if (_shared->audio_device()->MicrophoneIsAvailable(&available) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000414 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000415 _shared->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000416 "Init() failed to check microphone availability, trying to "
417 "initialize microphone anyway");
niklase@google.com470e71d2011-07-07 08:21:25 +0000418 }
419 else if (!available)
420 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000421 _shared->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000422 "Init() microphone not available, trying to initialize "
423 "microphone anyway");
niklase@google.com470e71d2011-07-07 08:21:25 +0000424 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000425 if (_shared->audio_device()->InitMicrophone() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000426 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000427 _shared->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000428 "Init() failed to initialize the microphone");
niklase@google.com470e71d2011-07-07 08:21:25 +0000429 }
430
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000431 // Set number of channels
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000432 if (_shared->audio_device()->StereoPlayoutIsAvailable(&available) != 0) {
433 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
434 "Init() failed to query stereo playout mode");
xians@webrtc.org79af7342012-01-31 12:22:14 +0000435 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000436 if (_shared->audio_device()->SetStereoPlayout(available) != 0)
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000437 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000438 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000439 "Init() failed to set mono/stereo playout mode");
440 }
andrew@webrtc.org3192d652011-12-21 18:00:59 +0000441
442 // TODO(andrew): These functions don't tell us whether stereo recording
443 // is truly available. We simply set the AudioProcessing input to stereo
444 // here, because we have to wait until receiving the first frame to
445 // determine the actual number of channels anyway.
446 //
447 // These functions may be changed; tracked here:
448 // http://code.google.com/p/webrtc/issues/detail?id=204
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000449 _shared->audio_device()->StereoRecordingIsAvailable(&available);
450 if (_shared->audio_device()->SetStereoRecording(available) != 0)
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000451 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000452 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000453 "Init() failed to set mono/stereo recording mode");
454 }
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000455
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000456 if (!audioproc) {
457 audioproc = AudioProcessing::Create(VoEId(_shared->instance_id(), -1));
458 if (!audioproc) {
459 LOG(LS_ERROR) << "Failed to create AudioProcessing.";
460 _shared->SetLastError(VE_NO_MEMORY);
461 return -1;
462 }
463 }
464 _shared->set_audio_processing(audioproc);
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000465
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000466 // Set the error state for any failures in this block.
467 _shared->SetLastError(VE_APM_ERROR);
468 if (audioproc->echo_cancellation()->set_device_sample_rate_hz(48000)) {
469 LOG_FERR1(LS_ERROR, set_device_sample_rate_hz, 48000);
470 return -1;
471 }
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000472
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +0000473 // Configure AudioProcessing components.
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000474 if (audioproc->high_pass_filter()->Enable(true) != 0) {
475 LOG_FERR1(LS_ERROR, high_pass_filter()->Enable, true);
476 return -1;
477 }
478 if (audioproc->echo_cancellation()->enable_drift_compensation(false) != 0) {
479 LOG_FERR1(LS_ERROR, enable_drift_compensation, false);
480 return -1;
481 }
482 if (audioproc->noise_suppression()->set_level(kDefaultNsMode) != 0) {
483 LOG_FERR1(LS_ERROR, noise_suppression()->set_level, kDefaultNsMode);
484 return -1;
485 }
486 GainControl* agc = audioproc->gain_control();
487 if (agc->set_analog_level_limits(kMinVolumeLevel, kMaxVolumeLevel) != 0) {
488 LOG_FERR2(LS_ERROR, agc->set_analog_level_limits, kMinVolumeLevel,
489 kMaxVolumeLevel);
490 return -1;
491 }
492 if (agc->set_mode(kDefaultAgcMode) != 0) {
493 LOG_FERR1(LS_ERROR, agc->set_mode, kDefaultAgcMode);
494 return -1;
495 }
496 if (agc->Enable(kDefaultAgcState) != 0) {
497 LOG_FERR1(LS_ERROR, agc->Enable, kDefaultAgcState);
498 return -1;
499 }
500 _shared->SetLastError(0); // Clear error state.
501
niklase@google.com470e71d2011-07-07 08:21:25 +0000502#ifdef WEBRTC_VOICE_ENGINE_AGC
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000503 bool agc_enabled = agc->mode() == GainControl::kAdaptiveAnalog &&
504 agc->is_enabled();
505 if (_shared->audio_device()->SetAGC(agc_enabled) != 0) {
506 LOG_FERR1(LS_ERROR, audio_device()->SetAGC, agc_enabled);
507 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR);
andrew@webrtc.orga9a1df02013-03-05 23:36:10 +0000508 // TODO(ajm): No error return here due to
509 // https://code.google.com/p/webrtc/issues/detail?id=1464
niklase@google.com470e71d2011-07-07 08:21:25 +0000510 }
511#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000512
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000513 return _shared->statistics().SetInitialized();
niklase@google.com470e71d2011-07-07 08:21:25 +0000514}
515
516int VoEBaseImpl::Terminate()
517{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000518 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000519 "Terminate()");
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000520 CriticalSectionScoped cs(_shared->crit_sec());
niklase@google.com470e71d2011-07-07 08:21:25 +0000521 return TerminateInternal();
522}
523
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000524int VoEBaseImpl::CreateChannel() {
525 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
526 "CreateChannel()");
527 CriticalSectionScoped cs(_shared->crit_sec());
528 if (!_shared->statistics().Initialized()) {
529 _shared->SetLastError(VE_NOT_INITED, kTraceError);
530 return -1;
531 }
532
533 voe::ChannelOwner channel_owner = _shared->channel_manager().CreateChannel();
534
535 return InitializeChannel(&channel_owner);
536}
537
538int VoEBaseImpl::CreateChannel(const Config& config) {
539 CriticalSectionScoped cs(_shared->crit_sec());
540 if (!_shared->statistics().Initialized()) {
541 _shared->SetLastError(VE_NOT_INITED, kTraceError);
542 return -1;
543 }
544 voe::ChannelOwner channel_owner = _shared->channel_manager().CreateChannel(
545 config);
546 return InitializeChannel(&channel_owner);
547}
548
549int VoEBaseImpl::InitializeChannel(voe::ChannelOwner* channel_owner)
niklase@google.com470e71d2011-07-07 08:21:25 +0000550{
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000551 if (channel_owner->channel()->SetEngineInformation(
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000552 _shared->statistics(),
553 *_shared->output_mixer(),
554 *_shared->transmit_mixer(),
555 *_shared->process_thread(),
556 *_shared->audio_device(),
557 _voiceEngineObserverPtr,
558 &_callbackCritSect) != 0) {
559 _shared->SetLastError(
560 VE_CHANNEL_NOT_CREATED,
561 kTraceError,
562 "CreateChannel() failed to associate engine and channel."
563 " Destroying channel.");
564 _shared->channel_manager()
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000565 .DestroyChannel(channel_owner->channel()->ChannelId());
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000566 return -1;
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000567 } else if (channel_owner->channel()->Init() != 0) {
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000568 _shared->SetLastError(
569 VE_CHANNEL_NOT_CREATED,
570 kTraceError,
571 "CreateChannel() failed to initialize channel. Destroying"
572 " channel.");
573 _shared->channel_manager()
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000574 .DestroyChannel(channel_owner->channel()->ChannelId());
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000575 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000576 }
577
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000578 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
579 VoEId(_shared->instance_id(), -1),
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000580 "CreateChannel() => %d", channel_owner->channel()->ChannelId());
581 return channel_owner->channel()->ChannelId();
niklase@google.com470e71d2011-07-07 08:21:25 +0000582}
583
584int VoEBaseImpl::DeleteChannel(int channel)
585{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000586 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000587 "DeleteChannel(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000588 CriticalSectionScoped cs(_shared->crit_sec());
niklase@google.com470e71d2011-07-07 08:21:25 +0000589
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000590 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000591 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000592 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000593 return -1;
594 }
595
596 {
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000597 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
598 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000599 if (channelPtr == NULL)
600 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000601 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
602 "DeleteChannel() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000603 return -1;
604 }
605 }
606
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000607 _shared->channel_manager().DestroyChannel(channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000608
609 if (StopSend() != 0)
610 {
611 return -1;
612 }
613
614 if (StopPlayout() != 0)
615 {
616 return -1;
617 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +0000618
niklase@google.com470e71d2011-07-07 08:21:25 +0000619 return 0;
620}
621
niklase@google.com470e71d2011-07-07 08:21:25 +0000622int VoEBaseImpl::StartReceive(int channel)
623{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000624 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000625 "StartReceive(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000626 CriticalSectionScoped cs(_shared->crit_sec());
627 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000628 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000629 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000630 return -1;
631 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000632 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
633 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000634 if (channelPtr == NULL)
635 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000636 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
637 "StartReceive() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000638 return -1;
639 }
640 return channelPtr->StartReceiving();
641}
642
643int VoEBaseImpl::StopReceive(int channel)
644{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000645 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000646 "StopListen(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000647 CriticalSectionScoped cs(_shared->crit_sec());
648 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000649 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000650 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000651 return -1;
652 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000653 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
654 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000655 if (channelPtr == NULL)
656 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000657 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
658 "SetLocalReceiver() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000659 return -1;
660 }
661 return channelPtr->StopReceiving();
662}
663
664int VoEBaseImpl::StartPlayout(int channel)
665{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000666 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000667 "StartPlayout(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000668 CriticalSectionScoped cs(_shared->crit_sec());
669 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000670 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000671 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000672 return -1;
673 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000674 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
675 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000676 if (channelPtr == NULL)
677 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000678 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
679 "StartPlayout() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000680 return -1;
681 }
682 if (channelPtr->Playing())
683 {
684 return 0;
685 }
686 if (StartPlayout() != 0)
687 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000688 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
689 "StartPlayout() failed to start playout");
niklase@google.com470e71d2011-07-07 08:21:25 +0000690 return -1;
691 }
692 return channelPtr->StartPlayout();
693}
694
695int VoEBaseImpl::StopPlayout(int channel)
696{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000697 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000698 "StopPlayout(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000699 CriticalSectionScoped cs(_shared->crit_sec());
700 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000701 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000702 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000703 return -1;
704 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000705 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
706 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000707 if (channelPtr == NULL)
708 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000709 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
710 "StopPlayout() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000711 return -1;
712 }
713 if (channelPtr->StopPlayout() != 0)
714 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000715 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
716 VoEId(_shared->instance_id(), -1),
717 "StopPlayout() failed to stop playout for channel %d", channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000718 }
719 return StopPlayout();
720}
721
722int VoEBaseImpl::StartSend(int channel)
723{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000724 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000725 "StartSend(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000726 CriticalSectionScoped cs(_shared->crit_sec());
727 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000728 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000729 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000730 return -1;
731 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000732 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
733 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000734 if (channelPtr == NULL)
735 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000736 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
737 "StartSend() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000738 return -1;
739 }
740 if (channelPtr->Sending())
741 {
742 return 0;
743 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000744 if (StartSend() != 0)
745 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000746 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
747 "StartSend() failed to start recording");
niklase@google.com470e71d2011-07-07 08:21:25 +0000748 return -1;
749 }
750 return channelPtr->StartSend();
751}
752
753int VoEBaseImpl::StopSend(int channel)
754{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000755 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000756 "StopSend(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000757 CriticalSectionScoped cs(_shared->crit_sec());
758 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000759 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000760 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000761 return -1;
762 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000763 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
764 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000765 if (channelPtr == NULL)
766 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000767 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
768 "StopSend() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000769 return -1;
770 }
771 if (channelPtr->StopSend() != 0)
772 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000773 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
774 VoEId(_shared->instance_id(), -1),
775 "StopSend() failed to stop sending for channel %d", channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000776 }
777 return StopSend();
778}
779
780int VoEBaseImpl::GetVersion(char version[1024])
781{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000782 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000783 "GetVersion(version=?)");
784 assert(kVoiceEngineVersionMaxMessageSize == 1024);
785
786 if (version == NULL)
787 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000788 _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000789 return (-1);
790 }
791
792 char versionBuf[kVoiceEngineVersionMaxMessageSize];
793 char* versionPtr = versionBuf;
794
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000795 int32_t len = 0;
796 int32_t accLen = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000797
798 len = AddVoEVersion(versionPtr);
799 if (len == -1)
800 {
801 return -1;
802 }
803 versionPtr += len;
804 accLen += len;
805 assert(accLen < kVoiceEngineVersionMaxMessageSize);
806
807 len = AddBuildInfo(versionPtr);
808 if (len == -1)
809 {
810 return -1;
811 }
812 versionPtr += len;
813 accLen += len;
814 assert(accLen < kVoiceEngineVersionMaxMessageSize);
815
pwestin@webrtc.org684f0572013-03-13 23:20:57 +0000816#ifdef WEBRTC_EXTERNAL_TRANSPORT
817 len = AddExternalTransportBuild(versionPtr);
818 if (len == -1)
819 {
820 return -1;
821 }
822 versionPtr += len;
823 accLen += len;
824 assert(accLen < kVoiceEngineVersionMaxMessageSize);
825#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000826#ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT
827 len = AddExternalRecAndPlayoutBuild(versionPtr);
828 if (len == -1)
829 {
830 return -1;
831 }
832 versionPtr += len;
833 accLen += len;
834 assert(accLen < kVoiceEngineVersionMaxMessageSize);
pwestin@webrtc.orgc450a192012-01-04 15:00:12 +0000835 #endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000836
837 memcpy(version, versionBuf, accLen);
838 version[accLen] = '\0';
839
840 // to avoid the truncation in the trace, split the string into parts
841 char partOfVersion[256];
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000842 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
843 VoEId(_shared->instance_id(), -1), "GetVersion() =>");
niklase@google.com470e71d2011-07-07 08:21:25 +0000844 for (int partStart = 0; partStart < accLen;)
845 {
846 memset(partOfVersion, 0, sizeof(partOfVersion));
847 int partEnd = partStart + 180;
848 while (version[partEnd] != '\n' && version[partEnd] != '\0')
849 {
850 partEnd--;
851 }
852 if (partEnd < accLen)
853 {
854 memcpy(partOfVersion, &version[partStart], partEnd - partStart);
855 }
856 else
857 {
858 memcpy(partOfVersion, &version[partStart], accLen - partStart);
859 }
860 partStart = partEnd;
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000861 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
862 VoEId(_shared->instance_id(), -1), "%s", partOfVersion);
niklase@google.com470e71d2011-07-07 08:21:25 +0000863 }
864
865 return 0;
866}
867
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000868int32_t VoEBaseImpl::AddBuildInfo(char* str) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000869{
andrew@webrtc.org3054ba62013-12-04 17:00:44 +0000870 return sprintf(str, "Build: %s\n", BUILDINFO);
niklase@google.com470e71d2011-07-07 08:21:25 +0000871}
872
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000873int32_t VoEBaseImpl::AddVoEVersion(char* str) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000874{
875 return sprintf(str, "VoiceEngine 4.1.0\n");
876}
877
pwestin@webrtc.org684f0572013-03-13 23:20:57 +0000878#ifdef WEBRTC_EXTERNAL_TRANSPORT
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000879int32_t VoEBaseImpl::AddExternalTransportBuild(char* str) const
pwestin@webrtc.org684f0572013-03-13 23:20:57 +0000880{
881 return sprintf(str, "External transport build\n");
882}
883#endif
884
niklase@google.com470e71d2011-07-07 08:21:25 +0000885#ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000886int32_t VoEBaseImpl::AddExternalRecAndPlayoutBuild(char* str) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000887{
888 return sprintf(str, "External recording and playout build\n");
889}
890#endif
891
niklase@google.com470e71d2011-07-07 08:21:25 +0000892int VoEBaseImpl::LastError()
893{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000894 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000895 "LastError()");
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000896 return (_shared->statistics().LastError());
niklase@google.com470e71d2011-07-07 08:21:25 +0000897}
898
899
900int VoEBaseImpl::SetNetEQPlayoutMode(int channel, NetEqModes mode)
901{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000902 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000903 "SetNetEQPlayoutMode(channel=%i, mode=%i)", channel, mode);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000904 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000905 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000906 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000907 return -1;
908 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000909 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
910 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000911 if (channelPtr == NULL)
912 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000913 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
914 "SetNetEQPlayoutMode() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000915 return -1;
916 }
917 return channelPtr->SetNetEQPlayoutMode(mode);
918}
919
920int VoEBaseImpl::GetNetEQPlayoutMode(int channel, NetEqModes& mode)
921{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000922 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000923 "GetNetEQPlayoutMode(channel=%i, mode=?)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000924 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000925 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000926 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000927 return -1;
928 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000929 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
930 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000931 if (channelPtr == NULL)
932 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000933 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
934 "GetNetEQPlayoutMode() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000935 return -1;
936 }
937 return channelPtr->GetNetEQPlayoutMode(mode);
938}
939
niklase@google.com470e71d2011-07-07 08:21:25 +0000940int VoEBaseImpl::SetOnHoldStatus(int channel, bool enable, OnHoldModes mode)
941{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000942 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000943 "SetOnHoldStatus(channel=%d, enable=%d, mode=%d)", channel,
944 enable, mode);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000945 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000946 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000947 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000948 return -1;
949 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000950 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
951 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000952 if (channelPtr == NULL)
953 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000954 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
955 "SetOnHoldStatus() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000956 return -1;
957 }
958 return channelPtr->SetOnHoldStatus(enable, mode);
959}
960
961int VoEBaseImpl::GetOnHoldStatus(int channel, bool& enabled, OnHoldModes& mode)
962{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000963 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000964 "GetOnHoldStatus(channel=%d, enabled=?, mode=?)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000965 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000966 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000967 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000968 return -1;
969 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000970 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
971 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000972 if (channelPtr == NULL)
973 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000974 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
975 "GetOnHoldStatus() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000976 return -1;
977 }
978 return channelPtr->GetOnHoldStatus(enabled, mode);
979}
980
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000981int32_t VoEBaseImpl::StartPlayout()
niklase@google.com470e71d2011-07-07 08:21:25 +0000982{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000983 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000984 "VoEBaseImpl::StartPlayout()");
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000985 if (_shared->audio_device()->Playing())
niklase@google.com470e71d2011-07-07 08:21:25 +0000986 {
987 return 0;
988 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000989 if (!_shared->ext_playout())
niklase@google.com470e71d2011-07-07 08:21:25 +0000990 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000991 if (_shared->audio_device()->InitPlayout() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000992 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000993 WEBRTC_TRACE(kTraceError, kTraceVoice,
994 VoEId(_shared->instance_id(), -1),
995 "StartPlayout() failed to initialize playout");
niklase@google.com470e71d2011-07-07 08:21:25 +0000996 return -1;
997 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000998 if (_shared->audio_device()->StartPlayout() != 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 start playout");
niklase@google.com470e71d2011-07-07 08:21:25 +00001003 return -1;
1004 }
1005 }
1006 return 0;
1007}
1008
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +00001009int32_t VoEBaseImpl::StopPlayout() {
1010 WEBRTC_TRACE(kTraceInfo,
1011 kTraceVoice,
1012 VoEId(_shared->instance_id(), -1),
1013 "VoEBaseImpl::StopPlayout()");
1014 // Stop audio-device playing if no channel is playing out
xians@webrtc.org675e2602013-10-17 16:15:34 +00001015 if (_shared->NumOfPlayingChannels() == 0) {
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +00001016 if (_shared->audio_device()->StopPlayout() != 0) {
1017 _shared->SetLastError(VE_CANNOT_STOP_PLAYOUT,
1018 kTraceError,
1019 "StopPlayout() failed to stop playout");
1020 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001021 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +00001022 }
1023 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001024}
1025
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001026int32_t VoEBaseImpl::StartSend()
niklase@google.com470e71d2011-07-07 08:21:25 +00001027{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001028 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001029 "VoEBaseImpl::StartSend()");
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001030 if (_shared->audio_device()->Recording())
niklase@google.com470e71d2011-07-07 08:21:25 +00001031 {
1032 return 0;
1033 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001034 if (!_shared->ext_recording())
niklase@google.com470e71d2011-07-07 08:21:25 +00001035 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001036 if (_shared->audio_device()->InitRecording() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001037 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001038 WEBRTC_TRACE(kTraceError, kTraceVoice,
1039 VoEId(_shared->instance_id(), -1),
1040 "StartSend() failed to initialize recording");
niklase@google.com470e71d2011-07-07 08:21:25 +00001041 return -1;
1042 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001043 if (_shared->audio_device()->StartRecording() != 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 start recording");
niklase@google.com470e71d2011-07-07 08:21:25 +00001048 return -1;
1049 }
1050 }
1051
1052 return 0;
1053}
1054
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001055int32_t VoEBaseImpl::StopSend()
niklase@google.com470e71d2011-07-07 08:21:25 +00001056{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001057 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001058 "VoEBaseImpl::StopSend()");
1059
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001060 if (_shared->NumOfSendingChannels() == 0 &&
1061 !_shared->transmit_mixer()->IsRecordingMic())
niklase@google.com470e71d2011-07-07 08:21:25 +00001062 {
1063 // Stop audio-device recording if no channel is recording
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001064 if (_shared->audio_device()->StopRecording() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001065 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001066 _shared->SetLastError(VE_CANNOT_STOP_RECORDING, kTraceError,
1067 "StopSend() failed to stop recording");
niklase@google.com470e71d2011-07-07 08:21:25 +00001068 return -1;
1069 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001070 _shared->transmit_mixer()->StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +00001071 }
1072
1073 return 0;
1074}
1075
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001076int32_t VoEBaseImpl::TerminateInternal()
niklase@google.com470e71d2011-07-07 08:21:25 +00001077{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001078 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001079 "VoEBaseImpl::TerminateInternal()");
1080
1081 // Delete any remaining channel objects
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +00001082 _shared->channel_manager().DestroyAllChannels();
niklase@google.com470e71d2011-07-07 08:21:25 +00001083
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001084 if (_shared->process_thread())
niklase@google.com470e71d2011-07-07 08:21:25 +00001085 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001086 if (_shared->audio_device())
niklase@google.com470e71d2011-07-07 08:21:25 +00001087 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001088 if (_shared->process_thread()->
1089 DeRegisterModule(_shared->audio_device()) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001090 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001091 _shared->SetLastError(VE_THREAD_ERROR, kTraceError,
1092 "TerminateInternal() failed to deregister ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +00001093 }
1094 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001095 if (_shared->process_thread()->Stop() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001096 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001097 _shared->SetLastError(VE_THREAD_ERROR, kTraceError,
1098 "TerminateInternal() failed to stop module process thread");
niklase@google.com470e71d2011-07-07 08:21:25 +00001099 }
1100 }
1101
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +00001102 if (_shared->audio_device())
niklase@google.com470e71d2011-07-07 08:21:25 +00001103 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001104 if (_shared->audio_device()->StopPlayout() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001105 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001106 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
1107 "TerminateInternal() failed to stop playout");
niklase@google.com470e71d2011-07-07 08:21:25 +00001108 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001109 if (_shared->audio_device()->StopRecording() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001110 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001111 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
1112 "TerminateInternal() failed to stop recording");
niklase@google.com470e71d2011-07-07 08:21:25 +00001113 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001114 if (_shared->audio_device()->RegisterEventObserver(NULL) != 0) {
1115 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
1116 "TerminateInternal() failed to de-register event observer "
1117 "for the ADM");
xians@webrtc.org79af7342012-01-31 12:22:14 +00001118 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001119 if (_shared->audio_device()->RegisterAudioCallback(NULL) != 0) {
1120 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
1121 "TerminateInternal() failed to de-register audio callback "
1122 "for the ADM");
xians@webrtc.org79af7342012-01-31 12:22:14 +00001123 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001124 if (_shared->audio_device()->Terminate() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001125 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001126 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
1127 "TerminateInternal() failed to terminate the ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +00001128 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001129 _shared->set_audio_device(NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +00001130 }
1131
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +00001132 if (_shared->audio_processing()) {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001133 _shared->set_audio_processing(NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +00001134 }
1135
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001136 return _shared->statistics().SetUnInitialized();
niklase@google.com470e71d2011-07-07 08:21:25 +00001137}
1138
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00001139int VoEBaseImpl::ProcessRecordedDataWithAPM(
1140 const int voe_channels[],
1141 int number_of_voe_channels,
1142 const void* audio_data,
1143 uint32_t sample_rate,
1144 uint8_t number_of_channels,
1145 uint32_t number_of_frames,
1146 uint32_t audio_delay_milliseconds,
1147 int32_t clock_drift,
1148 uint32_t current_volume,
1149 bool key_pressed) {
1150 assert(_shared->transmit_mixer() != NULL);
1151 assert(_shared->audio_device() != NULL);
1152
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00001153 uint32_t max_volume = 0;
1154 uint16_t current_voe_mic_level = 0;
andrew@webrtc.org023cc5a2014-01-11 01:25:53 +00001155 // Check for zero to skip this calculation; the consumer may use this to
1156 // indicate no volume is available.
1157 if (current_volume != 0) {
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00001158 // Scale from ADM to VoE level range
1159 if (_shared->audio_device()->MaxMicrophoneVolume(&max_volume) == 0) {
1160 if (max_volume) {
1161 current_voe_mic_level = static_cast<uint16_t>(
1162 (current_volume * kMaxVolumeLevel +
1163 static_cast<int>(max_volume / 2)) / max_volume);
1164 }
1165 }
1166 // We learned that on certain systems (e.g Linux) the current_voe_mic_level
1167 // can be greater than the maxVolumeLevel therefore
1168 // we are going to cap the current_voe_mic_level to the maxVolumeLevel
1169 // and change the maxVolume to current_volume if it turns out that
1170 // the current_voe_mic_level is indeed greater than the maxVolumeLevel.
1171 if (current_voe_mic_level > kMaxVolumeLevel) {
1172 current_voe_mic_level = kMaxVolumeLevel;
1173 max_volume = current_volume;
1174 }
1175 }
1176
1177 // Keep track if the MicLevel has been changed by the AGC, if not,
1178 // use the old value AGC returns to let AGC continue its trend,
1179 // so eventually the AGC is able to change the mic level. This handles
1180 // issues with truncation introduced by the scaling.
1181 if (_oldMicLevel == current_volume)
1182 current_voe_mic_level = static_cast<uint16_t>(_oldVoEMicLevel);
1183
1184 // Perform channel-independent operations
1185 // (APM, mix with file, record to file, mute, etc.)
1186 _shared->transmit_mixer()->PrepareDemux(
1187 audio_data, number_of_frames, number_of_channels, sample_rate,
1188 static_cast<uint16_t>(audio_delay_milliseconds), clock_drift,
1189 current_voe_mic_level, key_pressed);
1190
1191 // Copy the audio frame to each sending channel and perform
1192 // channel-dependent operations (file mixing, mute, etc.), encode and
1193 // packetize+transmit the RTP packet. When |number_of_voe_channels| == 0,
1194 // do the operations on all the existing VoE channels; otherwise the
1195 // operations will be done on specific channels.
1196 if (number_of_voe_channels == 0) {
1197 _shared->transmit_mixer()->DemuxAndMix();
1198 _shared->transmit_mixer()->EncodeAndSend();
1199 } else {
1200 _shared->transmit_mixer()->DemuxAndMix(voe_channels,
1201 number_of_voe_channels);
1202 _shared->transmit_mixer()->EncodeAndSend(voe_channels,
1203 number_of_voe_channels);
1204 }
1205
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00001206 // Scale from VoE to ADM level range.
1207 uint32_t new_voe_mic_level = _shared->transmit_mixer()->CaptureLevel();
1208
1209 // Keep track of the value AGC returns.
1210 _oldVoEMicLevel = new_voe_mic_level;
1211 _oldMicLevel = current_volume;
1212
1213 if (new_voe_mic_level != current_voe_mic_level) {
1214 // Return the new volume if AGC has changed the volume.
1215 return static_cast<int>(
1216 (new_voe_mic_level * max_volume +
1217 static_cast<int>(kMaxVolumeLevel / 2)) / kMaxVolumeLevel);
1218 }
1219
1220 // Return 0 to indicate no change on the volume.
1221 return 0;
1222}
1223
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00001224} // namespace webrtc