blob: aeec9bcc9f2dbb53109fe5204c9ddcb22a2ce72a [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
xians@webrtc.org79af7342012-01-31 12:22:14 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
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
henrika@google.com73d65512011-09-07 15:11:18 +000013#include "audio_coding_module.h"
henrika@google.com73d65512011-09-07 15:11:18 +000014#include "audio_processing.h"
15#include "channel.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000016#include "critical_section_wrapper.h"
17#include "file_wrapper.h"
andrew@webrtc.org236d5d32012-09-21 20:46:40 +000018#include "modules/audio_device/audio_device_impl.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000019#include "output_mixer.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000020#include "signal_processing_library.h"
henrika@google.com73d65512011-09-07 15:11:18 +000021#include "trace.h"
22#include "transmit_mixer.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000023#include "utility.h"
henrika@google.com73d65512011-09-07 15:11:18 +000024#include "voe_errors.h"
25#include "voice_engine_impl.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000026
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 }
tommi@webrtc.org0989fb72013-02-15 15:07:32 +000043 VoiceEngineImpl* s = static_cast<VoiceEngineImpl*>(voiceEngine);
tommi@webrtc.orga990e122012-04-26 15:28:22 +000044 s->AddRef();
45 return s;
niklase@google.com470e71d2011-07-07 08:21:25 +000046}
47
tommi@webrtc.org851becd2012-04-04 14:57:19 +000048VoEBaseImpl::VoEBaseImpl(voe::SharedData* shared) :
niklase@google.com470e71d2011-07-07 08:21:25 +000049 _voiceEngineObserverPtr(NULL),
50 _callbackCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
tommi@webrtc.org851becd2012-04-04 14:57:19 +000051 _voiceEngineObserver(false), _oldVoEMicLevel(0), _oldMicLevel(0),
52 _shared(shared)
niklase@google.com470e71d2011-07-07 08:21:25 +000053{
tommi@webrtc.org851becd2012-04-04 14:57:19 +000054 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +000055 "VoEBaseImpl() - ctor");
56}
57
58VoEBaseImpl::~VoEBaseImpl()
59{
tommi@webrtc.org851becd2012-04-04 14:57:19 +000060 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +000061 "~VoEBaseImpl() - dtor");
62
63 TerminateInternal();
64
65 delete &_callbackCritSect;
66}
67
niklase@google.com470e71d2011-07-07 08:21:25 +000068void VoEBaseImpl::OnErrorIsReported(const ErrorCode error)
69{
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +000070 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +000071 if (_voiceEngineObserver)
72 {
73 if (_voiceEngineObserverPtr)
74 {
75 int errCode(0);
76 if (error == AudioDeviceObserver::kRecordingError)
77 {
78 errCode = VE_RUNTIME_REC_ERROR;
tommi@webrtc.org851becd2012-04-04 14:57:19 +000079 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
80 VoEId(_shared->instance_id(), -1),
81 "VoEBaseImpl::OnErrorIsReported() => VE_RUNTIME_REC_ERROR");
niklase@google.com470e71d2011-07-07 08:21:25 +000082 }
83 else if (error == AudioDeviceObserver::kPlayoutError)
84 {
85 errCode = VE_RUNTIME_PLAY_ERROR;
tommi@webrtc.org851becd2012-04-04 14:57:19 +000086 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
87 VoEId(_shared->instance_id(), -1),
88 "VoEBaseImpl::OnErrorIsReported() => "
89 "VE_RUNTIME_PLAY_ERROR");
niklase@google.com470e71d2011-07-07 08:21:25 +000090 }
91 // Deliver callback (-1 <=> no channel dependency)
92 _voiceEngineObserverPtr->CallbackOnError(-1, errCode);
93 }
94 }
95}
96
97void VoEBaseImpl::OnWarningIsReported(const WarningCode warning)
98{
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +000099 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000100 if (_voiceEngineObserver)
101 {
102 if (_voiceEngineObserverPtr)
103 {
104 int warningCode(0);
105 if (warning == AudioDeviceObserver::kRecordingWarning)
106 {
107 warningCode = VE_RUNTIME_REC_WARNING;
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000108 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
109 VoEId(_shared->instance_id(), -1),
110 "VoEBaseImpl::OnErrorIsReported() => "
111 "VE_RUNTIME_REC_WARNING");
niklase@google.com470e71d2011-07-07 08:21:25 +0000112 }
113 else if (warning == AudioDeviceObserver::kPlayoutWarning)
114 {
115 warningCode = VE_RUNTIME_PLAY_WARNING;
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000116 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
117 VoEId(_shared->instance_id(), -1),
118 "VoEBaseImpl::OnErrorIsReported() => "
119 "VE_RUNTIME_PLAY_WARNING");
niklase@google.com470e71d2011-07-07 08:21:25 +0000120 }
121 // Deliver callback (-1 <=> no channel dependency)
122 _voiceEngineObserverPtr->CallbackOnError(-1, warningCode);
123 }
124 }
125}
126
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000127int32_t VoEBaseImpl::RecordedDataIsAvailable(
henrika@webrtc.org907bc552012-03-09 08:59:19 +0000128 const void* audioSamples,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000129 const uint32_t nSamples,
130 const uint8_t nBytesPerSample,
131 const uint8_t nChannels,
132 const uint32_t samplesPerSec,
133 const uint32_t totalDelayMS,
134 const int32_t clockDrift,
135 const uint32_t currentMicLevel,
niklas.enbom@webrtc.org3be565b2013-05-07 21:04:24 +0000136 const bool keyPressed,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000137 uint32_t& newMicLevel)
niklase@google.com470e71d2011-07-07 08:21:25 +0000138{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000139 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000140 "VoEBaseImpl::RecordedDataIsAvailable(nSamples=%u, "
141 "nBytesPerSample=%u, nChannels=%u, samplesPerSec=%u, "
142 "totalDelayMS=%u, clockDrift=%d, currentMicLevel=%u)",
143 nSamples, nBytesPerSample, nChannels, samplesPerSec,
144 totalDelayMS, clockDrift, currentMicLevel);
145
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000146 assert(_shared->transmit_mixer() != NULL);
147 assert(_shared->audio_device() != NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000148
niklase@google.com470e71d2011-07-07 08:21:25 +0000149 bool isAnalogAGC(false);
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000150 uint32_t maxVolume(0);
151 uint16_t currentVoEMicLevel(0);
152 uint32_t newVoEMicLevel(0);
niklase@google.com470e71d2011-07-07 08:21:25 +0000153
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000154 if (_shared->audio_processing() &&
155 (_shared->audio_processing()->gain_control()->mode()
niklase@google.com470e71d2011-07-07 08:21:25 +0000156 == GainControl::kAdaptiveAnalog))
157 {
158 isAnalogAGC = true;
159 }
160
161 // Will only deal with the volume in adaptive analog mode
162 if (isAnalogAGC)
163 {
164 // Scale from ADM to VoE level range
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000165 if (_shared->audio_device()->MaxMicrophoneVolume(&maxVolume) == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000166 {
167 if (0 != maxVolume)
168 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000169 currentVoEMicLevel = (uint16_t) ((currentMicLevel
niklase@google.com470e71d2011-07-07 08:21:25 +0000170 * kMaxVolumeLevel + (int) (maxVolume / 2))
171 / (maxVolume));
172 }
173 }
punyabrata@webrtc.org6b6d0812011-09-28 17:45:03 +0000174 // We learned that on certain systems (e.g Linux) the currentVoEMicLevel
175 // can be greater than the maxVolumeLevel therefore
176 // we are going to cap the currentVoEMicLevel to the maxVolumeLevel
xians@webrtc.org3ab6dda2012-02-16 18:15:54 +0000177 // and change the maxVolume to currentMicLevel if it turns out that
178 // the currentVoEMicLevel is indeed greater than the maxVolumeLevel.
punyabrata@webrtc.org6b6d0812011-09-28 17:45:03 +0000179 if (currentVoEMicLevel > kMaxVolumeLevel)
180 {
181 currentVoEMicLevel = kMaxVolumeLevel;
xians@webrtc.org3ab6dda2012-02-16 18:15:54 +0000182 maxVolume = currentMicLevel;
punyabrata@webrtc.org6b6d0812011-09-28 17:45:03 +0000183 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000184 }
185
186 // Keep track if the MicLevel has been changed by the AGC, if not,
187 // use the old value AGC returns to let AGC continue its trend,
188 // so eventually the AGC is able to change the mic level. This handles
189 // issues with truncation introduced by the scaling.
190 if (_oldMicLevel == currentMicLevel)
191 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000192 currentVoEMicLevel = (uint16_t) _oldVoEMicLevel;
niklase@google.com470e71d2011-07-07 08:21:25 +0000193 }
194
niklase@google.com470e71d2011-07-07 08:21:25 +0000195 // Perform channel-independent operations
196 // (APM, mix with file, record to file, mute, etc.)
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000197 _shared->transmit_mixer()->PrepareDemux(audioSamples, nSamples, nChannels,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000198 samplesPerSec, static_cast<uint16_t>(totalDelayMS), clockDrift,
niklas.enbom@webrtc.org3be565b2013-05-07 21:04:24 +0000199 currentVoEMicLevel, keyPressed);
niklase@google.com470e71d2011-07-07 08:21:25 +0000200
201 // Copy the audio frame to each sending channel and perform
202 // channel-dependent operations (file mixing, mute, etc.) to prepare
203 // for encoding.
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000204 _shared->transmit_mixer()->DemuxAndMix();
niklase@google.com470e71d2011-07-07 08:21:25 +0000205 // Do the encoding and packetize+transmit the RTP packet when encoding
206 // is done.
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000207 _shared->transmit_mixer()->EncodeAndSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000208
209 // Will only deal with the volume in adaptive analog mode
210 if (isAnalogAGC)
211 {
212 // Scale from VoE to ADM level range
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000213 newVoEMicLevel = _shared->transmit_mixer()->CaptureLevel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000214 if (newVoEMicLevel != currentVoEMicLevel)
215 {
216 // Add (kMaxVolumeLevel/2) to round the value
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000217 newMicLevel = (uint32_t) ((newVoEMicLevel * maxVolume
niklase@google.com470e71d2011-07-07 08:21:25 +0000218 + (int) (kMaxVolumeLevel / 2)) / (kMaxVolumeLevel));
219 }
220 else
221 {
222 // Pass zero if the level is unchanged
223 newMicLevel = 0;
224 }
225
226 // Keep track of the value AGC returns
227 _oldVoEMicLevel = newVoEMicLevel;
228 _oldMicLevel = currentMicLevel;
229 }
230
231 return 0;
232}
233
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000234int32_t VoEBaseImpl::NeedMorePlayData(
235 const uint32_t nSamples,
236 const uint8_t nBytesPerSample,
237 const uint8_t nChannels,
238 const uint32_t samplesPerSec,
henrika@webrtc.org907bc552012-03-09 08:59:19 +0000239 void* audioSamples,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000240 uint32_t& nSamplesOut)
niklase@google.com470e71d2011-07-07 08:21:25 +0000241{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000242 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000243 "VoEBaseImpl::NeedMorePlayData(nSamples=%u, "
244 "nBytesPerSample=%d, nChannels=%d, samplesPerSec=%u)",
245 nSamples, nBytesPerSample, nChannels, samplesPerSec);
246
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000247 assert(_shared->output_mixer() != NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000248
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +0000249 // TODO(andrew): if the device is running in mono, we should tell the mixer
250 // here so that it will only request mono from AudioCodingModule.
niklase@google.com470e71d2011-07-07 08:21:25 +0000251 // Perform mixing of all active participants (channel-based mixing)
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000252 _shared->output_mixer()->MixActiveChannels();
niklase@google.com470e71d2011-07-07 08:21:25 +0000253
254 // Additional operations on the combined signal
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000255 _shared->output_mixer()->DoOperationsOnCombinedSignal();
niklase@google.com470e71d2011-07-07 08:21:25 +0000256
257 // Retrieve the final output mix (resampled to match the ADM)
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000258 _shared->output_mixer()->GetMixedAudio(samplesPerSec, nChannels,
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +0000259 &_audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000260
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +0000261 assert(static_cast<int>(nSamples) == _audioFrame.samples_per_channel_);
xians@google.com0b0665a2011-08-08 08:18:44 +0000262 assert(samplesPerSec ==
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000263 static_cast<uint32_t>(_audioFrame.sample_rate_hz_));
niklase@google.com470e71d2011-07-07 08:21:25 +0000264
265 // Deliver audio (PCM) samples to the ADM
266 memcpy(
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000267 (int16_t*) audioSamples,
268 (const int16_t*) _audioFrame.data_,
269 sizeof(int16_t) * (_audioFrame.samples_per_channel_
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000270 * _audioFrame.num_channels_));
niklase@google.com470e71d2011-07-07 08:21:25 +0000271
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000272 nSamplesOut = _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000273
274 return 0;
275}
276
277int VoEBaseImpl::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
278{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000279 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000280 "RegisterVoiceEngineObserver(observer=0x%d)", &observer);
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000281 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000282 if (_voiceEngineObserverPtr)
283 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000284 _shared->SetLastError(VE_INVALID_OPERATION, kTraceError,
285 "RegisterVoiceEngineObserver() observer already enabled");
niklase@google.com470e71d2011-07-07 08:21:25 +0000286 return -1;
287 }
288
289 // Register the observer in all active channels
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000290 voe::ScopedChannel sc(_shared->channel_manager());
niklase@google.com470e71d2011-07-07 08:21:25 +0000291 void* iterator(NULL);
292 voe::Channel* channelPtr = sc.GetFirstChannel(iterator);
293 while (channelPtr != NULL)
294 {
295 channelPtr->RegisterVoiceEngineObserver(observer);
296 channelPtr = sc.GetNextChannel(iterator);
297 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000298 _shared->transmit_mixer()->RegisterVoiceEngineObserver(observer);
niklase@google.com470e71d2011-07-07 08:21:25 +0000299
300 _voiceEngineObserverPtr = &observer;
301 _voiceEngineObserver = true;
302
303 return 0;
304}
305
306int VoEBaseImpl::DeRegisterVoiceEngineObserver()
307{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000308 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000309 "DeRegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000310 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000311 if (!_voiceEngineObserverPtr)
312 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000313 _shared->SetLastError(VE_INVALID_OPERATION, kTraceError,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000314 "DeRegisterVoiceEngineObserver() observer already disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +0000315 return 0;
316 }
317
318 _voiceEngineObserver = false;
319 _voiceEngineObserverPtr = NULL;
320
321 // Deregister the observer in all active channels
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000322 voe::ScopedChannel sc(_shared->channel_manager());
niklase@google.com470e71d2011-07-07 08:21:25 +0000323 void* iterator(NULL);
324 voe::Channel* channelPtr = sc.GetFirstChannel(iterator);
325 while (channelPtr != NULL)
326 {
327 channelPtr->DeRegisterVoiceEngineObserver();
328 channelPtr = sc.GetNextChannel(iterator);
329 }
330
331 return 0;
332}
333
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000334int VoEBaseImpl::Init(AudioDeviceModule* external_adm,
335 AudioProcessing* audioproc)
niklase@google.com470e71d2011-07-07 08:21:25 +0000336{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000337 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
henrika@google.com73d65512011-09-07 15:11:18 +0000338 "Init(external_adm=0x%p)", external_adm);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000339 CriticalSectionScoped cs(_shared->crit_sec());
niklase@google.com470e71d2011-07-07 08:21:25 +0000340
kma@webrtc.org0221b782012-09-08 00:09:26 +0000341 WebRtcSpl_Init();
342
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000343 if (_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000344 {
345 return 0;
346 }
347
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000348 if (_shared->process_thread())
niklase@google.com470e71d2011-07-07 08:21:25 +0000349 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000350 if (_shared->process_thread()->Start() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000351 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000352 _shared->SetLastError(VE_THREAD_ERROR, kTraceError,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000353 "Init() failed to start module process thread");
niklase@google.com470e71d2011-07-07 08:21:25 +0000354 return -1;
355 }
356 }
357
andrew@webrtc.org3192d652011-12-21 18:00:59 +0000358 // Create an internal ADM if the user has not added an external
henrika@google.com73d65512011-09-07 15:11:18 +0000359 // ADM implementation as input to Init().
360 if (external_adm == NULL)
niklase@google.com470e71d2011-07-07 08:21:25 +0000361 {
henrika@google.com73d65512011-09-07 15:11:18 +0000362 // Create the internal ADM implementation.
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000363 _shared->set_audio_device(AudioDeviceModuleImpl::Create(
364 VoEId(_shared->instance_id(), -1), _shared->audio_device_layer()));
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000365
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000366 if (_shared->audio_device() == NULL)
niklase@google.com470e71d2011-07-07 08:21:25 +0000367 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000368 _shared->SetLastError(VE_NO_MEMORY, kTraceCritical,
369 "Init() failed to create the ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +0000370 return -1;
371 }
372 }
henrika@google.com73d65512011-09-07 15:11:18 +0000373 else
374 {
375 // Use the already existing external ADM implementation.
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000376 _shared->set_audio_device(external_adm);
377 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
henrika@google.com73d65512011-09-07 15:11:18 +0000378 "An external ADM implementation will be used in VoiceEngine");
379 }
380
niklase@google.com470e71d2011-07-07 08:21:25 +0000381 // Register the ADM to the process thread, which will drive the error
382 // callback mechanism
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000383 if (_shared->process_thread() &&
384 _shared->process_thread()->RegisterModule(_shared->audio_device()) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000385 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000386 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
387 "Init() failed to register the ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +0000388 return -1;
389 }
390
391 bool available(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000392
393 // --------------------
394 // Reinitialize the ADM
395
396 // Register the AudioObserver implementation
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000397 if (_shared->audio_device()->RegisterEventObserver(this) != 0) {
398 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
399 "Init() failed to register event observer for the ADM");
xians@webrtc.org79af7342012-01-31 12:22:14 +0000400 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000401
402 // Register the AudioTransport implementation
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000403 if (_shared->audio_device()->RegisterAudioCallback(this) != 0) {
404 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
405 "Init() failed to register audio callback for the ADM");
xians@webrtc.org79af7342012-01-31 12:22:14 +0000406 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000407
408 // ADM initialization
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000409 if (_shared->audio_device()->Init() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000410 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000411 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
412 "Init() failed to initialize the ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +0000413 return -1;
414 }
415
416 // Initialize the default speaker
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000417 if (_shared->audio_device()->SetPlayoutDevice(
418 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000419 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000420 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000421 "Init() failed to set the default output device");
niklase@google.com470e71d2011-07-07 08:21:25 +0000422 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000423 if (_shared->audio_device()->SpeakerIsAvailable(&available) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000424 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000425 _shared->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000426 "Init() failed to check speaker availability, trying to "
427 "initialize speaker anyway");
niklase@google.com470e71d2011-07-07 08:21:25 +0000428 }
429 else if (!available)
430 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000431 _shared->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000432 "Init() speaker not available, trying to initialize speaker "
433 "anyway");
niklase@google.com470e71d2011-07-07 08:21:25 +0000434 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000435 if (_shared->audio_device()->InitSpeaker() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000436 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000437 _shared->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000438 "Init() failed to initialize the speaker");
niklase@google.com470e71d2011-07-07 08:21:25 +0000439 }
440
441 // Initialize the default microphone
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000442 if (_shared->audio_device()->SetRecordingDevice(
443 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000444 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000445 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000446 "Init() failed to set the default input device");
niklase@google.com470e71d2011-07-07 08:21:25 +0000447 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000448 if (_shared->audio_device()->MicrophoneIsAvailable(&available) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000449 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000450 _shared->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000451 "Init() failed to check microphone availability, trying to "
452 "initialize microphone anyway");
niklase@google.com470e71d2011-07-07 08:21:25 +0000453 }
454 else if (!available)
455 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000456 _shared->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000457 "Init() microphone not available, trying to initialize "
458 "microphone anyway");
niklase@google.com470e71d2011-07-07 08:21:25 +0000459 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000460 if (_shared->audio_device()->InitMicrophone() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000461 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000462 _shared->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000463 "Init() failed to initialize the microphone");
niklase@google.com470e71d2011-07-07 08:21:25 +0000464 }
465
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000466 // Set number of channels
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000467 if (_shared->audio_device()->StereoPlayoutIsAvailable(&available) != 0) {
468 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
469 "Init() failed to query stereo playout mode");
xians@webrtc.org79af7342012-01-31 12:22:14 +0000470 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000471 if (_shared->audio_device()->SetStereoPlayout(available) != 0)
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000472 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000473 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000474 "Init() failed to set mono/stereo playout mode");
475 }
andrew@webrtc.org3192d652011-12-21 18:00:59 +0000476
477 // TODO(andrew): These functions don't tell us whether stereo recording
478 // is truly available. We simply set the AudioProcessing input to stereo
479 // here, because we have to wait until receiving the first frame to
480 // determine the actual number of channels anyway.
481 //
482 // These functions may be changed; tracked here:
483 // http://code.google.com/p/webrtc/issues/detail?id=204
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000484 _shared->audio_device()->StereoRecordingIsAvailable(&available);
485 if (_shared->audio_device()->SetStereoRecording(available) != 0)
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000486 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000487 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000488 "Init() failed to set mono/stereo recording mode");
489 }
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000490
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000491 if (!audioproc) {
492 audioproc = AudioProcessing::Create(VoEId(_shared->instance_id(), -1));
493 if (!audioproc) {
494 LOG(LS_ERROR) << "Failed to create AudioProcessing.";
495 _shared->SetLastError(VE_NO_MEMORY);
496 return -1;
497 }
498 }
499 _shared->set_audio_processing(audioproc);
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000500
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000501 // Set the error state for any failures in this block.
502 _shared->SetLastError(VE_APM_ERROR);
503 if (audioproc->echo_cancellation()->set_device_sample_rate_hz(48000)) {
504 LOG_FERR1(LS_ERROR, set_device_sample_rate_hz, 48000);
505 return -1;
506 }
507 // Assume 16 kHz mono until the audio frames are received from the capture
508 // device, at which point this can be updated.
509 if (audioproc->set_sample_rate_hz(16000)) {
510 LOG_FERR1(LS_ERROR, set_sample_rate_hz, 16000);
511 return -1;
512 }
513 if (audioproc->set_num_channels(1, 1) != 0) {
514 LOG_FERR2(LS_ERROR, set_num_channels, 1, 1);
515 return -1;
516 }
517 if (audioproc->set_num_reverse_channels(1) != 0) {
518 LOG_FERR1(LS_ERROR, set_num_reverse_channels, 1);
519 return -1;
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000520 }
521
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000522 // Configure AudioProcessing components. All are disabled by default.
523 if (audioproc->high_pass_filter()->Enable(true) != 0) {
524 LOG_FERR1(LS_ERROR, high_pass_filter()->Enable, true);
525 return -1;
526 }
527 if (audioproc->echo_cancellation()->enable_drift_compensation(false) != 0) {
528 LOG_FERR1(LS_ERROR, enable_drift_compensation, false);
529 return -1;
530 }
531 if (audioproc->noise_suppression()->set_level(kDefaultNsMode) != 0) {
532 LOG_FERR1(LS_ERROR, noise_suppression()->set_level, kDefaultNsMode);
533 return -1;
534 }
535 GainControl* agc = audioproc->gain_control();
536 if (agc->set_analog_level_limits(kMinVolumeLevel, kMaxVolumeLevel) != 0) {
537 LOG_FERR2(LS_ERROR, agc->set_analog_level_limits, kMinVolumeLevel,
538 kMaxVolumeLevel);
539 return -1;
540 }
541 if (agc->set_mode(kDefaultAgcMode) != 0) {
542 LOG_FERR1(LS_ERROR, agc->set_mode, kDefaultAgcMode);
543 return -1;
544 }
545 if (agc->Enable(kDefaultAgcState) != 0) {
546 LOG_FERR1(LS_ERROR, agc->Enable, kDefaultAgcState);
547 return -1;
548 }
549 _shared->SetLastError(0); // Clear error state.
550
niklase@google.com470e71d2011-07-07 08:21:25 +0000551#ifdef WEBRTC_VOICE_ENGINE_AGC
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000552 bool agc_enabled = agc->mode() == GainControl::kAdaptiveAnalog &&
553 agc->is_enabled();
554 if (_shared->audio_device()->SetAGC(agc_enabled) != 0) {
555 LOG_FERR1(LS_ERROR, audio_device()->SetAGC, agc_enabled);
556 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR);
andrew@webrtc.orga9a1df02013-03-05 23:36:10 +0000557 // TODO(ajm): No error return here due to
558 // https://code.google.com/p/webrtc/issues/detail?id=1464
niklase@google.com470e71d2011-07-07 08:21:25 +0000559 }
560#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000561
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000562 return _shared->statistics().SetInitialized();
niklase@google.com470e71d2011-07-07 08:21:25 +0000563}
564
565int VoEBaseImpl::Terminate()
566{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000567 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000568 "Terminate()");
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000569 CriticalSectionScoped cs(_shared->crit_sec());
niklase@google.com470e71d2011-07-07 08:21:25 +0000570 return TerminateInternal();
571}
572
573int VoEBaseImpl::MaxNumOfChannels()
574{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000575 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000576 "MaxNumOfChannels()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000577 int32_t maxNumOfChannels =
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000578 _shared->channel_manager().MaxNumOfChannels();
579 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
580 VoEId(_shared->instance_id(), -1),
581 "MaxNumOfChannels() => %d", maxNumOfChannels);
niklase@google.com470e71d2011-07-07 08:21:25 +0000582 return (maxNumOfChannels);
583}
584
585int VoEBaseImpl::CreateChannel()
586{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000587 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000588 "CreateChannel()");
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000589 CriticalSectionScoped cs(_shared->crit_sec());
niklase@google.com470e71d2011-07-07 08:21:25 +0000590
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000591 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000592 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000593 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000594 return -1;
595 }
596
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000597 int32_t channelId = -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000598
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000599 if (!_shared->channel_manager().CreateChannel(channelId))
niklase@google.com470e71d2011-07-07 08:21:25 +0000600 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000601 _shared->SetLastError(VE_CHANNEL_NOT_CREATED, kTraceError,
602 "CreateChannel() failed to allocate memory for channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000603 return -1;
604 }
605
606 bool destroyChannel(false);
607 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000608 voe::ScopedChannel sc(_shared->channel_manager(), channelId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000609 voe::Channel* channelPtr = sc.ChannelPtr();
610 if (channelPtr == NULL)
611 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000612 _shared->SetLastError(VE_CHANNEL_NOT_CREATED, kTraceError,
613 "CreateChannel() failed to allocate memory for channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000614 return -1;
615 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000616 else if (channelPtr->SetEngineInformation(_shared->statistics(),
617 *_shared->output_mixer(),
618 *_shared->transmit_mixer(),
619 *_shared->process_thread(),
620 *_shared->audio_device(),
niklase@google.com470e71d2011-07-07 08:21:25 +0000621 _voiceEngineObserverPtr,
622 &_callbackCritSect) != 0)
623 {
624 destroyChannel = true;
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000625 _shared->SetLastError(VE_CHANNEL_NOT_CREATED, kTraceError,
626 "CreateChannel() failed to associate engine and channel."
627 " Destroying channel.");
niklase@google.com470e71d2011-07-07 08:21:25 +0000628 }
629 else if (channelPtr->Init() != 0)
630 {
631 destroyChannel = true;
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000632 _shared->SetLastError(VE_CHANNEL_NOT_CREATED, kTraceError,
633 "CreateChannel() failed to initialize channel. Destroying"
634 " channel.");
niklase@google.com470e71d2011-07-07 08:21:25 +0000635 }
636 }
637 if (destroyChannel)
638 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000639 _shared->channel_manager().DestroyChannel(channelId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000640 return -1;
641 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000642 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
643 VoEId(_shared->instance_id(), -1),
644 "CreateChannel() => %d", channelId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000645 return channelId;
646}
647
648int VoEBaseImpl::DeleteChannel(int channel)
649{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000650 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000651 "DeleteChannel(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000652 CriticalSectionScoped cs(_shared->crit_sec());
niklase@google.com470e71d2011-07-07 08:21:25 +0000653
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000654 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000655 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000656 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000657 return -1;
658 }
659
660 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000661 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000662 voe::Channel* channelPtr = sc.ChannelPtr();
663 if (channelPtr == NULL)
664 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000665 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
666 "DeleteChannel() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000667 return -1;
668 }
669 }
670
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000671 if (_shared->channel_manager().DestroyChannel(channel) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000672 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000673 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
674 "DeleteChannel() failed to destroy channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000675 return -1;
676 }
677
678 if (StopSend() != 0)
679 {
680 return -1;
681 }
682
683 if (StopPlayout() != 0)
684 {
685 return -1;
686 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +0000687
niklase@google.com470e71d2011-07-07 08:21:25 +0000688 return 0;
689}
690
niklase@google.com470e71d2011-07-07 08:21:25 +0000691int VoEBaseImpl::StartReceive(int channel)
692{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000693 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000694 "StartReceive(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000695 CriticalSectionScoped cs(_shared->crit_sec());
696 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000697 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000698 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000699 return -1;
700 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000701 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000702 voe::Channel* channelPtr = sc.ChannelPtr();
703 if (channelPtr == NULL)
704 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000705 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
706 "StartReceive() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000707 return -1;
708 }
709 return channelPtr->StartReceiving();
710}
711
712int VoEBaseImpl::StopReceive(int channel)
713{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000714 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000715 "StopListen(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000716 CriticalSectionScoped cs(_shared->crit_sec());
717 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000718 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000719 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000720 return -1;
721 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000722 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000723 voe::Channel* channelPtr = sc.ChannelPtr();
724 if (channelPtr == NULL)
725 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000726 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
727 "SetLocalReceiver() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000728 return -1;
729 }
730 return channelPtr->StopReceiving();
731}
732
733int VoEBaseImpl::StartPlayout(int channel)
734{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000735 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000736 "StartPlayout(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000737 CriticalSectionScoped cs(_shared->crit_sec());
738 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000739 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000740 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000741 return -1;
742 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000743 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000744 voe::Channel* channelPtr = sc.ChannelPtr();
745 if (channelPtr == NULL)
746 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000747 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
748 "StartPlayout() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000749 return -1;
750 }
751 if (channelPtr->Playing())
752 {
753 return 0;
754 }
755 if (StartPlayout() != 0)
756 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000757 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
758 "StartPlayout() failed to start playout");
niklase@google.com470e71d2011-07-07 08:21:25 +0000759 return -1;
760 }
761 return channelPtr->StartPlayout();
762}
763
764int VoEBaseImpl::StopPlayout(int channel)
765{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000766 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000767 "StopPlayout(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000768 CriticalSectionScoped cs(_shared->crit_sec());
769 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000770 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000771 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000772 return -1;
773 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000774 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000775 voe::Channel* channelPtr = sc.ChannelPtr();
776 if (channelPtr == NULL)
777 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000778 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
779 "StopPlayout() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000780 return -1;
781 }
782 if (channelPtr->StopPlayout() != 0)
783 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000784 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
785 VoEId(_shared->instance_id(), -1),
786 "StopPlayout() failed to stop playout for channel %d", channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000787 }
788 return StopPlayout();
789}
790
791int VoEBaseImpl::StartSend(int channel)
792{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000793 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000794 "StartSend(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000795 CriticalSectionScoped cs(_shared->crit_sec());
796 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000797 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000798 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000799 return -1;
800 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000801 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000802 voe::Channel* channelPtr = sc.ChannelPtr();
803 if (channelPtr == NULL)
804 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000805 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
806 "StartSend() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000807 return -1;
808 }
809 if (channelPtr->Sending())
810 {
811 return 0;
812 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000813 if (StartSend() != 0)
814 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000815 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
816 "StartSend() failed to start recording");
niklase@google.com470e71d2011-07-07 08:21:25 +0000817 return -1;
818 }
819 return channelPtr->StartSend();
820}
821
822int VoEBaseImpl::StopSend(int channel)
823{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000824 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000825 "StopSend(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000826 CriticalSectionScoped cs(_shared->crit_sec());
827 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000828 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000829 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000830 return -1;
831 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000832 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000833 voe::Channel* channelPtr = sc.ChannelPtr();
834 if (channelPtr == NULL)
835 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000836 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
837 "StopSend() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000838 return -1;
839 }
840 if (channelPtr->StopSend() != 0)
841 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000842 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
843 VoEId(_shared->instance_id(), -1),
844 "StopSend() failed to stop sending for channel %d", channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000845 }
846 return StopSend();
847}
848
849int VoEBaseImpl::GetVersion(char version[1024])
850{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000851 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000852 "GetVersion(version=?)");
853 assert(kVoiceEngineVersionMaxMessageSize == 1024);
854
855 if (version == NULL)
856 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000857 _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000858 return (-1);
859 }
860
861 char versionBuf[kVoiceEngineVersionMaxMessageSize];
862 char* versionPtr = versionBuf;
863
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000864 int32_t len = 0;
865 int32_t accLen = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000866
867 len = AddVoEVersion(versionPtr);
868 if (len == -1)
869 {
870 return -1;
871 }
872 versionPtr += len;
873 accLen += len;
874 assert(accLen < kVoiceEngineVersionMaxMessageSize);
875
876 len = AddBuildInfo(versionPtr);
877 if (len == -1)
878 {
879 return -1;
880 }
881 versionPtr += len;
882 accLen += len;
883 assert(accLen < kVoiceEngineVersionMaxMessageSize);
884
pwestin@webrtc.org684f0572013-03-13 23:20:57 +0000885#ifdef WEBRTC_EXTERNAL_TRANSPORT
886 len = AddExternalTransportBuild(versionPtr);
887 if (len == -1)
888 {
889 return -1;
890 }
891 versionPtr += len;
892 accLen += len;
893 assert(accLen < kVoiceEngineVersionMaxMessageSize);
894#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000895#ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT
896 len = AddExternalRecAndPlayoutBuild(versionPtr);
897 if (len == -1)
898 {
899 return -1;
900 }
901 versionPtr += len;
902 accLen += len;
903 assert(accLen < kVoiceEngineVersionMaxMessageSize);
pwestin@webrtc.orgc450a192012-01-04 15:00:12 +0000904 #endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000905
906 memcpy(version, versionBuf, accLen);
907 version[accLen] = '\0';
908
909 // to avoid the truncation in the trace, split the string into parts
910 char partOfVersion[256];
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000911 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
912 VoEId(_shared->instance_id(), -1), "GetVersion() =>");
niklase@google.com470e71d2011-07-07 08:21:25 +0000913 for (int partStart = 0; partStart < accLen;)
914 {
915 memset(partOfVersion, 0, sizeof(partOfVersion));
916 int partEnd = partStart + 180;
917 while (version[partEnd] != '\n' && version[partEnd] != '\0')
918 {
919 partEnd--;
920 }
921 if (partEnd < accLen)
922 {
923 memcpy(partOfVersion, &version[partStart], partEnd - partStart);
924 }
925 else
926 {
927 memcpy(partOfVersion, &version[partStart], accLen - partStart);
928 }
929 partStart = partEnd;
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000930 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
931 VoEId(_shared->instance_id(), -1), "%s", partOfVersion);
niklase@google.com470e71d2011-07-07 08:21:25 +0000932 }
933
934 return 0;
935}
936
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000937int32_t VoEBaseImpl::AddBuildInfo(char* str) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000938{
leozwang@webrtc.org48a5df62012-04-24 14:50:50 +0000939 return sprintf(str, "Build: svn:%s %s\n", WEBRTC_SVNREVISION, BUILDINFO);
niklase@google.com470e71d2011-07-07 08:21:25 +0000940}
941
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000942int32_t VoEBaseImpl::AddVoEVersion(char* str) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000943{
944 return sprintf(str, "VoiceEngine 4.1.0\n");
945}
946
pwestin@webrtc.org684f0572013-03-13 23:20:57 +0000947#ifdef WEBRTC_EXTERNAL_TRANSPORT
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000948int32_t VoEBaseImpl::AddExternalTransportBuild(char* str) const
pwestin@webrtc.org684f0572013-03-13 23:20:57 +0000949{
950 return sprintf(str, "External transport build\n");
951}
952#endif
953
niklase@google.com470e71d2011-07-07 08:21:25 +0000954#ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000955int32_t VoEBaseImpl::AddExternalRecAndPlayoutBuild(char* str) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000956{
957 return sprintf(str, "External recording and playout build\n");
958}
959#endif
960
niklase@google.com470e71d2011-07-07 08:21:25 +0000961int VoEBaseImpl::LastError()
962{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000963 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000964 "LastError()");
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000965 return (_shared->statistics().LastError());
niklase@google.com470e71d2011-07-07 08:21:25 +0000966}
967
968
969int VoEBaseImpl::SetNetEQPlayoutMode(int channel, NetEqModes mode)
970{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000971 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000972 "SetNetEQPlayoutMode(channel=%i, mode=%i)", channel, mode);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000973 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000974 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000975 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000976 return -1;
977 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000978 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000979 voe::Channel* channelPtr = sc.ChannelPtr();
980 if (channelPtr == NULL)
981 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000982 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
983 "SetNetEQPlayoutMode() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000984 return -1;
985 }
986 return channelPtr->SetNetEQPlayoutMode(mode);
987}
988
989int VoEBaseImpl::GetNetEQPlayoutMode(int channel, NetEqModes& mode)
990{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000991 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000992 "GetNetEQPlayoutMode(channel=%i, mode=?)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000993 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000994 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000995 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000996 return -1;
997 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000998 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000999 voe::Channel* channelPtr = sc.ChannelPtr();
1000 if (channelPtr == NULL)
1001 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001002 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
1003 "GetNetEQPlayoutMode() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +00001004 return -1;
1005 }
1006 return channelPtr->GetNetEQPlayoutMode(mode);
1007}
1008
niklase@google.com470e71d2011-07-07 08:21:25 +00001009int VoEBaseImpl::SetOnHoldStatus(int channel, bool enable, OnHoldModes mode)
1010{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001011 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001012 "SetOnHoldStatus(channel=%d, enable=%d, mode=%d)", channel,
1013 enable, mode);
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001014 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +00001015 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001016 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +00001017 return -1;
1018 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001019 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +00001020 voe::Channel* channelPtr = sc.ChannelPtr();
1021 if (channelPtr == NULL)
1022 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001023 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
1024 "SetOnHoldStatus() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +00001025 return -1;
1026 }
1027 return channelPtr->SetOnHoldStatus(enable, mode);
1028}
1029
1030int VoEBaseImpl::GetOnHoldStatus(int channel, bool& enabled, OnHoldModes& mode)
1031{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001032 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001033 "GetOnHoldStatus(channel=%d, enabled=?, mode=?)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001034 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +00001035 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001036 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +00001037 return -1;
1038 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001039 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +00001040 voe::Channel* channelPtr = sc.ChannelPtr();
1041 if (channelPtr == NULL)
1042 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001043 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
1044 "GetOnHoldStatus() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +00001045 return -1;
1046 }
1047 return channelPtr->GetOnHoldStatus(enabled, mode);
1048}
1049
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001050int32_t VoEBaseImpl::StartPlayout()
niklase@google.com470e71d2011-07-07 08:21:25 +00001051{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001052 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001053 "VoEBaseImpl::StartPlayout()");
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001054 if (_shared->audio_device()->Playing())
niklase@google.com470e71d2011-07-07 08:21:25 +00001055 {
1056 return 0;
1057 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001058 if (!_shared->ext_playout())
niklase@google.com470e71d2011-07-07 08:21:25 +00001059 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001060 if (_shared->audio_device()->InitPlayout() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001061 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001062 WEBRTC_TRACE(kTraceError, kTraceVoice,
1063 VoEId(_shared->instance_id(), -1),
1064 "StartPlayout() failed to initialize playout");
niklase@google.com470e71d2011-07-07 08:21:25 +00001065 return -1;
1066 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001067 if (_shared->audio_device()->StartPlayout() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001068 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001069 WEBRTC_TRACE(kTraceError, kTraceVoice,
1070 VoEId(_shared->instance_id(), -1),
1071 "StartPlayout() failed to start playout");
niklase@google.com470e71d2011-07-07 08:21:25 +00001072 return -1;
1073 }
1074 }
1075 return 0;
1076}
1077
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001078int32_t VoEBaseImpl::StopPlayout()
niklase@google.com470e71d2011-07-07 08:21:25 +00001079{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001080 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001081 "VoEBaseImpl::StopPlayout()");
1082
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001083 int32_t numOfChannels = _shared->channel_manager().NumOfChannels();
niklase@google.com470e71d2011-07-07 08:21:25 +00001084 if (numOfChannels <= 0)
1085 {
1086 return 0;
1087 }
1088
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001089 uint16_t nChannelsPlaying(0);
1090 int32_t* channelsArray = new int32_t[numOfChannels];
niklase@google.com470e71d2011-07-07 08:21:25 +00001091
1092 // Get number of playing channels
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001093 _shared->channel_manager().GetChannelIds(channelsArray, numOfChannels);
niklase@google.com470e71d2011-07-07 08:21:25 +00001094 for (int i = 0; i < numOfChannels; i++)
1095 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001096 voe::ScopedChannel sc(_shared->channel_manager(), channelsArray[i]);
niklase@google.com470e71d2011-07-07 08:21:25 +00001097 voe::Channel* chPtr = sc.ChannelPtr();
1098 if (chPtr)
1099 {
1100 if (chPtr->Playing())
1101 {
1102 nChannelsPlaying++;
1103 }
1104 }
1105 }
1106 delete[] channelsArray;
1107
1108 // Stop audio-device playing if no channel is playing out
1109 if (nChannelsPlaying == 0)
1110 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001111 if (_shared->audio_device()->StopPlayout() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001112 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001113 _shared->SetLastError(VE_CANNOT_STOP_PLAYOUT, kTraceError,
1114 "StopPlayout() failed to stop playout");
niklase@google.com470e71d2011-07-07 08:21:25 +00001115 return -1;
1116 }
1117 }
1118 return 0;
1119}
1120
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001121int32_t VoEBaseImpl::StartSend()
niklase@google.com470e71d2011-07-07 08:21:25 +00001122{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001123 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001124 "VoEBaseImpl::StartSend()");
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001125 if (_shared->audio_device()->Recording())
niklase@google.com470e71d2011-07-07 08:21:25 +00001126 {
1127 return 0;
1128 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001129 if (!_shared->ext_recording())
niklase@google.com470e71d2011-07-07 08:21:25 +00001130 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001131 if (_shared->audio_device()->InitRecording() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001132 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001133 WEBRTC_TRACE(kTraceError, kTraceVoice,
1134 VoEId(_shared->instance_id(), -1),
1135 "StartSend() failed to initialize recording");
niklase@google.com470e71d2011-07-07 08:21:25 +00001136 return -1;
1137 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001138 if (_shared->audio_device()->StartRecording() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001139 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001140 WEBRTC_TRACE(kTraceError, kTraceVoice,
1141 VoEId(_shared->instance_id(), -1),
1142 "StartSend() failed to start recording");
niklase@google.com470e71d2011-07-07 08:21:25 +00001143 return -1;
1144 }
1145 }
1146
1147 return 0;
1148}
1149
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001150int32_t VoEBaseImpl::StopSend()
niklase@google.com470e71d2011-07-07 08:21:25 +00001151{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001152 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001153 "VoEBaseImpl::StopSend()");
1154
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001155 if (_shared->NumOfSendingChannels() == 0 &&
1156 !_shared->transmit_mixer()->IsRecordingMic())
niklase@google.com470e71d2011-07-07 08:21:25 +00001157 {
1158 // Stop audio-device recording if no channel is recording
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001159 if (_shared->audio_device()->StopRecording() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001160 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001161 _shared->SetLastError(VE_CANNOT_STOP_RECORDING, kTraceError,
1162 "StopSend() failed to stop recording");
niklase@google.com470e71d2011-07-07 08:21:25 +00001163 return -1;
1164 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001165 _shared->transmit_mixer()->StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +00001166 }
1167
1168 return 0;
1169}
1170
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001171int32_t VoEBaseImpl::TerminateInternal()
niklase@google.com470e71d2011-07-07 08:21:25 +00001172{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001173 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001174 "VoEBaseImpl::TerminateInternal()");
1175
1176 // Delete any remaining channel objects
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001177 int32_t numOfChannels = _shared->channel_manager().NumOfChannels();
niklase@google.com470e71d2011-07-07 08:21:25 +00001178 if (numOfChannels > 0)
1179 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001180 int32_t* channelsArray = new int32_t[numOfChannels];
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001181 _shared->channel_manager().GetChannelIds(channelsArray, numOfChannels);
niklase@google.com470e71d2011-07-07 08:21:25 +00001182 for (int i = 0; i < numOfChannels; i++)
1183 {
1184 DeleteChannel(channelsArray[i]);
1185 }
1186 delete[] channelsArray;
1187 }
1188
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001189 if (_shared->process_thread())
niklase@google.com470e71d2011-07-07 08:21:25 +00001190 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001191 if (_shared->audio_device())
niklase@google.com470e71d2011-07-07 08:21:25 +00001192 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001193 if (_shared->process_thread()->
1194 DeRegisterModule(_shared->audio_device()) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001195 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001196 _shared->SetLastError(VE_THREAD_ERROR, kTraceError,
1197 "TerminateInternal() failed to deregister ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +00001198 }
1199 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001200 if (_shared->process_thread()->Stop() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001201 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001202 _shared->SetLastError(VE_THREAD_ERROR, kTraceError,
1203 "TerminateInternal() failed to stop module process thread");
niklase@google.com470e71d2011-07-07 08:21:25 +00001204 }
1205 }
1206
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +00001207 if (_shared->audio_device())
niklase@google.com470e71d2011-07-07 08:21:25 +00001208 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001209 if (_shared->audio_device()->StopPlayout() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001210 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001211 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
1212 "TerminateInternal() failed to stop playout");
niklase@google.com470e71d2011-07-07 08:21:25 +00001213 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001214 if (_shared->audio_device()->StopRecording() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001215 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001216 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
1217 "TerminateInternal() failed to stop recording");
niklase@google.com470e71d2011-07-07 08:21:25 +00001218 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001219 if (_shared->audio_device()->RegisterEventObserver(NULL) != 0) {
1220 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
1221 "TerminateInternal() failed to de-register event observer "
1222 "for the ADM");
xians@webrtc.org79af7342012-01-31 12:22:14 +00001223 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001224 if (_shared->audio_device()->RegisterAudioCallback(NULL) != 0) {
1225 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
1226 "TerminateInternal() failed to de-register audio callback "
1227 "for the ADM");
xians@webrtc.org79af7342012-01-31 12:22:14 +00001228 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001229 if (_shared->audio_device()->Terminate() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001230 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001231 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
1232 "TerminateInternal() failed to terminate the ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +00001233 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001234 _shared->set_audio_device(NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +00001235 }
1236
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +00001237 if (_shared->audio_processing()) {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001238 _shared->set_audio_processing(NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +00001239 }
1240
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001241 return _shared->statistics().SetUnInitialized();
niklase@google.com470e71d2011-07-07 08:21:25 +00001242}
1243
1244} // namespace webrtc