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