blob: c703efdaaa7a7d5d78f56c68621b60f46b70d48a [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
pbos@webrtc.org956aa7e2013-05-21 13:52:32 +000011#include "webrtc/voice_engine/voe_base_impl.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000012
pbos@webrtc.org956aa7e2013-05-21 13:52:32 +000013#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
14#include "webrtc/modules/audio_coding/main/interface/audio_coding_module.h"
15#include "webrtc/modules/audio_device/audio_device_impl.h"
16#include "webrtc/modules/audio_processing/include/audio_processing.h"
17#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
18#include "webrtc/system_wrappers/interface/file_wrapper.h"
19#include "webrtc/system_wrappers/interface/trace.h"
20#include "webrtc/voice_engine/channel.h"
21#include "webrtc/voice_engine/include/voe_errors.h"
22#include "webrtc/voice_engine/output_mixer.h"
23#include "webrtc/voice_engine/transmit_mixer.h"
24#include "webrtc/voice_engine/utility.h"
25#include "webrtc/voice_engine/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
pbos@webrtc.org92135212013-05-14 08:31:39 +000068void VoEBaseImpl::OnErrorIsReported(ErrorCode error)
niklase@google.com470e71d2011-07-07 08:21:25 +000069{
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
pbos@webrtc.org92135212013-05-14 08:31:39 +000097void VoEBaseImpl::OnWarningIsReported(WarningCode warning)
niklase@google.com470e71d2011-07-07 08:21:25 +000098{
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +000099 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000100 if (_voiceEngineObserver)
101 {
102 if (_voiceEngineObserverPtr)
103 {
104 int warningCode(0);
105 if (warning == AudioDeviceObserver::kRecordingWarning)
106 {
107 warningCode = VE_RUNTIME_REC_WARNING;
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000108 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
109 VoEId(_shared->instance_id(), -1),
110 "VoEBaseImpl::OnErrorIsReported() => "
111 "VE_RUNTIME_REC_WARNING");
niklase@google.com470e71d2011-07-07 08:21:25 +0000112 }
113 else if (warning == AudioDeviceObserver::kPlayoutWarning)
114 {
115 warningCode = VE_RUNTIME_PLAY_WARNING;
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000116 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
117 VoEId(_shared->instance_id(), -1),
118 "VoEBaseImpl::OnErrorIsReported() => "
119 "VE_RUNTIME_PLAY_WARNING");
niklase@google.com470e71d2011-07-07 08:21:25 +0000120 }
121 // Deliver callback (-1 <=> no channel dependency)
122 _voiceEngineObserverPtr->CallbackOnError(-1, warningCode);
123 }
124 }
125}
126
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000127int32_t VoEBaseImpl::RecordedDataIsAvailable(
henrika@webrtc.org907bc552012-03-09 08:59:19 +0000128 const void* audioSamples,
pbos@webrtc.org92135212013-05-14 08:31:39 +0000129 uint32_t nSamples,
130 uint8_t nBytesPerSample,
131 uint8_t nChannels,
132 uint32_t samplesPerSec,
133 uint32_t totalDelayMS,
134 int32_t clockDrift,
135 uint32_t currentMicLevel,
136 bool keyPressed,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000137 uint32_t& newMicLevel)
niklase@google.com470e71d2011-07-07 08:21:25 +0000138{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000139 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000140 "VoEBaseImpl::RecordedDataIsAvailable(nSamples=%u, "
141 "nBytesPerSample=%u, nChannels=%u, samplesPerSec=%u, "
142 "totalDelayMS=%u, clockDrift=%d, currentMicLevel=%u)",
143 nSamples, nBytesPerSample, nChannels, samplesPerSec,
144 totalDelayMS, clockDrift, currentMicLevel);
145
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000146 assert(_shared->transmit_mixer() != NULL);
147 assert(_shared->audio_device() != NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000148
niklase@google.com470e71d2011-07-07 08:21:25 +0000149 bool isAnalogAGC(false);
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000150 uint32_t maxVolume(0);
151 uint16_t currentVoEMicLevel(0);
152 uint32_t newVoEMicLevel(0);
niklase@google.com470e71d2011-07-07 08:21:25 +0000153
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000154 if (_shared->audio_processing() &&
155 (_shared->audio_processing()->gain_control()->mode()
niklase@google.com470e71d2011-07-07 08:21:25 +0000156 == GainControl::kAdaptiveAnalog))
157 {
158 isAnalogAGC = true;
159 }
160
161 // Will only deal with the volume in adaptive analog mode
162 if (isAnalogAGC)
163 {
164 // Scale from ADM to VoE level range
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000165 if (_shared->audio_device()->MaxMicrophoneVolume(&maxVolume) == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000166 {
167 if (0 != maxVolume)
168 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000169 currentVoEMicLevel = (uint16_t) ((currentMicLevel
niklase@google.com470e71d2011-07-07 08:21:25 +0000170 * kMaxVolumeLevel + (int) (maxVolume / 2))
171 / (maxVolume));
172 }
173 }
punyabrata@webrtc.org6b6d0812011-09-28 17:45:03 +0000174 // We learned that on certain systems (e.g Linux) the currentVoEMicLevel
175 // can be greater than the maxVolumeLevel therefore
176 // we are going to cap the currentVoEMicLevel to the maxVolumeLevel
xians@webrtc.org3ab6dda2012-02-16 18:15:54 +0000177 // and change the maxVolume to currentMicLevel if it turns out that
178 // the currentVoEMicLevel is indeed greater than the maxVolumeLevel.
punyabrata@webrtc.org6b6d0812011-09-28 17:45:03 +0000179 if (currentVoEMicLevel > kMaxVolumeLevel)
180 {
181 currentVoEMicLevel = kMaxVolumeLevel;
xians@webrtc.org3ab6dda2012-02-16 18:15:54 +0000182 maxVolume = currentMicLevel;
punyabrata@webrtc.org6b6d0812011-09-28 17:45:03 +0000183 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000184 }
185
186 // Keep track if the MicLevel has been changed by the AGC, if not,
187 // use the old value AGC returns to let AGC continue its trend,
188 // so eventually the AGC is able to change the mic level. This handles
189 // issues with truncation introduced by the scaling.
190 if (_oldMicLevel == currentMicLevel)
191 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000192 currentVoEMicLevel = (uint16_t) _oldVoEMicLevel;
niklase@google.com470e71d2011-07-07 08:21:25 +0000193 }
194
niklase@google.com470e71d2011-07-07 08:21:25 +0000195 // Perform channel-independent operations
196 // (APM, mix with file, record to file, mute, etc.)
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000197 _shared->transmit_mixer()->PrepareDemux(audioSamples, nSamples, nChannels,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000198 samplesPerSec, static_cast<uint16_t>(totalDelayMS), clockDrift,
niklas.enbom@webrtc.org3be565b2013-05-07 21:04:24 +0000199 currentVoEMicLevel, keyPressed);
niklase@google.com470e71d2011-07-07 08:21:25 +0000200
201 // Copy the audio frame to each sending channel and perform
202 // channel-dependent operations (file mixing, mute, etc.) to prepare
203 // for encoding.
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000204 _shared->transmit_mixer()->DemuxAndMix();
niklase@google.com470e71d2011-07-07 08:21:25 +0000205 // Do the encoding and packetize+transmit the RTP packet when encoding
206 // is done.
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000207 _shared->transmit_mixer()->EncodeAndSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000208
209 // Will only deal with the volume in adaptive analog mode
210 if (isAnalogAGC)
211 {
212 // Scale from VoE to ADM level range
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000213 newVoEMicLevel = _shared->transmit_mixer()->CaptureLevel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000214 if (newVoEMicLevel != currentVoEMicLevel)
215 {
216 // Add (kMaxVolumeLevel/2) to round the value
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000217 newMicLevel = (uint32_t) ((newVoEMicLevel * maxVolume
niklase@google.com470e71d2011-07-07 08:21:25 +0000218 + (int) (kMaxVolumeLevel / 2)) / (kMaxVolumeLevel));
219 }
220 else
221 {
222 // Pass zero if the level is unchanged
223 newMicLevel = 0;
224 }
225
226 // Keep track of the value AGC returns
227 _oldVoEMicLevel = newVoEMicLevel;
228 _oldMicLevel = currentMicLevel;
229 }
230
231 return 0;
232}
233
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000234int32_t VoEBaseImpl::NeedMorePlayData(
pbos@webrtc.org92135212013-05-14 08:31:39 +0000235 uint32_t nSamples,
236 uint8_t nBytesPerSample,
237 uint8_t nChannels,
238 uint32_t samplesPerSec,
henrika@webrtc.org907bc552012-03-09 08:59:19 +0000239 void* audioSamples,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000240 uint32_t& nSamplesOut)
niklase@google.com470e71d2011-07-07 08:21:25 +0000241{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000242 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000243 "VoEBaseImpl::NeedMorePlayData(nSamples=%u, "
244 "nBytesPerSample=%d, nChannels=%d, samplesPerSec=%u)",
245 nSamples, nBytesPerSample, nChannels, samplesPerSec);
246
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000247 assert(_shared->output_mixer() != NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000248
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +0000249 // TODO(andrew): if the device is running in mono, we should tell the mixer
250 // here so that it will only request mono from AudioCodingModule.
niklase@google.com470e71d2011-07-07 08:21:25 +0000251 // Perform mixing of all active participants (channel-based mixing)
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000252 _shared->output_mixer()->MixActiveChannels();
niklase@google.com470e71d2011-07-07 08:21:25 +0000253
254 // Additional operations on the combined signal
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000255 _shared->output_mixer()->DoOperationsOnCombinedSignal();
niklase@google.com470e71d2011-07-07 08:21:25 +0000256
257 // Retrieve the final output mix (resampled to match the ADM)
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000258 _shared->output_mixer()->GetMixedAudio(samplesPerSec, nChannels,
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +0000259 &_audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000260
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +0000261 assert(static_cast<int>(nSamples) == _audioFrame.samples_per_channel_);
xians@google.com0b0665a2011-08-08 08:18:44 +0000262 assert(samplesPerSec ==
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000263 static_cast<uint32_t>(_audioFrame.sample_rate_hz_));
niklase@google.com470e71d2011-07-07 08:21:25 +0000264
265 // Deliver audio (PCM) samples to the ADM
266 memcpy(
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000267 (int16_t*) audioSamples,
268 (const int16_t*) _audioFrame.data_,
269 sizeof(int16_t) * (_audioFrame.samples_per_channel_
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000270 * _audioFrame.num_channels_));
niklase@google.com470e71d2011-07-07 08:21:25 +0000271
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000272 nSamplesOut = _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000273
274 return 0;
275}
276
xians@webrtc.org2f84afa2013-07-31 16:23:37 +0000277int VoEBaseImpl::OnDataAvailable(int voe_channels[],
278 int number_of_voe_channels,
279 const int16_t* audio_data,
280 int sample_rate,
281 int number_of_channels,
282 int number_of_frames,
283 int audio_delay_milliseconds,
284 int current_volume,
285 bool key_pressed,
286 bool need_audio_processing) {
287 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_shared->instance_id(), -1),
288 "VoEBaseImpl::OnDataAvailable(number_of_voe_channels=%d, "
289 "sample_rate=%d, number_of_channels=%d, number_of_frames=%d, "
290 "audio_delay_milliseconds=%d, current_volume=%d, "
291 "key_pressed=%d, need_audio_processing=%d)",
292 number_of_voe_channels, sample_rate, number_of_channels,
293 number_of_frames, audio_delay_milliseconds, current_volume,
294 key_pressed, need_audio_processing);
295
296 if (need_audio_processing) {
297 // Perform channel-independent operations
298 // (APM, mix with file, record to file, mute, etc.)
299 _shared->transmit_mixer()->PrepareDemux(
300 audio_data, number_of_frames, number_of_channels,
301 sample_rate, static_cast<uint16_t>(audio_delay_milliseconds), 0,
302 current_volume, key_pressed);
303 _shared->transmit_mixer()->DemuxAndMix(voe_channels,
304 number_of_voe_channels);
305 _shared->transmit_mixer()->EncodeAndSend(voe_channels,
306 number_of_voe_channels);
307 // Update the volume if the analog AGC is working.
308 if (_shared->audio_processing() &&
309 _shared->audio_processing()->gain_control()->mode() ==
310 GainControl::kAdaptiveAnalog) {
311 return _shared->transmit_mixer()->CaptureLevel();
312 }
313
314 // Return 0 to indicate no need to change the volume.
315 return 0;
316 }
317
318 // No need to go through the APM, demultiplex the data to each VoE channel,
319 // encode and send to the network.
320 for (int i = 0; i < number_of_voe_channels; ++i) {
321 voe::ScopedChannel sc(_shared->channel_manager(), voe_channels[i]);
322 voe::Channel* channel_ptr = sc.ChannelPtr();
323 if (!channel_ptr)
324 continue;
325
326 if (channel_ptr->InputIsOnHold()) {
327 channel_ptr->UpdateLocalTimeStamp();
328 } else if (channel_ptr->Sending()) {
329 channel_ptr->Demultiplex(audio_data, sample_rate, number_of_frames,
330 number_of_channels);
331 channel_ptr->PrepareEncodeAndSend(sample_rate);
332 channel_ptr->EncodeAndSend();
333 }
334 }
335
336 // Return 0 to indicate no need to change the volume.
337 return 0;
338}
339
niklase@google.com470e71d2011-07-07 08:21:25 +0000340int VoEBaseImpl::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
341{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000342 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000343 "RegisterVoiceEngineObserver(observer=0x%d)", &observer);
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000344 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000345 if (_voiceEngineObserverPtr)
346 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000347 _shared->SetLastError(VE_INVALID_OPERATION, kTraceError,
348 "RegisterVoiceEngineObserver() observer already enabled");
niklase@google.com470e71d2011-07-07 08:21:25 +0000349 return -1;
350 }
351
352 // Register the observer in all active channels
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000353 voe::ScopedChannel sc(_shared->channel_manager());
niklase@google.com470e71d2011-07-07 08:21:25 +0000354 void* iterator(NULL);
355 voe::Channel* channelPtr = sc.GetFirstChannel(iterator);
356 while (channelPtr != NULL)
357 {
358 channelPtr->RegisterVoiceEngineObserver(observer);
359 channelPtr = sc.GetNextChannel(iterator);
360 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000361 _shared->transmit_mixer()->RegisterVoiceEngineObserver(observer);
niklase@google.com470e71d2011-07-07 08:21:25 +0000362
363 _voiceEngineObserverPtr = &observer;
364 _voiceEngineObserver = true;
365
366 return 0;
367}
368
369int VoEBaseImpl::DeRegisterVoiceEngineObserver()
370{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000371 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000372 "DeRegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000373 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000374 if (!_voiceEngineObserverPtr)
375 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000376 _shared->SetLastError(VE_INVALID_OPERATION, kTraceError,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000377 "DeRegisterVoiceEngineObserver() observer already disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +0000378 return 0;
379 }
380
381 _voiceEngineObserver = false;
382 _voiceEngineObserverPtr = NULL;
383
384 // Deregister the observer in all active channels
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000385 voe::ScopedChannel sc(_shared->channel_manager());
niklase@google.com470e71d2011-07-07 08:21:25 +0000386 void* iterator(NULL);
387 voe::Channel* channelPtr = sc.GetFirstChannel(iterator);
388 while (channelPtr != NULL)
389 {
390 channelPtr->DeRegisterVoiceEngineObserver();
391 channelPtr = sc.GetNextChannel(iterator);
392 }
393
394 return 0;
395}
396
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000397int VoEBaseImpl::Init(AudioDeviceModule* external_adm,
398 AudioProcessing* audioproc)
niklase@google.com470e71d2011-07-07 08:21:25 +0000399{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000400 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
henrika@google.com73d65512011-09-07 15:11:18 +0000401 "Init(external_adm=0x%p)", external_adm);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000402 CriticalSectionScoped cs(_shared->crit_sec());
niklase@google.com470e71d2011-07-07 08:21:25 +0000403
kma@webrtc.org0221b782012-09-08 00:09:26 +0000404 WebRtcSpl_Init();
405
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000406 if (_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000407 {
408 return 0;
409 }
410
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000411 if (_shared->process_thread())
niklase@google.com470e71d2011-07-07 08:21:25 +0000412 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000413 if (_shared->process_thread()->Start() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000414 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000415 _shared->SetLastError(VE_THREAD_ERROR, kTraceError,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000416 "Init() failed to start module process thread");
niklase@google.com470e71d2011-07-07 08:21:25 +0000417 return -1;
418 }
419 }
420
andrew@webrtc.org3192d652011-12-21 18:00:59 +0000421 // Create an internal ADM if the user has not added an external
henrika@google.com73d65512011-09-07 15:11:18 +0000422 // ADM implementation as input to Init().
423 if (external_adm == NULL)
niklase@google.com470e71d2011-07-07 08:21:25 +0000424 {
henrika@google.com73d65512011-09-07 15:11:18 +0000425 // Create the internal ADM implementation.
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000426 _shared->set_audio_device(AudioDeviceModuleImpl::Create(
427 VoEId(_shared->instance_id(), -1), _shared->audio_device_layer()));
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000428
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000429 if (_shared->audio_device() == NULL)
niklase@google.com470e71d2011-07-07 08:21:25 +0000430 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000431 _shared->SetLastError(VE_NO_MEMORY, kTraceCritical,
432 "Init() failed to create the ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +0000433 return -1;
434 }
435 }
henrika@google.com73d65512011-09-07 15:11:18 +0000436 else
437 {
438 // Use the already existing external ADM implementation.
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000439 _shared->set_audio_device(external_adm);
440 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
henrika@google.com73d65512011-09-07 15:11:18 +0000441 "An external ADM implementation will be used in VoiceEngine");
442 }
443
niklase@google.com470e71d2011-07-07 08:21:25 +0000444 // Register the ADM to the process thread, which will drive the error
445 // callback mechanism
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000446 if (_shared->process_thread() &&
447 _shared->process_thread()->RegisterModule(_shared->audio_device()) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000448 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000449 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
450 "Init() failed to register the ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +0000451 return -1;
452 }
453
454 bool available(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000455
456 // --------------------
457 // Reinitialize the ADM
458
459 // Register the AudioObserver implementation
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000460 if (_shared->audio_device()->RegisterEventObserver(this) != 0) {
461 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
462 "Init() failed to register event observer for the ADM");
xians@webrtc.org79af7342012-01-31 12:22:14 +0000463 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000464
465 // Register the AudioTransport implementation
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000466 if (_shared->audio_device()->RegisterAudioCallback(this) != 0) {
467 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
468 "Init() failed to register audio callback for the ADM");
xians@webrtc.org79af7342012-01-31 12:22:14 +0000469 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000470
471 // ADM initialization
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000472 if (_shared->audio_device()->Init() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000473 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000474 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
475 "Init() failed to initialize the ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +0000476 return -1;
477 }
478
479 // Initialize the default speaker
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000480 if (_shared->audio_device()->SetPlayoutDevice(
481 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000482 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000483 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000484 "Init() failed to set the default output device");
niklase@google.com470e71d2011-07-07 08:21:25 +0000485 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000486 if (_shared->audio_device()->SpeakerIsAvailable(&available) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000487 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000488 _shared->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000489 "Init() failed to check speaker availability, trying to "
490 "initialize speaker anyway");
niklase@google.com470e71d2011-07-07 08:21:25 +0000491 }
492 else if (!available)
493 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000494 _shared->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000495 "Init() speaker not available, trying to initialize speaker "
496 "anyway");
niklase@google.com470e71d2011-07-07 08:21:25 +0000497 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000498 if (_shared->audio_device()->InitSpeaker() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000499 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000500 _shared->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000501 "Init() failed to initialize the speaker");
niklase@google.com470e71d2011-07-07 08:21:25 +0000502 }
503
504 // Initialize the default microphone
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000505 if (_shared->audio_device()->SetRecordingDevice(
506 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000507 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000508 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000509 "Init() failed to set the default input device");
niklase@google.com470e71d2011-07-07 08:21:25 +0000510 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000511 if (_shared->audio_device()->MicrophoneIsAvailable(&available) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000512 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000513 _shared->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000514 "Init() failed to check microphone availability, trying to "
515 "initialize microphone anyway");
niklase@google.com470e71d2011-07-07 08:21:25 +0000516 }
517 else if (!available)
518 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000519 _shared->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000520 "Init() microphone not available, trying to initialize "
521 "microphone anyway");
niklase@google.com470e71d2011-07-07 08:21:25 +0000522 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000523 if (_shared->audio_device()->InitMicrophone() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000524 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000525 _shared->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000526 "Init() failed to initialize the microphone");
niklase@google.com470e71d2011-07-07 08:21:25 +0000527 }
528
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000529 // Set number of channels
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000530 if (_shared->audio_device()->StereoPlayoutIsAvailable(&available) != 0) {
531 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
532 "Init() failed to query stereo playout mode");
xians@webrtc.org79af7342012-01-31 12:22:14 +0000533 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000534 if (_shared->audio_device()->SetStereoPlayout(available) != 0)
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000535 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000536 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000537 "Init() failed to set mono/stereo playout mode");
538 }
andrew@webrtc.org3192d652011-12-21 18:00:59 +0000539
540 // TODO(andrew): These functions don't tell us whether stereo recording
541 // is truly available. We simply set the AudioProcessing input to stereo
542 // here, because we have to wait until receiving the first frame to
543 // determine the actual number of channels anyway.
544 //
545 // These functions may be changed; tracked here:
546 // http://code.google.com/p/webrtc/issues/detail?id=204
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000547 _shared->audio_device()->StereoRecordingIsAvailable(&available);
548 if (_shared->audio_device()->SetStereoRecording(available) != 0)
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000549 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000550 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000551 "Init() failed to set mono/stereo recording mode");
552 }
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000553
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000554 if (!audioproc) {
555 audioproc = AudioProcessing::Create(VoEId(_shared->instance_id(), -1));
556 if (!audioproc) {
557 LOG(LS_ERROR) << "Failed to create AudioProcessing.";
558 _shared->SetLastError(VE_NO_MEMORY);
559 return -1;
560 }
561 }
562 _shared->set_audio_processing(audioproc);
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000563
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000564 // Set the error state for any failures in this block.
565 _shared->SetLastError(VE_APM_ERROR);
566 if (audioproc->echo_cancellation()->set_device_sample_rate_hz(48000)) {
567 LOG_FERR1(LS_ERROR, set_device_sample_rate_hz, 48000);
568 return -1;
569 }
570 // Assume 16 kHz mono until the audio frames are received from the capture
571 // device, at which point this can be updated.
572 if (audioproc->set_sample_rate_hz(16000)) {
573 LOG_FERR1(LS_ERROR, set_sample_rate_hz, 16000);
574 return -1;
575 }
576 if (audioproc->set_num_channels(1, 1) != 0) {
577 LOG_FERR2(LS_ERROR, set_num_channels, 1, 1);
578 return -1;
579 }
580 if (audioproc->set_num_reverse_channels(1) != 0) {
581 LOG_FERR1(LS_ERROR, set_num_reverse_channels, 1);
582 return -1;
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000583 }
584
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000585 // Configure AudioProcessing components. All are disabled by default.
586 if (audioproc->high_pass_filter()->Enable(true) != 0) {
587 LOG_FERR1(LS_ERROR, high_pass_filter()->Enable, true);
588 return -1;
589 }
590 if (audioproc->echo_cancellation()->enable_drift_compensation(false) != 0) {
591 LOG_FERR1(LS_ERROR, enable_drift_compensation, false);
592 return -1;
593 }
594 if (audioproc->noise_suppression()->set_level(kDefaultNsMode) != 0) {
595 LOG_FERR1(LS_ERROR, noise_suppression()->set_level, kDefaultNsMode);
596 return -1;
597 }
598 GainControl* agc = audioproc->gain_control();
599 if (agc->set_analog_level_limits(kMinVolumeLevel, kMaxVolumeLevel) != 0) {
600 LOG_FERR2(LS_ERROR, agc->set_analog_level_limits, kMinVolumeLevel,
601 kMaxVolumeLevel);
602 return -1;
603 }
604 if (agc->set_mode(kDefaultAgcMode) != 0) {
605 LOG_FERR1(LS_ERROR, agc->set_mode, kDefaultAgcMode);
606 return -1;
607 }
608 if (agc->Enable(kDefaultAgcState) != 0) {
609 LOG_FERR1(LS_ERROR, agc->Enable, kDefaultAgcState);
610 return -1;
611 }
612 _shared->SetLastError(0); // Clear error state.
613
niklase@google.com470e71d2011-07-07 08:21:25 +0000614#ifdef WEBRTC_VOICE_ENGINE_AGC
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000615 bool agc_enabled = agc->mode() == GainControl::kAdaptiveAnalog &&
616 agc->is_enabled();
617 if (_shared->audio_device()->SetAGC(agc_enabled) != 0) {
618 LOG_FERR1(LS_ERROR, audio_device()->SetAGC, agc_enabled);
619 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR);
andrew@webrtc.orga9a1df02013-03-05 23:36:10 +0000620 // TODO(ajm): No error return here due to
621 // https://code.google.com/p/webrtc/issues/detail?id=1464
niklase@google.com470e71d2011-07-07 08:21:25 +0000622 }
623#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000624
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000625 return _shared->statistics().SetInitialized();
niklase@google.com470e71d2011-07-07 08:21:25 +0000626}
627
628int VoEBaseImpl::Terminate()
629{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000630 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000631 "Terminate()");
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000632 CriticalSectionScoped cs(_shared->crit_sec());
niklase@google.com470e71d2011-07-07 08:21:25 +0000633 return TerminateInternal();
634}
635
636int VoEBaseImpl::MaxNumOfChannels()
637{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000638 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000639 "MaxNumOfChannels()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000640 int32_t maxNumOfChannels =
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000641 _shared->channel_manager().MaxNumOfChannels();
642 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
643 VoEId(_shared->instance_id(), -1),
644 "MaxNumOfChannels() => %d", maxNumOfChannels);
niklase@google.com470e71d2011-07-07 08:21:25 +0000645 return (maxNumOfChannels);
646}
647
648int VoEBaseImpl::CreateChannel()
649{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000650 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000651 "CreateChannel()");
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000652 CriticalSectionScoped cs(_shared->crit_sec());
niklase@google.com470e71d2011-07-07 08:21:25 +0000653
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000654 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000655 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000656 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000657 return -1;
658 }
659
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000660 int32_t channelId = -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000661
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000662 if (!_shared->channel_manager().CreateChannel(channelId))
niklase@google.com470e71d2011-07-07 08:21:25 +0000663 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000664 _shared->SetLastError(VE_CHANNEL_NOT_CREATED, kTraceError,
665 "CreateChannel() failed to allocate memory for channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000666 return -1;
667 }
668
669 bool destroyChannel(false);
670 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000671 voe::ScopedChannel sc(_shared->channel_manager(), channelId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000672 voe::Channel* channelPtr = sc.ChannelPtr();
673 if (channelPtr == NULL)
674 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000675 _shared->SetLastError(VE_CHANNEL_NOT_CREATED, kTraceError,
676 "CreateChannel() failed to allocate memory for channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000677 return -1;
678 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000679 else if (channelPtr->SetEngineInformation(_shared->statistics(),
680 *_shared->output_mixer(),
681 *_shared->transmit_mixer(),
682 *_shared->process_thread(),
683 *_shared->audio_device(),
niklase@google.com470e71d2011-07-07 08:21:25 +0000684 _voiceEngineObserverPtr,
685 &_callbackCritSect) != 0)
686 {
687 destroyChannel = true;
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000688 _shared->SetLastError(VE_CHANNEL_NOT_CREATED, kTraceError,
689 "CreateChannel() failed to associate engine and channel."
690 " Destroying channel.");
niklase@google.com470e71d2011-07-07 08:21:25 +0000691 }
692 else if (channelPtr->Init() != 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 initialize channel. Destroying"
697 " channel.");
niklase@google.com470e71d2011-07-07 08:21:25 +0000698 }
699 }
700 if (destroyChannel)
701 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000702 _shared->channel_manager().DestroyChannel(channelId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000703 return -1;
704 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000705 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
706 VoEId(_shared->instance_id(), -1),
707 "CreateChannel() => %d", channelId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000708 return channelId;
709}
710
711int VoEBaseImpl::DeleteChannel(int channel)
712{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000713 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000714 "DeleteChannel(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000715 CriticalSectionScoped cs(_shared->crit_sec());
niklase@google.com470e71d2011-07-07 08:21:25 +0000716
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000717 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000718 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000719 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000720 return -1;
721 }
722
723 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000724 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000725 voe::Channel* channelPtr = sc.ChannelPtr();
726 if (channelPtr == NULL)
727 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000728 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
729 "DeleteChannel() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000730 return -1;
731 }
732 }
733
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000734 if (_shared->channel_manager().DestroyChannel(channel) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000735 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000736 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
737 "DeleteChannel() failed to destroy channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000738 return -1;
739 }
740
741 if (StopSend() != 0)
742 {
743 return -1;
744 }
745
746 if (StopPlayout() != 0)
747 {
748 return -1;
749 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +0000750
niklase@google.com470e71d2011-07-07 08:21:25 +0000751 return 0;
752}
753
niklase@google.com470e71d2011-07-07 08:21:25 +0000754int VoEBaseImpl::StartReceive(int channel)
755{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000756 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000757 "StartReceive(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000758 CriticalSectionScoped cs(_shared->crit_sec());
759 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000760 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000761 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000762 return -1;
763 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000764 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000765 voe::Channel* channelPtr = sc.ChannelPtr();
766 if (channelPtr == NULL)
767 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000768 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
769 "StartReceive() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000770 return -1;
771 }
772 return channelPtr->StartReceiving();
773}
774
775int VoEBaseImpl::StopReceive(int channel)
776{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000777 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000778 "StopListen(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000779 CriticalSectionScoped cs(_shared->crit_sec());
780 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000781 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000782 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000783 return -1;
784 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000785 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000786 voe::Channel* channelPtr = sc.ChannelPtr();
787 if (channelPtr == NULL)
788 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000789 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
790 "SetLocalReceiver() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000791 return -1;
792 }
793 return channelPtr->StopReceiving();
794}
795
796int VoEBaseImpl::StartPlayout(int channel)
797{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000798 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000799 "StartPlayout(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000800 CriticalSectionScoped cs(_shared->crit_sec());
801 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000802 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000803 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000804 return -1;
805 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000806 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000807 voe::Channel* channelPtr = sc.ChannelPtr();
808 if (channelPtr == NULL)
809 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000810 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
811 "StartPlayout() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000812 return -1;
813 }
814 if (channelPtr->Playing())
815 {
816 return 0;
817 }
818 if (StartPlayout() != 0)
819 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000820 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
821 "StartPlayout() failed to start playout");
niklase@google.com470e71d2011-07-07 08:21:25 +0000822 return -1;
823 }
824 return channelPtr->StartPlayout();
825}
826
827int VoEBaseImpl::StopPlayout(int channel)
828{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000829 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000830 "StopPlayout(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000831 CriticalSectionScoped cs(_shared->crit_sec());
832 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 "StopPlayout() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000843 return -1;
844 }
845 if (channelPtr->StopPlayout() != 0)
846 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000847 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
848 VoEId(_shared->instance_id(), -1),
849 "StopPlayout() failed to stop playout for channel %d", channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000850 }
851 return StopPlayout();
852}
853
854int VoEBaseImpl::StartSend(int channel)
855{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000856 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000857 "StartSend(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000858 CriticalSectionScoped cs(_shared->crit_sec());
859 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000860 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000861 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000862 return -1;
863 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000864 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000865 voe::Channel* channelPtr = sc.ChannelPtr();
866 if (channelPtr == NULL)
867 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000868 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
869 "StartSend() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000870 return -1;
871 }
872 if (channelPtr->Sending())
873 {
874 return 0;
875 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000876 if (StartSend() != 0)
877 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000878 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
879 "StartSend() failed to start recording");
niklase@google.com470e71d2011-07-07 08:21:25 +0000880 return -1;
881 }
882 return channelPtr->StartSend();
883}
884
885int VoEBaseImpl::StopSend(int channel)
886{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000887 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000888 "StopSend(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000889 CriticalSectionScoped cs(_shared->crit_sec());
890 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000891 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000892 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000893 return -1;
894 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000895 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000896 voe::Channel* channelPtr = sc.ChannelPtr();
897 if (channelPtr == NULL)
898 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000899 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
900 "StopSend() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000901 return -1;
902 }
903 if (channelPtr->StopSend() != 0)
904 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000905 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
906 VoEId(_shared->instance_id(), -1),
907 "StopSend() failed to stop sending for channel %d", channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000908 }
909 return StopSend();
910}
911
912int VoEBaseImpl::GetVersion(char version[1024])
913{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000914 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000915 "GetVersion(version=?)");
916 assert(kVoiceEngineVersionMaxMessageSize == 1024);
917
918 if (version == NULL)
919 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000920 _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000921 return (-1);
922 }
923
924 char versionBuf[kVoiceEngineVersionMaxMessageSize];
925 char* versionPtr = versionBuf;
926
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000927 int32_t len = 0;
928 int32_t accLen = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000929
930 len = AddVoEVersion(versionPtr);
931 if (len == -1)
932 {
933 return -1;
934 }
935 versionPtr += len;
936 accLen += len;
937 assert(accLen < kVoiceEngineVersionMaxMessageSize);
938
939 len = AddBuildInfo(versionPtr);
940 if (len == -1)
941 {
942 return -1;
943 }
944 versionPtr += len;
945 accLen += len;
946 assert(accLen < kVoiceEngineVersionMaxMessageSize);
947
pwestin@webrtc.org684f0572013-03-13 23:20:57 +0000948#ifdef WEBRTC_EXTERNAL_TRANSPORT
949 len = AddExternalTransportBuild(versionPtr);
950 if (len == -1)
951 {
952 return -1;
953 }
954 versionPtr += len;
955 accLen += len;
956 assert(accLen < kVoiceEngineVersionMaxMessageSize);
957#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000958#ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT
959 len = AddExternalRecAndPlayoutBuild(versionPtr);
960 if (len == -1)
961 {
962 return -1;
963 }
964 versionPtr += len;
965 accLen += len;
966 assert(accLen < kVoiceEngineVersionMaxMessageSize);
pwestin@webrtc.orgc450a192012-01-04 15:00:12 +0000967 #endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000968
969 memcpy(version, versionBuf, accLen);
970 version[accLen] = '\0';
971
972 // to avoid the truncation in the trace, split the string into parts
973 char partOfVersion[256];
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000974 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
975 VoEId(_shared->instance_id(), -1), "GetVersion() =>");
niklase@google.com470e71d2011-07-07 08:21:25 +0000976 for (int partStart = 0; partStart < accLen;)
977 {
978 memset(partOfVersion, 0, sizeof(partOfVersion));
979 int partEnd = partStart + 180;
980 while (version[partEnd] != '\n' && version[partEnd] != '\0')
981 {
982 partEnd--;
983 }
984 if (partEnd < accLen)
985 {
986 memcpy(partOfVersion, &version[partStart], partEnd - partStart);
987 }
988 else
989 {
990 memcpy(partOfVersion, &version[partStart], accLen - partStart);
991 }
992 partStart = partEnd;
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000993 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
994 VoEId(_shared->instance_id(), -1), "%s", partOfVersion);
niklase@google.com470e71d2011-07-07 08:21:25 +0000995 }
996
997 return 0;
998}
999
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001000int32_t VoEBaseImpl::AddBuildInfo(char* str) const
niklase@google.com470e71d2011-07-07 08:21:25 +00001001{
leozwang@webrtc.org48a5df62012-04-24 14:50:50 +00001002 return sprintf(str, "Build: svn:%s %s\n", WEBRTC_SVNREVISION, BUILDINFO);
niklase@google.com470e71d2011-07-07 08:21:25 +00001003}
1004
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001005int32_t VoEBaseImpl::AddVoEVersion(char* str) const
niklase@google.com470e71d2011-07-07 08:21:25 +00001006{
1007 return sprintf(str, "VoiceEngine 4.1.0\n");
1008}
1009
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001010#ifdef WEBRTC_EXTERNAL_TRANSPORT
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001011int32_t VoEBaseImpl::AddExternalTransportBuild(char* str) const
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001012{
1013 return sprintf(str, "External transport build\n");
1014}
1015#endif
1016
niklase@google.com470e71d2011-07-07 08:21:25 +00001017#ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001018int32_t VoEBaseImpl::AddExternalRecAndPlayoutBuild(char* str) const
niklase@google.com470e71d2011-07-07 08:21:25 +00001019{
1020 return sprintf(str, "External recording and playout build\n");
1021}
1022#endif
1023
niklase@google.com470e71d2011-07-07 08:21:25 +00001024int VoEBaseImpl::LastError()
1025{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001026 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001027 "LastError()");
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001028 return (_shared->statistics().LastError());
niklase@google.com470e71d2011-07-07 08:21:25 +00001029}
1030
1031
1032int VoEBaseImpl::SetNetEQPlayoutMode(int channel, NetEqModes mode)
1033{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001034 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001035 "SetNetEQPlayoutMode(channel=%i, mode=%i)", channel, mode);
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001036 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +00001037 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001038 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +00001039 return -1;
1040 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001041 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +00001042 voe::Channel* channelPtr = sc.ChannelPtr();
1043 if (channelPtr == NULL)
1044 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001045 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
1046 "SetNetEQPlayoutMode() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +00001047 return -1;
1048 }
1049 return channelPtr->SetNetEQPlayoutMode(mode);
1050}
1051
1052int VoEBaseImpl::GetNetEQPlayoutMode(int channel, NetEqModes& mode)
1053{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001054 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001055 "GetNetEQPlayoutMode(channel=%i, mode=?)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001056 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +00001057 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001058 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +00001059 return -1;
1060 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001061 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +00001062 voe::Channel* channelPtr = sc.ChannelPtr();
1063 if (channelPtr == NULL)
1064 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001065 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
1066 "GetNetEQPlayoutMode() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +00001067 return -1;
1068 }
1069 return channelPtr->GetNetEQPlayoutMode(mode);
1070}
1071
niklase@google.com470e71d2011-07-07 08:21:25 +00001072int VoEBaseImpl::SetOnHoldStatus(int channel, bool enable, OnHoldModes mode)
1073{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001074 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001075 "SetOnHoldStatus(channel=%d, enable=%d, mode=%d)", channel,
1076 enable, mode);
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001077 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +00001078 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001079 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +00001080 return -1;
1081 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001082 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +00001083 voe::Channel* channelPtr = sc.ChannelPtr();
1084 if (channelPtr == NULL)
1085 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001086 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
1087 "SetOnHoldStatus() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +00001088 return -1;
1089 }
1090 return channelPtr->SetOnHoldStatus(enable, mode);
1091}
1092
1093int VoEBaseImpl::GetOnHoldStatus(int channel, bool& enabled, OnHoldModes& mode)
1094{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001095 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001096 "GetOnHoldStatus(channel=%d, enabled=?, mode=?)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001097 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +00001098 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001099 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +00001100 return -1;
1101 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001102 voe::ScopedChannel sc(_shared->channel_manager(), channel);
niklase@google.com470e71d2011-07-07 08:21:25 +00001103 voe::Channel* channelPtr = sc.ChannelPtr();
1104 if (channelPtr == NULL)
1105 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001106 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
1107 "GetOnHoldStatus() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +00001108 return -1;
1109 }
1110 return channelPtr->GetOnHoldStatus(enabled, mode);
1111}
1112
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001113int32_t VoEBaseImpl::StartPlayout()
niklase@google.com470e71d2011-07-07 08:21:25 +00001114{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001115 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001116 "VoEBaseImpl::StartPlayout()");
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001117 if (_shared->audio_device()->Playing())
niklase@google.com470e71d2011-07-07 08:21:25 +00001118 {
1119 return 0;
1120 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001121 if (!_shared->ext_playout())
niklase@google.com470e71d2011-07-07 08:21:25 +00001122 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001123 if (_shared->audio_device()->InitPlayout() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001124 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001125 WEBRTC_TRACE(kTraceError, kTraceVoice,
1126 VoEId(_shared->instance_id(), -1),
1127 "StartPlayout() failed to initialize playout");
niklase@google.com470e71d2011-07-07 08:21:25 +00001128 return -1;
1129 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001130 if (_shared->audio_device()->StartPlayout() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001131 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001132 WEBRTC_TRACE(kTraceError, kTraceVoice,
1133 VoEId(_shared->instance_id(), -1),
1134 "StartPlayout() failed to start playout");
niklase@google.com470e71d2011-07-07 08:21:25 +00001135 return -1;
1136 }
1137 }
1138 return 0;
1139}
1140
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001141int32_t VoEBaseImpl::StopPlayout()
niklase@google.com470e71d2011-07-07 08:21:25 +00001142{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001143 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001144 "VoEBaseImpl::StopPlayout()");
1145
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001146 int32_t numOfChannels = _shared->channel_manager().NumOfChannels();
niklase@google.com470e71d2011-07-07 08:21:25 +00001147 if (numOfChannels <= 0)
1148 {
1149 return 0;
1150 }
1151
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001152 uint16_t nChannelsPlaying(0);
1153 int32_t* channelsArray = new int32_t[numOfChannels];
niklase@google.com470e71d2011-07-07 08:21:25 +00001154
1155 // Get number of playing channels
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001156 _shared->channel_manager().GetChannelIds(channelsArray, numOfChannels);
niklase@google.com470e71d2011-07-07 08:21:25 +00001157 for (int i = 0; i < numOfChannels; i++)
1158 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001159 voe::ScopedChannel sc(_shared->channel_manager(), channelsArray[i]);
niklase@google.com470e71d2011-07-07 08:21:25 +00001160 voe::Channel* chPtr = sc.ChannelPtr();
1161 if (chPtr)
1162 {
1163 if (chPtr->Playing())
1164 {
1165 nChannelsPlaying++;
1166 }
1167 }
1168 }
1169 delete[] channelsArray;
1170
1171 // Stop audio-device playing if no channel is playing out
1172 if (nChannelsPlaying == 0)
1173 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001174 if (_shared->audio_device()->StopPlayout() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001175 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001176 _shared->SetLastError(VE_CANNOT_STOP_PLAYOUT, kTraceError,
1177 "StopPlayout() failed to stop playout");
niklase@google.com470e71d2011-07-07 08:21:25 +00001178 return -1;
1179 }
1180 }
1181 return 0;
1182}
1183
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001184int32_t VoEBaseImpl::StartSend()
niklase@google.com470e71d2011-07-07 08:21:25 +00001185{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001186 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001187 "VoEBaseImpl::StartSend()");
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001188 if (_shared->audio_device()->Recording())
niklase@google.com470e71d2011-07-07 08:21:25 +00001189 {
1190 return 0;
1191 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001192 if (!_shared->ext_recording())
niklase@google.com470e71d2011-07-07 08:21:25 +00001193 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001194 if (_shared->audio_device()->InitRecording() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001195 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001196 WEBRTC_TRACE(kTraceError, kTraceVoice,
1197 VoEId(_shared->instance_id(), -1),
1198 "StartSend() failed to initialize recording");
niklase@google.com470e71d2011-07-07 08:21:25 +00001199 return -1;
1200 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001201 if (_shared->audio_device()->StartRecording() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001202 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001203 WEBRTC_TRACE(kTraceError, kTraceVoice,
1204 VoEId(_shared->instance_id(), -1),
1205 "StartSend() failed to start recording");
niklase@google.com470e71d2011-07-07 08:21:25 +00001206 return -1;
1207 }
1208 }
1209
1210 return 0;
1211}
1212
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001213int32_t VoEBaseImpl::StopSend()
niklase@google.com470e71d2011-07-07 08:21:25 +00001214{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001215 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001216 "VoEBaseImpl::StopSend()");
1217
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001218 if (_shared->NumOfSendingChannels() == 0 &&
1219 !_shared->transmit_mixer()->IsRecordingMic())
niklase@google.com470e71d2011-07-07 08:21:25 +00001220 {
1221 // Stop audio-device recording if no channel is recording
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001222 if (_shared->audio_device()->StopRecording() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001223 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001224 _shared->SetLastError(VE_CANNOT_STOP_RECORDING, kTraceError,
1225 "StopSend() failed to stop recording");
niklase@google.com470e71d2011-07-07 08:21:25 +00001226 return -1;
1227 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001228 _shared->transmit_mixer()->StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +00001229 }
1230
1231 return 0;
1232}
1233
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001234int32_t VoEBaseImpl::TerminateInternal()
niklase@google.com470e71d2011-07-07 08:21:25 +00001235{
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001236 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +00001237 "VoEBaseImpl::TerminateInternal()");
1238
1239 // Delete any remaining channel objects
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001240 int32_t numOfChannels = _shared->channel_manager().NumOfChannels();
niklase@google.com470e71d2011-07-07 08:21:25 +00001241 if (numOfChannels > 0)
1242 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001243 int32_t* channelsArray = new int32_t[numOfChannels];
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001244 _shared->channel_manager().GetChannelIds(channelsArray, numOfChannels);
niklase@google.com470e71d2011-07-07 08:21:25 +00001245 for (int i = 0; i < numOfChannels; i++)
1246 {
1247 DeleteChannel(channelsArray[i]);
1248 }
1249 delete[] channelsArray;
1250 }
1251
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001252 if (_shared->process_thread())
niklase@google.com470e71d2011-07-07 08:21:25 +00001253 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001254 if (_shared->audio_device())
niklase@google.com470e71d2011-07-07 08:21:25 +00001255 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001256 if (_shared->process_thread()->
1257 DeRegisterModule(_shared->audio_device()) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001258 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001259 _shared->SetLastError(VE_THREAD_ERROR, kTraceError,
1260 "TerminateInternal() failed to deregister ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +00001261 }
1262 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001263 if (_shared->process_thread()->Stop() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001264 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001265 _shared->SetLastError(VE_THREAD_ERROR, kTraceError,
1266 "TerminateInternal() failed to stop module process thread");
niklase@google.com470e71d2011-07-07 08:21:25 +00001267 }
1268 }
1269
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +00001270 if (_shared->audio_device())
niklase@google.com470e71d2011-07-07 08:21:25 +00001271 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001272 if (_shared->audio_device()->StopPlayout() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001273 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001274 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
1275 "TerminateInternal() failed to stop playout");
niklase@google.com470e71d2011-07-07 08:21:25 +00001276 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001277 if (_shared->audio_device()->StopRecording() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001278 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001279 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
1280 "TerminateInternal() failed to stop recording");
niklase@google.com470e71d2011-07-07 08:21:25 +00001281 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001282 if (_shared->audio_device()->RegisterEventObserver(NULL) != 0) {
1283 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
1284 "TerminateInternal() failed to de-register event observer "
1285 "for the ADM");
xians@webrtc.org79af7342012-01-31 12:22:14 +00001286 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001287 if (_shared->audio_device()->RegisterAudioCallback(NULL) != 0) {
1288 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
1289 "TerminateInternal() failed to de-register audio callback "
1290 "for the ADM");
xians@webrtc.org79af7342012-01-31 12:22:14 +00001291 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001292 if (_shared->audio_device()->Terminate() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001293 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001294 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
1295 "TerminateInternal() failed to terminate the ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +00001296 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001297 _shared->set_audio_device(NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +00001298 }
1299
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +00001300 if (_shared->audio_processing()) {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001301 _shared->set_audio_processing(NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +00001302 }
1303
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001304 return _shared->statistics().SetUnInitialized();
niklase@google.com470e71d2011-07-07 08:21:25 +00001305}
1306
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00001307} // namespace webrtc