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