blob: 1b6e14491e768951131b4ab264165ea17f8fe14e [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
niklase@google.com470e71d2011-07-07 08:21:25 +000028namespace webrtc
29{
30
31VoEBase* VoEBase::GetInterface(VoiceEngine* voiceEngine)
32{
33 if (NULL == voiceEngine)
34 {
35 return NULL;
36 }
tommi@webrtc.org0989fb72013-02-15 15:07:32 +000037 VoiceEngineImpl* s = static_cast<VoiceEngineImpl*>(voiceEngine);
tommi@webrtc.orga990e122012-04-26 15:28:22 +000038 s->AddRef();
39 return s;
niklase@google.com470e71d2011-07-07 08:21:25 +000040}
41
tommi@webrtc.org851becd2012-04-04 14:57:19 +000042VoEBaseImpl::VoEBaseImpl(voe::SharedData* shared) :
niklase@google.com470e71d2011-07-07 08:21:25 +000043 _voiceEngineObserverPtr(NULL),
44 _callbackCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
andrew@webrtc.org27c69802014-02-18 20:24:56 +000045 _voiceEngineObserver(false), _shared(shared)
niklase@google.com470e71d2011-07-07 08:21:25 +000046{
tommi@webrtc.org851becd2012-04-04 14:57:19 +000047 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +000048 "VoEBaseImpl() - ctor");
49}
50
51VoEBaseImpl::~VoEBaseImpl()
52{
tommi@webrtc.org851becd2012-04-04 14:57:19 +000053 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +000054 "~VoEBaseImpl() - dtor");
55
56 TerminateInternal();
57
58 delete &_callbackCritSect;
59}
60
pbos@webrtc.org92135212013-05-14 08:31:39 +000061void VoEBaseImpl::OnErrorIsReported(ErrorCode error)
niklase@google.com470e71d2011-07-07 08:21:25 +000062{
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +000063 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +000064 if (_voiceEngineObserver)
65 {
66 if (_voiceEngineObserverPtr)
67 {
68 int errCode(0);
69 if (error == AudioDeviceObserver::kRecordingError)
70 {
71 errCode = VE_RUNTIME_REC_ERROR;
tommi@webrtc.org851becd2012-04-04 14:57:19 +000072 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
73 VoEId(_shared->instance_id(), -1),
74 "VoEBaseImpl::OnErrorIsReported() => VE_RUNTIME_REC_ERROR");
niklase@google.com470e71d2011-07-07 08:21:25 +000075 }
76 else if (error == AudioDeviceObserver::kPlayoutError)
77 {
78 errCode = VE_RUNTIME_PLAY_ERROR;
tommi@webrtc.org851becd2012-04-04 14:57:19 +000079 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
80 VoEId(_shared->instance_id(), -1),
81 "VoEBaseImpl::OnErrorIsReported() => "
82 "VE_RUNTIME_PLAY_ERROR");
niklase@google.com470e71d2011-07-07 08:21:25 +000083 }
84 // Deliver callback (-1 <=> no channel dependency)
85 _voiceEngineObserverPtr->CallbackOnError(-1, errCode);
86 }
87 }
88}
89
pbos@webrtc.org92135212013-05-14 08:31:39 +000090void VoEBaseImpl::OnWarningIsReported(WarningCode warning)
niklase@google.com470e71d2011-07-07 08:21:25 +000091{
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +000092 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +000093 if (_voiceEngineObserver)
94 {
95 if (_voiceEngineObserverPtr)
96 {
97 int warningCode(0);
98 if (warning == AudioDeviceObserver::kRecordingWarning)
99 {
100 warningCode = VE_RUNTIME_REC_WARNING;
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000101 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
102 VoEId(_shared->instance_id(), -1),
103 "VoEBaseImpl::OnErrorIsReported() => "
104 "VE_RUNTIME_REC_WARNING");
niklase@google.com470e71d2011-07-07 08:21:25 +0000105 }
106 else if (warning == AudioDeviceObserver::kPlayoutWarning)
107 {
108 warningCode = VE_RUNTIME_PLAY_WARNING;
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000109 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
110 VoEId(_shared->instance_id(), -1),
111 "VoEBaseImpl::OnErrorIsReported() => "
112 "VE_RUNTIME_PLAY_WARNING");
niklase@google.com470e71d2011-07-07 08:21:25 +0000113 }
114 // Deliver callback (-1 <=> no channel dependency)
115 _voiceEngineObserverPtr->CallbackOnError(-1, warningCode);
116 }
117 }
118}
119
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000120int32_t VoEBaseImpl::RecordedDataIsAvailable(
henrika@webrtc.org907bc552012-03-09 08:59:19 +0000121 const void* audioSamples,
pbos@webrtc.org92135212013-05-14 08:31:39 +0000122 uint32_t nSamples,
123 uint8_t nBytesPerSample,
124 uint8_t nChannels,
125 uint32_t samplesPerSec,
126 uint32_t totalDelayMS,
127 int32_t clockDrift,
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000128 uint32_t micLevel,
pbos@webrtc.org92135212013-05-14 08:31:39 +0000129 bool keyPressed,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000130 uint32_t& newMicLevel)
niklase@google.com470e71d2011-07-07 08:21:25 +0000131{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000132 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000133 "VoEBaseImpl::RecordedDataIsAvailable(nSamples=%u, "
134 "nBytesPerSample=%u, nChannels=%u, samplesPerSec=%u, "
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000135 "totalDelayMS=%u, clockDrift=%d, micLevel=%u)",
niklase@google.com470e71d2011-07-07 08:21:25 +0000136 nSamples, nBytesPerSample, nChannels, samplesPerSec,
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000137 totalDelayMS, clockDrift, micLevel);
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000138 newMicLevel = static_cast<uint32_t>(ProcessRecordedDataWithAPM(
139 NULL, 0, audioSamples, samplesPerSec, nChannels, nSamples,
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000140 totalDelayMS, clockDrift, micLevel, keyPressed));
niklase@google.com470e71d2011-07-07 08:21:25 +0000141
142 return 0;
143}
144
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000145int32_t VoEBaseImpl::NeedMorePlayData(
pbos@webrtc.org92135212013-05-14 08:31:39 +0000146 uint32_t nSamples,
147 uint8_t nBytesPerSample,
148 uint8_t nChannels,
149 uint32_t samplesPerSec,
henrika@webrtc.org907bc552012-03-09 08:59:19 +0000150 void* audioSamples,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000151 uint32_t& nSamplesOut)
niklase@google.com470e71d2011-07-07 08:21:25 +0000152{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000153 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000154 "VoEBaseImpl::NeedMorePlayData(nSamples=%u, "
155 "nBytesPerSample=%d, nChannels=%d, samplesPerSec=%u)",
156 nSamples, nBytesPerSample, nChannels, samplesPerSec);
157
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000158 assert(_shared->output_mixer() != NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000159
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +0000160 // TODO(andrew): if the device is running in mono, we should tell the mixer
161 // here so that it will only request mono from AudioCodingModule.
niklase@google.com470e71d2011-07-07 08:21:25 +0000162 // Perform mixing of all active participants (channel-based mixing)
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000163 _shared->output_mixer()->MixActiveChannels();
niklase@google.com470e71d2011-07-07 08:21:25 +0000164
165 // Additional operations on the combined signal
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000166 _shared->output_mixer()->DoOperationsOnCombinedSignal();
niklase@google.com470e71d2011-07-07 08:21:25 +0000167
168 // Retrieve the final output mix (resampled to match the ADM)
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000169 _shared->output_mixer()->GetMixedAudio(samplesPerSec, nChannels,
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +0000170 &_audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000171
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +0000172 assert(static_cast<int>(nSamples) == _audioFrame.samples_per_channel_);
xians@google.com0b0665a2011-08-08 08:18:44 +0000173 assert(samplesPerSec ==
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000174 static_cast<uint32_t>(_audioFrame.sample_rate_hz_));
niklase@google.com470e71d2011-07-07 08:21:25 +0000175
176 // Deliver audio (PCM) samples to the ADM
177 memcpy(
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000178 (int16_t*) audioSamples,
179 (const int16_t*) _audioFrame.data_,
180 sizeof(int16_t) * (_audioFrame.samples_per_channel_
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000181 * _audioFrame.num_channels_));
niklase@google.com470e71d2011-07-07 08:21:25 +0000182
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000183 nSamplesOut = _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000184
185 return 0;
186}
187
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000188int VoEBaseImpl::OnDataAvailable(const int voe_channels[],
xians@webrtc.org2f84afa2013-07-31 16:23:37 +0000189 int number_of_voe_channels,
190 const int16_t* audio_data,
191 int sample_rate,
192 int number_of_channels,
193 int number_of_frames,
194 int audio_delay_milliseconds,
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000195 int volume,
xians@webrtc.org2f84afa2013-07-31 16:23:37 +0000196 bool key_pressed,
197 bool need_audio_processing) {
198 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_shared->instance_id(), -1),
199 "VoEBaseImpl::OnDataAvailable(number_of_voe_channels=%d, "
200 "sample_rate=%d, number_of_channels=%d, number_of_frames=%d, "
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000201 "audio_delay_milliseconds=%d, volume=%d, "
xians@webrtc.org2f84afa2013-07-31 16:23:37 +0000202 "key_pressed=%d, need_audio_processing=%d)",
203 number_of_voe_channels, sample_rate, number_of_channels,
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000204 number_of_frames, audio_delay_milliseconds, volume,
xians@webrtc.org2f84afa2013-07-31 16:23:37 +0000205 key_pressed, need_audio_processing);
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000206 if (number_of_voe_channels == 0)
207 return 0;
xians@webrtc.org2f84afa2013-07-31 16:23:37 +0000208
209 if (need_audio_processing) {
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000210 return ProcessRecordedDataWithAPM(
211 voe_channels, number_of_voe_channels, audio_data, sample_rate,
212 number_of_channels, number_of_frames, audio_delay_milliseconds,
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000213 0, volume, key_pressed);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +0000214 }
215
216 // No need to go through the APM, demultiplex the data to each VoE channel,
217 // encode and send to the network.
218 for (int i = 0; i < number_of_voe_channels; ++i) {
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000219 // TODO(ajm): In the case where multiple channels are using the same codec
220 // rate, this path needlessly does extra conversions. We should convert once
221 // and share between channels.
xians@webrtc.orgc1e28032014-02-02 15:30:20 +0000222 OnData(voe_channels[i], audio_data, 16, sample_rate,
223 number_of_channels, number_of_frames);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +0000224 }
225
226 // Return 0 to indicate no need to change the volume.
227 return 0;
228}
229
xians@webrtc.orgc1e28032014-02-02 15:30:20 +0000230void VoEBaseImpl::OnData(int voe_channel, const void* audio_data,
231 int bits_per_sample, int sample_rate,
232 int number_of_channels,
233 int number_of_frames) {
xians@webrtc.org07e51962014-01-29 13:54:02 +0000234 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(voe_channel);
235 voe::Channel* channel_ptr = ch.channel();
236 if (!channel_ptr)
237 return;
238
239 if (channel_ptr->InputIsOnHold()) {
240 channel_ptr->UpdateLocalTimeStamp();
241 } else if (channel_ptr->Sending()) {
242 channel_ptr->Demultiplex(static_cast<const int16_t*>(audio_data),
243 sample_rate, number_of_frames, number_of_channels);
244 channel_ptr->PrepareEncodeAndSend(sample_rate);
245 channel_ptr->EncodeAndSend();
246 }
247}
248
niklase@google.com470e71d2011-07-07 08:21:25 +0000249int VoEBaseImpl::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
250{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000251 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000252 "RegisterVoiceEngineObserver(observer=0x%d)", &observer);
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000253 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000254 if (_voiceEngineObserverPtr)
255 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000256 _shared->SetLastError(VE_INVALID_OPERATION, kTraceError,
257 "RegisterVoiceEngineObserver() observer already enabled");
niklase@google.com470e71d2011-07-07 08:21:25 +0000258 return -1;
259 }
260
261 // Register the observer in all active channels
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000262 for (voe::ChannelManager::Iterator it(&_shared->channel_manager());
263 it.IsValid();
264 it.Increment()) {
265 it.GetChannel()->RegisterVoiceEngineObserver(observer);
niklase@google.com470e71d2011-07-07 08:21:25 +0000266 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000267
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000268 _shared->transmit_mixer()->RegisterVoiceEngineObserver(observer);
niklase@google.com470e71d2011-07-07 08:21:25 +0000269
270 _voiceEngineObserverPtr = &observer;
271 _voiceEngineObserver = true;
272
273 return 0;
274}
275
276int VoEBaseImpl::DeRegisterVoiceEngineObserver()
277{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000278 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000279 "DeRegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000280 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000281 if (!_voiceEngineObserverPtr)
282 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000283 _shared->SetLastError(VE_INVALID_OPERATION, kTraceError,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000284 "DeRegisterVoiceEngineObserver() observer already disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +0000285 return 0;
286 }
287
288 _voiceEngineObserver = false;
289 _voiceEngineObserverPtr = NULL;
290
291 // Deregister the observer in all active channels
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000292 for (voe::ChannelManager::Iterator it(&_shared->channel_manager());
293 it.IsValid();
294 it.Increment()) {
295 it.GetChannel()->DeRegisterVoiceEngineObserver();
niklase@google.com470e71d2011-07-07 08:21:25 +0000296 }
297
298 return 0;
299}
300
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000301int VoEBaseImpl::Init(AudioDeviceModule* external_adm,
302 AudioProcessing* audioproc)
niklase@google.com470e71d2011-07-07 08:21:25 +0000303{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000304 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
henrika@google.com73d65512011-09-07 15:11:18 +0000305 "Init(external_adm=0x%p)", external_adm);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000306 CriticalSectionScoped cs(_shared->crit_sec());
niklase@google.com470e71d2011-07-07 08:21:25 +0000307
kma@webrtc.org0221b782012-09-08 00:09:26 +0000308 WebRtcSpl_Init();
309
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000310 if (_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000311 {
312 return 0;
313 }
314
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000315 if (_shared->process_thread())
niklase@google.com470e71d2011-07-07 08:21:25 +0000316 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000317 if (_shared->process_thread()->Start() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000318 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000319 _shared->SetLastError(VE_THREAD_ERROR, kTraceError,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000320 "Init() failed to start module process thread");
niklase@google.com470e71d2011-07-07 08:21:25 +0000321 return -1;
322 }
323 }
324
andrew@webrtc.org3192d652011-12-21 18:00:59 +0000325 // Create an internal ADM if the user has not added an external
henrika@google.com73d65512011-09-07 15:11:18 +0000326 // ADM implementation as input to Init().
327 if (external_adm == NULL)
niklase@google.com470e71d2011-07-07 08:21:25 +0000328 {
henrika@google.com73d65512011-09-07 15:11:18 +0000329 // Create the internal ADM implementation.
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000330 _shared->set_audio_device(AudioDeviceModuleImpl::Create(
331 VoEId(_shared->instance_id(), -1), _shared->audio_device_layer()));
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000332
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000333 if (_shared->audio_device() == NULL)
niklase@google.com470e71d2011-07-07 08:21:25 +0000334 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000335 _shared->SetLastError(VE_NO_MEMORY, kTraceCritical,
336 "Init() failed to create the ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +0000337 return -1;
338 }
339 }
henrika@google.com73d65512011-09-07 15:11:18 +0000340 else
341 {
342 // Use the already existing external ADM implementation.
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000343 _shared->set_audio_device(external_adm);
344 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
henrika@google.com73d65512011-09-07 15:11:18 +0000345 "An external ADM implementation will be used in VoiceEngine");
346 }
347
niklase@google.com470e71d2011-07-07 08:21:25 +0000348 // Register the ADM to the process thread, which will drive the error
349 // callback mechanism
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000350 if (_shared->process_thread() &&
351 _shared->process_thread()->RegisterModule(_shared->audio_device()) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000352 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000353 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
354 "Init() failed to register the ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +0000355 return -1;
356 }
357
358 bool available(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000359
360 // --------------------
361 // Reinitialize the ADM
362
363 // Register the AudioObserver implementation
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000364 if (_shared->audio_device()->RegisterEventObserver(this) != 0) {
365 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
366 "Init() failed to register event observer for the ADM");
xians@webrtc.org79af7342012-01-31 12:22:14 +0000367 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000368
369 // Register the AudioTransport implementation
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000370 if (_shared->audio_device()->RegisterAudioCallback(this) != 0) {
371 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
372 "Init() failed to register audio callback for the ADM");
xians@webrtc.org79af7342012-01-31 12:22:14 +0000373 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000374
375 // ADM initialization
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000376 if (_shared->audio_device()->Init() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000377 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000378 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
379 "Init() failed to initialize the ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +0000380 return -1;
381 }
382
383 // Initialize the default speaker
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000384 if (_shared->audio_device()->SetPlayoutDevice(
385 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000386 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000387 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000388 "Init() failed to set the default output device");
niklase@google.com470e71d2011-07-07 08:21:25 +0000389 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000390 if (_shared->audio_device()->InitSpeaker() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000391 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000392 _shared->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000393 "Init() failed to initialize the speaker");
niklase@google.com470e71d2011-07-07 08:21:25 +0000394 }
395
396 // Initialize the default microphone
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000397 if (_shared->audio_device()->SetRecordingDevice(
398 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000399 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000400 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000401 "Init() failed to set the default input device");
niklase@google.com470e71d2011-07-07 08:21:25 +0000402 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000403 if (_shared->audio_device()->InitMicrophone() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000404 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000405 _shared->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000406 "Init() failed to initialize the microphone");
niklase@google.com470e71d2011-07-07 08:21:25 +0000407 }
408
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000409 // Set number of channels
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000410 if (_shared->audio_device()->StereoPlayoutIsAvailable(&available) != 0) {
411 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
412 "Init() failed to query stereo playout mode");
xians@webrtc.org79af7342012-01-31 12:22:14 +0000413 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000414 if (_shared->audio_device()->SetStereoPlayout(available) != 0)
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000415 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000416 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000417 "Init() failed to set mono/stereo playout mode");
418 }
andrew@webrtc.org3192d652011-12-21 18:00:59 +0000419
420 // TODO(andrew): These functions don't tell us whether stereo recording
421 // is truly available. We simply set the AudioProcessing input to stereo
422 // here, because we have to wait until receiving the first frame to
423 // determine the actual number of channels anyway.
424 //
425 // These functions may be changed; tracked here:
426 // http://code.google.com/p/webrtc/issues/detail?id=204
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000427 _shared->audio_device()->StereoRecordingIsAvailable(&available);
428 if (_shared->audio_device()->SetStereoRecording(available) != 0)
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000429 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000430 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000431 "Init() failed to set mono/stereo recording mode");
432 }
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000433
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000434 if (!audioproc) {
435 audioproc = AudioProcessing::Create(VoEId(_shared->instance_id(), -1));
436 if (!audioproc) {
437 LOG(LS_ERROR) << "Failed to create AudioProcessing.";
438 _shared->SetLastError(VE_NO_MEMORY);
439 return -1;
440 }
441 }
442 _shared->set_audio_processing(audioproc);
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000443
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000444 // Set the error state for any failures in this block.
445 _shared->SetLastError(VE_APM_ERROR);
446 if (audioproc->echo_cancellation()->set_device_sample_rate_hz(48000)) {
447 LOG_FERR1(LS_ERROR, set_device_sample_rate_hz, 48000);
448 return -1;
449 }
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000450
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +0000451 // Configure AudioProcessing components.
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000452 if (audioproc->high_pass_filter()->Enable(true) != 0) {
453 LOG_FERR1(LS_ERROR, high_pass_filter()->Enable, true);
454 return -1;
455 }
456 if (audioproc->echo_cancellation()->enable_drift_compensation(false) != 0) {
457 LOG_FERR1(LS_ERROR, enable_drift_compensation, false);
458 return -1;
459 }
460 if (audioproc->noise_suppression()->set_level(kDefaultNsMode) != 0) {
461 LOG_FERR1(LS_ERROR, noise_suppression()->set_level, kDefaultNsMode);
462 return -1;
463 }
464 GainControl* agc = audioproc->gain_control();
465 if (agc->set_analog_level_limits(kMinVolumeLevel, kMaxVolumeLevel) != 0) {
466 LOG_FERR2(LS_ERROR, agc->set_analog_level_limits, kMinVolumeLevel,
467 kMaxVolumeLevel);
468 return -1;
469 }
470 if (agc->set_mode(kDefaultAgcMode) != 0) {
471 LOG_FERR1(LS_ERROR, agc->set_mode, kDefaultAgcMode);
472 return -1;
473 }
474 if (agc->Enable(kDefaultAgcState) != 0) {
475 LOG_FERR1(LS_ERROR, agc->Enable, kDefaultAgcState);
476 return -1;
477 }
478 _shared->SetLastError(0); // Clear error state.
479
niklase@google.com470e71d2011-07-07 08:21:25 +0000480#ifdef WEBRTC_VOICE_ENGINE_AGC
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000481 bool agc_enabled = agc->mode() == GainControl::kAdaptiveAnalog &&
482 agc->is_enabled();
483 if (_shared->audio_device()->SetAGC(agc_enabled) != 0) {
484 LOG_FERR1(LS_ERROR, audio_device()->SetAGC, agc_enabled);
485 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR);
andrew@webrtc.orga9a1df02013-03-05 23:36:10 +0000486 // TODO(ajm): No error return here due to
487 // https://code.google.com/p/webrtc/issues/detail?id=1464
niklase@google.com470e71d2011-07-07 08:21:25 +0000488 }
489#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000490
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000491 return _shared->statistics().SetInitialized();
niklase@google.com470e71d2011-07-07 08:21:25 +0000492}
493
494int VoEBaseImpl::Terminate()
495{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000496 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000497 "Terminate()");
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000498 CriticalSectionScoped cs(_shared->crit_sec());
niklase@google.com470e71d2011-07-07 08:21:25 +0000499 return TerminateInternal();
500}
501
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000502int VoEBaseImpl::CreateChannel() {
503 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
504 "CreateChannel()");
505 CriticalSectionScoped cs(_shared->crit_sec());
506 if (!_shared->statistics().Initialized()) {
507 _shared->SetLastError(VE_NOT_INITED, kTraceError);
508 return -1;
509 }
510
511 voe::ChannelOwner channel_owner = _shared->channel_manager().CreateChannel();
512
513 return InitializeChannel(&channel_owner);
514}
515
516int VoEBaseImpl::CreateChannel(const Config& config) {
517 CriticalSectionScoped cs(_shared->crit_sec());
518 if (!_shared->statistics().Initialized()) {
519 _shared->SetLastError(VE_NOT_INITED, kTraceError);
520 return -1;
521 }
522 voe::ChannelOwner channel_owner = _shared->channel_manager().CreateChannel(
523 config);
524 return InitializeChannel(&channel_owner);
525}
526
527int VoEBaseImpl::InitializeChannel(voe::ChannelOwner* channel_owner)
niklase@google.com470e71d2011-07-07 08:21:25 +0000528{
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000529 if (channel_owner->channel()->SetEngineInformation(
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000530 _shared->statistics(),
531 *_shared->output_mixer(),
532 *_shared->transmit_mixer(),
533 *_shared->process_thread(),
534 *_shared->audio_device(),
535 _voiceEngineObserverPtr,
536 &_callbackCritSect) != 0) {
537 _shared->SetLastError(
538 VE_CHANNEL_NOT_CREATED,
539 kTraceError,
540 "CreateChannel() failed to associate engine and channel."
541 " Destroying channel.");
542 _shared->channel_manager()
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000543 .DestroyChannel(channel_owner->channel()->ChannelId());
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000544 return -1;
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000545 } else if (channel_owner->channel()->Init() != 0) {
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000546 _shared->SetLastError(
547 VE_CHANNEL_NOT_CREATED,
548 kTraceError,
549 "CreateChannel() failed to initialize channel. Destroying"
550 " channel.");
551 _shared->channel_manager()
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000552 .DestroyChannel(channel_owner->channel()->ChannelId());
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000553 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000554 }
555
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000556 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
557 VoEId(_shared->instance_id(), -1),
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000558 "CreateChannel() => %d", channel_owner->channel()->ChannelId());
559 return channel_owner->channel()->ChannelId();
niklase@google.com470e71d2011-07-07 08:21:25 +0000560}
561
562int VoEBaseImpl::DeleteChannel(int channel)
563{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000564 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000565 "DeleteChannel(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000566 CriticalSectionScoped cs(_shared->crit_sec());
niklase@google.com470e71d2011-07-07 08:21:25 +0000567
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000568 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000569 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000570 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000571 return -1;
572 }
573
574 {
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000575 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
576 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000577 if (channelPtr == NULL)
578 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000579 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
580 "DeleteChannel() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000581 return -1;
582 }
583 }
584
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000585 _shared->channel_manager().DestroyChannel(channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000586
587 if (StopSend() != 0)
588 {
589 return -1;
590 }
591
592 if (StopPlayout() != 0)
593 {
594 return -1;
595 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +0000596
niklase@google.com470e71d2011-07-07 08:21:25 +0000597 return 0;
598}
599
niklase@google.com470e71d2011-07-07 08:21:25 +0000600int VoEBaseImpl::StartReceive(int channel)
601{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000602 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000603 "StartReceive(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000604 CriticalSectionScoped cs(_shared->crit_sec());
605 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000606 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000607 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000608 return -1;
609 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000610 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
611 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000612 if (channelPtr == NULL)
613 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000614 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
615 "StartReceive() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000616 return -1;
617 }
618 return channelPtr->StartReceiving();
619}
620
621int VoEBaseImpl::StopReceive(int channel)
622{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000623 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000624 "StopListen(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000625 CriticalSectionScoped cs(_shared->crit_sec());
626 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000627 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000628 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000629 return -1;
630 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000631 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
632 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000633 if (channelPtr == NULL)
634 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000635 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
636 "SetLocalReceiver() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000637 return -1;
638 }
639 return channelPtr->StopReceiving();
640}
641
642int VoEBaseImpl::StartPlayout(int channel)
643{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000644 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000645 "StartPlayout(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000646 CriticalSectionScoped cs(_shared->crit_sec());
647 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000648 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000649 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000650 return -1;
651 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000652 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
653 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000654 if (channelPtr == NULL)
655 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000656 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
657 "StartPlayout() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000658 return -1;
659 }
660 if (channelPtr->Playing())
661 {
662 return 0;
663 }
664 if (StartPlayout() != 0)
665 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000666 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
667 "StartPlayout() failed to start playout");
niklase@google.com470e71d2011-07-07 08:21:25 +0000668 return -1;
669 }
670 return channelPtr->StartPlayout();
671}
672
673int VoEBaseImpl::StopPlayout(int channel)
674{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000675 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000676 "StopPlayout(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000677 CriticalSectionScoped cs(_shared->crit_sec());
678 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000679 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000680 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000681 return -1;
682 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000683 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
684 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000685 if (channelPtr == NULL)
686 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000687 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
688 "StopPlayout() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000689 return -1;
690 }
691 if (channelPtr->StopPlayout() != 0)
692 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000693 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
694 VoEId(_shared->instance_id(), -1),
695 "StopPlayout() failed to stop playout for channel %d", channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000696 }
697 return StopPlayout();
698}
699
700int VoEBaseImpl::StartSend(int channel)
701{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000702 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000703 "StartSend(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000704 CriticalSectionScoped cs(_shared->crit_sec());
705 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000706 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000707 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000708 return -1;
709 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000710 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
711 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000712 if (channelPtr == NULL)
713 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000714 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
715 "StartSend() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000716 return -1;
717 }
718 if (channelPtr->Sending())
719 {
720 return 0;
721 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000722 if (StartSend() != 0)
723 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000724 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
725 "StartSend() failed to start recording");
niklase@google.com470e71d2011-07-07 08:21:25 +0000726 return -1;
727 }
728 return channelPtr->StartSend();
729}
730
731int VoEBaseImpl::StopSend(int channel)
732{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000733 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000734 "StopSend(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000735 CriticalSectionScoped cs(_shared->crit_sec());
736 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000737 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000738 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000739 return -1;
740 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000741 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
742 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000743 if (channelPtr == NULL)
744 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000745 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
746 "StopSend() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000747 return -1;
748 }
749 if (channelPtr->StopSend() != 0)
750 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000751 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
752 VoEId(_shared->instance_id(), -1),
753 "StopSend() failed to stop sending for channel %d", channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000754 }
755 return StopSend();
756}
757
758int VoEBaseImpl::GetVersion(char version[1024])
759{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000760 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000761 "GetVersion(version=?)");
762 assert(kVoiceEngineVersionMaxMessageSize == 1024);
763
764 if (version == NULL)
765 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000766 _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000767 return (-1);
768 }
769
770 char versionBuf[kVoiceEngineVersionMaxMessageSize];
771 char* versionPtr = versionBuf;
772
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000773 int32_t len = 0;
774 int32_t accLen = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000775
776 len = AddVoEVersion(versionPtr);
777 if (len == -1)
778 {
779 return -1;
780 }
781 versionPtr += len;
782 accLen += len;
783 assert(accLen < kVoiceEngineVersionMaxMessageSize);
784
785 len = AddBuildInfo(versionPtr);
786 if (len == -1)
787 {
788 return -1;
789 }
790 versionPtr += len;
791 accLen += len;
792 assert(accLen < kVoiceEngineVersionMaxMessageSize);
793
pwestin@webrtc.org684f0572013-03-13 23:20:57 +0000794#ifdef WEBRTC_EXTERNAL_TRANSPORT
795 len = AddExternalTransportBuild(versionPtr);
796 if (len == -1)
797 {
798 return -1;
799 }
800 versionPtr += len;
801 accLen += len;
802 assert(accLen < kVoiceEngineVersionMaxMessageSize);
803#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000804#ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT
805 len = AddExternalRecAndPlayoutBuild(versionPtr);
806 if (len == -1)
807 {
808 return -1;
809 }
810 versionPtr += len;
811 accLen += len;
812 assert(accLen < kVoiceEngineVersionMaxMessageSize);
pwestin@webrtc.orgc450a192012-01-04 15:00:12 +0000813 #endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000814
815 memcpy(version, versionBuf, accLen);
816 version[accLen] = '\0';
817
818 // to avoid the truncation in the trace, split the string into parts
819 char partOfVersion[256];
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000820 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
821 VoEId(_shared->instance_id(), -1), "GetVersion() =>");
niklase@google.com470e71d2011-07-07 08:21:25 +0000822 for (int partStart = 0; partStart < accLen;)
823 {
824 memset(partOfVersion, 0, sizeof(partOfVersion));
825 int partEnd = partStart + 180;
826 while (version[partEnd] != '\n' && version[partEnd] != '\0')
827 {
828 partEnd--;
829 }
830 if (partEnd < accLen)
831 {
832 memcpy(partOfVersion, &version[partStart], partEnd - partStart);
833 }
834 else
835 {
836 memcpy(partOfVersion, &version[partStart], accLen - partStart);
837 }
838 partStart = partEnd;
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000839 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
840 VoEId(_shared->instance_id(), -1), "%s", partOfVersion);
niklase@google.com470e71d2011-07-07 08:21:25 +0000841 }
842
843 return 0;
844}
845
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000846int32_t VoEBaseImpl::AddBuildInfo(char* str) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000847{
andrew@webrtc.org3054ba62013-12-04 17:00:44 +0000848 return sprintf(str, "Build: %s\n", BUILDINFO);
niklase@google.com470e71d2011-07-07 08:21:25 +0000849}
850
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000851int32_t VoEBaseImpl::AddVoEVersion(char* str) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000852{
853 return sprintf(str, "VoiceEngine 4.1.0\n");
854}
855
pwestin@webrtc.org684f0572013-03-13 23:20:57 +0000856#ifdef WEBRTC_EXTERNAL_TRANSPORT
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000857int32_t VoEBaseImpl::AddExternalTransportBuild(char* str) const
pwestin@webrtc.org684f0572013-03-13 23:20:57 +0000858{
859 return sprintf(str, "External transport build\n");
860}
861#endif
862
niklase@google.com470e71d2011-07-07 08:21:25 +0000863#ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000864int32_t VoEBaseImpl::AddExternalRecAndPlayoutBuild(char* str) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000865{
866 return sprintf(str, "External recording and playout build\n");
867}
868#endif
869
niklase@google.com470e71d2011-07-07 08:21:25 +0000870int VoEBaseImpl::LastError()
871{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000872 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000873 "LastError()");
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000874 return (_shared->statistics().LastError());
niklase@google.com470e71d2011-07-07 08:21:25 +0000875}
876
877
878int VoEBaseImpl::SetNetEQPlayoutMode(int channel, NetEqModes mode)
879{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000880 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000881 "SetNetEQPlayoutMode(channel=%i, mode=%i)", channel, mode);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000882 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000883 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000884 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000885 return -1;
886 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000887 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
888 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000889 if (channelPtr == NULL)
890 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000891 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
892 "SetNetEQPlayoutMode() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000893 return -1;
894 }
895 return channelPtr->SetNetEQPlayoutMode(mode);
896}
897
898int VoEBaseImpl::GetNetEQPlayoutMode(int channel, NetEqModes& mode)
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 "GetNetEQPlayoutMode(channel=%i, mode=?)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000902 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000903 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000904 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000905 return -1;
906 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000907 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
908 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000909 if (channelPtr == NULL)
910 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000911 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
912 "GetNetEQPlayoutMode() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000913 return -1;
914 }
915 return channelPtr->GetNetEQPlayoutMode(mode);
916}
917
niklase@google.com470e71d2011-07-07 08:21:25 +0000918int VoEBaseImpl::SetOnHoldStatus(int channel, bool enable, OnHoldModes mode)
919{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000920 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000921 "SetOnHoldStatus(channel=%d, enable=%d, mode=%d)", channel,
922 enable, mode);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000923 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000924 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000925 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000926 return -1;
927 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000928 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
929 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000930 if (channelPtr == NULL)
931 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000932 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
933 "SetOnHoldStatus() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000934 return -1;
935 }
936 return channelPtr->SetOnHoldStatus(enable, mode);
937}
938
939int VoEBaseImpl::GetOnHoldStatus(int channel, bool& enabled, OnHoldModes& mode)
940{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000941 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000942 "GetOnHoldStatus(channel=%d, enabled=?, mode=?)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000943 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000944 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000945 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000946 return -1;
947 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000948 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
949 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000950 if (channelPtr == NULL)
951 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000952 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
953 "GetOnHoldStatus() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000954 return -1;
955 }
956 return channelPtr->GetOnHoldStatus(enabled, mode);
957}
958
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000959int32_t VoEBaseImpl::StartPlayout()
niklase@google.com470e71d2011-07-07 08:21:25 +0000960{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000961 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000962 "VoEBaseImpl::StartPlayout()");
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000963 if (_shared->audio_device()->Playing())
niklase@google.com470e71d2011-07-07 08:21:25 +0000964 {
965 return 0;
966 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000967 if (!_shared->ext_playout())
niklase@google.com470e71d2011-07-07 08:21:25 +0000968 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000969 if (_shared->audio_device()->InitPlayout() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000970 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000971 WEBRTC_TRACE(kTraceError, kTraceVoice,
972 VoEId(_shared->instance_id(), -1),
973 "StartPlayout() failed to initialize playout");
niklase@google.com470e71d2011-07-07 08:21:25 +0000974 return -1;
975 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000976 if (_shared->audio_device()->StartPlayout() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000977 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000978 WEBRTC_TRACE(kTraceError, kTraceVoice,
979 VoEId(_shared->instance_id(), -1),
980 "StartPlayout() failed to start playout");
niklase@google.com470e71d2011-07-07 08:21:25 +0000981 return -1;
982 }
983 }
984 return 0;
985}
986
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000987int32_t VoEBaseImpl::StopPlayout() {
988 WEBRTC_TRACE(kTraceInfo,
989 kTraceVoice,
990 VoEId(_shared->instance_id(), -1),
991 "VoEBaseImpl::StopPlayout()");
992 // Stop audio-device playing if no channel is playing out
xians@webrtc.org675e2602013-10-17 16:15:34 +0000993 if (_shared->NumOfPlayingChannels() == 0) {
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000994 if (_shared->audio_device()->StopPlayout() != 0) {
995 _shared->SetLastError(VE_CANNOT_STOP_PLAYOUT,
996 kTraceError,
997 "StopPlayout() failed to stop playout");
998 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000999 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +00001000 }
1001 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001002}
1003
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001004int32_t VoEBaseImpl::StartSend()
niklase@google.com470e71d2011-07-07 08:21:25 +00001005{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001006 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001007 "VoEBaseImpl::StartSend()");
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001008 if (_shared->audio_device()->Recording())
niklase@google.com470e71d2011-07-07 08:21:25 +00001009 {
1010 return 0;
1011 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001012 if (!_shared->ext_recording())
niklase@google.com470e71d2011-07-07 08:21:25 +00001013 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001014 if (_shared->audio_device()->InitRecording() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001015 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001016 WEBRTC_TRACE(kTraceError, kTraceVoice,
1017 VoEId(_shared->instance_id(), -1),
1018 "StartSend() failed to initialize recording");
niklase@google.com470e71d2011-07-07 08:21:25 +00001019 return -1;
1020 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001021 if (_shared->audio_device()->StartRecording() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001022 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001023 WEBRTC_TRACE(kTraceError, kTraceVoice,
1024 VoEId(_shared->instance_id(), -1),
1025 "StartSend() failed to start recording");
niklase@google.com470e71d2011-07-07 08:21:25 +00001026 return -1;
1027 }
1028 }
1029
1030 return 0;
1031}
1032
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001033int32_t VoEBaseImpl::StopSend()
niklase@google.com470e71d2011-07-07 08:21:25 +00001034{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001035 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001036 "VoEBaseImpl::StopSend()");
1037
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001038 if (_shared->NumOfSendingChannels() == 0 &&
1039 !_shared->transmit_mixer()->IsRecordingMic())
niklase@google.com470e71d2011-07-07 08:21:25 +00001040 {
1041 // Stop audio-device recording if no channel is recording
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001042 if (_shared->audio_device()->StopRecording() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001043 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001044 _shared->SetLastError(VE_CANNOT_STOP_RECORDING, kTraceError,
1045 "StopSend() failed to stop recording");
niklase@google.com470e71d2011-07-07 08:21:25 +00001046 return -1;
1047 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001048 _shared->transmit_mixer()->StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +00001049 }
1050
1051 return 0;
1052}
1053
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001054int32_t VoEBaseImpl::TerminateInternal()
niklase@google.com470e71d2011-07-07 08:21:25 +00001055{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001056 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001057 "VoEBaseImpl::TerminateInternal()");
1058
1059 // Delete any remaining channel objects
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +00001060 _shared->channel_manager().DestroyAllChannels();
niklase@google.com470e71d2011-07-07 08:21:25 +00001061
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001062 if (_shared->process_thread())
niklase@google.com470e71d2011-07-07 08:21:25 +00001063 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001064 if (_shared->audio_device())
niklase@google.com470e71d2011-07-07 08:21:25 +00001065 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001066 if (_shared->process_thread()->
1067 DeRegisterModule(_shared->audio_device()) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001068 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001069 _shared->SetLastError(VE_THREAD_ERROR, kTraceError,
1070 "TerminateInternal() failed to deregister ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +00001071 }
1072 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001073 if (_shared->process_thread()->Stop() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001074 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001075 _shared->SetLastError(VE_THREAD_ERROR, kTraceError,
1076 "TerminateInternal() failed to stop module process thread");
niklase@google.com470e71d2011-07-07 08:21:25 +00001077 }
1078 }
1079
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +00001080 if (_shared->audio_device())
niklase@google.com470e71d2011-07-07 08:21:25 +00001081 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001082 if (_shared->audio_device()->StopPlayout() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001083 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001084 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
1085 "TerminateInternal() failed to stop playout");
niklase@google.com470e71d2011-07-07 08:21:25 +00001086 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001087 if (_shared->audio_device()->StopRecording() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001088 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001089 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
1090 "TerminateInternal() failed to stop recording");
niklase@google.com470e71d2011-07-07 08:21:25 +00001091 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001092 if (_shared->audio_device()->RegisterEventObserver(NULL) != 0) {
1093 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
1094 "TerminateInternal() failed to de-register event observer "
1095 "for the ADM");
xians@webrtc.org79af7342012-01-31 12:22:14 +00001096 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001097 if (_shared->audio_device()->RegisterAudioCallback(NULL) != 0) {
1098 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
1099 "TerminateInternal() failed to de-register audio callback "
1100 "for the ADM");
xians@webrtc.org79af7342012-01-31 12:22:14 +00001101 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001102 if (_shared->audio_device()->Terminate() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001103 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001104 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
1105 "TerminateInternal() failed to terminate the ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +00001106 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001107 _shared->set_audio_device(NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +00001108 }
1109
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +00001110 if (_shared->audio_processing()) {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001111 _shared->set_audio_processing(NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +00001112 }
1113
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001114 return _shared->statistics().SetUnInitialized();
niklase@google.com470e71d2011-07-07 08:21:25 +00001115}
1116
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00001117int VoEBaseImpl::ProcessRecordedDataWithAPM(
1118 const int voe_channels[],
1119 int number_of_voe_channels,
1120 const void* audio_data,
1121 uint32_t sample_rate,
1122 uint8_t number_of_channels,
1123 uint32_t number_of_frames,
1124 uint32_t audio_delay_milliseconds,
1125 int32_t clock_drift,
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001126 uint32_t volume,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00001127 bool key_pressed) {
1128 assert(_shared->transmit_mixer() != NULL);
1129 assert(_shared->audio_device() != NULL);
1130
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00001131 uint32_t max_volume = 0;
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001132 uint16_t voe_mic_level = 0;
andrew@webrtc.org023cc5a2014-01-11 01:25:53 +00001133 // Check for zero to skip this calculation; the consumer may use this to
1134 // indicate no volume is available.
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001135 if (volume != 0) {
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00001136 // Scale from ADM to VoE level range
1137 if (_shared->audio_device()->MaxMicrophoneVolume(&max_volume) == 0) {
1138 if (max_volume) {
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001139 voe_mic_level = static_cast<uint16_t>(
1140 (volume * kMaxVolumeLevel +
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00001141 static_cast<int>(max_volume / 2)) / max_volume);
1142 }
1143 }
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001144 // We learned that on certain systems (e.g Linux) the voe_mic_level
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00001145 // can be greater than the maxVolumeLevel therefore
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001146 // we are going to cap the voe_mic_level to the maxVolumeLevel
1147 // and change the maxVolume to volume if it turns out that
1148 // the voe_mic_level is indeed greater than the maxVolumeLevel.
1149 if (voe_mic_level > kMaxVolumeLevel) {
1150 voe_mic_level = kMaxVolumeLevel;
1151 max_volume = volume;
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00001152 }
1153 }
1154
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00001155 // Perform channel-independent operations
1156 // (APM, mix with file, record to file, mute, etc.)
1157 _shared->transmit_mixer()->PrepareDemux(
1158 audio_data, number_of_frames, number_of_channels, sample_rate,
1159 static_cast<uint16_t>(audio_delay_milliseconds), clock_drift,
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001160 voe_mic_level, key_pressed);
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00001161
1162 // Copy the audio frame to each sending channel and perform
1163 // channel-dependent operations (file mixing, mute, etc.), encode and
1164 // packetize+transmit the RTP packet. When |number_of_voe_channels| == 0,
1165 // do the operations on all the existing VoE channels; otherwise the
1166 // operations will be done on specific channels.
1167 if (number_of_voe_channels == 0) {
1168 _shared->transmit_mixer()->DemuxAndMix();
1169 _shared->transmit_mixer()->EncodeAndSend();
1170 } else {
1171 _shared->transmit_mixer()->DemuxAndMix(voe_channels,
1172 number_of_voe_channels);
1173 _shared->transmit_mixer()->EncodeAndSend(voe_channels,
1174 number_of_voe_channels);
1175 }
1176
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00001177 // Scale from VoE to ADM level range.
1178 uint32_t new_voe_mic_level = _shared->transmit_mixer()->CaptureLevel();
1179
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001180 if (new_voe_mic_level != voe_mic_level) {
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00001181 // Return the new volume if AGC has changed the volume.
1182 return static_cast<int>(
1183 (new_voe_mic_level * max_volume +
1184 static_cast<int>(kMaxVolumeLevel / 2)) / kMaxVolumeLevel);
1185 }
1186
1187 // Return 0 to indicate no change on the volume.
1188 return 0;
1189}
1190
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00001191} // namespace webrtc