1b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org/*
2b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *
4b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  Use of this source code is governed by a BSD-style license
5b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  that can be found in the LICENSE file in the root of the source
6b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  tree. An additional intellectual property rights grant can be found
7b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  in the file PATENTS.  All contributing project authors may
8b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  be found in the AUTHORS file in the root of the source tree.
9b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org */
10b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
11471ae72f18e7b23a96b245dbd508386fe139449cpbos@webrtc.org#include "webrtc/voice_engine/voe_base_impl.h"
12b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
13b43ac9f2c5d33f5613ad2757e1e62a0aa3c2d34fturaj@webrtc.org#include "webrtc/common.h"
14471ae72f18e7b23a96b245dbd508386fe139449cpbos@webrtc.org#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
15471ae72f18e7b23a96b245dbd508386fe139449cpbos@webrtc.org#include "webrtc/modules/audio_coding/main/interface/audio_coding_module.h"
16471ae72f18e7b23a96b245dbd508386fe139449cpbos@webrtc.org#include "webrtc/modules/audio_device/audio_device_impl.h"
17471ae72f18e7b23a96b245dbd508386fe139449cpbos@webrtc.org#include "webrtc/modules/audio_processing/include/audio_processing.h"
18471ae72f18e7b23a96b245dbd508386fe139449cpbos@webrtc.org#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
19471ae72f18e7b23a96b245dbd508386fe139449cpbos@webrtc.org#include "webrtc/system_wrappers/interface/file_wrapper.h"
20471ae72f18e7b23a96b245dbd508386fe139449cpbos@webrtc.org#include "webrtc/system_wrappers/interface/trace.h"
21471ae72f18e7b23a96b245dbd508386fe139449cpbos@webrtc.org#include "webrtc/voice_engine/channel.h"
22471ae72f18e7b23a96b245dbd508386fe139449cpbos@webrtc.org#include "webrtc/voice_engine/include/voe_errors.h"
23471ae72f18e7b23a96b245dbd508386fe139449cpbos@webrtc.org#include "webrtc/voice_engine/output_mixer.h"
24471ae72f18e7b23a96b245dbd508386fe139449cpbos@webrtc.org#include "webrtc/voice_engine/transmit_mixer.h"
25471ae72f18e7b23a96b245dbd508386fe139449cpbos@webrtc.org#include "webrtc/voice_engine/utility.h"
26471ae72f18e7b23a96b245dbd508386fe139449cpbos@webrtc.org#include "webrtc/voice_engine/voice_engine_impl.h"
27b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
28b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgnamespace webrtc
29b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
30b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
31b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgVoEBase* VoEBase::GetInterface(VoiceEngine* voiceEngine)
32b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
33b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (NULL == voiceEngine)
34b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
35b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return NULL;
36b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
37b9e5a3d589349ee55e41cb54eca4ec822018f5c5tommi@webrtc.org    VoiceEngineImpl* s = static_cast<VoiceEngineImpl*>(voiceEngine);
38b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    s->AddRef();
39b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return s;
40b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
41b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
42b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgVoEBaseImpl::VoEBaseImpl(voe::SharedData* shared) :
43b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _voiceEngineObserverPtr(NULL),
44b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _callbackCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
45ad065d00af1d67641f9dbba6b6842d68daa714c1andrew@webrtc.org    _voiceEngineObserver(false), _shared(shared)
46b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
47b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
48b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "VoEBaseImpl() - ctor");
49b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
50b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
51b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgVoEBaseImpl::~VoEBaseImpl()
52b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
53b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
54b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "~VoEBaseImpl() - dtor");
55b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
56b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    TerminateInternal();
57b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
58b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    delete &_callbackCritSect;
59b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
60b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
61ca7a9a2696d2f73f543241093c4faeb4c608678cpbos@webrtc.orgvoid VoEBaseImpl::OnErrorIsReported(ErrorCode error)
62b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
63b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    CriticalSectionScoped cs(&_callbackCritSect);
64b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_voiceEngineObserver)
65b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
66b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (_voiceEngineObserverPtr)
67b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
68b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            int errCode(0);
69b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            if (error == AudioDeviceObserver::kRecordingError)
70b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
71b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                errCode = VE_RUNTIME_REC_ERROR;
72b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                WEBRTC_TRACE(kTraceInfo, kTraceVoice,
73b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    VoEId(_shared->instance_id(), -1),
74b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    "VoEBaseImpl::OnErrorIsReported() => VE_RUNTIME_REC_ERROR");
75b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
76b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            else if (error == AudioDeviceObserver::kPlayoutError)
77b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
78b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                errCode = VE_RUNTIME_PLAY_ERROR;
79b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                WEBRTC_TRACE(kTraceInfo, kTraceVoice,
80b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    VoEId(_shared->instance_id(), -1),
81b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    "VoEBaseImpl::OnErrorIsReported() => "
82b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    "VE_RUNTIME_PLAY_ERROR");
83b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
84b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            // Deliver callback (-1 <=> no channel dependency)
85b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            _voiceEngineObserverPtr->CallbackOnError(-1, errCode);
86b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
87b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
88b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
89b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
90ca7a9a2696d2f73f543241093c4faeb4c608678cpbos@webrtc.orgvoid VoEBaseImpl::OnWarningIsReported(WarningCode warning)
91b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
92b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    CriticalSectionScoped cs(&_callbackCritSect);
93b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_voiceEngineObserver)
94b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
95b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (_voiceEngineObserverPtr)
96b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
97b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            int warningCode(0);
98b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            if (warning == AudioDeviceObserver::kRecordingWarning)
99b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
100b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                warningCode = VE_RUNTIME_REC_WARNING;
101b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                WEBRTC_TRACE(kTraceInfo, kTraceVoice,
102b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    VoEId(_shared->instance_id(), -1),
103b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    "VoEBaseImpl::OnErrorIsReported() => "
104b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    "VE_RUNTIME_REC_WARNING");
105b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
106b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            else if (warning == AudioDeviceObserver::kPlayoutWarning)
107b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
108b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                warningCode = VE_RUNTIME_PLAY_WARNING;
109b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                WEBRTC_TRACE(kTraceInfo, kTraceVoice,
110b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    VoEId(_shared->instance_id(), -1),
111b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    "VoEBaseImpl::OnErrorIsReported() => "
112b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    "VE_RUNTIME_PLAY_WARNING");
113b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
114b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            // Deliver callback (-1 <=> no channel dependency)
115b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            _voiceEngineObserverPtr->CallbackOnError(-1, warningCode);
116b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
117b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
118b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
119b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
12054f03bc96c30337a3a97af7262cfb5148063b162pbos@webrtc.orgint32_t VoEBaseImpl::RecordedDataIsAvailable(
121b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        const void* audioSamples,
122ca7a9a2696d2f73f543241093c4faeb4c608678cpbos@webrtc.org        uint32_t nSamples,
123ca7a9a2696d2f73f543241093c4faeb4c608678cpbos@webrtc.org        uint8_t nBytesPerSample,
124ca7a9a2696d2f73f543241093c4faeb4c608678cpbos@webrtc.org        uint8_t nChannels,
125ca7a9a2696d2f73f543241093c4faeb4c608678cpbos@webrtc.org        uint32_t samplesPerSec,
126ca7a9a2696d2f73f543241093c4faeb4c608678cpbos@webrtc.org        uint32_t totalDelayMS,
127ca7a9a2696d2f73f543241093c4faeb4c608678cpbos@webrtc.org        int32_t clockDrift,
128ad065d00af1d67641f9dbba6b6842d68daa714c1andrew@webrtc.org        uint32_t micLevel,
129ca7a9a2696d2f73f543241093c4faeb4c608678cpbos@webrtc.org        bool keyPressed,
13054f03bc96c30337a3a97af7262cfb5148063b162pbos@webrtc.org        uint32_t& newMicLevel)
131b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
132b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_shared->instance_id(), -1),
133b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "VoEBaseImpl::RecordedDataIsAvailable(nSamples=%u, "
134b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "nBytesPerSample=%u, nChannels=%u, samplesPerSec=%u, "
135ad065d00af1d67641f9dbba6b6842d68daa714c1andrew@webrtc.org                     "totalDelayMS=%u, clockDrift=%d, micLevel=%u)",
136b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 nSamples, nBytesPerSample, nChannels, samplesPerSec,
137ad065d00af1d67641f9dbba6b6842d68daa714c1andrew@webrtc.org                 totalDelayMS, clockDrift, micLevel);
1380e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org    newMicLevel = static_cast<uint32_t>(ProcessRecordedDataWithAPM(
1390e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org        NULL, 0, audioSamples, samplesPerSec, nChannels, nSamples,
140ad065d00af1d67641f9dbba6b6842d68daa714c1andrew@webrtc.org        totalDelayMS, clockDrift, micLevel, keyPressed));
141b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
142b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
143b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
144b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
14554f03bc96c30337a3a97af7262cfb5148063b162pbos@webrtc.orgint32_t VoEBaseImpl::NeedMorePlayData(
146ca7a9a2696d2f73f543241093c4faeb4c608678cpbos@webrtc.org        uint32_t nSamples,
147ca7a9a2696d2f73f543241093c4faeb4c608678cpbos@webrtc.org        uint8_t nBytesPerSample,
148ca7a9a2696d2f73f543241093c4faeb4c608678cpbos@webrtc.org        uint8_t nChannels,
149ca7a9a2696d2f73f543241093c4faeb4c608678cpbos@webrtc.org        uint32_t samplesPerSec,
150b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        void* audioSamples,
15122f69bd27abc89979460df6d01de8685cb058aabwu@webrtc.org        uint32_t& nSamplesOut,
15281f8df9af96c6b4bf43234f2a0162146a5da6112wu@webrtc.org        int64_t* elapsed_time_ms,
15322f69bd27abc89979460df6d01de8685cb058aabwu@webrtc.org        int64_t* ntp_time_ms)
154b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
15591d88e1320d33fdc3648041bd941509e722f3ac4xians@webrtc.org  WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_shared->instance_id(), -1),
15691d88e1320d33fdc3648041bd941509e722f3ac4xians@webrtc.org               "VoEBaseImpl::NeedMorePlayData(nSamples=%u, "
15791d88e1320d33fdc3648041bd941509e722f3ac4xians@webrtc.org               "nBytesPerSample=%d, nChannels=%d, samplesPerSec=%u)",
15891d88e1320d33fdc3648041bd941509e722f3ac4xians@webrtc.org               nSamples, nBytesPerSample, nChannels, samplesPerSec);
159b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
16091d88e1320d33fdc3648041bd941509e722f3ac4xians@webrtc.org  GetPlayoutData(static_cast<int>(samplesPerSec),
16191d88e1320d33fdc3648041bd941509e722f3ac4xians@webrtc.org                 static_cast<int>(nChannels),
16222f69bd27abc89979460df6d01de8685cb058aabwu@webrtc.org                 static_cast<int>(nSamples), true, audioSamples,
16381f8df9af96c6b4bf43234f2a0162146a5da6112wu@webrtc.org                 elapsed_time_ms, ntp_time_ms);
164b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
16591d88e1320d33fdc3648041bd941509e722f3ac4xians@webrtc.org  nSamplesOut = _audioFrame.samples_per_channel_;
166b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
16791d88e1320d33fdc3648041bd941509e722f3ac4xians@webrtc.org  return 0;
168b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
169b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1700e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.orgint VoEBaseImpl::OnDataAvailable(const int voe_channels[],
17144f1239d9595c91f69f656e5beb1382463c4da8fxians@webrtc.org                                 int number_of_voe_channels,
17244f1239d9595c91f69f656e5beb1382463c4da8fxians@webrtc.org                                 const int16_t* audio_data,
17344f1239d9595c91f69f656e5beb1382463c4da8fxians@webrtc.org                                 int sample_rate,
17444f1239d9595c91f69f656e5beb1382463c4da8fxians@webrtc.org                                 int number_of_channels,
17544f1239d9595c91f69f656e5beb1382463c4da8fxians@webrtc.org                                 int number_of_frames,
17644f1239d9595c91f69f656e5beb1382463c4da8fxians@webrtc.org                                 int audio_delay_milliseconds,
177ad065d00af1d67641f9dbba6b6842d68daa714c1andrew@webrtc.org                                 int volume,
17844f1239d9595c91f69f656e5beb1382463c4da8fxians@webrtc.org                                 bool key_pressed,
17944f1239d9595c91f69f656e5beb1382463c4da8fxians@webrtc.org                                 bool need_audio_processing) {
18044f1239d9595c91f69f656e5beb1382463c4da8fxians@webrtc.org  WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_shared->instance_id(), -1),
18144f1239d9595c91f69f656e5beb1382463c4da8fxians@webrtc.org               "VoEBaseImpl::OnDataAvailable(number_of_voe_channels=%d, "
18244f1239d9595c91f69f656e5beb1382463c4da8fxians@webrtc.org               "sample_rate=%d, number_of_channels=%d, number_of_frames=%d, "
183ad065d00af1d67641f9dbba6b6842d68daa714c1andrew@webrtc.org               "audio_delay_milliseconds=%d, volume=%d, "
18444f1239d9595c91f69f656e5beb1382463c4da8fxians@webrtc.org               "key_pressed=%d, need_audio_processing=%d)",
18544f1239d9595c91f69f656e5beb1382463c4da8fxians@webrtc.org               number_of_voe_channels, sample_rate, number_of_channels,
186ad065d00af1d67641f9dbba6b6842d68daa714c1andrew@webrtc.org               number_of_frames, audio_delay_milliseconds, volume,
18744f1239d9595c91f69f656e5beb1382463c4da8fxians@webrtc.org               key_pressed, need_audio_processing);
1880e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org  if (number_of_voe_channels == 0)
1890e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org    return 0;
19044f1239d9595c91f69f656e5beb1382463c4da8fxians@webrtc.org
19144f1239d9595c91f69f656e5beb1382463c4da8fxians@webrtc.org  if (need_audio_processing) {
1920e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org    return ProcessRecordedDataWithAPM(
1930e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org        voe_channels, number_of_voe_channels, audio_data, sample_rate,
1940e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org        number_of_channels, number_of_frames, audio_delay_milliseconds,
195ad065d00af1d67641f9dbba6b6842d68daa714c1andrew@webrtc.org        0, volume, key_pressed);
19644f1239d9595c91f69f656e5beb1382463c4da8fxians@webrtc.org  }
19744f1239d9595c91f69f656e5beb1382463c4da8fxians@webrtc.org
19844f1239d9595c91f69f656e5beb1382463c4da8fxians@webrtc.org  // No need to go through the APM, demultiplex the data to each VoE channel,
19944f1239d9595c91f69f656e5beb1382463c4da8fxians@webrtc.org  // encode and send to the network.
20044f1239d9595c91f69f656e5beb1382463c4da8fxians@webrtc.org  for (int i = 0; i < number_of_voe_channels; ++i) {
201f7c73b531c9f2aca2adb87044613a7b7fa94de84andrew@webrtc.org    // TODO(ajm): In the case where multiple channels are using the same codec
202f7c73b531c9f2aca2adb87044613a7b7fa94de84andrew@webrtc.org    // rate, this path needlessly does extra conversions. We should convert once
203f7c73b531c9f2aca2adb87044613a7b7fa94de84andrew@webrtc.org    // and share between channels.
20491d88e1320d33fdc3648041bd941509e722f3ac4xians@webrtc.org    PushCaptureData(voe_channels[i], audio_data, 16, sample_rate,
20591d88e1320d33fdc3648041bd941509e722f3ac4xians@webrtc.org                    number_of_channels, number_of_frames);
20644f1239d9595c91f69f656e5beb1382463c4da8fxians@webrtc.org  }
20744f1239d9595c91f69f656e5beb1382463c4da8fxians@webrtc.org
20844f1239d9595c91f69f656e5beb1382463c4da8fxians@webrtc.org  // Return 0 to indicate no need to change the volume.
20944f1239d9595c91f69f656e5beb1382463c4da8fxians@webrtc.org  return 0;
21044f1239d9595c91f69f656e5beb1382463c4da8fxians@webrtc.org}
21144f1239d9595c91f69f656e5beb1382463c4da8fxians@webrtc.org
21287c8b86c9f8a9929a2a564b2833244c6290e4701xians@webrtc.orgvoid VoEBaseImpl::OnData(int voe_channel, const void* audio_data,
21387c8b86c9f8a9929a2a564b2833244c6290e4701xians@webrtc.org                         int bits_per_sample, int sample_rate,
21487c8b86c9f8a9929a2a564b2833244c6290e4701xians@webrtc.org                         int number_of_channels,
21587c8b86c9f8a9929a2a564b2833244c6290e4701xians@webrtc.org                         int number_of_frames) {
21691d88e1320d33fdc3648041bd941509e722f3ac4xians@webrtc.org  PushCaptureData(voe_channel, audio_data, bits_per_sample, sample_rate,
21791d88e1320d33fdc3648041bd941509e722f3ac4xians@webrtc.org                  number_of_channels, number_of_frames);
21891d88e1320d33fdc3648041bd941509e722f3ac4xians@webrtc.org}
21991d88e1320d33fdc3648041bd941509e722f3ac4xians@webrtc.org
22091d88e1320d33fdc3648041bd941509e722f3ac4xians@webrtc.orgvoid VoEBaseImpl::PushCaptureData(int voe_channel, const void* audio_data,
22191d88e1320d33fdc3648041bd941509e722f3ac4xians@webrtc.org                                  int bits_per_sample, int sample_rate,
22291d88e1320d33fdc3648041bd941509e722f3ac4xians@webrtc.org                                  int number_of_channels,
22391d88e1320d33fdc3648041bd941509e722f3ac4xians@webrtc.org                                  int number_of_frames) {
224942ba53c7737740f4513cc658e51c41c8839a3a6xians@webrtc.org  voe::ChannelOwner ch = _shared->channel_manager().GetChannel(voe_channel);
225942ba53c7737740f4513cc658e51c41c8839a3a6xians@webrtc.org  voe::Channel* channel_ptr = ch.channel();
226942ba53c7737740f4513cc658e51c41c8839a3a6xians@webrtc.org  if (!channel_ptr)
227942ba53c7737740f4513cc658e51c41c8839a3a6xians@webrtc.org    return;
228942ba53c7737740f4513cc658e51c41c8839a3a6xians@webrtc.org
229692224a58367e945336c7fd62376fcfa54497437henrika@webrtc.org  if (channel_ptr->Sending()) {
230942ba53c7737740f4513cc658e51c41c8839a3a6xians@webrtc.org    channel_ptr->Demultiplex(static_cast<const int16_t*>(audio_data),
231942ba53c7737740f4513cc658e51c41c8839a3a6xians@webrtc.org                             sample_rate, number_of_frames, number_of_channels);
232942ba53c7737740f4513cc658e51c41c8839a3a6xians@webrtc.org    channel_ptr->PrepareEncodeAndSend(sample_rate);
233942ba53c7737740f4513cc658e51c41c8839a3a6xians@webrtc.org    channel_ptr->EncodeAndSend();
234942ba53c7737740f4513cc658e51c41c8839a3a6xians@webrtc.org  }
235942ba53c7737740f4513cc658e51c41c8839a3a6xians@webrtc.org}
236942ba53c7737740f4513cc658e51c41c8839a3a6xians@webrtc.org
23791d88e1320d33fdc3648041bd941509e722f3ac4xians@webrtc.orgvoid VoEBaseImpl::PullRenderData(int bits_per_sample, int sample_rate,
23891d88e1320d33fdc3648041bd941509e722f3ac4xians@webrtc.org                                 int number_of_channels, int number_of_frames,
23922f69bd27abc89979460df6d01de8685cb058aabwu@webrtc.org                                 void* audio_data,
24081f8df9af96c6b4bf43234f2a0162146a5da6112wu@webrtc.org                                 int64_t* elapsed_time_ms,
24122f69bd27abc89979460df6d01de8685cb058aabwu@webrtc.org                                 int64_t* ntp_time_ms) {
24291d88e1320d33fdc3648041bd941509e722f3ac4xians@webrtc.org  assert(bits_per_sample == 16);
24391d88e1320d33fdc3648041bd941509e722f3ac4xians@webrtc.org  assert(number_of_frames == static_cast<int>(sample_rate / 100));
24491d88e1320d33fdc3648041bd941509e722f3ac4xians@webrtc.org
24591d88e1320d33fdc3648041bd941509e722f3ac4xians@webrtc.org  GetPlayoutData(sample_rate, number_of_channels, number_of_frames, false,
24681f8df9af96c6b4bf43234f2a0162146a5da6112wu@webrtc.org                 audio_data, elapsed_time_ms, ntp_time_ms);
24791d88e1320d33fdc3648041bd941509e722f3ac4xians@webrtc.org}
24891d88e1320d33fdc3648041bd941509e722f3ac4xians@webrtc.org
249b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint VoEBaseImpl::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
250b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
251b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
252b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "RegisterVoiceEngineObserver(observer=0x%d)", &observer);
253b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    CriticalSectionScoped cs(&_callbackCritSect);
254b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_voiceEngineObserverPtr)
255b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
256b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _shared->SetLastError(VE_INVALID_OPERATION, kTraceError,
257b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            "RegisterVoiceEngineObserver() observer already enabled");
258b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
259b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
260b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
261b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Register the observer in all active channels
262b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org    for (voe::ChannelManager::Iterator it(&_shared->channel_manager());
263b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org         it.IsValid();
264b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org         it.Increment()) {
265b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org      it.GetChannel()->RegisterVoiceEngineObserver(observer);
266b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
267b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org
268b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _shared->transmit_mixer()->RegisterVoiceEngineObserver(observer);
269b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
270b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _voiceEngineObserverPtr = &observer;
271b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _voiceEngineObserver = true;
272b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
273b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
274b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
275b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
276b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint VoEBaseImpl::DeRegisterVoiceEngineObserver()
277b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
278b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
279b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "DeRegisterVoiceEngineObserver()");
280b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    CriticalSectionScoped cs(&_callbackCritSect);
281b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!_voiceEngineObserverPtr)
282b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
283b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _shared->SetLastError(VE_INVALID_OPERATION, kTraceError,
284b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            "DeRegisterVoiceEngineObserver() observer already disabled");
285b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return 0;
286b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
287b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
288b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _voiceEngineObserver = false;
289b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _voiceEngineObserverPtr = NULL;
290b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
291b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Deregister the observer in all active channels
292b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org    for (voe::ChannelManager::Iterator it(&_shared->channel_manager());
293b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org         it.IsValid();
294b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org         it.Increment()) {
295b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org      it.GetChannel()->DeRegisterVoiceEngineObserver();
296b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
297b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
298b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
299b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
300b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
301b79627b0f3cf072721f3ae4a584a4f90edba2d1bandrew@webrtc.orgint VoEBaseImpl::Init(AudioDeviceModule* external_adm,
302b79627b0f3cf072721f3ae4a584a4f90edba2d1bandrew@webrtc.org                      AudioProcessing* audioproc)
303b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
304b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
305b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        "Init(external_adm=0x%p)", external_adm);
306b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    CriticalSectionScoped cs(_shared->crit_sec());
307b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
308b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WebRtcSpl_Init();
309b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
310b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_shared->statistics().Initialized())
311b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
312b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return 0;
313b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
314b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
315b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_shared->process_thread())
316b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
317b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (_shared->process_thread()->Start() != 0)
318b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
319b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            _shared->SetLastError(VE_THREAD_ERROR, kTraceError,
320b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                "Init() failed to start module process thread");
321b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            return -1;
322b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
323b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
324b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
325b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Create an internal ADM if the user has not added an external
326b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // ADM implementation as input to Init().
327b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (external_adm == NULL)
328b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
329b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // Create the internal ADM implementation.
330b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _shared->set_audio_device(AudioDeviceModuleImpl::Create(
331b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            VoEId(_shared->instance_id(), -1), _shared->audio_device_layer()));
332b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
333b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (_shared->audio_device() == NULL)
334b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
335b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            _shared->SetLastError(VE_NO_MEMORY, kTraceCritical,
336b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                "Init() failed to create the ADM");
337b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            return -1;
338b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
339b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
340b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    else
341b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
342b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // Use the already existing external ADM implementation.
343b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _shared->set_audio_device(external_adm);
344b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
345b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            "An external ADM implementation will be used in VoiceEngine");
346b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
347b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
348b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Register the ADM to the process thread, which will drive the error
349b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // callback mechanism
350b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_shared->process_thread() &&
351b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _shared->process_thread()->RegisterModule(_shared->audio_device()) != 0)
352b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
353b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
354b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            "Init() failed to register the ADM");
355b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
356b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
357b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
358b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    bool available(false);
359b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
360b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // --------------------
361b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Reinitialize the ADM
362b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
363b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Register the AudioObserver implementation
364b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_shared->audio_device()->RegisterEventObserver(this) != 0) {
365b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
366b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org          "Init() failed to register event observer for the ADM");
367b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
368b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
369b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Register the AudioTransport implementation
370b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_shared->audio_device()->RegisterAudioCallback(this) != 0) {
371b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
372b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org          "Init() failed to register audio callback for the ADM");
373b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
374b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
375b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // ADM initialization
376b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_shared->audio_device()->Init() != 0)
377b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
378b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
379b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            "Init() failed to initialize the ADM");
380b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
381b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
382b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
383b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Initialize the default speaker
384b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_shared->audio_device()->SetPlayoutDevice(
385b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0)
386b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
387b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceInfo,
388b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            "Init() failed to set the default output device");
389b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
390b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_shared->audio_device()->InitSpeaker() != 0)
391b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
392b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _shared->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceInfo,
393b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            "Init() failed to initialize the speaker");
394b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
395b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
396b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Initialize the default microphone
397b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_shared->audio_device()->SetRecordingDevice(
398b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0)
399b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
400b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceInfo,
401b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            "Init() failed to set the default input device");
402b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
403b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_shared->audio_device()->InitMicrophone() != 0)
404b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
405b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _shared->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceInfo,
406b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            "Init() failed to initialize the microphone");
407b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
408b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
409b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Set number of channels
410b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_shared->audio_device()->StereoPlayoutIsAvailable(&available) != 0) {
411b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
412b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org          "Init() failed to query stereo playout mode");
413b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
414b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_shared->audio_device()->SetStereoPlayout(available) != 0)
415b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
416b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
417b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            "Init() failed to set mono/stereo playout mode");
418b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
419b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
420b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // TODO(andrew): These functions don't tell us whether stereo recording
421b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // is truly available. We simply set the AudioProcessing input to stereo
422b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // here, because we have to wait until receiving the first frame to
423b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // determine the actual number of channels anyway.
424b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    //
425b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // These functions may be changed; tracked here:
426b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // http://code.google.com/p/webrtc/issues/detail?id=204
427b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _shared->audio_device()->StereoRecordingIsAvailable(&available);
428b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_shared->audio_device()->SetStereoRecording(available) != 0)
429b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
430b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
431b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            "Init() failed to set mono/stereo recording mode");
432b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
433b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
434b79627b0f3cf072721f3ae4a584a4f90edba2d1bandrew@webrtc.org    if (!audioproc) {
435b79627b0f3cf072721f3ae4a584a4f90edba2d1bandrew@webrtc.org      audioproc = AudioProcessing::Create(VoEId(_shared->instance_id(), -1));
436b79627b0f3cf072721f3ae4a584a4f90edba2d1bandrew@webrtc.org      if (!audioproc) {
437b79627b0f3cf072721f3ae4a584a4f90edba2d1bandrew@webrtc.org        LOG(LS_ERROR) << "Failed to create AudioProcessing.";
438b79627b0f3cf072721f3ae4a584a4f90edba2d1bandrew@webrtc.org        _shared->SetLastError(VE_NO_MEMORY);
439b79627b0f3cf072721f3ae4a584a4f90edba2d1bandrew@webrtc.org        return -1;
440b79627b0f3cf072721f3ae4a584a4f90edba2d1bandrew@webrtc.org      }
441b79627b0f3cf072721f3ae4a584a4f90edba2d1bandrew@webrtc.org    }
442b79627b0f3cf072721f3ae4a584a4f90edba2d1bandrew@webrtc.org    _shared->set_audio_processing(audioproc);
443b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
444b79627b0f3cf072721f3ae4a584a4f90edba2d1bandrew@webrtc.org    // Set the error state for any failures in this block.
445b79627b0f3cf072721f3ae4a584a4f90edba2d1bandrew@webrtc.org    _shared->SetLastError(VE_APM_ERROR);
446e06943f2aeb970e7c11070c327ab3b3264e2722fandrew@webrtc.org    // Configure AudioProcessing components.
447b79627b0f3cf072721f3ae4a584a4f90edba2d1bandrew@webrtc.org    if (audioproc->high_pass_filter()->Enable(true) != 0) {
448b79627b0f3cf072721f3ae4a584a4f90edba2d1bandrew@webrtc.org      LOG_FERR1(LS_ERROR, high_pass_filter()->Enable, true);
449b79627b0f3cf072721f3ae4a584a4f90edba2d1bandrew@webrtc.org      return -1;
450b79627b0f3cf072721f3ae4a584a4f90edba2d1bandrew@webrtc.org    }
451b79627b0f3cf072721f3ae4a584a4f90edba2d1bandrew@webrtc.org    if (audioproc->echo_cancellation()->enable_drift_compensation(false) != 0) {
452b79627b0f3cf072721f3ae4a584a4f90edba2d1bandrew@webrtc.org      LOG_FERR1(LS_ERROR, enable_drift_compensation, false);
453b79627b0f3cf072721f3ae4a584a4f90edba2d1bandrew@webrtc.org      return -1;
454b79627b0f3cf072721f3ae4a584a4f90edba2d1bandrew@webrtc.org    }
455b79627b0f3cf072721f3ae4a584a4f90edba2d1bandrew@webrtc.org    if (audioproc->noise_suppression()->set_level(kDefaultNsMode) != 0) {
456b79627b0f3cf072721f3ae4a584a4f90edba2d1bandrew@webrtc.org      LOG_FERR1(LS_ERROR, noise_suppression()->set_level, kDefaultNsMode);
457b79627b0f3cf072721f3ae4a584a4f90edba2d1bandrew@webrtc.org      return -1;
458b79627b0f3cf072721f3ae4a584a4f90edba2d1bandrew@webrtc.org    }
459b79627b0f3cf072721f3ae4a584a4f90edba2d1bandrew@webrtc.org    GainControl* agc = audioproc->gain_control();
460b79627b0f3cf072721f3ae4a584a4f90edba2d1bandrew@webrtc.org    if (agc->set_analog_level_limits(kMinVolumeLevel, kMaxVolumeLevel) != 0) {
461b79627b0f3cf072721f3ae4a584a4f90edba2d1bandrew@webrtc.org      LOG_FERR2(LS_ERROR, agc->set_analog_level_limits, kMinVolumeLevel,
462b79627b0f3cf072721f3ae4a584a4f90edba2d1bandrew@webrtc.org                kMaxVolumeLevel);
463b79627b0f3cf072721f3ae4a584a4f90edba2d1bandrew@webrtc.org      return -1;
464b79627b0f3cf072721f3ae4a584a4f90edba2d1bandrew@webrtc.org    }
465b79627b0f3cf072721f3ae4a584a4f90edba2d1bandrew@webrtc.org    if (agc->set_mode(kDefaultAgcMode) != 0) {
466b79627b0f3cf072721f3ae4a584a4f90edba2d1bandrew@webrtc.org      LOG_FERR1(LS_ERROR, agc->set_mode, kDefaultAgcMode);
467b79627b0f3cf072721f3ae4a584a4f90edba2d1bandrew@webrtc.org      return -1;
468b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
469b79627b0f3cf072721f3ae4a584a4f90edba2d1bandrew@webrtc.org    if (agc->Enable(kDefaultAgcState) != 0) {
470b79627b0f3cf072721f3ae4a584a4f90edba2d1bandrew@webrtc.org      LOG_FERR1(LS_ERROR, agc->Enable, kDefaultAgcState);
471b79627b0f3cf072721f3ae4a584a4f90edba2d1bandrew@webrtc.org      return -1;
472b79627b0f3cf072721f3ae4a584a4f90edba2d1bandrew@webrtc.org    }
473b79627b0f3cf072721f3ae4a584a4f90edba2d1bandrew@webrtc.org    _shared->SetLastError(0);  // Clear error state.
474b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
475b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#ifdef WEBRTC_VOICE_ENGINE_AGC
476b79627b0f3cf072721f3ae4a584a4f90edba2d1bandrew@webrtc.org    bool agc_enabled = agc->mode() == GainControl::kAdaptiveAnalog &&
477b79627b0f3cf072721f3ae4a584a4f90edba2d1bandrew@webrtc.org                       agc->is_enabled();
478b79627b0f3cf072721f3ae4a584a4f90edba2d1bandrew@webrtc.org    if (_shared->audio_device()->SetAGC(agc_enabled) != 0) {
479b79627b0f3cf072721f3ae4a584a4f90edba2d1bandrew@webrtc.org      LOG_FERR1(LS_ERROR, audio_device()->SetAGC, agc_enabled);
480b79627b0f3cf072721f3ae4a584a4f90edba2d1bandrew@webrtc.org      _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR);
4810f919be3c4aeb12157d9bda58c765050fed1ebf8andrew@webrtc.org      // TODO(ajm): No error return here due to
4820f919be3c4aeb12157d9bda58c765050fed1ebf8andrew@webrtc.org      // https://code.google.com/p/webrtc/issues/detail?id=1464
483b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
484b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#endif
485b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
486b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return _shared->statistics().SetInitialized();
487b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
488b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
489b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint VoEBaseImpl::Terminate()
490b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
491b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
492b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "Terminate()");
493b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    CriticalSectionScoped cs(_shared->crit_sec());
494b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return TerminateInternal();
495b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
496b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
497b43ac9f2c5d33f5613ad2757e1e62a0aa3c2d34fturaj@webrtc.orgint VoEBaseImpl::CreateChannel() {
498b43ac9f2c5d33f5613ad2757e1e62a0aa3c2d34fturaj@webrtc.org  WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
499b43ac9f2c5d33f5613ad2757e1e62a0aa3c2d34fturaj@webrtc.org               "CreateChannel()");
500b43ac9f2c5d33f5613ad2757e1e62a0aa3c2d34fturaj@webrtc.org  CriticalSectionScoped cs(_shared->crit_sec());
501b43ac9f2c5d33f5613ad2757e1e62a0aa3c2d34fturaj@webrtc.org  if (!_shared->statistics().Initialized()) {
502b43ac9f2c5d33f5613ad2757e1e62a0aa3c2d34fturaj@webrtc.org      _shared->SetLastError(VE_NOT_INITED, kTraceError);
503b43ac9f2c5d33f5613ad2757e1e62a0aa3c2d34fturaj@webrtc.org      return -1;
504b43ac9f2c5d33f5613ad2757e1e62a0aa3c2d34fturaj@webrtc.org  }
505b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
506b43ac9f2c5d33f5613ad2757e1e62a0aa3c2d34fturaj@webrtc.org  voe::ChannelOwner channel_owner = _shared->channel_manager().CreateChannel();
507b43ac9f2c5d33f5613ad2757e1e62a0aa3c2d34fturaj@webrtc.org
508b43ac9f2c5d33f5613ad2757e1e62a0aa3c2d34fturaj@webrtc.org  return InitializeChannel(&channel_owner);
509b43ac9f2c5d33f5613ad2757e1e62a0aa3c2d34fturaj@webrtc.org}
510b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
511b43ac9f2c5d33f5613ad2757e1e62a0aa3c2d34fturaj@webrtc.orgint VoEBaseImpl::CreateChannel(const Config& config) {
512b43ac9f2c5d33f5613ad2757e1e62a0aa3c2d34fturaj@webrtc.org  CriticalSectionScoped cs(_shared->crit_sec());
513b43ac9f2c5d33f5613ad2757e1e62a0aa3c2d34fturaj@webrtc.org  if (!_shared->statistics().Initialized()) {
514b43ac9f2c5d33f5613ad2757e1e62a0aa3c2d34fturaj@webrtc.org      _shared->SetLastError(VE_NOT_INITED, kTraceError);
515b43ac9f2c5d33f5613ad2757e1e62a0aa3c2d34fturaj@webrtc.org      return -1;
516b43ac9f2c5d33f5613ad2757e1e62a0aa3c2d34fturaj@webrtc.org  }
517b43ac9f2c5d33f5613ad2757e1e62a0aa3c2d34fturaj@webrtc.org  voe::ChannelOwner channel_owner = _shared->channel_manager().CreateChannel(
518b43ac9f2c5d33f5613ad2757e1e62a0aa3c2d34fturaj@webrtc.org      config);
519b43ac9f2c5d33f5613ad2757e1e62a0aa3c2d34fturaj@webrtc.org  return InitializeChannel(&channel_owner);
520b43ac9f2c5d33f5613ad2757e1e62a0aa3c2d34fturaj@webrtc.org}
521b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org
522b43ac9f2c5d33f5613ad2757e1e62a0aa3c2d34fturaj@webrtc.orgint VoEBaseImpl::InitializeChannel(voe::ChannelOwner* channel_owner)
523b43ac9f2c5d33f5613ad2757e1e62a0aa3c2d34fturaj@webrtc.org{
524b43ac9f2c5d33f5613ad2757e1e62a0aa3c2d34fturaj@webrtc.org    if (channel_owner->channel()->SetEngineInformation(
525b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org            _shared->statistics(),
526b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org            *_shared->output_mixer(),
527b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org            *_shared->transmit_mixer(),
528b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org            *_shared->process_thread(),
529b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org            *_shared->audio_device(),
530b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org            _voiceEngineObserverPtr,
531b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org            &_callbackCritSect) != 0) {
532b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org      _shared->SetLastError(
533b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org          VE_CHANNEL_NOT_CREATED,
534b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org          kTraceError,
535b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org          "CreateChannel() failed to associate engine and channel."
536b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org          " Destroying channel.");
537b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org      _shared->channel_manager()
538b43ac9f2c5d33f5613ad2757e1e62a0aa3c2d34fturaj@webrtc.org          .DestroyChannel(channel_owner->channel()->ChannelId());
539b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org      return -1;
540b43ac9f2c5d33f5613ad2757e1e62a0aa3c2d34fturaj@webrtc.org    } else if (channel_owner->channel()->Init() != 0) {
541b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org      _shared->SetLastError(
542b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org          VE_CHANNEL_NOT_CREATED,
543b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org          kTraceError,
544b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org          "CreateChannel() failed to initialize channel. Destroying"
545b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org          " channel.");
546b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org      _shared->channel_manager()
547b43ac9f2c5d33f5613ad2757e1e62a0aa3c2d34fturaj@webrtc.org          .DestroyChannel(channel_owner->channel()->ChannelId());
548b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org      return -1;
549b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
550b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
551b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
552b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        VoEId(_shared->instance_id(), -1),
553b43ac9f2c5d33f5613ad2757e1e62a0aa3c2d34fturaj@webrtc.org        "CreateChannel() => %d", channel_owner->channel()->ChannelId());
554b43ac9f2c5d33f5613ad2757e1e62a0aa3c2d34fturaj@webrtc.org    return channel_owner->channel()->ChannelId();
555b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
556b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
557b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint VoEBaseImpl::DeleteChannel(int channel)
558b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
559b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
560b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "DeleteChannel(channel=%d)", channel);
561b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    CriticalSectionScoped cs(_shared->crit_sec());
562b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
563b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!_shared->statistics().Initialized())
564b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
565b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _shared->SetLastError(VE_NOT_INITED, kTraceError);
566b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
567b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
568b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
569b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
570b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org        voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
571b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org        voe::Channel* channelPtr = ch.channel();
572b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (channelPtr == NULL)
573b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
574b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
575b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                "DeleteChannel() failed to locate channel");
576b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            return -1;
577b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
578b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
579b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
580b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org    _shared->channel_manager().DestroyChannel(channel);
581b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
582b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (StopSend() != 0)
583b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
584b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
585b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
586b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
587b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (StopPlayout() != 0)
588b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
589b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
590b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
591912b7f727086279bfa950dce96953fe018f49580pwestin@webrtc.org
592b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
593b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
594b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
595b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint VoEBaseImpl::StartReceive(int channel)
596b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
597b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
598b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "StartReceive(channel=%d)", channel);
599b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    CriticalSectionScoped cs(_shared->crit_sec());
600b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!_shared->statistics().Initialized())
601b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
602b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _shared->SetLastError(VE_NOT_INITED, kTraceError);
603b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
604b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
605b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org    voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
606b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org    voe::Channel* channelPtr = ch.channel();
607b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (channelPtr == NULL)
608b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
609b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
610b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            "StartReceive() failed to locate channel");
611b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
612b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
613b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return channelPtr->StartReceiving();
614b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
615b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
616b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint VoEBaseImpl::StopReceive(int channel)
617b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
618b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
619b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "StopListen(channel=%d)", channel);
620b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    CriticalSectionScoped cs(_shared->crit_sec());
621b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!_shared->statistics().Initialized())
622b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
623b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _shared->SetLastError(VE_NOT_INITED, kTraceError);
624b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
625b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
626b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org    voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
627b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org    voe::Channel* channelPtr = ch.channel();
628b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (channelPtr == NULL)
629b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
630b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
631b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            "SetLocalReceiver() failed to locate channel");
632b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
633b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
634b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return channelPtr->StopReceiving();
635b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
636b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
637b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint VoEBaseImpl::StartPlayout(int channel)
638b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
639b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
640b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "StartPlayout(channel=%d)", channel);
641b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    CriticalSectionScoped cs(_shared->crit_sec());
642b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!_shared->statistics().Initialized())
643b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
644b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _shared->SetLastError(VE_NOT_INITED, kTraceError);
645b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
646b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
647b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org    voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
648b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org    voe::Channel* channelPtr = ch.channel();
649b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (channelPtr == NULL)
650b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
651b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
652b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            "StartPlayout() failed to locate channel");
653b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
654b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
655b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (channelPtr->Playing())
656b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
657b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return 0;
658b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
659b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (StartPlayout() != 0)
660b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
661b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
662b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            "StartPlayout() failed to start playout");
663b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
664b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
665b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return channelPtr->StartPlayout();
666b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
667b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
668b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint VoEBaseImpl::StopPlayout(int channel)
669b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
670b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
671b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "StopPlayout(channel=%d)", channel);
672b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    CriticalSectionScoped cs(_shared->crit_sec());
673b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!_shared->statistics().Initialized())
674b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
675b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _shared->SetLastError(VE_NOT_INITED, kTraceError);
676b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
677b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
678b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org    voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
679b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org    voe::Channel* channelPtr = ch.channel();
680b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (channelPtr == NULL)
681b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
682b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
683b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            "StopPlayout() failed to locate channel");
684b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
685b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
686b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (channelPtr->StopPlayout() != 0)
687b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
688b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceWarning, kTraceVoice,
689b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            VoEId(_shared->instance_id(), -1),
690b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            "StopPlayout() failed to stop playout for channel %d", channel);
691b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
692b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return StopPlayout();
693b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
694b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
695b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint VoEBaseImpl::StartSend(int channel)
696b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
697b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
698b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "StartSend(channel=%d)", channel);
699b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    CriticalSectionScoped cs(_shared->crit_sec());
700b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!_shared->statistics().Initialized())
701b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
702b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _shared->SetLastError(VE_NOT_INITED, kTraceError);
703b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
704b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
705b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org    voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
706b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org    voe::Channel* channelPtr = ch.channel();
707b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (channelPtr == NULL)
708b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
709b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
710b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            "StartSend() failed to locate channel");
711b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
712b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
713b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (channelPtr->Sending())
714b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
715b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return 0;
716b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
717b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (StartSend() != 0)
718b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
719b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
720b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            "StartSend() failed to start recording");
721b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
722b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
723b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return channelPtr->StartSend();
724b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
725b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
726b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint VoEBaseImpl::StopSend(int channel)
727b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
728b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
729b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "StopSend(channel=%d)", channel);
730b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    CriticalSectionScoped cs(_shared->crit_sec());
731b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!_shared->statistics().Initialized())
732b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
733b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _shared->SetLastError(VE_NOT_INITED, kTraceError);
734b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
735b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
736b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org    voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
737b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org    voe::Channel* channelPtr = ch.channel();
738b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (channelPtr == NULL)
739b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
740b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
741b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            "StopSend() failed to locate channel");
742b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
743b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
744b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (channelPtr->StopSend() != 0)
745b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
746b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceWarning, kTraceVoice,
747b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            VoEId(_shared->instance_id(), -1),
748b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            "StopSend() failed to stop sending for channel %d", channel);
749b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
750b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return StopSend();
751b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
752b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
753b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint VoEBaseImpl::GetVersion(char version[1024])
754b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
755b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
756b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "GetVersion(version=?)");
757b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    assert(kVoiceEngineVersionMaxMessageSize == 1024);
758b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
759b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (version == NULL)
760b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
761b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError);
762b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return (-1);
763b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
764b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
765b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    char versionBuf[kVoiceEngineVersionMaxMessageSize];
766b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    char* versionPtr = versionBuf;
767b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
76854f03bc96c30337a3a97af7262cfb5148063b162pbos@webrtc.org    int32_t len = 0;
76954f03bc96c30337a3a97af7262cfb5148063b162pbos@webrtc.org    int32_t accLen = 0;
770b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
771b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    len = AddVoEVersion(versionPtr);
772b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (len == -1)
773b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
774b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
775b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
776b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    versionPtr += len;
777b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    accLen += len;
778b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    assert(accLen < kVoiceEngineVersionMaxMessageSize);
779b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
780b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    len = AddBuildInfo(versionPtr);
781b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (len == -1)
782b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
783b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
784b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
785b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    versionPtr += len;
786b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    accLen += len;
787b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    assert(accLen < kVoiceEngineVersionMaxMessageSize);
788b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
789912b7f727086279bfa950dce96953fe018f49580pwestin@webrtc.org#ifdef WEBRTC_EXTERNAL_TRANSPORT
790912b7f727086279bfa950dce96953fe018f49580pwestin@webrtc.org    len = AddExternalTransportBuild(versionPtr);
791912b7f727086279bfa950dce96953fe018f49580pwestin@webrtc.org    if (len == -1)
792912b7f727086279bfa950dce96953fe018f49580pwestin@webrtc.org    {
793912b7f727086279bfa950dce96953fe018f49580pwestin@webrtc.org         return -1;
794912b7f727086279bfa950dce96953fe018f49580pwestin@webrtc.org    }
795912b7f727086279bfa950dce96953fe018f49580pwestin@webrtc.org    versionPtr += len;
796912b7f727086279bfa950dce96953fe018f49580pwestin@webrtc.org    accLen += len;
797912b7f727086279bfa950dce96953fe018f49580pwestin@webrtc.org    assert(accLen < kVoiceEngineVersionMaxMessageSize);
798912b7f727086279bfa950dce96953fe018f49580pwestin@webrtc.org#endif
799b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
800b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    memcpy(version, versionBuf, accLen);
801b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    version[accLen] = '\0';
802b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
803b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // to avoid the truncation in the trace, split the string into parts
804b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    char partOfVersion[256];
805b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
806b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        VoEId(_shared->instance_id(), -1), "GetVersion() =>");
807b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    for (int partStart = 0; partStart < accLen;)
808b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
809b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        memset(partOfVersion, 0, sizeof(partOfVersion));
810b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        int partEnd = partStart + 180;
811b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        while (version[partEnd] != '\n' && version[partEnd] != '\0')
812b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
813b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            partEnd--;
814b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
815b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (partEnd < accLen)
816b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
817b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            memcpy(partOfVersion, &version[partStart], partEnd - partStart);
818b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
819b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        else
820b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
821b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            memcpy(partOfVersion, &version[partStart], accLen - partStart);
822b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
823b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        partStart = partEnd;
824b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
825b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            VoEId(_shared->instance_id(), -1), "%s", partOfVersion);
826b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
827b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
828b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
829b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
830b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
83154f03bc96c30337a3a97af7262cfb5148063b162pbos@webrtc.orgint32_t VoEBaseImpl::AddBuildInfo(char* str) const
832b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
833c7d736366468e04cd818fd74ee4844b954012614andrew@webrtc.org    return sprintf(str, "Build: %s\n", BUILDINFO);
834b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
835b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
83654f03bc96c30337a3a97af7262cfb5148063b162pbos@webrtc.orgint32_t VoEBaseImpl::AddVoEVersion(char* str) const
837b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
838b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return sprintf(str, "VoiceEngine 4.1.0\n");
839b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
840b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
841912b7f727086279bfa950dce96953fe018f49580pwestin@webrtc.org#ifdef WEBRTC_EXTERNAL_TRANSPORT
84254f03bc96c30337a3a97af7262cfb5148063b162pbos@webrtc.orgint32_t VoEBaseImpl::AddExternalTransportBuild(char* str) const
843912b7f727086279bfa950dce96953fe018f49580pwestin@webrtc.org{
844912b7f727086279bfa950dce96953fe018f49580pwestin@webrtc.org    return sprintf(str, "External transport build\n");
845912b7f727086279bfa950dce96953fe018f49580pwestin@webrtc.org}
846912b7f727086279bfa950dce96953fe018f49580pwestin@webrtc.org#endif
847912b7f727086279bfa950dce96953fe018f49580pwestin@webrtc.org
848b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgint VoEBaseImpl::LastError()
849b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
850b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
851b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "LastError()");
852b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return (_shared->statistics().LastError());
853b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
854b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
85554f03bc96c30337a3a97af7262cfb5148063b162pbos@webrtc.orgint32_t VoEBaseImpl::StartPlayout()
856b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
857b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
858b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "VoEBaseImpl::StartPlayout()");
859b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_shared->audio_device()->Playing())
860b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
861b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return 0;
862b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
863b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!_shared->ext_playout())
864b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
865b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (_shared->audio_device()->InitPlayout() != 0)
866b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
867b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            WEBRTC_TRACE(kTraceError, kTraceVoice,
868b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                VoEId(_shared->instance_id(), -1),
869b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                "StartPlayout() failed to initialize playout");
870b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            return -1;
871b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
872b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (_shared->audio_device()->StartPlayout() != 0)
873b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
874b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            WEBRTC_TRACE(kTraceError, kTraceVoice,
875b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                VoEId(_shared->instance_id(), -1),
876b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                "StartPlayout() failed to start playout");
877b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            return -1;
878b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
879b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
880b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
881b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
882b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
883b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.orgint32_t VoEBaseImpl::StopPlayout() {
884b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org  WEBRTC_TRACE(kTraceInfo,
885b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org               kTraceVoice,
886b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org               VoEId(_shared->instance_id(), -1),
887b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org               "VoEBaseImpl::StopPlayout()");
888b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org  // Stop audio-device playing if no channel is playing out
8893d553d4203f945029900c85c0e402e598fef4361xians@webrtc.org  if (_shared->NumOfPlayingChannels() == 0) {
890b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org    if (_shared->audio_device()->StopPlayout() != 0) {
891b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org      _shared->SetLastError(VE_CANNOT_STOP_PLAYOUT,
892b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org                            kTraceError,
893b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org                            "StopPlayout() failed to stop playout");
894b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org      return -1;
895b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
896b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org  }
897b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org  return 0;
898b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
899b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
90054f03bc96c30337a3a97af7262cfb5148063b162pbos@webrtc.orgint32_t VoEBaseImpl::StartSend()
901b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
902b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
903b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "VoEBaseImpl::StartSend()");
904b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_shared->audio_device()->Recording())
905b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
906b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return 0;
907b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
908b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!_shared->ext_recording())
909b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
910b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (_shared->audio_device()->InitRecording() != 0)
911b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
912b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            WEBRTC_TRACE(kTraceError, kTraceVoice,
913b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                VoEId(_shared->instance_id(), -1),
914b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                "StartSend() failed to initialize recording");
915b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            return -1;
916b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
917b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (_shared->audio_device()->StartRecording() != 0)
918b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
919b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            WEBRTC_TRACE(kTraceError, kTraceVoice,
920b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                VoEId(_shared->instance_id(), -1),
921b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                "StartSend() failed to start recording");
922b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            return -1;
923b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
924b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
925b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
926b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
927b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
928b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
92954f03bc96c30337a3a97af7262cfb5148063b162pbos@webrtc.orgint32_t VoEBaseImpl::StopSend()
930b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
931b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
932b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "VoEBaseImpl::StopSend()");
933b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
934b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_shared->NumOfSendingChannels() == 0 &&
935b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        !_shared->transmit_mixer()->IsRecordingMic())
936b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
937b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // Stop audio-device recording if no channel is recording
938b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (_shared->audio_device()->StopRecording() != 0)
939b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
940b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            _shared->SetLastError(VE_CANNOT_STOP_RECORDING, kTraceError,
941b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                "StopSend() failed to stop recording");
942b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            return -1;
943b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
944b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _shared->transmit_mixer()->StopSend();
945b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
946b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
947b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
948b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
949b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
95054f03bc96c30337a3a97af7262cfb5148063b162pbos@webrtc.orgint32_t VoEBaseImpl::TerminateInternal()
951b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
952b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
953b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "VoEBaseImpl::TerminateInternal()");
954b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
955b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Delete any remaining channel objects
956b3ada1540827c60a63058570a94a57dfd260ad11pbos@webrtc.org    _shared->channel_manager().DestroyAllChannels();
957b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
958b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_shared->process_thread())
959b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
960b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (_shared->audio_device())
961b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
962b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            if (_shared->process_thread()->
963b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    DeRegisterModule(_shared->audio_device()) != 0)
964b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
965b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                _shared->SetLastError(VE_THREAD_ERROR, kTraceError,
966b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    "TerminateInternal() failed to deregister ADM");
967b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
968b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
969b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (_shared->process_thread()->Stop() != 0)
970b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
971b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            _shared->SetLastError(VE_THREAD_ERROR, kTraceError,
972b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                "TerminateInternal() failed to stop module process thread");
973b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
974b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
975b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
976b79627b0f3cf072721f3ae4a584a4f90edba2d1bandrew@webrtc.org    if (_shared->audio_device())
977b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
978b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (_shared->audio_device()->StopPlayout() != 0)
979b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
980b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
981b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                "TerminateInternal() failed to stop playout");
982b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
983b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (_shared->audio_device()->StopRecording() != 0)
984b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
985b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
986b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                "TerminateInternal() failed to stop recording");
987b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
988b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (_shared->audio_device()->RegisterEventObserver(NULL) != 0) {
989b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org          _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
990b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org              "TerminateInternal() failed to de-register event observer "
991b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org              "for the ADM");
992b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
993b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (_shared->audio_device()->RegisterAudioCallback(NULL) != 0) {
994b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org          _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
995b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org              "TerminateInternal() failed to de-register audio callback "
996b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org              "for the ADM");
997b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
998b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (_shared->audio_device()->Terminate() != 0)
999b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
1000b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
1001b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                "TerminateInternal() failed to terminate the ADM");
1002b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
1003b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _shared->set_audio_device(NULL);
1004b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1005b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1006b79627b0f3cf072721f3ae4a584a4f90edba2d1bandrew@webrtc.org    if (_shared->audio_processing()) {
1007b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _shared->set_audio_processing(NULL);
1008b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
1009b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1010b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return _shared->statistics().SetUnInitialized();
1011b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
1012b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
10130e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.orgint VoEBaseImpl::ProcessRecordedDataWithAPM(
10140e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org    const int voe_channels[],
10150e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org    int number_of_voe_channels,
10160e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org    const void* audio_data,
10170e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org    uint32_t sample_rate,
10180e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org    uint8_t number_of_channels,
10190e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org    uint32_t number_of_frames,
10200e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org    uint32_t audio_delay_milliseconds,
10210e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org    int32_t clock_drift,
1022ad065d00af1d67641f9dbba6b6842d68daa714c1andrew@webrtc.org    uint32_t volume,
10230e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org    bool key_pressed) {
10240e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org  assert(_shared->transmit_mixer() != NULL);
10250e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org  assert(_shared->audio_device() != NULL);
10260e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org
10270e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org  uint32_t max_volume = 0;
1028ad065d00af1d67641f9dbba6b6842d68daa714c1andrew@webrtc.org  uint16_t voe_mic_level = 0;
102922470b5ee6298ed0fe8209563758ec171a1c4397andrew@webrtc.org  // Check for zero to skip this calculation; the consumer may use this to
103022470b5ee6298ed0fe8209563758ec171a1c4397andrew@webrtc.org  // indicate no volume is available.
1031ad065d00af1d67641f9dbba6b6842d68daa714c1andrew@webrtc.org  if (volume != 0) {
10320e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org    // Scale from ADM to VoE level range
10330e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org    if (_shared->audio_device()->MaxMicrophoneVolume(&max_volume) == 0) {
10340e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org      if (max_volume) {
1035ad065d00af1d67641f9dbba6b6842d68daa714c1andrew@webrtc.org        voe_mic_level = static_cast<uint16_t>(
1036ad065d00af1d67641f9dbba6b6842d68daa714c1andrew@webrtc.org            (volume * kMaxVolumeLevel +
10370e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org                static_cast<int>(max_volume / 2)) / max_volume);
10380e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org      }
10390e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org    }
1040ad065d00af1d67641f9dbba6b6842d68daa714c1andrew@webrtc.org    // We learned that on certain systems (e.g Linux) the voe_mic_level
10410e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org    // can be greater than the maxVolumeLevel therefore
1042ad065d00af1d67641f9dbba6b6842d68daa714c1andrew@webrtc.org    // we are going to cap the voe_mic_level to the maxVolumeLevel
1043ad065d00af1d67641f9dbba6b6842d68daa714c1andrew@webrtc.org    // and change the maxVolume to volume if it turns out that
1044ad065d00af1d67641f9dbba6b6842d68daa714c1andrew@webrtc.org    // the voe_mic_level is indeed greater than the maxVolumeLevel.
1045ad065d00af1d67641f9dbba6b6842d68daa714c1andrew@webrtc.org    if (voe_mic_level > kMaxVolumeLevel) {
1046ad065d00af1d67641f9dbba6b6842d68daa714c1andrew@webrtc.org      voe_mic_level = kMaxVolumeLevel;
1047ad065d00af1d67641f9dbba6b6842d68daa714c1andrew@webrtc.org      max_volume = volume;
10480e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org    }
10490e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org  }
10500e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org
10510e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org  // Perform channel-independent operations
10520e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org  // (APM, mix with file, record to file, mute, etc.)
10530e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org  _shared->transmit_mixer()->PrepareDemux(
10540e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org      audio_data, number_of_frames, number_of_channels, sample_rate,
10550e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org      static_cast<uint16_t>(audio_delay_milliseconds), clock_drift,
1056ad065d00af1d67641f9dbba6b6842d68daa714c1andrew@webrtc.org      voe_mic_level, key_pressed);
10570e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org
10580e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org  // Copy the audio frame to each sending channel and perform
10590e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org  // channel-dependent operations (file mixing, mute, etc.), encode and
10600e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org  // packetize+transmit the RTP packet. When |number_of_voe_channels| == 0,
10610e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org  // do the operations on all the existing VoE channels; otherwise the
10620e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org  // operations will be done on specific channels.
10630e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org  if (number_of_voe_channels == 0) {
10640e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org    _shared->transmit_mixer()->DemuxAndMix();
10650e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org    _shared->transmit_mixer()->EncodeAndSend();
10660e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org  } else {
10670e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org    _shared->transmit_mixer()->DemuxAndMix(voe_channels,
10680e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org                                           number_of_voe_channels);
10690e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org    _shared->transmit_mixer()->EncodeAndSend(voe_channels,
10700e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org                                             number_of_voe_channels);
10710e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org  }
10720e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org
10730e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org  // Scale from VoE to ADM level range.
10740e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org  uint32_t new_voe_mic_level = _shared->transmit_mixer()->CaptureLevel();
10750e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org
1076ad065d00af1d67641f9dbba6b6842d68daa714c1andrew@webrtc.org  if (new_voe_mic_level != voe_mic_level) {
10770e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org    // Return the new volume if AGC has changed the volume.
10780e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org    return static_cast<int>(
10790e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org        (new_voe_mic_level * max_volume +
10800e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org            static_cast<int>(kMaxVolumeLevel / 2)) / kMaxVolumeLevel);
10810e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org  }
10820e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org
10830e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org  // Return 0 to indicate no change on the volume.
10840e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org  return 0;
10850e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org}
10860e6fa8c05cde2587e30dcf5e405132193d60dd42xians@webrtc.org
108791d88e1320d33fdc3648041bd941509e722f3ac4xians@webrtc.orgvoid VoEBaseImpl::GetPlayoutData(int sample_rate, int number_of_channels,
108891d88e1320d33fdc3648041bd941509e722f3ac4xians@webrtc.org                                 int number_of_frames, bool feed_data_to_apm,
108922f69bd27abc89979460df6d01de8685cb058aabwu@webrtc.org                                 void* audio_data,
109081f8df9af96c6b4bf43234f2a0162146a5da6112wu@webrtc.org                                 int64_t* elapsed_time_ms,
109122f69bd27abc89979460df6d01de8685cb058aabwu@webrtc.org                                 int64_t* ntp_time_ms) {
109291d88e1320d33fdc3648041bd941509e722f3ac4xians@webrtc.org  assert(_shared->output_mixer() != NULL);
109391d88e1320d33fdc3648041bd941509e722f3ac4xians@webrtc.org
109491d88e1320d33fdc3648041bd941509e722f3ac4xians@webrtc.org  // TODO(andrew): if the device is running in mono, we should tell the mixer
109591d88e1320d33fdc3648041bd941509e722f3ac4xians@webrtc.org  // here so that it will only request mono from AudioCodingModule.
109691d88e1320d33fdc3648041bd941509e722f3ac4xians@webrtc.org  // Perform mixing of all active participants (channel-based mixing)
109791d88e1320d33fdc3648041bd941509e722f3ac4xians@webrtc.org  _shared->output_mixer()->MixActiveChannels();
109891d88e1320d33fdc3648041bd941509e722f3ac4xians@webrtc.org
109991d88e1320d33fdc3648041bd941509e722f3ac4xians@webrtc.org  // Additional operations on the combined signal
110091d88e1320d33fdc3648041bd941509e722f3ac4xians@webrtc.org  _shared->output_mixer()->DoOperationsOnCombinedSignal(feed_data_to_apm);
110191d88e1320d33fdc3648041bd941509e722f3ac4xians@webrtc.org
110291d88e1320d33fdc3648041bd941509e722f3ac4xians@webrtc.org  // Retrieve the final output mix (resampled to match the ADM)
110391d88e1320d33fdc3648041bd941509e722f3ac4xians@webrtc.org  _shared->output_mixer()->GetMixedAudio(sample_rate, number_of_channels,
110491d88e1320d33fdc3648041bd941509e722f3ac4xians@webrtc.org                                         &_audioFrame);
110591d88e1320d33fdc3648041bd941509e722f3ac4xians@webrtc.org
110691d88e1320d33fdc3648041bd941509e722f3ac4xians@webrtc.org  assert(number_of_frames == _audioFrame.samples_per_channel_);
110791d88e1320d33fdc3648041bd941509e722f3ac4xians@webrtc.org  assert(sample_rate == _audioFrame.sample_rate_hz_);
110891d88e1320d33fdc3648041bd941509e722f3ac4xians@webrtc.org
110991d88e1320d33fdc3648041bd941509e722f3ac4xians@webrtc.org  // Deliver audio (PCM) samples to the ADM
111091d88e1320d33fdc3648041bd941509e722f3ac4xians@webrtc.org  memcpy(audio_data, _audioFrame.data_,
111191d88e1320d33fdc3648041bd941509e722f3ac4xians@webrtc.org         sizeof(int16_t) * number_of_frames * number_of_channels);
111222f69bd27abc89979460df6d01de8685cb058aabwu@webrtc.org
111381f8df9af96c6b4bf43234f2a0162146a5da6112wu@webrtc.org  *elapsed_time_ms = _audioFrame.elapsed_time_ms_;
111422f69bd27abc89979460df6d01de8685cb058aabwu@webrtc.org  *ntp_time_ms = _audioFrame.ntp_time_ms_;
111591d88e1320d33fdc3648041bd941509e722f3ac4xians@webrtc.org}
111691d88e1320d33fdc3648041bd941509e722f3ac4xians@webrtc.org
11173b89e10f31160da35b408fd00cb8f89d2b08862dpbos@webrtc.org}  // namespace webrtc
1118