voe_base_impl.cc revision 361bac7a4f30a81e58c53ba86c58ffec085306d7
1/*
2 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 *
4 *  Use of this source code is governed by a BSD-style license
5 *  that can be found in the LICENSE file in the root of the source
6 *  tree. An additional intellectual property rights grant can be found
7 *  in the file PATENTS.  All contributing project authors may
8 *  be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "voe_base_impl.h"
12
13#include "audio_coding_module.h"
14#include "audio_processing.h"
15#include "channel.h"
16#include "critical_section_wrapper.h"
17#include "file_wrapper.h"
18#include "modules/audio_device/audio_device_impl.h"
19#include "output_mixer.h"
20#include "signal_processing_library.h"
21#include "trace.h"
22#include "transmit_mixer.h"
23#include "utility.h"
24#include "voe_errors.h"
25#include "voice_engine_impl.h"
26
27#if (defined(_WIN32) && defined(_DLL) && (_MSC_VER == 1400))
28// Fix for VS 2005 MD/MDd link problem
29#include <stdio.h>
30extern "C"
31    { FILE _iob[3] = {   __iob_func()[0], __iob_func()[1], __iob_func()[2]}; }
32#endif
33
34namespace webrtc
35{
36
37VoEBase* VoEBase::GetInterface(VoiceEngine* voiceEngine)
38{
39    if (NULL == voiceEngine)
40    {
41        return NULL;
42    }
43    VoiceEngineImpl* s = static_cast<VoiceEngineImpl*>(voiceEngine);
44    s->AddRef();
45    return s;
46}
47
48VoEBaseImpl::VoEBaseImpl(voe::SharedData* shared) :
49    _voiceEngineObserverPtr(NULL),
50    _callbackCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
51    _voiceEngineObserver(false), _oldVoEMicLevel(0), _oldMicLevel(0),
52    _shared(shared)
53{
54    WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
55                 "VoEBaseImpl() - ctor");
56}
57
58VoEBaseImpl::~VoEBaseImpl()
59{
60    WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
61                 "~VoEBaseImpl() - dtor");
62
63    TerminateInternal();
64
65    delete &_callbackCritSect;
66}
67
68void VoEBaseImpl::OnErrorIsReported(const ErrorCode error)
69{
70    CriticalSectionScoped cs(&_callbackCritSect);
71    if (_voiceEngineObserver)
72    {
73        if (_voiceEngineObserverPtr)
74        {
75            int errCode(0);
76            if (error == AudioDeviceObserver::kRecordingError)
77            {
78                errCode = VE_RUNTIME_REC_ERROR;
79                WEBRTC_TRACE(kTraceInfo, kTraceVoice,
80                    VoEId(_shared->instance_id(), -1),
81                    "VoEBaseImpl::OnErrorIsReported() => VE_RUNTIME_REC_ERROR");
82            }
83            else if (error == AudioDeviceObserver::kPlayoutError)
84            {
85                errCode = VE_RUNTIME_PLAY_ERROR;
86                WEBRTC_TRACE(kTraceInfo, kTraceVoice,
87                    VoEId(_shared->instance_id(), -1),
88                    "VoEBaseImpl::OnErrorIsReported() => "
89                    "VE_RUNTIME_PLAY_ERROR");
90            }
91            // Deliver callback (-1 <=> no channel dependency)
92            _voiceEngineObserverPtr->CallbackOnError(-1, errCode);
93        }
94    }
95}
96
97void VoEBaseImpl::OnWarningIsReported(const WarningCode warning)
98{
99    CriticalSectionScoped cs(&_callbackCritSect);
100    if (_voiceEngineObserver)
101    {
102        if (_voiceEngineObserverPtr)
103        {
104            int warningCode(0);
105            if (warning == AudioDeviceObserver::kRecordingWarning)
106            {
107                warningCode = VE_RUNTIME_REC_WARNING;
108                WEBRTC_TRACE(kTraceInfo, kTraceVoice,
109                    VoEId(_shared->instance_id(), -1),
110                    "VoEBaseImpl::OnErrorIsReported() => "
111                    "VE_RUNTIME_REC_WARNING");
112            }
113            else if (warning == AudioDeviceObserver::kPlayoutWarning)
114            {
115                warningCode = VE_RUNTIME_PLAY_WARNING;
116                WEBRTC_TRACE(kTraceInfo, kTraceVoice,
117                    VoEId(_shared->instance_id(), -1),
118                    "VoEBaseImpl::OnErrorIsReported() => "
119                    "VE_RUNTIME_PLAY_WARNING");
120            }
121            // Deliver callback (-1 <=> no channel dependency)
122            _voiceEngineObserverPtr->CallbackOnError(-1, warningCode);
123        }
124    }
125}
126
127WebRtc_Word32 VoEBaseImpl::RecordedDataIsAvailable(
128        const void* audioSamples,
129        const WebRtc_UWord32 nSamples,
130        const WebRtc_UWord8 nBytesPerSample,
131        const WebRtc_UWord8 nChannels,
132        const WebRtc_UWord32 samplesPerSec,
133        const WebRtc_UWord32 totalDelayMS,
134        const WebRtc_Word32 clockDrift,
135        const WebRtc_UWord32 currentMicLevel,
136        WebRtc_UWord32& newMicLevel)
137{
138    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_shared->instance_id(), -1),
139                 "VoEBaseImpl::RecordedDataIsAvailable(nSamples=%u, "
140                     "nBytesPerSample=%u, nChannels=%u, samplesPerSec=%u, "
141                     "totalDelayMS=%u, clockDrift=%d, currentMicLevel=%u)",
142                 nSamples, nBytesPerSample, nChannels, samplesPerSec,
143                 totalDelayMS, clockDrift, currentMicLevel);
144
145    assert(_shared->transmit_mixer() != NULL);
146    assert(_shared->audio_device() != NULL);
147
148    bool isAnalogAGC(false);
149    WebRtc_UWord32 maxVolume(0);
150    WebRtc_UWord16 currentVoEMicLevel(0);
151    WebRtc_UWord32 newVoEMicLevel(0);
152
153    if (_shared->audio_processing() &&
154        (_shared->audio_processing()->gain_control()->mode()
155                    == GainControl::kAdaptiveAnalog))
156    {
157        isAnalogAGC = true;
158    }
159
160    // Will only deal with the volume in adaptive analog mode
161    if (isAnalogAGC)
162    {
163        // Scale from ADM to VoE level range
164        if (_shared->audio_device()->MaxMicrophoneVolume(&maxVolume) == 0)
165        {
166            if (0 != maxVolume)
167            {
168                currentVoEMicLevel = (WebRtc_UWord16) ((currentMicLevel
169                        * kMaxVolumeLevel + (int) (maxVolume / 2))
170                        / (maxVolume));
171            }
172        }
173        // We learned that on certain systems (e.g Linux) the currentVoEMicLevel
174        // can be greater than the maxVolumeLevel therefore
175        // we are going to cap the currentVoEMicLevel to the maxVolumeLevel
176        // and change the maxVolume to currentMicLevel if it turns out that
177        // the currentVoEMicLevel is indeed greater than the maxVolumeLevel.
178        if (currentVoEMicLevel > kMaxVolumeLevel)
179        {
180            currentVoEMicLevel = kMaxVolumeLevel;
181            maxVolume = currentMicLevel;
182        }
183    }
184
185    // Keep track if the MicLevel has been changed by the AGC, if not,
186    // use the old value AGC returns to let AGC continue its trend,
187    // so eventually the AGC is able to change the mic level. This handles
188    // issues with truncation introduced by the scaling.
189    if (_oldMicLevel == currentMicLevel)
190    {
191        currentVoEMicLevel = (WebRtc_UWord16) _oldVoEMicLevel;
192    }
193
194    // Perform channel-independent operations
195    // (APM, mix with file, record to file, mute, etc.)
196    _shared->transmit_mixer()->PrepareDemux(audioSamples, nSamples, nChannels,
197        samplesPerSec, static_cast<WebRtc_UWord16>(totalDelayMS), clockDrift,
198        currentVoEMicLevel);
199
200    // Copy the audio frame to each sending channel and perform
201    // channel-dependent operations (file mixing, mute, etc.) to prepare
202    // for encoding.
203    _shared->transmit_mixer()->DemuxAndMix();
204    // Do the encoding and packetize+transmit the RTP packet when encoding
205    // is done.
206    _shared->transmit_mixer()->EncodeAndSend();
207
208    // Will only deal with the volume in adaptive analog mode
209    if (isAnalogAGC)
210    {
211        // Scale from VoE to ADM level range
212        newVoEMicLevel = _shared->transmit_mixer()->CaptureLevel();
213        if (newVoEMicLevel != currentVoEMicLevel)
214        {
215            // Add (kMaxVolumeLevel/2) to round the value
216            newMicLevel = (WebRtc_UWord32) ((newVoEMicLevel * maxVolume
217                    + (int) (kMaxVolumeLevel / 2)) / (kMaxVolumeLevel));
218        }
219        else
220        {
221            // Pass zero if the level is unchanged
222            newMicLevel = 0;
223        }
224
225        // Keep track of the value AGC returns
226        _oldVoEMicLevel = newVoEMicLevel;
227        _oldMicLevel = currentMicLevel;
228    }
229
230    return 0;
231}
232
233WebRtc_Word32 VoEBaseImpl::NeedMorePlayData(
234        const WebRtc_UWord32 nSamples,
235        const WebRtc_UWord8 nBytesPerSample,
236        const WebRtc_UWord8 nChannels,
237        const WebRtc_UWord32 samplesPerSec,
238        void* audioSamples,
239        WebRtc_UWord32& nSamplesOut)
240{
241    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_shared->instance_id(), -1),
242                 "VoEBaseImpl::NeedMorePlayData(nSamples=%u, "
243                     "nBytesPerSample=%d, nChannels=%d, samplesPerSec=%u)",
244                 nSamples, nBytesPerSample, nChannels, samplesPerSec);
245
246    assert(_shared->output_mixer() != NULL);
247
248    // TODO(andrew): if the device is running in mono, we should tell the mixer
249    // here so that it will only request mono from AudioCodingModule.
250    // Perform mixing of all active participants (channel-based mixing)
251    _shared->output_mixer()->MixActiveChannels();
252
253    // Additional operations on the combined signal
254    _shared->output_mixer()->DoOperationsOnCombinedSignal();
255
256    // Retrieve the final output mix (resampled to match the ADM)
257    _shared->output_mixer()->GetMixedAudio(samplesPerSec, nChannels,
258        &_audioFrame);
259
260    assert(static_cast<int>(nSamples) == _audioFrame.samples_per_channel_);
261    assert(samplesPerSec ==
262        static_cast<WebRtc_UWord32>(_audioFrame.sample_rate_hz_));
263
264    // Deliver audio (PCM) samples to the ADM
265    memcpy(
266           (WebRtc_Word16*) audioSamples,
267           (const WebRtc_Word16*) _audioFrame.data_,
268           sizeof(WebRtc_Word16) * (_audioFrame.samples_per_channel_
269                   * _audioFrame.num_channels_));
270
271    nSamplesOut = _audioFrame.samples_per_channel_;
272
273    return 0;
274}
275
276int VoEBaseImpl::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
277{
278    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
279                 "RegisterVoiceEngineObserver(observer=0x%d)", &observer);
280    CriticalSectionScoped cs(&_callbackCritSect);
281    if (_voiceEngineObserverPtr)
282    {
283        _shared->SetLastError(VE_INVALID_OPERATION, kTraceError,
284            "RegisterVoiceEngineObserver() observer already enabled");
285        return -1;
286    }
287
288    // Register the observer in all active channels
289    voe::ScopedChannel sc(_shared->channel_manager());
290    void* iterator(NULL);
291    voe::Channel* channelPtr = sc.GetFirstChannel(iterator);
292    while (channelPtr != NULL)
293    {
294        channelPtr->RegisterVoiceEngineObserver(observer);
295        channelPtr = sc.GetNextChannel(iterator);
296    }
297    _shared->transmit_mixer()->RegisterVoiceEngineObserver(observer);
298
299    _voiceEngineObserverPtr = &observer;
300    _voiceEngineObserver = true;
301
302    return 0;
303}
304
305int VoEBaseImpl::DeRegisterVoiceEngineObserver()
306{
307    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
308                 "DeRegisterVoiceEngineObserver()");
309    CriticalSectionScoped cs(&_callbackCritSect);
310    if (!_voiceEngineObserverPtr)
311    {
312        _shared->SetLastError(VE_INVALID_OPERATION, kTraceError,
313            "DeRegisterVoiceEngineObserver() observer already disabled");
314        return 0;
315    }
316
317    _voiceEngineObserver = false;
318    _voiceEngineObserverPtr = NULL;
319
320    // Deregister the observer in all active channels
321    voe::ScopedChannel sc(_shared->channel_manager());
322    void* iterator(NULL);
323    voe::Channel* channelPtr = sc.GetFirstChannel(iterator);
324    while (channelPtr != NULL)
325    {
326        channelPtr->DeRegisterVoiceEngineObserver();
327        channelPtr = sc.GetNextChannel(iterator);
328    }
329
330    return 0;
331}
332
333int VoEBaseImpl::Init(AudioDeviceModule* external_adm,
334                      AudioProcessing* audioproc)
335{
336    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
337        "Init(external_adm=0x%p)", external_adm);
338    CriticalSectionScoped cs(_shared->crit_sec());
339
340    WebRtcSpl_Init();
341
342    if (_shared->statistics().Initialized())
343    {
344        return 0;
345    }
346
347    if (_shared->process_thread())
348    {
349        if (_shared->process_thread()->Start() != 0)
350        {
351            _shared->SetLastError(VE_THREAD_ERROR, kTraceError,
352                "Init() failed to start module process thread");
353            return -1;
354        }
355    }
356
357    // Create an internal ADM if the user has not added an external
358    // ADM implementation as input to Init().
359    if (external_adm == NULL)
360    {
361        // Create the internal ADM implementation.
362        _shared->set_audio_device(AudioDeviceModuleImpl::Create(
363            VoEId(_shared->instance_id(), -1), _shared->audio_device_layer()));
364
365        if (_shared->audio_device() == NULL)
366        {
367            _shared->SetLastError(VE_NO_MEMORY, kTraceCritical,
368                "Init() failed to create the ADM");
369            return -1;
370        }
371    }
372    else
373    {
374        // Use the already existing external ADM implementation.
375        _shared->set_audio_device(external_adm);
376        WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
377            "An external ADM implementation will be used in VoiceEngine");
378    }
379
380    // Register the ADM to the process thread, which will drive the error
381    // callback mechanism
382    if (_shared->process_thread() &&
383        _shared->process_thread()->RegisterModule(_shared->audio_device()) != 0)
384    {
385        _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
386            "Init() failed to register the ADM");
387        return -1;
388    }
389
390    bool available(false);
391
392    // --------------------
393    // Reinitialize the ADM
394
395    // Register the AudioObserver implementation
396    if (_shared->audio_device()->RegisterEventObserver(this) != 0) {
397      _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
398          "Init() failed to register event observer for the ADM");
399    }
400
401    // Register the AudioTransport implementation
402    if (_shared->audio_device()->RegisterAudioCallback(this) != 0) {
403      _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
404          "Init() failed to register audio callback for the ADM");
405    }
406
407    // ADM initialization
408    if (_shared->audio_device()->Init() != 0)
409    {
410        _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
411            "Init() failed to initialize the ADM");
412        return -1;
413    }
414
415    // Initialize the default speaker
416    if (_shared->audio_device()->SetPlayoutDevice(
417            WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0)
418    {
419        _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceInfo,
420            "Init() failed to set the default output device");
421    }
422    if (_shared->audio_device()->SpeakerIsAvailable(&available) != 0)
423    {
424        _shared->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceInfo,
425            "Init() failed to check speaker availability, trying to "
426            "initialize speaker anyway");
427    }
428    else if (!available)
429    {
430        _shared->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceInfo,
431            "Init() speaker not available, trying to initialize speaker "
432            "anyway");
433    }
434    if (_shared->audio_device()->InitSpeaker() != 0)
435    {
436        _shared->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceInfo,
437            "Init() failed to initialize the speaker");
438    }
439
440    // Initialize the default microphone
441    if (_shared->audio_device()->SetRecordingDevice(
442            WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0)
443    {
444        _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceInfo,
445            "Init() failed to set the default input device");
446    }
447    if (_shared->audio_device()->MicrophoneIsAvailable(&available) != 0)
448    {
449        _shared->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceInfo,
450            "Init() failed to check microphone availability, trying to "
451            "initialize microphone anyway");
452    }
453    else if (!available)
454    {
455        _shared->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceInfo,
456            "Init() microphone not available, trying to initialize "
457            "microphone anyway");
458    }
459    if (_shared->audio_device()->InitMicrophone() != 0)
460    {
461        _shared->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceInfo,
462            "Init() failed to initialize the microphone");
463    }
464
465    // Set number of channels
466    if (_shared->audio_device()->StereoPlayoutIsAvailable(&available) != 0) {
467      _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
468          "Init() failed to query stereo playout mode");
469    }
470    if (_shared->audio_device()->SetStereoPlayout(available) != 0)
471    {
472        _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
473            "Init() failed to set mono/stereo playout mode");
474    }
475
476    // TODO(andrew): These functions don't tell us whether stereo recording
477    // is truly available. We simply set the AudioProcessing input to stereo
478    // here, because we have to wait until receiving the first frame to
479    // determine the actual number of channels anyway.
480    //
481    // These functions may be changed; tracked here:
482    // http://code.google.com/p/webrtc/issues/detail?id=204
483    _shared->audio_device()->StereoRecordingIsAvailable(&available);
484    if (_shared->audio_device()->SetStereoRecording(available) != 0)
485    {
486        _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
487            "Init() failed to set mono/stereo recording mode");
488    }
489
490    if (!audioproc) {
491      audioproc = AudioProcessing::Create(VoEId(_shared->instance_id(), -1));
492      if (!audioproc) {
493        LOG(LS_ERROR) << "Failed to create AudioProcessing.";
494        _shared->SetLastError(VE_NO_MEMORY);
495        return -1;
496      }
497    }
498    _shared->set_audio_processing(audioproc);
499
500    // Set the error state for any failures in this block.
501    _shared->SetLastError(VE_APM_ERROR);
502    if (audioproc->echo_cancellation()->set_device_sample_rate_hz(48000)) {
503      LOG_FERR1(LS_ERROR, set_device_sample_rate_hz, 48000);
504      return -1;
505    }
506    // Assume 16 kHz mono until the audio frames are received from the capture
507    // device, at which point this can be updated.
508    if (audioproc->set_sample_rate_hz(16000)) {
509      LOG_FERR1(LS_ERROR, set_sample_rate_hz, 16000);
510      return -1;
511    }
512    if (audioproc->set_num_channels(1, 1) != 0) {
513      LOG_FERR2(LS_ERROR, set_num_channels, 1, 1);
514      return -1;
515    }
516    if (audioproc->set_num_reverse_channels(1) != 0) {
517      LOG_FERR1(LS_ERROR, set_num_reverse_channels, 1);
518      return -1;
519    }
520
521    // Configure AudioProcessing components. All are disabled by default.
522    if (audioproc->high_pass_filter()->Enable(true) != 0) {
523      LOG_FERR1(LS_ERROR, high_pass_filter()->Enable, true);
524      return -1;
525    }
526    if (audioproc->echo_cancellation()->enable_drift_compensation(false) != 0) {
527      LOG_FERR1(LS_ERROR, enable_drift_compensation, false);
528      return -1;
529    }
530    if (audioproc->noise_suppression()->set_level(kDefaultNsMode) != 0) {
531      LOG_FERR1(LS_ERROR, noise_suppression()->set_level, kDefaultNsMode);
532      return -1;
533    }
534    GainControl* agc = audioproc->gain_control();
535    if (agc->set_analog_level_limits(kMinVolumeLevel, kMaxVolumeLevel) != 0) {
536      LOG_FERR2(LS_ERROR, agc->set_analog_level_limits, kMinVolumeLevel,
537                kMaxVolumeLevel);
538      return -1;
539    }
540    if (agc->set_mode(kDefaultAgcMode) != 0) {
541      LOG_FERR1(LS_ERROR, agc->set_mode, kDefaultAgcMode);
542      return -1;
543    }
544    if (agc->Enable(kDefaultAgcState) != 0) {
545      LOG_FERR1(LS_ERROR, agc->Enable, kDefaultAgcState);
546      return -1;
547    }
548    _shared->SetLastError(0);  // Clear error state.
549
550#ifdef WEBRTC_VOICE_ENGINE_AGC
551    bool agc_enabled = agc->mode() == GainControl::kAdaptiveAnalog &&
552                       agc->is_enabled();
553    if (_shared->audio_device()->SetAGC(agc_enabled) != 0) {
554      LOG_FERR1(LS_ERROR, audio_device()->SetAGC, agc_enabled);
555      _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR);
556      // TODO(ajm): No error return here due to
557      // https://code.google.com/p/webrtc/issues/detail?id=1464
558    }
559#endif
560
561    return _shared->statistics().SetInitialized();
562}
563
564int VoEBaseImpl::Terminate()
565{
566    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
567                 "Terminate()");
568    CriticalSectionScoped cs(_shared->crit_sec());
569    return TerminateInternal();
570}
571
572int VoEBaseImpl::MaxNumOfChannels()
573{
574    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
575                 "MaxNumOfChannels()");
576    WebRtc_Word32 maxNumOfChannels =
577        _shared->channel_manager().MaxNumOfChannels();
578    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
579        VoEId(_shared->instance_id(), -1),
580        "MaxNumOfChannels() => %d", maxNumOfChannels);
581    return (maxNumOfChannels);
582}
583
584int VoEBaseImpl::CreateChannel()
585{
586    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
587                 "CreateChannel()");
588    CriticalSectionScoped cs(_shared->crit_sec());
589
590    if (!_shared->statistics().Initialized())
591    {
592        _shared->SetLastError(VE_NOT_INITED, kTraceError);
593        return -1;
594    }
595
596    WebRtc_Word32 channelId = -1;
597
598    if (!_shared->channel_manager().CreateChannel(channelId))
599    {
600        _shared->SetLastError(VE_CHANNEL_NOT_CREATED, kTraceError,
601            "CreateChannel() failed to allocate memory for channel");
602        return -1;
603    }
604
605    bool destroyChannel(false);
606    {
607        voe::ScopedChannel sc(_shared->channel_manager(), channelId);
608        voe::Channel* channelPtr = sc.ChannelPtr();
609        if (channelPtr == NULL)
610        {
611            _shared->SetLastError(VE_CHANNEL_NOT_CREATED, kTraceError,
612                "CreateChannel() failed to allocate memory for channel");
613            return -1;
614        }
615        else if (channelPtr->SetEngineInformation(_shared->statistics(),
616                                                  *_shared->output_mixer(),
617                                                  *_shared->transmit_mixer(),
618                                                  *_shared->process_thread(),
619                                                  *_shared->audio_device(),
620                                                  _voiceEngineObserverPtr,
621                                                  &_callbackCritSect) != 0)
622        {
623            destroyChannel = true;
624            _shared->SetLastError(VE_CHANNEL_NOT_CREATED, kTraceError,
625                "CreateChannel() failed to associate engine and channel."
626                " Destroying channel.");
627        }
628        else if (channelPtr->Init() != 0)
629        {
630            destroyChannel = true;
631            _shared->SetLastError(VE_CHANNEL_NOT_CREATED, kTraceError,
632                "CreateChannel() failed to initialize channel. Destroying"
633                " channel.");
634        }
635    }
636    if (destroyChannel)
637    {
638        _shared->channel_manager().DestroyChannel(channelId);
639        return -1;
640    }
641    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
642        VoEId(_shared->instance_id(), -1),
643        "CreateChannel() => %d", channelId);
644    return channelId;
645}
646
647int VoEBaseImpl::DeleteChannel(int channel)
648{
649    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
650                 "DeleteChannel(channel=%d)", channel);
651    CriticalSectionScoped cs(_shared->crit_sec());
652
653    if (!_shared->statistics().Initialized())
654    {
655        _shared->SetLastError(VE_NOT_INITED, kTraceError);
656        return -1;
657    }
658
659    {
660        voe::ScopedChannel sc(_shared->channel_manager(), channel);
661        voe::Channel* channelPtr = sc.ChannelPtr();
662        if (channelPtr == NULL)
663        {
664            _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
665                "DeleteChannel() failed to locate channel");
666            return -1;
667        }
668    }
669
670    if (_shared->channel_manager().DestroyChannel(channel) != 0)
671    {
672        _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
673            "DeleteChannel() failed to destroy channel");
674        return -1;
675    }
676
677    if (StopSend() != 0)
678    {
679        return -1;
680    }
681
682    if (StopPlayout() != 0)
683    {
684        return -1;
685    }
686    return 0;
687}
688
689int VoEBaseImpl::StartReceive(int channel)
690{
691    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
692                 "StartReceive(channel=%d)", channel);
693    CriticalSectionScoped cs(_shared->crit_sec());
694    if (!_shared->statistics().Initialized())
695    {
696        _shared->SetLastError(VE_NOT_INITED, kTraceError);
697        return -1;
698    }
699    voe::ScopedChannel sc(_shared->channel_manager(), channel);
700    voe::Channel* channelPtr = sc.ChannelPtr();
701    if (channelPtr == NULL)
702    {
703        _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
704            "StartReceive() failed to locate channel");
705        return -1;
706    }
707    return channelPtr->StartReceiving();
708}
709
710int VoEBaseImpl::StopReceive(int channel)
711{
712    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
713                 "StopListen(channel=%d)", channel);
714    CriticalSectionScoped cs(_shared->crit_sec());
715    if (!_shared->statistics().Initialized())
716    {
717        _shared->SetLastError(VE_NOT_INITED, kTraceError);
718        return -1;
719    }
720    voe::ScopedChannel sc(_shared->channel_manager(), channel);
721    voe::Channel* channelPtr = sc.ChannelPtr();
722    if (channelPtr == NULL)
723    {
724        _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
725            "SetLocalReceiver() failed to locate channel");
726        return -1;
727    }
728    return channelPtr->StopReceiving();
729}
730
731int VoEBaseImpl::StartPlayout(int channel)
732{
733    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
734                 "StartPlayout(channel=%d)", channel);
735    CriticalSectionScoped cs(_shared->crit_sec());
736    if (!_shared->statistics().Initialized())
737    {
738        _shared->SetLastError(VE_NOT_INITED, kTraceError);
739        return -1;
740    }
741    voe::ScopedChannel sc(_shared->channel_manager(), channel);
742    voe::Channel* channelPtr = sc.ChannelPtr();
743    if (channelPtr == NULL)
744    {
745        _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
746            "StartPlayout() failed to locate channel");
747        return -1;
748    }
749    if (channelPtr->Playing())
750    {
751        return 0;
752    }
753    if (StartPlayout() != 0)
754    {
755        _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
756            "StartPlayout() failed to start playout");
757        return -1;
758    }
759    return channelPtr->StartPlayout();
760}
761
762int VoEBaseImpl::StopPlayout(int channel)
763{
764    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
765                 "StopPlayout(channel=%d)", channel);
766    CriticalSectionScoped cs(_shared->crit_sec());
767    if (!_shared->statistics().Initialized())
768    {
769        _shared->SetLastError(VE_NOT_INITED, kTraceError);
770        return -1;
771    }
772    voe::ScopedChannel sc(_shared->channel_manager(), channel);
773    voe::Channel* channelPtr = sc.ChannelPtr();
774    if (channelPtr == NULL)
775    {
776        _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
777            "StopPlayout() failed to locate channel");
778        return -1;
779    }
780    if (channelPtr->StopPlayout() != 0)
781    {
782        WEBRTC_TRACE(kTraceWarning, kTraceVoice,
783            VoEId(_shared->instance_id(), -1),
784            "StopPlayout() failed to stop playout for channel %d", channel);
785    }
786    return StopPlayout();
787}
788
789int VoEBaseImpl::StartSend(int channel)
790{
791    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
792                 "StartSend(channel=%d)", channel);
793    CriticalSectionScoped cs(_shared->crit_sec());
794    if (!_shared->statistics().Initialized())
795    {
796        _shared->SetLastError(VE_NOT_INITED, kTraceError);
797        return -1;
798    }
799    voe::ScopedChannel sc(_shared->channel_manager(), channel);
800    voe::Channel* channelPtr = sc.ChannelPtr();
801    if (channelPtr == NULL)
802    {
803        _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
804            "StartSend() failed to locate channel");
805        return -1;
806    }
807    if (channelPtr->Sending())
808    {
809        return 0;
810    }
811    if (StartSend() != 0)
812    {
813        _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
814            "StartSend() failed to start recording");
815        return -1;
816    }
817    return channelPtr->StartSend();
818}
819
820int VoEBaseImpl::StopSend(int channel)
821{
822    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
823                 "StopSend(channel=%d)", channel);
824    CriticalSectionScoped cs(_shared->crit_sec());
825    if (!_shared->statistics().Initialized())
826    {
827        _shared->SetLastError(VE_NOT_INITED, kTraceError);
828        return -1;
829    }
830    voe::ScopedChannel sc(_shared->channel_manager(), channel);
831    voe::Channel* channelPtr = sc.ChannelPtr();
832    if (channelPtr == NULL)
833    {
834        _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
835            "StopSend() failed to locate channel");
836        return -1;
837    }
838    if (channelPtr->StopSend() != 0)
839    {
840        WEBRTC_TRACE(kTraceWarning, kTraceVoice,
841            VoEId(_shared->instance_id(), -1),
842            "StopSend() failed to stop sending for channel %d", channel);
843    }
844    return StopSend();
845}
846
847int VoEBaseImpl::GetVersion(char version[1024])
848{
849    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
850                 "GetVersion(version=?)");
851    assert(kVoiceEngineVersionMaxMessageSize == 1024);
852
853    if (version == NULL)
854    {
855        _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError);
856        return (-1);
857    }
858
859    char versionBuf[kVoiceEngineVersionMaxMessageSize];
860    char* versionPtr = versionBuf;
861
862    WebRtc_Word32 len = 0;
863    WebRtc_Word32 accLen = 0;
864
865    len = AddVoEVersion(versionPtr);
866    if (len == -1)
867    {
868        return -1;
869    }
870    versionPtr += len;
871    accLen += len;
872    assert(accLen < kVoiceEngineVersionMaxMessageSize);
873
874    len = AddBuildInfo(versionPtr);
875    if (len == -1)
876    {
877        return -1;
878    }
879    versionPtr += len;
880    accLen += len;
881    assert(accLen < kVoiceEngineVersionMaxMessageSize);
882
883#ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT
884    len = AddExternalRecAndPlayoutBuild(versionPtr);
885    if (len == -1)
886    {
887        return -1;
888    }
889    versionPtr += len;
890    accLen += len;
891    assert(accLen < kVoiceEngineVersionMaxMessageSize);
892 #endif
893
894    memcpy(version, versionBuf, accLen);
895    version[accLen] = '\0';
896
897    // to avoid the truncation in the trace, split the string into parts
898    char partOfVersion[256];
899    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
900        VoEId(_shared->instance_id(), -1), "GetVersion() =>");
901    for (int partStart = 0; partStart < accLen;)
902    {
903        memset(partOfVersion, 0, sizeof(partOfVersion));
904        int partEnd = partStart + 180;
905        while (version[partEnd] != '\n' && version[partEnd] != '\0')
906        {
907            partEnd--;
908        }
909        if (partEnd < accLen)
910        {
911            memcpy(partOfVersion, &version[partStart], partEnd - partStart);
912        }
913        else
914        {
915            memcpy(partOfVersion, &version[partStart], accLen - partStart);
916        }
917        partStart = partEnd;
918        WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
919            VoEId(_shared->instance_id(), -1), "%s", partOfVersion);
920    }
921
922    return 0;
923}
924
925WebRtc_Word32 VoEBaseImpl::AddBuildInfo(char* str) const
926{
927    return sprintf(str, "Build: svn:%s %s\n", WEBRTC_SVNREVISION, BUILDINFO);
928}
929
930WebRtc_Word32 VoEBaseImpl::AddVoEVersion(char* str) const
931{
932    return sprintf(str, "VoiceEngine 4.1.0\n");
933}
934
935#ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT
936WebRtc_Word32 VoEBaseImpl::AddExternalRecAndPlayoutBuild(char* str) const
937{
938    return sprintf(str, "External recording and playout build\n");
939}
940#endif
941
942int VoEBaseImpl::LastError()
943{
944    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
945                 "LastError()");
946    return (_shared->statistics().LastError());
947}
948
949
950int VoEBaseImpl::SetNetEQPlayoutMode(int channel, NetEqModes mode)
951{
952    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
953                 "SetNetEQPlayoutMode(channel=%i, mode=%i)", channel, mode);
954    if (!_shared->statistics().Initialized())
955    {
956        _shared->SetLastError(VE_NOT_INITED, kTraceError);
957        return -1;
958    }
959    voe::ScopedChannel sc(_shared->channel_manager(), channel);
960    voe::Channel* channelPtr = sc.ChannelPtr();
961    if (channelPtr == NULL)
962    {
963        _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
964            "SetNetEQPlayoutMode() failed to locate channel");
965        return -1;
966    }
967    return channelPtr->SetNetEQPlayoutMode(mode);
968}
969
970int VoEBaseImpl::GetNetEQPlayoutMode(int channel, NetEqModes& mode)
971{
972    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
973                 "GetNetEQPlayoutMode(channel=%i, mode=?)", channel);
974    if (!_shared->statistics().Initialized())
975    {
976        _shared->SetLastError(VE_NOT_INITED, kTraceError);
977        return -1;
978    }
979    voe::ScopedChannel sc(_shared->channel_manager(), channel);
980    voe::Channel* channelPtr = sc.ChannelPtr();
981    if (channelPtr == NULL)
982    {
983        _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
984            "GetNetEQPlayoutMode() failed to locate channel");
985        return -1;
986    }
987    return channelPtr->GetNetEQPlayoutMode(mode);
988}
989
990int VoEBaseImpl::SetOnHoldStatus(int channel, bool enable, OnHoldModes mode)
991{
992    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
993                 "SetOnHoldStatus(channel=%d, enable=%d, mode=%d)", channel,
994                 enable, mode);
995    if (!_shared->statistics().Initialized())
996    {
997        _shared->SetLastError(VE_NOT_INITED, kTraceError);
998        return -1;
999    }
1000    voe::ScopedChannel sc(_shared->channel_manager(), channel);
1001    voe::Channel* channelPtr = sc.ChannelPtr();
1002    if (channelPtr == NULL)
1003    {
1004        _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
1005            "SetOnHoldStatus() failed to locate channel");
1006        return -1;
1007    }
1008    return channelPtr->SetOnHoldStatus(enable, mode);
1009}
1010
1011int VoEBaseImpl::GetOnHoldStatus(int channel, bool& enabled, OnHoldModes& mode)
1012{
1013    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
1014                 "GetOnHoldStatus(channel=%d, enabled=?, mode=?)", channel);
1015    if (!_shared->statistics().Initialized())
1016    {
1017        _shared->SetLastError(VE_NOT_INITED, kTraceError);
1018        return -1;
1019    }
1020    voe::ScopedChannel sc(_shared->channel_manager(), channel);
1021    voe::Channel* channelPtr = sc.ChannelPtr();
1022    if (channelPtr == NULL)
1023    {
1024        _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
1025            "GetOnHoldStatus() failed to locate channel");
1026        return -1;
1027    }
1028    return channelPtr->GetOnHoldStatus(enabled, mode);
1029}
1030
1031WebRtc_Word32 VoEBaseImpl::StartPlayout()
1032{
1033    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
1034                 "VoEBaseImpl::StartPlayout()");
1035    if (_shared->audio_device()->Playing())
1036    {
1037        return 0;
1038    }
1039    if (!_shared->ext_playout())
1040    {
1041        if (_shared->audio_device()->InitPlayout() != 0)
1042        {
1043            WEBRTC_TRACE(kTraceError, kTraceVoice,
1044                VoEId(_shared->instance_id(), -1),
1045                "StartPlayout() failed to initialize playout");
1046            return -1;
1047        }
1048        if (_shared->audio_device()->StartPlayout() != 0)
1049        {
1050            WEBRTC_TRACE(kTraceError, kTraceVoice,
1051                VoEId(_shared->instance_id(), -1),
1052                "StartPlayout() failed to start playout");
1053            return -1;
1054        }
1055    }
1056    return 0;
1057}
1058
1059WebRtc_Word32 VoEBaseImpl::StopPlayout()
1060{
1061    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
1062                 "VoEBaseImpl::StopPlayout()");
1063
1064    WebRtc_Word32 numOfChannels = _shared->channel_manager().NumOfChannels();
1065    if (numOfChannels <= 0)
1066    {
1067        return 0;
1068    }
1069
1070    WebRtc_UWord16 nChannelsPlaying(0);
1071    WebRtc_Word32* channelsArray = new WebRtc_Word32[numOfChannels];
1072
1073    // Get number of playing channels
1074    _shared->channel_manager().GetChannelIds(channelsArray, numOfChannels);
1075    for (int i = 0; i < numOfChannels; i++)
1076    {
1077        voe::ScopedChannel sc(_shared->channel_manager(), channelsArray[i]);
1078        voe::Channel* chPtr = sc.ChannelPtr();
1079        if (chPtr)
1080        {
1081            if (chPtr->Playing())
1082            {
1083                nChannelsPlaying++;
1084            }
1085        }
1086    }
1087    delete[] channelsArray;
1088
1089    // Stop audio-device playing if no channel is playing out
1090    if (nChannelsPlaying == 0)
1091    {
1092        if (_shared->audio_device()->StopPlayout() != 0)
1093        {
1094            _shared->SetLastError(VE_CANNOT_STOP_PLAYOUT, kTraceError,
1095                "StopPlayout() failed to stop playout");
1096            return -1;
1097        }
1098    }
1099    return 0;
1100}
1101
1102WebRtc_Word32 VoEBaseImpl::StartSend()
1103{
1104    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
1105                 "VoEBaseImpl::StartSend()");
1106    if (_shared->audio_device()->Recording())
1107    {
1108        return 0;
1109    }
1110    if (!_shared->ext_recording())
1111    {
1112        if (_shared->audio_device()->InitRecording() != 0)
1113        {
1114            WEBRTC_TRACE(kTraceError, kTraceVoice,
1115                VoEId(_shared->instance_id(), -1),
1116                "StartSend() failed to initialize recording");
1117            return -1;
1118        }
1119        if (_shared->audio_device()->StartRecording() != 0)
1120        {
1121            WEBRTC_TRACE(kTraceError, kTraceVoice,
1122                VoEId(_shared->instance_id(), -1),
1123                "StartSend() failed to start recording");
1124            return -1;
1125        }
1126    }
1127
1128    return 0;
1129}
1130
1131WebRtc_Word32 VoEBaseImpl::StopSend()
1132{
1133    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
1134                 "VoEBaseImpl::StopSend()");
1135
1136    if (_shared->NumOfSendingChannels() == 0 &&
1137        !_shared->transmit_mixer()->IsRecordingMic())
1138    {
1139        // Stop audio-device recording if no channel is recording
1140        if (_shared->audio_device()->StopRecording() != 0)
1141        {
1142            _shared->SetLastError(VE_CANNOT_STOP_RECORDING, kTraceError,
1143                "StopSend() failed to stop recording");
1144            return -1;
1145        }
1146        _shared->transmit_mixer()->StopSend();
1147    }
1148
1149    return 0;
1150}
1151
1152WebRtc_Word32 VoEBaseImpl::TerminateInternal()
1153{
1154    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
1155                 "VoEBaseImpl::TerminateInternal()");
1156
1157    // Delete any remaining channel objects
1158    WebRtc_Word32 numOfChannels = _shared->channel_manager().NumOfChannels();
1159    if (numOfChannels > 0)
1160    {
1161        WebRtc_Word32* channelsArray = new WebRtc_Word32[numOfChannels];
1162        _shared->channel_manager().GetChannelIds(channelsArray, numOfChannels);
1163        for (int i = 0; i < numOfChannels; i++)
1164        {
1165            DeleteChannel(channelsArray[i]);
1166        }
1167        delete[] channelsArray;
1168    }
1169
1170    if (_shared->process_thread())
1171    {
1172        if (_shared->audio_device())
1173        {
1174            if (_shared->process_thread()->
1175                    DeRegisterModule(_shared->audio_device()) != 0)
1176            {
1177                _shared->SetLastError(VE_THREAD_ERROR, kTraceError,
1178                    "TerminateInternal() failed to deregister ADM");
1179            }
1180        }
1181        if (_shared->process_thread()->Stop() != 0)
1182        {
1183            _shared->SetLastError(VE_THREAD_ERROR, kTraceError,
1184                "TerminateInternal() failed to stop module process thread");
1185        }
1186    }
1187
1188    if (_shared->audio_device())
1189    {
1190        if (_shared->audio_device()->StopPlayout() != 0)
1191        {
1192            _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
1193                "TerminateInternal() failed to stop playout");
1194        }
1195        if (_shared->audio_device()->StopRecording() != 0)
1196        {
1197            _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
1198                "TerminateInternal() failed to stop recording");
1199        }
1200        if (_shared->audio_device()->RegisterEventObserver(NULL) != 0) {
1201          _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
1202              "TerminateInternal() failed to de-register event observer "
1203              "for the ADM");
1204        }
1205        if (_shared->audio_device()->RegisterAudioCallback(NULL) != 0) {
1206          _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
1207              "TerminateInternal() failed to de-register audio callback "
1208              "for the ADM");
1209        }
1210        if (_shared->audio_device()->Terminate() != 0)
1211        {
1212            _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
1213                "TerminateInternal() failed to terminate the ADM");
1214        }
1215        _shared->set_audio_device(NULL);
1216    }
1217
1218    if (_shared->audio_processing()) {
1219        _shared->set_audio_processing(NULL);
1220    }
1221
1222    return _shared->statistics().SetUnInitialized();
1223}
1224
1225} // namespace webrtc
1226