blob: 41b230ea19e4136bfcde24411622e2dbf992c285 [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
226 if (channel_ptr->InputIsOnHold()) {
227 channel_ptr->UpdateLocalTimeStamp();
228 } else if (channel_ptr->Sending()) {
229 channel_ptr->Demultiplex(static_cast<const int16_t*>(audio_data),
230 sample_rate, number_of_frames, number_of_channels);
231 channel_ptr->PrepareEncodeAndSend(sample_rate);
232 channel_ptr->EncodeAndSend();
233 }
234}
235
xians@webrtc.org91d88e12014-04-14 10:50:37 +0000236void VoEBaseImpl::PullRenderData(int bits_per_sample, int sample_rate,
237 int number_of_channels, int number_of_frames,
238 void* audio_data) {
239 assert(bits_per_sample == 16);
240 assert(number_of_frames == static_cast<int>(sample_rate / 100));
241
242 GetPlayoutData(sample_rate, number_of_channels, number_of_frames, false,
243 audio_data);
244}
245
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000246int VoEBaseImpl::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
247{
248 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
249 "RegisterVoiceEngineObserver(observer=0x%d)", &observer);
250 CriticalSectionScoped cs(&_callbackCritSect);
251 if (_voiceEngineObserverPtr)
252 {
253 _shared->SetLastError(VE_INVALID_OPERATION, kTraceError,
254 "RegisterVoiceEngineObserver() observer already enabled");
255 return -1;
256 }
257
258 // Register the observer in all active channels
pbos@webrtc.orgb3ada152013-08-07 17:57:36 +0000259 for (voe::ChannelManager::Iterator it(&_shared->channel_manager());
260 it.IsValid();
261 it.Increment()) {
262 it.GetChannel()->RegisterVoiceEngineObserver(observer);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000263 }
pbos@webrtc.orgb3ada152013-08-07 17:57:36 +0000264
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000265 _shared->transmit_mixer()->RegisterVoiceEngineObserver(observer);
266
267 _voiceEngineObserverPtr = &observer;
268 _voiceEngineObserver = true;
269
270 return 0;
271}
272
273int VoEBaseImpl::DeRegisterVoiceEngineObserver()
274{
275 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
276 "DeRegisterVoiceEngineObserver()");
277 CriticalSectionScoped cs(&_callbackCritSect);
278 if (!_voiceEngineObserverPtr)
279 {
280 _shared->SetLastError(VE_INVALID_OPERATION, kTraceError,
281 "DeRegisterVoiceEngineObserver() observer already disabled");
282 return 0;
283 }
284
285 _voiceEngineObserver = false;
286 _voiceEngineObserverPtr = NULL;
287
288 // Deregister the observer in all active channels
pbos@webrtc.orgb3ada152013-08-07 17:57:36 +0000289 for (voe::ChannelManager::Iterator it(&_shared->channel_manager());
290 it.IsValid();
291 it.Increment()) {
292 it.GetChannel()->DeRegisterVoiceEngineObserver();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000293 }
294
295 return 0;
296}
297
andrew@webrtc.orgb79627b2013-03-05 01:12:49 +0000298int VoEBaseImpl::Init(AudioDeviceModule* external_adm,
299 AudioProcessing* audioproc)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000300{
301 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
302 "Init(external_adm=0x%p)", external_adm);
303 CriticalSectionScoped cs(_shared->crit_sec());
304
305 WebRtcSpl_Init();
306
307 if (_shared->statistics().Initialized())
308 {
309 return 0;
310 }
311
312 if (_shared->process_thread())
313 {
314 if (_shared->process_thread()->Start() != 0)
315 {
316 _shared->SetLastError(VE_THREAD_ERROR, kTraceError,
317 "Init() failed to start module process thread");
318 return -1;
319 }
320 }
321
322 // Create an internal ADM if the user has not added an external
323 // ADM implementation as input to Init().
324 if (external_adm == NULL)
325 {
326 // Create the internal ADM implementation.
327 _shared->set_audio_device(AudioDeviceModuleImpl::Create(
328 VoEId(_shared->instance_id(), -1), _shared->audio_device_layer()));
329
330 if (_shared->audio_device() == NULL)
331 {
332 _shared->SetLastError(VE_NO_MEMORY, kTraceCritical,
333 "Init() failed to create the ADM");
334 return -1;
335 }
336 }
337 else
338 {
339 // Use the already existing external ADM implementation.
340 _shared->set_audio_device(external_adm);
341 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
342 "An external ADM implementation will be used in VoiceEngine");
343 }
344
345 // Register the ADM to the process thread, which will drive the error
346 // callback mechanism
347 if (_shared->process_thread() &&
348 _shared->process_thread()->RegisterModule(_shared->audio_device()) != 0)
349 {
350 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
351 "Init() failed to register the ADM");
352 return -1;
353 }
354
355 bool available(false);
356
357 // --------------------
358 // Reinitialize the ADM
359
360 // Register the AudioObserver implementation
361 if (_shared->audio_device()->RegisterEventObserver(this) != 0) {
362 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
363 "Init() failed to register event observer for the ADM");
364 }
365
366 // Register the AudioTransport implementation
367 if (_shared->audio_device()->RegisterAudioCallback(this) != 0) {
368 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
369 "Init() failed to register audio callback for the ADM");
370 }
371
372 // ADM initialization
373 if (_shared->audio_device()->Init() != 0)
374 {
375 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
376 "Init() failed to initialize the ADM");
377 return -1;
378 }
379
380 // Initialize the default speaker
381 if (_shared->audio_device()->SetPlayoutDevice(
382 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0)
383 {
384 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceInfo,
385 "Init() failed to set the default output device");
386 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000387 if (_shared->audio_device()->InitSpeaker() != 0)
388 {
389 _shared->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceInfo,
390 "Init() failed to initialize the speaker");
391 }
392
393 // Initialize the default microphone
394 if (_shared->audio_device()->SetRecordingDevice(
395 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0)
396 {
397 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceInfo,
398 "Init() failed to set the default input device");
399 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000400 if (_shared->audio_device()->InitMicrophone() != 0)
401 {
402 _shared->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceInfo,
403 "Init() failed to initialize the microphone");
404 }
405
406 // Set number of channels
407 if (_shared->audio_device()->StereoPlayoutIsAvailable(&available) != 0) {
408 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
409 "Init() failed to query stereo playout mode");
410 }
411 if (_shared->audio_device()->SetStereoPlayout(available) != 0)
412 {
413 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
414 "Init() failed to set mono/stereo playout mode");
415 }
416
417 // TODO(andrew): These functions don't tell us whether stereo recording
418 // is truly available. We simply set the AudioProcessing input to stereo
419 // here, because we have to wait until receiving the first frame to
420 // determine the actual number of channels anyway.
421 //
422 // These functions may be changed; tracked here:
423 // http://code.google.com/p/webrtc/issues/detail?id=204
424 _shared->audio_device()->StereoRecordingIsAvailable(&available);
425 if (_shared->audio_device()->SetStereoRecording(available) != 0)
426 {
427 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
428 "Init() failed to set mono/stereo recording mode");
429 }
430
andrew@webrtc.orgb79627b2013-03-05 01:12:49 +0000431 if (!audioproc) {
432 audioproc = AudioProcessing::Create(VoEId(_shared->instance_id(), -1));
433 if (!audioproc) {
434 LOG(LS_ERROR) << "Failed to create AudioProcessing.";
435 _shared->SetLastError(VE_NO_MEMORY);
436 return -1;
437 }
438 }
439 _shared->set_audio_processing(audioproc);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000440
andrew@webrtc.orgb79627b2013-03-05 01:12:49 +0000441 // Set the error state for any failures in this block.
442 _shared->SetLastError(VE_APM_ERROR);
443 if (audioproc->echo_cancellation()->set_device_sample_rate_hz(48000)) {
444 LOG_FERR1(LS_ERROR, set_device_sample_rate_hz, 48000);
445 return -1;
446 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000447
andrew@webrtc.orge06943f2013-10-04 17:54:09 +0000448 // Configure AudioProcessing components.
andrew@webrtc.orgb79627b2013-03-05 01:12:49 +0000449 if (audioproc->high_pass_filter()->Enable(true) != 0) {
450 LOG_FERR1(LS_ERROR, high_pass_filter()->Enable, true);
451 return -1;
452 }
453 if (audioproc->echo_cancellation()->enable_drift_compensation(false) != 0) {
454 LOG_FERR1(LS_ERROR, enable_drift_compensation, false);
455 return -1;
456 }
457 if (audioproc->noise_suppression()->set_level(kDefaultNsMode) != 0) {
458 LOG_FERR1(LS_ERROR, noise_suppression()->set_level, kDefaultNsMode);
459 return -1;
460 }
461 GainControl* agc = audioproc->gain_control();
462 if (agc->set_analog_level_limits(kMinVolumeLevel, kMaxVolumeLevel) != 0) {
463 LOG_FERR2(LS_ERROR, agc->set_analog_level_limits, kMinVolumeLevel,
464 kMaxVolumeLevel);
465 return -1;
466 }
467 if (agc->set_mode(kDefaultAgcMode) != 0) {
468 LOG_FERR1(LS_ERROR, agc->set_mode, kDefaultAgcMode);
469 return -1;
470 }
471 if (agc->Enable(kDefaultAgcState) != 0) {
472 LOG_FERR1(LS_ERROR, agc->Enable, kDefaultAgcState);
473 return -1;
474 }
475 _shared->SetLastError(0); // Clear error state.
476
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000477#ifdef WEBRTC_VOICE_ENGINE_AGC
andrew@webrtc.orgb79627b2013-03-05 01:12:49 +0000478 bool agc_enabled = agc->mode() == GainControl::kAdaptiveAnalog &&
479 agc->is_enabled();
480 if (_shared->audio_device()->SetAGC(agc_enabled) != 0) {
481 LOG_FERR1(LS_ERROR, audio_device()->SetAGC, agc_enabled);
482 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR);
andrew@webrtc.org0f919be2013-03-05 23:36:10 +0000483 // TODO(ajm): No error return here due to
484 // https://code.google.com/p/webrtc/issues/detail?id=1464
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000485 }
486#endif
487
488 return _shared->statistics().SetInitialized();
489}
490
491int VoEBaseImpl::Terminate()
492{
493 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
494 "Terminate()");
495 CriticalSectionScoped cs(_shared->crit_sec());
496 return TerminateInternal();
497}
498
turaj@webrtc.orgb43ac9f2013-11-13 00:02:48 +0000499int VoEBaseImpl::CreateChannel() {
500 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
501 "CreateChannel()");
502 CriticalSectionScoped cs(_shared->crit_sec());
503 if (!_shared->statistics().Initialized()) {
504 _shared->SetLastError(VE_NOT_INITED, kTraceError);
505 return -1;
506 }
507
508 voe::ChannelOwner channel_owner = _shared->channel_manager().CreateChannel();
509
510 return InitializeChannel(&channel_owner);
511}
512
513int VoEBaseImpl::CreateChannel(const Config& config) {
514 CriticalSectionScoped cs(_shared->crit_sec());
515 if (!_shared->statistics().Initialized()) {
516 _shared->SetLastError(VE_NOT_INITED, kTraceError);
517 return -1;
518 }
519 voe::ChannelOwner channel_owner = _shared->channel_manager().CreateChannel(
520 config);
521 return InitializeChannel(&channel_owner);
522}
523
524int VoEBaseImpl::InitializeChannel(voe::ChannelOwner* channel_owner)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000525{
turaj@webrtc.orgb43ac9f2013-11-13 00:02:48 +0000526 if (channel_owner->channel()->SetEngineInformation(
pbos@webrtc.orgb3ada152013-08-07 17:57:36 +0000527 _shared->statistics(),
528 *_shared->output_mixer(),
529 *_shared->transmit_mixer(),
530 *_shared->process_thread(),
531 *_shared->audio_device(),
532 _voiceEngineObserverPtr,
533 &_callbackCritSect) != 0) {
534 _shared->SetLastError(
535 VE_CHANNEL_NOT_CREATED,
536 kTraceError,
537 "CreateChannel() failed to associate engine and channel."
538 " Destroying channel.");
539 _shared->channel_manager()
turaj@webrtc.orgb43ac9f2013-11-13 00:02:48 +0000540 .DestroyChannel(channel_owner->channel()->ChannelId());
pbos@webrtc.orgb3ada152013-08-07 17:57:36 +0000541 return -1;
turaj@webrtc.orgb43ac9f2013-11-13 00:02:48 +0000542 } else if (channel_owner->channel()->Init() != 0) {
pbos@webrtc.orgb3ada152013-08-07 17:57:36 +0000543 _shared->SetLastError(
544 VE_CHANNEL_NOT_CREATED,
545 kTraceError,
546 "CreateChannel() failed to initialize channel. Destroying"
547 " channel.");
548 _shared->channel_manager()
turaj@webrtc.orgb43ac9f2013-11-13 00:02:48 +0000549 .DestroyChannel(channel_owner->channel()->ChannelId());
pbos@webrtc.orgb3ada152013-08-07 17:57:36 +0000550 return -1;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000551 }
552
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000553 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
554 VoEId(_shared->instance_id(), -1),
turaj@webrtc.orgb43ac9f2013-11-13 00:02:48 +0000555 "CreateChannel() => %d", channel_owner->channel()->ChannelId());
556 return channel_owner->channel()->ChannelId();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000557}
558
559int VoEBaseImpl::DeleteChannel(int channel)
560{
561 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
562 "DeleteChannel(channel=%d)", channel);
563 CriticalSectionScoped cs(_shared->crit_sec());
564
565 if (!_shared->statistics().Initialized())
566 {
567 _shared->SetLastError(VE_NOT_INITED, kTraceError);
568 return -1;
569 }
570
571 {
pbos@webrtc.orgb3ada152013-08-07 17:57:36 +0000572 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
573 voe::Channel* channelPtr = ch.channel();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000574 if (channelPtr == NULL)
575 {
576 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
577 "DeleteChannel() failed to locate channel");
578 return -1;
579 }
580 }
581
pbos@webrtc.orgb3ada152013-08-07 17:57:36 +0000582 _shared->channel_manager().DestroyChannel(channel);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000583
584 if (StopSend() != 0)
585 {
586 return -1;
587 }
588
589 if (StopPlayout() != 0)
590 {
591 return -1;
592 }
pwestin@webrtc.org912b7f72013-03-13 23:20:57 +0000593
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000594 return 0;
595}
596
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000597int VoEBaseImpl::StartReceive(int channel)
598{
599 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
600 "StartReceive(channel=%d)", channel);
601 CriticalSectionScoped cs(_shared->crit_sec());
602 if (!_shared->statistics().Initialized())
603 {
604 _shared->SetLastError(VE_NOT_INITED, kTraceError);
605 return -1;
606 }
pbos@webrtc.orgb3ada152013-08-07 17:57:36 +0000607 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
608 voe::Channel* channelPtr = ch.channel();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000609 if (channelPtr == NULL)
610 {
611 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
612 "StartReceive() failed to locate channel");
613 return -1;
614 }
615 return channelPtr->StartReceiving();
616}
617
618int VoEBaseImpl::StopReceive(int channel)
619{
620 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
621 "StopListen(channel=%d)", channel);
622 CriticalSectionScoped cs(_shared->crit_sec());
623 if (!_shared->statistics().Initialized())
624 {
625 _shared->SetLastError(VE_NOT_INITED, kTraceError);
626 return -1;
627 }
pbos@webrtc.orgb3ada152013-08-07 17:57:36 +0000628 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
629 voe::Channel* channelPtr = ch.channel();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000630 if (channelPtr == NULL)
631 {
632 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
633 "SetLocalReceiver() failed to locate channel");
634 return -1;
635 }
636 return channelPtr->StopReceiving();
637}
638
639int VoEBaseImpl::StartPlayout(int channel)
640{
641 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
642 "StartPlayout(channel=%d)", channel);
643 CriticalSectionScoped cs(_shared->crit_sec());
644 if (!_shared->statistics().Initialized())
645 {
646 _shared->SetLastError(VE_NOT_INITED, kTraceError);
647 return -1;
648 }
pbos@webrtc.orgb3ada152013-08-07 17:57:36 +0000649 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
650 voe::Channel* channelPtr = ch.channel();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000651 if (channelPtr == NULL)
652 {
653 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
654 "StartPlayout() failed to locate channel");
655 return -1;
656 }
657 if (channelPtr->Playing())
658 {
659 return 0;
660 }
661 if (StartPlayout() != 0)
662 {
663 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
664 "StartPlayout() failed to start playout");
665 return -1;
666 }
667 return channelPtr->StartPlayout();
668}
669
670int VoEBaseImpl::StopPlayout(int channel)
671{
672 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
673 "StopPlayout(channel=%d)", channel);
674 CriticalSectionScoped cs(_shared->crit_sec());
675 if (!_shared->statistics().Initialized())
676 {
677 _shared->SetLastError(VE_NOT_INITED, kTraceError);
678 return -1;
679 }
pbos@webrtc.orgb3ada152013-08-07 17:57:36 +0000680 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
681 voe::Channel* channelPtr = ch.channel();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000682 if (channelPtr == NULL)
683 {
684 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
685 "StopPlayout() failed to locate channel");
686 return -1;
687 }
688 if (channelPtr->StopPlayout() != 0)
689 {
690 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
691 VoEId(_shared->instance_id(), -1),
692 "StopPlayout() failed to stop playout for channel %d", channel);
693 }
694 return StopPlayout();
695}
696
697int VoEBaseImpl::StartSend(int channel)
698{
699 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
700 "StartSend(channel=%d)", channel);
701 CriticalSectionScoped cs(_shared->crit_sec());
702 if (!_shared->statistics().Initialized())
703 {
704 _shared->SetLastError(VE_NOT_INITED, kTraceError);
705 return -1;
706 }
pbos@webrtc.orgb3ada152013-08-07 17:57:36 +0000707 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
708 voe::Channel* channelPtr = ch.channel();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000709 if (channelPtr == NULL)
710 {
711 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
712 "StartSend() failed to locate channel");
713 return -1;
714 }
715 if (channelPtr->Sending())
716 {
717 return 0;
718 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000719 if (StartSend() != 0)
720 {
721 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
722 "StartSend() failed to start recording");
723 return -1;
724 }
725 return channelPtr->StartSend();
726}
727
728int VoEBaseImpl::StopSend(int channel)
729{
730 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
731 "StopSend(channel=%d)", channel);
732 CriticalSectionScoped cs(_shared->crit_sec());
733 if (!_shared->statistics().Initialized())
734 {
735 _shared->SetLastError(VE_NOT_INITED, kTraceError);
736 return -1;
737 }
pbos@webrtc.orgb3ada152013-08-07 17:57:36 +0000738 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
739 voe::Channel* channelPtr = ch.channel();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000740 if (channelPtr == NULL)
741 {
742 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
743 "StopSend() failed to locate channel");
744 return -1;
745 }
746 if (channelPtr->StopSend() != 0)
747 {
748 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
749 VoEId(_shared->instance_id(), -1),
750 "StopSend() failed to stop sending for channel %d", channel);
751 }
752 return StopSend();
753}
754
755int VoEBaseImpl::GetVersion(char version[1024])
756{
757 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
758 "GetVersion(version=?)");
759 assert(kVoiceEngineVersionMaxMessageSize == 1024);
760
761 if (version == NULL)
762 {
763 _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError);
764 return (-1);
765 }
766
767 char versionBuf[kVoiceEngineVersionMaxMessageSize];
768 char* versionPtr = versionBuf;
769
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000770 int32_t len = 0;
771 int32_t accLen = 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000772
773 len = AddVoEVersion(versionPtr);
774 if (len == -1)
775 {
776 return -1;
777 }
778 versionPtr += len;
779 accLen += len;
780 assert(accLen < kVoiceEngineVersionMaxMessageSize);
781
782 len = AddBuildInfo(versionPtr);
783 if (len == -1)
784 {
785 return -1;
786 }
787 versionPtr += len;
788 accLen += len;
789 assert(accLen < kVoiceEngineVersionMaxMessageSize);
790
pwestin@webrtc.org912b7f72013-03-13 23:20:57 +0000791#ifdef WEBRTC_EXTERNAL_TRANSPORT
792 len = AddExternalTransportBuild(versionPtr);
793 if (len == -1)
794 {
795 return -1;
796 }
797 versionPtr += len;
798 accLen += len;
799 assert(accLen < kVoiceEngineVersionMaxMessageSize);
800#endif
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000801#ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT
802 len = AddExternalRecAndPlayoutBuild(versionPtr);
803 if (len == -1)
804 {
805 return -1;
806 }
807 versionPtr += len;
808 accLen += len;
809 assert(accLen < kVoiceEngineVersionMaxMessageSize);
810 #endif
811
812 memcpy(version, versionBuf, accLen);
813 version[accLen] = '\0';
814
815 // to avoid the truncation in the trace, split the string into parts
816 char partOfVersion[256];
817 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
818 VoEId(_shared->instance_id(), -1), "GetVersion() =>");
819 for (int partStart = 0; partStart < accLen;)
820 {
821 memset(partOfVersion, 0, sizeof(partOfVersion));
822 int partEnd = partStart + 180;
823 while (version[partEnd] != '\n' && version[partEnd] != '\0')
824 {
825 partEnd--;
826 }
827 if (partEnd < accLen)
828 {
829 memcpy(partOfVersion, &version[partStart], partEnd - partStart);
830 }
831 else
832 {
833 memcpy(partOfVersion, &version[partStart], accLen - partStart);
834 }
835 partStart = partEnd;
836 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
837 VoEId(_shared->instance_id(), -1), "%s", partOfVersion);
838 }
839
840 return 0;
841}
842
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000843int32_t VoEBaseImpl::AddBuildInfo(char* str) const
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000844{
andrew@webrtc.orgc7d73632013-12-04 17:00:44 +0000845 return sprintf(str, "Build: %s\n", BUILDINFO);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000846}
847
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000848int32_t VoEBaseImpl::AddVoEVersion(char* str) const
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000849{
850 return sprintf(str, "VoiceEngine 4.1.0\n");
851}
852
pwestin@webrtc.org912b7f72013-03-13 23:20:57 +0000853#ifdef WEBRTC_EXTERNAL_TRANSPORT
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000854int32_t VoEBaseImpl::AddExternalTransportBuild(char* str) const
pwestin@webrtc.org912b7f72013-03-13 23:20:57 +0000855{
856 return sprintf(str, "External transport build\n");
857}
858#endif
859
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000860#ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000861int32_t VoEBaseImpl::AddExternalRecAndPlayoutBuild(char* str) const
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000862{
863 return sprintf(str, "External recording and playout build\n");
864}
865#endif
866
867int VoEBaseImpl::LastError()
868{
869 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
870 "LastError()");
871 return (_shared->statistics().LastError());
872}
873
874
875int VoEBaseImpl::SetNetEQPlayoutMode(int channel, NetEqModes mode)
876{
877 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
878 "SetNetEQPlayoutMode(channel=%i, mode=%i)", channel, mode);
879 if (!_shared->statistics().Initialized())
880 {
881 _shared->SetLastError(VE_NOT_INITED, kTraceError);
882 return -1;
883 }
pbos@webrtc.orgb3ada152013-08-07 17:57:36 +0000884 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
885 voe::Channel* channelPtr = ch.channel();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000886 if (channelPtr == NULL)
887 {
888 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
889 "SetNetEQPlayoutMode() failed to locate channel");
890 return -1;
891 }
892 return channelPtr->SetNetEQPlayoutMode(mode);
893}
894
895int VoEBaseImpl::GetNetEQPlayoutMode(int channel, NetEqModes& mode)
896{
897 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
898 "GetNetEQPlayoutMode(channel=%i, mode=?)", channel);
899 if (!_shared->statistics().Initialized())
900 {
901 _shared->SetLastError(VE_NOT_INITED, kTraceError);
902 return -1;
903 }
pbos@webrtc.orgb3ada152013-08-07 17:57:36 +0000904 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
905 voe::Channel* channelPtr = ch.channel();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000906 if (channelPtr == NULL)
907 {
908 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
909 "GetNetEQPlayoutMode() failed to locate channel");
910 return -1;
911 }
912 return channelPtr->GetNetEQPlayoutMode(mode);
913}
914
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000915int VoEBaseImpl::SetOnHoldStatus(int channel, bool enable, OnHoldModes mode)
916{
917 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
918 "SetOnHoldStatus(channel=%d, enable=%d, mode=%d)", channel,
919 enable, mode);
920 if (!_shared->statistics().Initialized())
921 {
922 _shared->SetLastError(VE_NOT_INITED, kTraceError);
923 return -1;
924 }
pbos@webrtc.orgb3ada152013-08-07 17:57:36 +0000925 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
926 voe::Channel* channelPtr = ch.channel();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000927 if (channelPtr == NULL)
928 {
929 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
930 "SetOnHoldStatus() failed to locate channel");
931 return -1;
932 }
933 return channelPtr->SetOnHoldStatus(enable, mode);
934}
935
936int VoEBaseImpl::GetOnHoldStatus(int channel, bool& enabled, OnHoldModes& mode)
937{
938 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
939 "GetOnHoldStatus(channel=%d, enabled=?, mode=?)", channel);
940 if (!_shared->statistics().Initialized())
941 {
942 _shared->SetLastError(VE_NOT_INITED, kTraceError);
943 return -1;
944 }
pbos@webrtc.orgb3ada152013-08-07 17:57:36 +0000945 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
946 voe::Channel* channelPtr = ch.channel();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000947 if (channelPtr == NULL)
948 {
949 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
950 "GetOnHoldStatus() failed to locate channel");
951 return -1;
952 }
953 return channelPtr->GetOnHoldStatus(enabled, mode);
954}
955
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000956int32_t VoEBaseImpl::StartPlayout()
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000957{
958 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
959 "VoEBaseImpl::StartPlayout()");
960 if (_shared->audio_device()->Playing())
961 {
962 return 0;
963 }
964 if (!_shared->ext_playout())
965 {
966 if (_shared->audio_device()->InitPlayout() != 0)
967 {
968 WEBRTC_TRACE(kTraceError, kTraceVoice,
969 VoEId(_shared->instance_id(), -1),
970 "StartPlayout() failed to initialize playout");
971 return -1;
972 }
973 if (_shared->audio_device()->StartPlayout() != 0)
974 {
975 WEBRTC_TRACE(kTraceError, kTraceVoice,
976 VoEId(_shared->instance_id(), -1),
977 "StartPlayout() failed to start playout");
978 return -1;
979 }
980 }
981 return 0;
982}
983
pbos@webrtc.orgb3ada152013-08-07 17:57:36 +0000984int32_t VoEBaseImpl::StopPlayout() {
985 WEBRTC_TRACE(kTraceInfo,
986 kTraceVoice,
987 VoEId(_shared->instance_id(), -1),
988 "VoEBaseImpl::StopPlayout()");
989 // Stop audio-device playing if no channel is playing out
xians@webrtc.org3d553d42013-10-17 16:15:34 +0000990 if (_shared->NumOfPlayingChannels() == 0) {
pbos@webrtc.orgb3ada152013-08-07 17:57:36 +0000991 if (_shared->audio_device()->StopPlayout() != 0) {
992 _shared->SetLastError(VE_CANNOT_STOP_PLAYOUT,
993 kTraceError,
994 "StopPlayout() failed to stop playout");
995 return -1;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000996 }
pbos@webrtc.orgb3ada152013-08-07 17:57:36 +0000997 }
998 return 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000999}
1000
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001001int32_t VoEBaseImpl::StartSend()
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001002{
1003 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
1004 "VoEBaseImpl::StartSend()");
1005 if (_shared->audio_device()->Recording())
1006 {
1007 return 0;
1008 }
1009 if (!_shared->ext_recording())
1010 {
1011 if (_shared->audio_device()->InitRecording() != 0)
1012 {
1013 WEBRTC_TRACE(kTraceError, kTraceVoice,
1014 VoEId(_shared->instance_id(), -1),
1015 "StartSend() failed to initialize recording");
1016 return -1;
1017 }
1018 if (_shared->audio_device()->StartRecording() != 0)
1019 {
1020 WEBRTC_TRACE(kTraceError, kTraceVoice,
1021 VoEId(_shared->instance_id(), -1),
1022 "StartSend() failed to start recording");
1023 return -1;
1024 }
1025 }
1026
1027 return 0;
1028}
1029
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001030int32_t VoEBaseImpl::StopSend()
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001031{
1032 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
1033 "VoEBaseImpl::StopSend()");
1034
1035 if (_shared->NumOfSendingChannels() == 0 &&
1036 !_shared->transmit_mixer()->IsRecordingMic())
1037 {
1038 // Stop audio-device recording if no channel is recording
1039 if (_shared->audio_device()->StopRecording() != 0)
1040 {
1041 _shared->SetLastError(VE_CANNOT_STOP_RECORDING, kTraceError,
1042 "StopSend() failed to stop recording");
1043 return -1;
1044 }
1045 _shared->transmit_mixer()->StopSend();
1046 }
1047
1048 return 0;
1049}
1050
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001051int32_t VoEBaseImpl::TerminateInternal()
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001052{
1053 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
1054 "VoEBaseImpl::TerminateInternal()");
1055
1056 // Delete any remaining channel objects
pbos@webrtc.orgb3ada152013-08-07 17:57:36 +00001057 _shared->channel_manager().DestroyAllChannels();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001058
1059 if (_shared->process_thread())
1060 {
1061 if (_shared->audio_device())
1062 {
1063 if (_shared->process_thread()->
1064 DeRegisterModule(_shared->audio_device()) != 0)
1065 {
1066 _shared->SetLastError(VE_THREAD_ERROR, kTraceError,
1067 "TerminateInternal() failed to deregister ADM");
1068 }
1069 }
1070 if (_shared->process_thread()->Stop() != 0)
1071 {
1072 _shared->SetLastError(VE_THREAD_ERROR, kTraceError,
1073 "TerminateInternal() failed to stop module process thread");
1074 }
1075 }
1076
andrew@webrtc.orgb79627b2013-03-05 01:12:49 +00001077 if (_shared->audio_device())
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001078 {
1079 if (_shared->audio_device()->StopPlayout() != 0)
1080 {
1081 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
1082 "TerminateInternal() failed to stop playout");
1083 }
1084 if (_shared->audio_device()->StopRecording() != 0)
1085 {
1086 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
1087 "TerminateInternal() failed to stop recording");
1088 }
1089 if (_shared->audio_device()->RegisterEventObserver(NULL) != 0) {
1090 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
1091 "TerminateInternal() failed to de-register event observer "
1092 "for the ADM");
1093 }
1094 if (_shared->audio_device()->RegisterAudioCallback(NULL) != 0) {
1095 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
1096 "TerminateInternal() failed to de-register audio callback "
1097 "for the ADM");
1098 }
1099 if (_shared->audio_device()->Terminate() != 0)
1100 {
1101 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
1102 "TerminateInternal() failed to terminate the ADM");
1103 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001104 _shared->set_audio_device(NULL);
1105 }
1106
andrew@webrtc.orgb79627b2013-03-05 01:12:49 +00001107 if (_shared->audio_processing()) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001108 _shared->set_audio_processing(NULL);
1109 }
1110
1111 return _shared->statistics().SetUnInitialized();
1112}
1113
xians@webrtc.org0e6fa8c2013-07-31 16:27:42 +00001114int VoEBaseImpl::ProcessRecordedDataWithAPM(
1115 const int voe_channels[],
1116 int number_of_voe_channels,
1117 const void* audio_data,
1118 uint32_t sample_rate,
1119 uint8_t number_of_channels,
1120 uint32_t number_of_frames,
1121 uint32_t audio_delay_milliseconds,
1122 int32_t clock_drift,
andrew@webrtc.orgad065d02014-02-18 20:24:56 +00001123 uint32_t volume,
xians@webrtc.org0e6fa8c2013-07-31 16:27:42 +00001124 bool key_pressed) {
1125 assert(_shared->transmit_mixer() != NULL);
1126 assert(_shared->audio_device() != NULL);
1127
xians@webrtc.org0e6fa8c2013-07-31 16:27:42 +00001128 uint32_t max_volume = 0;
andrew@webrtc.orgad065d02014-02-18 20:24:56 +00001129 uint16_t voe_mic_level = 0;
andrew@webrtc.org22470b52014-01-11 01:25:53 +00001130 // Check for zero to skip this calculation; the consumer may use this to
1131 // indicate no volume is available.
andrew@webrtc.orgad065d02014-02-18 20:24:56 +00001132 if (volume != 0) {
xians@webrtc.org0e6fa8c2013-07-31 16:27:42 +00001133 // Scale from ADM to VoE level range
1134 if (_shared->audio_device()->MaxMicrophoneVolume(&max_volume) == 0) {
1135 if (max_volume) {
andrew@webrtc.orgad065d02014-02-18 20:24:56 +00001136 voe_mic_level = static_cast<uint16_t>(
1137 (volume * kMaxVolumeLevel +
xians@webrtc.org0e6fa8c2013-07-31 16:27:42 +00001138 static_cast<int>(max_volume / 2)) / max_volume);
1139 }
1140 }
andrew@webrtc.orgad065d02014-02-18 20:24:56 +00001141 // We learned that on certain systems (e.g Linux) the voe_mic_level
xians@webrtc.org0e6fa8c2013-07-31 16:27:42 +00001142 // can be greater than the maxVolumeLevel therefore
andrew@webrtc.orgad065d02014-02-18 20:24:56 +00001143 // we are going to cap the voe_mic_level to the maxVolumeLevel
1144 // and change the maxVolume to volume if it turns out that
1145 // the voe_mic_level is indeed greater than the maxVolumeLevel.
1146 if (voe_mic_level > kMaxVolumeLevel) {
1147 voe_mic_level = kMaxVolumeLevel;
1148 max_volume = volume;
xians@webrtc.org0e6fa8c2013-07-31 16:27:42 +00001149 }
1150 }
1151
xians@webrtc.org0e6fa8c2013-07-31 16:27:42 +00001152 // Perform channel-independent operations
1153 // (APM, mix with file, record to file, mute, etc.)
1154 _shared->transmit_mixer()->PrepareDemux(
1155 audio_data, number_of_frames, number_of_channels, sample_rate,
1156 static_cast<uint16_t>(audio_delay_milliseconds), clock_drift,
andrew@webrtc.orgad065d02014-02-18 20:24:56 +00001157 voe_mic_level, key_pressed);
xians@webrtc.org0e6fa8c2013-07-31 16:27:42 +00001158
1159 // Copy the audio frame to each sending channel and perform
1160 // channel-dependent operations (file mixing, mute, etc.), encode and
1161 // packetize+transmit the RTP packet. When |number_of_voe_channels| == 0,
1162 // do the operations on all the existing VoE channels; otherwise the
1163 // operations will be done on specific channels.
1164 if (number_of_voe_channels == 0) {
1165 _shared->transmit_mixer()->DemuxAndMix();
1166 _shared->transmit_mixer()->EncodeAndSend();
1167 } else {
1168 _shared->transmit_mixer()->DemuxAndMix(voe_channels,
1169 number_of_voe_channels);
1170 _shared->transmit_mixer()->EncodeAndSend(voe_channels,
1171 number_of_voe_channels);
1172 }
1173
xians@webrtc.org0e6fa8c2013-07-31 16:27:42 +00001174 // Scale from VoE to ADM level range.
1175 uint32_t new_voe_mic_level = _shared->transmit_mixer()->CaptureLevel();
1176
andrew@webrtc.orgad065d02014-02-18 20:24:56 +00001177 if (new_voe_mic_level != voe_mic_level) {
xians@webrtc.org0e6fa8c2013-07-31 16:27:42 +00001178 // Return the new volume if AGC has changed the volume.
1179 return static_cast<int>(
1180 (new_voe_mic_level * max_volume +
1181 static_cast<int>(kMaxVolumeLevel / 2)) / kMaxVolumeLevel);
1182 }
1183
1184 // Return 0 to indicate no change on the volume.
1185 return 0;
1186}
1187
xians@webrtc.org91d88e12014-04-14 10:50:37 +00001188void VoEBaseImpl::GetPlayoutData(int sample_rate, int number_of_channels,
1189 int number_of_frames, bool feed_data_to_apm,
1190 void* audio_data) {
1191 assert(_shared->output_mixer() != NULL);
1192
1193 // TODO(andrew): if the device is running in mono, we should tell the mixer
1194 // here so that it will only request mono from AudioCodingModule.
1195 // Perform mixing of all active participants (channel-based mixing)
1196 _shared->output_mixer()->MixActiveChannels();
1197
1198 // Additional operations on the combined signal
1199 _shared->output_mixer()->DoOperationsOnCombinedSignal(feed_data_to_apm);
1200
1201 // Retrieve the final output mix (resampled to match the ADM)
1202 _shared->output_mixer()->GetMixedAudio(sample_rate, number_of_channels,
1203 &_audioFrame);
1204
1205 assert(number_of_frames == _audioFrame.samples_per_channel_);
1206 assert(sample_rate == _audioFrame.sample_rate_hz_);
1207
1208 // Deliver audio (PCM) samples to the ADM
1209 memcpy(audio_data, _audioFrame.data_,
1210 sizeof(int16_t) * number_of_frames * number_of_channels);
1211}
1212
pbos@webrtc.org3b89e102013-07-03 15:12:26 +00001213} // namespace webrtc