• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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