1 /*
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "webrtc/voice_engine/voe_hardware_impl.h"
12
13 #include <assert.h>
14
15 #include "webrtc/system_wrappers/include/critical_section_wrapper.h"
16 #include "webrtc/system_wrappers/include/trace.h"
17 #include "webrtc/voice_engine/include/voe_errors.h"
18 #include "webrtc/voice_engine/voice_engine_impl.h"
19
20 namespace webrtc {
21
GetInterface(VoiceEngine * voiceEngine)22 VoEHardware* VoEHardware::GetInterface(VoiceEngine* voiceEngine) {
23 #ifndef WEBRTC_VOICE_ENGINE_HARDWARE_API
24 return NULL;
25 #else
26 if (NULL == voiceEngine) {
27 return NULL;
28 }
29 VoiceEngineImpl* s = static_cast<VoiceEngineImpl*>(voiceEngine);
30 s->AddRef();
31 return s;
32 #endif
33 }
34
35 #ifdef WEBRTC_VOICE_ENGINE_HARDWARE_API
36
VoEHardwareImpl(voe::SharedData * shared)37 VoEHardwareImpl::VoEHardwareImpl(voe::SharedData* shared) : _shared(shared) {
38 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
39 "VoEHardwareImpl() - ctor");
40 }
41
~VoEHardwareImpl()42 VoEHardwareImpl::~VoEHardwareImpl() {
43 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
44 "~VoEHardwareImpl() - dtor");
45 }
46
SetAudioDeviceLayer(AudioLayers audioLayer)47 int VoEHardwareImpl::SetAudioDeviceLayer(AudioLayers audioLayer) {
48 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
49 "SetAudioDeviceLayer(audioLayer=%d)", audioLayer);
50
51 // Don't allow a change if VoE is initialized
52 if (_shared->statistics().Initialized()) {
53 _shared->SetLastError(VE_ALREADY_INITED, kTraceError);
54 return -1;
55 }
56
57 // Map to AudioDeviceModule::AudioLayer
58 AudioDeviceModule::AudioLayer wantedLayer(
59 AudioDeviceModule::kPlatformDefaultAudio);
60 switch (audioLayer) {
61 case kAudioPlatformDefault:
62 // already set above
63 break;
64 case kAudioWindowsCore:
65 wantedLayer = AudioDeviceModule::kWindowsCoreAudio;
66 break;
67 case kAudioWindowsWave:
68 wantedLayer = AudioDeviceModule::kWindowsWaveAudio;
69 break;
70 case kAudioLinuxAlsa:
71 wantedLayer = AudioDeviceModule::kLinuxAlsaAudio;
72 break;
73 case kAudioLinuxPulse:
74 wantedLayer = AudioDeviceModule::kLinuxPulseAudio;
75 break;
76 }
77
78 // Save the audio device layer for Init()
79 _shared->set_audio_device_layer(wantedLayer);
80
81 return 0;
82 }
83
GetAudioDeviceLayer(AudioLayers & audioLayer)84 int VoEHardwareImpl::GetAudioDeviceLayer(AudioLayers& audioLayer) {
85 // Can always be called regardless of VoE state
86
87 AudioDeviceModule::AudioLayer activeLayer(
88 AudioDeviceModule::kPlatformDefaultAudio);
89
90 if (_shared->audio_device()) {
91 // Get active audio layer from ADM
92 if (_shared->audio_device()->ActiveAudioLayer(&activeLayer) != 0) {
93 _shared->SetLastError(VE_UNDEFINED_SC_ERR, kTraceError,
94 " Audio Device error");
95 return -1;
96 }
97 } else {
98 // Return VoE's internal layer setting
99 activeLayer = _shared->audio_device_layer();
100 }
101
102 // Map to AudioLayers
103 switch (activeLayer) {
104 case AudioDeviceModule::kPlatformDefaultAudio:
105 audioLayer = kAudioPlatformDefault;
106 break;
107 case AudioDeviceModule::kWindowsCoreAudio:
108 audioLayer = kAudioWindowsCore;
109 break;
110 case AudioDeviceModule::kWindowsWaveAudio:
111 audioLayer = kAudioWindowsWave;
112 break;
113 case AudioDeviceModule::kLinuxAlsaAudio:
114 audioLayer = kAudioLinuxAlsa;
115 break;
116 case AudioDeviceModule::kLinuxPulseAudio:
117 audioLayer = kAudioLinuxPulse;
118 break;
119 default:
120 _shared->SetLastError(VE_UNDEFINED_SC_ERR, kTraceError,
121 " unknown audio layer");
122 }
123
124 return 0;
125 }
GetNumOfRecordingDevices(int & devices)126 int VoEHardwareImpl::GetNumOfRecordingDevices(int& devices) {
127 if (!_shared->statistics().Initialized()) {
128 _shared->SetLastError(VE_NOT_INITED, kTraceError);
129 return -1;
130 }
131
132 devices = static_cast<int>(_shared->audio_device()->RecordingDevices());
133
134 return 0;
135 }
136
GetNumOfPlayoutDevices(int & devices)137 int VoEHardwareImpl::GetNumOfPlayoutDevices(int& devices) {
138 if (!_shared->statistics().Initialized()) {
139 _shared->SetLastError(VE_NOT_INITED, kTraceError);
140 return -1;
141 }
142
143 devices = static_cast<int>(_shared->audio_device()->PlayoutDevices());
144
145 return 0;
146 }
147
GetRecordingDeviceName(int index,char strNameUTF8[128],char strGuidUTF8[128])148 int VoEHardwareImpl::GetRecordingDeviceName(int index,
149 char strNameUTF8[128],
150 char strGuidUTF8[128]) {
151 if (!_shared->statistics().Initialized()) {
152 _shared->SetLastError(VE_NOT_INITED, kTraceError);
153 return -1;
154 }
155 if (strNameUTF8 == NULL) {
156 _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
157 "GetRecordingDeviceName() invalid argument");
158 return -1;
159 }
160
161 // Note that strGuidUTF8 is allowed to be NULL
162
163 // Init len variable to length of supplied vectors
164 const uint16_t strLen = 128;
165
166 // Check if length has been changed in module
167 static_assert(strLen == kAdmMaxDeviceNameSize, "");
168 static_assert(strLen == kAdmMaxGuidSize, "");
169
170 char name[strLen];
171 char guid[strLen];
172
173 // Get names from module
174 if (_shared->audio_device()->RecordingDeviceName(index, name, guid) != 0) {
175 _shared->SetLastError(VE_CANNOT_RETRIEVE_DEVICE_NAME, kTraceError,
176 "GetRecordingDeviceName() failed to get device name");
177 return -1;
178 }
179
180 // Copy to vectors supplied by user
181 strncpy(strNameUTF8, name, strLen);
182
183 if (strGuidUTF8 != NULL) {
184 strncpy(strGuidUTF8, guid, strLen);
185 }
186
187 return 0;
188 }
189
GetPlayoutDeviceName(int index,char strNameUTF8[128],char strGuidUTF8[128])190 int VoEHardwareImpl::GetPlayoutDeviceName(int index,
191 char strNameUTF8[128],
192 char strGuidUTF8[128]) {
193 if (!_shared->statistics().Initialized()) {
194 _shared->SetLastError(VE_NOT_INITED, kTraceError);
195 return -1;
196 }
197 if (strNameUTF8 == NULL) {
198 _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
199 "GetPlayoutDeviceName() invalid argument");
200 return -1;
201 }
202
203 // Note that strGuidUTF8 is allowed to be NULL
204
205 // Init len variable to length of supplied vectors
206 const uint16_t strLen = 128;
207
208 // Check if length has been changed in module
209 static_assert(strLen == kAdmMaxDeviceNameSize, "");
210 static_assert(strLen == kAdmMaxGuidSize, "");
211
212 char name[strLen];
213 char guid[strLen];
214
215 // Get names from module
216 if (_shared->audio_device()->PlayoutDeviceName(index, name, guid) != 0) {
217 _shared->SetLastError(VE_CANNOT_RETRIEVE_DEVICE_NAME, kTraceError,
218 "GetPlayoutDeviceName() failed to get device name");
219 return -1;
220 }
221
222 // Copy to vectors supplied by user
223 strncpy(strNameUTF8, name, strLen);
224
225 if (strGuidUTF8 != NULL) {
226 strncpy(strGuidUTF8, guid, strLen);
227 }
228
229 return 0;
230 }
231
SetRecordingDevice(int index,StereoChannel recordingChannel)232 int VoEHardwareImpl::SetRecordingDevice(int index,
233 StereoChannel recordingChannel) {
234 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
235 "SetRecordingDevice(index=%d, recordingChannel=%d)", index,
236 (int)recordingChannel);
237 CriticalSectionScoped cs(_shared->crit_sec());
238
239 if (!_shared->statistics().Initialized()) {
240 _shared->SetLastError(VE_NOT_INITED, kTraceError);
241 return -1;
242 }
243
244 bool isRecording(false);
245
246 // Store state about activated recording to be able to restore it after the
247 // recording device has been modified.
248 if (_shared->audio_device()->Recording()) {
249 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
250 "SetRecordingDevice() device is modified while recording"
251 " is active...");
252 isRecording = true;
253 if (_shared->audio_device()->StopRecording() == -1) {
254 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
255 "SetRecordingDevice() unable to stop recording");
256 return -1;
257 }
258 }
259
260 // We let the module do the index sanity
261
262 // Set recording channel
263 AudioDeviceModule::ChannelType recCh = AudioDeviceModule::kChannelBoth;
264 switch (recordingChannel) {
265 case kStereoLeft:
266 recCh = AudioDeviceModule::kChannelLeft;
267 break;
268 case kStereoRight:
269 recCh = AudioDeviceModule::kChannelRight;
270 break;
271 case kStereoBoth:
272 // default setting kChannelBoth (<=> mono)
273 break;
274 }
275
276 if (_shared->audio_device()->SetRecordingChannel(recCh) != 0) {
277 _shared->SetLastError(
278 VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
279 "SetRecordingChannel() unable to set the recording channel");
280 }
281
282 // Map indices to unsigned since underlying functions need that
283 uint16_t indexU = static_cast<uint16_t>(index);
284
285 int32_t res(0);
286
287 if (index == -1) {
288 res = _shared->audio_device()->SetRecordingDevice(
289 AudioDeviceModule::kDefaultCommunicationDevice);
290 } else if (index == -2) {
291 res = _shared->audio_device()->SetRecordingDevice(
292 AudioDeviceModule::kDefaultDevice);
293 } else {
294 res = _shared->audio_device()->SetRecordingDevice(indexU);
295 }
296
297 if (res != 0) {
298 _shared->SetLastError(
299 VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
300 "SetRecordingDevice() unable to set the recording device");
301 return -1;
302 }
303
304 // Init microphone, so user can do volume settings etc
305 if (_shared->audio_device()->InitMicrophone() == -1) {
306 _shared->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceWarning,
307 "SetRecordingDevice() cannot access microphone");
308 }
309
310 // Set number of channels
311 bool available = false;
312 if (_shared->audio_device()->StereoRecordingIsAvailable(&available) != 0) {
313 _shared->SetLastError(
314 VE_SOUNDCARD_ERROR, kTraceWarning,
315 "StereoRecordingIsAvailable() failed to query stereo recording");
316 }
317
318 if (_shared->audio_device()->SetStereoRecording(available) != 0) {
319 _shared->SetLastError(
320 VE_SOUNDCARD_ERROR, kTraceWarning,
321 "SetRecordingDevice() failed to set mono recording mode");
322 }
323
324 // Restore recording if it was enabled already when calling this function.
325 if (isRecording) {
326 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
327 "SetRecordingDevice() recording is now being restored...");
328 if (_shared->audio_device()->InitRecording() != 0) {
329 WEBRTC_TRACE(kTraceError, kTraceVoice,
330 VoEId(_shared->instance_id(), -1),
331 "SetRecordingDevice() failed to initialize recording");
332 return -1;
333 }
334 if (_shared->audio_device()->StartRecording() != 0) {
335 WEBRTC_TRACE(kTraceError, kTraceVoice,
336 VoEId(_shared->instance_id(), -1),
337 "SetRecordingDevice() failed to start recording");
338 return -1;
339 }
340 }
341
342 return 0;
343 }
344
SetPlayoutDevice(int index)345 int VoEHardwareImpl::SetPlayoutDevice(int index) {
346 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
347 "SetPlayoutDevice(index=%d)", index);
348 CriticalSectionScoped cs(_shared->crit_sec());
349
350 if (!_shared->statistics().Initialized()) {
351 _shared->SetLastError(VE_NOT_INITED, kTraceError);
352 return -1;
353 }
354
355 bool isPlaying(false);
356
357 // Store state about activated playout to be able to restore it after the
358 // playout device has been modified.
359 if (_shared->audio_device()->Playing()) {
360 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
361 "SetPlayoutDevice() device is modified while playout is "
362 "active...");
363 isPlaying = true;
364 if (_shared->audio_device()->StopPlayout() == -1) {
365 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
366 "SetPlayoutDevice() unable to stop playout");
367 return -1;
368 }
369 }
370
371 // We let the module do the index sanity
372
373 // Map indices to unsigned since underlying functions need that
374 uint16_t indexU = static_cast<uint16_t>(index);
375
376 int32_t res(0);
377
378 if (index == -1) {
379 res = _shared->audio_device()->SetPlayoutDevice(
380 AudioDeviceModule::kDefaultCommunicationDevice);
381 } else if (index == -2) {
382 res = _shared->audio_device()->SetPlayoutDevice(
383 AudioDeviceModule::kDefaultDevice);
384 } else {
385 res = _shared->audio_device()->SetPlayoutDevice(indexU);
386 }
387
388 if (res != 0) {
389 _shared->SetLastError(
390 VE_SOUNDCARD_ERROR, kTraceError,
391 "SetPlayoutDevice() unable to set the playout device");
392 return -1;
393 }
394
395 // Init speaker, so user can do volume settings etc
396 if (_shared->audio_device()->InitSpeaker() == -1) {
397 _shared->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceWarning,
398 "SetPlayoutDevice() cannot access speaker");
399 }
400
401 // Set number of channels
402 bool available = false;
403 _shared->audio_device()->StereoPlayoutIsAvailable(&available);
404 if (_shared->audio_device()->SetStereoPlayout(available) != 0) {
405 _shared->SetLastError(
406 VE_SOUNDCARD_ERROR, kTraceWarning,
407 "SetPlayoutDevice() failed to set stereo playout mode");
408 }
409
410 // Restore playout if it was enabled already when calling this function.
411 if (isPlaying) {
412 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
413 "SetPlayoutDevice() playout is now being restored...");
414 if (_shared->audio_device()->InitPlayout() != 0) {
415 WEBRTC_TRACE(kTraceError, kTraceVoice,
416 VoEId(_shared->instance_id(), -1),
417 "SetPlayoutDevice() failed to initialize playout");
418 return -1;
419 }
420 if (_shared->audio_device()->StartPlayout() != 0) {
421 WEBRTC_TRACE(kTraceError, kTraceVoice,
422 VoEId(_shared->instance_id(), -1),
423 "SetPlayoutDevice() failed to start playout");
424 return -1;
425 }
426 }
427
428 return 0;
429 }
430
SetRecordingSampleRate(unsigned int samples_per_sec)431 int VoEHardwareImpl::SetRecordingSampleRate(unsigned int samples_per_sec) {
432 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
433 "%s", __FUNCTION__);
434 if (!_shared->statistics().Initialized()) {
435 _shared->SetLastError(VE_NOT_INITED, kTraceError);
436 return false;
437 }
438 return _shared->audio_device()->SetRecordingSampleRate(samples_per_sec);
439 }
440
RecordingSampleRate(unsigned int * samples_per_sec) const441 int VoEHardwareImpl::RecordingSampleRate(unsigned int* samples_per_sec) const {
442 if (!_shared->statistics().Initialized()) {
443 _shared->SetLastError(VE_NOT_INITED, kTraceError);
444 return false;
445 }
446 return _shared->audio_device()->RecordingSampleRate(samples_per_sec);
447 }
448
SetPlayoutSampleRate(unsigned int samples_per_sec)449 int VoEHardwareImpl::SetPlayoutSampleRate(unsigned int samples_per_sec) {
450 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
451 "%s", __FUNCTION__);
452 if (!_shared->statistics().Initialized()) {
453 _shared->SetLastError(VE_NOT_INITED, kTraceError);
454 return false;
455 }
456 return _shared->audio_device()->SetPlayoutSampleRate(samples_per_sec);
457 }
458
PlayoutSampleRate(unsigned int * samples_per_sec) const459 int VoEHardwareImpl::PlayoutSampleRate(unsigned int* samples_per_sec) const {
460 if (!_shared->statistics().Initialized()) {
461 _shared->SetLastError(VE_NOT_INITED, kTraceError);
462 return false;
463 }
464 return _shared->audio_device()->PlayoutSampleRate(samples_per_sec);
465 }
466
BuiltInAECIsAvailable() const467 bool VoEHardwareImpl::BuiltInAECIsAvailable() const {
468 if (!_shared->statistics().Initialized()) {
469 _shared->SetLastError(VE_NOT_INITED, kTraceError);
470 return false;
471 }
472 return _shared->audio_device()->BuiltInAECIsAvailable();
473 }
474
EnableBuiltInAEC(bool enable)475 int VoEHardwareImpl::EnableBuiltInAEC(bool enable) {
476 if (!_shared->statistics().Initialized()) {
477 _shared->SetLastError(VE_NOT_INITED, kTraceError);
478 return -1;
479 }
480 return _shared->audio_device()->EnableBuiltInAEC(enable);
481 }
482
BuiltInAGCIsAvailable() const483 bool VoEHardwareImpl::BuiltInAGCIsAvailable() const {
484 if (!_shared->statistics().Initialized()) {
485 _shared->SetLastError(VE_NOT_INITED, kTraceError);
486 return false;
487 }
488 return _shared->audio_device()->BuiltInAGCIsAvailable();
489 }
490
EnableBuiltInAGC(bool enable)491 int VoEHardwareImpl::EnableBuiltInAGC(bool enable) {
492 if (!_shared->statistics().Initialized()) {
493 _shared->SetLastError(VE_NOT_INITED, kTraceError);
494 return -1;
495 }
496 return _shared->audio_device()->EnableBuiltInAGC(enable);
497 }
498
BuiltInNSIsAvailable() const499 bool VoEHardwareImpl::BuiltInNSIsAvailable() const {
500 if (!_shared->statistics().Initialized()) {
501 _shared->SetLastError(VE_NOT_INITED, kTraceError);
502 return false;
503 }
504 return _shared->audio_device()->BuiltInNSIsAvailable();
505 }
506
EnableBuiltInNS(bool enable)507 int VoEHardwareImpl::EnableBuiltInNS(bool enable) {
508 if (!_shared->statistics().Initialized()) {
509 _shared->SetLastError(VE_NOT_INITED, kTraceError);
510 return -1;
511 }
512 return _shared->audio_device()->EnableBuiltInNS(enable);
513 }
514
515 #endif // WEBRTC_VOICE_ENGINE_HARDWARE_API
516
517 } // namespace webrtc
518