1470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/* 279af734807109d119573ce23daa1a2bff0f0eecaxians@webrtc.org * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. 3470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com * 4470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com * Use of this source code is governed by a BSD-style license 5470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com * that can be found in the LICENSE file in the root of the source 6470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com * tree. An additional intellectual property rights grant can be found 7470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com * in the file PATENTS. All contributing project authors may 8470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com * be found in the AUTHORS file in the root of the source tree. 9470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com */ 10470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 11956aa7e0874f2e08c335a82a2c32f400fac8b031pbos@webrtc.org#include "webrtc/voice_engine/voe_base_impl.h" 12470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 13dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting#include "webrtc/base/format_macros.h" 14ad856229a796a8efa1126ef8aa8d238f2b0a2b21pbos#include "webrtc/base/logging.h" 1503f33709f8be1da10dde6a2c9b2da5fbc3d35099turaj@webrtc.org#include "webrtc/common.h" 16956aa7e0874f2e08c335a82a2c32f400fac8b031pbos@webrtc.org#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h" 173e6db2321ccdc8738c9cecbe9bdab13d4f0f658dkjellander#include "webrtc/modules/audio_coding/include/audio_coding_module.h" 18956aa7e0874f2e08c335a82a2c32f400fac8b031pbos@webrtc.org#include "webrtc/modules/audio_device/audio_device_impl.h" 19956aa7e0874f2e08c335a82a2c32f400fac8b031pbos@webrtc.org#include "webrtc/modules/audio_processing/include/audio_processing.h" 2098f53510b222f71fdd8b799b2f33737ceeb28c61Henrik Kjellander#include "webrtc/system_wrappers/include/critical_section_wrapper.h" 2198f53510b222f71fdd8b799b2f33737ceeb28c61Henrik Kjellander#include "webrtc/system_wrappers/include/file_wrapper.h" 22956aa7e0874f2e08c335a82a2c32f400fac8b031pbos@webrtc.org#include "webrtc/voice_engine/channel.h" 23956aa7e0874f2e08c335a82a2c32f400fac8b031pbos@webrtc.org#include "webrtc/voice_engine/include/voe_errors.h" 24956aa7e0874f2e08c335a82a2c32f400fac8b031pbos@webrtc.org#include "webrtc/voice_engine/output_mixer.h" 25956aa7e0874f2e08c335a82a2c32f400fac8b031pbos@webrtc.org#include "webrtc/voice_engine/transmit_mixer.h" 26956aa7e0874f2e08c335a82a2c32f400fac8b031pbos@webrtc.org#include "webrtc/voice_engine/utility.h" 27956aa7e0874f2e08c335a82a2c32f400fac8b031pbos@webrtc.org#include "webrtc/voice_engine/voice_engine_impl.h" 28470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 292dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusicnamespace webrtc { 30470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 312dd6a270c0eb9f540427537b03330d0ed6824f9dJelena MarusicVoEBase* VoEBase::GetInterface(VoiceEngine* voiceEngine) { 322dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (nullptr == voiceEngine) { 332dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return nullptr; 342dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 352dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic VoiceEngineImpl* s = static_cast<VoiceEngineImpl*>(voiceEngine); 362dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic s->AddRef(); 372dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return s; 382dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic} 392dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic 402dd6a270c0eb9f540427537b03330d0ed6824f9dJelena MarusicVoEBaseImpl::VoEBaseImpl(voe::SharedData* shared) 412dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic : voiceEngineObserverPtr_(nullptr), 422dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic callbackCritSect_(*CriticalSectionWrapper::CreateCriticalSection()), 432dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_(shared) {} 442dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic 452dd6a270c0eb9f540427537b03330d0ed6824f9dJelena MarusicVoEBaseImpl::~VoEBaseImpl() { 462dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic TerminateInternal(); 472dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic delete &callbackCritSect_; 482dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic} 492dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic 5013725089ef91f932b37b2447c3f05d9cd9f89984solenbergvoid VoEBaseImpl::OnErrorIsReported(const ErrorCode error) { 512dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic CriticalSectionScoped cs(&callbackCritSect_); 522dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic int errCode = 0; 532dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (error == AudioDeviceObserver::kRecordingError) { 542dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic errCode = VE_RUNTIME_REC_ERROR; 552dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic LOG_F(LS_ERROR) << "VE_RUNTIME_REC_ERROR"; 562dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } else if (error == AudioDeviceObserver::kPlayoutError) { 572dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic errCode = VE_RUNTIME_PLAY_ERROR; 582dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic LOG_F(LS_ERROR) << "VE_RUNTIME_PLAY_ERROR"; 592dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 602dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (voiceEngineObserverPtr_) { 612dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic // Deliver callback (-1 <=> no channel dependency) 622dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic voiceEngineObserverPtr_->CallbackOnError(-1, errCode); 632dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 64470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com} 65470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 6613725089ef91f932b37b2447c3f05d9cd9f89984solenbergvoid VoEBaseImpl::OnWarningIsReported(const WarningCode warning) { 672dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic CriticalSectionScoped cs(&callbackCritSect_); 682dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic int warningCode = 0; 692dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (warning == AudioDeviceObserver::kRecordingWarning) { 702dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic warningCode = VE_RUNTIME_REC_WARNING; 712dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic LOG_F(LS_WARNING) << "VE_RUNTIME_REC_WARNING"; 722dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } else if (warning == AudioDeviceObserver::kPlayoutWarning) { 732dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic warningCode = VE_RUNTIME_PLAY_WARNING; 742dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic LOG_F(LS_WARNING) << "VE_RUNTIME_PLAY_WARNING"; 752dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 762dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (voiceEngineObserverPtr_) { 772dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic // Deliver callback (-1 <=> no channel dependency) 782dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic voiceEngineObserverPtr_->CallbackOnError(-1, warningCode); 792dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 80470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com} 81470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 8213725089ef91f932b37b2447c3f05d9cd9f89984solenbergint32_t VoEBaseImpl::RecordedDataIsAvailable(const void* audioSamples, 8313725089ef91f932b37b2447c3f05d9cd9f89984solenberg const size_t nSamples, 8413725089ef91f932b37b2447c3f05d9cd9f89984solenberg const size_t nBytesPerSample, 856955870806624479723addfae6dcf5d13968796cPeter Kasting const size_t nChannels, 8613725089ef91f932b37b2447c3f05d9cd9f89984solenberg const uint32_t samplesPerSec, 8713725089ef91f932b37b2447c3f05d9cd9f89984solenberg const uint32_t totalDelayMS, 8813725089ef91f932b37b2447c3f05d9cd9f89984solenberg const int32_t clockDrift, 8913725089ef91f932b37b2447c3f05d9cd9f89984solenberg const uint32_t currentMicLevel, 9013725089ef91f932b37b2447c3f05d9cd9f89984solenberg const bool keyPressed, 9113725089ef91f932b37b2447c3f05d9cd9f89984solenberg uint32_t& newMicLevel) { 922dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic newMicLevel = static_cast<uint32_t>(ProcessRecordedDataWithAPM( 932dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic nullptr, 0, audioSamples, samplesPerSec, nChannels, nSamples, 9413725089ef91f932b37b2447c3f05d9cd9f89984solenberg totalDelayMS, clockDrift, currentMicLevel, keyPressed)); 952dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return 0; 96470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com} 97470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 9813725089ef91f932b37b2447c3f05d9cd9f89984solenbergint32_t VoEBaseImpl::NeedMorePlayData(const size_t nSamples, 9913725089ef91f932b37b2447c3f05d9cd9f89984solenberg const size_t nBytesPerSample, 1006955870806624479723addfae6dcf5d13968796cPeter Kasting const size_t nChannels, 10113725089ef91f932b37b2447c3f05d9cd9f89984solenberg const uint32_t samplesPerSec, 10213725089ef91f932b37b2447c3f05d9cd9f89984solenberg void* audioSamples, 10313725089ef91f932b37b2447c3f05d9cd9f89984solenberg size_t& nSamplesOut, 1042dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic int64_t* elapsed_time_ms, 1052dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic int64_t* ntp_time_ms) { 1066955870806624479723addfae6dcf5d13968796cPeter Kasting GetPlayoutData(static_cast<int>(samplesPerSec), nChannels, nSamples, true, 1076955870806624479723addfae6dcf5d13968796cPeter Kasting audioSamples, elapsed_time_ms, ntp_time_ms); 1082dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic nSamplesOut = audioFrame_.samples_per_channel_; 1095692531f18cae04d8a8107793dc74ae932bdf219xians@webrtc.org return 0; 110470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com} 111470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 1128fff1f065ea9d25970c3839294acdd606a5ddf22xians@webrtc.orgint VoEBaseImpl::OnDataAvailable(const int voe_channels[], 1136955870806624479723addfae6dcf5d13968796cPeter Kasting size_t number_of_voe_channels, 1142dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic const int16_t* audio_data, int sample_rate, 1156955870806624479723addfae6dcf5d13968796cPeter Kasting size_t number_of_channels, 116dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting size_t number_of_frames, 1172dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic int audio_delay_milliseconds, int volume, 1182dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic bool key_pressed, bool need_audio_processing) { 1192dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (number_of_voe_channels == 0) return 0; 1202f84afad30b088ddebb4063bc47ac9a79d735a2bxians@webrtc.org 1212f84afad30b088ddebb4063bc47ac9a79d735a2bxians@webrtc.org if (need_audio_processing) { 1228fff1f065ea9d25970c3839294acdd606a5ddf22xians@webrtc.org return ProcessRecordedDataWithAPM( 1238fff1f065ea9d25970c3839294acdd606a5ddf22xians@webrtc.org voe_channels, number_of_voe_channels, audio_data, sample_rate, 1242dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic number_of_channels, number_of_frames, audio_delay_milliseconds, 0, 1252dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic volume, key_pressed); 1262f84afad30b088ddebb4063bc47ac9a79d735a2bxians@webrtc.org } 1272f84afad30b088ddebb4063bc47ac9a79d735a2bxians@webrtc.org 1282f84afad30b088ddebb4063bc47ac9a79d735a2bxians@webrtc.org // No need to go through the APM, demultiplex the data to each VoE channel, 1292f84afad30b088ddebb4063bc47ac9a79d735a2bxians@webrtc.org // encode and send to the network. 1306955870806624479723addfae6dcf5d13968796cPeter Kasting for (size_t i = 0; i < number_of_voe_channels; ++i) { 13140ee3d07eda24b8e8214429d9885d9ad9a2c04f7andrew@webrtc.org // TODO(ajm): In the case where multiple channels are using the same codec 13240ee3d07eda24b8e8214429d9885d9ad9a2c04f7andrew@webrtc.org // rate, this path needlessly does extra conversions. We should convert once 13340ee3d07eda24b8e8214429d9885d9ad9a2c04f7andrew@webrtc.org // and share between channels. 1345692531f18cae04d8a8107793dc74ae932bdf219xians@webrtc.org PushCaptureData(voe_channels[i], audio_data, 16, sample_rate, 1355692531f18cae04d8a8107793dc74ae932bdf219xians@webrtc.org number_of_channels, number_of_frames); 1362f84afad30b088ddebb4063bc47ac9a79d735a2bxians@webrtc.org } 1372f84afad30b088ddebb4063bc47ac9a79d735a2bxians@webrtc.org 1382f84afad30b088ddebb4063bc47ac9a79d735a2bxians@webrtc.org // Return 0 to indicate no need to change the volume. 1392f84afad30b088ddebb4063bc47ac9a79d735a2bxians@webrtc.org return 0; 1402f84afad30b088ddebb4063bc47ac9a79d735a2bxians@webrtc.org} 1412f84afad30b088ddebb4063bc47ac9a79d735a2bxians@webrtc.org 142c1e28038bac58f096bdb06bc36fddd9130c82f27xians@webrtc.orgvoid VoEBaseImpl::OnData(int voe_channel, const void* audio_data, 143c1e28038bac58f096bdb06bc36fddd9130c82f27xians@webrtc.org int bits_per_sample, int sample_rate, 1446955870806624479723addfae6dcf5d13968796cPeter Kasting size_t number_of_channels, size_t number_of_frames) { 1455692531f18cae04d8a8107793dc74ae932bdf219xians@webrtc.org PushCaptureData(voe_channel, audio_data, bits_per_sample, sample_rate, 1465692531f18cae04d8a8107793dc74ae932bdf219xians@webrtc.org number_of_channels, number_of_frames); 1475692531f18cae04d8a8107793dc74ae932bdf219xians@webrtc.org} 1485692531f18cae04d8a8107793dc74ae932bdf219xians@webrtc.org 1495692531f18cae04d8a8107793dc74ae932bdf219xians@webrtc.orgvoid VoEBaseImpl::PushCaptureData(int voe_channel, const void* audio_data, 1505692531f18cae04d8a8107793dc74ae932bdf219xians@webrtc.org int bits_per_sample, int sample_rate, 1516955870806624479723addfae6dcf5d13968796cPeter Kasting size_t number_of_channels, 152dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting size_t number_of_frames) { 1532dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic voe::ChannelOwner ch = shared_->channel_manager().GetChannel(voe_channel); 15407e51964143cfc5a00192e9ab71d240d0575718dxians@webrtc.org voe::Channel* channel_ptr = ch.channel(); 1552dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (!channel_ptr) return; 15607e51964143cfc5a00192e9ab71d240d0575718dxians@webrtc.org 15766803489f9694cb7c7c0dd3ba07b63e2b6b71779henrika@webrtc.org if (channel_ptr->Sending()) { 15807e51964143cfc5a00192e9ab71d240d0575718dxians@webrtc.org channel_ptr->Demultiplex(static_cast<const int16_t*>(audio_data), 15907e51964143cfc5a00192e9ab71d240d0575718dxians@webrtc.org sample_rate, number_of_frames, number_of_channels); 16007e51964143cfc5a00192e9ab71d240d0575718dxians@webrtc.org channel_ptr->PrepareEncodeAndSend(sample_rate); 16107e51964143cfc5a00192e9ab71d240d0575718dxians@webrtc.org channel_ptr->EncodeAndSend(); 16207e51964143cfc5a00192e9ab71d240d0575718dxians@webrtc.org } 16307e51964143cfc5a00192e9ab71d240d0575718dxians@webrtc.org} 16407e51964143cfc5a00192e9ab71d240d0575718dxians@webrtc.org 165dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kastingvoid VoEBaseImpl::PullRenderData(int bits_per_sample, 166dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting int sample_rate, 1676955870806624479723addfae6dcf5d13968796cPeter Kasting size_t number_of_channels, 168dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting size_t number_of_frames, 1692dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic void* audio_data, int64_t* elapsed_time_ms, 170cb711f77d2ff9ebd42678869a73353809b3af66ewu@webrtc.org int64_t* ntp_time_ms) { 1716fc2d2f487b3e6223dff518e04fb301ba6d2cf43Jelena Marusic assert(bits_per_sample == 16); 172dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting assert(number_of_frames == static_cast<size_t>(sample_rate / 100)); 1735692531f18cae04d8a8107793dc74ae932bdf219xians@webrtc.org 1745692531f18cae04d8a8107793dc74ae932bdf219xians@webrtc.org GetPlayoutData(sample_rate, number_of_channels, number_of_frames, false, 17594454b71adc37e15fd3f5a5fc432063f05caabcbwu@webrtc.org audio_data, elapsed_time_ms, ntp_time_ms); 1765692531f18cae04d8a8107793dc74ae932bdf219xians@webrtc.org} 1775692531f18cae04d8a8107793dc74ae932bdf219xians@webrtc.org 1782dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusicint VoEBaseImpl::RegisterVoiceEngineObserver(VoiceEngineObserver& observer) { 1792dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic CriticalSectionScoped cs(&callbackCritSect_); 1802dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (voiceEngineObserverPtr_) { 1812dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->SetLastError( 1822dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic VE_INVALID_OPERATION, kTraceError, 1832dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic "RegisterVoiceEngineObserver() observer already enabled"); 1842dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return -1; 1852dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 186470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 1872dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic // Register the observer in all active channels 1882dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic for (voe::ChannelManager::Iterator it(&shared_->channel_manager()); 1892dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic it.IsValid(); it.Increment()) { 1902dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic it.GetChannel()->RegisterVoiceEngineObserver(observer); 1912dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 192676ff1ed893d6ae59a7ce29a4428e0d7c9f855d9pbos@webrtc.org 1932dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->transmit_mixer()->RegisterVoiceEngineObserver(observer); 1942dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic voiceEngineObserverPtr_ = &observer; 1952dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return 0; 196470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com} 197470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 1982dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusicint VoEBaseImpl::DeRegisterVoiceEngineObserver() { 1992dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic CriticalSectionScoped cs(&callbackCritSect_); 2002dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (!voiceEngineObserverPtr_) { 2012dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->SetLastError( 2022dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic VE_INVALID_OPERATION, kTraceError, 2032dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic "DeRegisterVoiceEngineObserver() observer already disabled"); 2042dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return 0; 2052dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 2062dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic voiceEngineObserverPtr_ = nullptr; 207470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 2082dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic // Deregister the observer in all active channels 2092dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic for (voe::ChannelManager::Iterator it(&shared_->channel_manager()); 2102dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic it.IsValid(); it.Increment()) { 2112dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic it.GetChannel()->DeRegisterVoiceEngineObserver(); 2122dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 213470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 2142dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return 0; 215470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com} 216470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 217f0a90c37c4b8a2581268f0054cc9d977e7beee8eandrew@webrtc.orgint VoEBaseImpl::Init(AudioDeviceModule* external_adm, 2182dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic AudioProcessing* audioproc) { 2192dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic CriticalSectionScoped cs(shared_->crit_sec()); 2202dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic WebRtcSpl_Init(); 2212dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (shared_->statistics().Initialized()) { 2222dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return 0; 2232dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 2242dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (shared_->process_thread()) { 2252dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->process_thread()->Start(); 2262dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 227470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 2282dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic // Create an internal ADM if the user has not added an external 2292dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic // ADM implementation as input to Init(). 2302dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (external_adm == nullptr) { 231931e6583b21d2d3d1ee8fd240f63708dc56d1a19Tommi#if !defined(WEBRTC_INCLUDE_INTERNAL_AUDIO_DEVICE) 232931e6583b21d2d3d1ee8fd240f63708dc56d1a19Tommi return -1; 233931e6583b21d2d3d1ee8fd240f63708dc56d1a19Tommi#else 2342dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic // Create the internal ADM implementation. 2352dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->set_audio_device(AudioDeviceModuleImpl::Create( 2362dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic VoEId(shared_->instance_id(), -1), shared_->audio_device_layer())); 237470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 2382dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (shared_->audio_device() == nullptr) { 2392dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->SetLastError(VE_NO_MEMORY, kTraceCritical, 2402dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic "Init() failed to create the ADM"); 2412dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return -1; 242e33a102eee68b2163d21548551e876fc7525684eniklas.enbom@webrtc.org } 243931e6583b21d2d3d1ee8fd240f63708dc56d1a19Tommi#endif // WEBRTC_INCLUDE_INTERNAL_AUDIO_DEVICE 2442dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } else { 2452dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic // Use the already existing external ADM implementation. 2462dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->set_audio_device(external_adm); 2472dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic LOG_F(LS_INFO) 2482dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic << "An external ADM implementation will be used in VoiceEngine"; 2492dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 250e33a102eee68b2163d21548551e876fc7525684eniklas.enbom@webrtc.org 2512dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic // Register the ADM to the process thread, which will drive the error 2522dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic // callback mechanism 2532dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (shared_->process_thread()) { 2542dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->process_thread()->RegisterModule(shared_->audio_device()); 2552dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 256e33a102eee68b2163d21548551e876fc7525684eniklas.enbom@webrtc.org 2572dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic bool available = false; 258e33a102eee68b2163d21548551e876fc7525684eniklas.enbom@webrtc.org 2592dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic // -------------------- 2602dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic // Reinitialize the ADM 261e33a102eee68b2163d21548551e876fc7525684eniklas.enbom@webrtc.org 2622dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic // Register the AudioObserver implementation 2632dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (shared_->audio_device()->RegisterEventObserver(this) != 0) { 2642dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->SetLastError( 2652dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning, 2662dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic "Init() failed to register event observer for the ADM"); 2672dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 268e33a102eee68b2163d21548551e876fc7525684eniklas.enbom@webrtc.org 2692dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic // Register the AudioTransport implementation 2702dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (shared_->audio_device()->RegisterAudioCallback(this) != 0) { 2712dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->SetLastError( 2722dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning, 2732dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic "Init() failed to register audio callback for the ADM"); 2742dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 275e33a102eee68b2163d21548551e876fc7525684eniklas.enbom@webrtc.org 2762dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic // ADM initialization 2772dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (shared_->audio_device()->Init() != 0) { 2782dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError, 2792dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic "Init() failed to initialize the ADM"); 2802dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return -1; 2812dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 282e33a102eee68b2163d21548551e876fc7525684eniklas.enbom@webrtc.org 2832dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic // Initialize the default speaker 2842dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (shared_->audio_device()->SetPlayoutDevice( 2852dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0) { 2862dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceInfo, 2872dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic "Init() failed to set the default output device"); 2882dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 2892dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (shared_->audio_device()->InitSpeaker() != 0) { 2902dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceInfo, 2912dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic "Init() failed to initialize the speaker"); 2922dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 293e33a102eee68b2163d21548551e876fc7525684eniklas.enbom@webrtc.org 2942dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic // Initialize the default microphone 2952dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (shared_->audio_device()->SetRecordingDevice( 2962dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0) { 2972dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceInfo, 2982dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic "Init() failed to set the default input device"); 2992dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 3002dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (shared_->audio_device()->InitMicrophone() != 0) { 3012dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceInfo, 3022dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic "Init() failed to initialize the microphone"); 3032dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 304e33a102eee68b2163d21548551e876fc7525684eniklas.enbom@webrtc.org 3052dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic // Set number of channels 3062dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (shared_->audio_device()->StereoPlayoutIsAvailable(&available) != 0) { 3072dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning, 3082dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic "Init() failed to query stereo playout mode"); 3092dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 3102dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (shared_->audio_device()->SetStereoPlayout(available) != 0) { 3112dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning, 3122dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic "Init() failed to set mono/stereo playout mode"); 3132dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 3143192d655bdc50134952ed81b2a64cd0561f2de83andrew@webrtc.org 3152dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic // TODO(andrew): These functions don't tell us whether stereo recording 3162dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic // is truly available. We simply set the AudioProcessing input to stereo 3172dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic // here, because we have to wait until receiving the first frame to 3182dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic // determine the actual number of channels anyway. 3192dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic // 3202dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic // These functions may be changed; tracked here: 3212dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic // http://code.google.com/p/webrtc/issues/detail?id=204 3222dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->audio_device()->StereoRecordingIsAvailable(&available); 3232dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (shared_->audio_device()->SetStereoRecording(available) != 0) { 3242dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning, 3252dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic "Init() failed to set mono/stereo recording mode"); 3262dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 327e33a102eee68b2163d21548551e876fc7525684eniklas.enbom@webrtc.org 3282dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (!audioproc) { 3292dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic audioproc = AudioProcessing::Create(); 330f0a90c37c4b8a2581268f0054cc9d977e7beee8eandrew@webrtc.org if (!audioproc) { 3312dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic LOG(LS_ERROR) << "Failed to create AudioProcessing."; 3322dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->SetLastError(VE_NO_MEMORY); 333f0a90c37c4b8a2581268f0054cc9d977e7beee8eandrew@webrtc.org return -1; 334f0a90c37c4b8a2581268f0054cc9d977e7beee8eandrew@webrtc.org } 3352dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 3362dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->set_audio_processing(audioproc); 3372dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic 3382dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic // Set the error state for any failures in this block. 3392dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->SetLastError(VE_APM_ERROR); 3402dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic // Configure AudioProcessing components. 3412dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (audioproc->high_pass_filter()->Enable(true) != 0) { 342f353dd59b59aea3c3a1c64aa20a66c2a8c32225eJelena Marusic LOG_F(LS_ERROR) << "Failed to enable high pass filter."; 3432dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return -1; 3442dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 3452dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (audioproc->echo_cancellation()->enable_drift_compensation(false) != 0) { 346f353dd59b59aea3c3a1c64aa20a66c2a8c32225eJelena Marusic LOG_F(LS_ERROR) << "Failed to disable drift compensation."; 3472dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return -1; 3482dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 3492dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (audioproc->noise_suppression()->set_level(kDefaultNsMode) != 0) { 350f353dd59b59aea3c3a1c64aa20a66c2a8c32225eJelena Marusic LOG_F(LS_ERROR) << "Failed to set noise suppression level: " 351f353dd59b59aea3c3a1c64aa20a66c2a8c32225eJelena Marusic << kDefaultNsMode; 3522dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return -1; 3532dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 3542dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic GainControl* agc = audioproc->gain_control(); 3552dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (agc->set_analog_level_limits(kMinVolumeLevel, kMaxVolumeLevel) != 0) { 356f353dd59b59aea3c3a1c64aa20a66c2a8c32225eJelena Marusic LOG_F(LS_ERROR) << "Failed to set analog level limits with minimum: " 357f353dd59b59aea3c3a1c64aa20a66c2a8c32225eJelena Marusic << kMinVolumeLevel << " and maximum: " << kMaxVolumeLevel; 3582dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return -1; 3592dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 3602dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (agc->set_mode(kDefaultAgcMode) != 0) { 361f353dd59b59aea3c3a1c64aa20a66c2a8c32225eJelena Marusic LOG_F(LS_ERROR) << "Failed to set mode: " << kDefaultAgcMode; 3622dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return -1; 3632dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 3642dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (agc->Enable(kDefaultAgcState) != 0) { 365f353dd59b59aea3c3a1c64aa20a66c2a8c32225eJelena Marusic LOG_F(LS_ERROR) << "Failed to set agc state: " << kDefaultAgcState; 3662dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return -1; 3672dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 3682dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->SetLastError(0); // Clear error state. 369470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 370470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#ifdef WEBRTC_VOICE_ENGINE_AGC 3712dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic bool agc_enabled = 3722dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic agc->mode() == GainControl::kAdaptiveAnalog && agc->is_enabled(); 3732dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (shared_->audio_device()->SetAGC(agc_enabled) != 0) { 374f353dd59b59aea3c3a1c64aa20a66c2a8c32225eJelena Marusic LOG_F(LS_ERROR) << "Failed to set agc to enabled: " << agc_enabled; 3752dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR); 3762dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic // TODO(ajm): No error return here due to 3772dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic // https://code.google.com/p/webrtc/issues/detail?id=1464 3782dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 379470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#endif 380470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 3812dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return shared_->statistics().SetInitialized(); 382470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com} 383470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 3842dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusicint VoEBaseImpl::Terminate() { 3852dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic CriticalSectionScoped cs(shared_->crit_sec()); 3862dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return TerminateInternal(); 387470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com} 388470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 38903f33709f8be1da10dde6a2c9b2da5fbc3d35099turaj@webrtc.orgint VoEBaseImpl::CreateChannel() { 3902dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic CriticalSectionScoped cs(shared_->crit_sec()); 3912dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (!shared_->statistics().Initialized()) { 3922dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->SetLastError(VE_NOT_INITED, kTraceError); 3932dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return -1; 39403f33709f8be1da10dde6a2c9b2da5fbc3d35099turaj@webrtc.org } 395470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 3962dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic voe::ChannelOwner channel_owner = shared_->channel_manager().CreateChannel(); 39703f33709f8be1da10dde6a2c9b2da5fbc3d35099turaj@webrtc.org return InitializeChannel(&channel_owner); 39803f33709f8be1da10dde6a2c9b2da5fbc3d35099turaj@webrtc.org} 399470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 40003f33709f8be1da10dde6a2c9b2da5fbc3d35099turaj@webrtc.orgint VoEBaseImpl::CreateChannel(const Config& config) { 4012dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic CriticalSectionScoped cs(shared_->crit_sec()); 4022dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (!shared_->statistics().Initialized()) { 4032dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->SetLastError(VE_NOT_INITED, kTraceError); 4042dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return -1; 40503f33709f8be1da10dde6a2c9b2da5fbc3d35099turaj@webrtc.org } 4062dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic voe::ChannelOwner channel_owner = 4072dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->channel_manager().CreateChannel(config); 40803f33709f8be1da10dde6a2c9b2da5fbc3d35099turaj@webrtc.org return InitializeChannel(&channel_owner); 40903f33709f8be1da10dde6a2c9b2da5fbc3d35099turaj@webrtc.org} 410676ff1ed893d6ae59a7ce29a4428e0d7c9f855d9pbos@webrtc.org 4112dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusicint VoEBaseImpl::InitializeChannel(voe::ChannelOwner* channel_owner) { 4122dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (channel_owner->channel()->SetEngineInformation( 4132dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->statistics(), *shared_->output_mixer(), 4142dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic *shared_->transmit_mixer(), *shared_->process_thread(), 4152dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic *shared_->audio_device(), voiceEngineObserverPtr_, 4162dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic &callbackCritSect_) != 0) { 4172dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->SetLastError( 4182dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic VE_CHANNEL_NOT_CREATED, kTraceError, 4192dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic "CreateChannel() failed to associate engine and channel." 4202dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic " Destroying channel."); 4212dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->channel_manager().DestroyChannel( 4222dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic channel_owner->channel()->ChannelId()); 4232dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return -1; 4242dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } else if (channel_owner->channel()->Init() != 0) { 4252dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->SetLastError( 4262dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic VE_CHANNEL_NOT_CREATED, kTraceError, 4272dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic "CreateChannel() failed to initialize channel. Destroying" 4282dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic " channel."); 4292dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->channel_manager().DestroyChannel( 4302dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic channel_owner->channel()->ChannelId()); 4312dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return -1; 4322dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 4332dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return channel_owner->channel()->ChannelId(); 434470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com} 435470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 4362dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusicint VoEBaseImpl::DeleteChannel(int channel) { 4372dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic CriticalSectionScoped cs(shared_->crit_sec()); 4382dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (!shared_->statistics().Initialized()) { 4392dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->SetLastError(VE_NOT_INITED, kTraceError); 4402dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return -1; 4412dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 442470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 4432dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic { 4442dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel); 4452dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic voe::Channel* channelPtr = ch.channel(); 4462dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (channelPtr == nullptr) { 4472dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, 4482dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic "DeleteChannel() failed to locate channel"); 4492dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return -1; 450470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com } 4512dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 452684f0577fbe4ea393fef1dddf2ca7d02e3205b49pwestin@webrtc.org 4532dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->channel_manager().DestroyChannel(channel); 4542dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (StopSend() != 0) { 4552dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return -1; 4562dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 4572dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (StopPlayout() != 0) { 4582dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return -1; 4592dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 4602dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return 0; 461470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com} 462470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 4632dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusicint VoEBaseImpl::StartReceive(int channel) { 4642dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic CriticalSectionScoped cs(shared_->crit_sec()); 4652dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (!shared_->statistics().Initialized()) { 4662dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->SetLastError(VE_NOT_INITED, kTraceError); 4672dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return -1; 4682dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 4692dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel); 4702dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic voe::Channel* channelPtr = ch.channel(); 4712dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (channelPtr == nullptr) { 4722dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, 4732dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic "StartReceive() failed to locate channel"); 4742dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return -1; 4752dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 4762dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return channelPtr->StartReceiving(); 477470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com} 478470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 4792dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusicint VoEBaseImpl::StopReceive(int channel) { 4802dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic CriticalSectionScoped cs(shared_->crit_sec()); 4812dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (!shared_->statistics().Initialized()) { 4822dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->SetLastError(VE_NOT_INITED, kTraceError); 4832dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return -1; 4842dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 4852dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel); 4862dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic voe::Channel* channelPtr = ch.channel(); 4872dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (channelPtr == nullptr) { 4882dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, 4892dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic "SetLocalReceiver() failed to locate channel"); 4902dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return -1; 4912dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 4922dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return channelPtr->StopReceiving(); 493470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com} 494470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 4952dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusicint VoEBaseImpl::StartPlayout(int channel) { 4962dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic CriticalSectionScoped cs(shared_->crit_sec()); 4972dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (!shared_->statistics().Initialized()) { 4982dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->SetLastError(VE_NOT_INITED, kTraceError); 4992dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return -1; 5002dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 5012dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel); 5022dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic voe::Channel* channelPtr = ch.channel(); 5032dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (channelPtr == nullptr) { 5042dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, 5052dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic "StartPlayout() failed to locate channel"); 5062dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return -1; 5072dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 5082dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (channelPtr->Playing()) { 5092dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return 0; 5102dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 5112dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (StartPlayout() != 0) { 5122dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError, 5132dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic "StartPlayout() failed to start playout"); 5142dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return -1; 5152dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 5162dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return channelPtr->StartPlayout(); 517470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com} 518470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 5192dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusicint VoEBaseImpl::StopPlayout(int channel) { 5202dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic CriticalSectionScoped cs(shared_->crit_sec()); 5212dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (!shared_->statistics().Initialized()) { 5222dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->SetLastError(VE_NOT_INITED, kTraceError); 5232dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return -1; 5242dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 5252dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel); 5262dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic voe::Channel* channelPtr = ch.channel(); 5272dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (channelPtr == nullptr) { 5282dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, 5292dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic "StopPlayout() failed to locate channel"); 5302dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return -1; 5312dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 5322dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (channelPtr->StopPlayout() != 0) { 5332dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic LOG_F(LS_WARNING) << "StopPlayout() failed to stop playout for channel " 5342dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic << channel; 5352dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 5362dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return StopPlayout(); 537470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com} 538470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 5392dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusicint VoEBaseImpl::StartSend(int channel) { 5402dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic CriticalSectionScoped cs(shared_->crit_sec()); 5412dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (!shared_->statistics().Initialized()) { 5422dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->SetLastError(VE_NOT_INITED, kTraceError); 5432dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return -1; 5442dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 5452dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel); 5462dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic voe::Channel* channelPtr = ch.channel(); 5472dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (channelPtr == nullptr) { 5482dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, 5492dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic "StartSend() failed to locate channel"); 5502dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return -1; 5512dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 5522dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (channelPtr->Sending()) { 5532dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return 0; 5542dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 5552dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (StartSend() != 0) { 5562dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError, 5572dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic "StartSend() failed to start recording"); 5582dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return -1; 5592dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 5602dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return channelPtr->StartSend(); 561470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com} 562470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 5632dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusicint VoEBaseImpl::StopSend(int channel) { 5642dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic CriticalSectionScoped cs(shared_->crit_sec()); 5652dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (!shared_->statistics().Initialized()) { 5662dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->SetLastError(VE_NOT_INITED, kTraceError); 5672dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return -1; 5682dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 5692dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel); 5702dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic voe::Channel* channelPtr = ch.channel(); 5712dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (channelPtr == nullptr) { 5722dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, 5732dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic "StopSend() failed to locate channel"); 5742dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return -1; 5752dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 5762dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (channelPtr->StopSend() != 0) { 5772dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic LOG_F(LS_WARNING) << "StopSend() failed to stop sending for channel " 5782dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic << channel; 5792dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 5802dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return StopSend(); 581470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com} 582470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 5832dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusicint VoEBaseImpl::GetVersion(char version[1024]) { 5842dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (version == nullptr) { 5852dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->SetLastError(VE_INVALID_ARGUMENT, kTraceError); 5862dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return -1; 5872dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 588470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 5892515af28e97213b4a4b89269f6b855378d31e153solenberg std::string versionString = VoiceEngine::GetVersionString(); 5902515af28e97213b4a4b89269f6b855378d31e153solenberg RTC_DCHECK_GT(1024u, versionString.size() + 1); 5912515af28e97213b4a4b89269f6b855378d31e153solenberg char* end = std::copy(versionString.cbegin(), versionString.cend(), version); 5922515af28e97213b4a4b89269f6b855378d31e153solenberg end[0] = '\n'; 5932515af28e97213b4a4b89269f6b855378d31e153solenberg end[1] = '\0'; 5942dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return 0; 595470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com} 596470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 5972dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusicint VoEBaseImpl::LastError() { return (shared_->statistics().LastError()); } 598470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 5992dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusicint32_t VoEBaseImpl::StartPlayout() { 600e313e0278315c918d1ae810f79e4b3f176d58659solenberg if (!shared_->audio_device()->Playing()) { 6012dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (shared_->audio_device()->InitPlayout() != 0) { 6022dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic LOG_F(LS_ERROR) << "Failed to initialize playout"; 6032dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return -1; 604470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com } 6052dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (shared_->audio_device()->StartPlayout() != 0) { 6062dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic LOG_F(LS_ERROR) << "Failed to start playout"; 6072dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return -1; 608470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com } 6092dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 6102dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return 0; 611470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com} 612470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 613676ff1ed893d6ae59a7ce29a4428e0d7c9f855d9pbos@webrtc.orgint32_t VoEBaseImpl::StopPlayout() { 614676ff1ed893d6ae59a7ce29a4428e0d7c9f855d9pbos@webrtc.org // Stop audio-device playing if no channel is playing out 6152dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (shared_->NumOfPlayingChannels() == 0) { 6162dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (shared_->audio_device()->StopPlayout() != 0) { 6172dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->SetLastError(VE_CANNOT_STOP_PLAYOUT, kTraceError, 618676ff1ed893d6ae59a7ce29a4428e0d7c9f855d9pbos@webrtc.org "StopPlayout() failed to stop playout"); 619676ff1ed893d6ae59a7ce29a4428e0d7c9f855d9pbos@webrtc.org return -1; 620470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com } 621676ff1ed893d6ae59a7ce29a4428e0d7c9f855d9pbos@webrtc.org } 622676ff1ed893d6ae59a7ce29a4428e0d7c9f855d9pbos@webrtc.org return 0; 623470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com} 624470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 6252dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusicint32_t VoEBaseImpl::StartSend() { 626e313e0278315c918d1ae810f79e4b3f176d58659solenberg if (!shared_->audio_device()->Recording()) { 6272dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (shared_->audio_device()->InitRecording() != 0) { 6282dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic LOG_F(LS_ERROR) << "Failed to initialize recording"; 6292dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return -1; 630470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com } 6312dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (shared_->audio_device()->StartRecording() != 0) { 6322dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic LOG_F(LS_ERROR) << "Failed to start recording"; 6332dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return -1; 634470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com } 6352dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 6362dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return 0; 637470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com} 638470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 6392dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusicint32_t VoEBaseImpl::StopSend() { 6402dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (shared_->NumOfSendingChannels() == 0 && 6412dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic !shared_->transmit_mixer()->IsRecordingMic()) { 6422dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic // Stop audio-device recording if no channel is recording 6432dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (shared_->audio_device()->StopRecording() != 0) { 6442dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->SetLastError(VE_CANNOT_STOP_RECORDING, kTraceError, 6452dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic "StopSend() failed to stop recording"); 6462dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return -1; 647470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com } 6482dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->transmit_mixer()->StopSend(); 6492dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 650470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 6512dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return 0; 652470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com} 653470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 6542dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusicint32_t VoEBaseImpl::TerminateInternal() { 6552dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic // Delete any remaining channel objects 6562dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->channel_manager().DestroyAllChannels(); 657470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 6582dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (shared_->process_thread()) { 6592dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (shared_->audio_device()) { 6602dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->process_thread()->DeRegisterModule(shared_->audio_device()); 661470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com } 6622dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->process_thread()->Stop(); 6632dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 664470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 6652dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (shared_->audio_device()) { 6662dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (shared_->audio_device()->StopPlayout() != 0) { 6672dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning, 6682dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic "TerminateInternal() failed to stop playout"); 669470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com } 6702dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (shared_->audio_device()->StopRecording() != 0) { 6712dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning, 6722dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic "TerminateInternal() failed to stop recording"); 6732dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 6742dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (shared_->audio_device()->RegisterEventObserver(nullptr) != 0) { 6752dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->SetLastError( 6762dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning, 6772dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic "TerminateInternal() failed to de-register event observer " 6782dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic "for the ADM"); 679470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com } 6802dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (shared_->audio_device()->RegisterAudioCallback(nullptr) != 0) { 6812dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->SetLastError( 6822dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning, 6832dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic "TerminateInternal() failed to de-register audio callback " 6842dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic "for the ADM"); 6852dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 6862dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (shared_->audio_device()->Terminate() != 0) { 6872dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError, 6882dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic "TerminateInternal() failed to terminate the ADM"); 6892dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 6902dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->set_audio_device(nullptr); 6912dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 692470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 6932dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (shared_->audio_processing()) { 6942dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->set_audio_processing(nullptr); 6952dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic } 6962dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic 6972dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return shared_->statistics().SetUnInitialized(); 698470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com} 699470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com 7008fff1f065ea9d25970c3839294acdd606a5ddf22xians@webrtc.orgint VoEBaseImpl::ProcessRecordedDataWithAPM( 7016955870806624479723addfae6dcf5d13968796cPeter Kasting const int voe_channels[], size_t number_of_voe_channels, 7026955870806624479723addfae6dcf5d13968796cPeter Kasting const void* audio_data, uint32_t sample_rate, size_t number_of_channels, 703dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting size_t number_of_frames, uint32_t audio_delay_milliseconds, 7042dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic int32_t clock_drift, uint32_t volume, bool key_pressed) { 7052dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic assert(shared_->transmit_mixer() != nullptr); 7062dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic assert(shared_->audio_device() != nullptr); 7078fff1f065ea9d25970c3839294acdd606a5ddf22xians@webrtc.org 7088fff1f065ea9d25970c3839294acdd606a5ddf22xians@webrtc.org uint32_t max_volume = 0; 70927c6980239a0c6bc81121a1aa75c27f9187aacf4andrew@webrtc.org uint16_t voe_mic_level = 0; 710023cc5abc7d25fb3133b4d0206b67dcc6204b6e8andrew@webrtc.org // Check for zero to skip this calculation; the consumer may use this to 711023cc5abc7d25fb3133b4d0206b67dcc6204b6e8andrew@webrtc.org // indicate no volume is available. 71227c6980239a0c6bc81121a1aa75c27f9187aacf4andrew@webrtc.org if (volume != 0) { 7138fff1f065ea9d25970c3839294acdd606a5ddf22xians@webrtc.org // Scale from ADM to VoE level range 7142dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic if (shared_->audio_device()->MaxMicrophoneVolume(&max_volume) == 0) { 7158fff1f065ea9d25970c3839294acdd606a5ddf22xians@webrtc.org if (max_volume) { 71627c6980239a0c6bc81121a1aa75c27f9187aacf4andrew@webrtc.org voe_mic_level = static_cast<uint16_t>( 7172dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic (volume * kMaxVolumeLevel + static_cast<int>(max_volume / 2)) / 7182dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic max_volume); 7198fff1f065ea9d25970c3839294acdd606a5ddf22xians@webrtc.org } 7208fff1f065ea9d25970c3839294acdd606a5ddf22xians@webrtc.org } 72127c6980239a0c6bc81121a1aa75c27f9187aacf4andrew@webrtc.org // We learned that on certain systems (e.g Linux) the voe_mic_level 7228fff1f065ea9d25970c3839294acdd606a5ddf22xians@webrtc.org // can be greater than the maxVolumeLevel therefore 72327c6980239a0c6bc81121a1aa75c27f9187aacf4andrew@webrtc.org // we are going to cap the voe_mic_level to the maxVolumeLevel 72427c6980239a0c6bc81121a1aa75c27f9187aacf4andrew@webrtc.org // and change the maxVolume to volume if it turns out that 72527c6980239a0c6bc81121a1aa75c27f9187aacf4andrew@webrtc.org // the voe_mic_level is indeed greater than the maxVolumeLevel. 72627c6980239a0c6bc81121a1aa75c27f9187aacf4andrew@webrtc.org if (voe_mic_level > kMaxVolumeLevel) { 72727c6980239a0c6bc81121a1aa75c27f9187aacf4andrew@webrtc.org voe_mic_level = kMaxVolumeLevel; 72827c6980239a0c6bc81121a1aa75c27f9187aacf4andrew@webrtc.org max_volume = volume; 7298fff1f065ea9d25970c3839294acdd606a5ddf22xians@webrtc.org } 7308fff1f065ea9d25970c3839294acdd606a5ddf22xians@webrtc.org } 7318fff1f065ea9d25970c3839294acdd606a5ddf22xians@webrtc.org 7328fff1f065ea9d25970c3839294acdd606a5ddf22xians@webrtc.org // Perform channel-independent operations 7338fff1f065ea9d25970c3839294acdd606a5ddf22xians@webrtc.org // (APM, mix with file, record to file, mute, etc.) 7342dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->transmit_mixer()->PrepareDemux( 7358fff1f065ea9d25970c3839294acdd606a5ddf22xians@webrtc.org audio_data, number_of_frames, number_of_channels, sample_rate, 7368fff1f065ea9d25970c3839294acdd606a5ddf22xians@webrtc.org static_cast<uint16_t>(audio_delay_milliseconds), clock_drift, 73727c6980239a0c6bc81121a1aa75c27f9187aacf4andrew@webrtc.org voe_mic_level, key_pressed); 7388fff1f065ea9d25970c3839294acdd606a5ddf22xians@webrtc.org 7398fff1f065ea9d25970c3839294acdd606a5ddf22xians@webrtc.org // Copy the audio frame to each sending channel and perform 7408fff1f065ea9d25970c3839294acdd606a5ddf22xians@webrtc.org // channel-dependent operations (file mixing, mute, etc.), encode and 7418fff1f065ea9d25970c3839294acdd606a5ddf22xians@webrtc.org // packetize+transmit the RTP packet. When |number_of_voe_channels| == 0, 7428fff1f065ea9d25970c3839294acdd606a5ddf22xians@webrtc.org // do the operations on all the existing VoE channels; otherwise the 7438fff1f065ea9d25970c3839294acdd606a5ddf22xians@webrtc.org // operations will be done on specific channels. 7448fff1f065ea9d25970c3839294acdd606a5ddf22xians@webrtc.org if (number_of_voe_channels == 0) { 7452dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->transmit_mixer()->DemuxAndMix(); 7462dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->transmit_mixer()->EncodeAndSend(); 7478fff1f065ea9d25970c3839294acdd606a5ddf22xians@webrtc.org } else { 7482dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->transmit_mixer()->DemuxAndMix(voe_channels, 7498fff1f065ea9d25970c3839294acdd606a5ddf22xians@webrtc.org number_of_voe_channels); 7502dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->transmit_mixer()->EncodeAndSend(voe_channels, 7518fff1f065ea9d25970c3839294acdd606a5ddf22xians@webrtc.org number_of_voe_channels); 7528fff1f065ea9d25970c3839294acdd606a5ddf22xians@webrtc.org } 7538fff1f065ea9d25970c3839294acdd606a5ddf22xians@webrtc.org 7548fff1f065ea9d25970c3839294acdd606a5ddf22xians@webrtc.org // Scale from VoE to ADM level range. 7552dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic uint32_t new_voe_mic_level = shared_->transmit_mixer()->CaptureLevel(); 75627c6980239a0c6bc81121a1aa75c27f9187aacf4andrew@webrtc.org if (new_voe_mic_level != voe_mic_level) { 7578fff1f065ea9d25970c3839294acdd606a5ddf22xians@webrtc.org // Return the new volume if AGC has changed the volume. 7582dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic return static_cast<int>((new_voe_mic_level * max_volume + 7592dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic static_cast<int>(kMaxVolumeLevel / 2)) / 7602dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic kMaxVolumeLevel); 7618fff1f065ea9d25970c3839294acdd606a5ddf22xians@webrtc.org } 7628fff1f065ea9d25970c3839294acdd606a5ddf22xians@webrtc.org 7638fff1f065ea9d25970c3839294acdd606a5ddf22xians@webrtc.org // Return 0 to indicate no change on the volume. 7648fff1f065ea9d25970c3839294acdd606a5ddf22xians@webrtc.org return 0; 7658fff1f065ea9d25970c3839294acdd606a5ddf22xians@webrtc.org} 7668fff1f065ea9d25970c3839294acdd606a5ddf22xians@webrtc.org 7676955870806624479723addfae6dcf5d13968796cPeter Kastingvoid VoEBaseImpl::GetPlayoutData(int sample_rate, size_t number_of_channels, 768dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting size_t number_of_frames, bool feed_data_to_apm, 7692dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic void* audio_data, int64_t* elapsed_time_ms, 770cb711f77d2ff9ebd42678869a73353809b3af66ewu@webrtc.org int64_t* ntp_time_ms) { 7712dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic assert(shared_->output_mixer() != nullptr); 7725692531f18cae04d8a8107793dc74ae932bdf219xians@webrtc.org 7735692531f18cae04d8a8107793dc74ae932bdf219xians@webrtc.org // TODO(andrew): if the device is running in mono, we should tell the mixer 7745692531f18cae04d8a8107793dc74ae932bdf219xians@webrtc.org // here so that it will only request mono from AudioCodingModule. 7755692531f18cae04d8a8107793dc74ae932bdf219xians@webrtc.org // Perform mixing of all active participants (channel-based mixing) 7762dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->output_mixer()->MixActiveChannels(); 7775692531f18cae04d8a8107793dc74ae932bdf219xians@webrtc.org 7785692531f18cae04d8a8107793dc74ae932bdf219xians@webrtc.org // Additional operations on the combined signal 7792dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->output_mixer()->DoOperationsOnCombinedSignal(feed_data_to_apm); 7805692531f18cae04d8a8107793dc74ae932bdf219xians@webrtc.org 7815692531f18cae04d8a8107793dc74ae932bdf219xians@webrtc.org // Retrieve the final output mix (resampled to match the ADM) 7822dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic shared_->output_mixer()->GetMixedAudio(sample_rate, number_of_channels, 7832dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic &audioFrame_); 7845692531f18cae04d8a8107793dc74ae932bdf219xians@webrtc.org 7852dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic assert(number_of_frames == audioFrame_.samples_per_channel_); 7862dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic assert(sample_rate == audioFrame_.sample_rate_hz_); 7875692531f18cae04d8a8107793dc74ae932bdf219xians@webrtc.org 7885692531f18cae04d8a8107793dc74ae932bdf219xians@webrtc.org // Deliver audio (PCM) samples to the ADM 7892dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic memcpy(audio_data, audioFrame_.data_, 7905692531f18cae04d8a8107793dc74ae932bdf219xians@webrtc.org sizeof(int16_t) * number_of_frames * number_of_channels); 791cb711f77d2ff9ebd42678869a73353809b3af66ewu@webrtc.org 7922dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic *elapsed_time_ms = audioFrame_.elapsed_time_ms_; 7932dd6a270c0eb9f540427537b03330d0ed6824f9dJelena Marusic *ntp_time_ms = audioFrame_.ntp_time_ms_; 7945692531f18cae04d8a8107793dc74ae932bdf219xians@webrtc.org} 7955692531f18cae04d8a8107793dc74ae932bdf219xians@webrtc.org 7962013aeced2b7821a407f302802c4a16fd02728b1Minyueint VoEBaseImpl::AssociateSendChannel(int channel, 7972013aeced2b7821a407f302802c4a16fd02728b1Minyue int accociate_send_channel) { 7982013aeced2b7821a407f302802c4a16fd02728b1Minyue CriticalSectionScoped cs(shared_->crit_sec()); 7992013aeced2b7821a407f302802c4a16fd02728b1Minyue 8002013aeced2b7821a407f302802c4a16fd02728b1Minyue if (!shared_->statistics().Initialized()) { 8012013aeced2b7821a407f302802c4a16fd02728b1Minyue shared_->SetLastError(VE_NOT_INITED, kTraceError); 8022013aeced2b7821a407f302802c4a16fd02728b1Minyue return -1; 8032013aeced2b7821a407f302802c4a16fd02728b1Minyue } 8042013aeced2b7821a407f302802c4a16fd02728b1Minyue 8052013aeced2b7821a407f302802c4a16fd02728b1Minyue voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel); 8062013aeced2b7821a407f302802c4a16fd02728b1Minyue voe::Channel* channel_ptr = ch.channel(); 8072013aeced2b7821a407f302802c4a16fd02728b1Minyue if (channel_ptr == NULL) { 8082013aeced2b7821a407f302802c4a16fd02728b1Minyue shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, 8092013aeced2b7821a407f302802c4a16fd02728b1Minyue "AssociateSendChannel() failed to locate channel"); 8102013aeced2b7821a407f302802c4a16fd02728b1Minyue return -1; 8112013aeced2b7821a407f302802c4a16fd02728b1Minyue } 8122013aeced2b7821a407f302802c4a16fd02728b1Minyue 8132013aeced2b7821a407f302802c4a16fd02728b1Minyue ch = shared_->channel_manager().GetChannel(accociate_send_channel); 8142013aeced2b7821a407f302802c4a16fd02728b1Minyue voe::Channel* accociate_send_channel_ptr = ch.channel(); 8152013aeced2b7821a407f302802c4a16fd02728b1Minyue if (accociate_send_channel_ptr == NULL) { 8162013aeced2b7821a407f302802c4a16fd02728b1Minyue shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, 8172013aeced2b7821a407f302802c4a16fd02728b1Minyue "AssociateSendChannel() failed to locate accociate_send_channel"); 8182013aeced2b7821a407f302802c4a16fd02728b1Minyue return -1; 8192013aeced2b7821a407f302802c4a16fd02728b1Minyue } 8202013aeced2b7821a407f302802c4a16fd02728b1Minyue 8212013aeced2b7821a407f302802c4a16fd02728b1Minyue channel_ptr->set_associate_send_channel(ch); 8222013aeced2b7821a407f302802c4a16fd02728b1Minyue return 0; 8232013aeced2b7821a407f302802c4a16fd02728b1Minyue} 8242013aeced2b7821a407f302802c4a16fd02728b1Minyue 825d900e8bea84c474696bf0219aed1353ce65ffd8epbos@webrtc.org} // namespace webrtc 826