blob: 1b14be72f40fff64da8ff84fc1f1d12f9c076799 [file] [log] [blame]
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001/*
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "voe_base_impl.h"
12
13#include "audio_coding_module.h"
14#include "audio_processing.h"
15#include "channel.h"
16#include "critical_section_wrapper.h"
17#include "file_wrapper.h"
18#include "modules/audio_device/audio_device_impl.h"
19#include "output_mixer.h"
20#include "signal_processing_library.h"
21#include "trace.h"
22#include "transmit_mixer.h"
23#include "utility.h"
24#include "voe_errors.h"
25#include "voice_engine_impl.h"
26
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.orgb9e5a3d2013-02-15 15:07:32 +000043 VoiceEngineImpl* s = static_cast<VoiceEngineImpl*>(voiceEngine);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000044 s->AddRef();
45 return s;
46}
47
48VoEBaseImpl::VoEBaseImpl(voe::SharedData* shared) :
49 _voiceEngineObserverPtr(NULL),
50 _callbackCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
51 _voiceEngineObserver(false), _oldVoEMicLevel(0), _oldMicLevel(0),
52 _shared(shared)
53{
54 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
55 "VoEBaseImpl() - ctor");
56}
57
58VoEBaseImpl::~VoEBaseImpl()
59{
60 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
61 "~VoEBaseImpl() - dtor");
62
63 TerminateInternal();
64
65 delete &_callbackCritSect;
66}
67
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +000068void VoEBaseImpl::OnErrorIsReported(ErrorCode error)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000069{
70 CriticalSectionScoped cs(&_callbackCritSect);
71 if (_voiceEngineObserver)
72 {
73 if (_voiceEngineObserverPtr)
74 {
75 int errCode(0);
76 if (error == AudioDeviceObserver::kRecordingError)
77 {
78 errCode = VE_RUNTIME_REC_ERROR;
79 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
80 VoEId(_shared->instance_id(), -1),
81 "VoEBaseImpl::OnErrorIsReported() => VE_RUNTIME_REC_ERROR");
82 }
83 else if (error == AudioDeviceObserver::kPlayoutError)
84 {
85 errCode = VE_RUNTIME_PLAY_ERROR;
86 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
87 VoEId(_shared->instance_id(), -1),
88 "VoEBaseImpl::OnErrorIsReported() => "
89 "VE_RUNTIME_PLAY_ERROR");
90 }
91 // Deliver callback (-1 <=> no channel dependency)
92 _voiceEngineObserverPtr->CallbackOnError(-1, errCode);
93 }
94 }
95}
96
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +000097void VoEBaseImpl::OnWarningIsReported(WarningCode warning)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000098{
99 CriticalSectionScoped cs(&_callbackCritSect);
100 if (_voiceEngineObserver)
101 {
102 if (_voiceEngineObserverPtr)
103 {
104 int warningCode(0);
105 if (warning == AudioDeviceObserver::kRecordingWarning)
106 {
107 warningCode = VE_RUNTIME_REC_WARNING;
108 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
109 VoEId(_shared->instance_id(), -1),
110 "VoEBaseImpl::OnErrorIsReported() => "
111 "VE_RUNTIME_REC_WARNING");
112 }
113 else if (warning == AudioDeviceObserver::kPlayoutWarning)
114 {
115 warningCode = VE_RUNTIME_PLAY_WARNING;
116 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
117 VoEId(_shared->instance_id(), -1),
118 "VoEBaseImpl::OnErrorIsReported() => "
119 "VE_RUNTIME_PLAY_WARNING");
120 }
121 // Deliver callback (-1 <=> no channel dependency)
122 _voiceEngineObserverPtr->CallbackOnError(-1, warningCode);
123 }
124 }
125}
126
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000127int32_t VoEBaseImpl::RecordedDataIsAvailable(
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000128 const void* audioSamples,
pbos@webrtc.orgca7a9a22013-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.org54f03bc2013-04-09 10:09:10 +0000137 uint32_t& newMicLevel)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000138{
139 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_shared->instance_id(), -1),
140 "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
146 assert(_shared->transmit_mixer() != NULL);
147 assert(_shared->audio_device() != NULL);
148
149 bool isAnalogAGC(false);
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000150 uint32_t maxVolume(0);
151 uint16_t currentVoEMicLevel(0);
152 uint32_t newVoEMicLevel(0);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000153
154 if (_shared->audio_processing() &&
155 (_shared->audio_processing()->gain_control()->mode()
156 == 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
165 if (_shared->audio_device()->MaxMicrophoneVolume(&maxVolume) == 0)
166 {
167 if (0 != maxVolume)
168 {
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000169 currentVoEMicLevel = (uint16_t) ((currentMicLevel
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000170 * kMaxVolumeLevel + (int) (maxVolume / 2))
171 / (maxVolume));
172 }
173 }
174 // 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
177 // and change the maxVolume to currentMicLevel if it turns out that
178 // the currentVoEMicLevel is indeed greater than the maxVolumeLevel.
179 if (currentVoEMicLevel > kMaxVolumeLevel)
180 {
181 currentVoEMicLevel = kMaxVolumeLevel;
182 maxVolume = currentMicLevel;
183 }
184 }
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.org54f03bc2013-04-09 10:09:10 +0000192 currentVoEMicLevel = (uint16_t) _oldVoEMicLevel;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000193 }
194
195 // Perform channel-independent operations
196 // (APM, mix with file, record to file, mute, etc.)
197 _shared->transmit_mixer()->PrepareDemux(audioSamples, nSamples, nChannels,
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000198 samplesPerSec, static_cast<uint16_t>(totalDelayMS), clockDrift,
niklas.enbom@webrtc.org28832e12013-05-07 21:04:24 +0000199 currentVoEMicLevel, keyPressed);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +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.
204 _shared->transmit_mixer()->DemuxAndMix();
205 // Do the encoding and packetize+transmit the RTP packet when encoding
206 // is done.
207 _shared->transmit_mixer()->EncodeAndSend();
208
209 // Will only deal with the volume in adaptive analog mode
210 if (isAnalogAGC)
211 {
212 // Scale from VoE to ADM level range
213 newVoEMicLevel = _shared->transmit_mixer()->CaptureLevel();
214 if (newVoEMicLevel != currentVoEMicLevel)
215 {
216 // Add (kMaxVolumeLevel/2) to round the value
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000217 newMicLevel = (uint32_t) ((newVoEMicLevel * maxVolume
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +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.org54f03bc2013-04-09 10:09:10 +0000234int32_t VoEBaseImpl::NeedMorePlayData(
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +0000235 uint32_t nSamples,
236 uint8_t nBytesPerSample,
237 uint8_t nChannels,
238 uint32_t samplesPerSec,
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000239 void* audioSamples,
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000240 uint32_t& nSamplesOut)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000241{
242 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_shared->instance_id(), -1),
243 "VoEBaseImpl::NeedMorePlayData(nSamples=%u, "
244 "nBytesPerSample=%d, nChannels=%d, samplesPerSec=%u)",
245 nSamples, nBytesPerSample, nChannels, samplesPerSec);
246
247 assert(_shared->output_mixer() != NULL);
248
249 // 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.
251 // Perform mixing of all active participants (channel-based mixing)
252 _shared->output_mixer()->MixActiveChannels();
253
254 // Additional operations on the combined signal
255 _shared->output_mixer()->DoOperationsOnCombinedSignal();
256
257 // Retrieve the final output mix (resampled to match the ADM)
258 _shared->output_mixer()->GetMixedAudio(samplesPerSec, nChannels,
259 &_audioFrame);
260
261 assert(static_cast<int>(nSamples) == _audioFrame.samples_per_channel_);
262 assert(samplesPerSec ==
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000263 static_cast<uint32_t>(_audioFrame.sample_rate_hz_));
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000264
265 // Deliver audio (PCM) samples to the ADM
266 memcpy(
pbos@webrtc.org54f03bc2013-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.orgb015cbe2012-10-22 18:19:23 +0000270 * _audioFrame.num_channels_));
271
272 nSamplesOut = _audioFrame.samples_per_channel_;
273
274 return 0;
275}
276
277int VoEBaseImpl::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
278{
279 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
280 "RegisterVoiceEngineObserver(observer=0x%d)", &observer);
281 CriticalSectionScoped cs(&_callbackCritSect);
282 if (_voiceEngineObserverPtr)
283 {
284 _shared->SetLastError(VE_INVALID_OPERATION, kTraceError,
285 "RegisterVoiceEngineObserver() observer already enabled");
286 return -1;
287 }
288
289 // Register the observer in all active channels
290 voe::ScopedChannel sc(_shared->channel_manager());
291 void* iterator(NULL);
292 voe::Channel* channelPtr = sc.GetFirstChannel(iterator);
293 while (channelPtr != NULL)
294 {
295 channelPtr->RegisterVoiceEngineObserver(observer);
296 channelPtr = sc.GetNextChannel(iterator);
297 }
298 _shared->transmit_mixer()->RegisterVoiceEngineObserver(observer);
299
300 _voiceEngineObserverPtr = &observer;
301 _voiceEngineObserver = true;
302
303 return 0;
304}
305
306int VoEBaseImpl::DeRegisterVoiceEngineObserver()
307{
308 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
309 "DeRegisterVoiceEngineObserver()");
310 CriticalSectionScoped cs(&_callbackCritSect);
311 if (!_voiceEngineObserverPtr)
312 {
313 _shared->SetLastError(VE_INVALID_OPERATION, kTraceError,
314 "DeRegisterVoiceEngineObserver() observer already disabled");
315 return 0;
316 }
317
318 _voiceEngineObserver = false;
319 _voiceEngineObserverPtr = NULL;
320
321 // Deregister the observer in all active channels
322 voe::ScopedChannel sc(_shared->channel_manager());
323 void* iterator(NULL);
324 voe::Channel* channelPtr = sc.GetFirstChannel(iterator);
325 while (channelPtr != NULL)
326 {
327 channelPtr->DeRegisterVoiceEngineObserver();
328 channelPtr = sc.GetNextChannel(iterator);
329 }
330
331 return 0;
332}
333
andrew@webrtc.orgb79627b2013-03-05 01:12:49 +0000334int VoEBaseImpl::Init(AudioDeviceModule* external_adm,
335 AudioProcessing* audioproc)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000336{
337 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
338 "Init(external_adm=0x%p)", external_adm);
339 CriticalSectionScoped cs(_shared->crit_sec());
340
341 WebRtcSpl_Init();
342
343 if (_shared->statistics().Initialized())
344 {
345 return 0;
346 }
347
348 if (_shared->process_thread())
349 {
350 if (_shared->process_thread()->Start() != 0)
351 {
352 _shared->SetLastError(VE_THREAD_ERROR, kTraceError,
353 "Init() failed to start module process thread");
354 return -1;
355 }
356 }
357
358 // Create an internal ADM if the user has not added an external
359 // ADM implementation as input to Init().
360 if (external_adm == NULL)
361 {
362 // Create the internal ADM implementation.
363 _shared->set_audio_device(AudioDeviceModuleImpl::Create(
364 VoEId(_shared->instance_id(), -1), _shared->audio_device_layer()));
365
366 if (_shared->audio_device() == NULL)
367 {
368 _shared->SetLastError(VE_NO_MEMORY, kTraceCritical,
369 "Init() failed to create the ADM");
370 return -1;
371 }
372 }
373 else
374 {
375 // Use the already existing external ADM implementation.
376 _shared->set_audio_device(external_adm);
377 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
378 "An external ADM implementation will be used in VoiceEngine");
379 }
380
381 // Register the ADM to the process thread, which will drive the error
382 // callback mechanism
383 if (_shared->process_thread() &&
384 _shared->process_thread()->RegisterModule(_shared->audio_device()) != 0)
385 {
386 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
387 "Init() failed to register the ADM");
388 return -1;
389 }
390
391 bool available(false);
392
393 // --------------------
394 // Reinitialize the ADM
395
396 // Register the AudioObserver implementation
397 if (_shared->audio_device()->RegisterEventObserver(this) != 0) {
398 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
399 "Init() failed to register event observer for the ADM");
400 }
401
402 // Register the AudioTransport implementation
403 if (_shared->audio_device()->RegisterAudioCallback(this) != 0) {
404 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
405 "Init() failed to register audio callback for the ADM");
406 }
407
408 // ADM initialization
409 if (_shared->audio_device()->Init() != 0)
410 {
411 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
412 "Init() failed to initialize the ADM");
413 return -1;
414 }
415
416 // Initialize the default speaker
417 if (_shared->audio_device()->SetPlayoutDevice(
418 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0)
419 {
420 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceInfo,
421 "Init() failed to set the default output device");
422 }
423 if (_shared->audio_device()->SpeakerIsAvailable(&available) != 0)
424 {
425 _shared->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceInfo,
426 "Init() failed to check speaker availability, trying to "
427 "initialize speaker anyway");
428 }
429 else if (!available)
430 {
431 _shared->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceInfo,
432 "Init() speaker not available, trying to initialize speaker "
433 "anyway");
434 }
435 if (_shared->audio_device()->InitSpeaker() != 0)
436 {
437 _shared->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceInfo,
438 "Init() failed to initialize the speaker");
439 }
440
441 // Initialize the default microphone
442 if (_shared->audio_device()->SetRecordingDevice(
443 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0)
444 {
445 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceInfo,
446 "Init() failed to set the default input device");
447 }
448 if (_shared->audio_device()->MicrophoneIsAvailable(&available) != 0)
449 {
450 _shared->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceInfo,
451 "Init() failed to check microphone availability, trying to "
452 "initialize microphone anyway");
453 }
454 else if (!available)
455 {
456 _shared->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceInfo,
457 "Init() microphone not available, trying to initialize "
458 "microphone anyway");
459 }
460 if (_shared->audio_device()->InitMicrophone() != 0)
461 {
462 _shared->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceInfo,
463 "Init() failed to initialize the microphone");
464 }
465
466 // Set number of channels
467 if (_shared->audio_device()->StereoPlayoutIsAvailable(&available) != 0) {
468 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
469 "Init() failed to query stereo playout mode");
470 }
471 if (_shared->audio_device()->SetStereoPlayout(available) != 0)
472 {
473 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
474 "Init() failed to set mono/stereo playout mode");
475 }
476
477 // TODO(andrew): These functions don't tell us whether stereo recording
478 // is truly available. We simply set the AudioProcessing input to stereo
479 // here, because we have to wait until receiving the first frame to
480 // determine the actual number of channels anyway.
481 //
482 // These functions may be changed; tracked here:
483 // http://code.google.com/p/webrtc/issues/detail?id=204
484 _shared->audio_device()->StereoRecordingIsAvailable(&available);
485 if (_shared->audio_device()->SetStereoRecording(available) != 0)
486 {
487 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
488 "Init() failed to set mono/stereo recording mode");
489 }
490
andrew@webrtc.orgb79627b2013-03-05 01:12:49 +0000491 if (!audioproc) {
492 audioproc = AudioProcessing::Create(VoEId(_shared->instance_id(), -1));
493 if (!audioproc) {
494 LOG(LS_ERROR) << "Failed to create AudioProcessing.";
495 _shared->SetLastError(VE_NO_MEMORY);
496 return -1;
497 }
498 }
499 _shared->set_audio_processing(audioproc);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000500
andrew@webrtc.orgb79627b2013-03-05 01:12:49 +0000501 // Set the error state for any failures in this block.
502 _shared->SetLastError(VE_APM_ERROR);
503 if (audioproc->echo_cancellation()->set_device_sample_rate_hz(48000)) {
504 LOG_FERR1(LS_ERROR, set_device_sample_rate_hz, 48000);
505 return -1;
506 }
507 // Assume 16 kHz mono until the audio frames are received from the capture
508 // device, at which point this can be updated.
509 if (audioproc->set_sample_rate_hz(16000)) {
510 LOG_FERR1(LS_ERROR, set_sample_rate_hz, 16000);
511 return -1;
512 }
513 if (audioproc->set_num_channels(1, 1) != 0) {
514 LOG_FERR2(LS_ERROR, set_num_channels, 1, 1);
515 return -1;
516 }
517 if (audioproc->set_num_reverse_channels(1) != 0) {
518 LOG_FERR1(LS_ERROR, set_num_reverse_channels, 1);
519 return -1;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000520 }
521
andrew@webrtc.orgb79627b2013-03-05 01:12:49 +0000522 // Configure AudioProcessing components. All are disabled by default.
523 if (audioproc->high_pass_filter()->Enable(true) != 0) {
524 LOG_FERR1(LS_ERROR, high_pass_filter()->Enable, true);
525 return -1;
526 }
527 if (audioproc->echo_cancellation()->enable_drift_compensation(false) != 0) {
528 LOG_FERR1(LS_ERROR, enable_drift_compensation, false);
529 return -1;
530 }
531 if (audioproc->noise_suppression()->set_level(kDefaultNsMode) != 0) {
532 LOG_FERR1(LS_ERROR, noise_suppression()->set_level, kDefaultNsMode);
533 return -1;
534 }
535 GainControl* agc = audioproc->gain_control();
536 if (agc->set_analog_level_limits(kMinVolumeLevel, kMaxVolumeLevel) != 0) {
537 LOG_FERR2(LS_ERROR, agc->set_analog_level_limits, kMinVolumeLevel,
538 kMaxVolumeLevel);
539 return -1;
540 }
541 if (agc->set_mode(kDefaultAgcMode) != 0) {
542 LOG_FERR1(LS_ERROR, agc->set_mode, kDefaultAgcMode);
543 return -1;
544 }
545 if (agc->Enable(kDefaultAgcState) != 0) {
546 LOG_FERR1(LS_ERROR, agc->Enable, kDefaultAgcState);
547 return -1;
548 }
549 _shared->SetLastError(0); // Clear error state.
550
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000551#ifdef WEBRTC_VOICE_ENGINE_AGC
andrew@webrtc.orgb79627b2013-03-05 01:12:49 +0000552 bool agc_enabled = agc->mode() == GainControl::kAdaptiveAnalog &&
553 agc->is_enabled();
554 if (_shared->audio_device()->SetAGC(agc_enabled) != 0) {
555 LOG_FERR1(LS_ERROR, audio_device()->SetAGC, agc_enabled);
556 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR);
andrew@webrtc.org0f919be2013-03-05 23:36:10 +0000557 // TODO(ajm): No error return here due to
558 // https://code.google.com/p/webrtc/issues/detail?id=1464
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000559 }
560#endif
561
562 return _shared->statistics().SetInitialized();
563}
564
565int VoEBaseImpl::Terminate()
566{
567 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
568 "Terminate()");
569 CriticalSectionScoped cs(_shared->crit_sec());
570 return TerminateInternal();
571}
572
573int VoEBaseImpl::MaxNumOfChannels()
574{
575 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
576 "MaxNumOfChannels()");
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000577 int32_t maxNumOfChannels =
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000578 _shared->channel_manager().MaxNumOfChannels();
579 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
580 VoEId(_shared->instance_id(), -1),
581 "MaxNumOfChannels() => %d", maxNumOfChannels);
582 return (maxNumOfChannels);
583}
584
585int VoEBaseImpl::CreateChannel()
586{
587 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
588 "CreateChannel()");
589 CriticalSectionScoped cs(_shared->crit_sec());
590
591 if (!_shared->statistics().Initialized())
592 {
593 _shared->SetLastError(VE_NOT_INITED, kTraceError);
594 return -1;
595 }
596
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000597 int32_t channelId = -1;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000598
599 if (!_shared->channel_manager().CreateChannel(channelId))
600 {
601 _shared->SetLastError(VE_CHANNEL_NOT_CREATED, kTraceError,
602 "CreateChannel() failed to allocate memory for channel");
603 return -1;
604 }
605
606 bool destroyChannel(false);
607 {
608 voe::ScopedChannel sc(_shared->channel_manager(), channelId);
609 voe::Channel* channelPtr = sc.ChannelPtr();
610 if (channelPtr == NULL)
611 {
612 _shared->SetLastError(VE_CHANNEL_NOT_CREATED, kTraceError,
613 "CreateChannel() failed to allocate memory for channel");
614 return -1;
615 }
616 else if (channelPtr->SetEngineInformation(_shared->statistics(),
617 *_shared->output_mixer(),
618 *_shared->transmit_mixer(),
619 *_shared->process_thread(),
620 *_shared->audio_device(),
621 _voiceEngineObserverPtr,
622 &_callbackCritSect) != 0)
623 {
624 destroyChannel = true;
625 _shared->SetLastError(VE_CHANNEL_NOT_CREATED, kTraceError,
626 "CreateChannel() failed to associate engine and channel."
627 " Destroying channel.");
628 }
629 else if (channelPtr->Init() != 0)
630 {
631 destroyChannel = true;
632 _shared->SetLastError(VE_CHANNEL_NOT_CREATED, kTraceError,
633 "CreateChannel() failed to initialize channel. Destroying"
634 " channel.");
635 }
636 }
637 if (destroyChannel)
638 {
639 _shared->channel_manager().DestroyChannel(channelId);
640 return -1;
641 }
642 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
643 VoEId(_shared->instance_id(), -1),
644 "CreateChannel() => %d", channelId);
645 return channelId;
646}
647
648int VoEBaseImpl::DeleteChannel(int channel)
649{
650 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
651 "DeleteChannel(channel=%d)", channel);
652 CriticalSectionScoped cs(_shared->crit_sec());
653
654 if (!_shared->statistics().Initialized())
655 {
656 _shared->SetLastError(VE_NOT_INITED, kTraceError);
657 return -1;
658 }
659
660 {
661 voe::ScopedChannel sc(_shared->channel_manager(), channel);
662 voe::Channel* channelPtr = sc.ChannelPtr();
663 if (channelPtr == NULL)
664 {
665 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
666 "DeleteChannel() failed to locate channel");
667 return -1;
668 }
669 }
670
671 if (_shared->channel_manager().DestroyChannel(channel) != 0)
672 {
673 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
674 "DeleteChannel() failed to destroy channel");
675 return -1;
676 }
677
678 if (StopSend() != 0)
679 {
680 return -1;
681 }
682
683 if (StopPlayout() != 0)
684 {
685 return -1;
686 }
pwestin@webrtc.org912b7f72013-03-13 23:20:57 +0000687
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000688 return 0;
689}
690
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000691int VoEBaseImpl::StartReceive(int channel)
692{
693 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
694 "StartReceive(channel=%d)", channel);
695 CriticalSectionScoped cs(_shared->crit_sec());
696 if (!_shared->statistics().Initialized())
697 {
698 _shared->SetLastError(VE_NOT_INITED, kTraceError);
699 return -1;
700 }
701 voe::ScopedChannel sc(_shared->channel_manager(), channel);
702 voe::Channel* channelPtr = sc.ChannelPtr();
703 if (channelPtr == NULL)
704 {
705 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
706 "StartReceive() failed to locate channel");
707 return -1;
708 }
709 return channelPtr->StartReceiving();
710}
711
712int VoEBaseImpl::StopReceive(int channel)
713{
714 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
715 "StopListen(channel=%d)", channel);
716 CriticalSectionScoped cs(_shared->crit_sec());
717 if (!_shared->statistics().Initialized())
718 {
719 _shared->SetLastError(VE_NOT_INITED, kTraceError);
720 return -1;
721 }
722 voe::ScopedChannel sc(_shared->channel_manager(), channel);
723 voe::Channel* channelPtr = sc.ChannelPtr();
724 if (channelPtr == NULL)
725 {
726 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
727 "SetLocalReceiver() failed to locate channel");
728 return -1;
729 }
730 return channelPtr->StopReceiving();
731}
732
733int VoEBaseImpl::StartPlayout(int channel)
734{
735 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
736 "StartPlayout(channel=%d)", channel);
737 CriticalSectionScoped cs(_shared->crit_sec());
738 if (!_shared->statistics().Initialized())
739 {
740 _shared->SetLastError(VE_NOT_INITED, kTraceError);
741 return -1;
742 }
743 voe::ScopedChannel sc(_shared->channel_manager(), channel);
744 voe::Channel* channelPtr = sc.ChannelPtr();
745 if (channelPtr == NULL)
746 {
747 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
748 "StartPlayout() failed to locate channel");
749 return -1;
750 }
751 if (channelPtr->Playing())
752 {
753 return 0;
754 }
755 if (StartPlayout() != 0)
756 {
757 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
758 "StartPlayout() failed to start playout");
759 return -1;
760 }
761 return channelPtr->StartPlayout();
762}
763
764int VoEBaseImpl::StopPlayout(int channel)
765{
766 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
767 "StopPlayout(channel=%d)", channel);
768 CriticalSectionScoped cs(_shared->crit_sec());
769 if (!_shared->statistics().Initialized())
770 {
771 _shared->SetLastError(VE_NOT_INITED, kTraceError);
772 return -1;
773 }
774 voe::ScopedChannel sc(_shared->channel_manager(), channel);
775 voe::Channel* channelPtr = sc.ChannelPtr();
776 if (channelPtr == NULL)
777 {
778 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
779 "StopPlayout() failed to locate channel");
780 return -1;
781 }
782 if (channelPtr->StopPlayout() != 0)
783 {
784 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
785 VoEId(_shared->instance_id(), -1),
786 "StopPlayout() failed to stop playout for channel %d", channel);
787 }
788 return StopPlayout();
789}
790
791int VoEBaseImpl::StartSend(int channel)
792{
793 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
794 "StartSend(channel=%d)", channel);
795 CriticalSectionScoped cs(_shared->crit_sec());
796 if (!_shared->statistics().Initialized())
797 {
798 _shared->SetLastError(VE_NOT_INITED, kTraceError);
799 return -1;
800 }
801 voe::ScopedChannel sc(_shared->channel_manager(), channel);
802 voe::Channel* channelPtr = sc.ChannelPtr();
803 if (channelPtr == NULL)
804 {
805 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
806 "StartSend() failed to locate channel");
807 return -1;
808 }
809 if (channelPtr->Sending())
810 {
811 return 0;
812 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000813 if (StartSend() != 0)
814 {
815 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
816 "StartSend() failed to start recording");
817 return -1;
818 }
819 return channelPtr->StartSend();
820}
821
822int VoEBaseImpl::StopSend(int channel)
823{
824 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
825 "StopSend(channel=%d)", channel);
826 CriticalSectionScoped cs(_shared->crit_sec());
827 if (!_shared->statistics().Initialized())
828 {
829 _shared->SetLastError(VE_NOT_INITED, kTraceError);
830 return -1;
831 }
832 voe::ScopedChannel sc(_shared->channel_manager(), channel);
833 voe::Channel* channelPtr = sc.ChannelPtr();
834 if (channelPtr == NULL)
835 {
836 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
837 "StopSend() failed to locate channel");
838 return -1;
839 }
840 if (channelPtr->StopSend() != 0)
841 {
842 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
843 VoEId(_shared->instance_id(), -1),
844 "StopSend() failed to stop sending for channel %d", channel);
845 }
846 return StopSend();
847}
848
849int VoEBaseImpl::GetVersion(char version[1024])
850{
851 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
852 "GetVersion(version=?)");
853 assert(kVoiceEngineVersionMaxMessageSize == 1024);
854
855 if (version == NULL)
856 {
857 _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError);
858 return (-1);
859 }
860
861 char versionBuf[kVoiceEngineVersionMaxMessageSize];
862 char* versionPtr = versionBuf;
863
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000864 int32_t len = 0;
865 int32_t accLen = 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000866
867 len = AddVoEVersion(versionPtr);
868 if (len == -1)
869 {
870 return -1;
871 }
872 versionPtr += len;
873 accLen += len;
874 assert(accLen < kVoiceEngineVersionMaxMessageSize);
875
876 len = AddBuildInfo(versionPtr);
877 if (len == -1)
878 {
879 return -1;
880 }
881 versionPtr += len;
882 accLen += len;
883 assert(accLen < kVoiceEngineVersionMaxMessageSize);
884
pwestin@webrtc.org912b7f72013-03-13 23:20:57 +0000885#ifdef WEBRTC_EXTERNAL_TRANSPORT
886 len = AddExternalTransportBuild(versionPtr);
887 if (len == -1)
888 {
889 return -1;
890 }
891 versionPtr += len;
892 accLen += len;
893 assert(accLen < kVoiceEngineVersionMaxMessageSize);
894#endif
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000895#ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT
896 len = AddExternalRecAndPlayoutBuild(versionPtr);
897 if (len == -1)
898 {
899 return -1;
900 }
901 versionPtr += len;
902 accLen += len;
903 assert(accLen < kVoiceEngineVersionMaxMessageSize);
904 #endif
905
906 memcpy(version, versionBuf, accLen);
907 version[accLen] = '\0';
908
909 // to avoid the truncation in the trace, split the string into parts
910 char partOfVersion[256];
911 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
912 VoEId(_shared->instance_id(), -1), "GetVersion() =>");
913 for (int partStart = 0; partStart < accLen;)
914 {
915 memset(partOfVersion, 0, sizeof(partOfVersion));
916 int partEnd = partStart + 180;
917 while (version[partEnd] != '\n' && version[partEnd] != '\0')
918 {
919 partEnd--;
920 }
921 if (partEnd < accLen)
922 {
923 memcpy(partOfVersion, &version[partStart], partEnd - partStart);
924 }
925 else
926 {
927 memcpy(partOfVersion, &version[partStart], accLen - partStart);
928 }
929 partStart = partEnd;
930 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
931 VoEId(_shared->instance_id(), -1), "%s", partOfVersion);
932 }
933
934 return 0;
935}
936
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000937int32_t VoEBaseImpl::AddBuildInfo(char* str) const
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000938{
939 return sprintf(str, "Build: svn:%s %s\n", WEBRTC_SVNREVISION, BUILDINFO);
940}
941
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000942int32_t VoEBaseImpl::AddVoEVersion(char* str) const
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000943{
944 return sprintf(str, "VoiceEngine 4.1.0\n");
945}
946
pwestin@webrtc.org912b7f72013-03-13 23:20:57 +0000947#ifdef WEBRTC_EXTERNAL_TRANSPORT
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000948int32_t VoEBaseImpl::AddExternalTransportBuild(char* str) const
pwestin@webrtc.org912b7f72013-03-13 23:20:57 +0000949{
950 return sprintf(str, "External transport build\n");
951}
952#endif
953
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000954#ifdef WEBRTC_VOE_EXTERNAL_REC_AND_PLAYOUT
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000955int32_t VoEBaseImpl::AddExternalRecAndPlayoutBuild(char* str) const
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000956{
957 return sprintf(str, "External recording and playout build\n");
958}
959#endif
960
961int VoEBaseImpl::LastError()
962{
963 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
964 "LastError()");
965 return (_shared->statistics().LastError());
966}
967
968
969int VoEBaseImpl::SetNetEQPlayoutMode(int channel, NetEqModes mode)
970{
971 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
972 "SetNetEQPlayoutMode(channel=%i, mode=%i)", channel, mode);
973 if (!_shared->statistics().Initialized())
974 {
975 _shared->SetLastError(VE_NOT_INITED, kTraceError);
976 return -1;
977 }
978 voe::ScopedChannel sc(_shared->channel_manager(), channel);
979 voe::Channel* channelPtr = sc.ChannelPtr();
980 if (channelPtr == NULL)
981 {
982 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
983 "SetNetEQPlayoutMode() failed to locate channel");
984 return -1;
985 }
986 return channelPtr->SetNetEQPlayoutMode(mode);
987}
988
989int VoEBaseImpl::GetNetEQPlayoutMode(int channel, NetEqModes& mode)
990{
991 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
992 "GetNetEQPlayoutMode(channel=%i, mode=?)", channel);
993 if (!_shared->statistics().Initialized())
994 {
995 _shared->SetLastError(VE_NOT_INITED, kTraceError);
996 return -1;
997 }
998 voe::ScopedChannel sc(_shared->channel_manager(), channel);
999 voe::Channel* channelPtr = sc.ChannelPtr();
1000 if (channelPtr == NULL)
1001 {
1002 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
1003 "GetNetEQPlayoutMode() failed to locate channel");
1004 return -1;
1005 }
1006 return channelPtr->GetNetEQPlayoutMode(mode);
1007}
1008
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001009int VoEBaseImpl::SetOnHoldStatus(int channel, bool enable, OnHoldModes mode)
1010{
1011 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
1012 "SetOnHoldStatus(channel=%d, enable=%d, mode=%d)", channel,
1013 enable, mode);
1014 if (!_shared->statistics().Initialized())
1015 {
1016 _shared->SetLastError(VE_NOT_INITED, kTraceError);
1017 return -1;
1018 }
1019 voe::ScopedChannel sc(_shared->channel_manager(), channel);
1020 voe::Channel* channelPtr = sc.ChannelPtr();
1021 if (channelPtr == NULL)
1022 {
1023 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
1024 "SetOnHoldStatus() failed to locate channel");
1025 return -1;
1026 }
1027 return channelPtr->SetOnHoldStatus(enable, mode);
1028}
1029
1030int VoEBaseImpl::GetOnHoldStatus(int channel, bool& enabled, OnHoldModes& mode)
1031{
1032 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
1033 "GetOnHoldStatus(channel=%d, enabled=?, mode=?)", channel);
1034 if (!_shared->statistics().Initialized())
1035 {
1036 _shared->SetLastError(VE_NOT_INITED, kTraceError);
1037 return -1;
1038 }
1039 voe::ScopedChannel sc(_shared->channel_manager(), channel);
1040 voe::Channel* channelPtr = sc.ChannelPtr();
1041 if (channelPtr == NULL)
1042 {
1043 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
1044 "GetOnHoldStatus() failed to locate channel");
1045 return -1;
1046 }
1047 return channelPtr->GetOnHoldStatus(enabled, mode);
1048}
1049
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001050int32_t VoEBaseImpl::StartPlayout()
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001051{
1052 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
1053 "VoEBaseImpl::StartPlayout()");
1054 if (_shared->audio_device()->Playing())
1055 {
1056 return 0;
1057 }
1058 if (!_shared->ext_playout())
1059 {
1060 if (_shared->audio_device()->InitPlayout() != 0)
1061 {
1062 WEBRTC_TRACE(kTraceError, kTraceVoice,
1063 VoEId(_shared->instance_id(), -1),
1064 "StartPlayout() failed to initialize playout");
1065 return -1;
1066 }
1067 if (_shared->audio_device()->StartPlayout() != 0)
1068 {
1069 WEBRTC_TRACE(kTraceError, kTraceVoice,
1070 VoEId(_shared->instance_id(), -1),
1071 "StartPlayout() failed to start playout");
1072 return -1;
1073 }
1074 }
1075 return 0;
1076}
1077
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001078int32_t VoEBaseImpl::StopPlayout()
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001079{
1080 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
1081 "VoEBaseImpl::StopPlayout()");
1082
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001083 int32_t numOfChannels = _shared->channel_manager().NumOfChannels();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001084 if (numOfChannels <= 0)
1085 {
1086 return 0;
1087 }
1088
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001089 uint16_t nChannelsPlaying(0);
1090 int32_t* channelsArray = new int32_t[numOfChannels];
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001091
1092 // Get number of playing channels
1093 _shared->channel_manager().GetChannelIds(channelsArray, numOfChannels);
1094 for (int i = 0; i < numOfChannels; i++)
1095 {
1096 voe::ScopedChannel sc(_shared->channel_manager(), channelsArray[i]);
1097 voe::Channel* chPtr = sc.ChannelPtr();
1098 if (chPtr)
1099 {
1100 if (chPtr->Playing())
1101 {
1102 nChannelsPlaying++;
1103 }
1104 }
1105 }
1106 delete[] channelsArray;
1107
1108 // Stop audio-device playing if no channel is playing out
1109 if (nChannelsPlaying == 0)
1110 {
1111 if (_shared->audio_device()->StopPlayout() != 0)
1112 {
1113 _shared->SetLastError(VE_CANNOT_STOP_PLAYOUT, kTraceError,
1114 "StopPlayout() failed to stop playout");
1115 return -1;
1116 }
1117 }
1118 return 0;
1119}
1120
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001121int32_t VoEBaseImpl::StartSend()
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001122{
1123 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
1124 "VoEBaseImpl::StartSend()");
1125 if (_shared->audio_device()->Recording())
1126 {
1127 return 0;
1128 }
1129 if (!_shared->ext_recording())
1130 {
1131 if (_shared->audio_device()->InitRecording() != 0)
1132 {
1133 WEBRTC_TRACE(kTraceError, kTraceVoice,
1134 VoEId(_shared->instance_id(), -1),
1135 "StartSend() failed to initialize recording");
1136 return -1;
1137 }
1138 if (_shared->audio_device()->StartRecording() != 0)
1139 {
1140 WEBRTC_TRACE(kTraceError, kTraceVoice,
1141 VoEId(_shared->instance_id(), -1),
1142 "StartSend() failed to start recording");
1143 return -1;
1144 }
1145 }
1146
1147 return 0;
1148}
1149
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001150int32_t VoEBaseImpl::StopSend()
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001151{
1152 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
1153 "VoEBaseImpl::StopSend()");
1154
1155 if (_shared->NumOfSendingChannels() == 0 &&
1156 !_shared->transmit_mixer()->IsRecordingMic())
1157 {
1158 // Stop audio-device recording if no channel is recording
1159 if (_shared->audio_device()->StopRecording() != 0)
1160 {
1161 _shared->SetLastError(VE_CANNOT_STOP_RECORDING, kTraceError,
1162 "StopSend() failed to stop recording");
1163 return -1;
1164 }
1165 _shared->transmit_mixer()->StopSend();
1166 }
1167
1168 return 0;
1169}
1170
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001171int32_t VoEBaseImpl::TerminateInternal()
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001172{
1173 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
1174 "VoEBaseImpl::TerminateInternal()");
1175
1176 // Delete any remaining channel objects
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001177 int32_t numOfChannels = _shared->channel_manager().NumOfChannels();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001178 if (numOfChannels > 0)
1179 {
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001180 int32_t* channelsArray = new int32_t[numOfChannels];
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001181 _shared->channel_manager().GetChannelIds(channelsArray, numOfChannels);
1182 for (int i = 0; i < numOfChannels; i++)
1183 {
1184 DeleteChannel(channelsArray[i]);
1185 }
1186 delete[] channelsArray;
1187 }
1188
1189 if (_shared->process_thread())
1190 {
1191 if (_shared->audio_device())
1192 {
1193 if (_shared->process_thread()->
1194 DeRegisterModule(_shared->audio_device()) != 0)
1195 {
1196 _shared->SetLastError(VE_THREAD_ERROR, kTraceError,
1197 "TerminateInternal() failed to deregister ADM");
1198 }
1199 }
1200 if (_shared->process_thread()->Stop() != 0)
1201 {
1202 _shared->SetLastError(VE_THREAD_ERROR, kTraceError,
1203 "TerminateInternal() failed to stop module process thread");
1204 }
1205 }
1206
andrew@webrtc.orgb79627b2013-03-05 01:12:49 +00001207 if (_shared->audio_device())
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001208 {
1209 if (_shared->audio_device()->StopPlayout() != 0)
1210 {
1211 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
1212 "TerminateInternal() failed to stop playout");
1213 }
1214 if (_shared->audio_device()->StopRecording() != 0)
1215 {
1216 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
1217 "TerminateInternal() failed to stop recording");
1218 }
1219 if (_shared->audio_device()->RegisterEventObserver(NULL) != 0) {
1220 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
1221 "TerminateInternal() failed to de-register event observer "
1222 "for the ADM");
1223 }
1224 if (_shared->audio_device()->RegisterAudioCallback(NULL) != 0) {
1225 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
1226 "TerminateInternal() failed to de-register audio callback "
1227 "for the ADM");
1228 }
1229 if (_shared->audio_device()->Terminate() != 0)
1230 {
1231 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
1232 "TerminateInternal() failed to terminate the ADM");
1233 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001234 _shared->set_audio_device(NULL);
1235 }
1236
andrew@webrtc.orgb79627b2013-03-05 01:12:49 +00001237 if (_shared->audio_processing()) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001238 _shared->set_audio_processing(NULL);
1239 }
1240
1241 return _shared->statistics().SetUnInitialized();
1242}
1243
1244} // namespace webrtc