blob: b63564639e0676e5b5a9a0f47cf7c73fe3636026 [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.orga990e122012-04-26 15:28:22 +000043 VoiceEngineImpl* s = reinterpret_cast<VoiceEngineImpl*>(voiceEngine);
44 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
henrika@google.com73d65512011-09-07 15:11:18 +0000333int VoEBaseImpl::Init(AudioDeviceModule* external_adm)
niklase@google.com470e71d2011-07-07 08:21:25 +0000334{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000335 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
henrika@google.com73d65512011-09-07 15:11:18 +0000336 "Init(external_adm=0x%p)", external_adm);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000337 CriticalSectionScoped cs(_shared->crit_sec());
niklase@google.com470e71d2011-07-07 08:21:25 +0000338
kma@webrtc.org0221b782012-09-08 00:09:26 +0000339 WebRtcSpl_Init();
340
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000341 if (_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000342 {
343 return 0;
344 }
345
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000346 if (_shared->process_thread())
niklase@google.com470e71d2011-07-07 08:21:25 +0000347 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000348 if (_shared->process_thread()->Start() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000349 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000350 _shared->SetLastError(VE_THREAD_ERROR, kTraceError,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000351 "Init() failed to start module process thread");
niklase@google.com470e71d2011-07-07 08:21:25 +0000352 return -1;
353 }
354 }
355
andrew@webrtc.org3192d652011-12-21 18:00:59 +0000356 // Create an internal ADM if the user has not added an external
henrika@google.com73d65512011-09-07 15:11:18 +0000357 // ADM implementation as input to Init().
358 if (external_adm == NULL)
niklase@google.com470e71d2011-07-07 08:21:25 +0000359 {
henrika@google.com73d65512011-09-07 15:11:18 +0000360 // Create the internal ADM implementation.
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000361 _shared->set_audio_device(AudioDeviceModuleImpl::Create(
362 VoEId(_shared->instance_id(), -1), _shared->audio_device_layer()));
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000363
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000364 if (_shared->audio_device() == NULL)
niklase@google.com470e71d2011-07-07 08:21:25 +0000365 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000366 _shared->SetLastError(VE_NO_MEMORY, kTraceCritical,
367 "Init() failed to create the ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +0000368 return -1;
369 }
370 }
henrika@google.com73d65512011-09-07 15:11:18 +0000371 else
372 {
373 // Use the already existing external ADM implementation.
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000374 _shared->set_audio_device(external_adm);
375 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
henrika@google.com73d65512011-09-07 15:11:18 +0000376 "An external ADM implementation will be used in VoiceEngine");
377 }
378
niklase@google.com470e71d2011-07-07 08:21:25 +0000379 // Register the ADM to the process thread, which will drive the error
380 // callback mechanism
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000381 if (_shared->process_thread() &&
382 _shared->process_thread()->RegisterModule(_shared->audio_device()) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000383 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000384 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
385 "Init() failed to register the ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +0000386 return -1;
387 }
388
389 bool available(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000390
391 // --------------------
392 // Reinitialize the ADM
393
394 // Register the AudioObserver implementation
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000395 if (_shared->audio_device()->RegisterEventObserver(this) != 0) {
396 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
397 "Init() failed to register event observer for the ADM");
xians@webrtc.org79af7342012-01-31 12:22:14 +0000398 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000399
400 // Register the AudioTransport implementation
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000401 if (_shared->audio_device()->RegisterAudioCallback(this) != 0) {
402 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
403 "Init() failed to register audio callback for the ADM");
xians@webrtc.org79af7342012-01-31 12:22:14 +0000404 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000405
406 // ADM initialization
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000407 if (_shared->audio_device()->Init() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000408 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000409 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
410 "Init() failed to initialize the ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +0000411 return -1;
412 }
413
414 // Initialize the default speaker
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000415 if (_shared->audio_device()->SetPlayoutDevice(
416 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000417 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000418 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000419 "Init() failed to set the default output device");
niklase@google.com470e71d2011-07-07 08:21:25 +0000420 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000421 if (_shared->audio_device()->SpeakerIsAvailable(&available) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000422 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000423 _shared->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000424 "Init() failed to check speaker availability, trying to "
425 "initialize speaker anyway");
niklase@google.com470e71d2011-07-07 08:21:25 +0000426 }
427 else if (!available)
428 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000429 _shared->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000430 "Init() speaker not available, trying to initialize speaker "
431 "anyway");
niklase@google.com470e71d2011-07-07 08:21:25 +0000432 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000433 if (_shared->audio_device()->InitSpeaker() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000434 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000435 _shared->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000436 "Init() failed to initialize the speaker");
niklase@google.com470e71d2011-07-07 08:21:25 +0000437 }
438
439 // Initialize the default microphone
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000440 if (_shared->audio_device()->SetRecordingDevice(
441 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000442 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000443 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000444 "Init() failed to set the default input device");
niklase@google.com470e71d2011-07-07 08:21:25 +0000445 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000446 if (_shared->audio_device()->MicrophoneIsAvailable(&available) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000447 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000448 _shared->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000449 "Init() failed to check microphone availability, trying to "
450 "initialize microphone anyway");
niklase@google.com470e71d2011-07-07 08:21:25 +0000451 }
452 else if (!available)
453 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000454 _shared->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000455 "Init() microphone not available, trying to initialize "
456 "microphone anyway");
niklase@google.com470e71d2011-07-07 08:21:25 +0000457 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000458 if (_shared->audio_device()->InitMicrophone() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000459 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000460 _shared->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000461 "Init() failed to initialize the microphone");
niklase@google.com470e71d2011-07-07 08:21:25 +0000462 }
463
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000464 // Set number of channels
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000465 if (_shared->audio_device()->StereoPlayoutIsAvailable(&available) != 0) {
466 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
467 "Init() failed to query stereo playout mode");
xians@webrtc.org79af7342012-01-31 12:22:14 +0000468 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000469 if (_shared->audio_device()->SetStereoPlayout(available) != 0)
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000470 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000471 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000472 "Init() failed to set mono/stereo playout mode");
473 }
andrew@webrtc.org3192d652011-12-21 18:00:59 +0000474
475 // TODO(andrew): These functions don't tell us whether stereo recording
476 // is truly available. We simply set the AudioProcessing input to stereo
477 // here, because we have to wait until receiving the first frame to
478 // determine the actual number of channels anyway.
479 //
480 // These functions may be changed; tracked here:
481 // http://code.google.com/p/webrtc/issues/detail?id=204
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000482 _shared->audio_device()->StereoRecordingIsAvailable(&available);
483 if (_shared->audio_device()->SetStereoRecording(available) != 0)
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000484 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000485 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000486 "Init() failed to set mono/stereo recording mode");
487 }
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000488
489 // APM initialization done after sound card since we need
490 // to know if we support stereo recording or not.
491
492 // Create the AudioProcessing Module if it does not exist.
493
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000494 if (_shared->audio_processing() == NULL)
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000495 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000496 _shared->set_audio_processing(AudioProcessing::Create(
497 VoEId(_shared->instance_id(), -1)));
498 if (_shared->audio_processing() == NULL)
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000499 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000500 _shared->SetLastError(VE_NO_MEMORY, kTraceCritical,
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000501 "Init() failed to create the AP module");
502 return -1;
503 }
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000504 // Ensure that mixers in both directions has access to the created APM
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000505 _shared->transmit_mixer()->SetAudioProcessingModule(
506 _shared->audio_processing());
507 _shared->output_mixer()->SetAudioProcessingModule(
508 _shared->audio_processing());
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000509
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000510 if (_shared->audio_processing()->echo_cancellation()->
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000511 set_device_sample_rate_hz(
512 kVoiceEngineAudioProcessingDeviceSampleRateHz))
513 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000514 _shared->SetLastError(VE_APM_ERROR, kTraceError,
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000515 "Init() failed to set the device sample rate to 48K for AP "
516 " module");
517 return -1;
518 }
519 // Using 8 kHz as inital Fs. Might be changed already at first call.
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000520 if (_shared->audio_processing()->set_sample_rate_hz(8000))
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000521 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000522 _shared->SetLastError(VE_APM_ERROR, kTraceError,
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000523 "Init() failed to set the sample rate to 8K for AP module");
524 return -1;
525 }
526
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +0000527 // Assume mono until the audio frames are received from the capture
528 // device, at which point this can be updated.
529 if (_shared->audio_processing()->set_num_channels(1, 1) != 0)
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000530 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000531 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceError,
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000532 "Init() failed to set channels for the primary audio stream");
533 return -1;
534 }
535
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000536 if (_shared->audio_processing()->set_num_reverse_channels(1) != 0)
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000537 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000538 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceError,
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000539 "Init() failed to set channels for the primary audio stream");
540 return -1;
541 }
542 // high-pass filter
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000543 if (_shared->audio_processing()->high_pass_filter()->Enable(
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000544 WEBRTC_VOICE_ENGINE_HP_DEFAULT_STATE) != 0)
545 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000546 _shared->SetLastError(VE_APM_ERROR, kTraceError,
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000547 "Init() failed to set the high-pass filter for AP module");
548 return -1;
549 }
550 // Echo Cancellation
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000551 if (_shared->audio_processing()->echo_cancellation()->
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000552 enable_drift_compensation(false) != 0)
553 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000554 _shared->SetLastError(VE_APM_ERROR, kTraceError,
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000555 "Init() failed to set drift compensation for AP module");
556 return -1;
557 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000558 if (_shared->audio_processing()->echo_cancellation()->Enable(
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000559 WEBRTC_VOICE_ENGINE_EC_DEFAULT_STATE))
560 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000561 _shared->SetLastError(VE_APM_ERROR, kTraceError,
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000562 "Init() failed to set echo cancellation state for AP module");
563 return -1;
564 }
565 // Noise Reduction
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000566 if (_shared->audio_processing()->noise_suppression()->set_level(
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000567 (NoiseSuppression::Level) WEBRTC_VOICE_ENGINE_NS_DEFAULT_MODE)
568 != 0)
569 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000570 _shared->SetLastError(VE_APM_ERROR, kTraceError,
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000571 "Init() failed to set noise reduction level for AP module");
572 return -1;
573 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000574 if (_shared->audio_processing()->noise_suppression()->Enable(
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000575 WEBRTC_VOICE_ENGINE_NS_DEFAULT_STATE) != 0)
576 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000577 _shared->SetLastError(VE_APM_ERROR, kTraceError,
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000578 "Init() failed to set noise reduction state for AP module");
579 return -1;
580 }
581 // Automatic Gain control
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000582 if (_shared->audio_processing()->gain_control()->
583 set_analog_level_limits(kMinVolumeLevel,kMaxVolumeLevel) != 0)
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000584 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000585 _shared->SetLastError(VE_APM_ERROR, kTraceError,
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000586 "Init() failed to set AGC analog level for AP module");
587 return -1;
588 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000589 if (_shared->audio_processing()->gain_control()->set_mode(
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000590 (GainControl::Mode) WEBRTC_VOICE_ENGINE_AGC_DEFAULT_MODE)
591 != 0)
592 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000593 _shared->SetLastError(VE_APM_ERROR, kTraceError,
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000594 "Init() failed to set AGC mode for AP module");
595 return -1;
596 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000597 if (_shared->audio_processing()->gain_control()->Enable(
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000598 WEBRTC_VOICE_ENGINE_AGC_DEFAULT_STATE)
599 != 0)
600 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000601 _shared->SetLastError(VE_APM_ERROR, kTraceError,
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000602 "Init() failed to set AGC state for AP module");
603 return -1;
604 }
605 // VAD
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000606 if (_shared->audio_processing()->voice_detection()->Enable(
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000607 WEBRTC_VOICE_ENGINE_VAD_DEFAULT_STATE)
608 != 0)
609 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000610 _shared->SetLastError(VE_APM_ERROR, kTraceError,
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000611 "Init() failed to set VAD state for AP module");
612 return -1;
613 }
614 }
615
616 // Set default AGC mode for the ADM
niklase@google.com470e71d2011-07-07 08:21:25 +0000617#ifdef WEBRTC_VOICE_ENGINE_AGC
618 bool enable(false);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000619 if (_shared->audio_processing()->gain_control()->mode()
niklase@google.com470e71d2011-07-07 08:21:25 +0000620 != GainControl::kFixedDigital)
621 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000622 enable = _shared->audio_processing()->gain_control()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +0000623 // Only set the AGC mode for the ADM when Adaptive AGC mode is selected
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000624 if (_shared->audio_device()->SetAGC(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000625 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000626 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000627 kTraceError, "Init() failed to set default AGC mode in ADM 0");
niklase@google.com470e71d2011-07-07 08:21:25 +0000628 }
629 }
630#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000631
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000632 return _shared->statistics().SetInitialized();
niklase@google.com470e71d2011-07-07 08:21:25 +0000633}
634
635int VoEBaseImpl::Terminate()
636{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000637 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000638 "Terminate()");
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000639 CriticalSectionScoped cs(_shared->crit_sec());
niklase@google.com470e71d2011-07-07 08:21:25 +0000640 return TerminateInternal();
641}
642
643int VoEBaseImpl::MaxNumOfChannels()
644{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000645 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000646 "MaxNumOfChannels()");
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000647 WebRtc_Word32 maxNumOfChannels =
648 _shared->channel_manager().MaxNumOfChannels();
649 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
650 VoEId(_shared->instance_id(), -1),
651 "MaxNumOfChannels() => %d", maxNumOfChannels);
niklase@google.com470e71d2011-07-07 08:21:25 +0000652 return (maxNumOfChannels);
653}
654
655int VoEBaseImpl::CreateChannel()
656{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000657 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000658 "CreateChannel()");
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000659 CriticalSectionScoped cs(_shared->crit_sec());
niklase@google.com470e71d2011-07-07 08:21:25 +0000660
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000661 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000662 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000663 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000664 return -1;
665 }
666
667 WebRtc_Word32 channelId = -1;
668
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000669 if (!_shared->channel_manager().CreateChannel(channelId))
niklase@google.com470e71d2011-07-07 08:21:25 +0000670 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000671 _shared->SetLastError(VE_CHANNEL_NOT_CREATED, kTraceError,
672 "CreateChannel() failed to allocate memory for channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000673 return -1;
674 }
675
676 bool destroyChannel(false);
677 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000678 voe::ScopedChannel sc(_shared->channel_manager(), channelId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000679 voe::Channel* channelPtr = sc.ChannelPtr();
680 if (channelPtr == NULL)
681 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000682 _shared->SetLastError(VE_CHANNEL_NOT_CREATED, kTraceError,
683 "CreateChannel() failed to allocate memory for channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000684 return -1;
685 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000686 else if (channelPtr->SetEngineInformation(_shared->statistics(),
687 *_shared->output_mixer(),
688 *_shared->transmit_mixer(),
689 *_shared->process_thread(),
690 *_shared->audio_device(),
niklase@google.com470e71d2011-07-07 08:21:25 +0000691 _voiceEngineObserverPtr,
692 &_callbackCritSect) != 0)
693 {
694 destroyChannel = true;
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000695 _shared->SetLastError(VE_CHANNEL_NOT_CREATED, kTraceError,
696 "CreateChannel() failed to associate engine and channel."
697 " Destroying channel.");
niklase@google.com470e71d2011-07-07 08:21:25 +0000698 }
699 else if (channelPtr->Init() != 0)
700 {
701 destroyChannel = true;
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000702 _shared->SetLastError(VE_CHANNEL_NOT_CREATED, kTraceError,
703 "CreateChannel() failed to initialize channel. Destroying"
704 " channel.");
niklase@google.com470e71d2011-07-07 08:21:25 +0000705 }
706 }
707 if (destroyChannel)
708 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000709 _shared->channel_manager().DestroyChannel(channelId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000710 return -1;
711 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000712 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
713 VoEId(_shared->instance_id(), -1),
714 "CreateChannel() => %d", channelId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000715 return channelId;
716}
717
718int VoEBaseImpl::DeleteChannel(int channel)
719{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000720 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000721 "DeleteChannel(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000722 CriticalSectionScoped cs(_shared->crit_sec());
niklase@google.com470e71d2011-07-07 08:21:25 +0000723
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000724 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000725 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000726 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000727 return -1;
728 }
729
730 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000731 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000732 voe::Channel* channelPtr = sc.ChannelPtr();
733 if (channelPtr == NULL)
734 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000735 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
736 "DeleteChannel() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000737 return -1;
738 }
739 }
740
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000741 if (_shared->channel_manager().DestroyChannel(channel) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000742 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000743 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
744 "DeleteChannel() failed to destroy channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000745 return -1;
746 }
747
748 if (StopSend() != 0)
749 {
750 return -1;
751 }
752
753 if (StopPlayout() != 0)
754 {
755 return -1;
756 }
757
758 return 0;
759}
760
761int VoEBaseImpl::SetLocalReceiver(int channel, int port, int RTCPport,
762 const char ipAddr[64],
763 const char multiCastAddr[64])
764{
765 // Inititialize local receive sockets (RTP and RTCP).
766 //
767 // The sockets are always first closed and then created again by this
768 // function call. The created sockets are by default also used for
769 // transmission (unless source port is set in SetSendDestination).
770 //
771 // Note that, sockets can also be created automatically if a user calls
772 // SetSendDestination and StartSend without having called SetLocalReceiver
773 // first. The sockets are then created at the first packet transmission.
774
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000775 CriticalSectionScoped cs(_shared->crit_sec());
niklase@google.com470e71d2011-07-07 08:21:25 +0000776 if (ipAddr == NULL && multiCastAddr == NULL)
777 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000778 WEBRTC_TRACE(kTraceApiCall, kTraceVoice,
779 VoEId(_shared->instance_id(), -1),
780 "SetLocalReceiver(channel=%d, port=%d, RTCPport=%d)",
781 channel, port, RTCPport);
niklase@google.com470e71d2011-07-07 08:21:25 +0000782 }
783 else if (ipAddr != NULL && multiCastAddr == NULL)
784 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000785 WEBRTC_TRACE(kTraceApiCall, kTraceVoice,
786 VoEId(_shared->instance_id(), -1),
787 "SetLocalReceiver(channel=%d, port=%d, RTCPport=%d, ipAddr=%s)",
788 channel, port, RTCPport, ipAddr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000789 }
790 else if (ipAddr == NULL && multiCastAddr != NULL)
791 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000792 WEBRTC_TRACE(kTraceApiCall, kTraceVoice,
793 VoEId(_shared->instance_id(), -1),
794 "SetLocalReceiver(channel=%d, port=%d, RTCPport=%d, "
795 "multiCastAddr=%s)", channel, port, RTCPport, multiCastAddr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000796 }
797 else
798 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000799 WEBRTC_TRACE(kTraceApiCall, kTraceVoice,
800 VoEId(_shared->instance_id(), -1),
801 "SetLocalReceiver(channel=%d, port=%d, RTCPport=%d, "
802 "ipAddr=%s, multiCastAddr=%s)", channel, port, RTCPport, ipAddr,
803 multiCastAddr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000804 }
805#ifndef WEBRTC_EXTERNAL_TRANSPORT
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000806 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000807 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000808 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000809 return -1;
810 }
811 if ((port < 0) || (port > 65535))
812 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000813 _shared->SetLastError(VE_INVALID_PORT_NMBR, kTraceError,
814 "SetLocalReceiver() invalid RTP port");
niklase@google.com470e71d2011-07-07 08:21:25 +0000815 return -1;
816 }
817 if (((RTCPport != kVoEDefault) && (RTCPport < 0)) || ((RTCPport
818 != kVoEDefault) && (RTCPport > 65535)))
819 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000820 _shared->SetLastError(VE_INVALID_PORT_NMBR, kTraceError,
821 "SetLocalReceiver() invalid RTCP port");
niklase@google.com470e71d2011-07-07 08:21:25 +0000822 return -1;
823 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000824 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000825 voe::Channel* channelPtr = sc.ChannelPtr();
826 if (channelPtr == NULL)
827 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000828 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
829 "SetLocalReceiver() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000830 return -1;
831 }
832
833 // Cast RTCP port. In the RTP module 0 corresponds to RTP port + 1 in
834 // the module, which is the default.
835 WebRtc_UWord16 rtcpPortUW16(0);
836 if (RTCPport != kVoEDefault)
837 {
838 rtcpPortUW16 = static_cast<WebRtc_UWord16> (RTCPport);
839 }
840
841 return channelPtr->SetLocalReceiver(port, rtcpPortUW16, ipAddr,
842 multiCastAddr);
843#else
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000844 _shared->SetLastError(VE_EXTERNAL_TRANSPORT_ENABLED,
845 kTraceWarning, "SetLocalReceiver() VoE is built for external "
846 "transport");
niklase@google.com470e71d2011-07-07 08:21:25 +0000847 return -1;
848#endif
849}
850
851int VoEBaseImpl::GetLocalReceiver(int channel, int& port, int& RTCPport,
852 char ipAddr[64])
853{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000854 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000855 "GetLocalReceiver(channel=%d, ipAddr[]=?)", channel);
856#ifndef WEBRTC_EXTERNAL_TRANSPORT
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000857 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000858 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000859 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000860 return -1;
861 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000862 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000863 voe::Channel* channelPtr = sc.ChannelPtr();
864 if (channelPtr == NULL)
865 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000866 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
867 "SetLocalReceiver() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000868 return -1;
869 }
870 WebRtc_Word32 ret = channelPtr->GetLocalReceiver(port, RTCPport, ipAddr);
871 if (ipAddr != NULL)
872 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000873 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
874 VoEId(_shared->instance_id(), -1),
875 "GetLocalReceiver() => port=%d, RTCPport=%d, ipAddr=%s",
876 port, RTCPport, ipAddr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000877 }
878 else
879 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000880 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
881 VoEId(_shared->instance_id(), -1),
882 "GetLocalReceiver() => port=%d, RTCPport=%d", port, RTCPport);
niklase@google.com470e71d2011-07-07 08:21:25 +0000883 }
884 return ret;
885#else
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000886 _shared->SetLastError(VE_EXTERNAL_TRANSPORT_ENABLED, kTraceWarning,
887 "SetLocalReceiver() VoE is built for external transport");
niklase@google.com470e71d2011-07-07 08:21:25 +0000888 return -1;
889#endif
890}
891
892int VoEBaseImpl::SetSendDestination(int channel, int port, const char* ipaddr,
893 int sourcePort, int RTCPport)
894{
895 WEBRTC_TRACE(
896 kTraceApiCall,
897 kTraceVoice,
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000898 VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000899 "SetSendDestination(channel=%d, port=%d, ipaddr=%s,"
900 "sourcePort=%d, RTCPport=%d)",
901 channel, port, ipaddr, sourcePort, RTCPport);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000902 CriticalSectionScoped cs(_shared->crit_sec());
niklase@google.com470e71d2011-07-07 08:21:25 +0000903#ifndef WEBRTC_EXTERNAL_TRANSPORT
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000904 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000905 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000906 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000907 return -1;
908 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000909 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000910 voe::Channel* channelPtr = sc.ChannelPtr();
911 if (channelPtr == NULL)
912 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000913 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
914 "SetSendDestination() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000915 return -1;
916 }
917 if ((port < 0) || (port > 65535))
918 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000919 _shared->SetLastError(VE_INVALID_PORT_NMBR, kTraceError,
920 "SetSendDestination() invalid RTP port");
niklase@google.com470e71d2011-07-07 08:21:25 +0000921 return -1;
922 }
923 if (((RTCPport != kVoEDefault) && (RTCPport < 0)) || ((RTCPport
924 != kVoEDefault) && (RTCPport > 65535)))
925 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000926 _shared->SetLastError(VE_INVALID_PORT_NMBR, kTraceError,
927 "SetSendDestination() invalid RTCP port");
niklase@google.com470e71d2011-07-07 08:21:25 +0000928 return -1;
929 }
930 if (((sourcePort != kVoEDefault) && (sourcePort < 0)) || ((sourcePort
931 != kVoEDefault) && (sourcePort > 65535)))
932 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000933 _shared->SetLastError(VE_INVALID_PORT_NMBR, kTraceError,
934 "SetSendDestination() invalid source port");
niklase@google.com470e71d2011-07-07 08:21:25 +0000935 return -1;
936 }
937
938 // Cast RTCP port. In the RTP module 0 corresponds to RTP port + 1 in the
939 // module, which is the default.
940 WebRtc_UWord16 rtcpPortUW16(0);
941 if (RTCPport != kVoEDefault)
942 {
943 rtcpPortUW16 = static_cast<WebRtc_UWord16> (RTCPport);
944 WEBRTC_TRACE(
945 kTraceInfo,
946 kTraceVoice,
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000947 VoEId(_shared->instance_id(), channel),
niklase@google.com470e71d2011-07-07 08:21:25 +0000948 "SetSendDestination() non default RTCP port %u will be "
949 "utilized",
950 rtcpPortUW16);
951 }
952
953 return channelPtr->SetSendDestination(port, ipaddr, sourcePort,
954 rtcpPortUW16);
955#else
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000956 _shared->SetLastError(VE_EXTERNAL_TRANSPORT_ENABLED, kTraceWarning,
957 "SetSendDestination() VoE is built for external transport");
niklase@google.com470e71d2011-07-07 08:21:25 +0000958 return -1;
959#endif
960}
961
962int VoEBaseImpl::GetSendDestination(int channel, int& port, char ipAddr[64],
963 int& sourcePort, int& RTCPport)
964{
965 WEBRTC_TRACE(
966 kTraceApiCall,
967 kTraceVoice,
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000968 VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000969 "GetSendDestination(channel=%d, ipAddr[]=?, sourcePort=?,"
970 "RTCPport=?)",
971 channel);
972#ifndef WEBRTC_EXTERNAL_TRANSPORT
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 "GetSendDestination() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000984 return -1;
985 }
986 WebRtc_Word32 ret = channelPtr->GetSendDestination(port, ipAddr,
987 sourcePort, RTCPport);
988 if (ipAddr != NULL)
989 {
990 WEBRTC_TRACE(
991 kTraceStateInfo,
992 kTraceVoice,
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000993 VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000994 "GetSendDestination() => port=%d, RTCPport=%d, ipAddr=%s, "
995 "sourcePort=%d, RTCPport=%d",
996 port, RTCPport, ipAddr, sourcePort, RTCPport);
997 }
998 else
999 {
1000 WEBRTC_TRACE(
1001 kTraceStateInfo,
1002 kTraceVoice,
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001003 VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001004 "GetSendDestination() => port=%d, RTCPport=%d, "
1005 "sourcePort=%d, RTCPport=%d",
1006 port, RTCPport, sourcePort, RTCPport);
1007 }
1008 return ret;
1009#else
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001010 _shared->SetLastError(VE_EXTERNAL_TRANSPORT_ENABLED, kTraceWarning,
1011 "GetSendDestination() VoE is built for external transport");
niklase@google.com470e71d2011-07-07 08:21:25 +00001012 return -1;
1013#endif
1014}
1015
1016int VoEBaseImpl::StartReceive(int channel)
1017{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001018 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001019 "StartReceive(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001020 CriticalSectionScoped cs(_shared->crit_sec());
1021 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +00001022 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001023 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +00001024 return -1;
1025 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001026 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +00001027 voe::Channel* channelPtr = sc.ChannelPtr();
1028 if (channelPtr == NULL)
1029 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001030 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
1031 "StartReceive() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +00001032 return -1;
1033 }
1034 return channelPtr->StartReceiving();
1035}
1036
1037int VoEBaseImpl::StopReceive(int channel)
1038{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001039 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001040 "StopListen(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001041 CriticalSectionScoped cs(_shared->crit_sec());
1042 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +00001043 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001044 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +00001045 return -1;
1046 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001047 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +00001048 voe::Channel* channelPtr = sc.ChannelPtr();
1049 if (channelPtr == NULL)
1050 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001051 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
1052 "SetLocalReceiver() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +00001053 return -1;
1054 }
1055 return channelPtr->StopReceiving();
1056}
1057
1058int VoEBaseImpl::StartPlayout(int channel)
1059{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001060 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001061 "StartPlayout(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001062 CriticalSectionScoped cs(_shared->crit_sec());
1063 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +00001064 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001065 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +00001066 return -1;
1067 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001068 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +00001069 voe::Channel* channelPtr = sc.ChannelPtr();
1070 if (channelPtr == NULL)
1071 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001072 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
1073 "StartPlayout() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +00001074 return -1;
1075 }
1076 if (channelPtr->Playing())
1077 {
1078 return 0;
1079 }
1080 if (StartPlayout() != 0)
1081 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001082 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
1083 "StartPlayout() failed to start playout");
niklase@google.com470e71d2011-07-07 08:21:25 +00001084 return -1;
1085 }
1086 return channelPtr->StartPlayout();
1087}
1088
1089int VoEBaseImpl::StopPlayout(int channel)
1090{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001091 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001092 "StopPlayout(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001093 CriticalSectionScoped cs(_shared->crit_sec());
1094 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +00001095 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001096 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +00001097 return -1;
1098 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001099 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +00001100 voe::Channel* channelPtr = sc.ChannelPtr();
1101 if (channelPtr == NULL)
1102 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001103 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
1104 "StopPlayout() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +00001105 return -1;
1106 }
1107 if (channelPtr->StopPlayout() != 0)
1108 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001109 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1110 VoEId(_shared->instance_id(), -1),
1111 "StopPlayout() failed to stop playout for channel %d", channel);
niklase@google.com470e71d2011-07-07 08:21:25 +00001112 }
1113 return StopPlayout();
1114}
1115
1116int VoEBaseImpl::StartSend(int channel)
1117{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001118 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001119 "StartSend(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001120 CriticalSectionScoped cs(_shared->crit_sec());
1121 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +00001122 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001123 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +00001124 return -1;
1125 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001126 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +00001127 voe::Channel* channelPtr = sc.ChannelPtr();
1128 if (channelPtr == NULL)
1129 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001130 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
1131 "StartSend() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +00001132 return -1;
1133 }
1134 if (channelPtr->Sending())
1135 {
1136 return 0;
1137 }
1138#ifndef WEBRTC_EXTERNAL_TRANSPORT
1139 if (!channelPtr->ExternalTransport()
1140 && !channelPtr->SendSocketsInitialized())
1141 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001142 _shared->SetLastError(VE_DESTINATION_NOT_INITED, kTraceError,
1143 "StartSend() must set send destination first");
niklase@google.com470e71d2011-07-07 08:21:25 +00001144 return -1;
1145 }
1146#endif
1147 if (StartSend() != 0)
1148 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001149 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
1150 "StartSend() failed to start recording");
niklase@google.com470e71d2011-07-07 08:21:25 +00001151 return -1;
1152 }
1153 return channelPtr->StartSend();
1154}
1155
1156int VoEBaseImpl::StopSend(int channel)
1157{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001158 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001159 "StopSend(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001160 CriticalSectionScoped cs(_shared->crit_sec());
1161 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +00001162 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001163 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +00001164 return -1;
1165 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001166 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +00001167 voe::Channel* channelPtr = sc.ChannelPtr();
1168 if (channelPtr == NULL)
1169 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001170 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
1171 "StopSend() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +00001172 return -1;
1173 }
1174 if (channelPtr->StopSend() != 0)
1175 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001176 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1177 VoEId(_shared->instance_id(), -1),
1178 "StopSend() failed to stop sending for channel %d", channel);
niklase@google.com470e71d2011-07-07 08:21:25 +00001179 }
1180 return StopSend();
1181}
1182
1183int VoEBaseImpl::GetVersion(char version[1024])
1184{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001185 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001186 "GetVersion(version=?)");
1187 assert(kVoiceEngineVersionMaxMessageSize == 1024);
1188
1189 if (version == NULL)
1190 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001191 _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +00001192 return (-1);
1193 }
1194
1195 char versionBuf[kVoiceEngineVersionMaxMessageSize];
1196 char* versionPtr = versionBuf;
1197
1198 WebRtc_Word32 len = 0;
1199 WebRtc_Word32 accLen = 0;
1200
1201 len = AddVoEVersion(versionPtr);
1202 if (len == -1)
1203 {
1204 return -1;
1205 }
1206 versionPtr += len;
1207 accLen += len;
1208 assert(accLen < kVoiceEngineVersionMaxMessageSize);
1209
1210 len = AddBuildInfo(versionPtr);
1211 if (len == -1)
1212 {
1213 return -1;
1214 }
1215 versionPtr += len;
1216 accLen += len;
1217 assert(accLen < kVoiceEngineVersionMaxMessageSize);
1218
1219#ifdef WEBRTC_EXTERNAL_TRANSPORT
1220 len = AddExternalTransportBuild(versionPtr);
1221 if (len == -1)
1222 {
pwestin@webrtc.orgc450a192012-01-04 15:00:12 +00001223 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001224 }
1225 versionPtr += len;
1226 accLen += len;
1227 assert(accLen < kVoiceEngineVersionMaxMessageSize);
1228#endif
niklase@google.com470e71d2011-07-07 08:21:25 +00001229#ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT
1230 len = AddExternalRecAndPlayoutBuild(versionPtr);
1231 if (len == -1)
1232 {
1233 return -1;
1234 }
1235 versionPtr += len;
1236 accLen += len;
1237 assert(accLen < kVoiceEngineVersionMaxMessageSize);
pwestin@webrtc.orgc450a192012-01-04 15:00:12 +00001238 #endif
niklase@google.com470e71d2011-07-07 08:21:25 +00001239
1240 memcpy(version, versionBuf, accLen);
1241 version[accLen] = '\0';
1242
1243 // to avoid the truncation in the trace, split the string into parts
1244 char partOfVersion[256];
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001245 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
1246 VoEId(_shared->instance_id(), -1), "GetVersion() =>");
niklase@google.com470e71d2011-07-07 08:21:25 +00001247 for (int partStart = 0; partStart < accLen;)
1248 {
1249 memset(partOfVersion, 0, sizeof(partOfVersion));
1250 int partEnd = partStart + 180;
1251 while (version[partEnd] != '\n' && version[partEnd] != '\0')
1252 {
1253 partEnd--;
1254 }
1255 if (partEnd < accLen)
1256 {
1257 memcpy(partOfVersion, &version[partStart], partEnd - partStart);
1258 }
1259 else
1260 {
1261 memcpy(partOfVersion, &version[partStart], accLen - partStart);
1262 }
1263 partStart = partEnd;
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001264 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
1265 VoEId(_shared->instance_id(), -1), "%s", partOfVersion);
niklase@google.com470e71d2011-07-07 08:21:25 +00001266 }
1267
1268 return 0;
1269}
1270
1271WebRtc_Word32 VoEBaseImpl::AddBuildInfo(char* str) const
1272{
leozwang@webrtc.org48a5df62012-04-24 14:50:50 +00001273 return sprintf(str, "Build: svn:%s %s\n", WEBRTC_SVNREVISION, BUILDINFO);
niklase@google.com470e71d2011-07-07 08:21:25 +00001274}
1275
1276WebRtc_Word32 VoEBaseImpl::AddVoEVersion(char* str) const
1277{
1278 return sprintf(str, "VoiceEngine 4.1.0\n");
1279}
1280
niklase@google.com470e71d2011-07-07 08:21:25 +00001281#ifdef WEBRTC_EXTERNAL_TRANSPORT
1282WebRtc_Word32 VoEBaseImpl::AddExternalTransportBuild(char* str) const
1283{
1284 return sprintf(str, "External transport build\n");
1285}
1286#endif
1287
1288#ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT
1289WebRtc_Word32 VoEBaseImpl::AddExternalRecAndPlayoutBuild(char* str) const
1290{
1291 return sprintf(str, "External recording and playout build\n");
1292}
1293#endif
1294
niklase@google.com470e71d2011-07-07 08:21:25 +00001295int VoEBaseImpl::LastError()
1296{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001297 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001298 "LastError()");
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001299 return (_shared->statistics().LastError());
niklase@google.com470e71d2011-07-07 08:21:25 +00001300}
1301
1302
1303int VoEBaseImpl::SetNetEQPlayoutMode(int channel, NetEqModes mode)
1304{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001305 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001306 "SetNetEQPlayoutMode(channel=%i, mode=%i)", channel, mode);
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001307 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +00001308 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001309 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +00001310 return -1;
1311 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001312 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +00001313 voe::Channel* channelPtr = sc.ChannelPtr();
1314 if (channelPtr == NULL)
1315 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001316 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
1317 "SetNetEQPlayoutMode() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +00001318 return -1;
1319 }
1320 return channelPtr->SetNetEQPlayoutMode(mode);
1321}
1322
1323int VoEBaseImpl::GetNetEQPlayoutMode(int channel, NetEqModes& mode)
1324{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001325 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001326 "GetNetEQPlayoutMode(channel=%i, mode=?)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001327 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +00001328 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001329 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +00001330 return -1;
1331 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001332 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +00001333 voe::Channel* channelPtr = sc.ChannelPtr();
1334 if (channelPtr == NULL)
1335 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001336 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
1337 "GetNetEQPlayoutMode() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +00001338 return -1;
1339 }
1340 return channelPtr->GetNetEQPlayoutMode(mode);
1341}
1342
1343int VoEBaseImpl::SetNetEQBGNMode(int channel, NetEqBgnModes mode)
1344{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001345 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001346 "SetNetEQBGNMode(channel=%i, mode=%i)", channel, mode);
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001347 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +00001348 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001349 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +00001350 return -1;
1351 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001352 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +00001353 voe::Channel* channelPtr = sc.ChannelPtr();
1354 if (channelPtr == NULL)
1355 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001356 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
1357 "SetNetEQBGNMode() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +00001358 return -1;
1359 }
1360 return channelPtr->SetNetEQBGNMode(mode);
1361}
1362
1363int VoEBaseImpl::GetNetEQBGNMode(int channel, NetEqBgnModes& mode)
1364{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001365 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001366 "GetNetEQBGNMode(channel=%i, mode=?)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001367 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +00001368 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001369 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +00001370 return -1;
1371 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001372 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +00001373 voe::Channel* channelPtr = sc.ChannelPtr();
1374 if (channelPtr == NULL)
1375 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001376 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
1377 "GetNetEQBGNMode() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +00001378 return -1;
1379 }
1380 return channelPtr->GetNetEQBGNMode(mode);
1381}
1382
1383int VoEBaseImpl::SetOnHoldStatus(int channel, bool enable, OnHoldModes mode)
1384{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001385 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001386 "SetOnHoldStatus(channel=%d, enable=%d, mode=%d)", channel,
1387 enable, mode);
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001388 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +00001389 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001390 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +00001391 return -1;
1392 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001393 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +00001394 voe::Channel* channelPtr = sc.ChannelPtr();
1395 if (channelPtr == NULL)
1396 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001397 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
1398 "SetOnHoldStatus() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +00001399 return -1;
1400 }
1401 return channelPtr->SetOnHoldStatus(enable, mode);
1402}
1403
1404int VoEBaseImpl::GetOnHoldStatus(int channel, bool& enabled, OnHoldModes& mode)
1405{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001406 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001407 "GetOnHoldStatus(channel=%d, enabled=?, mode=?)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001408 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +00001409 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001410 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +00001411 return -1;
1412 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001413 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +00001414 voe::Channel* channelPtr = sc.ChannelPtr();
1415 if (channelPtr == NULL)
1416 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001417 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
1418 "GetOnHoldStatus() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +00001419 return -1;
1420 }
1421 return channelPtr->GetOnHoldStatus(enabled, mode);
1422}
1423
1424WebRtc_Word32 VoEBaseImpl::StartPlayout()
1425{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001426 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001427 "VoEBaseImpl::StartPlayout()");
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001428 if (_shared->audio_device()->Playing())
niklase@google.com470e71d2011-07-07 08:21:25 +00001429 {
1430 return 0;
1431 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001432 if (!_shared->ext_playout())
niklase@google.com470e71d2011-07-07 08:21:25 +00001433 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001434 if (_shared->audio_device()->InitPlayout() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001435 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001436 WEBRTC_TRACE(kTraceError, kTraceVoice,
1437 VoEId(_shared->instance_id(), -1),
1438 "StartPlayout() failed to initialize playout");
niklase@google.com470e71d2011-07-07 08:21:25 +00001439 return -1;
1440 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001441 if (_shared->audio_device()->StartPlayout() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001442 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001443 WEBRTC_TRACE(kTraceError, kTraceVoice,
1444 VoEId(_shared->instance_id(), -1),
1445 "StartPlayout() failed to start playout");
niklase@google.com470e71d2011-07-07 08:21:25 +00001446 return -1;
1447 }
1448 }
1449 return 0;
1450}
1451
1452WebRtc_Word32 VoEBaseImpl::StopPlayout()
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::StopPlayout()");
1456
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001457 WebRtc_Word32 numOfChannels = _shared->channel_manager().NumOfChannels();
niklase@google.com470e71d2011-07-07 08:21:25 +00001458 if (numOfChannels <= 0)
1459 {
1460 return 0;
1461 }
1462
1463 WebRtc_UWord16 nChannelsPlaying(0);
1464 WebRtc_Word32* channelsArray = new WebRtc_Word32[numOfChannels];
1465
1466 // Get number of playing channels
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001467 _shared->channel_manager().GetChannelIds(channelsArray, numOfChannels);
niklase@google.com470e71d2011-07-07 08:21:25 +00001468 for (int i = 0; i < numOfChannels; i++)
1469 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001470 voe::ScopedChannel sc(_shared->channel_manager(), channelsArray[i]);
niklase@google.com470e71d2011-07-07 08:21:25 +00001471 voe::Channel* chPtr = sc.ChannelPtr();
1472 if (chPtr)
1473 {
1474 if (chPtr->Playing())
1475 {
1476 nChannelsPlaying++;
1477 }
1478 }
1479 }
1480 delete[] channelsArray;
1481
1482 // Stop audio-device playing if no channel is playing out
1483 if (nChannelsPlaying == 0)
1484 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001485 if (_shared->audio_device()->StopPlayout() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001486 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001487 _shared->SetLastError(VE_CANNOT_STOP_PLAYOUT, kTraceError,
1488 "StopPlayout() failed to stop playout");
niklase@google.com470e71d2011-07-07 08:21:25 +00001489 return -1;
1490 }
1491 }
1492 return 0;
1493}
1494
1495WebRtc_Word32 VoEBaseImpl::StartSend()
1496{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001497 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001498 "VoEBaseImpl::StartSend()");
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001499 if (_shared->audio_device()->Recording())
niklase@google.com470e71d2011-07-07 08:21:25 +00001500 {
1501 return 0;
1502 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001503 if (!_shared->ext_recording())
niklase@google.com470e71d2011-07-07 08:21:25 +00001504 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001505 if (_shared->audio_device()->InitRecording() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001506 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001507 WEBRTC_TRACE(kTraceError, kTraceVoice,
1508 VoEId(_shared->instance_id(), -1),
1509 "StartSend() failed to initialize recording");
niklase@google.com470e71d2011-07-07 08:21:25 +00001510 return -1;
1511 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001512 if (_shared->audio_device()->StartRecording() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001513 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001514 WEBRTC_TRACE(kTraceError, kTraceVoice,
1515 VoEId(_shared->instance_id(), -1),
1516 "StartSend() failed to start recording");
niklase@google.com470e71d2011-07-07 08:21:25 +00001517 return -1;
1518 }
1519 }
1520
1521 return 0;
1522}
1523
1524WebRtc_Word32 VoEBaseImpl::StopSend()
1525{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001526 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001527 "VoEBaseImpl::StopSend()");
1528
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001529 if (_shared->NumOfSendingChannels() == 0 &&
1530 !_shared->transmit_mixer()->IsRecordingMic())
niklase@google.com470e71d2011-07-07 08:21:25 +00001531 {
1532 // Stop audio-device recording if no channel is recording
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001533 if (_shared->audio_device()->StopRecording() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001534 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001535 _shared->SetLastError(VE_CANNOT_STOP_RECORDING, kTraceError,
1536 "StopSend() failed to stop recording");
niklase@google.com470e71d2011-07-07 08:21:25 +00001537 return -1;
1538 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001539 _shared->transmit_mixer()->StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +00001540 }
1541
1542 return 0;
1543}
1544
1545WebRtc_Word32 VoEBaseImpl::TerminateInternal()
1546{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001547 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001548 "VoEBaseImpl::TerminateInternal()");
1549
1550 // Delete any remaining channel objects
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001551 WebRtc_Word32 numOfChannels = _shared->channel_manager().NumOfChannels();
niklase@google.com470e71d2011-07-07 08:21:25 +00001552 if (numOfChannels > 0)
1553 {
1554 WebRtc_Word32* channelsArray = new WebRtc_Word32[numOfChannels];
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001555 _shared->channel_manager().GetChannelIds(channelsArray, numOfChannels);
niklase@google.com470e71d2011-07-07 08:21:25 +00001556 for (int i = 0; i < numOfChannels; i++)
1557 {
1558 DeleteChannel(channelsArray[i]);
1559 }
1560 delete[] channelsArray;
1561 }
1562
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001563 if (_shared->process_thread())
niklase@google.com470e71d2011-07-07 08:21:25 +00001564 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001565 if (_shared->audio_device())
niklase@google.com470e71d2011-07-07 08:21:25 +00001566 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001567 if (_shared->process_thread()->
1568 DeRegisterModule(_shared->audio_device()) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001569 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001570 _shared->SetLastError(VE_THREAD_ERROR, kTraceError,
1571 "TerminateInternal() failed to deregister ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +00001572 }
1573 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001574 if (_shared->process_thread()->Stop() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001575 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001576 _shared->SetLastError(VE_THREAD_ERROR, kTraceError,
1577 "TerminateInternal() failed to stop module process thread");
niklase@google.com470e71d2011-07-07 08:21:25 +00001578 }
1579 }
1580
1581 // Audio Device Module
1582
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001583 if (_shared->audio_device() != NULL)
niklase@google.com470e71d2011-07-07 08:21:25 +00001584 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001585 if (_shared->audio_device()->StopPlayout() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001586 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001587 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
1588 "TerminateInternal() failed to stop playout");
niklase@google.com470e71d2011-07-07 08:21:25 +00001589 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001590 if (_shared->audio_device()->StopRecording() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001591 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001592 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
1593 "TerminateInternal() failed to stop recording");
niklase@google.com470e71d2011-07-07 08:21:25 +00001594 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001595 if (_shared->audio_device()->RegisterEventObserver(NULL) != 0) {
1596 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
1597 "TerminateInternal() failed to de-register event observer "
1598 "for the ADM");
xians@webrtc.org79af7342012-01-31 12:22:14 +00001599 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001600 if (_shared->audio_device()->RegisterAudioCallback(NULL) != 0) {
1601 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
1602 "TerminateInternal() failed to de-register audio callback "
1603 "for the ADM");
xians@webrtc.org79af7342012-01-31 12:22:14 +00001604 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001605 if (_shared->audio_device()->Terminate() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001606 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001607 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
1608 "TerminateInternal() failed to terminate the ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +00001609 }
henrika@google.com73d65512011-09-07 15:11:18 +00001610
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001611 _shared->set_audio_device(NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +00001612 }
1613
1614 // AP module
1615
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001616 if (_shared->audio_processing() != NULL)
niklase@google.com470e71d2011-07-07 08:21:25 +00001617 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001618 _shared->transmit_mixer()->SetAudioProcessingModule(NULL);
1619 _shared->set_audio_processing(NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +00001620 }
1621
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001622 return _shared->statistics().SetUnInitialized();
niklase@google.com470e71d2011-07-07 08:21:25 +00001623}
1624
1625} // namespace webrtc