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