blob: 207f0b9744e2f1372d5f7a6de6bc6f9271e0a3a0 [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"
Jelena Marusic9e5e4212015-04-13 13:41:56 +020020#include "webrtc/system_wrappers/interface/logging.h"
pbos@webrtc.org956aa7e2013-05-21 13:52:32 +000021#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()),
Jelena Marusic9e5e4212015-04-13 13:41:56 +020045 _shared(shared)
niklase@google.com470e71d2011-07-07 08:21:25 +000046{
niklase@google.com470e71d2011-07-07 08:21:25 +000047}
48
49VoEBaseImpl::~VoEBaseImpl()
50{
niklase@google.com470e71d2011-07-07 08:21:25 +000051 TerminateInternal();
niklase@google.com470e71d2011-07-07 08:21:25 +000052 delete &_callbackCritSect;
53}
54
pbos@webrtc.org92135212013-05-14 08:31:39 +000055void VoEBaseImpl::OnErrorIsReported(ErrorCode error)
niklase@google.com470e71d2011-07-07 08:21:25 +000056{
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +000057 CriticalSectionScoped cs(&_callbackCritSect);
Jelena Marusic9e5e4212015-04-13 13:41:56 +020058 int errCode = 0;
59 if (error == AudioDeviceObserver::kRecordingError)
niklase@google.com470e71d2011-07-07 08:21:25 +000060 {
Jelena Marusic9e5e4212015-04-13 13:41:56 +020061 errCode = VE_RUNTIME_REC_ERROR;
62 LOG_F(LS_ERROR) << "VE_RUNTIME_REC_ERROR";
63 }
64 else if (error == AudioDeviceObserver::kPlayoutError)
65 {
66 errCode = VE_RUNTIME_PLAY_ERROR;
67 LOG_F(LS_ERROR) << "VE_RUNTIME_PLAY_ERROR";
68 }
69 if (_voiceEngineObserverPtr)
70 {
71 // Deliver callback (-1 <=> no channel dependency)
72 _voiceEngineObserverPtr->CallbackOnError(-1, errCode);
niklase@google.com470e71d2011-07-07 08:21:25 +000073 }
74}
75
pbos@webrtc.org92135212013-05-14 08:31:39 +000076void VoEBaseImpl::OnWarningIsReported(WarningCode warning)
niklase@google.com470e71d2011-07-07 08:21:25 +000077{
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +000078 CriticalSectionScoped cs(&_callbackCritSect);
Jelena Marusic9e5e4212015-04-13 13:41:56 +020079 int warningCode = 0;
80 if (warning == AudioDeviceObserver::kRecordingWarning)
niklase@google.com470e71d2011-07-07 08:21:25 +000081 {
Jelena Marusic9e5e4212015-04-13 13:41:56 +020082 warningCode = VE_RUNTIME_REC_WARNING;
83 LOG_F(LS_WARNING) << "VE_RUNTIME_REC_WARNING";
84 }
85 else if (warning == AudioDeviceObserver::kPlayoutWarning)
86 {
87 warningCode = VE_RUNTIME_PLAY_WARNING;
88 LOG_F(LS_WARNING) << "VE_RUNTIME_PLAY_WARNING";
89 }
90 if (_voiceEngineObserverPtr)
91 {
92 // Deliver callback (-1 <=> no channel dependency)
93 _voiceEngineObserverPtr->CallbackOnError(-1, warningCode);
niklase@google.com470e71d2011-07-07 08:21:25 +000094 }
95}
96
pbos@webrtc.org6141e132013-04-09 10:09:10 +000097int32_t VoEBaseImpl::RecordedDataIsAvailable(
henrika@webrtc.org907bc552012-03-09 08:59:19 +000098 const void* audioSamples,
pbos@webrtc.org92135212013-05-14 08:31:39 +000099 uint32_t nSamples,
100 uint8_t nBytesPerSample,
101 uint8_t nChannels,
102 uint32_t samplesPerSec,
103 uint32_t totalDelayMS,
104 int32_t clockDrift,
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000105 uint32_t micLevel,
pbos@webrtc.org92135212013-05-14 08:31:39 +0000106 bool keyPressed,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000107 uint32_t& newMicLevel)
niklase@google.com470e71d2011-07-07 08:21:25 +0000108{
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000109 newMicLevel = static_cast<uint32_t>(ProcessRecordedDataWithAPM(
110 NULL, 0, audioSamples, samplesPerSec, nChannels, nSamples,
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000111 totalDelayMS, clockDrift, micLevel, keyPressed));
niklase@google.com470e71d2011-07-07 08:21:25 +0000112 return 0;
113}
114
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000115int32_t VoEBaseImpl::NeedMorePlayData(
pbos@webrtc.org92135212013-05-14 08:31:39 +0000116 uint32_t nSamples,
117 uint8_t nBytesPerSample,
118 uint8_t nChannels,
119 uint32_t samplesPerSec,
henrika@webrtc.org907bc552012-03-09 08:59:19 +0000120 void* audioSamples,
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000121 uint32_t& nSamplesOut,
wu@webrtc.org94454b72014-06-05 20:34:08 +0000122 int64_t* elapsed_time_ms,
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000123 int64_t* ntp_time_ms)
niklase@google.com470e71d2011-07-07 08:21:25 +0000124{
xians@webrtc.org56925312014-04-14 10:50:37 +0000125 GetPlayoutData(static_cast<int>(samplesPerSec),
126 static_cast<int>(nChannels),
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000127 static_cast<int>(nSamples), true, audioSamples,
wu@webrtc.org94454b72014-06-05 20:34:08 +0000128 elapsed_time_ms, ntp_time_ms);
xians@webrtc.org56925312014-04-14 10:50:37 +0000129 nSamplesOut = _audioFrame.samples_per_channel_;
xians@webrtc.org56925312014-04-14 10:50:37 +0000130 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000131}
132
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000133int VoEBaseImpl::OnDataAvailable(const int voe_channels[],
xians@webrtc.org2f84afa2013-07-31 16:23:37 +0000134 int number_of_voe_channels,
135 const int16_t* audio_data,
136 int sample_rate,
137 int number_of_channels,
138 int number_of_frames,
139 int audio_delay_milliseconds,
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000140 int volume,
xians@webrtc.org2f84afa2013-07-31 16:23:37 +0000141 bool key_pressed,
142 bool need_audio_processing) {
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000143 if (number_of_voe_channels == 0)
144 return 0;
xians@webrtc.org2f84afa2013-07-31 16:23:37 +0000145
146 if (need_audio_processing) {
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000147 return ProcessRecordedDataWithAPM(
148 voe_channels, number_of_voe_channels, audio_data, sample_rate,
149 number_of_channels, number_of_frames, audio_delay_milliseconds,
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000150 0, volume, key_pressed);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +0000151 }
152
153 // No need to go through the APM, demultiplex the data to each VoE channel,
154 // encode and send to the network.
155 for (int i = 0; i < number_of_voe_channels; ++i) {
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000156 // TODO(ajm): In the case where multiple channels are using the same codec
157 // rate, this path needlessly does extra conversions. We should convert once
158 // and share between channels.
xians@webrtc.org56925312014-04-14 10:50:37 +0000159 PushCaptureData(voe_channels[i], audio_data, 16, sample_rate,
160 number_of_channels, number_of_frames);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +0000161 }
162
163 // Return 0 to indicate no need to change the volume.
164 return 0;
165}
166
xians@webrtc.orgc1e28032014-02-02 15:30:20 +0000167void VoEBaseImpl::OnData(int voe_channel, const void* audio_data,
168 int bits_per_sample, int sample_rate,
169 int number_of_channels,
170 int number_of_frames) {
xians@webrtc.org56925312014-04-14 10:50:37 +0000171 PushCaptureData(voe_channel, audio_data, bits_per_sample, sample_rate,
172 number_of_channels, number_of_frames);
173}
174
175void VoEBaseImpl::PushCaptureData(int voe_channel, const void* audio_data,
176 int bits_per_sample, int sample_rate,
177 int number_of_channels,
178 int number_of_frames) {
xians@webrtc.org07e51962014-01-29 13:54:02 +0000179 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(voe_channel);
180 voe::Channel* channel_ptr = ch.channel();
181 if (!channel_ptr)
182 return;
183
henrika@webrtc.org66803482014-04-17 10:45:01 +0000184 if (channel_ptr->Sending()) {
xians@webrtc.org07e51962014-01-29 13:54:02 +0000185 channel_ptr->Demultiplex(static_cast<const int16_t*>(audio_data),
186 sample_rate, number_of_frames, number_of_channels);
187 channel_ptr->PrepareEncodeAndSend(sample_rate);
188 channel_ptr->EncodeAndSend();
189 }
190}
191
xians@webrtc.org56925312014-04-14 10:50:37 +0000192void VoEBaseImpl::PullRenderData(int bits_per_sample, int sample_rate,
193 int number_of_channels, int number_of_frames,
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000194 void* audio_data,
wu@webrtc.org94454b72014-06-05 20:34:08 +0000195 int64_t* elapsed_time_ms,
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000196 int64_t* ntp_time_ms) {
Jelena Marusic6fc2d2f2015-04-13 14:07:04 +0200197 assert(bits_per_sample == 16);
198 assert(number_of_frames == static_cast<int>(sample_rate / 100));
xians@webrtc.org56925312014-04-14 10:50:37 +0000199
200 GetPlayoutData(sample_rate, number_of_channels, number_of_frames, false,
wu@webrtc.org94454b72014-06-05 20:34:08 +0000201 audio_data, elapsed_time_ms, ntp_time_ms);
xians@webrtc.org56925312014-04-14 10:50:37 +0000202}
203
niklase@google.com470e71d2011-07-07 08:21:25 +0000204int VoEBaseImpl::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
205{
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000206 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000207 if (_voiceEngineObserverPtr)
208 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000209 _shared->SetLastError(VE_INVALID_OPERATION, kTraceError,
210 "RegisterVoiceEngineObserver() observer already enabled");
niklase@google.com470e71d2011-07-07 08:21:25 +0000211 return -1;
212 }
213
214 // Register the observer in all active channels
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000215 for (voe::ChannelManager::Iterator it(&_shared->channel_manager());
216 it.IsValid();
217 it.Increment()) {
218 it.GetChannel()->RegisterVoiceEngineObserver(observer);
niklase@google.com470e71d2011-07-07 08:21:25 +0000219 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000220
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000221 _shared->transmit_mixer()->RegisterVoiceEngineObserver(observer);
niklase@google.com470e71d2011-07-07 08:21:25 +0000222 _voiceEngineObserverPtr = &observer;
niklase@google.com470e71d2011-07-07 08:21:25 +0000223 return 0;
224}
225
226int VoEBaseImpl::DeRegisterVoiceEngineObserver()
227{
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000228 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000229 if (!_voiceEngineObserverPtr)
230 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000231 _shared->SetLastError(VE_INVALID_OPERATION, kTraceError,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000232 "DeRegisterVoiceEngineObserver() observer already disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +0000233 return 0;
234 }
235
niklase@google.com470e71d2011-07-07 08:21:25 +0000236 _voiceEngineObserverPtr = NULL;
237
238 // Deregister the observer in all active channels
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000239 for (voe::ChannelManager::Iterator it(&_shared->channel_manager());
240 it.IsValid();
241 it.Increment()) {
242 it.GetChannel()->DeRegisterVoiceEngineObserver();
niklase@google.com470e71d2011-07-07 08:21:25 +0000243 }
244
245 return 0;
246}
247
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000248int VoEBaseImpl::Init(AudioDeviceModule* external_adm,
249 AudioProcessing* audioproc)
niklase@google.com470e71d2011-07-07 08:21:25 +0000250{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000251 CriticalSectionScoped cs(_shared->crit_sec());
niklase@google.com470e71d2011-07-07 08:21:25 +0000252
kma@webrtc.org0221b782012-09-08 00:09:26 +0000253 WebRtcSpl_Init();
254
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000255 if (_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000256 {
257 return 0;
258 }
259
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000260 if (_shared->process_thread())
niklase@google.com470e71d2011-07-07 08:21:25 +0000261 {
tommi@webrtc.org3985f012015-02-27 13:36:34 +0000262 _shared->process_thread()->Start();
niklase@google.com470e71d2011-07-07 08:21:25 +0000263 }
264
andrew@webrtc.org3192d652011-12-21 18:00:59 +0000265 // Create an internal ADM if the user has not added an external
henrika@google.com73d65512011-09-07 15:11:18 +0000266 // ADM implementation as input to Init().
267 if (external_adm == NULL)
niklase@google.com470e71d2011-07-07 08:21:25 +0000268 {
henrika@google.com73d65512011-09-07 15:11:18 +0000269 // Create the internal ADM implementation.
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000270 _shared->set_audio_device(AudioDeviceModuleImpl::Create(
271 VoEId(_shared->instance_id(), -1), _shared->audio_device_layer()));
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000272
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000273 if (_shared->audio_device() == NULL)
niklase@google.com470e71d2011-07-07 08:21:25 +0000274 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000275 _shared->SetLastError(VE_NO_MEMORY, kTraceCritical,
276 "Init() failed to create the ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +0000277 return -1;
278 }
279 }
henrika@google.com73d65512011-09-07 15:11:18 +0000280 else
281 {
282 // Use the already existing external ADM implementation.
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000283 _shared->set_audio_device(external_adm);
Jelena Marusic9e5e4212015-04-13 13:41:56 +0200284 LOG_F(LS_INFO) <<
285 "An external ADM implementation will be used in VoiceEngine";
henrika@google.com73d65512011-09-07 15:11:18 +0000286 }
287
niklase@google.com470e71d2011-07-07 08:21:25 +0000288 // Register the ADM to the process thread, which will drive the error
289 // callback mechanism
tommi@webrtc.org3985f012015-02-27 13:36:34 +0000290 if (_shared->process_thread())
niklase@google.com470e71d2011-07-07 08:21:25 +0000291 {
tommi@webrtc.org3985f012015-02-27 13:36:34 +0000292 _shared->process_thread()->RegisterModule(_shared->audio_device());
niklase@google.com470e71d2011-07-07 08:21:25 +0000293 }
294
295 bool available(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000296
297 // --------------------
298 // Reinitialize the ADM
299
300 // Register the AudioObserver implementation
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000301 if (_shared->audio_device()->RegisterEventObserver(this) != 0) {
302 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
303 "Init() failed to register event observer for the ADM");
xians@webrtc.org79af7342012-01-31 12:22:14 +0000304 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000305
306 // Register the AudioTransport implementation
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000307 if (_shared->audio_device()->RegisterAudioCallback(this) != 0) {
308 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
309 "Init() failed to register audio callback for the ADM");
xians@webrtc.org79af7342012-01-31 12:22:14 +0000310 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000311
312 // ADM initialization
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000313 if (_shared->audio_device()->Init() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000314 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000315 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
316 "Init() failed to initialize the ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +0000317 return -1;
318 }
319
320 // Initialize the default speaker
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000321 if (_shared->audio_device()->SetPlayoutDevice(
322 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000323 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000324 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000325 "Init() failed to set the default output device");
niklase@google.com470e71d2011-07-07 08:21:25 +0000326 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000327 if (_shared->audio_device()->InitSpeaker() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000328 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000329 _shared->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000330 "Init() failed to initialize the speaker");
niklase@google.com470e71d2011-07-07 08:21:25 +0000331 }
332
333 // Initialize the default microphone
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000334 if (_shared->audio_device()->SetRecordingDevice(
335 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000336 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000337 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000338 "Init() failed to set the default input device");
niklase@google.com470e71d2011-07-07 08:21:25 +0000339 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000340 if (_shared->audio_device()->InitMicrophone() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000341 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000342 _shared->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceInfo,
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000343 "Init() failed to initialize the microphone");
niklase@google.com470e71d2011-07-07 08:21:25 +0000344 }
345
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000346 // Set number of channels
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000347 if (_shared->audio_device()->StereoPlayoutIsAvailable(&available) != 0) {
348 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
349 "Init() failed to query stereo playout mode");
xians@webrtc.org79af7342012-01-31 12:22:14 +0000350 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000351 if (_shared->audio_device()->SetStereoPlayout(available) != 0)
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000352 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000353 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000354 "Init() failed to set mono/stereo playout mode");
355 }
andrew@webrtc.org3192d652011-12-21 18:00:59 +0000356
357 // TODO(andrew): These functions don't tell us whether stereo recording
358 // is truly available. We simply set the AudioProcessing input to stereo
359 // here, because we have to wait until receiving the first frame to
360 // determine the actual number of channels anyway.
361 //
362 // These functions may be changed; tracked here:
363 // http://code.google.com/p/webrtc/issues/detail?id=204
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000364 _shared->audio_device()->StereoRecordingIsAvailable(&available);
365 if (_shared->audio_device()->SetStereoRecording(available) != 0)
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000366 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000367 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000368 "Init() failed to set mono/stereo recording mode");
369 }
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000370
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000371 if (!audioproc) {
andrew@webrtc.org46323b32015-01-13 06:48:06 +0000372 audioproc = AudioProcessing::Create();
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000373 if (!audioproc) {
374 LOG(LS_ERROR) << "Failed to create AudioProcessing.";
375 _shared->SetLastError(VE_NO_MEMORY);
376 return -1;
377 }
378 }
379 _shared->set_audio_processing(audioproc);
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000380
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000381 // Set the error state for any failures in this block.
382 _shared->SetLastError(VE_APM_ERROR);
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +0000383 // Configure AudioProcessing components.
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000384 if (audioproc->high_pass_filter()->Enable(true) != 0) {
385 LOG_FERR1(LS_ERROR, high_pass_filter()->Enable, true);
386 return -1;
387 }
388 if (audioproc->echo_cancellation()->enable_drift_compensation(false) != 0) {
389 LOG_FERR1(LS_ERROR, enable_drift_compensation, false);
390 return -1;
391 }
392 if (audioproc->noise_suppression()->set_level(kDefaultNsMode) != 0) {
393 LOG_FERR1(LS_ERROR, noise_suppression()->set_level, kDefaultNsMode);
394 return -1;
395 }
396 GainControl* agc = audioproc->gain_control();
397 if (agc->set_analog_level_limits(kMinVolumeLevel, kMaxVolumeLevel) != 0) {
398 LOG_FERR2(LS_ERROR, agc->set_analog_level_limits, kMinVolumeLevel,
399 kMaxVolumeLevel);
400 return -1;
401 }
402 if (agc->set_mode(kDefaultAgcMode) != 0) {
403 LOG_FERR1(LS_ERROR, agc->set_mode, kDefaultAgcMode);
404 return -1;
405 }
406 if (agc->Enable(kDefaultAgcState) != 0) {
407 LOG_FERR1(LS_ERROR, agc->Enable, kDefaultAgcState);
408 return -1;
409 }
410 _shared->SetLastError(0); // Clear error state.
411
niklase@google.com470e71d2011-07-07 08:21:25 +0000412#ifdef WEBRTC_VOICE_ENGINE_AGC
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000413 bool agc_enabled = agc->mode() == GainControl::kAdaptiveAnalog &&
414 agc->is_enabled();
415 if (_shared->audio_device()->SetAGC(agc_enabled) != 0) {
416 LOG_FERR1(LS_ERROR, audio_device()->SetAGC, agc_enabled);
417 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR);
andrew@webrtc.orga9a1df02013-03-05 23:36:10 +0000418 // TODO(ajm): No error return here due to
419 // https://code.google.com/p/webrtc/issues/detail?id=1464
niklase@google.com470e71d2011-07-07 08:21:25 +0000420 }
421#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000422
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000423 return _shared->statistics().SetInitialized();
niklase@google.com470e71d2011-07-07 08:21:25 +0000424}
425
426int VoEBaseImpl::Terminate()
427{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000428 CriticalSectionScoped cs(_shared->crit_sec());
niklase@google.com470e71d2011-07-07 08:21:25 +0000429 return TerminateInternal();
430}
431
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000432int VoEBaseImpl::CreateChannel() {
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000433 CriticalSectionScoped cs(_shared->crit_sec());
434 if (!_shared->statistics().Initialized()) {
435 _shared->SetLastError(VE_NOT_INITED, kTraceError);
436 return -1;
437 }
438
439 voe::ChannelOwner channel_owner = _shared->channel_manager().CreateChannel();
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000440 return InitializeChannel(&channel_owner);
441}
442
443int VoEBaseImpl::CreateChannel(const Config& config) {
444 CriticalSectionScoped cs(_shared->crit_sec());
445 if (!_shared->statistics().Initialized()) {
446 _shared->SetLastError(VE_NOT_INITED, kTraceError);
447 return -1;
448 }
449 voe::ChannelOwner channel_owner = _shared->channel_manager().CreateChannel(
450 config);
451 return InitializeChannel(&channel_owner);
452}
453
454int VoEBaseImpl::InitializeChannel(voe::ChannelOwner* channel_owner)
niklase@google.com470e71d2011-07-07 08:21:25 +0000455{
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000456 if (channel_owner->channel()->SetEngineInformation(
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000457 _shared->statistics(),
458 *_shared->output_mixer(),
459 *_shared->transmit_mixer(),
460 *_shared->process_thread(),
461 *_shared->audio_device(),
462 _voiceEngineObserverPtr,
463 &_callbackCritSect) != 0) {
464 _shared->SetLastError(
465 VE_CHANNEL_NOT_CREATED,
466 kTraceError,
467 "CreateChannel() failed to associate engine and channel."
468 " Destroying channel.");
469 _shared->channel_manager()
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000470 .DestroyChannel(channel_owner->channel()->ChannelId());
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000471 return -1;
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000472 } else if (channel_owner->channel()->Init() != 0) {
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000473 _shared->SetLastError(
474 VE_CHANNEL_NOT_CREATED,
475 kTraceError,
476 "CreateChannel() failed to initialize channel. Destroying"
477 " channel.");
478 _shared->channel_manager()
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000479 .DestroyChannel(channel_owner->channel()->ChannelId());
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000480 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000481 }
482
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000483 return channel_owner->channel()->ChannelId();
niklase@google.com470e71d2011-07-07 08:21:25 +0000484}
485
486int VoEBaseImpl::DeleteChannel(int channel)
487{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000488 CriticalSectionScoped cs(_shared->crit_sec());
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000489 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000490 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000491 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000492 return -1;
493 }
494
495 {
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000496 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
497 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000498 if (channelPtr == NULL)
499 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000500 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
501 "DeleteChannel() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000502 return -1;
503 }
504 }
505
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000506 _shared->channel_manager().DestroyChannel(channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000507
508 if (StopSend() != 0)
509 {
510 return -1;
511 }
512
513 if (StopPlayout() != 0)
514 {
515 return -1;
516 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +0000517
niklase@google.com470e71d2011-07-07 08:21:25 +0000518 return 0;
519}
520
niklase@google.com470e71d2011-07-07 08:21:25 +0000521int VoEBaseImpl::StartReceive(int channel)
522{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000523 CriticalSectionScoped cs(_shared->crit_sec());
524 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000525 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000526 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000527 return -1;
528 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000529 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
530 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000531 if (channelPtr == NULL)
532 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000533 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
534 "StartReceive() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000535 return -1;
536 }
537 return channelPtr->StartReceiving();
538}
539
540int VoEBaseImpl::StopReceive(int channel)
541{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000542 CriticalSectionScoped cs(_shared->crit_sec());
543 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000544 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000545 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000546 return -1;
547 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000548 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
549 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000550 if (channelPtr == NULL)
551 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000552 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
553 "SetLocalReceiver() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000554 return -1;
555 }
556 return channelPtr->StopReceiving();
557}
558
559int VoEBaseImpl::StartPlayout(int channel)
560{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000561 CriticalSectionScoped cs(_shared->crit_sec());
562 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000563 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000564 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000565 return -1;
566 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000567 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
568 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000569 if (channelPtr == NULL)
570 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000571 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
572 "StartPlayout() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000573 return -1;
574 }
575 if (channelPtr->Playing())
576 {
577 return 0;
578 }
579 if (StartPlayout() != 0)
580 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000581 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
582 "StartPlayout() failed to start playout");
niklase@google.com470e71d2011-07-07 08:21:25 +0000583 return -1;
584 }
585 return channelPtr->StartPlayout();
586}
587
588int VoEBaseImpl::StopPlayout(int channel)
589{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000590 CriticalSectionScoped cs(_shared->crit_sec());
591 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000592 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000593 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000594 return -1;
595 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000596 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
597 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000598 if (channelPtr == NULL)
599 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000600 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
601 "StopPlayout() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000602 return -1;
603 }
604 if (channelPtr->StopPlayout() != 0)
605 {
Jelena Marusic9e5e4212015-04-13 13:41:56 +0200606 LOG_F(LS_WARNING)
607 << "StopPlayout() failed to stop playout for channel " << channel;
niklase@google.com470e71d2011-07-07 08:21:25 +0000608 }
609 return StopPlayout();
610}
611
612int VoEBaseImpl::StartSend(int channel)
613{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000614 CriticalSectionScoped cs(_shared->crit_sec());
615 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000616 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000617 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000618 return -1;
619 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000620 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
621 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000622 if (channelPtr == NULL)
623 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000624 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
625 "StartSend() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000626 return -1;
627 }
628 if (channelPtr->Sending())
629 {
630 return 0;
631 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000632 if (StartSend() != 0)
633 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000634 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
635 "StartSend() failed to start recording");
niklase@google.com470e71d2011-07-07 08:21:25 +0000636 return -1;
637 }
638 return channelPtr->StartSend();
639}
640
641int VoEBaseImpl::StopSend(int channel)
642{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000643 CriticalSectionScoped cs(_shared->crit_sec());
644 if (!_shared->statistics().Initialized())
niklase@google.com470e71d2011-07-07 08:21:25 +0000645 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000646 _shared->SetLastError(VE_NOT_INITED, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000647 return -1;
648 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000649 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
650 voe::Channel* channelPtr = ch.channel();
niklase@google.com470e71d2011-07-07 08:21:25 +0000651 if (channelPtr == NULL)
652 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000653 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
654 "StopSend() failed to locate channel");
niklase@google.com470e71d2011-07-07 08:21:25 +0000655 return -1;
656 }
657 if (channelPtr->StopSend() != 0)
658 {
Jelena Marusic9e5e4212015-04-13 13:41:56 +0200659 LOG_F(LS_WARNING)
660 << "StopSend() failed to stop sending for channel " << channel;
niklase@google.com470e71d2011-07-07 08:21:25 +0000661 }
662 return StopSend();
663}
664
665int VoEBaseImpl::GetVersion(char version[1024])
666{
Jelena Marusic6fc2d2f2015-04-13 14:07:04 +0200667 assert(kVoiceEngineVersionMaxMessageSize == 1024);
niklase@google.com470e71d2011-07-07 08:21:25 +0000668
669 if (version == NULL)
670 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000671 _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError);
niklase@google.com470e71d2011-07-07 08:21:25 +0000672 return (-1);
673 }
674
675 char versionBuf[kVoiceEngineVersionMaxMessageSize];
676 char* versionPtr = versionBuf;
677
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000678 int32_t len = 0;
679 int32_t accLen = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000680
681 len = AddVoEVersion(versionPtr);
682 if (len == -1)
683 {
684 return -1;
685 }
686 versionPtr += len;
687 accLen += len;
Jelena Marusic6fc2d2f2015-04-13 14:07:04 +0200688 assert(accLen < kVoiceEngineVersionMaxMessageSize);
niklase@google.com470e71d2011-07-07 08:21:25 +0000689
pwestin@webrtc.org684f0572013-03-13 23:20:57 +0000690#ifdef WEBRTC_EXTERNAL_TRANSPORT
691 len = AddExternalTransportBuild(versionPtr);
692 if (len == -1)
693 {
694 return -1;
695 }
696 versionPtr += len;
697 accLen += len;
Jelena Marusic6fc2d2f2015-04-13 14:07:04 +0200698 assert(accLen < kVoiceEngineVersionMaxMessageSize);
pwestin@webrtc.org684f0572013-03-13 23:20:57 +0000699#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000700
701 memcpy(version, versionBuf, accLen);
702 version[accLen] = '\0';
703
704 // to avoid the truncation in the trace, split the string into parts
705 char partOfVersion[256];
niklase@google.com470e71d2011-07-07 08:21:25 +0000706 for (int partStart = 0; partStart < accLen;)
707 {
708 memset(partOfVersion, 0, sizeof(partOfVersion));
709 int partEnd = partStart + 180;
710 while (version[partEnd] != '\n' && version[partEnd] != '\0')
711 {
712 partEnd--;
713 }
714 if (partEnd < accLen)
715 {
716 memcpy(partOfVersion, &version[partStart], partEnd - partStart);
717 }
718 else
719 {
720 memcpy(partOfVersion, &version[partStart], accLen - partStart);
721 }
722 partStart = partEnd;
niklase@google.com470e71d2011-07-07 08:21:25 +0000723 }
724
725 return 0;
726}
727
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000728int32_t VoEBaseImpl::AddVoEVersion(char* str) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000729{
730 return sprintf(str, "VoiceEngine 4.1.0\n");
731}
732
pwestin@webrtc.org684f0572013-03-13 23:20:57 +0000733#ifdef WEBRTC_EXTERNAL_TRANSPORT
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000734int32_t VoEBaseImpl::AddExternalTransportBuild(char* str) const
pwestin@webrtc.org684f0572013-03-13 23:20:57 +0000735{
736 return sprintf(str, "External transport build\n");
737}
738#endif
739
niklase@google.com470e71d2011-07-07 08:21:25 +0000740int VoEBaseImpl::LastError()
741{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000742 return (_shared->statistics().LastError());
niklase@google.com470e71d2011-07-07 08:21:25 +0000743}
744
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000745int32_t VoEBaseImpl::StartPlayout()
niklase@google.com470e71d2011-07-07 08:21:25 +0000746{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000747 if (_shared->audio_device()->Playing())
niklase@google.com470e71d2011-07-07 08:21:25 +0000748 {
749 return 0;
750 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000751 if (!_shared->ext_playout())
niklase@google.com470e71d2011-07-07 08:21:25 +0000752 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000753 if (_shared->audio_device()->InitPlayout() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000754 {
Jelena Marusic9e5e4212015-04-13 13:41:56 +0200755 LOG_F(LS_ERROR) << "Failed to initialize playout";
niklase@google.com470e71d2011-07-07 08:21:25 +0000756 return -1;
757 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000758 if (_shared->audio_device()->StartPlayout() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000759 {
Jelena Marusic9e5e4212015-04-13 13:41:56 +0200760 LOG_F(LS_ERROR) << "Failed to start playout";
niklase@google.com470e71d2011-07-07 08:21:25 +0000761 return -1;
762 }
763 }
764 return 0;
765}
766
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000767int32_t VoEBaseImpl::StopPlayout() {
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000768 // Stop audio-device playing if no channel is playing out
xians@webrtc.org675e2602013-10-17 16:15:34 +0000769 if (_shared->NumOfPlayingChannels() == 0) {
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000770 if (_shared->audio_device()->StopPlayout() != 0) {
771 _shared->SetLastError(VE_CANNOT_STOP_PLAYOUT,
772 kTraceError,
773 "StopPlayout() failed to stop playout");
774 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000775 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000776 }
777 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000778}
779
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000780int32_t VoEBaseImpl::StartSend()
niklase@google.com470e71d2011-07-07 08:21:25 +0000781{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000782 if (_shared->audio_device()->Recording())
niklase@google.com470e71d2011-07-07 08:21:25 +0000783 {
784 return 0;
785 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000786 if (!_shared->ext_recording())
niklase@google.com470e71d2011-07-07 08:21:25 +0000787 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000788 if (_shared->audio_device()->InitRecording() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000789 {
Jelena Marusic9e5e4212015-04-13 13:41:56 +0200790 LOG_F(LS_ERROR) << "Failed to initialize recording";
niklase@google.com470e71d2011-07-07 08:21:25 +0000791 return -1;
792 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000793 if (_shared->audio_device()->StartRecording() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000794 {
Jelena Marusic9e5e4212015-04-13 13:41:56 +0200795 LOG_F(LS_ERROR) << "Failed to start recording";
niklase@google.com470e71d2011-07-07 08:21:25 +0000796 return -1;
797 }
798 }
799
800 return 0;
801}
802
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000803int32_t VoEBaseImpl::StopSend()
niklase@google.com470e71d2011-07-07 08:21:25 +0000804{
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000805 if (_shared->NumOfSendingChannels() == 0 &&
806 !_shared->transmit_mixer()->IsRecordingMic())
niklase@google.com470e71d2011-07-07 08:21:25 +0000807 {
808 // Stop audio-device recording if no channel is recording
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000809 if (_shared->audio_device()->StopRecording() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000810 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000811 _shared->SetLastError(VE_CANNOT_STOP_RECORDING, kTraceError,
812 "StopSend() failed to stop recording");
niklase@google.com470e71d2011-07-07 08:21:25 +0000813 return -1;
814 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000815 _shared->transmit_mixer()->StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000816 }
817
818 return 0;
819}
820
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000821int32_t VoEBaseImpl::TerminateInternal()
niklase@google.com470e71d2011-07-07 08:21:25 +0000822{
niklase@google.com470e71d2011-07-07 08:21:25 +0000823 // Delete any remaining channel objects
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000824 _shared->channel_manager().DestroyAllChannels();
niklase@google.com470e71d2011-07-07 08:21:25 +0000825
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000826 if (_shared->process_thread())
niklase@google.com470e71d2011-07-07 08:21:25 +0000827 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000828 if (_shared->audio_device())
niklase@google.com470e71d2011-07-07 08:21:25 +0000829 {
tommi@webrtc.org3985f012015-02-27 13:36:34 +0000830 _shared->process_thread()->DeRegisterModule(
831 _shared->audio_device());
niklase@google.com470e71d2011-07-07 08:21:25 +0000832 }
tommi@webrtc.org3985f012015-02-27 13:36:34 +0000833 _shared->process_thread()->Stop();
niklase@google.com470e71d2011-07-07 08:21:25 +0000834 }
835
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000836 if (_shared->audio_device())
niklase@google.com470e71d2011-07-07 08:21:25 +0000837 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000838 if (_shared->audio_device()->StopPlayout() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000839 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000840 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
841 "TerminateInternal() failed to stop playout");
niklase@google.com470e71d2011-07-07 08:21:25 +0000842 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000843 if (_shared->audio_device()->StopRecording() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000844 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000845 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
846 "TerminateInternal() failed to stop recording");
niklase@google.com470e71d2011-07-07 08:21:25 +0000847 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000848 if (_shared->audio_device()->RegisterEventObserver(NULL) != 0) {
849 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
850 "TerminateInternal() failed to de-register event observer "
851 "for the ADM");
xians@webrtc.org79af7342012-01-31 12:22:14 +0000852 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000853 if (_shared->audio_device()->RegisterAudioCallback(NULL) != 0) {
854 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
855 "TerminateInternal() failed to de-register audio callback "
856 "for the ADM");
xians@webrtc.org79af7342012-01-31 12:22:14 +0000857 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000858 if (_shared->audio_device()->Terminate() != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000859 {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000860 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
861 "TerminateInternal() failed to terminate the ADM");
niklase@google.com470e71d2011-07-07 08:21:25 +0000862 }
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000863 _shared->set_audio_device(NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000864 }
865
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000866 if (_shared->audio_processing()) {
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000867 _shared->set_audio_processing(NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000868 }
869
tommi@webrtc.org851becd2012-04-04 14:57:19 +0000870 return _shared->statistics().SetUnInitialized();
niklase@google.com470e71d2011-07-07 08:21:25 +0000871}
872
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000873int VoEBaseImpl::ProcessRecordedDataWithAPM(
874 const int voe_channels[],
875 int number_of_voe_channels,
876 const void* audio_data,
877 uint32_t sample_rate,
878 uint8_t number_of_channels,
879 uint32_t number_of_frames,
880 uint32_t audio_delay_milliseconds,
881 int32_t clock_drift,
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000882 uint32_t volume,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000883 bool key_pressed) {
Jelena Marusic6fc2d2f2015-04-13 14:07:04 +0200884 assert(_shared->transmit_mixer() != nullptr);
885 assert(_shared->audio_device() != nullptr);
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000886
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000887 uint32_t max_volume = 0;
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000888 uint16_t voe_mic_level = 0;
andrew@webrtc.org023cc5a2014-01-11 01:25:53 +0000889 // Check for zero to skip this calculation; the consumer may use this to
890 // indicate no volume is available.
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000891 if (volume != 0) {
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000892 // Scale from ADM to VoE level range
893 if (_shared->audio_device()->MaxMicrophoneVolume(&max_volume) == 0) {
894 if (max_volume) {
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000895 voe_mic_level = static_cast<uint16_t>(
896 (volume * kMaxVolumeLevel +
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000897 static_cast<int>(max_volume / 2)) / max_volume);
898 }
899 }
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000900 // We learned that on certain systems (e.g Linux) the voe_mic_level
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000901 // can be greater than the maxVolumeLevel therefore
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000902 // we are going to cap the voe_mic_level to the maxVolumeLevel
903 // and change the maxVolume to volume if it turns out that
904 // the voe_mic_level is indeed greater than the maxVolumeLevel.
905 if (voe_mic_level > kMaxVolumeLevel) {
906 voe_mic_level = kMaxVolumeLevel;
907 max_volume = volume;
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000908 }
909 }
910
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000911 // Perform channel-independent operations
912 // (APM, mix with file, record to file, mute, etc.)
913 _shared->transmit_mixer()->PrepareDemux(
914 audio_data, number_of_frames, number_of_channels, sample_rate,
915 static_cast<uint16_t>(audio_delay_milliseconds), clock_drift,
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000916 voe_mic_level, key_pressed);
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000917
918 // Copy the audio frame to each sending channel and perform
919 // channel-dependent operations (file mixing, mute, etc.), encode and
920 // packetize+transmit the RTP packet. When |number_of_voe_channels| == 0,
921 // do the operations on all the existing VoE channels; otherwise the
922 // operations will be done on specific channels.
923 if (number_of_voe_channels == 0) {
924 _shared->transmit_mixer()->DemuxAndMix();
925 _shared->transmit_mixer()->EncodeAndSend();
926 } else {
927 _shared->transmit_mixer()->DemuxAndMix(voe_channels,
928 number_of_voe_channels);
929 _shared->transmit_mixer()->EncodeAndSend(voe_channels,
930 number_of_voe_channels);
931 }
932
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000933 // Scale from VoE to ADM level range.
934 uint32_t new_voe_mic_level = _shared->transmit_mixer()->CaptureLevel();
935
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000936 if (new_voe_mic_level != voe_mic_level) {
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000937 // Return the new volume if AGC has changed the volume.
938 return static_cast<int>(
939 (new_voe_mic_level * max_volume +
940 static_cast<int>(kMaxVolumeLevel / 2)) / kMaxVolumeLevel);
941 }
942
943 // Return 0 to indicate no change on the volume.
944 return 0;
945}
946
xians@webrtc.org56925312014-04-14 10:50:37 +0000947void VoEBaseImpl::GetPlayoutData(int sample_rate, int number_of_channels,
948 int number_of_frames, bool feed_data_to_apm,
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000949 void* audio_data,
wu@webrtc.org94454b72014-06-05 20:34:08 +0000950 int64_t* elapsed_time_ms,
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000951 int64_t* ntp_time_ms) {
Jelena Marusic6fc2d2f2015-04-13 14:07:04 +0200952 assert(_shared->output_mixer() != nullptr);
xians@webrtc.org56925312014-04-14 10:50:37 +0000953
954 // TODO(andrew): if the device is running in mono, we should tell the mixer
955 // here so that it will only request mono from AudioCodingModule.
956 // Perform mixing of all active participants (channel-based mixing)
957 _shared->output_mixer()->MixActiveChannels();
958
959 // Additional operations on the combined signal
960 _shared->output_mixer()->DoOperationsOnCombinedSignal(feed_data_to_apm);
961
962 // Retrieve the final output mix (resampled to match the ADM)
963 _shared->output_mixer()->GetMixedAudio(sample_rate, number_of_channels,
964 &_audioFrame);
965
Jelena Marusic6fc2d2f2015-04-13 14:07:04 +0200966 assert(number_of_frames == _audioFrame.samples_per_channel_);
967 assert(sample_rate == _audioFrame.sample_rate_hz_);
xians@webrtc.org56925312014-04-14 10:50:37 +0000968
969 // Deliver audio (PCM) samples to the ADM
970 memcpy(audio_data, _audioFrame.data_,
971 sizeof(int16_t) * number_of_frames * number_of_channels);
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000972
wu@webrtc.org94454b72014-06-05 20:34:08 +0000973 *elapsed_time_ms = _audioFrame.elapsed_time_ms_;
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000974 *ntp_time_ms = _audioFrame.ntp_time_ms_;
xians@webrtc.org56925312014-04-14 10:50:37 +0000975}
976
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000977} // namespace webrtc