blob: 1d5cf71b65823ae3f6fc16fd5778c59b6b6b6438 [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
127WebRtc_Word32 VoEBaseImpl::RecordedDataIsAvailable(
henrika@webrtc.org907bc552012-03-09 08:59:19 +0000128 const void* audioSamples,
niklase@google.com470e71d2011-07-07 08:21:25 +0000129 const WebRtc_UWord32 nSamples,
130 const WebRtc_UWord8 nBytesPerSample,
131 const WebRtc_UWord8 nChannels,
132 const WebRtc_UWord32 samplesPerSec,
133 const WebRtc_UWord32 totalDelayMS,
134 const WebRtc_Word32 clockDrift,
135 const WebRtc_UWord32 currentMicLevel,
136 WebRtc_UWord32& newMicLevel)
137{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000138 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000139 "VoEBaseImpl::RecordedDataIsAvailable(nSamples=%u, "
140 "nBytesPerSample=%u, nChannels=%u, samplesPerSec=%u, "
141 "totalDelayMS=%u, clockDrift=%d, currentMicLevel=%u)",
142 nSamples, nBytesPerSample, nChannels, samplesPerSec,
143 totalDelayMS, clockDrift, currentMicLevel);
144
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000145 assert(_shared->transmit_mixer() != NULL);
146 assert(_shared->audio_device() != NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000147
niklase@google.com470e71d2011-07-07 08:21:25 +0000148 bool isAnalogAGC(false);
149 WebRtc_UWord32 maxVolume(0);
150 WebRtc_UWord16 currentVoEMicLevel(0);
151 WebRtc_UWord32 newVoEMicLevel(0);
152
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000153 if (_shared->audio_processing() &&
154 (_shared->audio_processing()->gain_control()->mode()
niklase@google.com470e71d2011-07-07 08:21:25 +0000155 == GainControl::kAdaptiveAnalog))
156 {
157 isAnalogAGC = true;
158 }
159
160 // Will only deal with the volume in adaptive analog mode
161 if (isAnalogAGC)
162 {
163 // Scale from ADM to VoE level range
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000164 if (_shared->audio_device()->MaxMicrophoneVolume(&maxVolume) == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000165 {
166 if (0 != maxVolume)
167 {
168 currentVoEMicLevel = (WebRtc_UWord16) ((currentMicLevel
169 * kMaxVolumeLevel + (int) (maxVolume / 2))
170 / (maxVolume));
171 }
172 }
punyabrata@webrtc.org6b6d0812011-09-28 17:45:03 +0000173 // We learned that on certain systems (e.g Linux) the currentVoEMicLevel
174 // can be greater than the maxVolumeLevel therefore
175 // we are going to cap the currentVoEMicLevel to the maxVolumeLevel
xians@webrtc.org3ab6dda2012-02-16 18:15:54 +0000176 // and change the maxVolume to currentMicLevel if it turns out that
177 // the currentVoEMicLevel is indeed greater than the maxVolumeLevel.
punyabrata@webrtc.org6b6d0812011-09-28 17:45:03 +0000178 if (currentVoEMicLevel > kMaxVolumeLevel)
179 {
180 currentVoEMicLevel = kMaxVolumeLevel;
xians@webrtc.org3ab6dda2012-02-16 18:15:54 +0000181 maxVolume = currentMicLevel;
punyabrata@webrtc.org6b6d0812011-09-28 17:45:03 +0000182 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000183 }
184
185 // Keep track if the MicLevel has been changed by the AGC, if not,
186 // use the old value AGC returns to let AGC continue its trend,
187 // so eventually the AGC is able to change the mic level. This handles
188 // issues with truncation introduced by the scaling.
189 if (_oldMicLevel == currentMicLevel)
190 {
191 currentVoEMicLevel = (WebRtc_UWord16) _oldVoEMicLevel;
192 }
193
niklase@google.com470e71d2011-07-07 08:21:25 +0000194 // Perform channel-independent operations
195 // (APM, mix with file, record to file, mute, etc.)
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000196 _shared->transmit_mixer()->PrepareDemux(audioSamples, nSamples, nChannels,
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +0000197 samplesPerSec, static_cast<WebRtc_UWord16>(totalDelayMS), clockDrift,
198 currentVoEMicLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000199
200 // Copy the audio frame to each sending channel and perform
201 // channel-dependent operations (file mixing, mute, etc.) to prepare
202 // for encoding.
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000203 _shared->transmit_mixer()->DemuxAndMix();
niklase@google.com470e71d2011-07-07 08:21:25 +0000204 // Do the encoding and packetize+transmit the RTP packet when encoding
205 // is done.
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000206 _shared->transmit_mixer()->EncodeAndSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000207
208 // Will only deal with the volume in adaptive analog mode
209 if (isAnalogAGC)
210 {
211 // Scale from VoE to ADM level range
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000212 newVoEMicLevel = _shared->transmit_mixer()->CaptureLevel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000213 if (newVoEMicLevel != currentVoEMicLevel)
214 {
215 // Add (kMaxVolumeLevel/2) to round the value
216 newMicLevel = (WebRtc_UWord32) ((newVoEMicLevel * maxVolume
217 + (int) (kMaxVolumeLevel / 2)) / (kMaxVolumeLevel));
218 }
219 else
220 {
221 // Pass zero if the level is unchanged
222 newMicLevel = 0;
223 }
224
225 // Keep track of the value AGC returns
226 _oldVoEMicLevel = newVoEMicLevel;
227 _oldMicLevel = currentMicLevel;
228 }
229
230 return 0;
231}
232
233WebRtc_Word32 VoEBaseImpl::NeedMorePlayData(
234 const WebRtc_UWord32 nSamples,
235 const WebRtc_UWord8 nBytesPerSample,
236 const WebRtc_UWord8 nChannels,
237 const WebRtc_UWord32 samplesPerSec,
henrika@webrtc.org907bc552012-03-09 08:59:19 +0000238 void* audioSamples,
niklase@google.com470e71d2011-07-07 08:21:25 +0000239 WebRtc_UWord32& nSamplesOut)
240{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000241 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000242 "VoEBaseImpl::NeedMorePlayData(nSamples=%u, "
243 "nBytesPerSample=%d, nChannels=%d, samplesPerSec=%u)",
244 nSamples, nBytesPerSample, nChannels, samplesPerSec);
245
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000246 assert(_shared->output_mixer() != NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000247
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +0000248 // TODO(andrew): if the device is running in mono, we should tell the mixer
249 // here so that it will only request mono from AudioCodingModule.
niklase@google.com470e71d2011-07-07 08:21:25 +0000250 // Perform mixing of all active participants (channel-based mixing)
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000251 _shared->output_mixer()->MixActiveChannels();
niklase@google.com470e71d2011-07-07 08:21:25 +0000252
253 // Additional operations on the combined signal
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000254 _shared->output_mixer()->DoOperationsOnCombinedSignal();
niklase@google.com470e71d2011-07-07 08:21:25 +0000255
256 // Retrieve the final output mix (resampled to match the ADM)
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000257 _shared->output_mixer()->GetMixedAudio(samplesPerSec, nChannels,
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +0000258 &_audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000259
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +0000260 assert(static_cast<int>(nSamples) == _audioFrame.samples_per_channel_);
xians@google.com0b0665a2011-08-08 08:18:44 +0000261 assert(samplesPerSec ==
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000262 static_cast<WebRtc_UWord32>(_audioFrame.sample_rate_hz_));
niklase@google.com470e71d2011-07-07 08:21:25 +0000263
264 // Deliver audio (PCM) samples to the ADM
265 memcpy(
266 (WebRtc_Word16*) audioSamples,
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000267 (const WebRtc_Word16*) _audioFrame.data_,
268 sizeof(WebRtc_Word16) * (_audioFrame.samples_per_channel_
269 * _audioFrame.num_channels_));
niklase@google.com470e71d2011-07-07 08:21:25 +0000270
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000271 nSamplesOut = _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000272
273 return 0;
274}
275
276int VoEBaseImpl::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
277{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000278 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000279 "RegisterVoiceEngineObserver(observer=0x%d)", &observer);
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000280 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000281 if (_voiceEngineObserverPtr)
282 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000283 _shared->SetLastError(VE_INVALID_OPERATION, kTraceError,
284 "RegisterVoiceEngineObserver() observer already enabled");
niklase@google.com470e71d2011-07-07 08:21:25 +0000285 return -1;
286 }
287
288 // Register the observer in all active channels
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000289 voe::ScopedChannel sc(_shared->channel_manager());
niklase@google.com470e71d2011-07-07 08:21:25 +0000290 void* iterator(NULL);
291 voe::Channel* channelPtr = sc.GetFirstChannel(iterator);
292 while (channelPtr != NULL)
293 {
294 channelPtr->RegisterVoiceEngineObserver(observer);
295 channelPtr = sc.GetNextChannel(iterator);
296 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000297 _shared->transmit_mixer()->RegisterVoiceEngineObserver(observer);
niklase@google.com470e71d2011-07-07 08:21:25 +0000298
299 _voiceEngineObserverPtr = &observer;
300 _voiceEngineObserver = true;
301
302 return 0;
303}
304
305int VoEBaseImpl::DeRegisterVoiceEngineObserver()
306{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000307 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000308 "DeRegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000309 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000310 if (!_voiceEngineObserverPtr)
311 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000312 _shared->SetLastError(VE_INVALID_OPERATION, kTraceError,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000313 "DeRegisterVoiceEngineObserver() observer already disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +0000314 return 0;
315 }
316
317 _voiceEngineObserver = false;
318 _voiceEngineObserverPtr = NULL;
319
320 // Deregister the observer in all active channels
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000321 voe::ScopedChannel sc(_shared->channel_manager());
niklase@google.com470e71d2011-07-07 08:21:25 +0000322 void* iterator(NULL);
323 voe::Channel* channelPtr = sc.GetFirstChannel(iterator);
324 while (channelPtr != NULL)
325 {
326 channelPtr->DeRegisterVoiceEngineObserver();
327 channelPtr = sc.GetNextChannel(iterator);
328 }
329
330 return 0;
331}
332
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000333int VoEBaseImpl::Init(AudioDeviceModule* external_adm,
334 AudioProcessing* audioproc)
niklase@google.com470e71d2011-07-07 08:21:25 +0000335{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000336 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
henrika@google.com73d65512011-09-07 15:11:18 +0000337 "Init(external_adm=0x%p)", external_adm);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000338 CriticalSectionScoped cs(_shared->crit_sec());
niklase@google.com470e71d2011-07-07 08:21:25 +0000339
kma@webrtc.org0221b782012-09-08 00:09:26 +0000340 WebRtcSpl_Init();
341
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000342 if (_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000343 {
344 return 0;
345 }
346
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000347 if (_shared->process_thread())
niklase@google.com470e71d2011-07-07 08:21:25 +0000348 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000349 if (_shared->process_thread()->Start() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000350 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000351 _shared->SetLastError(VE_THREAD_ERROR, kTraceError,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000352 "Init() failed to start module process thread");
niklase@google.com470e71d2011-07-07 08:21:25 +0000353 return -1;
354 }
355 }
356
andrew@webrtc.org3192d652011-12-21 18:00:59 +0000357 // Create an internal ADM if the user has not added an external
henrika@google.com73d65512011-09-07 15:11:18 +0000358 // ADM implementation as input to Init().
359 if (external_adm == NULL)
niklase@google.com470e71d2011-07-07 08:21:25 +0000360 {
henrika@google.com73d65512011-09-07 15:11:18 +0000361 // Create the internal ADM implementation.
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000362 _shared->set_audio_device(AudioDeviceModuleImpl::Create(
363 VoEId(_shared->instance_id(), -1), _shared->audio_device_layer()));
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000364
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000365 if (_shared->audio_device() == NULL)
niklase@google.com470e71d2011-07-07 08:21:25 +0000366 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000367 _shared->SetLastError(VE_NO_MEMORY, kTraceCritical,
368 "Init() failed to create the ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +0000369 return -1;
370 }
371 }
henrika@google.com73d65512011-09-07 15:11:18 +0000372 else
373 {
374 // Use the already existing external ADM implementation.
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000375 _shared->set_audio_device(external_adm);
376 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
henrika@google.com73d65512011-09-07 15:11:18 +0000377 "An external ADM implementation will be used in VoiceEngine");
378 }
379
niklase@google.com470e71d2011-07-07 08:21:25 +0000380 // Register the ADM to the process thread, which will drive the error
381 // callback mechanism
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000382 if (_shared->process_thread() &&
383 _shared->process_thread()->RegisterModule(_shared->audio_device()) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000384 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000385 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
386 "Init() failed to register the ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +0000387 return -1;
388 }
389
390 bool available(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000391
392 // --------------------
393 // Reinitialize the ADM
394
395 // Register the AudioObserver implementation
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000396 if (_shared->audio_device()->RegisterEventObserver(this) != 0) {
397 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
398 "Init() failed to register event observer for the ADM");
xians@webrtc.org79af7342012-01-31 12:22:14 +0000399 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000400
401 // Register the AudioTransport implementation
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000402 if (_shared->audio_device()->RegisterAudioCallback(this) != 0) {
403 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
404 "Init() failed to register audio callback for the ADM");
xians@webrtc.org79af7342012-01-31 12:22:14 +0000405 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000406
407 // ADM initialization
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000408 if (_shared->audio_device()->Init() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000409 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000410 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
411 "Init() failed to initialize the ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +0000412 return -1;
413 }
414
415 // Initialize the default speaker
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000416 if (_shared->audio_device()->SetPlayoutDevice(
417 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000418 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000419 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000420 "Init() failed to set the default output device");
niklase@google.com470e71d2011-07-07 08:21:25 +0000421 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000422 if (_shared->audio_device()->SpeakerIsAvailable(&available) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000423 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000424 _shared->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000425 "Init() failed to check speaker availability, trying to "
426 "initialize speaker anyway");
niklase@google.com470e71d2011-07-07 08:21:25 +0000427 }
428 else if (!available)
429 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000430 _shared->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000431 "Init() speaker not available, trying to initialize speaker "
432 "anyway");
niklase@google.com470e71d2011-07-07 08:21:25 +0000433 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000434 if (_shared->audio_device()->InitSpeaker() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000435 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000436 _shared->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000437 "Init() failed to initialize the speaker");
niklase@google.com470e71d2011-07-07 08:21:25 +0000438 }
439
440 // Initialize the default microphone
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000441 if (_shared->audio_device()->SetRecordingDevice(
442 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000443 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000444 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000445 "Init() failed to set the default input device");
niklase@google.com470e71d2011-07-07 08:21:25 +0000446 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000447 if (_shared->audio_device()->MicrophoneIsAvailable(&available) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000448 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000449 _shared->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000450 "Init() failed to check microphone availability, trying to "
451 "initialize microphone anyway");
niklase@google.com470e71d2011-07-07 08:21:25 +0000452 }
453 else if (!available)
454 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000455 _shared->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000456 "Init() microphone not available, trying to initialize "
457 "microphone anyway");
niklase@google.com470e71d2011-07-07 08:21:25 +0000458 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000459 if (_shared->audio_device()->InitMicrophone() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000460 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000461 _shared->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000462 "Init() failed to initialize the microphone");
niklase@google.com470e71d2011-07-07 08:21:25 +0000463 }
464
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000465 // Set number of channels
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000466 if (_shared->audio_device()->StereoPlayoutIsAvailable(&available) != 0) {
467 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
468 "Init() failed to query stereo playout mode");
xians@webrtc.org79af7342012-01-31 12:22:14 +0000469 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000470 if (_shared->audio_device()->SetStereoPlayout(available) != 0)
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000471 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000472 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000473 "Init() failed to set mono/stereo playout mode");
474 }
andrew@webrtc.org3192d652011-12-21 18:00:59 +0000475
476 // TODO(andrew): These functions don't tell us whether stereo recording
477 // is truly available. We simply set the AudioProcessing input to stereo
478 // here, because we have to wait until receiving the first frame to
479 // determine the actual number of channels anyway.
480 //
481 // These functions may be changed; tracked here:
482 // http://code.google.com/p/webrtc/issues/detail?id=204
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000483 _shared->audio_device()->StereoRecordingIsAvailable(&available);
484 if (_shared->audio_device()->SetStereoRecording(available) != 0)
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000485 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000486 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000487 "Init() failed to set mono/stereo recording mode");
488 }
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000489
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000490 if (!audioproc) {
491 audioproc = AudioProcessing::Create(VoEId(_shared->instance_id(), -1));
492 if (!audioproc) {
493 LOG(LS_ERROR) << "Failed to create AudioProcessing.";
494 _shared->SetLastError(VE_NO_MEMORY);
495 return -1;
496 }
497 }
498 _shared->set_audio_processing(audioproc);
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000499
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000500 // Set the error state for any failures in this block.
501 _shared->SetLastError(VE_APM_ERROR);
502 if (audioproc->echo_cancellation()->set_device_sample_rate_hz(48000)) {
503 LOG_FERR1(LS_ERROR, set_device_sample_rate_hz, 48000);
504 return -1;
505 }
506 // Assume 16 kHz mono until the audio frames are received from the capture
507 // device, at which point this can be updated.
508 if (audioproc->set_sample_rate_hz(16000)) {
509 LOG_FERR1(LS_ERROR, set_sample_rate_hz, 16000);
510 return -1;
511 }
512 if (audioproc->set_num_channels(1, 1) != 0) {
513 LOG_FERR2(LS_ERROR, set_num_channels, 1, 1);
514 return -1;
515 }
516 if (audioproc->set_num_reverse_channels(1) != 0) {
517 LOG_FERR1(LS_ERROR, set_num_reverse_channels, 1);
518 return -1;
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000519 }
520
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000521 // Configure AudioProcessing components. All are disabled by default.
522 if (audioproc->high_pass_filter()->Enable(true) != 0) {
523 LOG_FERR1(LS_ERROR, high_pass_filter()->Enable, true);
524 return -1;
525 }
526 if (audioproc->echo_cancellation()->enable_drift_compensation(false) != 0) {
527 LOG_FERR1(LS_ERROR, enable_drift_compensation, false);
528 return -1;
529 }
530 if (audioproc->noise_suppression()->set_level(kDefaultNsMode) != 0) {
531 LOG_FERR1(LS_ERROR, noise_suppression()->set_level, kDefaultNsMode);
532 return -1;
533 }
534 GainControl* agc = audioproc->gain_control();
535 if (agc->set_analog_level_limits(kMinVolumeLevel, kMaxVolumeLevel) != 0) {
536 LOG_FERR2(LS_ERROR, agc->set_analog_level_limits, kMinVolumeLevel,
537 kMaxVolumeLevel);
538 return -1;
539 }
540 if (agc->set_mode(kDefaultAgcMode) != 0) {
541 LOG_FERR1(LS_ERROR, agc->set_mode, kDefaultAgcMode);
542 return -1;
543 }
544 if (agc->Enable(kDefaultAgcState) != 0) {
545 LOG_FERR1(LS_ERROR, agc->Enable, kDefaultAgcState);
546 return -1;
547 }
548 _shared->SetLastError(0); // Clear error state.
549
niklase@google.com470e71d2011-07-07 08:21:25 +0000550#ifdef WEBRTC_VOICE_ENGINE_AGC
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000551 bool agc_enabled = agc->mode() == GainControl::kAdaptiveAnalog &&
552 agc->is_enabled();
553 if (_shared->audio_device()->SetAGC(agc_enabled) != 0) {
554 LOG_FERR1(LS_ERROR, audio_device()->SetAGC, agc_enabled);
555 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR);
556 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000557 }
558#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000559
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000560 return _shared->statistics().SetInitialized();
niklase@google.com470e71d2011-07-07 08:21:25 +0000561}
562
563int VoEBaseImpl::Terminate()
564{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000565 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000566 "Terminate()");
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000567 CriticalSectionScoped cs(_shared->crit_sec());
niklase@google.com470e71d2011-07-07 08:21:25 +0000568 return TerminateInternal();
569}
570
571int VoEBaseImpl::MaxNumOfChannels()
572{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000573 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000574 "MaxNumOfChannels()");
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000575 WebRtc_Word32 maxNumOfChannels =
576 _shared->channel_manager().MaxNumOfChannels();
577 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
578 VoEId(_shared->instance_id(), -1),
579 "MaxNumOfChannels() => %d", maxNumOfChannels);
niklase@google.com470e71d2011-07-07 08:21:25 +0000580 return (maxNumOfChannels);
581}
582
583int VoEBaseImpl::CreateChannel()
584{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000585 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000586 "CreateChannel()");
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000587 CriticalSectionScoped cs(_shared->crit_sec());
niklase@google.com470e71d2011-07-07 08:21:25 +0000588
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000589 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000590 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000591 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000592 return -1;
593 }
594
595 WebRtc_Word32 channelId = -1;
596
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000597 if (!_shared->channel_manager().CreateChannel(channelId))
niklase@google.com470e71d2011-07-07 08:21:25 +0000598 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000599 _shared->SetLastError(VE_CHANNEL_NOT_CREATED, kTraceError,
600 "CreateChannel() failed to allocate memory for channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000601 return -1;
602 }
603
604 bool destroyChannel(false);
605 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000606 voe::ScopedChannel sc(_shared->channel_manager(), channelId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000607 voe::Channel* channelPtr = sc.ChannelPtr();
608 if (channelPtr == NULL)
609 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000610 _shared->SetLastError(VE_CHANNEL_NOT_CREATED, kTraceError,
611 "CreateChannel() failed to allocate memory for channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000612 return -1;
613 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000614 else if (channelPtr->SetEngineInformation(_shared->statistics(),
615 *_shared->output_mixer(),
616 *_shared->transmit_mixer(),
617 *_shared->process_thread(),
618 *_shared->audio_device(),
niklase@google.com470e71d2011-07-07 08:21:25 +0000619 _voiceEngineObserverPtr,
620 &_callbackCritSect) != 0)
621 {
622 destroyChannel = true;
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000623 _shared->SetLastError(VE_CHANNEL_NOT_CREATED, kTraceError,
624 "CreateChannel() failed to associate engine and channel."
625 " Destroying channel.");
niklase@google.com470e71d2011-07-07 08:21:25 +0000626 }
627 else if (channelPtr->Init() != 0)
628 {
629 destroyChannel = true;
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000630 _shared->SetLastError(VE_CHANNEL_NOT_CREATED, kTraceError,
631 "CreateChannel() failed to initialize channel. Destroying"
632 " channel.");
niklase@google.com470e71d2011-07-07 08:21:25 +0000633 }
634 }
635 if (destroyChannel)
636 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000637 _shared->channel_manager().DestroyChannel(channelId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000638 return -1;
639 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000640 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
641 VoEId(_shared->instance_id(), -1),
642 "CreateChannel() => %d", channelId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000643 return channelId;
644}
645
646int VoEBaseImpl::DeleteChannel(int channel)
647{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000648 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000649 "DeleteChannel(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000650 CriticalSectionScoped cs(_shared->crit_sec());
niklase@google.com470e71d2011-07-07 08:21:25 +0000651
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000652 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000653 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000654 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000655 return -1;
656 }
657
658 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000659 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000660 voe::Channel* channelPtr = sc.ChannelPtr();
661 if (channelPtr == NULL)
662 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000663 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
664 "DeleteChannel() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000665 return -1;
666 }
667 }
668
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000669 if (_shared->channel_manager().DestroyChannel(channel) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000670 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000671 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
672 "DeleteChannel() failed to destroy channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000673 return -1;
674 }
675
676 if (StopSend() != 0)
677 {
678 return -1;
679 }
680
681 if (StopPlayout() != 0)
682 {
683 return -1;
684 }
685
686 return 0;
687}
688
689int VoEBaseImpl::SetLocalReceiver(int channel, int port, int RTCPport,
690 const char ipAddr[64],
691 const char multiCastAddr[64])
692{
693 // Inititialize local receive sockets (RTP and RTCP).
694 //
695 // The sockets are always first closed and then created again by this
696 // function call. The created sockets are by default also used for
697 // transmission (unless source port is set in SetSendDestination).
698 //
699 // Note that, sockets can also be created automatically if a user calls
700 // SetSendDestination and StartSend without having called SetLocalReceiver
701 // first. The sockets are then created at the first packet transmission.
702
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000703 CriticalSectionScoped cs(_shared->crit_sec());
niklase@google.com470e71d2011-07-07 08:21:25 +0000704 if (ipAddr == NULL && multiCastAddr == NULL)
705 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000706 WEBRTC_TRACE(kTraceApiCall, kTraceVoice,
707 VoEId(_shared->instance_id(), -1),
708 "SetLocalReceiver(channel=%d, port=%d, RTCPport=%d)",
709 channel, port, RTCPport);
niklase@google.com470e71d2011-07-07 08:21:25 +0000710 }
711 else if (ipAddr != NULL && multiCastAddr == NULL)
712 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000713 WEBRTC_TRACE(kTraceApiCall, kTraceVoice,
714 VoEId(_shared->instance_id(), -1),
715 "SetLocalReceiver(channel=%d, port=%d, RTCPport=%d, ipAddr=%s)",
716 channel, port, RTCPport, ipAddr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000717 }
718 else if (ipAddr == NULL && multiCastAddr != NULL)
719 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000720 WEBRTC_TRACE(kTraceApiCall, kTraceVoice,
721 VoEId(_shared->instance_id(), -1),
722 "SetLocalReceiver(channel=%d, port=%d, RTCPport=%d, "
723 "multiCastAddr=%s)", channel, port, RTCPport, multiCastAddr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000724 }
725 else
726 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000727 WEBRTC_TRACE(kTraceApiCall, kTraceVoice,
728 VoEId(_shared->instance_id(), -1),
729 "SetLocalReceiver(channel=%d, port=%d, RTCPport=%d, "
730 "ipAddr=%s, multiCastAddr=%s)", channel, port, RTCPport, ipAddr,
731 multiCastAddr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000732 }
733#ifndef WEBRTC_EXTERNAL_TRANSPORT
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000734 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000735 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000736 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000737 return -1;
738 }
739 if ((port < 0) || (port > 65535))
740 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000741 _shared->SetLastError(VE_INVALID_PORT_NMBR, kTraceError,
742 "SetLocalReceiver() invalid RTP port");
niklase@google.com470e71d2011-07-07 08:21:25 +0000743 return -1;
744 }
745 if (((RTCPport != kVoEDefault) && (RTCPport < 0)) || ((RTCPport
746 != kVoEDefault) && (RTCPport > 65535)))
747 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000748 _shared->SetLastError(VE_INVALID_PORT_NMBR, kTraceError,
749 "SetLocalReceiver() invalid RTCP port");
niklase@google.com470e71d2011-07-07 08:21:25 +0000750 return -1;
751 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000752 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000753 voe::Channel* channelPtr = sc.ChannelPtr();
754 if (channelPtr == NULL)
755 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000756 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
757 "SetLocalReceiver() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000758 return -1;
759 }
760
761 // Cast RTCP port. In the RTP module 0 corresponds to RTP port + 1 in
762 // the module, which is the default.
763 WebRtc_UWord16 rtcpPortUW16(0);
764 if (RTCPport != kVoEDefault)
765 {
766 rtcpPortUW16 = static_cast<WebRtc_UWord16> (RTCPport);
767 }
768
769 return channelPtr->SetLocalReceiver(port, rtcpPortUW16, ipAddr,
770 multiCastAddr);
771#else
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000772 _shared->SetLastError(VE_EXTERNAL_TRANSPORT_ENABLED,
773 kTraceWarning, "SetLocalReceiver() VoE is built for external "
774 "transport");
niklase@google.com470e71d2011-07-07 08:21:25 +0000775 return -1;
776#endif
777}
778
779int VoEBaseImpl::GetLocalReceiver(int channel, int& port, int& RTCPport,
780 char ipAddr[64])
781{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000782 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000783 "GetLocalReceiver(channel=%d, ipAddr[]=?)", channel);
784#ifndef WEBRTC_EXTERNAL_TRANSPORT
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000785 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000786 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000787 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000788 return -1;
789 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000790 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000791 voe::Channel* channelPtr = sc.ChannelPtr();
792 if (channelPtr == NULL)
793 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000794 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
795 "SetLocalReceiver() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000796 return -1;
797 }
798 WebRtc_Word32 ret = channelPtr->GetLocalReceiver(port, RTCPport, ipAddr);
799 if (ipAddr != NULL)
800 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000801 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
802 VoEId(_shared->instance_id(), -1),
803 "GetLocalReceiver() => port=%d, RTCPport=%d, ipAddr=%s",
804 port, RTCPport, ipAddr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000805 }
806 else
807 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000808 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
809 VoEId(_shared->instance_id(), -1),
810 "GetLocalReceiver() => port=%d, RTCPport=%d", port, RTCPport);
niklase@google.com470e71d2011-07-07 08:21:25 +0000811 }
812 return ret;
813#else
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000814 _shared->SetLastError(VE_EXTERNAL_TRANSPORT_ENABLED, kTraceWarning,
815 "SetLocalReceiver() VoE is built for external transport");
niklase@google.com470e71d2011-07-07 08:21:25 +0000816 return -1;
817#endif
818}
819
820int VoEBaseImpl::SetSendDestination(int channel, int port, const char* ipaddr,
821 int sourcePort, int RTCPport)
822{
823 WEBRTC_TRACE(
824 kTraceApiCall,
825 kTraceVoice,
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000826 VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000827 "SetSendDestination(channel=%d, port=%d, ipaddr=%s,"
828 "sourcePort=%d, RTCPport=%d)",
829 channel, port, ipaddr, sourcePort, RTCPport);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000830 CriticalSectionScoped cs(_shared->crit_sec());
niklase@google.com470e71d2011-07-07 08:21:25 +0000831#ifndef WEBRTC_EXTERNAL_TRANSPORT
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000832 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000833 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000834 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000835 return -1;
836 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000837 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000838 voe::Channel* channelPtr = sc.ChannelPtr();
839 if (channelPtr == NULL)
840 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000841 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
842 "SetSendDestination() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000843 return -1;
844 }
845 if ((port < 0) || (port > 65535))
846 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000847 _shared->SetLastError(VE_INVALID_PORT_NMBR, kTraceError,
848 "SetSendDestination() invalid RTP port");
niklase@google.com470e71d2011-07-07 08:21:25 +0000849 return -1;
850 }
851 if (((RTCPport != kVoEDefault) && (RTCPport < 0)) || ((RTCPport
852 != kVoEDefault) && (RTCPport > 65535)))
853 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000854 _shared->SetLastError(VE_INVALID_PORT_NMBR, kTraceError,
855 "SetSendDestination() invalid RTCP port");
niklase@google.com470e71d2011-07-07 08:21:25 +0000856 return -1;
857 }
858 if (((sourcePort != kVoEDefault) && (sourcePort < 0)) || ((sourcePort
859 != kVoEDefault) && (sourcePort > 65535)))
860 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000861 _shared->SetLastError(VE_INVALID_PORT_NMBR, kTraceError,
862 "SetSendDestination() invalid source port");
niklase@google.com470e71d2011-07-07 08:21:25 +0000863 return -1;
864 }
865
866 // Cast RTCP port. In the RTP module 0 corresponds to RTP port + 1 in the
867 // module, which is the default.
868 WebRtc_UWord16 rtcpPortUW16(0);
869 if (RTCPport != kVoEDefault)
870 {
871 rtcpPortUW16 = static_cast<WebRtc_UWord16> (RTCPport);
872 WEBRTC_TRACE(
873 kTraceInfo,
874 kTraceVoice,
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000875 VoEId(_shared->instance_id(), channel),
niklase@google.com470e71d2011-07-07 08:21:25 +0000876 "SetSendDestination() non default RTCP port %u will be "
877 "utilized",
878 rtcpPortUW16);
879 }
880
881 return channelPtr->SetSendDestination(port, ipaddr, sourcePort,
882 rtcpPortUW16);
883#else
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000884 _shared->SetLastError(VE_EXTERNAL_TRANSPORT_ENABLED, kTraceWarning,
885 "SetSendDestination() VoE is built for external transport");
niklase@google.com470e71d2011-07-07 08:21:25 +0000886 return -1;
887#endif
888}
889
890int VoEBaseImpl::GetSendDestination(int channel, int& port, char ipAddr[64],
891 int& sourcePort, int& RTCPport)
892{
893 WEBRTC_TRACE(
894 kTraceApiCall,
895 kTraceVoice,
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000896 VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000897 "GetSendDestination(channel=%d, ipAddr[]=?, sourcePort=?,"
898 "RTCPport=?)",
899 channel);
900#ifndef WEBRTC_EXTERNAL_TRANSPORT
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000901 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000902 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000903 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000904 return -1;
905 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000906 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000907 voe::Channel* channelPtr = sc.ChannelPtr();
908 if (channelPtr == NULL)
909 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000910 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
911 "GetSendDestination() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000912 return -1;
913 }
914 WebRtc_Word32 ret = channelPtr->GetSendDestination(port, ipAddr,
915 sourcePort, RTCPport);
916 if (ipAddr != NULL)
917 {
918 WEBRTC_TRACE(
919 kTraceStateInfo,
920 kTraceVoice,
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000921 VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000922 "GetSendDestination() => port=%d, RTCPport=%d, ipAddr=%s, "
923 "sourcePort=%d, RTCPport=%d",
924 port, RTCPport, ipAddr, sourcePort, RTCPport);
925 }
926 else
927 {
928 WEBRTC_TRACE(
929 kTraceStateInfo,
930 kTraceVoice,
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000931 VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000932 "GetSendDestination() => port=%d, RTCPport=%d, "
933 "sourcePort=%d, RTCPport=%d",
934 port, RTCPport, sourcePort, RTCPport);
935 }
936 return ret;
937#else
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000938 _shared->SetLastError(VE_EXTERNAL_TRANSPORT_ENABLED, kTraceWarning,
939 "GetSendDestination() VoE is built for external transport");
niklase@google.com470e71d2011-07-07 08:21:25 +0000940 return -1;
941#endif
942}
943
944int VoEBaseImpl::StartReceive(int channel)
945{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000946 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000947 "StartReceive(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000948 CriticalSectionScoped cs(_shared->crit_sec());
949 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000950 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000951 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000952 return -1;
953 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000954 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000955 voe::Channel* channelPtr = sc.ChannelPtr();
956 if (channelPtr == NULL)
957 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000958 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
959 "StartReceive() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000960 return -1;
961 }
962 return channelPtr->StartReceiving();
963}
964
965int VoEBaseImpl::StopReceive(int channel)
966{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000967 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000968 "StopListen(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000969 CriticalSectionScoped cs(_shared->crit_sec());
970 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000971 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000972 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000973 return -1;
974 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000975 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000976 voe::Channel* channelPtr = sc.ChannelPtr();
977 if (channelPtr == NULL)
978 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000979 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
980 "SetLocalReceiver() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000981 return -1;
982 }
983 return channelPtr->StopReceiving();
984}
985
986int VoEBaseImpl::StartPlayout(int channel)
987{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000988 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000989 "StartPlayout(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000990 CriticalSectionScoped cs(_shared->crit_sec());
991 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000992 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000993 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000994 return -1;
995 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000996 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000997 voe::Channel* channelPtr = sc.ChannelPtr();
998 if (channelPtr == NULL)
999 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001000 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
1001 "StartPlayout() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +00001002 return -1;
1003 }
1004 if (channelPtr->Playing())
1005 {
1006 return 0;
1007 }
1008 if (StartPlayout() != 0)
1009 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001010 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
1011 "StartPlayout() failed to start playout");
niklase@google.com470e71d2011-07-07 08:21:25 +00001012 return -1;
1013 }
1014 return channelPtr->StartPlayout();
1015}
1016
1017int VoEBaseImpl::StopPlayout(int channel)
1018{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001019 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001020 "StopPlayout(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001021 CriticalSectionScoped cs(_shared->crit_sec());
1022 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +00001023 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001024 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +00001025 return -1;
1026 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001027 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +00001028 voe::Channel* channelPtr = sc.ChannelPtr();
1029 if (channelPtr == NULL)
1030 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001031 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
1032 "StopPlayout() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +00001033 return -1;
1034 }
1035 if (channelPtr->StopPlayout() != 0)
1036 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001037 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1038 VoEId(_shared->instance_id(), -1),
1039 "StopPlayout() failed to stop playout for channel %d", channel);
niklase@google.com470e71d2011-07-07 08:21:25 +00001040 }
1041 return StopPlayout();
1042}
1043
1044int VoEBaseImpl::StartSend(int channel)
1045{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001046 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001047 "StartSend(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001048 CriticalSectionScoped cs(_shared->crit_sec());
1049 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +00001050 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001051 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +00001052 return -1;
1053 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001054 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +00001055 voe::Channel* channelPtr = sc.ChannelPtr();
1056 if (channelPtr == NULL)
1057 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001058 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
1059 "StartSend() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +00001060 return -1;
1061 }
1062 if (channelPtr->Sending())
1063 {
1064 return 0;
1065 }
1066#ifndef WEBRTC_EXTERNAL_TRANSPORT
1067 if (!channelPtr->ExternalTransport()
1068 && !channelPtr->SendSocketsInitialized())
1069 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001070 _shared->SetLastError(VE_DESTINATION_NOT_INITED, kTraceError,
1071 "StartSend() must set send destination first");
niklase@google.com470e71d2011-07-07 08:21:25 +00001072 return -1;
1073 }
1074#endif
1075 if (StartSend() != 0)
1076 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001077 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
1078 "StartSend() failed to start recording");
niklase@google.com470e71d2011-07-07 08:21:25 +00001079 return -1;
1080 }
1081 return channelPtr->StartSend();
1082}
1083
1084int VoEBaseImpl::StopSend(int channel)
1085{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001086 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001087 "StopSend(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001088 CriticalSectionScoped cs(_shared->crit_sec());
1089 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +00001090 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001091 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +00001092 return -1;
1093 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001094 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +00001095 voe::Channel* channelPtr = sc.ChannelPtr();
1096 if (channelPtr == NULL)
1097 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001098 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
1099 "StopSend() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +00001100 return -1;
1101 }
1102 if (channelPtr->StopSend() != 0)
1103 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001104 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1105 VoEId(_shared->instance_id(), -1),
1106 "StopSend() failed to stop sending for channel %d", channel);
niklase@google.com470e71d2011-07-07 08:21:25 +00001107 }
1108 return StopSend();
1109}
1110
1111int VoEBaseImpl::GetVersion(char version[1024])
1112{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001113 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001114 "GetVersion(version=?)");
1115 assert(kVoiceEngineVersionMaxMessageSize == 1024);
1116
1117 if (version == NULL)
1118 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001119 _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +00001120 return (-1);
1121 }
1122
1123 char versionBuf[kVoiceEngineVersionMaxMessageSize];
1124 char* versionPtr = versionBuf;
1125
1126 WebRtc_Word32 len = 0;
1127 WebRtc_Word32 accLen = 0;
1128
1129 len = AddVoEVersion(versionPtr);
1130 if (len == -1)
1131 {
1132 return -1;
1133 }
1134 versionPtr += len;
1135 accLen += len;
1136 assert(accLen < kVoiceEngineVersionMaxMessageSize);
1137
1138 len = AddBuildInfo(versionPtr);
1139 if (len == -1)
1140 {
1141 return -1;
1142 }
1143 versionPtr += len;
1144 accLen += len;
1145 assert(accLen < kVoiceEngineVersionMaxMessageSize);
1146
1147#ifdef WEBRTC_EXTERNAL_TRANSPORT
1148 len = AddExternalTransportBuild(versionPtr);
1149 if (len == -1)
1150 {
pwestin@webrtc.orgc450a192012-01-04 15:00:12 +00001151 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001152 }
1153 versionPtr += len;
1154 accLen += len;
1155 assert(accLen < kVoiceEngineVersionMaxMessageSize);
1156#endif
niklase@google.com470e71d2011-07-07 08:21:25 +00001157#ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT
1158 len = AddExternalRecAndPlayoutBuild(versionPtr);
1159 if (len == -1)
1160 {
1161 return -1;
1162 }
1163 versionPtr += len;
1164 accLen += len;
1165 assert(accLen < kVoiceEngineVersionMaxMessageSize);
pwestin@webrtc.orgc450a192012-01-04 15:00:12 +00001166 #endif
niklase@google.com470e71d2011-07-07 08:21:25 +00001167
1168 memcpy(version, versionBuf, accLen);
1169 version[accLen] = '\0';
1170
1171 // to avoid the truncation in the trace, split the string into parts
1172 char partOfVersion[256];
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001173 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
1174 VoEId(_shared->instance_id(), -1), "GetVersion() =>");
niklase@google.com470e71d2011-07-07 08:21:25 +00001175 for (int partStart = 0; partStart < accLen;)
1176 {
1177 memset(partOfVersion, 0, sizeof(partOfVersion));
1178 int partEnd = partStart + 180;
1179 while (version[partEnd] != '\n' && version[partEnd] != '\0')
1180 {
1181 partEnd--;
1182 }
1183 if (partEnd < accLen)
1184 {
1185 memcpy(partOfVersion, &version[partStart], partEnd - partStart);
1186 }
1187 else
1188 {
1189 memcpy(partOfVersion, &version[partStart], accLen - partStart);
1190 }
1191 partStart = partEnd;
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001192 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
1193 VoEId(_shared->instance_id(), -1), "%s", partOfVersion);
niklase@google.com470e71d2011-07-07 08:21:25 +00001194 }
1195
1196 return 0;
1197}
1198
1199WebRtc_Word32 VoEBaseImpl::AddBuildInfo(char* str) const
1200{
leozwang@webrtc.org48a5df62012-04-24 14:50:50 +00001201 return sprintf(str, "Build: svn:%s %s\n", WEBRTC_SVNREVISION, BUILDINFO);
niklase@google.com470e71d2011-07-07 08:21:25 +00001202}
1203
1204WebRtc_Word32 VoEBaseImpl::AddVoEVersion(char* str) const
1205{
1206 return sprintf(str, "VoiceEngine 4.1.0\n");
1207}
1208
niklase@google.com470e71d2011-07-07 08:21:25 +00001209#ifdef WEBRTC_EXTERNAL_TRANSPORT
1210WebRtc_Word32 VoEBaseImpl::AddExternalTransportBuild(char* str) const
1211{
1212 return sprintf(str, "External transport build\n");
1213}
1214#endif
1215
1216#ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT
1217WebRtc_Word32 VoEBaseImpl::AddExternalRecAndPlayoutBuild(char* str) const
1218{
1219 return sprintf(str, "External recording and playout build\n");
1220}
1221#endif
1222
niklase@google.com470e71d2011-07-07 08:21:25 +00001223int VoEBaseImpl::LastError()
1224{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001225 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001226 "LastError()");
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001227 return (_shared->statistics().LastError());
niklase@google.com470e71d2011-07-07 08:21:25 +00001228}
1229
1230
1231int VoEBaseImpl::SetNetEQPlayoutMode(int channel, NetEqModes mode)
1232{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001233 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001234 "SetNetEQPlayoutMode(channel=%i, mode=%i)", channel, mode);
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001235 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +00001236 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001237 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +00001238 return -1;
1239 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001240 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +00001241 voe::Channel* channelPtr = sc.ChannelPtr();
1242 if (channelPtr == NULL)
1243 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001244 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
1245 "SetNetEQPlayoutMode() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +00001246 return -1;
1247 }
1248 return channelPtr->SetNetEQPlayoutMode(mode);
1249}
1250
1251int VoEBaseImpl::GetNetEQPlayoutMode(int channel, NetEqModes& mode)
1252{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001253 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001254 "GetNetEQPlayoutMode(channel=%i, mode=?)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001255 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +00001256 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001257 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +00001258 return -1;
1259 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001260 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +00001261 voe::Channel* channelPtr = sc.ChannelPtr();
1262 if (channelPtr == NULL)
1263 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001264 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
1265 "GetNetEQPlayoutMode() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +00001266 return -1;
1267 }
1268 return channelPtr->GetNetEQPlayoutMode(mode);
1269}
1270
1271int VoEBaseImpl::SetNetEQBGNMode(int channel, NetEqBgnModes mode)
1272{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001273 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001274 "SetNetEQBGNMode(channel=%i, mode=%i)", channel, mode);
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001275 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +00001276 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001277 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +00001278 return -1;
1279 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001280 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +00001281 voe::Channel* channelPtr = sc.ChannelPtr();
1282 if (channelPtr == NULL)
1283 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001284 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
1285 "SetNetEQBGNMode() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +00001286 return -1;
1287 }
1288 return channelPtr->SetNetEQBGNMode(mode);
1289}
1290
1291int VoEBaseImpl::GetNetEQBGNMode(int channel, NetEqBgnModes& mode)
1292{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001293 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001294 "GetNetEQBGNMode(channel=%i, mode=?)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001295 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +00001296 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001297 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +00001298 return -1;
1299 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001300 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +00001301 voe::Channel* channelPtr = sc.ChannelPtr();
1302 if (channelPtr == NULL)
1303 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001304 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
1305 "GetNetEQBGNMode() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +00001306 return -1;
1307 }
1308 return channelPtr->GetNetEQBGNMode(mode);
1309}
1310
1311int VoEBaseImpl::SetOnHoldStatus(int channel, bool enable, OnHoldModes mode)
1312{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001313 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001314 "SetOnHoldStatus(channel=%d, enable=%d, mode=%d)", channel,
1315 enable, mode);
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001316 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +00001317 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001318 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +00001319 return -1;
1320 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001321 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +00001322 voe::Channel* channelPtr = sc.ChannelPtr();
1323 if (channelPtr == NULL)
1324 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001325 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
1326 "SetOnHoldStatus() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +00001327 return -1;
1328 }
1329 return channelPtr->SetOnHoldStatus(enable, mode);
1330}
1331
1332int VoEBaseImpl::GetOnHoldStatus(int channel, bool& enabled, OnHoldModes& mode)
1333{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001334 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001335 "GetOnHoldStatus(channel=%d, enabled=?, mode=?)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001336 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +00001337 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001338 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +00001339 return -1;
1340 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001341 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +00001342 voe::Channel* channelPtr = sc.ChannelPtr();
1343 if (channelPtr == NULL)
1344 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001345 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
1346 "GetOnHoldStatus() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +00001347 return -1;
1348 }
1349 return channelPtr->GetOnHoldStatus(enabled, mode);
1350}
1351
1352WebRtc_Word32 VoEBaseImpl::StartPlayout()
1353{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001354 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001355 "VoEBaseImpl::StartPlayout()");
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001356 if (_shared->audio_device()->Playing())
niklase@google.com470e71d2011-07-07 08:21:25 +00001357 {
1358 return 0;
1359 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001360 if (!_shared->ext_playout())
niklase@google.com470e71d2011-07-07 08:21:25 +00001361 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001362 if (_shared->audio_device()->InitPlayout() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001363 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001364 WEBRTC_TRACE(kTraceError, kTraceVoice,
1365 VoEId(_shared->instance_id(), -1),
1366 "StartPlayout() failed to initialize playout");
niklase@google.com470e71d2011-07-07 08:21:25 +00001367 return -1;
1368 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001369 if (_shared->audio_device()->StartPlayout() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001370 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001371 WEBRTC_TRACE(kTraceError, kTraceVoice,
1372 VoEId(_shared->instance_id(), -1),
1373 "StartPlayout() failed to start playout");
niklase@google.com470e71d2011-07-07 08:21:25 +00001374 return -1;
1375 }
1376 }
1377 return 0;
1378}
1379
1380WebRtc_Word32 VoEBaseImpl::StopPlayout()
1381{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001382 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001383 "VoEBaseImpl::StopPlayout()");
1384
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001385 WebRtc_Word32 numOfChannels = _shared->channel_manager().NumOfChannels();
niklase@google.com470e71d2011-07-07 08:21:25 +00001386 if (numOfChannels <= 0)
1387 {
1388 return 0;
1389 }
1390
1391 WebRtc_UWord16 nChannelsPlaying(0);
1392 WebRtc_Word32* channelsArray = new WebRtc_Word32[numOfChannels];
1393
1394 // Get number of playing channels
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001395 _shared->channel_manager().GetChannelIds(channelsArray, numOfChannels);
niklase@google.com470e71d2011-07-07 08:21:25 +00001396 for (int i = 0; i < numOfChannels; i++)
1397 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001398 voe::ScopedChannel sc(_shared->channel_manager(), channelsArray[i]);
niklase@google.com470e71d2011-07-07 08:21:25 +00001399 voe::Channel* chPtr = sc.ChannelPtr();
1400 if (chPtr)
1401 {
1402 if (chPtr->Playing())
1403 {
1404 nChannelsPlaying++;
1405 }
1406 }
1407 }
1408 delete[] channelsArray;
1409
1410 // Stop audio-device playing if no channel is playing out
1411 if (nChannelsPlaying == 0)
1412 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001413 if (_shared->audio_device()->StopPlayout() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001414 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001415 _shared->SetLastError(VE_CANNOT_STOP_PLAYOUT, kTraceError,
1416 "StopPlayout() failed to stop playout");
niklase@google.com470e71d2011-07-07 08:21:25 +00001417 return -1;
1418 }
1419 }
1420 return 0;
1421}
1422
1423WebRtc_Word32 VoEBaseImpl::StartSend()
1424{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001425 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001426 "VoEBaseImpl::StartSend()");
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001427 if (_shared->audio_device()->Recording())
niklase@google.com470e71d2011-07-07 08:21:25 +00001428 {
1429 return 0;
1430 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001431 if (!_shared->ext_recording())
niklase@google.com470e71d2011-07-07 08:21:25 +00001432 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001433 if (_shared->audio_device()->InitRecording() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001434 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001435 WEBRTC_TRACE(kTraceError, kTraceVoice,
1436 VoEId(_shared->instance_id(), -1),
1437 "StartSend() failed to initialize recording");
niklase@google.com470e71d2011-07-07 08:21:25 +00001438 return -1;
1439 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001440 if (_shared->audio_device()->StartRecording() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001441 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001442 WEBRTC_TRACE(kTraceError, kTraceVoice,
1443 VoEId(_shared->instance_id(), -1),
1444 "StartSend() failed to start recording");
niklase@google.com470e71d2011-07-07 08:21:25 +00001445 return -1;
1446 }
1447 }
1448
1449 return 0;
1450}
1451
1452WebRtc_Word32 VoEBaseImpl::StopSend()
1453{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001454 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001455 "VoEBaseImpl::StopSend()");
1456
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001457 if (_shared->NumOfSendingChannels() == 0 &&
1458 !_shared->transmit_mixer()->IsRecordingMic())
niklase@google.com470e71d2011-07-07 08:21:25 +00001459 {
1460 // Stop audio-device recording if no channel is recording
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001461 if (_shared->audio_device()->StopRecording() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001462 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001463 _shared->SetLastError(VE_CANNOT_STOP_RECORDING, kTraceError,
1464 "StopSend() failed to stop recording");
niklase@google.com470e71d2011-07-07 08:21:25 +00001465 return -1;
1466 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001467 _shared->transmit_mixer()->StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +00001468 }
1469
1470 return 0;
1471}
1472
1473WebRtc_Word32 VoEBaseImpl::TerminateInternal()
1474{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001475 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001476 "VoEBaseImpl::TerminateInternal()");
1477
1478 // Delete any remaining channel objects
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001479 WebRtc_Word32 numOfChannels = _shared->channel_manager().NumOfChannels();
niklase@google.com470e71d2011-07-07 08:21:25 +00001480 if (numOfChannels > 0)
1481 {
1482 WebRtc_Word32* channelsArray = new WebRtc_Word32[numOfChannels];
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001483 _shared->channel_manager().GetChannelIds(channelsArray, numOfChannels);
niklase@google.com470e71d2011-07-07 08:21:25 +00001484 for (int i = 0; i < numOfChannels; i++)
1485 {
1486 DeleteChannel(channelsArray[i]);
1487 }
1488 delete[] channelsArray;
1489 }
1490
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001491 if (_shared->process_thread())
niklase@google.com470e71d2011-07-07 08:21:25 +00001492 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001493 if (_shared->audio_device())
niklase@google.com470e71d2011-07-07 08:21:25 +00001494 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001495 if (_shared->process_thread()->
1496 DeRegisterModule(_shared->audio_device()) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001497 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001498 _shared->SetLastError(VE_THREAD_ERROR, kTraceError,
1499 "TerminateInternal() failed to deregister ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +00001500 }
1501 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001502 if (_shared->process_thread()->Stop() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001503 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001504 _shared->SetLastError(VE_THREAD_ERROR, kTraceError,
1505 "TerminateInternal() failed to stop module process thread");
niklase@google.com470e71d2011-07-07 08:21:25 +00001506 }
1507 }
1508
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +00001509 if (_shared->audio_device())
niklase@google.com470e71d2011-07-07 08:21:25 +00001510 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001511 if (_shared->audio_device()->StopPlayout() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001512 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001513 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
1514 "TerminateInternal() failed to stop playout");
niklase@google.com470e71d2011-07-07 08:21:25 +00001515 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001516 if (_shared->audio_device()->StopRecording() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001517 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001518 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
1519 "TerminateInternal() failed to stop recording");
niklase@google.com470e71d2011-07-07 08:21:25 +00001520 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001521 if (_shared->audio_device()->RegisterEventObserver(NULL) != 0) {
1522 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
1523 "TerminateInternal() failed to de-register event observer "
1524 "for the ADM");
xians@webrtc.org79af7342012-01-31 12:22:14 +00001525 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001526 if (_shared->audio_device()->RegisterAudioCallback(NULL) != 0) {
1527 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
1528 "TerminateInternal() failed to de-register audio callback "
1529 "for the ADM");
xians@webrtc.org79af7342012-01-31 12:22:14 +00001530 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001531 if (_shared->audio_device()->Terminate() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001532 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001533 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
1534 "TerminateInternal() failed to terminate the ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +00001535 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001536 _shared->set_audio_device(NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +00001537 }
1538
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +00001539 if (_shared->audio_processing()) {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001540 _shared->set_audio_processing(NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +00001541 }
1542
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001543 return _shared->statistics().SetUnInitialized();
niklase@google.com470e71d2011-07-07 08:21:25 +00001544}
1545
1546} // namespace webrtc