blob: 1b4b8676623e45c13e39b50e61c7f40fb52e25d4 [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
turaj@webrtc.org03f33702013-11-13 00:02:48 +000013#include "webrtc/common.h"
pbos@webrtc.org956aa7e2013-05-21 13:52:32 +000014#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
15#include "webrtc/modules/audio_coding/main/interface/audio_coding_module.h"
16#include "webrtc/modules/audio_device/audio_device_impl.h"
17#include "webrtc/modules/audio_processing/include/audio_processing.h"
18#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
19#include "webrtc/system_wrappers/interface/file_wrapper.h"
20#include "webrtc/system_wrappers/interface/trace.h"
21#include "webrtc/voice_engine/channel.h"
22#include "webrtc/voice_engine/include/voe_errors.h"
23#include "webrtc/voice_engine/output_mixer.h"
24#include "webrtc/voice_engine/transmit_mixer.h"
25#include "webrtc/voice_engine/utility.h"
26#include "webrtc/voice_engine/voice_engine_impl.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000027
niklase@google.com470e71d2011-07-07 08:21:25 +000028namespace webrtc
29{
30
31VoEBase* VoEBase::GetInterface(VoiceEngine* voiceEngine)
32{
33 if (NULL == voiceEngine)
34 {
35 return NULL;
36 }
tommi@webrtc.org0989fb72013-02-15 15:07:32 +000037 VoiceEngineImpl* s = static_cast<VoiceEngineImpl*>(voiceEngine);
tommi@webrtc.orga990e122012-04-26 15:28:22 +000038 s->AddRef();
39 return s;
niklase@google.com470e71d2011-07-07 08:21:25 +000040}
41
tommi@webrtc.org851becd2012-04-04 14:57:19 +000042VoEBaseImpl::VoEBaseImpl(voe::SharedData* shared) :
niklase@google.com470e71d2011-07-07 08:21:25 +000043 _voiceEngineObserverPtr(NULL),
44 _callbackCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
andrew@webrtc.org27c69802014-02-18 20:24:56 +000045 _voiceEngineObserver(false), _shared(shared)
niklase@google.com470e71d2011-07-07 08:21:25 +000046{
tommi@webrtc.org851becd2012-04-04 14:57:19 +000047 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +000048 "VoEBaseImpl() - ctor");
49}
50
51VoEBaseImpl::~VoEBaseImpl()
52{
tommi@webrtc.org851becd2012-04-04 14:57:19 +000053 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +000054 "~VoEBaseImpl() - dtor");
55
56 TerminateInternal();
57
58 delete &_callbackCritSect;
59}
60
pbos@webrtc.org92135212013-05-14 08:31:39 +000061void VoEBaseImpl::OnErrorIsReported(ErrorCode error)
niklase@google.com470e71d2011-07-07 08:21:25 +000062{
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +000063 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +000064 if (_voiceEngineObserver)
65 {
66 if (_voiceEngineObserverPtr)
67 {
68 int errCode(0);
69 if (error == AudioDeviceObserver::kRecordingError)
70 {
71 errCode = VE_RUNTIME_REC_ERROR;
tommi@webrtc.org851becd2012-04-04 14:57:19 +000072 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
73 VoEId(_shared->instance_id(), -1),
74 "VoEBaseImpl::OnErrorIsReported() => VE_RUNTIME_REC_ERROR");
niklase@google.com470e71d2011-07-07 08:21:25 +000075 }
76 else if (error == AudioDeviceObserver::kPlayoutError)
77 {
78 errCode = VE_RUNTIME_PLAY_ERROR;
tommi@webrtc.org851becd2012-04-04 14:57:19 +000079 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
80 VoEId(_shared->instance_id(), -1),
81 "VoEBaseImpl::OnErrorIsReported() => "
82 "VE_RUNTIME_PLAY_ERROR");
niklase@google.com470e71d2011-07-07 08:21:25 +000083 }
84 // Deliver callback (-1 <=> no channel dependency)
85 _voiceEngineObserverPtr->CallbackOnError(-1, errCode);
86 }
87 }
88}
89
pbos@webrtc.org92135212013-05-14 08:31:39 +000090void VoEBaseImpl::OnWarningIsReported(WarningCode warning)
niklase@google.com470e71d2011-07-07 08:21:25 +000091{
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +000092 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +000093 if (_voiceEngineObserver)
94 {
95 if (_voiceEngineObserverPtr)
96 {
97 int warningCode(0);
98 if (warning == AudioDeviceObserver::kRecordingWarning)
99 {
100 warningCode = VE_RUNTIME_REC_WARNING;
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000101 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
102 VoEId(_shared->instance_id(), -1),
103 "VoEBaseImpl::OnErrorIsReported() => "
104 "VE_RUNTIME_REC_WARNING");
niklase@google.com470e71d2011-07-07 08:21:25 +0000105 }
106 else if (warning == AudioDeviceObserver::kPlayoutWarning)
107 {
108 warningCode = VE_RUNTIME_PLAY_WARNING;
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000109 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
110 VoEId(_shared->instance_id(), -1),
111 "VoEBaseImpl::OnErrorIsReported() => "
112 "VE_RUNTIME_PLAY_WARNING");
niklase@google.com470e71d2011-07-07 08:21:25 +0000113 }
114 // Deliver callback (-1 <=> no channel dependency)
115 _voiceEngineObserverPtr->CallbackOnError(-1, warningCode);
116 }
117 }
118}
119
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000120int32_t VoEBaseImpl::RecordedDataIsAvailable(
henrika@webrtc.org907bc552012-03-09 08:59:19 +0000121 const void* audioSamples,
pbos@webrtc.org92135212013-05-14 08:31:39 +0000122 uint32_t nSamples,
123 uint8_t nBytesPerSample,
124 uint8_t nChannels,
125 uint32_t samplesPerSec,
126 uint32_t totalDelayMS,
127 int32_t clockDrift,
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000128 uint32_t micLevel,
pbos@webrtc.org92135212013-05-14 08:31:39 +0000129 bool keyPressed,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000130 uint32_t& newMicLevel)
niklase@google.com470e71d2011-07-07 08:21:25 +0000131{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000132 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000133 "VoEBaseImpl::RecordedDataIsAvailable(nSamples=%u, "
134 "nBytesPerSample=%u, nChannels=%u, samplesPerSec=%u, "
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000135 "totalDelayMS=%u, clockDrift=%d, micLevel=%u)",
niklase@google.com470e71d2011-07-07 08:21:25 +0000136 nSamples, nBytesPerSample, nChannels, samplesPerSec,
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000137 totalDelayMS, clockDrift, micLevel);
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000138 newMicLevel = static_cast<uint32_t>(ProcessRecordedDataWithAPM(
139 NULL, 0, audioSamples, samplesPerSec, nChannels, nSamples,
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000140 totalDelayMS, clockDrift, micLevel, keyPressed));
niklase@google.com470e71d2011-07-07 08:21:25 +0000141
142 return 0;
143}
144
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000145int32_t VoEBaseImpl::NeedMorePlayData(
pbos@webrtc.org92135212013-05-14 08:31:39 +0000146 uint32_t nSamples,
147 uint8_t nBytesPerSample,
148 uint8_t nChannels,
149 uint32_t samplesPerSec,
henrika@webrtc.org907bc552012-03-09 08:59:19 +0000150 void* audioSamples,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000151 uint32_t& nSamplesOut)
niklase@google.com470e71d2011-07-07 08:21:25 +0000152{
xians@webrtc.org56925312014-04-14 10:50:37 +0000153 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_shared->instance_id(), -1),
154 "VoEBaseImpl::NeedMorePlayData(nSamples=%u, "
155 "nBytesPerSample=%d, nChannels=%d, samplesPerSec=%u)",
156 nSamples, nBytesPerSample, nChannels, samplesPerSec);
niklase@google.com470e71d2011-07-07 08:21:25 +0000157
xians@webrtc.org56925312014-04-14 10:50:37 +0000158 GetPlayoutData(static_cast<int>(samplesPerSec),
159 static_cast<int>(nChannels),
160 static_cast<int>(nSamples), true, audioSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +0000161
xians@webrtc.org56925312014-04-14 10:50:37 +0000162 nSamplesOut = _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000163
xians@webrtc.org56925312014-04-14 10:50:37 +0000164 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000165}
166
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000167int VoEBaseImpl::OnDataAvailable(const int voe_channels[],
xians@webrtc.org2f84afa2013-07-31 16:23:37 +0000168 int number_of_voe_channels,
169 const int16_t* audio_data,
170 int sample_rate,
171 int number_of_channels,
172 int number_of_frames,
173 int audio_delay_milliseconds,
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000174 int volume,
xians@webrtc.org2f84afa2013-07-31 16:23:37 +0000175 bool key_pressed,
176 bool need_audio_processing) {
177 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_shared->instance_id(), -1),
178 "VoEBaseImpl::OnDataAvailable(number_of_voe_channels=%d, "
179 "sample_rate=%d, number_of_channels=%d, number_of_frames=%d, "
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000180 "audio_delay_milliseconds=%d, volume=%d, "
xians@webrtc.org2f84afa2013-07-31 16:23:37 +0000181 "key_pressed=%d, need_audio_processing=%d)",
182 number_of_voe_channels, sample_rate, number_of_channels,
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000183 number_of_frames, audio_delay_milliseconds, volume,
xians@webrtc.org2f84afa2013-07-31 16:23:37 +0000184 key_pressed, need_audio_processing);
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000185 if (number_of_voe_channels == 0)
186 return 0;
xians@webrtc.org2f84afa2013-07-31 16:23:37 +0000187
188 if (need_audio_processing) {
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000189 return ProcessRecordedDataWithAPM(
190 voe_channels, number_of_voe_channels, audio_data, sample_rate,
191 number_of_channels, number_of_frames, audio_delay_milliseconds,
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000192 0, volume, key_pressed);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +0000193 }
194
195 // No need to go through the APM, demultiplex the data to each VoE channel,
196 // encode and send to the network.
197 for (int i = 0; i < number_of_voe_channels; ++i) {
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000198 // TODO(ajm): In the case where multiple channels are using the same codec
199 // rate, this path needlessly does extra conversions. We should convert once
200 // and share between channels.
xians@webrtc.org56925312014-04-14 10:50:37 +0000201 PushCaptureData(voe_channels[i], audio_data, 16, sample_rate,
202 number_of_channels, number_of_frames);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +0000203 }
204
205 // Return 0 to indicate no need to change the volume.
206 return 0;
207}
208
xians@webrtc.orgc1e28032014-02-02 15:30:20 +0000209void VoEBaseImpl::OnData(int voe_channel, const void* audio_data,
210 int bits_per_sample, int sample_rate,
211 int number_of_channels,
212 int number_of_frames) {
xians@webrtc.org56925312014-04-14 10:50:37 +0000213 PushCaptureData(voe_channel, audio_data, bits_per_sample, sample_rate,
214 number_of_channels, number_of_frames);
215}
216
217void VoEBaseImpl::PushCaptureData(int voe_channel, const void* audio_data,
218 int bits_per_sample, int sample_rate,
219 int number_of_channels,
220 int number_of_frames) {
xians@webrtc.org07e51962014-01-29 13:54:02 +0000221 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(voe_channel);
222 voe::Channel* channel_ptr = ch.channel();
223 if (!channel_ptr)
224 return;
225
henrika@webrtc.org66803482014-04-17 10:45:01 +0000226 if (channel_ptr->Sending()) {
xians@webrtc.org07e51962014-01-29 13:54:02 +0000227 channel_ptr->Demultiplex(static_cast<const int16_t*>(audio_data),
228 sample_rate, number_of_frames, number_of_channels);
229 channel_ptr->PrepareEncodeAndSend(sample_rate);
230 channel_ptr->EncodeAndSend();
231 }
232}
233
xians@webrtc.org56925312014-04-14 10:50:37 +0000234void VoEBaseImpl::PullRenderData(int bits_per_sample, int sample_rate,
235 int number_of_channels, int number_of_frames,
236 void* audio_data) {
237 assert(bits_per_sample == 16);
238 assert(number_of_frames == static_cast<int>(sample_rate / 100));
239
240 GetPlayoutData(sample_rate, number_of_channels, number_of_frames, false,
241 audio_data);
242}
243
niklase@google.com470e71d2011-07-07 08:21:25 +0000244int VoEBaseImpl::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
245{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000246 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000247 "RegisterVoiceEngineObserver(observer=0x%d)", &observer);
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000248 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000249 if (_voiceEngineObserverPtr)
250 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000251 _shared->SetLastError(VE_INVALID_OPERATION, kTraceError,
252 "RegisterVoiceEngineObserver() observer already enabled");
niklase@google.com470e71d2011-07-07 08:21:25 +0000253 return -1;
254 }
255
256 // Register the observer in all active channels
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000257 for (voe::ChannelManager::Iterator it(&_shared->channel_manager());
258 it.IsValid();
259 it.Increment()) {
260 it.GetChannel()->RegisterVoiceEngineObserver(observer);
niklase@google.com470e71d2011-07-07 08:21:25 +0000261 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000262
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000263 _shared->transmit_mixer()->RegisterVoiceEngineObserver(observer);
niklase@google.com470e71d2011-07-07 08:21:25 +0000264
265 _voiceEngineObserverPtr = &observer;
266 _voiceEngineObserver = true;
267
268 return 0;
269}
270
271int VoEBaseImpl::DeRegisterVoiceEngineObserver()
272{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000273 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000274 "DeRegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000275 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000276 if (!_voiceEngineObserverPtr)
277 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000278 _shared->SetLastError(VE_INVALID_OPERATION, kTraceError,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000279 "DeRegisterVoiceEngineObserver() observer already disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +0000280 return 0;
281 }
282
283 _voiceEngineObserver = false;
284 _voiceEngineObserverPtr = NULL;
285
286 // Deregister the observer in all active channels
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000287 for (voe::ChannelManager::Iterator it(&_shared->channel_manager());
288 it.IsValid();
289 it.Increment()) {
290 it.GetChannel()->DeRegisterVoiceEngineObserver();
niklase@google.com470e71d2011-07-07 08:21:25 +0000291 }
292
293 return 0;
294}
295
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000296int VoEBaseImpl::Init(AudioDeviceModule* external_adm,
297 AudioProcessing* audioproc)
niklase@google.com470e71d2011-07-07 08:21:25 +0000298{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000299 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
henrika@google.com73d65512011-09-07 15:11:18 +0000300 "Init(external_adm=0x%p)", external_adm);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000301 CriticalSectionScoped cs(_shared->crit_sec());
niklase@google.com470e71d2011-07-07 08:21:25 +0000302
kma@webrtc.org0221b782012-09-08 00:09:26 +0000303 WebRtcSpl_Init();
304
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000305 if (_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000306 {
307 return 0;
308 }
309
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000310 if (_shared->process_thread())
niklase@google.com470e71d2011-07-07 08:21:25 +0000311 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000312 if (_shared->process_thread()->Start() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000313 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000314 _shared->SetLastError(VE_THREAD_ERROR, kTraceError,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000315 "Init() failed to start module process thread");
niklase@google.com470e71d2011-07-07 08:21:25 +0000316 return -1;
317 }
318 }
319
andrew@webrtc.org3192d652011-12-21 18:00:59 +0000320 // Create an internal ADM if the user has not added an external
henrika@google.com73d65512011-09-07 15:11:18 +0000321 // ADM implementation as input to Init().
322 if (external_adm == NULL)
niklase@google.com470e71d2011-07-07 08:21:25 +0000323 {
henrika@google.com73d65512011-09-07 15:11:18 +0000324 // Create the internal ADM implementation.
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000325 _shared->set_audio_device(AudioDeviceModuleImpl::Create(
326 VoEId(_shared->instance_id(), -1), _shared->audio_device_layer()));
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000327
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000328 if (_shared->audio_device() == NULL)
niklase@google.com470e71d2011-07-07 08:21:25 +0000329 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000330 _shared->SetLastError(VE_NO_MEMORY, kTraceCritical,
331 "Init() failed to create the ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +0000332 return -1;
333 }
334 }
henrika@google.com73d65512011-09-07 15:11:18 +0000335 else
336 {
337 // Use the already existing external ADM implementation.
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000338 _shared->set_audio_device(external_adm);
339 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
henrika@google.com73d65512011-09-07 15:11:18 +0000340 "An external ADM implementation will be used in VoiceEngine");
341 }
342
niklase@google.com470e71d2011-07-07 08:21:25 +0000343 // Register the ADM to the process thread, which will drive the error
344 // callback mechanism
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000345 if (_shared->process_thread() &&
346 _shared->process_thread()->RegisterModule(_shared->audio_device()) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000347 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000348 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
349 "Init() failed to register the ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +0000350 return -1;
351 }
352
353 bool available(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000354
355 // --------------------
356 // Reinitialize the ADM
357
358 // Register the AudioObserver implementation
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000359 if (_shared->audio_device()->RegisterEventObserver(this) != 0) {
360 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
361 "Init() failed to register event observer for the ADM");
xians@webrtc.org79af7342012-01-31 12:22:14 +0000362 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000363
364 // Register the AudioTransport implementation
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000365 if (_shared->audio_device()->RegisterAudioCallback(this) != 0) {
366 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
367 "Init() failed to register audio callback for the ADM");
xians@webrtc.org79af7342012-01-31 12:22:14 +0000368 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000369
370 // ADM initialization
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000371 if (_shared->audio_device()->Init() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000372 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000373 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
374 "Init() failed to initialize the ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +0000375 return -1;
376 }
377
378 // Initialize the default speaker
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000379 if (_shared->audio_device()->SetPlayoutDevice(
380 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000381 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000382 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000383 "Init() failed to set the default output device");
niklase@google.com470e71d2011-07-07 08:21:25 +0000384 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000385 if (_shared->audio_device()->InitSpeaker() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000386 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000387 _shared->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000388 "Init() failed to initialize the speaker");
niklase@google.com470e71d2011-07-07 08:21:25 +0000389 }
390
391 // Initialize the default microphone
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000392 if (_shared->audio_device()->SetRecordingDevice(
393 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000394 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000395 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000396 "Init() failed to set the default input device");
niklase@google.com470e71d2011-07-07 08:21:25 +0000397 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000398 if (_shared->audio_device()->InitMicrophone() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000399 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000400 _shared->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000401 "Init() failed to initialize the microphone");
niklase@google.com470e71d2011-07-07 08:21:25 +0000402 }
403
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000404 // Set number of channels
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000405 if (_shared->audio_device()->StereoPlayoutIsAvailable(&available) != 0) {
406 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
407 "Init() failed to query stereo playout mode");
xians@webrtc.org79af7342012-01-31 12:22:14 +0000408 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000409 if (_shared->audio_device()->SetStereoPlayout(available) != 0)
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000410 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000411 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000412 "Init() failed to set mono/stereo playout mode");
413 }
andrew@webrtc.org3192d652011-12-21 18:00:59 +0000414
415 // TODO(andrew): These functions don't tell us whether stereo recording
416 // is truly available. We simply set the AudioProcessing input to stereo
417 // here, because we have to wait until receiving the first frame to
418 // determine the actual number of channels anyway.
419 //
420 // These functions may be changed; tracked here:
421 // http://code.google.com/p/webrtc/issues/detail?id=204
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000422 _shared->audio_device()->StereoRecordingIsAvailable(&available);
423 if (_shared->audio_device()->SetStereoRecording(available) != 0)
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000424 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000425 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000426 "Init() failed to set mono/stereo recording mode");
427 }
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000428
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000429 if (!audioproc) {
430 audioproc = AudioProcessing::Create(VoEId(_shared->instance_id(), -1));
431 if (!audioproc) {
432 LOG(LS_ERROR) << "Failed to create AudioProcessing.";
433 _shared->SetLastError(VE_NO_MEMORY);
434 return -1;
435 }
436 }
437 _shared->set_audio_processing(audioproc);
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000438
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000439 // Set the error state for any failures in this block.
440 _shared->SetLastError(VE_APM_ERROR);
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +0000441 // Configure AudioProcessing components.
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000442 if (audioproc->high_pass_filter()->Enable(true) != 0) {
443 LOG_FERR1(LS_ERROR, high_pass_filter()->Enable, true);
444 return -1;
445 }
446 if (audioproc->echo_cancellation()->enable_drift_compensation(false) != 0) {
447 LOG_FERR1(LS_ERROR, enable_drift_compensation, false);
448 return -1;
449 }
450 if (audioproc->noise_suppression()->set_level(kDefaultNsMode) != 0) {
451 LOG_FERR1(LS_ERROR, noise_suppression()->set_level, kDefaultNsMode);
452 return -1;
453 }
454 GainControl* agc = audioproc->gain_control();
455 if (agc->set_analog_level_limits(kMinVolumeLevel, kMaxVolumeLevel) != 0) {
456 LOG_FERR2(LS_ERROR, agc->set_analog_level_limits, kMinVolumeLevel,
457 kMaxVolumeLevel);
458 return -1;
459 }
460 if (agc->set_mode(kDefaultAgcMode) != 0) {
461 LOG_FERR1(LS_ERROR, agc->set_mode, kDefaultAgcMode);
462 return -1;
463 }
464 if (agc->Enable(kDefaultAgcState) != 0) {
465 LOG_FERR1(LS_ERROR, agc->Enable, kDefaultAgcState);
466 return -1;
467 }
468 _shared->SetLastError(0); // Clear error state.
469
niklase@google.com470e71d2011-07-07 08:21:25 +0000470#ifdef WEBRTC_VOICE_ENGINE_AGC
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000471 bool agc_enabled = agc->mode() == GainControl::kAdaptiveAnalog &&
472 agc->is_enabled();
473 if (_shared->audio_device()->SetAGC(agc_enabled) != 0) {
474 LOG_FERR1(LS_ERROR, audio_device()->SetAGC, agc_enabled);
475 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR);
andrew@webrtc.orga9a1df02013-03-05 23:36:10 +0000476 // TODO(ajm): No error return here due to
477 // https://code.google.com/p/webrtc/issues/detail?id=1464
niklase@google.com470e71d2011-07-07 08:21:25 +0000478 }
479#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000480
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000481 return _shared->statistics().SetInitialized();
niklase@google.com470e71d2011-07-07 08:21:25 +0000482}
483
484int VoEBaseImpl::Terminate()
485{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000486 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000487 "Terminate()");
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000488 CriticalSectionScoped cs(_shared->crit_sec());
niklase@google.com470e71d2011-07-07 08:21:25 +0000489 return TerminateInternal();
490}
491
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000492int VoEBaseImpl::CreateChannel() {
493 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
494 "CreateChannel()");
495 CriticalSectionScoped cs(_shared->crit_sec());
496 if (!_shared->statistics().Initialized()) {
497 _shared->SetLastError(VE_NOT_INITED, kTraceError);
498 return -1;
499 }
500
501 voe::ChannelOwner channel_owner = _shared->channel_manager().CreateChannel();
502
503 return InitializeChannel(&channel_owner);
504}
505
506int VoEBaseImpl::CreateChannel(const Config& config) {
507 CriticalSectionScoped cs(_shared->crit_sec());
508 if (!_shared->statistics().Initialized()) {
509 _shared->SetLastError(VE_NOT_INITED, kTraceError);
510 return -1;
511 }
512 voe::ChannelOwner channel_owner = _shared->channel_manager().CreateChannel(
513 config);
514 return InitializeChannel(&channel_owner);
515}
516
517int VoEBaseImpl::InitializeChannel(voe::ChannelOwner* channel_owner)
niklase@google.com470e71d2011-07-07 08:21:25 +0000518{
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000519 if (channel_owner->channel()->SetEngineInformation(
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000520 _shared->statistics(),
521 *_shared->output_mixer(),
522 *_shared->transmit_mixer(),
523 *_shared->process_thread(),
524 *_shared->audio_device(),
525 _voiceEngineObserverPtr,
526 &_callbackCritSect) != 0) {
527 _shared->SetLastError(
528 VE_CHANNEL_NOT_CREATED,
529 kTraceError,
530 "CreateChannel() failed to associate engine and channel."
531 " Destroying channel.");
532 _shared->channel_manager()
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000533 .DestroyChannel(channel_owner->channel()->ChannelId());
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000534 return -1;
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000535 } else if (channel_owner->channel()->Init() != 0) {
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000536 _shared->SetLastError(
537 VE_CHANNEL_NOT_CREATED,
538 kTraceError,
539 "CreateChannel() failed to initialize channel. Destroying"
540 " channel.");
541 _shared->channel_manager()
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000542 .DestroyChannel(channel_owner->channel()->ChannelId());
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000543 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000544 }
545
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000546 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
547 VoEId(_shared->instance_id(), -1),
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000548 "CreateChannel() => %d", channel_owner->channel()->ChannelId());
549 return channel_owner->channel()->ChannelId();
niklase@google.com470e71d2011-07-07 08:21:25 +0000550}
551
552int VoEBaseImpl::DeleteChannel(int channel)
553{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000554 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000555 "DeleteChannel(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000556 CriticalSectionScoped cs(_shared->crit_sec());
niklase@google.com470e71d2011-07-07 08:21:25 +0000557
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000558 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000559 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000560 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000561 return -1;
562 }
563
564 {
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000565 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
566 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000567 if (channelPtr == NULL)
568 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000569 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
570 "DeleteChannel() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000571 return -1;
572 }
573 }
574
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000575 _shared->channel_manager().DestroyChannel(channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000576
577 if (StopSend() != 0)
578 {
579 return -1;
580 }
581
582 if (StopPlayout() != 0)
583 {
584 return -1;
585 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +0000586
niklase@google.com470e71d2011-07-07 08:21:25 +0000587 return 0;
588}
589
niklase@google.com470e71d2011-07-07 08:21:25 +0000590int VoEBaseImpl::StartReceive(int channel)
591{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000592 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000593 "StartReceive(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000594 CriticalSectionScoped cs(_shared->crit_sec());
595 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000596 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000597 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000598 return -1;
599 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000600 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
601 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000602 if (channelPtr == NULL)
603 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000604 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
605 "StartReceive() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000606 return -1;
607 }
608 return channelPtr->StartReceiving();
609}
610
611int VoEBaseImpl::StopReceive(int channel)
612{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000613 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000614 "StopListen(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000615 CriticalSectionScoped cs(_shared->crit_sec());
616 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000617 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000618 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000619 return -1;
620 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000621 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
622 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000623 if (channelPtr == NULL)
624 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000625 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
626 "SetLocalReceiver() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000627 return -1;
628 }
629 return channelPtr->StopReceiving();
630}
631
632int VoEBaseImpl::StartPlayout(int channel)
633{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000634 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000635 "StartPlayout(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000636 CriticalSectionScoped cs(_shared->crit_sec());
637 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000638 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000639 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000640 return -1;
641 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000642 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
643 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000644 if (channelPtr == NULL)
645 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000646 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
647 "StartPlayout() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000648 return -1;
649 }
650 if (channelPtr->Playing())
651 {
652 return 0;
653 }
654 if (StartPlayout() != 0)
655 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000656 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
657 "StartPlayout() failed to start playout");
niklase@google.com470e71d2011-07-07 08:21:25 +0000658 return -1;
659 }
660 return channelPtr->StartPlayout();
661}
662
663int VoEBaseImpl::StopPlayout(int channel)
664{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000665 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000666 "StopPlayout(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000667 CriticalSectionScoped cs(_shared->crit_sec());
668 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000669 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000670 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000671 return -1;
672 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000673 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
674 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000675 if (channelPtr == NULL)
676 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000677 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
678 "StopPlayout() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000679 return -1;
680 }
681 if (channelPtr->StopPlayout() != 0)
682 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000683 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
684 VoEId(_shared->instance_id(), -1),
685 "StopPlayout() failed to stop playout for channel %d", channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000686 }
687 return StopPlayout();
688}
689
690int VoEBaseImpl::StartSend(int channel)
691{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000692 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000693 "StartSend(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000694 CriticalSectionScoped cs(_shared->crit_sec());
695 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000696 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000697 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000698 return -1;
699 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000700 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
701 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000702 if (channelPtr == NULL)
703 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000704 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
705 "StartSend() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000706 return -1;
707 }
708 if (channelPtr->Sending())
709 {
710 return 0;
711 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000712 if (StartSend() != 0)
713 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000714 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
715 "StartSend() failed to start recording");
niklase@google.com470e71d2011-07-07 08:21:25 +0000716 return -1;
717 }
718 return channelPtr->StartSend();
719}
720
721int VoEBaseImpl::StopSend(int channel)
722{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000723 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000724 "StopSend(channel=%d)", channel);
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000725 CriticalSectionScoped cs(_shared->crit_sec());
726 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000727 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000728 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000729 return -1;
730 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000731 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
732 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000733 if (channelPtr == NULL)
734 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000735 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
736 "StopSend() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000737 return -1;
738 }
739 if (channelPtr->StopSend() != 0)
740 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000741 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
742 VoEId(_shared->instance_id(), -1),
743 "StopSend() failed to stop sending for channel %d", channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000744 }
745 return StopSend();
746}
747
748int VoEBaseImpl::GetVersion(char version[1024])
749{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000750 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000751 "GetVersion(version=?)");
752 assert(kVoiceEngineVersionMaxMessageSize == 1024);
753
754 if (version == NULL)
755 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000756 _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000757 return (-1);
758 }
759
760 char versionBuf[kVoiceEngineVersionMaxMessageSize];
761 char* versionPtr = versionBuf;
762
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000763 int32_t len = 0;
764 int32_t accLen = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000765
766 len = AddVoEVersion(versionPtr);
767 if (len == -1)
768 {
769 return -1;
770 }
771 versionPtr += len;
772 accLen += len;
773 assert(accLen < kVoiceEngineVersionMaxMessageSize);
774
775 len = AddBuildInfo(versionPtr);
776 if (len == -1)
777 {
778 return -1;
779 }
780 versionPtr += len;
781 accLen += len;
782 assert(accLen < kVoiceEngineVersionMaxMessageSize);
783
pwestin@webrtc.org684f0572013-03-13 23:20:57 +0000784#ifdef WEBRTC_EXTERNAL_TRANSPORT
785 len = AddExternalTransportBuild(versionPtr);
786 if (len == -1)
787 {
788 return -1;
789 }
790 versionPtr += len;
791 accLen += len;
792 assert(accLen < kVoiceEngineVersionMaxMessageSize);
793#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000794
795 memcpy(version, versionBuf, accLen);
796 version[accLen] = '\0';
797
798 // to avoid the truncation in the trace, split the string into parts
799 char partOfVersion[256];
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000800 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
801 VoEId(_shared->instance_id(), -1), "GetVersion() =>");
niklase@google.com470e71d2011-07-07 08:21:25 +0000802 for (int partStart = 0; partStart < accLen;)
803 {
804 memset(partOfVersion, 0, sizeof(partOfVersion));
805 int partEnd = partStart + 180;
806 while (version[partEnd] != '\n' && version[partEnd] != '\0')
807 {
808 partEnd--;
809 }
810 if (partEnd < accLen)
811 {
812 memcpy(partOfVersion, &version[partStart], partEnd - partStart);
813 }
814 else
815 {
816 memcpy(partOfVersion, &version[partStart], accLen - partStart);
817 }
818 partStart = partEnd;
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000819 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
820 VoEId(_shared->instance_id(), -1), "%s", partOfVersion);
niklase@google.com470e71d2011-07-07 08:21:25 +0000821 }
822
823 return 0;
824}
825
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000826int32_t VoEBaseImpl::AddBuildInfo(char* str) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000827{
andrew@webrtc.org3054ba62013-12-04 17:00:44 +0000828 return sprintf(str, "Build: %s\n", BUILDINFO);
niklase@google.com470e71d2011-07-07 08:21:25 +0000829}
830
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000831int32_t VoEBaseImpl::AddVoEVersion(char* str) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000832{
833 return sprintf(str, "VoiceEngine 4.1.0\n");
834}
835
pwestin@webrtc.org684f0572013-03-13 23:20:57 +0000836#ifdef WEBRTC_EXTERNAL_TRANSPORT
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000837int32_t VoEBaseImpl::AddExternalTransportBuild(char* str) const
pwestin@webrtc.org684f0572013-03-13 23:20:57 +0000838{
839 return sprintf(str, "External transport build\n");
840}
841#endif
842
niklase@google.com470e71d2011-07-07 08:21:25 +0000843int VoEBaseImpl::LastError()
844{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000845 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000846 "LastError()");
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000847 return (_shared->statistics().LastError());
niklase@google.com470e71d2011-07-07 08:21:25 +0000848}
849
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000850int32_t VoEBaseImpl::StartPlayout()
niklase@google.com470e71d2011-07-07 08:21:25 +0000851{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000852 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000853 "VoEBaseImpl::StartPlayout()");
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000854 if (_shared->audio_device()->Playing())
niklase@google.com470e71d2011-07-07 08:21:25 +0000855 {
856 return 0;
857 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000858 if (!_shared->ext_playout())
niklase@google.com470e71d2011-07-07 08:21:25 +0000859 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000860 if (_shared->audio_device()->InitPlayout() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000861 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000862 WEBRTC_TRACE(kTraceError, kTraceVoice,
863 VoEId(_shared->instance_id(), -1),
864 "StartPlayout() failed to initialize playout");
niklase@google.com470e71d2011-07-07 08:21:25 +0000865 return -1;
866 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000867 if (_shared->audio_device()->StartPlayout() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000868 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000869 WEBRTC_TRACE(kTraceError, kTraceVoice,
870 VoEId(_shared->instance_id(), -1),
871 "StartPlayout() failed to start playout");
niklase@google.com470e71d2011-07-07 08:21:25 +0000872 return -1;
873 }
874 }
875 return 0;
876}
877
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000878int32_t VoEBaseImpl::StopPlayout() {
879 WEBRTC_TRACE(kTraceInfo,
880 kTraceVoice,
881 VoEId(_shared->instance_id(), -1),
882 "VoEBaseImpl::StopPlayout()");
883 // Stop audio-device playing if no channel is playing out
xians@webrtc.org675e2602013-10-17 16:15:34 +0000884 if (_shared->NumOfPlayingChannels() == 0) {
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000885 if (_shared->audio_device()->StopPlayout() != 0) {
886 _shared->SetLastError(VE_CANNOT_STOP_PLAYOUT,
887 kTraceError,
888 "StopPlayout() failed to stop playout");
889 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000890 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000891 }
892 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000893}
894
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000895int32_t VoEBaseImpl::StartSend()
niklase@google.com470e71d2011-07-07 08:21:25 +0000896{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000897 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000898 "VoEBaseImpl::StartSend()");
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000899 if (_shared->audio_device()->Recording())
niklase@google.com470e71d2011-07-07 08:21:25 +0000900 {
901 return 0;
902 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000903 if (!_shared->ext_recording())
niklase@google.com470e71d2011-07-07 08:21:25 +0000904 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000905 if (_shared->audio_device()->InitRecording() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000906 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000907 WEBRTC_TRACE(kTraceError, kTraceVoice,
908 VoEId(_shared->instance_id(), -1),
909 "StartSend() failed to initialize recording");
niklase@google.com470e71d2011-07-07 08:21:25 +0000910 return -1;
911 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000912 if (_shared->audio_device()->StartRecording() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000913 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000914 WEBRTC_TRACE(kTraceError, kTraceVoice,
915 VoEId(_shared->instance_id(), -1),
916 "StartSend() failed to start recording");
niklase@google.com470e71d2011-07-07 08:21:25 +0000917 return -1;
918 }
919 }
920
921 return 0;
922}
923
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000924int32_t VoEBaseImpl::StopSend()
niklase@google.com470e71d2011-07-07 08:21:25 +0000925{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000926 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000927 "VoEBaseImpl::StopSend()");
928
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000929 if (_shared->NumOfSendingChannels() == 0 &&
930 !_shared->transmit_mixer()->IsRecordingMic())
niklase@google.com470e71d2011-07-07 08:21:25 +0000931 {
932 // Stop audio-device recording if no channel is recording
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000933 if (_shared->audio_device()->StopRecording() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000934 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000935 _shared->SetLastError(VE_CANNOT_STOP_RECORDING, kTraceError,
936 "StopSend() failed to stop recording");
niklase@google.com470e71d2011-07-07 08:21:25 +0000937 return -1;
938 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000939 _shared->transmit_mixer()->StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000940 }
941
942 return 0;
943}
944
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000945int32_t VoEBaseImpl::TerminateInternal()
niklase@google.com470e71d2011-07-07 08:21:25 +0000946{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000947 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000948 "VoEBaseImpl::TerminateInternal()");
949
950 // Delete any remaining channel objects
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000951 _shared->channel_manager().DestroyAllChannels();
niklase@google.com470e71d2011-07-07 08:21:25 +0000952
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000953 if (_shared->process_thread())
niklase@google.com470e71d2011-07-07 08:21:25 +0000954 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000955 if (_shared->audio_device())
niklase@google.com470e71d2011-07-07 08:21:25 +0000956 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000957 if (_shared->process_thread()->
958 DeRegisterModule(_shared->audio_device()) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000959 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000960 _shared->SetLastError(VE_THREAD_ERROR, kTraceError,
961 "TerminateInternal() failed to deregister ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +0000962 }
963 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000964 if (_shared->process_thread()->Stop() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000965 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000966 _shared->SetLastError(VE_THREAD_ERROR, kTraceError,
967 "TerminateInternal() failed to stop module process thread");
niklase@google.com470e71d2011-07-07 08:21:25 +0000968 }
969 }
970
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000971 if (_shared->audio_device())
niklase@google.com470e71d2011-07-07 08:21:25 +0000972 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000973 if (_shared->audio_device()->StopPlayout() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000974 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000975 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
976 "TerminateInternal() failed to stop playout");
niklase@google.com470e71d2011-07-07 08:21:25 +0000977 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000978 if (_shared->audio_device()->StopRecording() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000979 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000980 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
981 "TerminateInternal() failed to stop recording");
niklase@google.com470e71d2011-07-07 08:21:25 +0000982 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000983 if (_shared->audio_device()->RegisterEventObserver(NULL) != 0) {
984 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
985 "TerminateInternal() failed to de-register event observer "
986 "for the ADM");
xians@webrtc.org79af7342012-01-31 12:22:14 +0000987 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000988 if (_shared->audio_device()->RegisterAudioCallback(NULL) != 0) {
989 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
990 "TerminateInternal() failed to de-register audio callback "
991 "for the ADM");
xians@webrtc.org79af7342012-01-31 12:22:14 +0000992 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000993 if (_shared->audio_device()->Terminate() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000994 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000995 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
996 "TerminateInternal() failed to terminate the ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +0000997 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000998 _shared->set_audio_device(NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000999 }
1000
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +00001001 if (_shared->audio_processing()) {
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001002 _shared->set_audio_processing(NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +00001003 }
1004
tommi@webrtc.org851becd2012-04-04 14:57:19 +00001005 return _shared->statistics().SetUnInitialized();
niklase@google.com470e71d2011-07-07 08:21:25 +00001006}
1007
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00001008int VoEBaseImpl::ProcessRecordedDataWithAPM(
1009 const int voe_channels[],
1010 int number_of_voe_channels,
1011 const void* audio_data,
1012 uint32_t sample_rate,
1013 uint8_t number_of_channels,
1014 uint32_t number_of_frames,
1015 uint32_t audio_delay_milliseconds,
1016 int32_t clock_drift,
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001017 uint32_t volume,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00001018 bool key_pressed) {
1019 assert(_shared->transmit_mixer() != NULL);
1020 assert(_shared->audio_device() != NULL);
1021
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00001022 uint32_t max_volume = 0;
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001023 uint16_t voe_mic_level = 0;
andrew@webrtc.org023cc5a2014-01-11 01:25:53 +00001024 // Check for zero to skip this calculation; the consumer may use this to
1025 // indicate no volume is available.
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001026 if (volume != 0) {
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00001027 // Scale from ADM to VoE level range
1028 if (_shared->audio_device()->MaxMicrophoneVolume(&max_volume) == 0) {
1029 if (max_volume) {
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001030 voe_mic_level = static_cast<uint16_t>(
1031 (volume * kMaxVolumeLevel +
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00001032 static_cast<int>(max_volume / 2)) / max_volume);
1033 }
1034 }
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001035 // We learned that on certain systems (e.g Linux) the voe_mic_level
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00001036 // can be greater than the maxVolumeLevel therefore
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001037 // we are going to cap the voe_mic_level to the maxVolumeLevel
1038 // and change the maxVolume to volume if it turns out that
1039 // the voe_mic_level is indeed greater than the maxVolumeLevel.
1040 if (voe_mic_level > kMaxVolumeLevel) {
1041 voe_mic_level = kMaxVolumeLevel;
1042 max_volume = volume;
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00001043 }
1044 }
1045
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00001046 // Perform channel-independent operations
1047 // (APM, mix with file, record to file, mute, etc.)
1048 _shared->transmit_mixer()->PrepareDemux(
1049 audio_data, number_of_frames, number_of_channels, sample_rate,
1050 static_cast<uint16_t>(audio_delay_milliseconds), clock_drift,
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001051 voe_mic_level, key_pressed);
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00001052
1053 // Copy the audio frame to each sending channel and perform
1054 // channel-dependent operations (file mixing, mute, etc.), encode and
1055 // packetize+transmit the RTP packet. When |number_of_voe_channels| == 0,
1056 // do the operations on all the existing VoE channels; otherwise the
1057 // operations will be done on specific channels.
1058 if (number_of_voe_channels == 0) {
1059 _shared->transmit_mixer()->DemuxAndMix();
1060 _shared->transmit_mixer()->EncodeAndSend();
1061 } else {
1062 _shared->transmit_mixer()->DemuxAndMix(voe_channels,
1063 number_of_voe_channels);
1064 _shared->transmit_mixer()->EncodeAndSend(voe_channels,
1065 number_of_voe_channels);
1066 }
1067
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00001068 // Scale from VoE to ADM level range.
1069 uint32_t new_voe_mic_level = _shared->transmit_mixer()->CaptureLevel();
1070
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001071 if (new_voe_mic_level != voe_mic_level) {
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00001072 // Return the new volume if AGC has changed the volume.
1073 return static_cast<int>(
1074 (new_voe_mic_level * max_volume +
1075 static_cast<int>(kMaxVolumeLevel / 2)) / kMaxVolumeLevel);
1076 }
1077
1078 // Return 0 to indicate no change on the volume.
1079 return 0;
1080}
1081
xians@webrtc.org56925312014-04-14 10:50:37 +00001082void VoEBaseImpl::GetPlayoutData(int sample_rate, int number_of_channels,
1083 int number_of_frames, bool feed_data_to_apm,
1084 void* audio_data) {
1085 assert(_shared->output_mixer() != NULL);
1086
1087 // TODO(andrew): if the device is running in mono, we should tell the mixer
1088 // here so that it will only request mono from AudioCodingModule.
1089 // Perform mixing of all active participants (channel-based mixing)
1090 _shared->output_mixer()->MixActiveChannels();
1091
1092 // Additional operations on the combined signal
1093 _shared->output_mixer()->DoOperationsOnCombinedSignal(feed_data_to_apm);
1094
1095 // Retrieve the final output mix (resampled to match the ADM)
1096 _shared->output_mixer()->GetMixedAudio(sample_rate, number_of_channels,
1097 &_audioFrame);
1098
1099 assert(number_of_frames == _audioFrame.samples_per_channel_);
1100 assert(sample_rate == _audioFrame.sample_rate_hz_);
1101
1102 // Deliver audio (PCM) samples to the ADM
1103 memcpy(audio_data, _audioFrame.data_,
1104 sizeof(int16_t) * number_of_frames * number_of_channels);
1105}
1106
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00001107} // namespace webrtc