blob: 3dddca5652afaa36193789bab9c81788b0e7368b [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) {
226 voe::ScopedChannel sc(_shared->channel_manager(), voe_channels[i]);
227 voe::Channel* channel_ptr = sc.ChannelPtr();
228 if (!channel_ptr)
229 continue;
230
231 if (channel_ptr->InputIsOnHold()) {
232 channel_ptr->UpdateLocalTimeStamp();
233 } else if (channel_ptr->Sending()) {
234 channel_ptr->Demultiplex(audio_data, sample_rate, number_of_frames,
235 number_of_channels);
236 channel_ptr->PrepareEncodeAndSend(sample_rate);
237 channel_ptr->EncodeAndSend();
238 }
239 }
240
241 // Return 0 to indicate no need to change the volume.
242 return 0;
243}
244
niklase@google.com470e71d2011-07-07 08:21:25 +0000245int VoEBaseImpl::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
246{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000247 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000248 "RegisterVoiceEngineObserver(observer=0x%d)", &observer);
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000249 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000250 if (_voiceEngineObserverPtr)
251 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000252 _shared->SetLastError(VE_INVALID_OPERATION, kTraceError,
253 "RegisterVoiceEngineObserver() observer already enabled");
niklase@google.com470e71d2011-07-07 08:21:25 +0000254 return -1;
255 }
256
257 // Register the observer in all active channels
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000258 voe::ScopedChannel sc(_shared->channel_manager());
niklase@google.com470e71d2011-07-07 08:21:25 +0000259 void* iterator(NULL);
260 voe::Channel* channelPtr = sc.GetFirstChannel(iterator);
261 while (channelPtr != NULL)
262 {
263 channelPtr->RegisterVoiceEngineObserver(observer);
264 channelPtr = sc.GetNextChannel(iterator);
265 }
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
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000290 voe::ScopedChannel sc(_shared->channel_manager());
niklase@google.com470e71d2011-07-07 08:21:25 +0000291 void* iterator(NULL);
292 voe::Channel* channelPtr = sc.GetFirstChannel(iterator);
293 while (channelPtr != NULL)
294 {
295 channelPtr->DeRegisterVoiceEngineObserver();
296 channelPtr = sc.GetNextChannel(iterator);
297 }
298
299 return 0;
300}
301
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000302int VoEBaseImpl::Init(AudioDeviceModule* external_adm,
303 AudioProcessing* audioproc)
niklase@google.com470e71d2011-07-07 08:21:25 +0000304{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000305 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
henrika@google.com73d65512011-09-07 15:11:18 +0000306 "Init(external_adm=0x%p)", external_adm);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000307 CriticalSectionScoped cs(_shared->crit_sec());
niklase@google.com470e71d2011-07-07 08:21:25 +0000308
kma@webrtc.org0221b782012-09-08 00:09:26 +0000309 WebRtcSpl_Init();
310
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000311 if (_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000312 {
313 return 0;
314 }
315
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000316 if (_shared->process_thread())
niklase@google.com470e71d2011-07-07 08:21:25 +0000317 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000318 if (_shared->process_thread()->Start() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000319 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000320 _shared->SetLastError(VE_THREAD_ERROR, kTraceError,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000321 "Init() failed to start module process thread");
niklase@google.com470e71d2011-07-07 08:21:25 +0000322 return -1;
323 }
324 }
325
andrew@webrtc.org3192d652011-12-21 18:00:59 +0000326 // Create an internal ADM if the user has not added an external
henrika@google.com73d65512011-09-07 15:11:18 +0000327 // ADM implementation as input to Init().
328 if (external_adm == NULL)
niklase@google.com470e71d2011-07-07 08:21:25 +0000329 {
henrika@google.com73d65512011-09-07 15:11:18 +0000330 // Create the internal ADM implementation.
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000331 _shared->set_audio_device(AudioDeviceModuleImpl::Create(
332 VoEId(_shared->instance_id(), -1), _shared->audio_device_layer()));
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000333
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000334 if (_shared->audio_device() == NULL)
niklase@google.com470e71d2011-07-07 08:21:25 +0000335 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000336 _shared->SetLastError(VE_NO_MEMORY, kTraceCritical,
337 "Init() failed to create the ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +0000338 return -1;
339 }
340 }
henrika@google.com73d65512011-09-07 15:11:18 +0000341 else
342 {
343 // Use the already existing external ADM implementation.
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000344 _shared->set_audio_device(external_adm);
345 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
henrika@google.com73d65512011-09-07 15:11:18 +0000346 "An external ADM implementation will be used in VoiceEngine");
347 }
348
niklase@google.com470e71d2011-07-07 08:21:25 +0000349 // Register the ADM to the process thread, which will drive the error
350 // callback mechanism
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000351 if (_shared->process_thread() &&
352 _shared->process_thread()->RegisterModule(_shared->audio_device()) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000353 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000354 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
355 "Init() failed to register the ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +0000356 return -1;
357 }
358
359 bool available(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000360
361 // --------------------
362 // Reinitialize the ADM
363
364 // Register the AudioObserver implementation
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000365 if (_shared->audio_device()->RegisterEventObserver(this) != 0) {
366 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
367 "Init() failed to register event observer for the ADM");
xians@webrtc.org79af7342012-01-31 12:22:14 +0000368 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000369
370 // Register the AudioTransport implementation
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000371 if (_shared->audio_device()->RegisterAudioCallback(this) != 0) {
372 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
373 "Init() failed to register audio callback for the ADM");
xians@webrtc.org79af7342012-01-31 12:22:14 +0000374 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000375
376 // ADM initialization
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000377 if (_shared->audio_device()->Init() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000378 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000379 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
380 "Init() failed to initialize the ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +0000381 return -1;
382 }
383
384 // Initialize the default speaker
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000385 if (_shared->audio_device()->SetPlayoutDevice(
386 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000387 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000388 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000389 "Init() failed to set the default output device");
niklase@google.com470e71d2011-07-07 08:21:25 +0000390 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000391 if (_shared->audio_device()->SpeakerIsAvailable(&available) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000392 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000393 _shared->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000394 "Init() failed to check speaker availability, trying to "
395 "initialize speaker anyway");
niklase@google.com470e71d2011-07-07 08:21:25 +0000396 }
397 else if (!available)
398 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000399 _shared->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000400 "Init() speaker not available, trying to initialize speaker "
401 "anyway");
niklase@google.com470e71d2011-07-07 08:21:25 +0000402 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000403 if (_shared->audio_device()->InitSpeaker() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000404 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000405 _shared->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000406 "Init() failed to initialize the speaker");
niklase@google.com470e71d2011-07-07 08:21:25 +0000407 }
408
409 // Initialize the default microphone
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000410 if (_shared->audio_device()->SetRecordingDevice(
411 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000412 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000413 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000414 "Init() failed to set the default input device");
niklase@google.com470e71d2011-07-07 08:21:25 +0000415 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000416 if (_shared->audio_device()->MicrophoneIsAvailable(&available) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000417 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000418 _shared->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000419 "Init() failed to check microphone availability, trying to "
420 "initialize microphone anyway");
niklase@google.com470e71d2011-07-07 08:21:25 +0000421 }
422 else if (!available)
423 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000424 _shared->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000425 "Init() microphone not available, trying to initialize "
426 "microphone anyway");
niklase@google.com470e71d2011-07-07 08:21:25 +0000427 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000428 if (_shared->audio_device()->InitMicrophone() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000429 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000430 _shared->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000431 "Init() failed to initialize the microphone");
niklase@google.com470e71d2011-07-07 08:21:25 +0000432 }
433
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000434 // Set number of channels
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000435 if (_shared->audio_device()->StereoPlayoutIsAvailable(&available) != 0) {
436 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
437 "Init() failed to query stereo playout mode");
xians@webrtc.org79af7342012-01-31 12:22:14 +0000438 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000439 if (_shared->audio_device()->SetStereoPlayout(available) != 0)
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000440 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000441 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000442 "Init() failed to set mono/stereo playout mode");
443 }
andrew@webrtc.org3192d652011-12-21 18:00:59 +0000444
445 // TODO(andrew): These functions don't tell us whether stereo recording
446 // is truly available. We simply set the AudioProcessing input to stereo
447 // here, because we have to wait until receiving the first frame to
448 // determine the actual number of channels anyway.
449 //
450 // These functions may be changed; tracked here:
451 // http://code.google.com/p/webrtc/issues/detail?id=204
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000452 _shared->audio_device()->StereoRecordingIsAvailable(&available);
453 if (_shared->audio_device()->SetStereoRecording(available) != 0)
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000454 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000455 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000456 "Init() failed to set mono/stereo recording mode");
457 }
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000458
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000459 if (!audioproc) {
460 audioproc = AudioProcessing::Create(VoEId(_shared->instance_id(), -1));
461 if (!audioproc) {
462 LOG(LS_ERROR) << "Failed to create AudioProcessing.";
463 _shared->SetLastError(VE_NO_MEMORY);
464 return -1;
465 }
466 }
467 _shared->set_audio_processing(audioproc);
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000468
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000469 // Set the error state for any failures in this block.
470 _shared->SetLastError(VE_APM_ERROR);
471 if (audioproc->echo_cancellation()->set_device_sample_rate_hz(48000)) {
472 LOG_FERR1(LS_ERROR, set_device_sample_rate_hz, 48000);
473 return -1;
474 }
475 // Assume 16 kHz mono until the audio frames are received from the capture
476 // device, at which point this can be updated.
477 if (audioproc->set_sample_rate_hz(16000)) {
478 LOG_FERR1(LS_ERROR, set_sample_rate_hz, 16000);
479 return -1;
480 }
481 if (audioproc->set_num_channels(1, 1) != 0) {
482 LOG_FERR2(LS_ERROR, set_num_channels, 1, 1);
483 return -1;
484 }
485 if (audioproc->set_num_reverse_channels(1) != 0) {
486 LOG_FERR1(LS_ERROR, set_num_reverse_channels, 1);
487 return -1;
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000488 }
489
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000490 // Configure AudioProcessing components. All are disabled by default.
491 if (audioproc->high_pass_filter()->Enable(true) != 0) {
492 LOG_FERR1(LS_ERROR, high_pass_filter()->Enable, true);
493 return -1;
494 }
495 if (audioproc->echo_cancellation()->enable_drift_compensation(false) != 0) {
496 LOG_FERR1(LS_ERROR, enable_drift_compensation, false);
497 return -1;
498 }
499 if (audioproc->noise_suppression()->set_level(kDefaultNsMode) != 0) {
500 LOG_FERR1(LS_ERROR, noise_suppression()->set_level, kDefaultNsMode);
501 return -1;
502 }
503 GainControl* agc = audioproc->gain_control();
504 if (agc->set_analog_level_limits(kMinVolumeLevel, kMaxVolumeLevel) != 0) {
505 LOG_FERR2(LS_ERROR, agc->set_analog_level_limits, kMinVolumeLevel,
506 kMaxVolumeLevel);
507 return -1;
508 }
509 if (agc->set_mode(kDefaultAgcMode) != 0) {
510 LOG_FERR1(LS_ERROR, agc->set_mode, kDefaultAgcMode);
511 return -1;
512 }
513 if (agc->Enable(kDefaultAgcState) != 0) {
514 LOG_FERR1(LS_ERROR, agc->Enable, kDefaultAgcState);
515 return -1;
516 }
517 _shared->SetLastError(0); // Clear error state.
518
niklase@google.com470e71d2011-07-07 08:21:25 +0000519#ifdef WEBRTC_VOICE_ENGINE_AGC
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000520 bool agc_enabled = agc->mode() == GainControl::kAdaptiveAnalog &&
521 agc->is_enabled();
522 if (_shared->audio_device()->SetAGC(agc_enabled) != 0) {
523 LOG_FERR1(LS_ERROR, audio_device()->SetAGC, agc_enabled);
524 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR);
andrew@webrtc.orga9a1df02013-03-05 23:36:10 +0000525 // TODO(ajm): No error return here due to
526 // https://code.google.com/p/webrtc/issues/detail?id=1464
niklase@google.com470e71d2011-07-07 08:21:25 +0000527 }
528#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000529
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000530 return _shared->statistics().SetInitialized();
niklase@google.com470e71d2011-07-07 08:21:25 +0000531}
532
533int VoEBaseImpl::Terminate()
534{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000535 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000536 "Terminate()");
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000537 CriticalSectionScoped cs(_shared->crit_sec());
niklase@google.com470e71d2011-07-07 08:21:25 +0000538 return TerminateInternal();
539}
540
541int VoEBaseImpl::MaxNumOfChannels()
542{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000543 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000544 "MaxNumOfChannels()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000545 int32_t maxNumOfChannels =
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000546 _shared->channel_manager().MaxNumOfChannels();
547 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
548 VoEId(_shared->instance_id(), -1),
549 "MaxNumOfChannels() => %d", maxNumOfChannels);
niklase@google.com470e71d2011-07-07 08:21:25 +0000550 return (maxNumOfChannels);
551}
552
553int VoEBaseImpl::CreateChannel()
554{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000555 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000556 "CreateChannel()");
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000557 CriticalSectionScoped cs(_shared->crit_sec());
niklase@google.com470e71d2011-07-07 08:21:25 +0000558
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000559 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000560 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000561 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000562 return -1;
563 }
564
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000565 int32_t channelId = -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000566
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000567 if (!_shared->channel_manager().CreateChannel(channelId))
niklase@google.com470e71d2011-07-07 08:21:25 +0000568 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000569 _shared->SetLastError(VE_CHANNEL_NOT_CREATED, kTraceError,
570 "CreateChannel() failed to allocate memory for channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000571 return -1;
572 }
573
574 bool destroyChannel(false);
575 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000576 voe::ScopedChannel sc(_shared->channel_manager(), channelId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000577 voe::Channel* channelPtr = sc.ChannelPtr();
578 if (channelPtr == NULL)
579 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000580 _shared->SetLastError(VE_CHANNEL_NOT_CREATED, kTraceError,
581 "CreateChannel() failed to allocate memory for channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000582 return -1;
583 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000584 else if (channelPtr->SetEngineInformation(_shared->statistics(),
585 *_shared->output_mixer(),
586 *_shared->transmit_mixer(),
587 *_shared->process_thread(),
588 *_shared->audio_device(),
niklase@google.com470e71d2011-07-07 08:21:25 +0000589 _voiceEngineObserverPtr,
590 &_callbackCritSect) != 0)
591 {
592 destroyChannel = true;
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000593 _shared->SetLastError(VE_CHANNEL_NOT_CREATED, kTraceError,
594 "CreateChannel() failed to associate engine and channel."
595 " Destroying channel.");
niklase@google.com470e71d2011-07-07 08:21:25 +0000596 }
597 else if (channelPtr->Init() != 0)
598 {
599 destroyChannel = true;
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000600 _shared->SetLastError(VE_CHANNEL_NOT_CREATED, kTraceError,
601 "CreateChannel() failed to initialize channel. Destroying"
602 " channel.");
niklase@google.com470e71d2011-07-07 08:21:25 +0000603 }
604 }
605 if (destroyChannel)
606 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000607 _shared->channel_manager().DestroyChannel(channelId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000608 return -1;
609 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000610 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
611 VoEId(_shared->instance_id(), -1),
612 "CreateChannel() => %d", channelId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000613 return channelId;
614}
615
616int VoEBaseImpl::DeleteChannel(int channel)
617{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000618 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000619 "DeleteChannel(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000620 CriticalSectionScoped cs(_shared->crit_sec());
niklase@google.com470e71d2011-07-07 08:21:25 +0000621
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000622 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000623 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000624 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000625 return -1;
626 }
627
628 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000629 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000630 voe::Channel* channelPtr = sc.ChannelPtr();
631 if (channelPtr == NULL)
632 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000633 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
634 "DeleteChannel() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000635 return -1;
636 }
637 }
638
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000639 if (_shared->channel_manager().DestroyChannel(channel) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000640 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000641 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
642 "DeleteChannel() failed to destroy channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000643 return -1;
644 }
645
646 if (StopSend() != 0)
647 {
648 return -1;
649 }
650
651 if (StopPlayout() != 0)
652 {
653 return -1;
654 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +0000655
niklase@google.com470e71d2011-07-07 08:21:25 +0000656 return 0;
657}
658
niklase@google.com470e71d2011-07-07 08:21:25 +0000659int VoEBaseImpl::StartReceive(int channel)
660{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000661 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000662 "StartReceive(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000663 CriticalSectionScoped cs(_shared->crit_sec());
664 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000665 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000666 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000667 return -1;
668 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000669 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000670 voe::Channel* channelPtr = sc.ChannelPtr();
671 if (channelPtr == NULL)
672 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000673 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
674 "StartReceive() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000675 return -1;
676 }
677 return channelPtr->StartReceiving();
678}
679
680int VoEBaseImpl::StopReceive(int channel)
681{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000682 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000683 "StopListen(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000684 CriticalSectionScoped cs(_shared->crit_sec());
685 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000686 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000687 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000688 return -1;
689 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000690 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000691 voe::Channel* channelPtr = sc.ChannelPtr();
692 if (channelPtr == NULL)
693 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000694 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
695 "SetLocalReceiver() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000696 return -1;
697 }
698 return channelPtr->StopReceiving();
699}
700
701int VoEBaseImpl::StartPlayout(int channel)
702{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000703 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000704 "StartPlayout(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000705 CriticalSectionScoped cs(_shared->crit_sec());
706 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000707 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000708 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000709 return -1;
710 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000711 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000712 voe::Channel* channelPtr = sc.ChannelPtr();
713 if (channelPtr == NULL)
714 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000715 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
716 "StartPlayout() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000717 return -1;
718 }
719 if (channelPtr->Playing())
720 {
721 return 0;
722 }
723 if (StartPlayout() != 0)
724 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000725 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
726 "StartPlayout() failed to start playout");
niklase@google.com470e71d2011-07-07 08:21:25 +0000727 return -1;
728 }
729 return channelPtr->StartPlayout();
730}
731
732int VoEBaseImpl::StopPlayout(int channel)
733{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000734 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000735 "StopPlayout(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000736 CriticalSectionScoped cs(_shared->crit_sec());
737 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000738 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000739 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000740 return -1;
741 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000742 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000743 voe::Channel* channelPtr = sc.ChannelPtr();
744 if (channelPtr == NULL)
745 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000746 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
747 "StopPlayout() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000748 return -1;
749 }
750 if (channelPtr->StopPlayout() != 0)
751 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000752 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
753 VoEId(_shared->instance_id(), -1),
754 "StopPlayout() failed to stop playout for channel %d", channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000755 }
756 return StopPlayout();
757}
758
759int VoEBaseImpl::StartSend(int channel)
760{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000761 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000762 "StartSend(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000763 CriticalSectionScoped cs(_shared->crit_sec());
764 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000765 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000766 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000767 return -1;
768 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000769 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000770 voe::Channel* channelPtr = sc.ChannelPtr();
771 if (channelPtr == NULL)
772 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000773 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
774 "StartSend() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000775 return -1;
776 }
777 if (channelPtr->Sending())
778 {
779 return 0;
780 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000781 if (StartSend() != 0)
782 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000783 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
784 "StartSend() failed to start recording");
niklase@google.com470e71d2011-07-07 08:21:25 +0000785 return -1;
786 }
787 return channelPtr->StartSend();
788}
789
790int VoEBaseImpl::StopSend(int channel)
791{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000792 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000793 "StopSend(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000794 CriticalSectionScoped cs(_shared->crit_sec());
795 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000796 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000797 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000798 return -1;
799 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000800 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000801 voe::Channel* channelPtr = sc.ChannelPtr();
802 if (channelPtr == NULL)
803 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000804 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
805 "StopSend() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000806 return -1;
807 }
808 if (channelPtr->StopSend() != 0)
809 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000810 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
811 VoEId(_shared->instance_id(), -1),
812 "StopSend() failed to stop sending for channel %d", channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000813 }
814 return StopSend();
815}
816
817int VoEBaseImpl::GetVersion(char version[1024])
818{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000819 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000820 "GetVersion(version=?)");
821 assert(kVoiceEngineVersionMaxMessageSize == 1024);
822
823 if (version == NULL)
824 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000825 _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000826 return (-1);
827 }
828
829 char versionBuf[kVoiceEngineVersionMaxMessageSize];
830 char* versionPtr = versionBuf;
831
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000832 int32_t len = 0;
833 int32_t accLen = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000834
835 len = AddVoEVersion(versionPtr);
836 if (len == -1)
837 {
838 return -1;
839 }
840 versionPtr += len;
841 accLen += len;
842 assert(accLen < kVoiceEngineVersionMaxMessageSize);
843
844 len = AddBuildInfo(versionPtr);
845 if (len == -1)
846 {
847 return -1;
848 }
849 versionPtr += len;
850 accLen += len;
851 assert(accLen < kVoiceEngineVersionMaxMessageSize);
852
pwestin@webrtc.org684f0572013-03-13 23:20:57 +0000853#ifdef WEBRTC_EXTERNAL_TRANSPORT
854 len = AddExternalTransportBuild(versionPtr);
855 if (len == -1)
856 {
857 return -1;
858 }
859 versionPtr += len;
860 accLen += len;
861 assert(accLen < kVoiceEngineVersionMaxMessageSize);
862#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000863#ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT
864 len = AddExternalRecAndPlayoutBuild(versionPtr);
865 if (len == -1)
866 {
867 return -1;
868 }
869 versionPtr += len;
870 accLen += len;
871 assert(accLen < kVoiceEngineVersionMaxMessageSize);
pwestin@webrtc.orgc450a192012-01-04 15:00:12 +0000872 #endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000873
874 memcpy(version, versionBuf, accLen);
875 version[accLen] = '\0';
876
877 // to avoid the truncation in the trace, split the string into parts
878 char partOfVersion[256];
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000879 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
880 VoEId(_shared->instance_id(), -1), "GetVersion() =>");
niklase@google.com470e71d2011-07-07 08:21:25 +0000881 for (int partStart = 0; partStart < accLen;)
882 {
883 memset(partOfVersion, 0, sizeof(partOfVersion));
884 int partEnd = partStart + 180;
885 while (version[partEnd] != '\n' && version[partEnd] != '\0')
886 {
887 partEnd--;
888 }
889 if (partEnd < accLen)
890 {
891 memcpy(partOfVersion, &version[partStart], partEnd - partStart);
892 }
893 else
894 {
895 memcpy(partOfVersion, &version[partStart], accLen - partStart);
896 }
897 partStart = partEnd;
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000898 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
899 VoEId(_shared->instance_id(), -1), "%s", partOfVersion);
niklase@google.com470e71d2011-07-07 08:21:25 +0000900 }
901
902 return 0;
903}
904
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000905int32_t VoEBaseImpl::AddBuildInfo(char* str) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000906{
leozwang@webrtc.org48a5df62012-04-24 14:50:50 +0000907 return sprintf(str, "Build: svn:%s %s\n", WEBRTC_SVNREVISION, BUILDINFO);
niklase@google.com470e71d2011-07-07 08:21:25 +0000908}
909
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000910int32_t VoEBaseImpl::AddVoEVersion(char* str) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000911{
912 return sprintf(str, "VoiceEngine 4.1.0\n");
913}
914
pwestin@webrtc.org684f0572013-03-13 23:20:57 +0000915#ifdef WEBRTC_EXTERNAL_TRANSPORT
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000916int32_t VoEBaseImpl::AddExternalTransportBuild(char* str) const
pwestin@webrtc.org684f0572013-03-13 23:20:57 +0000917{
918 return sprintf(str, "External transport build\n");
919}
920#endif
921
niklase@google.com470e71d2011-07-07 08:21:25 +0000922#ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000923int32_t VoEBaseImpl::AddExternalRecAndPlayoutBuild(char* str) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000924{
925 return sprintf(str, "External recording and playout build\n");
926}
927#endif
928
niklase@google.com470e71d2011-07-07 08:21:25 +0000929int VoEBaseImpl::LastError()
930{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000931 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000932 "LastError()");
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000933 return (_shared->statistics().LastError());
niklase@google.com470e71d2011-07-07 08:21:25 +0000934}
935
936
937int VoEBaseImpl::SetNetEQPlayoutMode(int channel, NetEqModes mode)
938{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000939 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000940 "SetNetEQPlayoutMode(channel=%i, mode=%i)", channel, mode);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000941 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000942 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000943 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000944 return -1;
945 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000946 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000947 voe::Channel* channelPtr = sc.ChannelPtr();
948 if (channelPtr == NULL)
949 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000950 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
951 "SetNetEQPlayoutMode() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000952 return -1;
953 }
954 return channelPtr->SetNetEQPlayoutMode(mode);
955}
956
957int VoEBaseImpl::GetNetEQPlayoutMode(int channel, NetEqModes& mode)
958{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000959 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000960 "GetNetEQPlayoutMode(channel=%i, mode=?)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000961 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000962 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000963 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000964 return -1;
965 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000966 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000967 voe::Channel* channelPtr = sc.ChannelPtr();
968 if (channelPtr == NULL)
969 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000970 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
971 "GetNetEQPlayoutMode() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000972 return -1;
973 }
974 return channelPtr->GetNetEQPlayoutMode(mode);
975}
976
niklase@google.com470e71d2011-07-07 08:21:25 +0000977int VoEBaseImpl::SetOnHoldStatus(int channel, bool enable, OnHoldModes mode)
978{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000979 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000980 "SetOnHoldStatus(channel=%d, enable=%d, mode=%d)", channel,
981 enable, mode);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000982 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000983 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000984 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000985 return -1;
986 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000987 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000988 voe::Channel* channelPtr = sc.ChannelPtr();
989 if (channelPtr == NULL)
990 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000991 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
992 "SetOnHoldStatus() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000993 return -1;
994 }
995 return channelPtr->SetOnHoldStatus(enable, mode);
996}
997
998int VoEBaseImpl::GetOnHoldStatus(int channel, bool& enabled, OnHoldModes& mode)
999{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001000 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001001 "GetOnHoldStatus(channel=%d, enabled=?, mode=?)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001002 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +00001003 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001004 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +00001005 return -1;
1006 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001007 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +00001008 voe::Channel* channelPtr = sc.ChannelPtr();
1009 if (channelPtr == NULL)
1010 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001011 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
1012 "GetOnHoldStatus() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +00001013 return -1;
1014 }
1015 return channelPtr->GetOnHoldStatus(enabled, mode);
1016}
1017
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001018int32_t VoEBaseImpl::StartPlayout()
niklase@google.com470e71d2011-07-07 08:21:25 +00001019{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001020 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001021 "VoEBaseImpl::StartPlayout()");
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001022 if (_shared->audio_device()->Playing())
niklase@google.com470e71d2011-07-07 08:21:25 +00001023 {
1024 return 0;
1025 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001026 if (!_shared->ext_playout())
niklase@google.com470e71d2011-07-07 08:21:25 +00001027 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001028 if (_shared->audio_device()->InitPlayout() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001029 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001030 WEBRTC_TRACE(kTraceError, kTraceVoice,
1031 VoEId(_shared->instance_id(), -1),
1032 "StartPlayout() failed to initialize playout");
niklase@google.com470e71d2011-07-07 08:21:25 +00001033 return -1;
1034 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001035 if (_shared->audio_device()->StartPlayout() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001036 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001037 WEBRTC_TRACE(kTraceError, kTraceVoice,
1038 VoEId(_shared->instance_id(), -1),
1039 "StartPlayout() failed to start playout");
niklase@google.com470e71d2011-07-07 08:21:25 +00001040 return -1;
1041 }
1042 }
1043 return 0;
1044}
1045
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001046int32_t VoEBaseImpl::StopPlayout()
niklase@google.com470e71d2011-07-07 08:21:25 +00001047{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001048 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001049 "VoEBaseImpl::StopPlayout()");
1050
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001051 int32_t numOfChannels = _shared->channel_manager().NumOfChannels();
niklase@google.com470e71d2011-07-07 08:21:25 +00001052 if (numOfChannels <= 0)
1053 {
1054 return 0;
1055 }
1056
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001057 uint16_t nChannelsPlaying(0);
1058 int32_t* channelsArray = new int32_t[numOfChannels];
niklase@google.com470e71d2011-07-07 08:21:25 +00001059
1060 // Get number of playing channels
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001061 _shared->channel_manager().GetChannelIds(channelsArray, numOfChannels);
niklase@google.com470e71d2011-07-07 08:21:25 +00001062 for (int i = 0; i < numOfChannels; i++)
1063 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001064 voe::ScopedChannel sc(_shared->channel_manager(), channelsArray[i]);
niklase@google.com470e71d2011-07-07 08:21:25 +00001065 voe::Channel* chPtr = sc.ChannelPtr();
1066 if (chPtr)
1067 {
1068 if (chPtr->Playing())
1069 {
1070 nChannelsPlaying++;
1071 }
1072 }
1073 }
1074 delete[] channelsArray;
1075
1076 // Stop audio-device playing if no channel is playing out
1077 if (nChannelsPlaying == 0)
1078 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001079 if (_shared->audio_device()->StopPlayout() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001080 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001081 _shared->SetLastError(VE_CANNOT_STOP_PLAYOUT, kTraceError,
1082 "StopPlayout() failed to stop playout");
niklase@google.com470e71d2011-07-07 08:21:25 +00001083 return -1;
1084 }
1085 }
1086 return 0;
1087}
1088
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001089int32_t VoEBaseImpl::StartSend()
niklase@google.com470e71d2011-07-07 08:21:25 +00001090{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001091 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001092 "VoEBaseImpl::StartSend()");
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001093 if (_shared->audio_device()->Recording())
niklase@google.com470e71d2011-07-07 08:21:25 +00001094 {
1095 return 0;
1096 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001097 if (!_shared->ext_recording())
niklase@google.com470e71d2011-07-07 08:21:25 +00001098 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001099 if (_shared->audio_device()->InitRecording() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001100 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001101 WEBRTC_TRACE(kTraceError, kTraceVoice,
1102 VoEId(_shared->instance_id(), -1),
1103 "StartSend() failed to initialize recording");
niklase@google.com470e71d2011-07-07 08:21:25 +00001104 return -1;
1105 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001106 if (_shared->audio_device()->StartRecording() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001107 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001108 WEBRTC_TRACE(kTraceError, kTraceVoice,
1109 VoEId(_shared->instance_id(), -1),
1110 "StartSend() failed to start recording");
niklase@google.com470e71d2011-07-07 08:21:25 +00001111 return -1;
1112 }
1113 }
1114
1115 return 0;
1116}
1117
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001118int32_t VoEBaseImpl::StopSend()
niklase@google.com470e71d2011-07-07 08:21:25 +00001119{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001120 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001121 "VoEBaseImpl::StopSend()");
1122
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001123 if (_shared->NumOfSendingChannels() == 0 &&
1124 !_shared->transmit_mixer()->IsRecordingMic())
niklase@google.com470e71d2011-07-07 08:21:25 +00001125 {
1126 // Stop audio-device recording if no channel is recording
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001127 if (_shared->audio_device()->StopRecording() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001128 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001129 _shared->SetLastError(VE_CANNOT_STOP_RECORDING, kTraceError,
1130 "StopSend() failed to stop recording");
niklase@google.com470e71d2011-07-07 08:21:25 +00001131 return -1;
1132 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001133 _shared->transmit_mixer()->StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +00001134 }
1135
1136 return 0;
1137}
1138
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001139int32_t VoEBaseImpl::TerminateInternal()
niklase@google.com470e71d2011-07-07 08:21:25 +00001140{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001141 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001142 "VoEBaseImpl::TerminateInternal()");
1143
1144 // Delete any remaining channel objects
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001145 int32_t numOfChannels = _shared->channel_manager().NumOfChannels();
niklase@google.com470e71d2011-07-07 08:21:25 +00001146 if (numOfChannels > 0)
1147 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001148 int32_t* channelsArray = new int32_t[numOfChannels];
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001149 _shared->channel_manager().GetChannelIds(channelsArray, numOfChannels);
niklase@google.com470e71d2011-07-07 08:21:25 +00001150 for (int i = 0; i < numOfChannels; i++)
1151 {
1152 DeleteChannel(channelsArray[i]);
1153 }
1154 delete[] channelsArray;
1155 }
1156
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001157 if (_shared->process_thread())
niklase@google.com470e71d2011-07-07 08:21:25 +00001158 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001159 if (_shared->audio_device())
niklase@google.com470e71d2011-07-07 08:21:25 +00001160 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001161 if (_shared->process_thread()->
1162 DeRegisterModule(_shared->audio_device()) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001163 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001164 _shared->SetLastError(VE_THREAD_ERROR, kTraceError,
1165 "TerminateInternal() failed to deregister ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +00001166 }
1167 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001168 if (_shared->process_thread()->Stop() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001169 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001170 _shared->SetLastError(VE_THREAD_ERROR, kTraceError,
1171 "TerminateInternal() failed to stop module process thread");
niklase@google.com470e71d2011-07-07 08:21:25 +00001172 }
1173 }
1174
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +00001175 if (_shared->audio_device())
niklase@google.com470e71d2011-07-07 08:21:25 +00001176 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001177 if (_shared->audio_device()->StopPlayout() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001178 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001179 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
1180 "TerminateInternal() failed to stop playout");
niklase@google.com470e71d2011-07-07 08:21:25 +00001181 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001182 if (_shared->audio_device()->StopRecording() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001183 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001184 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
1185 "TerminateInternal() failed to stop recording");
niklase@google.com470e71d2011-07-07 08:21:25 +00001186 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001187 if (_shared->audio_device()->RegisterEventObserver(NULL) != 0) {
1188 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
1189 "TerminateInternal() failed to de-register event observer "
1190 "for the ADM");
xians@webrtc.org79af7342012-01-31 12:22:14 +00001191 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001192 if (_shared->audio_device()->RegisterAudioCallback(NULL) != 0) {
1193 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
1194 "TerminateInternal() failed to de-register audio callback "
1195 "for the ADM");
xians@webrtc.org79af7342012-01-31 12:22:14 +00001196 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001197 if (_shared->audio_device()->Terminate() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001198 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001199 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
1200 "TerminateInternal() failed to terminate the ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +00001201 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001202 _shared->set_audio_device(NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +00001203 }
1204
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +00001205 if (_shared->audio_processing()) {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001206 _shared->set_audio_processing(NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +00001207 }
1208
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001209 return _shared->statistics().SetUnInitialized();
niklase@google.com470e71d2011-07-07 08:21:25 +00001210}
1211
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00001212int VoEBaseImpl::ProcessRecordedDataWithAPM(
1213 const int voe_channels[],
1214 int number_of_voe_channels,
1215 const void* audio_data,
1216 uint32_t sample_rate,
1217 uint8_t number_of_channels,
1218 uint32_t number_of_frames,
1219 uint32_t audio_delay_milliseconds,
1220 int32_t clock_drift,
1221 uint32_t current_volume,
1222 bool key_pressed) {
1223 assert(_shared->transmit_mixer() != NULL);
1224 assert(_shared->audio_device() != NULL);
1225
1226 bool is_analog_agc(false);
1227 if (_shared->audio_processing() &&
1228 _shared->audio_processing()->gain_control()->mode() ==
1229 GainControl::kAdaptiveAnalog) {
1230 is_analog_agc = true;
1231 }
1232
1233 // Only deal with the volume in adaptive analog mode.
1234 uint32_t max_volume = 0;
1235 uint16_t current_voe_mic_level = 0;
1236 if (is_analog_agc) {
1237 // Scale from ADM to VoE level range
1238 if (_shared->audio_device()->MaxMicrophoneVolume(&max_volume) == 0) {
1239 if (max_volume) {
1240 current_voe_mic_level = static_cast<uint16_t>(
1241 (current_volume * kMaxVolumeLevel +
1242 static_cast<int>(max_volume / 2)) / max_volume);
1243 }
1244 }
1245 // We learned that on certain systems (e.g Linux) the current_voe_mic_level
1246 // can be greater than the maxVolumeLevel therefore
1247 // we are going to cap the current_voe_mic_level to the maxVolumeLevel
1248 // and change the maxVolume to current_volume if it turns out that
1249 // the current_voe_mic_level is indeed greater than the maxVolumeLevel.
1250 if (current_voe_mic_level > kMaxVolumeLevel) {
1251 current_voe_mic_level = kMaxVolumeLevel;
1252 max_volume = current_volume;
1253 }
1254 }
1255
1256 // Keep track if the MicLevel has been changed by the AGC, if not,
1257 // use the old value AGC returns to let AGC continue its trend,
1258 // so eventually the AGC is able to change the mic level. This handles
1259 // issues with truncation introduced by the scaling.
1260 if (_oldMicLevel == current_volume)
1261 current_voe_mic_level = static_cast<uint16_t>(_oldVoEMicLevel);
1262
1263 // Perform channel-independent operations
1264 // (APM, mix with file, record to file, mute, etc.)
1265 _shared->transmit_mixer()->PrepareDemux(
1266 audio_data, number_of_frames, number_of_channels, sample_rate,
1267 static_cast<uint16_t>(audio_delay_milliseconds), clock_drift,
1268 current_voe_mic_level, key_pressed);
1269
1270 // Copy the audio frame to each sending channel and perform
1271 // channel-dependent operations (file mixing, mute, etc.), encode and
1272 // packetize+transmit the RTP packet. When |number_of_voe_channels| == 0,
1273 // do the operations on all the existing VoE channels; otherwise the
1274 // operations will be done on specific channels.
1275 if (number_of_voe_channels == 0) {
1276 _shared->transmit_mixer()->DemuxAndMix();
1277 _shared->transmit_mixer()->EncodeAndSend();
1278 } else {
1279 _shared->transmit_mixer()->DemuxAndMix(voe_channels,
1280 number_of_voe_channels);
1281 _shared->transmit_mixer()->EncodeAndSend(voe_channels,
1282 number_of_voe_channels);
1283 }
1284
1285 if (!is_analog_agc)
1286 return 0;
1287
1288 // Scale from VoE to ADM level range.
1289 uint32_t new_voe_mic_level = _shared->transmit_mixer()->CaptureLevel();
1290
1291 // Keep track of the value AGC returns.
1292 _oldVoEMicLevel = new_voe_mic_level;
1293 _oldMicLevel = current_volume;
1294
1295 if (new_voe_mic_level != current_voe_mic_level) {
1296 // Return the new volume if AGC has changed the volume.
1297 return static_cast<int>(
1298 (new_voe_mic_level * max_volume +
1299 static_cast<int>(kMaxVolumeLevel / 2)) / kMaxVolumeLevel);
1300 }
1301
1302 // Return 0 to indicate no change on the volume.
1303 return 0;
1304}
1305
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00001306} // namespace webrtc