2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
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.
11 #include "webrtc/voice_engine/voe_base_impl.h"
13 #include "webrtc/common.h"
14 #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"
31 VoEBase* VoEBase::GetInterface(VoiceEngine* voiceEngine)
33 if (NULL == voiceEngine)
37 VoiceEngineImpl* s = static_cast<VoiceEngineImpl*>(voiceEngine);
42 VoEBaseImpl::VoEBaseImpl(voe::SharedData* shared) :
43 _voiceEngineObserverPtr(NULL),
44 _callbackCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
45 _voiceEngineObserver(false), _shared(shared)
47 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
48 "VoEBaseImpl() - ctor");
51 VoEBaseImpl::~VoEBaseImpl()
53 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
54 "~VoEBaseImpl() - dtor");
58 delete &_callbackCritSect;
61 void VoEBaseImpl::OnErrorIsReported(ErrorCode error)
63 CriticalSectionScoped cs(&_callbackCritSect);
64 if (_voiceEngineObserver)
66 if (_voiceEngineObserverPtr)
69 if (error == AudioDeviceObserver::kRecordingError)
71 errCode = VE_RUNTIME_REC_ERROR;
72 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
73 VoEId(_shared->instance_id(), -1),
74 "VoEBaseImpl::OnErrorIsReported() => VE_RUNTIME_REC_ERROR");
76 else if (error == AudioDeviceObserver::kPlayoutError)
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");
84 // Deliver callback (-1 <=> no channel dependency)
85 _voiceEngineObserverPtr->CallbackOnError(-1, errCode);
90 void VoEBaseImpl::OnWarningIsReported(WarningCode warning)
92 CriticalSectionScoped cs(&_callbackCritSect);
93 if (_voiceEngineObserver)
95 if (_voiceEngineObserverPtr)
98 if (warning == AudioDeviceObserver::kRecordingWarning)
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");
106 else if (warning == AudioDeviceObserver::kPlayoutWarning)
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");
114 // Deliver callback (-1 <=> no channel dependency)
115 _voiceEngineObserverPtr->CallbackOnError(-1, warningCode);
120 int32_t VoEBaseImpl::RecordedDataIsAvailable(
121 const void* audioSamples,
123 uint8_t nBytesPerSample,
125 uint32_t samplesPerSec,
126 uint32_t totalDelayMS,
130 uint32_t& newMicLevel)
132 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_shared->instance_id(), -1),
133 "VoEBaseImpl::RecordedDataIsAvailable(nSamples=%u, "
134 "nBytesPerSample=%u, nChannels=%u, samplesPerSec=%u, "
135 "totalDelayMS=%u, clockDrift=%d, micLevel=%u)",
136 nSamples, nBytesPerSample, nChannels, samplesPerSec,
137 totalDelayMS, clockDrift, micLevel);
138 newMicLevel = static_cast<uint32_t>(ProcessRecordedDataWithAPM(
139 NULL, 0, audioSamples, samplesPerSec, nChannels, nSamples,
140 totalDelayMS, clockDrift, micLevel, keyPressed));
145 int32_t VoEBaseImpl::NeedMorePlayData(
147 uint8_t nBytesPerSample,
149 uint32_t samplesPerSec,
151 uint32_t& nSamplesOut)
153 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);
158 GetPlayoutData(static_cast<int>(samplesPerSec),
159 static_cast<int>(nChannels),
160 static_cast<int>(nSamples), true, audioSamples);
162 nSamplesOut = _audioFrame.samples_per_channel_;
167 int VoEBaseImpl::OnDataAvailable(const int voe_channels[],
168 int number_of_voe_channels,
169 const int16_t* audio_data,
171 int number_of_channels,
172 int number_of_frames,
173 int audio_delay_milliseconds,
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, "
180 "audio_delay_milliseconds=%d, volume=%d, "
181 "key_pressed=%d, need_audio_processing=%d)",
182 number_of_voe_channels, sample_rate, number_of_channels,
183 number_of_frames, audio_delay_milliseconds, volume,
184 key_pressed, need_audio_processing);
185 if (number_of_voe_channels == 0)
188 if (need_audio_processing) {
189 return ProcessRecordedDataWithAPM(
190 voe_channels, number_of_voe_channels, audio_data, sample_rate,
191 number_of_channels, number_of_frames, audio_delay_milliseconds,
192 0, volume, key_pressed);
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) {
198 // 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.
201 PushCaptureData(voe_channels[i], audio_data, 16, sample_rate,
202 number_of_channels, number_of_frames);
205 // Return 0 to indicate no need to change the volume.
209 void 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) {
213 PushCaptureData(voe_channel, audio_data, bits_per_sample, sample_rate,
214 number_of_channels, number_of_frames);
217 void 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) {
221 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(voe_channel);
222 voe::Channel* channel_ptr = ch.channel();
226 if (channel_ptr->Sending()) {
227 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();
234 void VoEBaseImpl::PullRenderData(int bits_per_sample, int sample_rate,
235 int number_of_channels, int number_of_frames,
237 assert(bits_per_sample == 16);
238 assert(number_of_frames == static_cast<int>(sample_rate / 100));
240 GetPlayoutData(sample_rate, number_of_channels, number_of_frames, false,
244 int VoEBaseImpl::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
246 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
247 "RegisterVoiceEngineObserver(observer=0x%d)", &observer);
248 CriticalSectionScoped cs(&_callbackCritSect);
249 if (_voiceEngineObserverPtr)
251 _shared->SetLastError(VE_INVALID_OPERATION, kTraceError,
252 "RegisterVoiceEngineObserver() observer already enabled");
256 // Register the observer in all active channels
257 for (voe::ChannelManager::Iterator it(&_shared->channel_manager());
260 it.GetChannel()->RegisterVoiceEngineObserver(observer);
263 _shared->transmit_mixer()->RegisterVoiceEngineObserver(observer);
265 _voiceEngineObserverPtr = &observer;
266 _voiceEngineObserver = true;
271 int VoEBaseImpl::DeRegisterVoiceEngineObserver()
273 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
274 "DeRegisterVoiceEngineObserver()");
275 CriticalSectionScoped cs(&_callbackCritSect);
276 if (!_voiceEngineObserverPtr)
278 _shared->SetLastError(VE_INVALID_OPERATION, kTraceError,
279 "DeRegisterVoiceEngineObserver() observer already disabled");
283 _voiceEngineObserver = false;
284 _voiceEngineObserverPtr = NULL;
286 // Deregister the observer in all active channels
287 for (voe::ChannelManager::Iterator it(&_shared->channel_manager());
290 it.GetChannel()->DeRegisterVoiceEngineObserver();
296 int VoEBaseImpl::Init(AudioDeviceModule* external_adm,
297 AudioProcessing* audioproc)
299 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
300 "Init(external_adm=0x%p)", external_adm);
301 CriticalSectionScoped cs(_shared->crit_sec());
305 if (_shared->statistics().Initialized())
310 if (_shared->process_thread())
312 if (_shared->process_thread()->Start() != 0)
314 _shared->SetLastError(VE_THREAD_ERROR, kTraceError,
315 "Init() failed to start module process thread");
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)
324 // Create the internal ADM implementation.
325 _shared->set_audio_device(AudioDeviceModuleImpl::Create(
326 VoEId(_shared->instance_id(), -1), _shared->audio_device_layer()));
328 if (_shared->audio_device() == NULL)
330 _shared->SetLastError(VE_NO_MEMORY, kTraceCritical,
331 "Init() failed to create the ADM");
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");
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)
348 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
349 "Init() failed to register the ADM");
353 bool available(false);
355 // --------------------
356 // Reinitialize the ADM
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");
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");
370 // ADM initialization
371 if (_shared->audio_device()->Init() != 0)
373 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
374 "Init() failed to initialize the ADM");
378 // Initialize the default speaker
379 if (_shared->audio_device()->SetPlayoutDevice(
380 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0)
382 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceInfo,
383 "Init() failed to set the default output device");
385 if (_shared->audio_device()->InitSpeaker() != 0)
387 _shared->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceInfo,
388 "Init() failed to initialize the speaker");
391 // Initialize the default microphone
392 if (_shared->audio_device()->SetRecordingDevice(
393 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0)
395 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceInfo,
396 "Init() failed to set the default input device");
398 if (_shared->audio_device()->InitMicrophone() != 0)
400 _shared->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceInfo,
401 "Init() failed to initialize the microphone");
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");
409 if (_shared->audio_device()->SetStereoPlayout(available) != 0)
411 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
412 "Init() failed to set mono/stereo playout mode");
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.
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)
425 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
426 "Init() failed to set mono/stereo recording mode");
430 audioproc = AudioProcessing::Create(VoEId(_shared->instance_id(), -1));
432 LOG(LS_ERROR) << "Failed to create AudioProcessing.";
433 _shared->SetLastError(VE_NO_MEMORY);
437 _shared->set_audio_processing(audioproc);
439 // Set the error state for any failures in this block.
440 _shared->SetLastError(VE_APM_ERROR);
441 // Configure AudioProcessing components.
442 if (audioproc->high_pass_filter()->Enable(true) != 0) {
443 LOG_FERR1(LS_ERROR, high_pass_filter()->Enable, true);
446 if (audioproc->echo_cancellation()->enable_drift_compensation(false) != 0) {
447 LOG_FERR1(LS_ERROR, enable_drift_compensation, false);
450 if (audioproc->noise_suppression()->set_level(kDefaultNsMode) != 0) {
451 LOG_FERR1(LS_ERROR, noise_suppression()->set_level, kDefaultNsMode);
454 GainControl* agc = audioproc->gain_control();
455 if (agc->set_analog_level_limits(kMinVolumeLevel, kMaxVolumeLevel) != 0) {
456 LOG_FERR2(LS_ERROR, agc->set_analog_level_limits, kMinVolumeLevel,
460 if (agc->set_mode(kDefaultAgcMode) != 0) {
461 LOG_FERR1(LS_ERROR, agc->set_mode, kDefaultAgcMode);
464 if (agc->Enable(kDefaultAgcState) != 0) {
465 LOG_FERR1(LS_ERROR, agc->Enable, kDefaultAgcState);
468 _shared->SetLastError(0); // Clear error state.
470 #ifdef WEBRTC_VOICE_ENGINE_AGC
471 bool agc_enabled = agc->mode() == GainControl::kAdaptiveAnalog &&
473 if (_shared->audio_device()->SetAGC(agc_enabled) != 0) {
474 LOG_FERR1(LS_ERROR, audio_device()->SetAGC, agc_enabled);
475 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR);
476 // TODO(ajm): No error return here due to
477 // https://code.google.com/p/webrtc/issues/detail?id=1464
481 return _shared->statistics().SetInitialized();
484 int VoEBaseImpl::Terminate()
486 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
488 CriticalSectionScoped cs(_shared->crit_sec());
489 return TerminateInternal();
492 int VoEBaseImpl::CreateChannel() {
493 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
495 CriticalSectionScoped cs(_shared->crit_sec());
496 if (!_shared->statistics().Initialized()) {
497 _shared->SetLastError(VE_NOT_INITED, kTraceError);
501 voe::ChannelOwner channel_owner = _shared->channel_manager().CreateChannel();
503 return InitializeChannel(&channel_owner);
506 int VoEBaseImpl::CreateChannel(const Config& config) {
507 CriticalSectionScoped cs(_shared->crit_sec());
508 if (!_shared->statistics().Initialized()) {
509 _shared->SetLastError(VE_NOT_INITED, kTraceError);
512 voe::ChannelOwner channel_owner = _shared->channel_manager().CreateChannel(
514 return InitializeChannel(&channel_owner);
517 int VoEBaseImpl::InitializeChannel(voe::ChannelOwner* channel_owner)
519 if (channel_owner->channel()->SetEngineInformation(
520 _shared->statistics(),
521 *_shared->output_mixer(),
522 *_shared->transmit_mixer(),
523 *_shared->process_thread(),
524 *_shared->audio_device(),
525 _voiceEngineObserverPtr,
526 &_callbackCritSect) != 0) {
527 _shared->SetLastError(
528 VE_CHANNEL_NOT_CREATED,
530 "CreateChannel() failed to associate engine and channel."
531 " Destroying channel.");
532 _shared->channel_manager()
533 .DestroyChannel(channel_owner->channel()->ChannelId());
535 } else if (channel_owner->channel()->Init() != 0) {
536 _shared->SetLastError(
537 VE_CHANNEL_NOT_CREATED,
539 "CreateChannel() failed to initialize channel. Destroying"
541 _shared->channel_manager()
542 .DestroyChannel(channel_owner->channel()->ChannelId());
546 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
547 VoEId(_shared->instance_id(), -1),
548 "CreateChannel() => %d", channel_owner->channel()->ChannelId());
549 return channel_owner->channel()->ChannelId();
552 int VoEBaseImpl::DeleteChannel(int channel)
554 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
555 "DeleteChannel(channel=%d)", channel);
556 CriticalSectionScoped cs(_shared->crit_sec());
558 if (!_shared->statistics().Initialized())
560 _shared->SetLastError(VE_NOT_INITED, kTraceError);
565 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
566 voe::Channel* channelPtr = ch.channel();
567 if (channelPtr == NULL)
569 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
570 "DeleteChannel() failed to locate channel");
575 _shared->channel_manager().DestroyChannel(channel);
582 if (StopPlayout() != 0)
590 int VoEBaseImpl::StartReceive(int channel)
592 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
593 "StartReceive(channel=%d)", channel);
594 CriticalSectionScoped cs(_shared->crit_sec());
595 if (!_shared->statistics().Initialized())
597 _shared->SetLastError(VE_NOT_INITED, kTraceError);
600 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
601 voe::Channel* channelPtr = ch.channel();
602 if (channelPtr == NULL)
604 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
605 "StartReceive() failed to locate channel");
608 return channelPtr->StartReceiving();
611 int VoEBaseImpl::StopReceive(int channel)
613 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
614 "StopListen(channel=%d)", channel);
615 CriticalSectionScoped cs(_shared->crit_sec());
616 if (!_shared->statistics().Initialized())
618 _shared->SetLastError(VE_NOT_INITED, kTraceError);
621 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
622 voe::Channel* channelPtr = ch.channel();
623 if (channelPtr == NULL)
625 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
626 "SetLocalReceiver() failed to locate channel");
629 return channelPtr->StopReceiving();
632 int VoEBaseImpl::StartPlayout(int channel)
634 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
635 "StartPlayout(channel=%d)", channel);
636 CriticalSectionScoped cs(_shared->crit_sec());
637 if (!_shared->statistics().Initialized())
639 _shared->SetLastError(VE_NOT_INITED, kTraceError);
642 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
643 voe::Channel* channelPtr = ch.channel();
644 if (channelPtr == NULL)
646 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
647 "StartPlayout() failed to locate channel");
650 if (channelPtr->Playing())
654 if (StartPlayout() != 0)
656 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
657 "StartPlayout() failed to start playout");
660 return channelPtr->StartPlayout();
663 int VoEBaseImpl::StopPlayout(int channel)
665 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
666 "StopPlayout(channel=%d)", channel);
667 CriticalSectionScoped cs(_shared->crit_sec());
668 if (!_shared->statistics().Initialized())
670 _shared->SetLastError(VE_NOT_INITED, kTraceError);
673 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
674 voe::Channel* channelPtr = ch.channel();
675 if (channelPtr == NULL)
677 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
678 "StopPlayout() failed to locate channel");
681 if (channelPtr->StopPlayout() != 0)
683 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
684 VoEId(_shared->instance_id(), -1),
685 "StopPlayout() failed to stop playout for channel %d", channel);
687 return StopPlayout();
690 int VoEBaseImpl::StartSend(int channel)
692 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
693 "StartSend(channel=%d)", channel);
694 CriticalSectionScoped cs(_shared->crit_sec());
695 if (!_shared->statistics().Initialized())
697 _shared->SetLastError(VE_NOT_INITED, kTraceError);
700 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
701 voe::Channel* channelPtr = ch.channel();
702 if (channelPtr == NULL)
704 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
705 "StartSend() failed to locate channel");
708 if (channelPtr->Sending())
712 if (StartSend() != 0)
714 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
715 "StartSend() failed to start recording");
718 return channelPtr->StartSend();
721 int VoEBaseImpl::StopSend(int channel)
723 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
724 "StopSend(channel=%d)", channel);
725 CriticalSectionScoped cs(_shared->crit_sec());
726 if (!_shared->statistics().Initialized())
728 _shared->SetLastError(VE_NOT_INITED, kTraceError);
731 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
732 voe::Channel* channelPtr = ch.channel();
733 if (channelPtr == NULL)
735 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
736 "StopSend() failed to locate channel");
739 if (channelPtr->StopSend() != 0)
741 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
742 VoEId(_shared->instance_id(), -1),
743 "StopSend() failed to stop sending for channel %d", channel);
748 int VoEBaseImpl::GetVersion(char version[1024])
750 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
751 "GetVersion(version=?)");
752 assert(kVoiceEngineVersionMaxMessageSize == 1024);
756 _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError);
760 char versionBuf[kVoiceEngineVersionMaxMessageSize];
761 char* versionPtr = versionBuf;
766 len = AddVoEVersion(versionPtr);
773 assert(accLen < kVoiceEngineVersionMaxMessageSize);
775 len = AddBuildInfo(versionPtr);
782 assert(accLen < kVoiceEngineVersionMaxMessageSize);
784 #ifdef WEBRTC_EXTERNAL_TRANSPORT
785 len = AddExternalTransportBuild(versionPtr);
792 assert(accLen < kVoiceEngineVersionMaxMessageSize);
794 #ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT
795 len = AddExternalRecAndPlayoutBuild(versionPtr);
802 assert(accLen < kVoiceEngineVersionMaxMessageSize);
805 memcpy(version, versionBuf, accLen);
806 version[accLen] = '\0';
808 // to avoid the truncation in the trace, split the string into parts
809 char partOfVersion[256];
810 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
811 VoEId(_shared->instance_id(), -1), "GetVersion() =>");
812 for (int partStart = 0; partStart < accLen;)
814 memset(partOfVersion, 0, sizeof(partOfVersion));
815 int partEnd = partStart + 180;
816 while (version[partEnd] != '\n' && version[partEnd] != '\0')
820 if (partEnd < accLen)
822 memcpy(partOfVersion, &version[partStart], partEnd - partStart);
826 memcpy(partOfVersion, &version[partStart], accLen - partStart);
829 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
830 VoEId(_shared->instance_id(), -1), "%s", partOfVersion);
836 int32_t VoEBaseImpl::AddBuildInfo(char* str) const
838 return sprintf(str, "Build: %s\n", BUILDINFO);
841 int32_t VoEBaseImpl::AddVoEVersion(char* str) const
843 return sprintf(str, "VoiceEngine 4.1.0\n");
846 #ifdef WEBRTC_EXTERNAL_TRANSPORT
847 int32_t VoEBaseImpl::AddExternalTransportBuild(char* str) const
849 return sprintf(str, "External transport build\n");
853 #ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT
854 int32_t VoEBaseImpl::AddExternalRecAndPlayoutBuild(char* str) const
856 return sprintf(str, "External recording and playout build\n");
860 int VoEBaseImpl::LastError()
862 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
864 return (_shared->statistics().LastError());
867 int32_t VoEBaseImpl::StartPlayout()
869 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
870 "VoEBaseImpl::StartPlayout()");
871 if (_shared->audio_device()->Playing())
875 if (!_shared->ext_playout())
877 if (_shared->audio_device()->InitPlayout() != 0)
879 WEBRTC_TRACE(kTraceError, kTraceVoice,
880 VoEId(_shared->instance_id(), -1),
881 "StartPlayout() failed to initialize playout");
884 if (_shared->audio_device()->StartPlayout() != 0)
886 WEBRTC_TRACE(kTraceError, kTraceVoice,
887 VoEId(_shared->instance_id(), -1),
888 "StartPlayout() failed to start playout");
895 int32_t VoEBaseImpl::StopPlayout() {
896 WEBRTC_TRACE(kTraceInfo,
898 VoEId(_shared->instance_id(), -1),
899 "VoEBaseImpl::StopPlayout()");
900 // Stop audio-device playing if no channel is playing out
901 if (_shared->NumOfPlayingChannels() == 0) {
902 if (_shared->audio_device()->StopPlayout() != 0) {
903 _shared->SetLastError(VE_CANNOT_STOP_PLAYOUT,
905 "StopPlayout() failed to stop playout");
912 int32_t VoEBaseImpl::StartSend()
914 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
915 "VoEBaseImpl::StartSend()");
916 if (_shared->audio_device()->Recording())
920 if (!_shared->ext_recording())
922 if (_shared->audio_device()->InitRecording() != 0)
924 WEBRTC_TRACE(kTraceError, kTraceVoice,
925 VoEId(_shared->instance_id(), -1),
926 "StartSend() failed to initialize recording");
929 if (_shared->audio_device()->StartRecording() != 0)
931 WEBRTC_TRACE(kTraceError, kTraceVoice,
932 VoEId(_shared->instance_id(), -1),
933 "StartSend() failed to start recording");
941 int32_t VoEBaseImpl::StopSend()
943 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
944 "VoEBaseImpl::StopSend()");
946 if (_shared->NumOfSendingChannels() == 0 &&
947 !_shared->transmit_mixer()->IsRecordingMic())
949 // Stop audio-device recording if no channel is recording
950 if (_shared->audio_device()->StopRecording() != 0)
952 _shared->SetLastError(VE_CANNOT_STOP_RECORDING, kTraceError,
953 "StopSend() failed to stop recording");
956 _shared->transmit_mixer()->StopSend();
962 int32_t VoEBaseImpl::TerminateInternal()
964 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
965 "VoEBaseImpl::TerminateInternal()");
967 // Delete any remaining channel objects
968 _shared->channel_manager().DestroyAllChannels();
970 if (_shared->process_thread())
972 if (_shared->audio_device())
974 if (_shared->process_thread()->
975 DeRegisterModule(_shared->audio_device()) != 0)
977 _shared->SetLastError(VE_THREAD_ERROR, kTraceError,
978 "TerminateInternal() failed to deregister ADM");
981 if (_shared->process_thread()->Stop() != 0)
983 _shared->SetLastError(VE_THREAD_ERROR, kTraceError,
984 "TerminateInternal() failed to stop module process thread");
988 if (_shared->audio_device())
990 if (_shared->audio_device()->StopPlayout() != 0)
992 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
993 "TerminateInternal() failed to stop playout");
995 if (_shared->audio_device()->StopRecording() != 0)
997 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
998 "TerminateInternal() failed to stop recording");
1000 if (_shared->audio_device()->RegisterEventObserver(NULL) != 0) {
1001 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
1002 "TerminateInternal() failed to de-register event observer "
1005 if (_shared->audio_device()->RegisterAudioCallback(NULL) != 0) {
1006 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
1007 "TerminateInternal() failed to de-register audio callback "
1010 if (_shared->audio_device()->Terminate() != 0)
1012 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
1013 "TerminateInternal() failed to terminate the ADM");
1015 _shared->set_audio_device(NULL);
1018 if (_shared->audio_processing()) {
1019 _shared->set_audio_processing(NULL);
1022 return _shared->statistics().SetUnInitialized();
1025 int VoEBaseImpl::ProcessRecordedDataWithAPM(
1026 const int voe_channels[],
1027 int number_of_voe_channels,
1028 const void* audio_data,
1029 uint32_t sample_rate,
1030 uint8_t number_of_channels,
1031 uint32_t number_of_frames,
1032 uint32_t audio_delay_milliseconds,
1033 int32_t clock_drift,
1036 assert(_shared->transmit_mixer() != NULL);
1037 assert(_shared->audio_device() != NULL);
1039 uint32_t max_volume = 0;
1040 uint16_t voe_mic_level = 0;
1041 // Check for zero to skip this calculation; the consumer may use this to
1042 // indicate no volume is available.
1044 // Scale from ADM to VoE level range
1045 if (_shared->audio_device()->MaxMicrophoneVolume(&max_volume) == 0) {
1047 voe_mic_level = static_cast<uint16_t>(
1048 (volume * kMaxVolumeLevel +
1049 static_cast<int>(max_volume / 2)) / max_volume);
1052 // We learned that on certain systems (e.g Linux) the voe_mic_level
1053 // can be greater than the maxVolumeLevel therefore
1054 // we are going to cap the voe_mic_level to the maxVolumeLevel
1055 // and change the maxVolume to volume if it turns out that
1056 // the voe_mic_level is indeed greater than the maxVolumeLevel.
1057 if (voe_mic_level > kMaxVolumeLevel) {
1058 voe_mic_level = kMaxVolumeLevel;
1059 max_volume = volume;
1063 // Perform channel-independent operations
1064 // (APM, mix with file, record to file, mute, etc.)
1065 _shared->transmit_mixer()->PrepareDemux(
1066 audio_data, number_of_frames, number_of_channels, sample_rate,
1067 static_cast<uint16_t>(audio_delay_milliseconds), clock_drift,
1068 voe_mic_level, key_pressed);
1070 // Copy the audio frame to each sending channel and perform
1071 // channel-dependent operations (file mixing, mute, etc.), encode and
1072 // packetize+transmit the RTP packet. When |number_of_voe_channels| == 0,
1073 // do the operations on all the existing VoE channels; otherwise the
1074 // operations will be done on specific channels.
1075 if (number_of_voe_channels == 0) {
1076 _shared->transmit_mixer()->DemuxAndMix();
1077 _shared->transmit_mixer()->EncodeAndSend();
1079 _shared->transmit_mixer()->DemuxAndMix(voe_channels,
1080 number_of_voe_channels);
1081 _shared->transmit_mixer()->EncodeAndSend(voe_channels,
1082 number_of_voe_channels);
1085 // Scale from VoE to ADM level range.
1086 uint32_t new_voe_mic_level = _shared->transmit_mixer()->CaptureLevel();
1088 if (new_voe_mic_level != voe_mic_level) {
1089 // Return the new volume if AGC has changed the volume.
1090 return static_cast<int>(
1091 (new_voe_mic_level * max_volume +
1092 static_cast<int>(kMaxVolumeLevel / 2)) / kMaxVolumeLevel);
1095 // Return 0 to indicate no change on the volume.
1099 void VoEBaseImpl::GetPlayoutData(int sample_rate, int number_of_channels,
1100 int number_of_frames, bool feed_data_to_apm,
1102 assert(_shared->output_mixer() != NULL);
1104 // TODO(andrew): if the device is running in mono, we should tell the mixer
1105 // here so that it will only request mono from AudioCodingModule.
1106 // Perform mixing of all active participants (channel-based mixing)
1107 _shared->output_mixer()->MixActiveChannels();
1109 // Additional operations on the combined signal
1110 _shared->output_mixer()->DoOperationsOnCombinedSignal(feed_data_to_apm);
1112 // Retrieve the final output mix (resampled to match the ADM)
1113 _shared->output_mixer()->GetMixedAudio(sample_rate, number_of_channels,
1116 assert(number_of_frames == _audioFrame.samples_per_channel_);
1117 assert(sample_rate == _audioFrame.sample_rate_hz_);
1119 // Deliver audio (PCM) samples to the ADM
1120 memcpy(audio_data, _audioFrame.data_,
1121 sizeof(int16_t) * number_of_frames * number_of_channels);
1124 } // namespace webrtc