blob: a0d01932c13a05369115d037b4a65fbda2d6ed1b [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()),
andrew@webrtc.org27c69802014-02-18 20:24:56 +000052 _voiceEngineObserver(false), _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,
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000135 uint32_t micLevel,
pbos@webrtc.org92135212013-05-14 08:31:39 +0000136 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, "
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000142 "totalDelayMS=%u, clockDrift=%d, micLevel=%u)",
niklase@google.com470e71d2011-07-07 08:21:25 +0000143 nSamples, nBytesPerSample, nChannels, samplesPerSec,
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000144 totalDelayMS, clockDrift, micLevel);
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000145 newMicLevel = static_cast<uint32_t>(ProcessRecordedDataWithAPM(
146 NULL, 0, audioSamples, samplesPerSec, nChannels, nSamples,
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000147 totalDelayMS, clockDrift, micLevel, 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,
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000202 int volume,
xians@webrtc.org2f84afa2013-07-31 16:23:37 +0000203 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, "
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000208 "audio_delay_milliseconds=%d, volume=%d, "
xians@webrtc.org2f84afa2013-07-31 16:23:37 +0000209 "key_pressed=%d, need_audio_processing=%d)",
210 number_of_voe_channels, sample_rate, number_of_channels,
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000211 number_of_frames, audio_delay_milliseconds, volume,
xians@webrtc.org2f84afa2013-07-31 16:23:37 +0000212 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,
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000220 0, 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) {
xians@webrtc.orgc1e28032014-02-02 15:30:20 +0000226 OnData(voe_channels[i], audio_data, 16, sample_rate,
227 number_of_channels, number_of_frames);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +0000228 }
229
230 // Return 0 to indicate no need to change the volume.
231 return 0;
232}
233
xians@webrtc.orgc1e28032014-02-02 15:30:20 +0000234void VoEBaseImpl::OnData(int voe_channel, const void* audio_data,
235 int bits_per_sample, int sample_rate,
236 int number_of_channels,
237 int number_of_frames) {
xians@webrtc.org07e51962014-01-29 13:54:02 +0000238 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(voe_channel);
239 voe::Channel* channel_ptr = ch.channel();
240 if (!channel_ptr)
241 return;
242
243 if (channel_ptr->InputIsOnHold()) {
244 channel_ptr->UpdateLocalTimeStamp();
245 } else if (channel_ptr->Sending()) {
246 channel_ptr->Demultiplex(static_cast<const int16_t*>(audio_data),
247 sample_rate, number_of_frames, number_of_channels);
248 channel_ptr->PrepareEncodeAndSend(sample_rate);
249 channel_ptr->EncodeAndSend();
250 }
251}
252
niklase@google.com470e71d2011-07-07 08:21:25 +0000253int VoEBaseImpl::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
254{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000255 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000256 "RegisterVoiceEngineObserver(observer=0x%d)", &observer);
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000257 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000258 if (_voiceEngineObserverPtr)
259 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000260 _shared->SetLastError(VE_INVALID_OPERATION, kTraceError,
261 "RegisterVoiceEngineObserver() observer already enabled");
niklase@google.com470e71d2011-07-07 08:21:25 +0000262 return -1;
263 }
264
265 // Register the observer in all active channels
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000266 for (voe::ChannelManager::Iterator it(&_shared->channel_manager());
267 it.IsValid();
268 it.Increment()) {
269 it.GetChannel()->RegisterVoiceEngineObserver(observer);
niklase@google.com470e71d2011-07-07 08:21:25 +0000270 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000271
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000272 _shared->transmit_mixer()->RegisterVoiceEngineObserver(observer);
niklase@google.com470e71d2011-07-07 08:21:25 +0000273
274 _voiceEngineObserverPtr = &observer;
275 _voiceEngineObserver = true;
276
277 return 0;
278}
279
280int VoEBaseImpl::DeRegisterVoiceEngineObserver()
281{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000282 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000283 "DeRegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000284 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000285 if (!_voiceEngineObserverPtr)
286 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000287 _shared->SetLastError(VE_INVALID_OPERATION, kTraceError,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000288 "DeRegisterVoiceEngineObserver() observer already disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +0000289 return 0;
290 }
291
292 _voiceEngineObserver = false;
293 _voiceEngineObserverPtr = NULL;
294
295 // Deregister the observer in all active channels
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000296 for (voe::ChannelManager::Iterator it(&_shared->channel_manager());
297 it.IsValid();
298 it.Increment()) {
299 it.GetChannel()->DeRegisterVoiceEngineObserver();
niklase@google.com470e71d2011-07-07 08:21:25 +0000300 }
301
302 return 0;
303}
304
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000305int VoEBaseImpl::Init(AudioDeviceModule* external_adm,
306 AudioProcessing* audioproc)
niklase@google.com470e71d2011-07-07 08:21:25 +0000307{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000308 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
henrika@google.com73d65512011-09-07 15:11:18 +0000309 "Init(external_adm=0x%p)", external_adm);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000310 CriticalSectionScoped cs(_shared->crit_sec());
niklase@google.com470e71d2011-07-07 08:21:25 +0000311
kma@webrtc.org0221b782012-09-08 00:09:26 +0000312 WebRtcSpl_Init();
313
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000314 if (_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000315 {
316 return 0;
317 }
318
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000319 if (_shared->process_thread())
niklase@google.com470e71d2011-07-07 08:21:25 +0000320 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000321 if (_shared->process_thread()->Start() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000322 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000323 _shared->SetLastError(VE_THREAD_ERROR, kTraceError,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000324 "Init() failed to start module process thread");
niklase@google.com470e71d2011-07-07 08:21:25 +0000325 return -1;
326 }
327 }
328
andrew@webrtc.org3192d652011-12-21 18:00:59 +0000329 // Create an internal ADM if the user has not added an external
henrika@google.com73d65512011-09-07 15:11:18 +0000330 // ADM implementation as input to Init().
331 if (external_adm == NULL)
niklase@google.com470e71d2011-07-07 08:21:25 +0000332 {
henrika@google.com73d65512011-09-07 15:11:18 +0000333 // Create the internal ADM implementation.
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000334 _shared->set_audio_device(AudioDeviceModuleImpl::Create(
335 VoEId(_shared->instance_id(), -1), _shared->audio_device_layer()));
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000336
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000337 if (_shared->audio_device() == NULL)
niklase@google.com470e71d2011-07-07 08:21:25 +0000338 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000339 _shared->SetLastError(VE_NO_MEMORY, kTraceCritical,
340 "Init() failed to create the ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +0000341 return -1;
342 }
343 }
henrika@google.com73d65512011-09-07 15:11:18 +0000344 else
345 {
346 // Use the already existing external ADM implementation.
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000347 _shared->set_audio_device(external_adm);
348 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
henrika@google.com73d65512011-09-07 15:11:18 +0000349 "An external ADM implementation will be used in VoiceEngine");
350 }
351
niklase@google.com470e71d2011-07-07 08:21:25 +0000352 // Register the ADM to the process thread, which will drive the error
353 // callback mechanism
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000354 if (_shared->process_thread() &&
355 _shared->process_thread()->RegisterModule(_shared->audio_device()) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000356 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000357 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
358 "Init() failed to register the ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +0000359 return -1;
360 }
361
362 bool available(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000363
364 // --------------------
365 // Reinitialize the ADM
366
367 // Register the AudioObserver implementation
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000368 if (_shared->audio_device()->RegisterEventObserver(this) != 0) {
369 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
370 "Init() failed to register event observer for the ADM");
xians@webrtc.org79af7342012-01-31 12:22:14 +0000371 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000372
373 // Register the AudioTransport implementation
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000374 if (_shared->audio_device()->RegisterAudioCallback(this) != 0) {
375 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
376 "Init() failed to register audio callback for the ADM");
xians@webrtc.org79af7342012-01-31 12:22:14 +0000377 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000378
379 // ADM initialization
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000380 if (_shared->audio_device()->Init() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000381 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000382 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
383 "Init() failed to initialize the ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +0000384 return -1;
385 }
386
387 // Initialize the default speaker
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000388 if (_shared->audio_device()->SetPlayoutDevice(
389 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000390 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000391 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000392 "Init() failed to set the default output device");
niklase@google.com470e71d2011-07-07 08:21:25 +0000393 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000394 if (_shared->audio_device()->SpeakerIsAvailable(&available) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000395 {
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() failed to check speaker availability, trying to "
398 "initialize speaker anyway");
niklase@google.com470e71d2011-07-07 08:21:25 +0000399 }
400 else if (!available)
401 {
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() speaker not available, trying to initialize speaker "
404 "anyway");
niklase@google.com470e71d2011-07-07 08:21:25 +0000405 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000406 if (_shared->audio_device()->InitSpeaker() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000407 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000408 _shared->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000409 "Init() failed to initialize the speaker");
niklase@google.com470e71d2011-07-07 08:21:25 +0000410 }
411
412 // Initialize the default microphone
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000413 if (_shared->audio_device()->SetRecordingDevice(
414 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000415 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000416 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000417 "Init() failed to set the default input device");
niklase@google.com470e71d2011-07-07 08:21:25 +0000418 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000419 if (_shared->audio_device()->MicrophoneIsAvailable(&available) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000420 {
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() failed to check microphone availability, trying to "
423 "initialize microphone anyway");
niklase@google.com470e71d2011-07-07 08:21:25 +0000424 }
425 else if (!available)
426 {
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() microphone not available, trying to initialize "
429 "microphone anyway");
niklase@google.com470e71d2011-07-07 08:21:25 +0000430 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000431 if (_shared->audio_device()->InitMicrophone() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000432 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000433 _shared->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000434 "Init() failed to initialize the microphone");
niklase@google.com470e71d2011-07-07 08:21:25 +0000435 }
436
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000437 // Set number of channels
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000438 if (_shared->audio_device()->StereoPlayoutIsAvailable(&available) != 0) {
439 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
440 "Init() failed to query stereo playout mode");
xians@webrtc.org79af7342012-01-31 12:22:14 +0000441 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000442 if (_shared->audio_device()->SetStereoPlayout(available) != 0)
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000443 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000444 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000445 "Init() failed to set mono/stereo playout mode");
446 }
andrew@webrtc.org3192d652011-12-21 18:00:59 +0000447
448 // TODO(andrew): These functions don't tell us whether stereo recording
449 // is truly available. We simply set the AudioProcessing input to stereo
450 // here, because we have to wait until receiving the first frame to
451 // determine the actual number of channels anyway.
452 //
453 // These functions may be changed; tracked here:
454 // http://code.google.com/p/webrtc/issues/detail?id=204
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000455 _shared->audio_device()->StereoRecordingIsAvailable(&available);
456 if (_shared->audio_device()->SetStereoRecording(available) != 0)
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000457 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000458 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000459 "Init() failed to set mono/stereo recording mode");
460 }
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000461
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000462 if (!audioproc) {
463 audioproc = AudioProcessing::Create(VoEId(_shared->instance_id(), -1));
464 if (!audioproc) {
465 LOG(LS_ERROR) << "Failed to create AudioProcessing.";
466 _shared->SetLastError(VE_NO_MEMORY);
467 return -1;
468 }
469 }
470 _shared->set_audio_processing(audioproc);
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000471
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000472 // Set the error state for any failures in this block.
473 _shared->SetLastError(VE_APM_ERROR);
474 if (audioproc->echo_cancellation()->set_device_sample_rate_hz(48000)) {
475 LOG_FERR1(LS_ERROR, set_device_sample_rate_hz, 48000);
476 return -1;
477 }
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000478
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +0000479 // Configure AudioProcessing components.
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000480 if (audioproc->high_pass_filter()->Enable(true) != 0) {
481 LOG_FERR1(LS_ERROR, high_pass_filter()->Enable, true);
482 return -1;
483 }
484 if (audioproc->echo_cancellation()->enable_drift_compensation(false) != 0) {
485 LOG_FERR1(LS_ERROR, enable_drift_compensation, false);
486 return -1;
487 }
488 if (audioproc->noise_suppression()->set_level(kDefaultNsMode) != 0) {
489 LOG_FERR1(LS_ERROR, noise_suppression()->set_level, kDefaultNsMode);
490 return -1;
491 }
492 GainControl* agc = audioproc->gain_control();
493 if (agc->set_analog_level_limits(kMinVolumeLevel, kMaxVolumeLevel) != 0) {
494 LOG_FERR2(LS_ERROR, agc->set_analog_level_limits, kMinVolumeLevel,
495 kMaxVolumeLevel);
496 return -1;
497 }
498 if (agc->set_mode(kDefaultAgcMode) != 0) {
499 LOG_FERR1(LS_ERROR, agc->set_mode, kDefaultAgcMode);
500 return -1;
501 }
502 if (agc->Enable(kDefaultAgcState) != 0) {
503 LOG_FERR1(LS_ERROR, agc->Enable, kDefaultAgcState);
504 return -1;
505 }
506 _shared->SetLastError(0); // Clear error state.
507
niklase@google.com470e71d2011-07-07 08:21:25 +0000508#ifdef WEBRTC_VOICE_ENGINE_AGC
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000509 bool agc_enabled = agc->mode() == GainControl::kAdaptiveAnalog &&
510 agc->is_enabled();
511 if (_shared->audio_device()->SetAGC(agc_enabled) != 0) {
512 LOG_FERR1(LS_ERROR, audio_device()->SetAGC, agc_enabled);
513 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR);
andrew@webrtc.orga9a1df02013-03-05 23:36:10 +0000514 // TODO(ajm): No error return here due to
515 // https://code.google.com/p/webrtc/issues/detail?id=1464
niklase@google.com470e71d2011-07-07 08:21:25 +0000516 }
517#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000518
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000519 return _shared->statistics().SetInitialized();
niklase@google.com470e71d2011-07-07 08:21:25 +0000520}
521
522int VoEBaseImpl::Terminate()
523{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000524 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000525 "Terminate()");
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000526 CriticalSectionScoped cs(_shared->crit_sec());
niklase@google.com470e71d2011-07-07 08:21:25 +0000527 return TerminateInternal();
528}
529
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000530int VoEBaseImpl::CreateChannel() {
531 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
532 "CreateChannel()");
533 CriticalSectionScoped cs(_shared->crit_sec());
534 if (!_shared->statistics().Initialized()) {
535 _shared->SetLastError(VE_NOT_INITED, kTraceError);
536 return -1;
537 }
538
539 voe::ChannelOwner channel_owner = _shared->channel_manager().CreateChannel();
540
541 return InitializeChannel(&channel_owner);
542}
543
544int VoEBaseImpl::CreateChannel(const Config& config) {
545 CriticalSectionScoped cs(_shared->crit_sec());
546 if (!_shared->statistics().Initialized()) {
547 _shared->SetLastError(VE_NOT_INITED, kTraceError);
548 return -1;
549 }
550 voe::ChannelOwner channel_owner = _shared->channel_manager().CreateChannel(
551 config);
552 return InitializeChannel(&channel_owner);
553}
554
555int VoEBaseImpl::InitializeChannel(voe::ChannelOwner* channel_owner)
niklase@google.com470e71d2011-07-07 08:21:25 +0000556{
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000557 if (channel_owner->channel()->SetEngineInformation(
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000558 _shared->statistics(),
559 *_shared->output_mixer(),
560 *_shared->transmit_mixer(),
561 *_shared->process_thread(),
562 *_shared->audio_device(),
563 _voiceEngineObserverPtr,
564 &_callbackCritSect) != 0) {
565 _shared->SetLastError(
566 VE_CHANNEL_NOT_CREATED,
567 kTraceError,
568 "CreateChannel() failed to associate engine and channel."
569 " Destroying channel.");
570 _shared->channel_manager()
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000571 .DestroyChannel(channel_owner->channel()->ChannelId());
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000572 return -1;
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000573 } else if (channel_owner->channel()->Init() != 0) {
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000574 _shared->SetLastError(
575 VE_CHANNEL_NOT_CREATED,
576 kTraceError,
577 "CreateChannel() failed to initialize channel. Destroying"
578 " channel.");
579 _shared->channel_manager()
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000580 .DestroyChannel(channel_owner->channel()->ChannelId());
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000581 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000582 }
583
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000584 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
585 VoEId(_shared->instance_id(), -1),
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000586 "CreateChannel() => %d", channel_owner->channel()->ChannelId());
587 return channel_owner->channel()->ChannelId();
niklase@google.com470e71d2011-07-07 08:21:25 +0000588}
589
590int VoEBaseImpl::DeleteChannel(int channel)
591{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000592 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000593 "DeleteChannel(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000594 CriticalSectionScoped cs(_shared->crit_sec());
niklase@google.com470e71d2011-07-07 08:21:25 +0000595
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000596 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000597 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000598 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000599 return -1;
600 }
601
602 {
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000603 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
604 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000605 if (channelPtr == NULL)
606 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000607 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
608 "DeleteChannel() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000609 return -1;
610 }
611 }
612
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000613 _shared->channel_manager().DestroyChannel(channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000614
615 if (StopSend() != 0)
616 {
617 return -1;
618 }
619
620 if (StopPlayout() != 0)
621 {
622 return -1;
623 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +0000624
niklase@google.com470e71d2011-07-07 08:21:25 +0000625 return 0;
626}
627
niklase@google.com470e71d2011-07-07 08:21:25 +0000628int VoEBaseImpl::StartReceive(int channel)
629{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000630 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000631 "StartReceive(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000632 CriticalSectionScoped cs(_shared->crit_sec());
633 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000634 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000635 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000636 return -1;
637 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000638 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
639 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000640 if (channelPtr == NULL)
641 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000642 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
643 "StartReceive() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000644 return -1;
645 }
646 return channelPtr->StartReceiving();
647}
648
649int VoEBaseImpl::StopReceive(int channel)
650{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000651 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000652 "StopListen(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000653 CriticalSectionScoped cs(_shared->crit_sec());
654 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000655 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000656 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000657 return -1;
658 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000659 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
660 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000661 if (channelPtr == NULL)
662 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000663 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
664 "SetLocalReceiver() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000665 return -1;
666 }
667 return channelPtr->StopReceiving();
668}
669
670int VoEBaseImpl::StartPlayout(int channel)
671{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000672 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000673 "StartPlayout(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000674 CriticalSectionScoped cs(_shared->crit_sec());
675 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000676 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000677 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000678 return -1;
679 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000680 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
681 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000682 if (channelPtr == NULL)
683 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000684 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
685 "StartPlayout() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000686 return -1;
687 }
688 if (channelPtr->Playing())
689 {
690 return 0;
691 }
692 if (StartPlayout() != 0)
693 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000694 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
695 "StartPlayout() failed to start playout");
niklase@google.com470e71d2011-07-07 08:21:25 +0000696 return -1;
697 }
698 return channelPtr->StartPlayout();
699}
700
701int VoEBaseImpl::StopPlayout(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 "StopPlayout(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 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000711 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
712 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000713 if (channelPtr == NULL)
714 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000715 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
716 "StopPlayout() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000717 return -1;
718 }
719 if (channelPtr->StopPlayout() != 0)
720 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000721 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
722 VoEId(_shared->instance_id(), -1),
723 "StopPlayout() failed to stop playout for channel %d", channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000724 }
725 return StopPlayout();
726}
727
728int VoEBaseImpl::StartSend(int channel)
729{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000730 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000731 "StartSend(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000732 CriticalSectionScoped cs(_shared->crit_sec());
733 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000734 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000735 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000736 return -1;
737 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000738 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
739 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000740 if (channelPtr == NULL)
741 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000742 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
743 "StartSend() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000744 return -1;
745 }
746 if (channelPtr->Sending())
747 {
748 return 0;
749 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000750 if (StartSend() != 0)
751 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000752 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
753 "StartSend() failed to start recording");
niklase@google.com470e71d2011-07-07 08:21:25 +0000754 return -1;
755 }
756 return channelPtr->StartSend();
757}
758
759int VoEBaseImpl::StopSend(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 "StopSend(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 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000769 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
770 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000771 if (channelPtr == NULL)
772 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000773 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
774 "StopSend() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000775 return -1;
776 }
777 if (channelPtr->StopSend() != 0)
778 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000779 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
780 VoEId(_shared->instance_id(), -1),
781 "StopSend() failed to stop sending for channel %d", channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000782 }
783 return StopSend();
784}
785
786int VoEBaseImpl::GetVersion(char version[1024])
787{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000788 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000789 "GetVersion(version=?)");
790 assert(kVoiceEngineVersionMaxMessageSize == 1024);
791
792 if (version == NULL)
793 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000794 _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000795 return (-1);
796 }
797
798 char versionBuf[kVoiceEngineVersionMaxMessageSize];
799 char* versionPtr = versionBuf;
800
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000801 int32_t len = 0;
802 int32_t accLen = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000803
804 len = AddVoEVersion(versionPtr);
805 if (len == -1)
806 {
807 return -1;
808 }
809 versionPtr += len;
810 accLen += len;
811 assert(accLen < kVoiceEngineVersionMaxMessageSize);
812
813 len = AddBuildInfo(versionPtr);
814 if (len == -1)
815 {
816 return -1;
817 }
818 versionPtr += len;
819 accLen += len;
820 assert(accLen < kVoiceEngineVersionMaxMessageSize);
821
pwestin@webrtc.org684f0572013-03-13 23:20:57 +0000822#ifdef WEBRTC_EXTERNAL_TRANSPORT
823 len = AddExternalTransportBuild(versionPtr);
824 if (len == -1)
825 {
826 return -1;
827 }
828 versionPtr += len;
829 accLen += len;
830 assert(accLen < kVoiceEngineVersionMaxMessageSize);
831#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000832#ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT
833 len = AddExternalRecAndPlayoutBuild(versionPtr);
834 if (len == -1)
835 {
836 return -1;
837 }
838 versionPtr += len;
839 accLen += len;
840 assert(accLen < kVoiceEngineVersionMaxMessageSize);
pwestin@webrtc.orgc450a192012-01-04 15:00:12 +0000841 #endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000842
843 memcpy(version, versionBuf, accLen);
844 version[accLen] = '\0';
845
846 // to avoid the truncation in the trace, split the string into parts
847 char partOfVersion[256];
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000848 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
849 VoEId(_shared->instance_id(), -1), "GetVersion() =>");
niklase@google.com470e71d2011-07-07 08:21:25 +0000850 for (int partStart = 0; partStart < accLen;)
851 {
852 memset(partOfVersion, 0, sizeof(partOfVersion));
853 int partEnd = partStart + 180;
854 while (version[partEnd] != '\n' && version[partEnd] != '\0')
855 {
856 partEnd--;
857 }
858 if (partEnd < accLen)
859 {
860 memcpy(partOfVersion, &version[partStart], partEnd - partStart);
861 }
862 else
863 {
864 memcpy(partOfVersion, &version[partStart], accLen - partStart);
865 }
866 partStart = partEnd;
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000867 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
868 VoEId(_shared->instance_id(), -1), "%s", partOfVersion);
niklase@google.com470e71d2011-07-07 08:21:25 +0000869 }
870
871 return 0;
872}
873
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000874int32_t VoEBaseImpl::AddBuildInfo(char* str) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000875{
andrew@webrtc.org3054ba62013-12-04 17:00:44 +0000876 return sprintf(str, "Build: %s\n", BUILDINFO);
niklase@google.com470e71d2011-07-07 08:21:25 +0000877}
878
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000879int32_t VoEBaseImpl::AddVoEVersion(char* str) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000880{
881 return sprintf(str, "VoiceEngine 4.1.0\n");
882}
883
pwestin@webrtc.org684f0572013-03-13 23:20:57 +0000884#ifdef WEBRTC_EXTERNAL_TRANSPORT
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000885int32_t VoEBaseImpl::AddExternalTransportBuild(char* str) const
pwestin@webrtc.org684f0572013-03-13 23:20:57 +0000886{
887 return sprintf(str, "External transport build\n");
888}
889#endif
890
niklase@google.com470e71d2011-07-07 08:21:25 +0000891#ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000892int32_t VoEBaseImpl::AddExternalRecAndPlayoutBuild(char* str) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000893{
894 return sprintf(str, "External recording and playout build\n");
895}
896#endif
897
niklase@google.com470e71d2011-07-07 08:21:25 +0000898int VoEBaseImpl::LastError()
899{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000900 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000901 "LastError()");
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000902 return (_shared->statistics().LastError());
niklase@google.com470e71d2011-07-07 08:21:25 +0000903}
904
905
906int VoEBaseImpl::SetNetEQPlayoutMode(int channel, NetEqModes mode)
907{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000908 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000909 "SetNetEQPlayoutMode(channel=%i, mode=%i)", channel, mode);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000910 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000911 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000912 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000913 return -1;
914 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000915 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
916 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000917 if (channelPtr == NULL)
918 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000919 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
920 "SetNetEQPlayoutMode() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000921 return -1;
922 }
923 return channelPtr->SetNetEQPlayoutMode(mode);
924}
925
926int VoEBaseImpl::GetNetEQPlayoutMode(int channel, NetEqModes& mode)
927{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000928 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000929 "GetNetEQPlayoutMode(channel=%i, mode=?)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000930 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000931 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000932 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000933 return -1;
934 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000935 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
936 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000937 if (channelPtr == NULL)
938 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000939 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
940 "GetNetEQPlayoutMode() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000941 return -1;
942 }
943 return channelPtr->GetNetEQPlayoutMode(mode);
944}
945
niklase@google.com470e71d2011-07-07 08:21:25 +0000946int VoEBaseImpl::SetOnHoldStatus(int channel, bool enable, OnHoldModes mode)
947{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000948 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000949 "SetOnHoldStatus(channel=%d, enable=%d, mode=%d)", channel,
950 enable, mode);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000951 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000952 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000953 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000954 return -1;
955 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000956 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
957 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000958 if (channelPtr == NULL)
959 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000960 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
961 "SetOnHoldStatus() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000962 return -1;
963 }
964 return channelPtr->SetOnHoldStatus(enable, mode);
965}
966
967int VoEBaseImpl::GetOnHoldStatus(int channel, bool& enabled, OnHoldModes& mode)
968{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000969 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000970 "GetOnHoldStatus(channel=%d, enabled=?, mode=?)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000971 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000972 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000973 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000974 return -1;
975 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000976 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
977 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000978 if (channelPtr == NULL)
979 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000980 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
981 "GetOnHoldStatus() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000982 return -1;
983 }
984 return channelPtr->GetOnHoldStatus(enabled, mode);
985}
986
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000987int32_t VoEBaseImpl::StartPlayout()
niklase@google.com470e71d2011-07-07 08:21:25 +0000988{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000989 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000990 "VoEBaseImpl::StartPlayout()");
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000991 if (_shared->audio_device()->Playing())
niklase@google.com470e71d2011-07-07 08:21:25 +0000992 {
993 return 0;
994 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000995 if (!_shared->ext_playout())
niklase@google.com470e71d2011-07-07 08:21:25 +0000996 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000997 if (_shared->audio_device()->InitPlayout() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000998 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000999 WEBRTC_TRACE(kTraceError, kTraceVoice,
1000 VoEId(_shared->instance_id(), -1),
1001 "StartPlayout() failed to initialize playout");
niklase@google.com470e71d2011-07-07 08:21:25 +00001002 return -1;
1003 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001004 if (_shared->audio_device()->StartPlayout() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001005 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001006 WEBRTC_TRACE(kTraceError, kTraceVoice,
1007 VoEId(_shared->instance_id(), -1),
1008 "StartPlayout() failed to start playout");
niklase@google.com470e71d2011-07-07 08:21:25 +00001009 return -1;
1010 }
1011 }
1012 return 0;
1013}
1014
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +00001015int32_t VoEBaseImpl::StopPlayout() {
1016 WEBRTC_TRACE(kTraceInfo,
1017 kTraceVoice,
1018 VoEId(_shared->instance_id(), -1),
1019 "VoEBaseImpl::StopPlayout()");
1020 // Stop audio-device playing if no channel is playing out
xians@webrtc.org675e2602013-10-17 16:15:34 +00001021 if (_shared->NumOfPlayingChannels() == 0) {
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +00001022 if (_shared->audio_device()->StopPlayout() != 0) {
1023 _shared->SetLastError(VE_CANNOT_STOP_PLAYOUT,
1024 kTraceError,
1025 "StopPlayout() failed to stop playout");
1026 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001027 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +00001028 }
1029 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001030}
1031
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001032int32_t VoEBaseImpl::StartSend()
niklase@google.com470e71d2011-07-07 08:21:25 +00001033{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001034 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001035 "VoEBaseImpl::StartSend()");
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001036 if (_shared->audio_device()->Recording())
niklase@google.com470e71d2011-07-07 08:21:25 +00001037 {
1038 return 0;
1039 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001040 if (!_shared->ext_recording())
niklase@google.com470e71d2011-07-07 08:21:25 +00001041 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001042 if (_shared->audio_device()->InitRecording() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001043 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001044 WEBRTC_TRACE(kTraceError, kTraceVoice,
1045 VoEId(_shared->instance_id(), -1),
1046 "StartSend() failed to initialize recording");
niklase@google.com470e71d2011-07-07 08:21:25 +00001047 return -1;
1048 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001049 if (_shared->audio_device()->StartRecording() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001050 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001051 WEBRTC_TRACE(kTraceError, kTraceVoice,
1052 VoEId(_shared->instance_id(), -1),
1053 "StartSend() failed to start recording");
niklase@google.com470e71d2011-07-07 08:21:25 +00001054 return -1;
1055 }
1056 }
1057
1058 return 0;
1059}
1060
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001061int32_t VoEBaseImpl::StopSend()
niklase@google.com470e71d2011-07-07 08:21:25 +00001062{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001063 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001064 "VoEBaseImpl::StopSend()");
1065
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001066 if (_shared->NumOfSendingChannels() == 0 &&
1067 !_shared->transmit_mixer()->IsRecordingMic())
niklase@google.com470e71d2011-07-07 08:21:25 +00001068 {
1069 // Stop audio-device recording if no channel is recording
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001070 if (_shared->audio_device()->StopRecording() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001071 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001072 _shared->SetLastError(VE_CANNOT_STOP_RECORDING, kTraceError,
1073 "StopSend() failed to stop recording");
niklase@google.com470e71d2011-07-07 08:21:25 +00001074 return -1;
1075 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001076 _shared->transmit_mixer()->StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +00001077 }
1078
1079 return 0;
1080}
1081
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001082int32_t VoEBaseImpl::TerminateInternal()
niklase@google.com470e71d2011-07-07 08:21:25 +00001083{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001084 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001085 "VoEBaseImpl::TerminateInternal()");
1086
1087 // Delete any remaining channel objects
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +00001088 _shared->channel_manager().DestroyAllChannels();
niklase@google.com470e71d2011-07-07 08:21:25 +00001089
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001090 if (_shared->process_thread())
niklase@google.com470e71d2011-07-07 08:21:25 +00001091 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001092 if (_shared->audio_device())
niklase@google.com470e71d2011-07-07 08:21:25 +00001093 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001094 if (_shared->process_thread()->
1095 DeRegisterModule(_shared->audio_device()) != 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 deregister ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +00001099 }
1100 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001101 if (_shared->process_thread()->Stop() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001102 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001103 _shared->SetLastError(VE_THREAD_ERROR, kTraceError,
1104 "TerminateInternal() failed to stop module process thread");
niklase@google.com470e71d2011-07-07 08:21:25 +00001105 }
1106 }
1107
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +00001108 if (_shared->audio_device())
niklase@google.com470e71d2011-07-07 08:21:25 +00001109 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001110 if (_shared->audio_device()->StopPlayout() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001111 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001112 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
1113 "TerminateInternal() failed to stop playout");
niklase@google.com470e71d2011-07-07 08:21:25 +00001114 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001115 if (_shared->audio_device()->StopRecording() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001116 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001117 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
1118 "TerminateInternal() failed to stop recording");
niklase@google.com470e71d2011-07-07 08:21:25 +00001119 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001120 if (_shared->audio_device()->RegisterEventObserver(NULL) != 0) {
1121 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
1122 "TerminateInternal() failed to de-register event observer "
1123 "for the ADM");
xians@webrtc.org79af7342012-01-31 12:22:14 +00001124 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001125 if (_shared->audio_device()->RegisterAudioCallback(NULL) != 0) {
1126 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
1127 "TerminateInternal() failed to de-register audio callback "
1128 "for the ADM");
xians@webrtc.org79af7342012-01-31 12:22:14 +00001129 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001130 if (_shared->audio_device()->Terminate() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001131 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001132 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
1133 "TerminateInternal() failed to terminate the ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +00001134 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001135 _shared->set_audio_device(NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +00001136 }
1137
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +00001138 if (_shared->audio_processing()) {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001139 _shared->set_audio_processing(NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +00001140 }
1141
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001142 return _shared->statistics().SetUnInitialized();
niklase@google.com470e71d2011-07-07 08:21:25 +00001143}
1144
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00001145int VoEBaseImpl::ProcessRecordedDataWithAPM(
1146 const int voe_channels[],
1147 int number_of_voe_channels,
1148 const void* audio_data,
1149 uint32_t sample_rate,
1150 uint8_t number_of_channels,
1151 uint32_t number_of_frames,
1152 uint32_t audio_delay_milliseconds,
1153 int32_t clock_drift,
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001154 uint32_t volume,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00001155 bool key_pressed) {
1156 assert(_shared->transmit_mixer() != NULL);
1157 assert(_shared->audio_device() != NULL);
1158
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00001159 uint32_t max_volume = 0;
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001160 uint16_t voe_mic_level = 0;
andrew@webrtc.org023cc5a2014-01-11 01:25:53 +00001161 // Check for zero to skip this calculation; the consumer may use this to
1162 // indicate no volume is available.
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001163 if (volume != 0) {
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00001164 // Scale from ADM to VoE level range
1165 if (_shared->audio_device()->MaxMicrophoneVolume(&max_volume) == 0) {
1166 if (max_volume) {
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001167 voe_mic_level = static_cast<uint16_t>(
1168 (volume * kMaxVolumeLevel +
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00001169 static_cast<int>(max_volume / 2)) / max_volume);
1170 }
1171 }
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001172 // We learned that on certain systems (e.g Linux) the voe_mic_level
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00001173 // can be greater than the maxVolumeLevel therefore
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001174 // we are going to cap the voe_mic_level to the maxVolumeLevel
1175 // and change the maxVolume to volume if it turns out that
1176 // the voe_mic_level is indeed greater than the maxVolumeLevel.
1177 if (voe_mic_level > kMaxVolumeLevel) {
1178 voe_mic_level = kMaxVolumeLevel;
1179 max_volume = volume;
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00001180 }
1181 }
1182
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00001183 // Perform channel-independent operations
1184 // (APM, mix with file, record to file, mute, etc.)
1185 _shared->transmit_mixer()->PrepareDemux(
1186 audio_data, number_of_frames, number_of_channels, sample_rate,
1187 static_cast<uint16_t>(audio_delay_milliseconds), clock_drift,
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001188 voe_mic_level, key_pressed);
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00001189
1190 // Copy the audio frame to each sending channel and perform
1191 // channel-dependent operations (file mixing, mute, etc.), encode and
1192 // packetize+transmit the RTP packet. When |number_of_voe_channels| == 0,
1193 // do the operations on all the existing VoE channels; otherwise the
1194 // operations will be done on specific channels.
1195 if (number_of_voe_channels == 0) {
1196 _shared->transmit_mixer()->DemuxAndMix();
1197 _shared->transmit_mixer()->EncodeAndSend();
1198 } else {
1199 _shared->transmit_mixer()->DemuxAndMix(voe_channels,
1200 number_of_voe_channels);
1201 _shared->transmit_mixer()->EncodeAndSend(voe_channels,
1202 number_of_voe_channels);
1203 }
1204
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00001205 // Scale from VoE to ADM level range.
1206 uint32_t new_voe_mic_level = _shared->transmit_mixer()->CaptureLevel();
1207
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001208 if (new_voe_mic_level != voe_mic_level) {
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00001209 // Return the new volume if AGC has changed the volume.
1210 return static_cast<int>(
1211 (new_voe_mic_level * max_volume +
1212 static_cast<int>(kMaxVolumeLevel / 2)) / kMaxVolumeLevel);
1213 }
1214
1215 // Return 0 to indicate no change on the volume.
1216 return 0;
1217}
1218
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00001219} // namespace webrtc