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