blob: 1b41933518e92f1d2290f2452ab31fe932f9f367 [file] [log] [blame]
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001/*
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 *
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.org471ae722013-05-21 13:52:32 +000011#include "webrtc/voice_engine/voe_base_impl.h"
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000012
turaj@webrtc.orgb43ac9f2013-11-13 00:02:48 +000013#include "webrtc/common.h"
pbos@webrtc.org471ae722013-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"
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000027
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000028namespace webrtc
29{
30
31VoEBase* VoEBase::GetInterface(VoiceEngine* voiceEngine)
32{
33 if (NULL == voiceEngine)
34 {
35 return NULL;
36 }
tommi@webrtc.orgb9e5a3d2013-02-15 15:07:32 +000037 VoiceEngineImpl* s = static_cast<VoiceEngineImpl*>(voiceEngine);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000038 s->AddRef();
39 return s;
40}
41
42VoEBaseImpl::VoEBaseImpl(voe::SharedData* shared) :
43 _voiceEngineObserverPtr(NULL),
44 _callbackCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
andrew@webrtc.orgad065d02014-02-18 20:24:56 +000045 _voiceEngineObserver(false), _shared(shared)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000046{
47 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
48 "VoEBaseImpl() - ctor");
49}
50
51VoEBaseImpl::~VoEBaseImpl()
52{
53 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
54 "~VoEBaseImpl() - dtor");
55
56 TerminateInternal();
57
58 delete &_callbackCritSect;
59}
60
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +000061void VoEBaseImpl::OnErrorIsReported(ErrorCode error)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000062{
63 CriticalSectionScoped cs(&_callbackCritSect);
64 if (_voiceEngineObserver)
65 {
66 if (_voiceEngineObserverPtr)
67 {
68 int errCode(0);
69 if (error == AudioDeviceObserver::kRecordingError)
70 {
71 errCode = VE_RUNTIME_REC_ERROR;
72 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
73 VoEId(_shared->instance_id(), -1),
74 "VoEBaseImpl::OnErrorIsReported() => VE_RUNTIME_REC_ERROR");
75 }
76 else if (error == AudioDeviceObserver::kPlayoutError)
77 {
78 errCode = VE_RUNTIME_PLAY_ERROR;
79 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
80 VoEId(_shared->instance_id(), -1),
81 "VoEBaseImpl::OnErrorIsReported() => "
82 "VE_RUNTIME_PLAY_ERROR");
83 }
84 // Deliver callback (-1 <=> no channel dependency)
85 _voiceEngineObserverPtr->CallbackOnError(-1, errCode);
86 }
87 }
88}
89
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +000090void VoEBaseImpl::OnWarningIsReported(WarningCode warning)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000091{
92 CriticalSectionScoped cs(&_callbackCritSect);
93 if (_voiceEngineObserver)
94 {
95 if (_voiceEngineObserverPtr)
96 {
97 int warningCode(0);
98 if (warning == AudioDeviceObserver::kRecordingWarning)
99 {
100 warningCode = VE_RUNTIME_REC_WARNING;
101 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
102 VoEId(_shared->instance_id(), -1),
103 "VoEBaseImpl::OnErrorIsReported() => "
104 "VE_RUNTIME_REC_WARNING");
105 }
106 else if (warning == AudioDeviceObserver::kPlayoutWarning)
107 {
108 warningCode = VE_RUNTIME_PLAY_WARNING;
109 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
110 VoEId(_shared->instance_id(), -1),
111 "VoEBaseImpl::OnErrorIsReported() => "
112 "VE_RUNTIME_PLAY_WARNING");
113 }
114 // Deliver callback (-1 <=> no channel dependency)
115 _voiceEngineObserverPtr->CallbackOnError(-1, warningCode);
116 }
117 }
118}
119
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000120int32_t VoEBaseImpl::RecordedDataIsAvailable(
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000121 const void* audioSamples,
pbos@webrtc.orgca7a9a22013-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.orgad065d02014-02-18 20:24:56 +0000128 uint32_t micLevel,
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +0000129 bool keyPressed,
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000130 uint32_t& newMicLevel)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000131{
132 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_shared->instance_id(), -1),
133 "VoEBaseImpl::RecordedDataIsAvailable(nSamples=%u, "
134 "nBytesPerSample=%u, nChannels=%u, samplesPerSec=%u, "
andrew@webrtc.orgad065d02014-02-18 20:24:56 +0000135 "totalDelayMS=%u, clockDrift=%d, micLevel=%u)",
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000136 nSamples, nBytesPerSample, nChannels, samplesPerSec,
andrew@webrtc.orgad065d02014-02-18 20:24:56 +0000137 totalDelayMS, clockDrift, micLevel);
xians@webrtc.org0e6fa8c2013-07-31 16:27:42 +0000138 newMicLevel = static_cast<uint32_t>(ProcessRecordedDataWithAPM(
139 NULL, 0, audioSamples, samplesPerSec, nChannels, nSamples,
andrew@webrtc.orgad065d02014-02-18 20:24:56 +0000140 totalDelayMS, clockDrift, micLevel, keyPressed));
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000141
142 return 0;
143}
144
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000145int32_t VoEBaseImpl::NeedMorePlayData(
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +0000146 uint32_t nSamples,
147 uint8_t nBytesPerSample,
148 uint8_t nChannels,
149 uint32_t samplesPerSec,
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000150 void* audioSamples,
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000151 uint32_t& nSamplesOut)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000152{
xians@webrtc.org91d88e12014-04-14 10:50:37 +0000153 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_shared->instance_id(), -1),
154 "VoEBaseImpl::NeedMorePlayData(nSamples=%u, "
155 "nBytesPerSample=%d, nChannels=%d, samplesPerSec=%u)",
156 nSamples, nBytesPerSample, nChannels, samplesPerSec);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000157
xians@webrtc.org91d88e12014-04-14 10:50:37 +0000158 GetPlayoutData(static_cast<int>(samplesPerSec),
159 static_cast<int>(nChannels),
160 static_cast<int>(nSamples), true, audioSamples);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000161
xians@webrtc.org91d88e12014-04-14 10:50:37 +0000162 nSamplesOut = _audioFrame.samples_per_channel_;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000163
xians@webrtc.org91d88e12014-04-14 10:50:37 +0000164 return 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000165}
166
xians@webrtc.org0e6fa8c2013-07-31 16:27:42 +0000167int VoEBaseImpl::OnDataAvailable(const int voe_channels[],
xians@webrtc.org44f12392013-07-31 16:23:37 +0000168 int number_of_voe_channels,
169 const int16_t* audio_data,
170 int sample_rate,
171 int number_of_channels,
172 int number_of_frames,
173 int audio_delay_milliseconds,
andrew@webrtc.orgad065d02014-02-18 20:24:56 +0000174 int volume,
xians@webrtc.org44f12392013-07-31 16:23:37 +0000175 bool key_pressed,
176 bool need_audio_processing) {
177 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_shared->instance_id(), -1),
178 "VoEBaseImpl::OnDataAvailable(number_of_voe_channels=%d, "
179 "sample_rate=%d, number_of_channels=%d, number_of_frames=%d, "
andrew@webrtc.orgad065d02014-02-18 20:24:56 +0000180 "audio_delay_milliseconds=%d, volume=%d, "
xians@webrtc.org44f12392013-07-31 16:23:37 +0000181 "key_pressed=%d, need_audio_processing=%d)",
182 number_of_voe_channels, sample_rate, number_of_channels,
andrew@webrtc.orgad065d02014-02-18 20:24:56 +0000183 number_of_frames, audio_delay_milliseconds, volume,
xians@webrtc.org44f12392013-07-31 16:23:37 +0000184 key_pressed, need_audio_processing);
xians@webrtc.org0e6fa8c2013-07-31 16:27:42 +0000185 if (number_of_voe_channels == 0)
186 return 0;
xians@webrtc.org44f12392013-07-31 16:23:37 +0000187
188 if (need_audio_processing) {
xians@webrtc.org0e6fa8c2013-07-31 16:27:42 +0000189 return ProcessRecordedDataWithAPM(
190 voe_channels, number_of_voe_channels, audio_data, sample_rate,
191 number_of_channels, number_of_frames, audio_delay_milliseconds,
andrew@webrtc.orgad065d02014-02-18 20:24:56 +0000192 0, volume, key_pressed);
xians@webrtc.org44f12392013-07-31 16:23:37 +0000193 }
194
195 // No need to go through the APM, demultiplex the data to each VoE channel,
196 // encode and send to the network.
197 for (int i = 0; i < number_of_voe_channels; ++i) {
andrew@webrtc.orgf7c73b52014-04-03 21:56:01 +0000198 // TODO(ajm): In the case where multiple channels are using the same codec
199 // rate, this path needlessly does extra conversions. We should convert once
200 // and share between channels.
xians@webrtc.org91d88e12014-04-14 10:50:37 +0000201 PushCaptureData(voe_channels[i], audio_data, 16, sample_rate,
202 number_of_channels, number_of_frames);
xians@webrtc.org44f12392013-07-31 16:23:37 +0000203 }
204
205 // Return 0 to indicate no need to change the volume.
206 return 0;
207}
208
xians@webrtc.org87c8b862014-02-02 15:30:20 +0000209void VoEBaseImpl::OnData(int voe_channel, const void* audio_data,
210 int bits_per_sample, int sample_rate,
211 int number_of_channels,
212 int number_of_frames) {
xians@webrtc.org91d88e12014-04-14 10:50:37 +0000213 PushCaptureData(voe_channel, audio_data, bits_per_sample, sample_rate,
214 number_of_channels, number_of_frames);
215}
216
217void VoEBaseImpl::PushCaptureData(int voe_channel, const void* audio_data,
218 int bits_per_sample, int sample_rate,
219 int number_of_channels,
220 int number_of_frames) {
xians@webrtc.org942ba532014-01-29 13:54:02 +0000221 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(voe_channel);
222 voe::Channel* channel_ptr = ch.channel();
223 if (!channel_ptr)
224 return;
225
henrika@webrtc.org692224a2014-04-17 10:45:01 +0000226 if (channel_ptr->Sending()) {
xians@webrtc.org942ba532014-01-29 13:54:02 +0000227 channel_ptr->Demultiplex(static_cast<const int16_t*>(audio_data),
228 sample_rate, number_of_frames, number_of_channels);
229 channel_ptr->PrepareEncodeAndSend(sample_rate);
230 channel_ptr->EncodeAndSend();
231 }
232}
233
xians@webrtc.org91d88e12014-04-14 10:50:37 +0000234void VoEBaseImpl::PullRenderData(int bits_per_sample, int sample_rate,
235 int number_of_channels, int number_of_frames,
236 void* audio_data) {
237 assert(bits_per_sample == 16);
238 assert(number_of_frames == static_cast<int>(sample_rate / 100));
239
240 GetPlayoutData(sample_rate, number_of_channels, number_of_frames, false,
241 audio_data);
242}
243
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000244int VoEBaseImpl::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
245{
246 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
247 "RegisterVoiceEngineObserver(observer=0x%d)", &observer);
248 CriticalSectionScoped cs(&_callbackCritSect);
249 if (_voiceEngineObserverPtr)
250 {
251 _shared->SetLastError(VE_INVALID_OPERATION, kTraceError,
252 "RegisterVoiceEngineObserver() observer already enabled");
253 return -1;
254 }
255
256 // Register the observer in all active channels
pbos@webrtc.orgb3ada152013-08-07 17:57:36 +0000257 for (voe::ChannelManager::Iterator it(&_shared->channel_manager());
258 it.IsValid();
259 it.Increment()) {
260 it.GetChannel()->RegisterVoiceEngineObserver(observer);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000261 }
pbos@webrtc.orgb3ada152013-08-07 17:57:36 +0000262
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000263 _shared->transmit_mixer()->RegisterVoiceEngineObserver(observer);
264
265 _voiceEngineObserverPtr = &observer;
266 _voiceEngineObserver = true;
267
268 return 0;
269}
270
271int VoEBaseImpl::DeRegisterVoiceEngineObserver()
272{
273 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
274 "DeRegisterVoiceEngineObserver()");
275 CriticalSectionScoped cs(&_callbackCritSect);
276 if (!_voiceEngineObserverPtr)
277 {
278 _shared->SetLastError(VE_INVALID_OPERATION, kTraceError,
279 "DeRegisterVoiceEngineObserver() observer already disabled");
280 return 0;
281 }
282
283 _voiceEngineObserver = false;
284 _voiceEngineObserverPtr = NULL;
285
286 // Deregister the observer in all active channels
pbos@webrtc.orgb3ada152013-08-07 17:57:36 +0000287 for (voe::ChannelManager::Iterator it(&_shared->channel_manager());
288 it.IsValid();
289 it.Increment()) {
290 it.GetChannel()->DeRegisterVoiceEngineObserver();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000291 }
292
293 return 0;
294}
295
andrew@webrtc.orgb79627b2013-03-05 01:12:49 +0000296int VoEBaseImpl::Init(AudioDeviceModule* external_adm,
297 AudioProcessing* audioproc)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000298{
299 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
300 "Init(external_adm=0x%p)", external_adm);
301 CriticalSectionScoped cs(_shared->crit_sec());
302
303 WebRtcSpl_Init();
304
305 if (_shared->statistics().Initialized())
306 {
307 return 0;
308 }
309
310 if (_shared->process_thread())
311 {
312 if (_shared->process_thread()->Start() != 0)
313 {
314 _shared->SetLastError(VE_THREAD_ERROR, kTraceError,
315 "Init() failed to start module process thread");
316 return -1;
317 }
318 }
319
320 // Create an internal ADM if the user has not added an external
321 // ADM implementation as input to Init().
322 if (external_adm == NULL)
323 {
324 // Create the internal ADM implementation.
325 _shared->set_audio_device(AudioDeviceModuleImpl::Create(
326 VoEId(_shared->instance_id(), -1), _shared->audio_device_layer()));
327
328 if (_shared->audio_device() == NULL)
329 {
330 _shared->SetLastError(VE_NO_MEMORY, kTraceCritical,
331 "Init() failed to create the ADM");
332 return -1;
333 }
334 }
335 else
336 {
337 // Use the already existing external ADM implementation.
338 _shared->set_audio_device(external_adm);
339 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
340 "An external ADM implementation will be used in VoiceEngine");
341 }
342
343 // Register the ADM to the process thread, which will drive the error
344 // callback mechanism
345 if (_shared->process_thread() &&
346 _shared->process_thread()->RegisterModule(_shared->audio_device()) != 0)
347 {
348 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
349 "Init() failed to register the ADM");
350 return -1;
351 }
352
353 bool available(false);
354
355 // --------------------
356 // Reinitialize the ADM
357
358 // Register the AudioObserver implementation
359 if (_shared->audio_device()->RegisterEventObserver(this) != 0) {
360 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
361 "Init() failed to register event observer for the ADM");
362 }
363
364 // Register the AudioTransport implementation
365 if (_shared->audio_device()->RegisterAudioCallback(this) != 0) {
366 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
367 "Init() failed to register audio callback for the ADM");
368 }
369
370 // ADM initialization
371 if (_shared->audio_device()->Init() != 0)
372 {
373 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
374 "Init() failed to initialize the ADM");
375 return -1;
376 }
377
378 // Initialize the default speaker
379 if (_shared->audio_device()->SetPlayoutDevice(
380 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0)
381 {
382 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceInfo,
383 "Init() failed to set the default output device");
384 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000385 if (_shared->audio_device()->InitSpeaker() != 0)
386 {
387 _shared->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceInfo,
388 "Init() failed to initialize the speaker");
389 }
390
391 // Initialize the default microphone
392 if (_shared->audio_device()->SetRecordingDevice(
393 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0)
394 {
395 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceInfo,
396 "Init() failed to set the default input device");
397 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000398 if (_shared->audio_device()->InitMicrophone() != 0)
399 {
400 _shared->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceInfo,
401 "Init() failed to initialize the microphone");
402 }
403
404 // Set number of channels
405 if (_shared->audio_device()->StereoPlayoutIsAvailable(&available) != 0) {
406 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
407 "Init() failed to query stereo playout mode");
408 }
409 if (_shared->audio_device()->SetStereoPlayout(available) != 0)
410 {
411 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
412 "Init() failed to set mono/stereo playout mode");
413 }
414
415 // TODO(andrew): These functions don't tell us whether stereo recording
416 // is truly available. We simply set the AudioProcessing input to stereo
417 // here, because we have to wait until receiving the first frame to
418 // determine the actual number of channels anyway.
419 //
420 // These functions may be changed; tracked here:
421 // http://code.google.com/p/webrtc/issues/detail?id=204
422 _shared->audio_device()->StereoRecordingIsAvailable(&available);
423 if (_shared->audio_device()->SetStereoRecording(available) != 0)
424 {
425 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
426 "Init() failed to set mono/stereo recording mode");
427 }
428
andrew@webrtc.orgb79627b2013-03-05 01:12:49 +0000429 if (!audioproc) {
430 audioproc = AudioProcessing::Create(VoEId(_shared->instance_id(), -1));
431 if (!audioproc) {
432 LOG(LS_ERROR) << "Failed to create AudioProcessing.";
433 _shared->SetLastError(VE_NO_MEMORY);
434 return -1;
435 }
436 }
437 _shared->set_audio_processing(audioproc);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000438
andrew@webrtc.orgb79627b2013-03-05 01:12:49 +0000439 // Set the error state for any failures in this block.
440 _shared->SetLastError(VE_APM_ERROR);
441 if (audioproc->echo_cancellation()->set_device_sample_rate_hz(48000)) {
442 LOG_FERR1(LS_ERROR, set_device_sample_rate_hz, 48000);
443 return -1;
444 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000445
andrew@webrtc.orge06943f2013-10-04 17:54:09 +0000446 // Configure AudioProcessing components.
andrew@webrtc.orgb79627b2013-03-05 01:12:49 +0000447 if (audioproc->high_pass_filter()->Enable(true) != 0) {
448 LOG_FERR1(LS_ERROR, high_pass_filter()->Enable, true);
449 return -1;
450 }
451 if (audioproc->echo_cancellation()->enable_drift_compensation(false) != 0) {
452 LOG_FERR1(LS_ERROR, enable_drift_compensation, false);
453 return -1;
454 }
455 if (audioproc->noise_suppression()->set_level(kDefaultNsMode) != 0) {
456 LOG_FERR1(LS_ERROR, noise_suppression()->set_level, kDefaultNsMode);
457 return -1;
458 }
459 GainControl* agc = audioproc->gain_control();
460 if (agc->set_analog_level_limits(kMinVolumeLevel, kMaxVolumeLevel) != 0) {
461 LOG_FERR2(LS_ERROR, agc->set_analog_level_limits, kMinVolumeLevel,
462 kMaxVolumeLevel);
463 return -1;
464 }
465 if (agc->set_mode(kDefaultAgcMode) != 0) {
466 LOG_FERR1(LS_ERROR, agc->set_mode, kDefaultAgcMode);
467 return -1;
468 }
469 if (agc->Enable(kDefaultAgcState) != 0) {
470 LOG_FERR1(LS_ERROR, agc->Enable, kDefaultAgcState);
471 return -1;
472 }
473 _shared->SetLastError(0); // Clear error state.
474
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000475#ifdef WEBRTC_VOICE_ENGINE_AGC
andrew@webrtc.orgb79627b2013-03-05 01:12:49 +0000476 bool agc_enabled = agc->mode() == GainControl::kAdaptiveAnalog &&
477 agc->is_enabled();
478 if (_shared->audio_device()->SetAGC(agc_enabled) != 0) {
479 LOG_FERR1(LS_ERROR, audio_device()->SetAGC, agc_enabled);
480 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR);
andrew@webrtc.org0f919be2013-03-05 23:36:10 +0000481 // TODO(ajm): No error return here due to
482 // https://code.google.com/p/webrtc/issues/detail?id=1464
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000483 }
484#endif
485
486 return _shared->statistics().SetInitialized();
487}
488
489int VoEBaseImpl::Terminate()
490{
491 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
492 "Terminate()");
493 CriticalSectionScoped cs(_shared->crit_sec());
494 return TerminateInternal();
495}
496
turaj@webrtc.orgb43ac9f2013-11-13 00:02:48 +0000497int VoEBaseImpl::CreateChannel() {
498 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
499 "CreateChannel()");
500 CriticalSectionScoped cs(_shared->crit_sec());
501 if (!_shared->statistics().Initialized()) {
502 _shared->SetLastError(VE_NOT_INITED, kTraceError);
503 return -1;
504 }
505
506 voe::ChannelOwner channel_owner = _shared->channel_manager().CreateChannel();
507
508 return InitializeChannel(&channel_owner);
509}
510
511int VoEBaseImpl::CreateChannel(const Config& config) {
512 CriticalSectionScoped cs(_shared->crit_sec());
513 if (!_shared->statistics().Initialized()) {
514 _shared->SetLastError(VE_NOT_INITED, kTraceError);
515 return -1;
516 }
517 voe::ChannelOwner channel_owner = _shared->channel_manager().CreateChannel(
518 config);
519 return InitializeChannel(&channel_owner);
520}
521
522int VoEBaseImpl::InitializeChannel(voe::ChannelOwner* channel_owner)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000523{
turaj@webrtc.orgb43ac9f2013-11-13 00:02:48 +0000524 if (channel_owner->channel()->SetEngineInformation(
pbos@webrtc.orgb3ada152013-08-07 17:57:36 +0000525 _shared->statistics(),
526 *_shared->output_mixer(),
527 *_shared->transmit_mixer(),
528 *_shared->process_thread(),
529 *_shared->audio_device(),
530 _voiceEngineObserverPtr,
531 &_callbackCritSect) != 0) {
532 _shared->SetLastError(
533 VE_CHANNEL_NOT_CREATED,
534 kTraceError,
535 "CreateChannel() failed to associate engine and channel."
536 " Destroying channel.");
537 _shared->channel_manager()
turaj@webrtc.orgb43ac9f2013-11-13 00:02:48 +0000538 .DestroyChannel(channel_owner->channel()->ChannelId());
pbos@webrtc.orgb3ada152013-08-07 17:57:36 +0000539 return -1;
turaj@webrtc.orgb43ac9f2013-11-13 00:02:48 +0000540 } else if (channel_owner->channel()->Init() != 0) {
pbos@webrtc.orgb3ada152013-08-07 17:57:36 +0000541 _shared->SetLastError(
542 VE_CHANNEL_NOT_CREATED,
543 kTraceError,
544 "CreateChannel() failed to initialize channel. Destroying"
545 " channel.");
546 _shared->channel_manager()
turaj@webrtc.orgb43ac9f2013-11-13 00:02:48 +0000547 .DestroyChannel(channel_owner->channel()->ChannelId());
pbos@webrtc.orgb3ada152013-08-07 17:57:36 +0000548 return -1;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000549 }
550
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000551 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
552 VoEId(_shared->instance_id(), -1),
turaj@webrtc.orgb43ac9f2013-11-13 00:02:48 +0000553 "CreateChannel() => %d", channel_owner->channel()->ChannelId());
554 return channel_owner->channel()->ChannelId();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000555}
556
557int VoEBaseImpl::DeleteChannel(int channel)
558{
559 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
560 "DeleteChannel(channel=%d)", channel);
561 CriticalSectionScoped cs(_shared->crit_sec());
562
563 if (!_shared->statistics().Initialized())
564 {
565 _shared->SetLastError(VE_NOT_INITED, kTraceError);
566 return -1;
567 }
568
569 {
pbos@webrtc.orgb3ada152013-08-07 17:57:36 +0000570 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
571 voe::Channel* channelPtr = ch.channel();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000572 if (channelPtr == NULL)
573 {
574 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
575 "DeleteChannel() failed to locate channel");
576 return -1;
577 }
578 }
579
pbos@webrtc.orgb3ada152013-08-07 17:57:36 +0000580 _shared->channel_manager().DestroyChannel(channel);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000581
582 if (StopSend() != 0)
583 {
584 return -1;
585 }
586
587 if (StopPlayout() != 0)
588 {
589 return -1;
590 }
pwestin@webrtc.org912b7f72013-03-13 23:20:57 +0000591
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000592 return 0;
593}
594
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000595int VoEBaseImpl::StartReceive(int channel)
596{
597 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
598 "StartReceive(channel=%d)", channel);
599 CriticalSectionScoped cs(_shared->crit_sec());
600 if (!_shared->statistics().Initialized())
601 {
602 _shared->SetLastError(VE_NOT_INITED, kTraceError);
603 return -1;
604 }
pbos@webrtc.orgb3ada152013-08-07 17:57:36 +0000605 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
606 voe::Channel* channelPtr = ch.channel();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000607 if (channelPtr == NULL)
608 {
609 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
610 "StartReceive() failed to locate channel");
611 return -1;
612 }
613 return channelPtr->StartReceiving();
614}
615
616int VoEBaseImpl::StopReceive(int channel)
617{
618 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
619 "StopListen(channel=%d)", channel);
620 CriticalSectionScoped cs(_shared->crit_sec());
621 if (!_shared->statistics().Initialized())
622 {
623 _shared->SetLastError(VE_NOT_INITED, kTraceError);
624 return -1;
625 }
pbos@webrtc.orgb3ada152013-08-07 17:57:36 +0000626 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
627 voe::Channel* channelPtr = ch.channel();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000628 if (channelPtr == NULL)
629 {
630 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
631 "SetLocalReceiver() failed to locate channel");
632 return -1;
633 }
634 return channelPtr->StopReceiving();
635}
636
637int VoEBaseImpl::StartPlayout(int channel)
638{
639 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
640 "StartPlayout(channel=%d)", channel);
641 CriticalSectionScoped cs(_shared->crit_sec());
642 if (!_shared->statistics().Initialized())
643 {
644 _shared->SetLastError(VE_NOT_INITED, kTraceError);
645 return -1;
646 }
pbos@webrtc.orgb3ada152013-08-07 17:57:36 +0000647 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
648 voe::Channel* channelPtr = ch.channel();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000649 if (channelPtr == NULL)
650 {
651 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
652 "StartPlayout() failed to locate channel");
653 return -1;
654 }
655 if (channelPtr->Playing())
656 {
657 return 0;
658 }
659 if (StartPlayout() != 0)
660 {
661 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
662 "StartPlayout() failed to start playout");
663 return -1;
664 }
665 return channelPtr->StartPlayout();
666}
667
668int VoEBaseImpl::StopPlayout(int channel)
669{
670 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
671 "StopPlayout(channel=%d)", channel);
672 CriticalSectionScoped cs(_shared->crit_sec());
673 if (!_shared->statistics().Initialized())
674 {
675 _shared->SetLastError(VE_NOT_INITED, kTraceError);
676 return -1;
677 }
pbos@webrtc.orgb3ada152013-08-07 17:57:36 +0000678 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
679 voe::Channel* channelPtr = ch.channel();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000680 if (channelPtr == NULL)
681 {
682 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
683 "StopPlayout() failed to locate channel");
684 return -1;
685 }
686 if (channelPtr->StopPlayout() != 0)
687 {
688 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
689 VoEId(_shared->instance_id(), -1),
690 "StopPlayout() failed to stop playout for channel %d", channel);
691 }
692 return StopPlayout();
693}
694
695int VoEBaseImpl::StartSend(int channel)
696{
697 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
698 "StartSend(channel=%d)", channel);
699 CriticalSectionScoped cs(_shared->crit_sec());
700 if (!_shared->statistics().Initialized())
701 {
702 _shared->SetLastError(VE_NOT_INITED, kTraceError);
703 return -1;
704 }
pbos@webrtc.orgb3ada152013-08-07 17:57:36 +0000705 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
706 voe::Channel* channelPtr = ch.channel();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000707 if (channelPtr == NULL)
708 {
709 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
710 "StartSend() failed to locate channel");
711 return -1;
712 }
713 if (channelPtr->Sending())
714 {
715 return 0;
716 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000717 if (StartSend() != 0)
718 {
719 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
720 "StartSend() failed to start recording");
721 return -1;
722 }
723 return channelPtr->StartSend();
724}
725
726int VoEBaseImpl::StopSend(int channel)
727{
728 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
729 "StopSend(channel=%d)", channel);
730 CriticalSectionScoped cs(_shared->crit_sec());
731 if (!_shared->statistics().Initialized())
732 {
733 _shared->SetLastError(VE_NOT_INITED, kTraceError);
734 return -1;
735 }
pbos@webrtc.orgb3ada152013-08-07 17:57:36 +0000736 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
737 voe::Channel* channelPtr = ch.channel();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000738 if (channelPtr == NULL)
739 {
740 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
741 "StopSend() failed to locate channel");
742 return -1;
743 }
744 if (channelPtr->StopSend() != 0)
745 {
746 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
747 VoEId(_shared->instance_id(), -1),
748 "StopSend() failed to stop sending for channel %d", channel);
749 }
750 return StopSend();
751}
752
753int VoEBaseImpl::GetVersion(char version[1024])
754{
755 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
756 "GetVersion(version=?)");
757 assert(kVoiceEngineVersionMaxMessageSize == 1024);
758
759 if (version == NULL)
760 {
761 _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError);
762 return (-1);
763 }
764
765 char versionBuf[kVoiceEngineVersionMaxMessageSize];
766 char* versionPtr = versionBuf;
767
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000768 int32_t len = 0;
769 int32_t accLen = 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000770
771 len = AddVoEVersion(versionPtr);
772 if (len == -1)
773 {
774 return -1;
775 }
776 versionPtr += len;
777 accLen += len;
778 assert(accLen < kVoiceEngineVersionMaxMessageSize);
779
780 len = AddBuildInfo(versionPtr);
781 if (len == -1)
782 {
783 return -1;
784 }
785 versionPtr += len;
786 accLen += len;
787 assert(accLen < kVoiceEngineVersionMaxMessageSize);
788
pwestin@webrtc.org912b7f72013-03-13 23:20:57 +0000789#ifdef WEBRTC_EXTERNAL_TRANSPORT
790 len = AddExternalTransportBuild(versionPtr);
791 if (len == -1)
792 {
793 return -1;
794 }
795 versionPtr += len;
796 accLen += len;
797 assert(accLen < kVoiceEngineVersionMaxMessageSize);
798#endif
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000799#ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT
800 len = AddExternalRecAndPlayoutBuild(versionPtr);
801 if (len == -1)
802 {
803 return -1;
804 }
805 versionPtr += len;
806 accLen += len;
807 assert(accLen < kVoiceEngineVersionMaxMessageSize);
808 #endif
809
810 memcpy(version, versionBuf, accLen);
811 version[accLen] = '\0';
812
813 // to avoid the truncation in the trace, split the string into parts
814 char partOfVersion[256];
815 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
816 VoEId(_shared->instance_id(), -1), "GetVersion() =>");
817 for (int partStart = 0; partStart < accLen;)
818 {
819 memset(partOfVersion, 0, sizeof(partOfVersion));
820 int partEnd = partStart + 180;
821 while (version[partEnd] != '\n' && version[partEnd] != '\0')
822 {
823 partEnd--;
824 }
825 if (partEnd < accLen)
826 {
827 memcpy(partOfVersion, &version[partStart], partEnd - partStart);
828 }
829 else
830 {
831 memcpy(partOfVersion, &version[partStart], accLen - partStart);
832 }
833 partStart = partEnd;
834 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
835 VoEId(_shared->instance_id(), -1), "%s", partOfVersion);
836 }
837
838 return 0;
839}
840
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000841int32_t VoEBaseImpl::AddBuildInfo(char* str) const
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000842{
andrew@webrtc.orgc7d73632013-12-04 17:00:44 +0000843 return sprintf(str, "Build: %s\n", BUILDINFO);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000844}
845
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000846int32_t VoEBaseImpl::AddVoEVersion(char* str) const
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000847{
848 return sprintf(str, "VoiceEngine 4.1.0\n");
849}
850
pwestin@webrtc.org912b7f72013-03-13 23:20:57 +0000851#ifdef WEBRTC_EXTERNAL_TRANSPORT
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000852int32_t VoEBaseImpl::AddExternalTransportBuild(char* str) const
pwestin@webrtc.org912b7f72013-03-13 23:20:57 +0000853{
854 return sprintf(str, "External transport build\n");
855}
856#endif
857
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000858#ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000859int32_t VoEBaseImpl::AddExternalRecAndPlayoutBuild(char* str) const
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000860{
861 return sprintf(str, "External recording and playout build\n");
862}
863#endif
864
865int VoEBaseImpl::LastError()
866{
867 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
868 "LastError()");
869 return (_shared->statistics().LastError());
870}
871
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000872int32_t VoEBaseImpl::StartPlayout()
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000873{
874 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
875 "VoEBaseImpl::StartPlayout()");
876 if (_shared->audio_device()->Playing())
877 {
878 return 0;
879 }
880 if (!_shared->ext_playout())
881 {
882 if (_shared->audio_device()->InitPlayout() != 0)
883 {
884 WEBRTC_TRACE(kTraceError, kTraceVoice,
885 VoEId(_shared->instance_id(), -1),
886 "StartPlayout() failed to initialize playout");
887 return -1;
888 }
889 if (_shared->audio_device()->StartPlayout() != 0)
890 {
891 WEBRTC_TRACE(kTraceError, kTraceVoice,
892 VoEId(_shared->instance_id(), -1),
893 "StartPlayout() failed to start playout");
894 return -1;
895 }
896 }
897 return 0;
898}
899
pbos@webrtc.orgb3ada152013-08-07 17:57:36 +0000900int32_t VoEBaseImpl::StopPlayout() {
901 WEBRTC_TRACE(kTraceInfo,
902 kTraceVoice,
903 VoEId(_shared->instance_id(), -1),
904 "VoEBaseImpl::StopPlayout()");
905 // Stop audio-device playing if no channel is playing out
xians@webrtc.org3d553d42013-10-17 16:15:34 +0000906 if (_shared->NumOfPlayingChannels() == 0) {
pbos@webrtc.orgb3ada152013-08-07 17:57:36 +0000907 if (_shared->audio_device()->StopPlayout() != 0) {
908 _shared->SetLastError(VE_CANNOT_STOP_PLAYOUT,
909 kTraceError,
910 "StopPlayout() failed to stop playout");
911 return -1;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000912 }
pbos@webrtc.orgb3ada152013-08-07 17:57:36 +0000913 }
914 return 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000915}
916
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000917int32_t VoEBaseImpl::StartSend()
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000918{
919 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
920 "VoEBaseImpl::StartSend()");
921 if (_shared->audio_device()->Recording())
922 {
923 return 0;
924 }
925 if (!_shared->ext_recording())
926 {
927 if (_shared->audio_device()->InitRecording() != 0)
928 {
929 WEBRTC_TRACE(kTraceError, kTraceVoice,
930 VoEId(_shared->instance_id(), -1),
931 "StartSend() failed to initialize recording");
932 return -1;
933 }
934 if (_shared->audio_device()->StartRecording() != 0)
935 {
936 WEBRTC_TRACE(kTraceError, kTraceVoice,
937 VoEId(_shared->instance_id(), -1),
938 "StartSend() failed to start recording");
939 return -1;
940 }
941 }
942
943 return 0;
944}
945
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000946int32_t VoEBaseImpl::StopSend()
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000947{
948 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
949 "VoEBaseImpl::StopSend()");
950
951 if (_shared->NumOfSendingChannels() == 0 &&
952 !_shared->transmit_mixer()->IsRecordingMic())
953 {
954 // Stop audio-device recording if no channel is recording
955 if (_shared->audio_device()->StopRecording() != 0)
956 {
957 _shared->SetLastError(VE_CANNOT_STOP_RECORDING, kTraceError,
958 "StopSend() failed to stop recording");
959 return -1;
960 }
961 _shared->transmit_mixer()->StopSend();
962 }
963
964 return 0;
965}
966
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000967int32_t VoEBaseImpl::TerminateInternal()
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000968{
969 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
970 "VoEBaseImpl::TerminateInternal()");
971
972 // Delete any remaining channel objects
pbos@webrtc.orgb3ada152013-08-07 17:57:36 +0000973 _shared->channel_manager().DestroyAllChannels();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000974
975 if (_shared->process_thread())
976 {
977 if (_shared->audio_device())
978 {
979 if (_shared->process_thread()->
980 DeRegisterModule(_shared->audio_device()) != 0)
981 {
982 _shared->SetLastError(VE_THREAD_ERROR, kTraceError,
983 "TerminateInternal() failed to deregister ADM");
984 }
985 }
986 if (_shared->process_thread()->Stop() != 0)
987 {
988 _shared->SetLastError(VE_THREAD_ERROR, kTraceError,
989 "TerminateInternal() failed to stop module process thread");
990 }
991 }
992
andrew@webrtc.orgb79627b2013-03-05 01:12:49 +0000993 if (_shared->audio_device())
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000994 {
995 if (_shared->audio_device()->StopPlayout() != 0)
996 {
997 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
998 "TerminateInternal() failed to stop playout");
999 }
1000 if (_shared->audio_device()->StopRecording() != 0)
1001 {
1002 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
1003 "TerminateInternal() failed to stop recording");
1004 }
1005 if (_shared->audio_device()->RegisterEventObserver(NULL) != 0) {
1006 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
1007 "TerminateInternal() failed to de-register event observer "
1008 "for the ADM");
1009 }
1010 if (_shared->audio_device()->RegisterAudioCallback(NULL) != 0) {
1011 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
1012 "TerminateInternal() failed to de-register audio callback "
1013 "for the ADM");
1014 }
1015 if (_shared->audio_device()->Terminate() != 0)
1016 {
1017 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
1018 "TerminateInternal() failed to terminate the ADM");
1019 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001020 _shared->set_audio_device(NULL);
1021 }
1022
andrew@webrtc.orgb79627b2013-03-05 01:12:49 +00001023 if (_shared->audio_processing()) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001024 _shared->set_audio_processing(NULL);
1025 }
1026
1027 return _shared->statistics().SetUnInitialized();
1028}
1029
xians@webrtc.org0e6fa8c2013-07-31 16:27:42 +00001030int VoEBaseImpl::ProcessRecordedDataWithAPM(
1031 const int voe_channels[],
1032 int number_of_voe_channels,
1033 const void* audio_data,
1034 uint32_t sample_rate,
1035 uint8_t number_of_channels,
1036 uint32_t number_of_frames,
1037 uint32_t audio_delay_milliseconds,
1038 int32_t clock_drift,
andrew@webrtc.orgad065d02014-02-18 20:24:56 +00001039 uint32_t volume,
xians@webrtc.org0e6fa8c2013-07-31 16:27:42 +00001040 bool key_pressed) {
1041 assert(_shared->transmit_mixer() != NULL);
1042 assert(_shared->audio_device() != NULL);
1043
xians@webrtc.org0e6fa8c2013-07-31 16:27:42 +00001044 uint32_t max_volume = 0;
andrew@webrtc.orgad065d02014-02-18 20:24:56 +00001045 uint16_t voe_mic_level = 0;
andrew@webrtc.org22470b52014-01-11 01:25:53 +00001046 // Check for zero to skip this calculation; the consumer may use this to
1047 // indicate no volume is available.
andrew@webrtc.orgad065d02014-02-18 20:24:56 +00001048 if (volume != 0) {
xians@webrtc.org0e6fa8c2013-07-31 16:27:42 +00001049 // Scale from ADM to VoE level range
1050 if (_shared->audio_device()->MaxMicrophoneVolume(&max_volume) == 0) {
1051 if (max_volume) {
andrew@webrtc.orgad065d02014-02-18 20:24:56 +00001052 voe_mic_level = static_cast<uint16_t>(
1053 (volume * kMaxVolumeLevel +
xians@webrtc.org0e6fa8c2013-07-31 16:27:42 +00001054 static_cast<int>(max_volume / 2)) / max_volume);
1055 }
1056 }
andrew@webrtc.orgad065d02014-02-18 20:24:56 +00001057 // We learned that on certain systems (e.g Linux) the voe_mic_level
xians@webrtc.org0e6fa8c2013-07-31 16:27:42 +00001058 // can be greater than the maxVolumeLevel therefore
andrew@webrtc.orgad065d02014-02-18 20:24:56 +00001059 // we are going to cap the voe_mic_level to the maxVolumeLevel
1060 // and change the maxVolume to volume if it turns out that
1061 // the voe_mic_level is indeed greater than the maxVolumeLevel.
1062 if (voe_mic_level > kMaxVolumeLevel) {
1063 voe_mic_level = kMaxVolumeLevel;
1064 max_volume = volume;
xians@webrtc.org0e6fa8c2013-07-31 16:27:42 +00001065 }
1066 }
1067
xians@webrtc.org0e6fa8c2013-07-31 16:27:42 +00001068 // Perform channel-independent operations
1069 // (APM, mix with file, record to file, mute, etc.)
1070 _shared->transmit_mixer()->PrepareDemux(
1071 audio_data, number_of_frames, number_of_channels, sample_rate,
1072 static_cast<uint16_t>(audio_delay_milliseconds), clock_drift,
andrew@webrtc.orgad065d02014-02-18 20:24:56 +00001073 voe_mic_level, key_pressed);
xians@webrtc.org0e6fa8c2013-07-31 16:27:42 +00001074
1075 // Copy the audio frame to each sending channel and perform
1076 // channel-dependent operations (file mixing, mute, etc.), encode and
1077 // packetize+transmit the RTP packet. When |number_of_voe_channels| == 0,
1078 // do the operations on all the existing VoE channels; otherwise the
1079 // operations will be done on specific channels.
1080 if (number_of_voe_channels == 0) {
1081 _shared->transmit_mixer()->DemuxAndMix();
1082 _shared->transmit_mixer()->EncodeAndSend();
1083 } else {
1084 _shared->transmit_mixer()->DemuxAndMix(voe_channels,
1085 number_of_voe_channels);
1086 _shared->transmit_mixer()->EncodeAndSend(voe_channels,
1087 number_of_voe_channels);
1088 }
1089
xians@webrtc.org0e6fa8c2013-07-31 16:27:42 +00001090 // Scale from VoE to ADM level range.
1091 uint32_t new_voe_mic_level = _shared->transmit_mixer()->CaptureLevel();
1092
andrew@webrtc.orgad065d02014-02-18 20:24:56 +00001093 if (new_voe_mic_level != voe_mic_level) {
xians@webrtc.org0e6fa8c2013-07-31 16:27:42 +00001094 // Return the new volume if AGC has changed the volume.
1095 return static_cast<int>(
1096 (new_voe_mic_level * max_volume +
1097 static_cast<int>(kMaxVolumeLevel / 2)) / kMaxVolumeLevel);
1098 }
1099
1100 // Return 0 to indicate no change on the volume.
1101 return 0;
1102}
1103
xians@webrtc.org91d88e12014-04-14 10:50:37 +00001104void VoEBaseImpl::GetPlayoutData(int sample_rate, int number_of_channels,
1105 int number_of_frames, bool feed_data_to_apm,
1106 void* audio_data) {
1107 assert(_shared->output_mixer() != NULL);
1108
1109 // TODO(andrew): if the device is running in mono, we should tell the mixer
1110 // here so that it will only request mono from AudioCodingModule.
1111 // Perform mixing of all active participants (channel-based mixing)
1112 _shared->output_mixer()->MixActiveChannels();
1113
1114 // Additional operations on the combined signal
1115 _shared->output_mixer()->DoOperationsOnCombinedSignal(feed_data_to_apm);
1116
1117 // Retrieve the final output mix (resampled to match the ADM)
1118 _shared->output_mixer()->GetMixedAudio(sample_rate, number_of_channels,
1119 &_audioFrame);
1120
1121 assert(number_of_frames == _audioFrame.samples_per_channel_);
1122 assert(sample_rate == _audioFrame.sample_rate_hz_);
1123
1124 // Deliver audio (PCM) samples to the ADM
1125 memcpy(audio_data, _audioFrame.data_,
1126 sizeof(int16_t) * number_of_frames * number_of_channels);
1127}
1128
pbos@webrtc.org3b89e102013-07-03 15:12:26 +00001129} // namespace webrtc