• 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 "modules/audio_device/linux/audio_device_alsa_linux.h"
12 
13 #include <assert.h>
14 
15 #include "modules/audio_device/audio_device_config.h"
16 #include "rtc_base/logging.h"
17 #include "rtc_base/system/arch.h"
18 #include "system_wrappers/include/sleep.h"
19 
GetAlsaSymbolTable()20 WebRTCAlsaSymbolTable* GetAlsaSymbolTable() {
21   static WebRTCAlsaSymbolTable* alsa_symbol_table = new WebRTCAlsaSymbolTable();
22   return alsa_symbol_table;
23 }
24 
25 // Accesses ALSA functions through our late-binding symbol table instead of
26 // directly. This way we don't have to link to libasound, which means our binary
27 // will work on systems that don't have it.
28 #define LATE(sym)                                                            \
29   LATESYM_GET(webrtc::adm_linux_alsa::AlsaSymbolTable, GetAlsaSymbolTable(), \
30               sym)
31 
32 // Redefine these here to be able to do late-binding
33 #undef snd_ctl_card_info_alloca
34 #define snd_ctl_card_info_alloca(ptr)                  \
35   do {                                                 \
36     *ptr = (snd_ctl_card_info_t*)__builtin_alloca(     \
37         LATE(snd_ctl_card_info_sizeof)());             \
38     memset(*ptr, 0, LATE(snd_ctl_card_info_sizeof)()); \
39   } while (0)
40 
41 #undef snd_pcm_info_alloca
42 #define snd_pcm_info_alloca(pInfo)                                           \
43   do {                                                                       \
44     *pInfo = (snd_pcm_info_t*)__builtin_alloca(LATE(snd_pcm_info_sizeof)()); \
45     memset(*pInfo, 0, LATE(snd_pcm_info_sizeof)());                          \
46   } while (0)
47 
48 // snd_lib_error_handler_t
WebrtcAlsaErrorHandler(const char * file,int line,const char * function,int err,const char * fmt,...)49 void WebrtcAlsaErrorHandler(const char* file,
50                             int line,
51                             const char* function,
52                             int err,
53                             const char* fmt,
54                             ...) {}
55 
56 namespace webrtc {
57 static const unsigned int ALSA_PLAYOUT_FREQ = 48000;
58 static const unsigned int ALSA_PLAYOUT_CH = 2;
59 static const unsigned int ALSA_PLAYOUT_LATENCY = 40 * 1000;  // in us
60 static const unsigned int ALSA_CAPTURE_FREQ = 48000;
61 static const unsigned int ALSA_CAPTURE_CH = 2;
62 static const unsigned int ALSA_CAPTURE_LATENCY = 40 * 1000;  // in us
63 static const unsigned int ALSA_CAPTURE_WAIT_TIMEOUT = 5;     // in ms
64 
65 #define FUNC_GET_NUM_OF_DEVICE 0
66 #define FUNC_GET_DEVICE_NAME 1
67 #define FUNC_GET_DEVICE_NAME_FOR_AN_ENUM 2
68 
AudioDeviceLinuxALSA()69 AudioDeviceLinuxALSA::AudioDeviceLinuxALSA()
70     : _ptrAudioBuffer(NULL),
71       _inputDeviceIndex(0),
72       _outputDeviceIndex(0),
73       _inputDeviceIsSpecified(false),
74       _outputDeviceIsSpecified(false),
75       _handleRecord(NULL),
76       _handlePlayout(NULL),
77       _recordingBuffersizeInFrame(0),
78       _recordingPeriodSizeInFrame(0),
79       _playoutBufferSizeInFrame(0),
80       _playoutPeriodSizeInFrame(0),
81       _recordingBufferSizeIn10MS(0),
82       _playoutBufferSizeIn10MS(0),
83       _recordingFramesIn10MS(0),
84       _playoutFramesIn10MS(0),
85       _recordingFreq(ALSA_CAPTURE_FREQ),
86       _playoutFreq(ALSA_PLAYOUT_FREQ),
87       _recChannels(ALSA_CAPTURE_CH),
88       _playChannels(ALSA_PLAYOUT_CH),
89       _recordingBuffer(NULL),
90       _playoutBuffer(NULL),
91       _recordingFramesLeft(0),
92       _playoutFramesLeft(0),
93       _initialized(false),
94       _recording(false),
95       _playing(false),
96       _recIsInitialized(false),
97       _playIsInitialized(false),
98       _recordingDelay(0),
99       _playoutDelay(0) {
100   memset(_oldKeyState, 0, sizeof(_oldKeyState));
101   RTC_LOG(LS_INFO) << __FUNCTION__ << " created";
102 }
103 
104 // ----------------------------------------------------------------------------
105 //  AudioDeviceLinuxALSA - dtor
106 // ----------------------------------------------------------------------------
107 
~AudioDeviceLinuxALSA()108 AudioDeviceLinuxALSA::~AudioDeviceLinuxALSA() {
109   RTC_LOG(LS_INFO) << __FUNCTION__ << " destroyed";
110 
111   Terminate();
112 
113   // Clean up the recording buffer and playout buffer.
114   if (_recordingBuffer) {
115     delete[] _recordingBuffer;
116     _recordingBuffer = NULL;
117   }
118   if (_playoutBuffer) {
119     delete[] _playoutBuffer;
120     _playoutBuffer = NULL;
121   }
122 }
123 
AttachAudioBuffer(AudioDeviceBuffer * audioBuffer)124 void AudioDeviceLinuxALSA::AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) {
125   MutexLock lock(&mutex_);
126 
127   _ptrAudioBuffer = audioBuffer;
128 
129   // Inform the AudioBuffer about default settings for this implementation.
130   // Set all values to zero here since the actual settings will be done by
131   // InitPlayout and InitRecording later.
132   _ptrAudioBuffer->SetRecordingSampleRate(0);
133   _ptrAudioBuffer->SetPlayoutSampleRate(0);
134   _ptrAudioBuffer->SetRecordingChannels(0);
135   _ptrAudioBuffer->SetPlayoutChannels(0);
136 }
137 
ActiveAudioLayer(AudioDeviceModule::AudioLayer & audioLayer) const138 int32_t AudioDeviceLinuxALSA::ActiveAudioLayer(
139     AudioDeviceModule::AudioLayer& audioLayer) const {
140   audioLayer = AudioDeviceModule::kLinuxAlsaAudio;
141   return 0;
142 }
143 
Init()144 AudioDeviceGeneric::InitStatus AudioDeviceLinuxALSA::Init() {
145   MutexLock lock(&mutex_);
146 
147   // Load libasound
148   if (!GetAlsaSymbolTable()->Load()) {
149     // Alsa is not installed on this system
150     RTC_LOG(LS_ERROR) << "failed to load symbol table";
151     return InitStatus::OTHER_ERROR;
152   }
153 
154   if (_initialized) {
155     return InitStatus::OK;
156   }
157 #if defined(WEBRTC_USE_X11)
158   // Get X display handle for typing detection
159   _XDisplay = XOpenDisplay(NULL);
160   if (!_XDisplay) {
161     RTC_LOG(LS_WARNING)
162         << "failed to open X display, typing detection will not work";
163   }
164 #endif
165 
166   _initialized = true;
167 
168   return InitStatus::OK;
169 }
170 
Terminate()171 int32_t AudioDeviceLinuxALSA::Terminate() {
172   if (!_initialized) {
173     return 0;
174   }
175 
176   MutexLock lock(&mutex_);
177 
178   _mixerManager.Close();
179 
180   // RECORDING
181   if (_ptrThreadRec) {
182     rtc::PlatformThread* tmpThread = _ptrThreadRec.release();
183     mutex_.Unlock();
184 
185     tmpThread->Stop();
186     delete tmpThread;
187 
188     mutex_.Lock();
189   }
190 
191   // PLAYOUT
192   if (_ptrThreadPlay) {
193     rtc::PlatformThread* tmpThread = _ptrThreadPlay.release();
194     mutex_.Unlock();
195 
196     tmpThread->Stop();
197     delete tmpThread;
198 
199     mutex_.Lock();
200   }
201 #if defined(WEBRTC_USE_X11)
202   if (_XDisplay) {
203     XCloseDisplay(_XDisplay);
204     _XDisplay = NULL;
205   }
206 #endif
207   _initialized = false;
208   _outputDeviceIsSpecified = false;
209   _inputDeviceIsSpecified = false;
210 
211   return 0;
212 }
213 
Initialized() const214 bool AudioDeviceLinuxALSA::Initialized() const {
215   return (_initialized);
216 }
217 
InitSpeaker()218 int32_t AudioDeviceLinuxALSA::InitSpeaker() {
219   MutexLock lock(&mutex_);
220 
221   if (_playing) {
222     return -1;
223   }
224 
225   char devName[kAdmMaxDeviceNameSize] = {0};
226   GetDevicesInfo(2, true, _outputDeviceIndex, devName, kAdmMaxDeviceNameSize);
227   return _mixerManager.OpenSpeaker(devName);
228 }
229 
InitMicrophone()230 int32_t AudioDeviceLinuxALSA::InitMicrophone() {
231   MutexLock lock(&mutex_);
232 
233   if (_recording) {
234     return -1;
235   }
236 
237   char devName[kAdmMaxDeviceNameSize] = {0};
238   GetDevicesInfo(2, false, _inputDeviceIndex, devName, kAdmMaxDeviceNameSize);
239   return _mixerManager.OpenMicrophone(devName);
240 }
241 
SpeakerIsInitialized() const242 bool AudioDeviceLinuxALSA::SpeakerIsInitialized() const {
243   return (_mixerManager.SpeakerIsInitialized());
244 }
245 
MicrophoneIsInitialized() const246 bool AudioDeviceLinuxALSA::MicrophoneIsInitialized() const {
247   return (_mixerManager.MicrophoneIsInitialized());
248 }
249 
SpeakerVolumeIsAvailable(bool & available)250 int32_t AudioDeviceLinuxALSA::SpeakerVolumeIsAvailable(bool& available) {
251   bool wasInitialized = _mixerManager.SpeakerIsInitialized();
252 
253   // Make an attempt to open up the
254   // output mixer corresponding to the currently selected output device.
255   if (!wasInitialized && InitSpeaker() == -1) {
256     // If we end up here it means that the selected speaker has no volume
257     // control.
258     available = false;
259     return 0;
260   }
261 
262   // Given that InitSpeaker was successful, we know that a volume control
263   // exists
264   available = true;
265 
266   // Close the initialized output mixer
267   if (!wasInitialized) {
268     _mixerManager.CloseSpeaker();
269   }
270 
271   return 0;
272 }
273 
SetSpeakerVolume(uint32_t volume)274 int32_t AudioDeviceLinuxALSA::SetSpeakerVolume(uint32_t volume) {
275   return (_mixerManager.SetSpeakerVolume(volume));
276 }
277 
SpeakerVolume(uint32_t & volume) const278 int32_t AudioDeviceLinuxALSA::SpeakerVolume(uint32_t& volume) const {
279   uint32_t level(0);
280 
281   if (_mixerManager.SpeakerVolume(level) == -1) {
282     return -1;
283   }
284 
285   volume = level;
286 
287   return 0;
288 }
289 
MaxSpeakerVolume(uint32_t & maxVolume) const290 int32_t AudioDeviceLinuxALSA::MaxSpeakerVolume(uint32_t& maxVolume) const {
291   uint32_t maxVol(0);
292 
293   if (_mixerManager.MaxSpeakerVolume(maxVol) == -1) {
294     return -1;
295   }
296 
297   maxVolume = maxVol;
298 
299   return 0;
300 }
301 
MinSpeakerVolume(uint32_t & minVolume) const302 int32_t AudioDeviceLinuxALSA::MinSpeakerVolume(uint32_t& minVolume) const {
303   uint32_t minVol(0);
304 
305   if (_mixerManager.MinSpeakerVolume(minVol) == -1) {
306     return -1;
307   }
308 
309   minVolume = minVol;
310 
311   return 0;
312 }
313 
SpeakerMuteIsAvailable(bool & available)314 int32_t AudioDeviceLinuxALSA::SpeakerMuteIsAvailable(bool& available) {
315   bool isAvailable(false);
316   bool wasInitialized = _mixerManager.SpeakerIsInitialized();
317 
318   // Make an attempt to open up the
319   // output mixer corresponding to the currently selected output device.
320   //
321   if (!wasInitialized && InitSpeaker() == -1) {
322     // If we end up here it means that the selected speaker has no volume
323     // control, hence it is safe to state that there is no mute control
324     // already at this stage.
325     available = false;
326     return 0;
327   }
328 
329   // Check if the selected speaker has a mute control
330   _mixerManager.SpeakerMuteIsAvailable(isAvailable);
331 
332   available = isAvailable;
333 
334   // Close the initialized output mixer
335   if (!wasInitialized) {
336     _mixerManager.CloseSpeaker();
337   }
338 
339   return 0;
340 }
341 
SetSpeakerMute(bool enable)342 int32_t AudioDeviceLinuxALSA::SetSpeakerMute(bool enable) {
343   return (_mixerManager.SetSpeakerMute(enable));
344 }
345 
SpeakerMute(bool & enabled) const346 int32_t AudioDeviceLinuxALSA::SpeakerMute(bool& enabled) const {
347   bool muted(0);
348 
349   if (_mixerManager.SpeakerMute(muted) == -1) {
350     return -1;
351   }
352 
353   enabled = muted;
354 
355   return 0;
356 }
357 
MicrophoneMuteIsAvailable(bool & available)358 int32_t AudioDeviceLinuxALSA::MicrophoneMuteIsAvailable(bool& available) {
359   bool isAvailable(false);
360   bool wasInitialized = _mixerManager.MicrophoneIsInitialized();
361 
362   // Make an attempt to open up the
363   // input mixer corresponding to the currently selected input device.
364   //
365   if (!wasInitialized && InitMicrophone() == -1) {
366     // If we end up here it means that the selected microphone has no volume
367     // control, hence it is safe to state that there is no mute control
368     // already at this stage.
369     available = false;
370     return 0;
371   }
372 
373   // Check if the selected microphone has a mute control
374   //
375   _mixerManager.MicrophoneMuteIsAvailable(isAvailable);
376   available = isAvailable;
377 
378   // Close the initialized input mixer
379   //
380   if (!wasInitialized) {
381     _mixerManager.CloseMicrophone();
382   }
383 
384   return 0;
385 }
386 
SetMicrophoneMute(bool enable)387 int32_t AudioDeviceLinuxALSA::SetMicrophoneMute(bool enable) {
388   return (_mixerManager.SetMicrophoneMute(enable));
389 }
390 
391 // ----------------------------------------------------------------------------
392 //  MicrophoneMute
393 // ----------------------------------------------------------------------------
394 
MicrophoneMute(bool & enabled) const395 int32_t AudioDeviceLinuxALSA::MicrophoneMute(bool& enabled) const {
396   bool muted(0);
397 
398   if (_mixerManager.MicrophoneMute(muted) == -1) {
399     return -1;
400   }
401 
402   enabled = muted;
403   return 0;
404 }
405 
StereoRecordingIsAvailable(bool & available)406 int32_t AudioDeviceLinuxALSA::StereoRecordingIsAvailable(bool& available) {
407   MutexLock lock(&mutex_);
408 
409   // If we already have initialized in stereo it's obviously available
410   if (_recIsInitialized && (2 == _recChannels)) {
411     available = true;
412     return 0;
413   }
414 
415   // Save rec states and the number of rec channels
416   bool recIsInitialized = _recIsInitialized;
417   bool recording = _recording;
418   int recChannels = _recChannels;
419 
420   available = false;
421 
422   // Stop/uninitialize recording if initialized (and possibly started)
423   if (_recIsInitialized) {
424     StopRecording();
425   }
426 
427   // Try init in stereo;
428   _recChannels = 2;
429   if (InitRecording() == 0) {
430     available = true;
431   }
432 
433   // Stop/uninitialize recording
434   StopRecording();
435 
436   // Recover previous states
437   _recChannels = recChannels;
438   if (recIsInitialized) {
439     InitRecording();
440   }
441   if (recording) {
442     StartRecording();
443   }
444 
445   return 0;
446 }
447 
SetStereoRecording(bool enable)448 int32_t AudioDeviceLinuxALSA::SetStereoRecording(bool enable) {
449   if (enable)
450     _recChannels = 2;
451   else
452     _recChannels = 1;
453 
454   return 0;
455 }
456 
StereoRecording(bool & enabled) const457 int32_t AudioDeviceLinuxALSA::StereoRecording(bool& enabled) const {
458   if (_recChannels == 2)
459     enabled = true;
460   else
461     enabled = false;
462 
463   return 0;
464 }
465 
StereoPlayoutIsAvailable(bool & available)466 int32_t AudioDeviceLinuxALSA::StereoPlayoutIsAvailable(bool& available) {
467   MutexLock lock(&mutex_);
468 
469   // If we already have initialized in stereo it's obviously available
470   if (_playIsInitialized && (2 == _playChannels)) {
471     available = true;
472     return 0;
473   }
474 
475   // Save rec states and the number of rec channels
476   bool playIsInitialized = _playIsInitialized;
477   bool playing = _playing;
478   int playChannels = _playChannels;
479 
480   available = false;
481 
482   // Stop/uninitialize recording if initialized (and possibly started)
483   if (_playIsInitialized) {
484     StopPlayout();
485   }
486 
487   // Try init in stereo;
488   _playChannels = 2;
489   if (InitPlayout() == 0) {
490     available = true;
491   }
492 
493   // Stop/uninitialize recording
494   StopPlayout();
495 
496   // Recover previous states
497   _playChannels = playChannels;
498   if (playIsInitialized) {
499     InitPlayout();
500   }
501   if (playing) {
502     StartPlayout();
503   }
504 
505   return 0;
506 }
507 
SetStereoPlayout(bool enable)508 int32_t AudioDeviceLinuxALSA::SetStereoPlayout(bool enable) {
509   if (enable)
510     _playChannels = 2;
511   else
512     _playChannels = 1;
513 
514   return 0;
515 }
516 
StereoPlayout(bool & enabled) const517 int32_t AudioDeviceLinuxALSA::StereoPlayout(bool& enabled) const {
518   if (_playChannels == 2)
519     enabled = true;
520   else
521     enabled = false;
522 
523   return 0;
524 }
525 
MicrophoneVolumeIsAvailable(bool & available)526 int32_t AudioDeviceLinuxALSA::MicrophoneVolumeIsAvailable(bool& available) {
527   bool wasInitialized = _mixerManager.MicrophoneIsInitialized();
528 
529   // Make an attempt to open up the
530   // input mixer corresponding to the currently selected output device.
531   if (!wasInitialized && InitMicrophone() == -1) {
532     // If we end up here it means that the selected microphone has no volume
533     // control.
534     available = false;
535     return 0;
536   }
537 
538   // Given that InitMicrophone was successful, we know that a volume control
539   // exists
540   available = true;
541 
542   // Close the initialized input mixer
543   if (!wasInitialized) {
544     _mixerManager.CloseMicrophone();
545   }
546 
547   return 0;
548 }
549 
SetMicrophoneVolume(uint32_t volume)550 int32_t AudioDeviceLinuxALSA::SetMicrophoneVolume(uint32_t volume) {
551   return (_mixerManager.SetMicrophoneVolume(volume));
552 
553   return 0;
554 }
555 
MicrophoneVolume(uint32_t & volume) const556 int32_t AudioDeviceLinuxALSA::MicrophoneVolume(uint32_t& volume) const {
557   uint32_t level(0);
558 
559   if (_mixerManager.MicrophoneVolume(level) == -1) {
560     RTC_LOG(LS_WARNING) << "failed to retrive current microphone level";
561     return -1;
562   }
563 
564   volume = level;
565 
566   return 0;
567 }
568 
MaxMicrophoneVolume(uint32_t & maxVolume) const569 int32_t AudioDeviceLinuxALSA::MaxMicrophoneVolume(uint32_t& maxVolume) const {
570   uint32_t maxVol(0);
571 
572   if (_mixerManager.MaxMicrophoneVolume(maxVol) == -1) {
573     return -1;
574   }
575 
576   maxVolume = maxVol;
577 
578   return 0;
579 }
580 
MinMicrophoneVolume(uint32_t & minVolume) const581 int32_t AudioDeviceLinuxALSA::MinMicrophoneVolume(uint32_t& minVolume) const {
582   uint32_t minVol(0);
583 
584   if (_mixerManager.MinMicrophoneVolume(minVol) == -1) {
585     return -1;
586   }
587 
588   minVolume = minVol;
589 
590   return 0;
591 }
592 
PlayoutDevices()593 int16_t AudioDeviceLinuxALSA::PlayoutDevices() {
594   return (int16_t)GetDevicesInfo(0, true);
595 }
596 
SetPlayoutDevice(uint16_t index)597 int32_t AudioDeviceLinuxALSA::SetPlayoutDevice(uint16_t index) {
598   if (_playIsInitialized) {
599     return -1;
600   }
601 
602   uint32_t nDevices = GetDevicesInfo(0, true);
603   RTC_LOG(LS_VERBOSE) << "number of available audio output devices is "
604                       << nDevices;
605 
606   if (index > (nDevices - 1)) {
607     RTC_LOG(LS_ERROR) << "device index is out of range [0," << (nDevices - 1)
608                       << "]";
609     return -1;
610   }
611 
612   _outputDeviceIndex = index;
613   _outputDeviceIsSpecified = true;
614 
615   return 0;
616 }
617 
SetPlayoutDevice(AudioDeviceModule::WindowsDeviceType)618 int32_t AudioDeviceLinuxALSA::SetPlayoutDevice(
619     AudioDeviceModule::WindowsDeviceType /*device*/) {
620   RTC_LOG(LS_ERROR) << "WindowsDeviceType not supported";
621   return -1;
622 }
623 
PlayoutDeviceName(uint16_t index,char name[kAdmMaxDeviceNameSize],char guid[kAdmMaxGuidSize])624 int32_t AudioDeviceLinuxALSA::PlayoutDeviceName(
625     uint16_t index,
626     char name[kAdmMaxDeviceNameSize],
627     char guid[kAdmMaxGuidSize]) {
628   const uint16_t nDevices(PlayoutDevices());
629 
630   if ((index > (nDevices - 1)) || (name == NULL)) {
631     return -1;
632   }
633 
634   memset(name, 0, kAdmMaxDeviceNameSize);
635 
636   if (guid != NULL) {
637     memset(guid, 0, kAdmMaxGuidSize);
638   }
639 
640   return GetDevicesInfo(1, true, index, name, kAdmMaxDeviceNameSize);
641 }
642 
RecordingDeviceName(uint16_t index,char name[kAdmMaxDeviceNameSize],char guid[kAdmMaxGuidSize])643 int32_t AudioDeviceLinuxALSA::RecordingDeviceName(
644     uint16_t index,
645     char name[kAdmMaxDeviceNameSize],
646     char guid[kAdmMaxGuidSize]) {
647   const uint16_t nDevices(RecordingDevices());
648 
649   if ((index > (nDevices - 1)) || (name == NULL)) {
650     return -1;
651   }
652 
653   memset(name, 0, kAdmMaxDeviceNameSize);
654 
655   if (guid != NULL) {
656     memset(guid, 0, kAdmMaxGuidSize);
657   }
658 
659   return GetDevicesInfo(1, false, index, name, kAdmMaxDeviceNameSize);
660 }
661 
RecordingDevices()662 int16_t AudioDeviceLinuxALSA::RecordingDevices() {
663   return (int16_t)GetDevicesInfo(0, false);
664 }
665 
SetRecordingDevice(uint16_t index)666 int32_t AudioDeviceLinuxALSA::SetRecordingDevice(uint16_t index) {
667   if (_recIsInitialized) {
668     return -1;
669   }
670 
671   uint32_t nDevices = GetDevicesInfo(0, false);
672   RTC_LOG(LS_VERBOSE) << "number of availiable audio input devices is "
673                       << nDevices;
674 
675   if (index > (nDevices - 1)) {
676     RTC_LOG(LS_ERROR) << "device index is out of range [0," << (nDevices - 1)
677                       << "]";
678     return -1;
679   }
680 
681   _inputDeviceIndex = index;
682   _inputDeviceIsSpecified = true;
683 
684   return 0;
685 }
686 
687 // ----------------------------------------------------------------------------
688 //  SetRecordingDevice II (II)
689 // ----------------------------------------------------------------------------
690 
SetRecordingDevice(AudioDeviceModule::WindowsDeviceType)691 int32_t AudioDeviceLinuxALSA::SetRecordingDevice(
692     AudioDeviceModule::WindowsDeviceType /*device*/) {
693   RTC_LOG(LS_ERROR) << "WindowsDeviceType not supported";
694   return -1;
695 }
696 
PlayoutIsAvailable(bool & available)697 int32_t AudioDeviceLinuxALSA::PlayoutIsAvailable(bool& available) {
698   available = false;
699 
700   // Try to initialize the playout side with mono
701   // Assumes that user set num channels after calling this function
702   _playChannels = 1;
703   int32_t res = InitPlayout();
704 
705   // Cancel effect of initialization
706   StopPlayout();
707 
708   if (res != -1) {
709     available = true;
710   } else {
711     // It may be possible to play out in stereo
712     res = StereoPlayoutIsAvailable(available);
713     if (available) {
714       // Then set channels to 2 so InitPlayout doesn't fail
715       _playChannels = 2;
716     }
717   }
718 
719   return res;
720 }
721 
RecordingIsAvailable(bool & available)722 int32_t AudioDeviceLinuxALSA::RecordingIsAvailable(bool& available) {
723   available = false;
724 
725   // Try to initialize the recording side with mono
726   // Assumes that user set num channels after calling this function
727   _recChannels = 1;
728   int32_t res = InitRecording();
729 
730   // Cancel effect of initialization
731   StopRecording();
732 
733   if (res != -1) {
734     available = true;
735   } else {
736     // It may be possible to record in stereo
737     res = StereoRecordingIsAvailable(available);
738     if (available) {
739       // Then set channels to 2 so InitPlayout doesn't fail
740       _recChannels = 2;
741     }
742   }
743 
744   return res;
745 }
746 
InitPlayout()747 int32_t AudioDeviceLinuxALSA::InitPlayout() {
748   int errVal = 0;
749 
750   MutexLock lock(&mutex_);
751   if (_playing) {
752     return -1;
753   }
754 
755   if (!_outputDeviceIsSpecified) {
756     return -1;
757   }
758 
759   if (_playIsInitialized) {
760     return 0;
761   }
762   // Initialize the speaker (devices might have been added or removed)
763   if (InitSpeaker() == -1) {
764     RTC_LOG(LS_WARNING) << "InitSpeaker() failed";
765   }
766 
767   // Start by closing any existing wave-output devices
768   //
769   if (_handlePlayout != NULL) {
770     LATE(snd_pcm_close)(_handlePlayout);
771     _handlePlayout = NULL;
772     _playIsInitialized = false;
773     if (errVal < 0) {
774       RTC_LOG(LS_ERROR) << "Error closing current playout sound device, error: "
775                         << LATE(snd_strerror)(errVal);
776     }
777   }
778 
779   // Open PCM device for playout
780   char deviceName[kAdmMaxDeviceNameSize] = {0};
781   GetDevicesInfo(2, true, _outputDeviceIndex, deviceName,
782                  kAdmMaxDeviceNameSize);
783 
784   RTC_LOG(LS_VERBOSE) << "InitPlayout open (" << deviceName << ")";
785 
786   errVal = LATE(snd_pcm_open)(&_handlePlayout, deviceName,
787                               SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
788 
789   if (errVal == -EBUSY)  // Device busy - try some more!
790   {
791     for (int i = 0; i < 5; i++) {
792       SleepMs(1000);
793       errVal = LATE(snd_pcm_open)(&_handlePlayout, deviceName,
794                                   SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
795       if (errVal == 0) {
796         break;
797       }
798     }
799   }
800   if (errVal < 0) {
801     RTC_LOG(LS_ERROR) << "unable to open playback device: "
802                       << LATE(snd_strerror)(errVal) << " (" << errVal << ")";
803     _handlePlayout = NULL;
804     return -1;
805   }
806 
807   _playoutFramesIn10MS = _playoutFreq / 100;
808   if ((errVal = LATE(snd_pcm_set_params)(
809            _handlePlayout,
810 #if defined(WEBRTC_ARCH_BIG_ENDIAN)
811            SND_PCM_FORMAT_S16_BE,
812 #else
813            SND_PCM_FORMAT_S16_LE,                             // format
814 #endif
815            SND_PCM_ACCESS_RW_INTERLEAVED,  // access
816            _playChannels,                  // channels
817            _playoutFreq,                   // rate
818            1,                              // soft_resample
819            ALSA_PLAYOUT_LATENCY  // 40*1000 //latency required overall latency
820                                  // in us
821            )) < 0) {             /* 0.5sec */
822     _playoutFramesIn10MS = 0;
823     RTC_LOG(LS_ERROR) << "unable to set playback device: "
824                       << LATE(snd_strerror)(errVal) << " (" << errVal << ")";
825     ErrorRecovery(errVal, _handlePlayout);
826     errVal = LATE(snd_pcm_close)(_handlePlayout);
827     _handlePlayout = NULL;
828     return -1;
829   }
830 
831   errVal = LATE(snd_pcm_get_params)(_handlePlayout, &_playoutBufferSizeInFrame,
832                                     &_playoutPeriodSizeInFrame);
833   if (errVal < 0) {
834     RTC_LOG(LS_ERROR) << "snd_pcm_get_params: " << LATE(snd_strerror)(errVal)
835                       << " (" << errVal << ")";
836     _playoutBufferSizeInFrame = 0;
837     _playoutPeriodSizeInFrame = 0;
838   } else {
839     RTC_LOG(LS_VERBOSE) << "playout snd_pcm_get_params buffer_size:"
840                         << _playoutBufferSizeInFrame
841                         << " period_size :" << _playoutPeriodSizeInFrame;
842   }
843 
844   if (_ptrAudioBuffer) {
845     // Update webrtc audio buffer with the selected parameters
846     _ptrAudioBuffer->SetPlayoutSampleRate(_playoutFreq);
847     _ptrAudioBuffer->SetPlayoutChannels(_playChannels);
848   }
849 
850   // Set play buffer size
851   _playoutBufferSizeIn10MS =
852       LATE(snd_pcm_frames_to_bytes)(_handlePlayout, _playoutFramesIn10MS);
853 
854   // Init varaibles used for play
855 
856   if (_handlePlayout != NULL) {
857     _playIsInitialized = true;
858     return 0;
859   } else {
860     return -1;
861   }
862 
863   return 0;
864 }
865 
InitRecording()866 int32_t AudioDeviceLinuxALSA::InitRecording() {
867   int errVal = 0;
868 
869   MutexLock lock(&mutex_);
870 
871   if (_recording) {
872     return -1;
873   }
874 
875   if (!_inputDeviceIsSpecified) {
876     return -1;
877   }
878 
879   if (_recIsInitialized) {
880     return 0;
881   }
882 
883   // Initialize the microphone (devices might have been added or removed)
884   if (InitMicrophone() == -1) {
885     RTC_LOG(LS_WARNING) << "InitMicrophone() failed";
886   }
887 
888   // Start by closing any existing pcm-input devices
889   //
890   if (_handleRecord != NULL) {
891     int errVal = LATE(snd_pcm_close)(_handleRecord);
892     _handleRecord = NULL;
893     _recIsInitialized = false;
894     if (errVal < 0) {
895       RTC_LOG(LS_ERROR)
896           << "Error closing current recording sound device, error: "
897           << LATE(snd_strerror)(errVal);
898     }
899   }
900 
901   // Open PCM device for recording
902   // The corresponding settings for playout are made after the record settings
903   char deviceName[kAdmMaxDeviceNameSize] = {0};
904   GetDevicesInfo(2, false, _inputDeviceIndex, deviceName,
905                  kAdmMaxDeviceNameSize);
906 
907   RTC_LOG(LS_VERBOSE) << "InitRecording open (" << deviceName << ")";
908   errVal = LATE(snd_pcm_open)(&_handleRecord, deviceName,
909                               SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
910 
911   // Available modes: 0 = blocking, SND_PCM_NONBLOCK, SND_PCM_ASYNC
912   if (errVal == -EBUSY)  // Device busy - try some more!
913   {
914     for (int i = 0; i < 5; i++) {
915       SleepMs(1000);
916       errVal = LATE(snd_pcm_open)(&_handleRecord, deviceName,
917                                   SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
918       if (errVal == 0) {
919         break;
920       }
921     }
922   }
923   if (errVal < 0) {
924     RTC_LOG(LS_ERROR) << "unable to open record device: "
925                       << LATE(snd_strerror)(errVal);
926     _handleRecord = NULL;
927     return -1;
928   }
929 
930   _recordingFramesIn10MS = _recordingFreq / 100;
931   if ((errVal =
932            LATE(snd_pcm_set_params)(_handleRecord,
933 #if defined(WEBRTC_ARCH_BIG_ENDIAN)
934                                     SND_PCM_FORMAT_S16_BE,  // format
935 #else
936                                     SND_PCM_FORMAT_S16_LE,    // format
937 #endif
938                                     SND_PCM_ACCESS_RW_INTERLEAVED,  // access
939                                     _recChannels,                   // channels
940                                     _recordingFreq,                 // rate
941                                     1,                    // soft_resample
942                                     ALSA_CAPTURE_LATENCY  // latency in us
943                                     )) < 0) {
944     // Fall back to another mode then.
945     if (_recChannels == 1)
946       _recChannels = 2;
947     else
948       _recChannels = 1;
949 
950     if ((errVal =
951              LATE(snd_pcm_set_params)(_handleRecord,
952 #if defined(WEBRTC_ARCH_BIG_ENDIAN)
953                                       SND_PCM_FORMAT_S16_BE,  // format
954 #else
955                                       SND_PCM_FORMAT_S16_LE,  // format
956 #endif
957                                       SND_PCM_ACCESS_RW_INTERLEAVED,  // access
958                                       _recChannels,         // channels
959                                       _recordingFreq,       // rate
960                                       1,                    // soft_resample
961                                       ALSA_CAPTURE_LATENCY  // latency in us
962                                       )) < 0) {
963       _recordingFramesIn10MS = 0;
964       RTC_LOG(LS_ERROR) << "unable to set record settings: "
965                         << LATE(snd_strerror)(errVal) << " (" << errVal << ")";
966       ErrorRecovery(errVal, _handleRecord);
967       errVal = LATE(snd_pcm_close)(_handleRecord);
968       _handleRecord = NULL;
969       return -1;
970     }
971   }
972 
973   errVal = LATE(snd_pcm_get_params)(_handleRecord, &_recordingBuffersizeInFrame,
974                                     &_recordingPeriodSizeInFrame);
975   if (errVal < 0) {
976     RTC_LOG(LS_ERROR) << "snd_pcm_get_params " << LATE(snd_strerror)(errVal)
977                       << " (" << errVal << ")";
978     _recordingBuffersizeInFrame = 0;
979     _recordingPeriodSizeInFrame = 0;
980   } else {
981     RTC_LOG(LS_VERBOSE) << "capture snd_pcm_get_params, buffer_size:"
982                         << _recordingBuffersizeInFrame
983                         << ", period_size:" << _recordingPeriodSizeInFrame;
984   }
985 
986   if (_ptrAudioBuffer) {
987     // Update webrtc audio buffer with the selected parameters
988     _ptrAudioBuffer->SetRecordingSampleRate(_recordingFreq);
989     _ptrAudioBuffer->SetRecordingChannels(_recChannels);
990   }
991 
992   // Set rec buffer size and create buffer
993   _recordingBufferSizeIn10MS =
994       LATE(snd_pcm_frames_to_bytes)(_handleRecord, _recordingFramesIn10MS);
995 
996   if (_handleRecord != NULL) {
997     // Mark recording side as initialized
998     _recIsInitialized = true;
999     return 0;
1000   } else {
1001     return -1;
1002   }
1003 
1004   return 0;
1005 }
1006 
StartRecording()1007 int32_t AudioDeviceLinuxALSA::StartRecording() {
1008   if (!_recIsInitialized) {
1009     return -1;
1010   }
1011 
1012   if (_recording) {
1013     return 0;
1014   }
1015 
1016   _recording = true;
1017 
1018   int errVal = 0;
1019   _recordingFramesLeft = _recordingFramesIn10MS;
1020 
1021   // Make sure we only create the buffer once.
1022   if (!_recordingBuffer)
1023     _recordingBuffer = new int8_t[_recordingBufferSizeIn10MS];
1024   if (!_recordingBuffer) {
1025     RTC_LOG(LS_ERROR) << "failed to alloc recording buffer";
1026     _recording = false;
1027     return -1;
1028   }
1029   // RECORDING
1030   _ptrThreadRec.reset(new rtc::PlatformThread(
1031       RecThreadFunc, this, "webrtc_audio_module_capture_thread",
1032       rtc::kRealtimePriority));
1033 
1034   _ptrThreadRec->Start();
1035 
1036   errVal = LATE(snd_pcm_prepare)(_handleRecord);
1037   if (errVal < 0) {
1038     RTC_LOG(LS_ERROR) << "capture snd_pcm_prepare failed ("
1039                       << LATE(snd_strerror)(errVal) << ")\n";
1040     // just log error
1041     // if snd_pcm_open fails will return -1
1042   }
1043 
1044   errVal = LATE(snd_pcm_start)(_handleRecord);
1045   if (errVal < 0) {
1046     RTC_LOG(LS_ERROR) << "capture snd_pcm_start err: "
1047                       << LATE(snd_strerror)(errVal);
1048     errVal = LATE(snd_pcm_start)(_handleRecord);
1049     if (errVal < 0) {
1050       RTC_LOG(LS_ERROR) << "capture snd_pcm_start 2nd try err: "
1051                         << LATE(snd_strerror)(errVal);
1052       StopRecording();
1053       return -1;
1054     }
1055   }
1056 
1057   return 0;
1058 }
1059 
StopRecording()1060 int32_t AudioDeviceLinuxALSA::StopRecording() {
1061   {
1062     MutexLock lock(&mutex_);
1063 
1064     if (!_recIsInitialized) {
1065       return 0;
1066     }
1067 
1068     if (_handleRecord == NULL) {
1069       return -1;
1070     }
1071 
1072     // Make sure we don't start recording (it's asynchronous).
1073     _recIsInitialized = false;
1074     _recording = false;
1075   }
1076 
1077   if (_ptrThreadRec) {
1078     _ptrThreadRec->Stop();
1079     _ptrThreadRec.reset();
1080   }
1081 
1082   MutexLock lock(&mutex_);
1083   _recordingFramesLeft = 0;
1084   if (_recordingBuffer) {
1085     delete[] _recordingBuffer;
1086     _recordingBuffer = NULL;
1087   }
1088 
1089   // Stop and close pcm recording device.
1090   int errVal = LATE(snd_pcm_drop)(_handleRecord);
1091   if (errVal < 0) {
1092     RTC_LOG(LS_ERROR) << "Error stop recording: " << LATE(snd_strerror)(errVal);
1093     return -1;
1094   }
1095 
1096   errVal = LATE(snd_pcm_close)(_handleRecord);
1097   if (errVal < 0) {
1098     RTC_LOG(LS_ERROR) << "Error closing record sound device, error: "
1099                       << LATE(snd_strerror)(errVal);
1100     return -1;
1101   }
1102 
1103   // Check if we have muted and unmute if so.
1104   bool muteEnabled = false;
1105   MicrophoneMute(muteEnabled);
1106   if (muteEnabled) {
1107     SetMicrophoneMute(false);
1108   }
1109 
1110   // set the pcm input handle to NULL
1111   _handleRecord = NULL;
1112   return 0;
1113 }
1114 
RecordingIsInitialized() const1115 bool AudioDeviceLinuxALSA::RecordingIsInitialized() const {
1116   return (_recIsInitialized);
1117 }
1118 
Recording() const1119 bool AudioDeviceLinuxALSA::Recording() const {
1120   return (_recording);
1121 }
1122 
PlayoutIsInitialized() const1123 bool AudioDeviceLinuxALSA::PlayoutIsInitialized() const {
1124   return (_playIsInitialized);
1125 }
1126 
StartPlayout()1127 int32_t AudioDeviceLinuxALSA::StartPlayout() {
1128   if (!_playIsInitialized) {
1129     return -1;
1130   }
1131 
1132   if (_playing) {
1133     return 0;
1134   }
1135 
1136   _playing = true;
1137 
1138   _playoutFramesLeft = 0;
1139   if (!_playoutBuffer)
1140     _playoutBuffer = new int8_t[_playoutBufferSizeIn10MS];
1141   if (!_playoutBuffer) {
1142     RTC_LOG(LS_ERROR) << "failed to alloc playout buf";
1143     _playing = false;
1144     return -1;
1145   }
1146 
1147   // PLAYOUT
1148   _ptrThreadPlay.reset(new rtc::PlatformThread(
1149       PlayThreadFunc, this, "webrtc_audio_module_play_thread",
1150       rtc::kRealtimePriority));
1151   _ptrThreadPlay->Start();
1152 
1153   int errVal = LATE(snd_pcm_prepare)(_handlePlayout);
1154   if (errVal < 0) {
1155     RTC_LOG(LS_ERROR) << "playout snd_pcm_prepare failed ("
1156                       << LATE(snd_strerror)(errVal) << ")\n";
1157     // just log error
1158     // if snd_pcm_open fails will return -1
1159   }
1160 
1161   return 0;
1162 }
1163 
StopPlayout()1164 int32_t AudioDeviceLinuxALSA::StopPlayout() {
1165   {
1166     MutexLock lock(&mutex_);
1167 
1168     if (!_playIsInitialized) {
1169       return 0;
1170     }
1171 
1172     if (_handlePlayout == NULL) {
1173       return -1;
1174     }
1175 
1176     _playing = false;
1177   }
1178 
1179   // stop playout thread first
1180   if (_ptrThreadPlay) {
1181     _ptrThreadPlay->Stop();
1182     _ptrThreadPlay.reset();
1183   }
1184 
1185   MutexLock lock(&mutex_);
1186 
1187   _playoutFramesLeft = 0;
1188   delete[] _playoutBuffer;
1189   _playoutBuffer = NULL;
1190 
1191   // stop and close pcm playout device
1192   int errVal = LATE(snd_pcm_drop)(_handlePlayout);
1193   if (errVal < 0) {
1194     RTC_LOG(LS_ERROR) << "Error stop playing: " << LATE(snd_strerror)(errVal);
1195   }
1196 
1197   errVal = LATE(snd_pcm_close)(_handlePlayout);
1198   if (errVal < 0)
1199     RTC_LOG(LS_ERROR) << "Error closing playout sound device, error: "
1200                       << LATE(snd_strerror)(errVal);
1201 
1202   // set the pcm input handle to NULL
1203   _playIsInitialized = false;
1204   _handlePlayout = NULL;
1205   RTC_LOG(LS_VERBOSE) << "handle_playout is now set to NULL";
1206 
1207   return 0;
1208 }
1209 
PlayoutDelay(uint16_t & delayMS) const1210 int32_t AudioDeviceLinuxALSA::PlayoutDelay(uint16_t& delayMS) const {
1211   delayMS = (uint16_t)_playoutDelay * 1000 / _playoutFreq;
1212   return 0;
1213 }
1214 
Playing() const1215 bool AudioDeviceLinuxALSA::Playing() const {
1216   return (_playing);
1217 }
1218 
1219 // ============================================================================
1220 //                                 Private Methods
1221 // ============================================================================
1222 
GetDevicesInfo(const int32_t function,const bool playback,const int32_t enumDeviceNo,char * enumDeviceName,const int32_t ednLen) const1223 int32_t AudioDeviceLinuxALSA::GetDevicesInfo(const int32_t function,
1224                                              const bool playback,
1225                                              const int32_t enumDeviceNo,
1226                                              char* enumDeviceName,
1227                                              const int32_t ednLen) const {
1228   // Device enumeration based on libjingle implementation
1229   // by Tristan Schmelcher at Google Inc.
1230 
1231   const char* type = playback ? "Output" : "Input";
1232   // dmix and dsnoop are only for playback and capture, respectively, but ALSA
1233   // stupidly includes them in both lists.
1234   const char* ignorePrefix = playback ? "dsnoop:" : "dmix:";
1235   // (ALSA lists many more "devices" of questionable interest, but we show them
1236   // just in case the weird devices may actually be desirable for some
1237   // users/systems.)
1238 
1239   int err;
1240   int enumCount(0);
1241   bool keepSearching(true);
1242 
1243   // From Chromium issue 95797
1244   // Loop through the sound cards to get Alsa device hints.
1245   // Don't use snd_device_name_hint(-1,..) since there is a access violation
1246   // inside this ALSA API with libasound.so.2.0.0.
1247   int card = -1;
1248   while (!(LATE(snd_card_next)(&card)) && (card >= 0) && keepSearching) {
1249     void** hints;
1250     err = LATE(snd_device_name_hint)(card, "pcm", &hints);
1251     if (err != 0) {
1252       RTC_LOG(LS_ERROR) << "GetDevicesInfo - device name hint error: "
1253                         << LATE(snd_strerror)(err);
1254       return -1;
1255     }
1256 
1257     enumCount++;  // default is 0
1258     if ((function == FUNC_GET_DEVICE_NAME ||
1259          function == FUNC_GET_DEVICE_NAME_FOR_AN_ENUM) &&
1260         enumDeviceNo == 0) {
1261       strcpy(enumDeviceName, "default");
1262 
1263       err = LATE(snd_device_name_free_hint)(hints);
1264       if (err != 0) {
1265         RTC_LOG(LS_ERROR) << "GetDevicesInfo - device name free hint error: "
1266                           << LATE(snd_strerror)(err);
1267       }
1268 
1269       return 0;
1270     }
1271 
1272     for (void** list = hints; *list != NULL; ++list) {
1273       char* actualType = LATE(snd_device_name_get_hint)(*list, "IOID");
1274       if (actualType) {  // NULL means it's both.
1275         bool wrongType = (strcmp(actualType, type) != 0);
1276         free(actualType);
1277         if (wrongType) {
1278           // Wrong type of device (i.e., input vs. output).
1279           continue;
1280         }
1281       }
1282 
1283       char* name = LATE(snd_device_name_get_hint)(*list, "NAME");
1284       if (!name) {
1285         RTC_LOG(LS_ERROR) << "Device has no name";
1286         // Skip it.
1287         continue;
1288       }
1289 
1290       // Now check if we actually want to show this device.
1291       if (strcmp(name, "default") != 0 && strcmp(name, "null") != 0 &&
1292           strcmp(name, "pulse") != 0 &&
1293           strncmp(name, ignorePrefix, strlen(ignorePrefix)) != 0) {
1294         // Yes, we do.
1295         char* desc = LATE(snd_device_name_get_hint)(*list, "DESC");
1296         if (!desc) {
1297           // Virtual devices don't necessarily have descriptions.
1298           // Use their names instead.
1299           desc = name;
1300         }
1301 
1302         if (FUNC_GET_NUM_OF_DEVICE == function) {
1303           RTC_LOG(LS_VERBOSE) << "Enum device " << enumCount << " - " << name;
1304         }
1305         if ((FUNC_GET_DEVICE_NAME == function) && (enumDeviceNo == enumCount)) {
1306           // We have found the enum device, copy the name to buffer.
1307           strncpy(enumDeviceName, desc, ednLen);
1308           enumDeviceName[ednLen - 1] = '\0';
1309           keepSearching = false;
1310           // Replace '\n' with '-'.
1311           char* pret = strchr(enumDeviceName, '\n' /*0xa*/);  // LF
1312           if (pret)
1313             *pret = '-';
1314         }
1315         if ((FUNC_GET_DEVICE_NAME_FOR_AN_ENUM == function) &&
1316             (enumDeviceNo == enumCount)) {
1317           // We have found the enum device, copy the name to buffer.
1318           strncpy(enumDeviceName, name, ednLen);
1319           enumDeviceName[ednLen - 1] = '\0';
1320           keepSearching = false;
1321         }
1322 
1323         if (keepSearching)
1324           ++enumCount;
1325 
1326         if (desc != name)
1327           free(desc);
1328       }
1329 
1330       free(name);
1331 
1332       if (!keepSearching)
1333         break;
1334     }
1335 
1336     err = LATE(snd_device_name_free_hint)(hints);
1337     if (err != 0) {
1338       RTC_LOG(LS_ERROR) << "GetDevicesInfo - device name free hint error: "
1339                         << LATE(snd_strerror)(err);
1340       // Continue and return true anyway, since we did get the whole list.
1341     }
1342   }
1343 
1344   if (FUNC_GET_NUM_OF_DEVICE == function) {
1345     if (enumCount == 1)  // only default?
1346       enumCount = 0;
1347     return enumCount;  // Normal return point for function 0
1348   }
1349 
1350   if (keepSearching) {
1351     // If we get here for function 1 and 2, we didn't find the specified
1352     // enum device.
1353     RTC_LOG(LS_ERROR)
1354         << "GetDevicesInfo - Could not find device name or numbers";
1355     return -1;
1356   }
1357 
1358   return 0;
1359 }
1360 
InputSanityCheckAfterUnlockedPeriod() const1361 int32_t AudioDeviceLinuxALSA::InputSanityCheckAfterUnlockedPeriod() const {
1362   if (_handleRecord == NULL) {
1363     RTC_LOG(LS_ERROR) << "input state has been modified during unlocked period";
1364     return -1;
1365   }
1366   return 0;
1367 }
1368 
OutputSanityCheckAfterUnlockedPeriod() const1369 int32_t AudioDeviceLinuxALSA::OutputSanityCheckAfterUnlockedPeriod() const {
1370   if (_handlePlayout == NULL) {
1371     RTC_LOG(LS_ERROR)
1372         << "output state has been modified during unlocked period";
1373     return -1;
1374   }
1375   return 0;
1376 }
1377 
ErrorRecovery(int32_t error,snd_pcm_t * deviceHandle)1378 int32_t AudioDeviceLinuxALSA::ErrorRecovery(int32_t error,
1379                                             snd_pcm_t* deviceHandle) {
1380   int st = LATE(snd_pcm_state)(deviceHandle);
1381   RTC_LOG(LS_VERBOSE) << "Trying to recover from "
1382                       << ((LATE(snd_pcm_stream)(deviceHandle) ==
1383                            SND_PCM_STREAM_CAPTURE)
1384                               ? "capture"
1385                               : "playout")
1386                       << " error: " << LATE(snd_strerror)(error) << " ("
1387                       << error << ") (state " << st << ")";
1388 
1389   // It is recommended to use snd_pcm_recover for all errors. If that function
1390   // cannot handle the error, the input error code will be returned, otherwise
1391   // 0 is returned. From snd_pcm_recover API doc: "This functions handles
1392   // -EINTR (4) (interrupted system call), -EPIPE (32) (playout overrun or
1393   // capture underrun) and -ESTRPIPE (86) (stream is suspended) error codes
1394   // trying to prepare given stream for next I/O."
1395 
1396   /** Open */
1397   //    SND_PCM_STATE_OPEN = 0,
1398   /** Setup installed */
1399   //    SND_PCM_STATE_SETUP,
1400   /** Ready to start */
1401   //    SND_PCM_STATE_PREPARED,
1402   /** Running */
1403   //    SND_PCM_STATE_RUNNING,
1404   /** Stopped: underrun (playback) or overrun (capture) detected */
1405   //    SND_PCM_STATE_XRUN,= 4
1406   /** Draining: running (playback) or stopped (capture) */
1407   //    SND_PCM_STATE_DRAINING,
1408   /** Paused */
1409   //    SND_PCM_STATE_PAUSED,
1410   /** Hardware is suspended */
1411   //    SND_PCM_STATE_SUSPENDED,
1412   //  ** Hardware is disconnected */
1413   //    SND_PCM_STATE_DISCONNECTED,
1414   //    SND_PCM_STATE_LAST = SND_PCM_STATE_DISCONNECTED
1415 
1416   // snd_pcm_recover isn't available in older alsa, e.g. on the FC4 machine
1417   // in Sthlm lab.
1418 
1419   int res = LATE(snd_pcm_recover)(deviceHandle, error, 1);
1420   if (0 == res) {
1421     RTC_LOG(LS_VERBOSE) << "Recovery - snd_pcm_recover OK";
1422 
1423     if ((error == -EPIPE || error == -ESTRPIPE) &&  // Buf underrun/overrun.
1424         _recording &&
1425         LATE(snd_pcm_stream)(deviceHandle) == SND_PCM_STREAM_CAPTURE) {
1426       // For capture streams we also have to repeat the explicit start()
1427       // to get data flowing again.
1428       int err = LATE(snd_pcm_start)(deviceHandle);
1429       if (err != 0) {
1430         RTC_LOG(LS_ERROR) << "Recovery - snd_pcm_start error: " << err;
1431         return -1;
1432       }
1433     }
1434 
1435     if ((error == -EPIPE || error == -ESTRPIPE) &&  // Buf underrun/overrun.
1436         _playing &&
1437         LATE(snd_pcm_stream)(deviceHandle) == SND_PCM_STREAM_PLAYBACK) {
1438       // For capture streams we also have to repeat the explicit start() to get
1439       // data flowing again.
1440       int err = LATE(snd_pcm_start)(deviceHandle);
1441       if (err != 0) {
1442         RTC_LOG(LS_ERROR) << "Recovery - snd_pcm_start error: "
1443                           << LATE(snd_strerror)(err);
1444         return -1;
1445       }
1446     }
1447 
1448     return -EPIPE == error ? 1 : 0;
1449   } else {
1450     RTC_LOG(LS_ERROR) << "Unrecoverable alsa stream error: " << res;
1451   }
1452 
1453   return res;
1454 }
1455 
1456 // ============================================================================
1457 //                                  Thread Methods
1458 // ============================================================================
1459 
PlayThreadFunc(void * pThis)1460 void AudioDeviceLinuxALSA::PlayThreadFunc(void* pThis) {
1461   AudioDeviceLinuxALSA* device = static_cast<AudioDeviceLinuxALSA*>(pThis);
1462   while (device->PlayThreadProcess()) {
1463   }
1464 }
1465 
RecThreadFunc(void * pThis)1466 void AudioDeviceLinuxALSA::RecThreadFunc(void* pThis) {
1467   AudioDeviceLinuxALSA* device = static_cast<AudioDeviceLinuxALSA*>(pThis);
1468   while (device->RecThreadProcess()) {
1469   }
1470 }
1471 
PlayThreadProcess()1472 bool AudioDeviceLinuxALSA::PlayThreadProcess() {
1473   if (!_playing)
1474     return false;
1475 
1476   int err;
1477   snd_pcm_sframes_t frames;
1478   snd_pcm_sframes_t avail_frames;
1479 
1480   Lock();
1481   // return a positive number of frames ready otherwise a negative error code
1482   avail_frames = LATE(snd_pcm_avail_update)(_handlePlayout);
1483   if (avail_frames < 0) {
1484     RTC_LOG(LS_ERROR) << "playout snd_pcm_avail_update error: "
1485                       << LATE(snd_strerror)(avail_frames);
1486     ErrorRecovery(avail_frames, _handlePlayout);
1487     UnLock();
1488     return true;
1489   } else if (avail_frames == 0) {
1490     UnLock();
1491 
1492     // maximum tixe in milliseconds to wait, a negative value means infinity
1493     err = LATE(snd_pcm_wait)(_handlePlayout, 2);
1494     if (err == 0) {  // timeout occured
1495       RTC_LOG(LS_VERBOSE) << "playout snd_pcm_wait timeout";
1496     }
1497 
1498     return true;
1499   }
1500 
1501   if (_playoutFramesLeft <= 0) {
1502     UnLock();
1503     _ptrAudioBuffer->RequestPlayoutData(_playoutFramesIn10MS);
1504     Lock();
1505 
1506     _playoutFramesLeft = _ptrAudioBuffer->GetPlayoutData(_playoutBuffer);
1507     assert(_playoutFramesLeft == _playoutFramesIn10MS);
1508   }
1509 
1510   if (static_cast<uint32_t>(avail_frames) > _playoutFramesLeft)
1511     avail_frames = _playoutFramesLeft;
1512 
1513   int size = LATE(snd_pcm_frames_to_bytes)(_handlePlayout, _playoutFramesLeft);
1514   frames = LATE(snd_pcm_writei)(
1515       _handlePlayout, &_playoutBuffer[_playoutBufferSizeIn10MS - size],
1516       avail_frames);
1517 
1518   if (frames < 0) {
1519     RTC_LOG(LS_VERBOSE) << "playout snd_pcm_writei error: "
1520                         << LATE(snd_strerror)(frames);
1521     _playoutFramesLeft = 0;
1522     ErrorRecovery(frames, _handlePlayout);
1523     UnLock();
1524     return true;
1525   } else {
1526     assert(frames == avail_frames);
1527     _playoutFramesLeft -= frames;
1528   }
1529 
1530   UnLock();
1531   return true;
1532 }
1533 
RecThreadProcess()1534 bool AudioDeviceLinuxALSA::RecThreadProcess() {
1535   if (!_recording)
1536     return false;
1537 
1538   int err;
1539   snd_pcm_sframes_t frames;
1540   snd_pcm_sframes_t avail_frames;
1541   int8_t buffer[_recordingBufferSizeIn10MS];
1542 
1543   Lock();
1544 
1545   // return a positive number of frames ready otherwise a negative error code
1546   avail_frames = LATE(snd_pcm_avail_update)(_handleRecord);
1547   if (avail_frames < 0) {
1548     RTC_LOG(LS_ERROR) << "capture snd_pcm_avail_update error: "
1549                       << LATE(snd_strerror)(avail_frames);
1550     ErrorRecovery(avail_frames, _handleRecord);
1551     UnLock();
1552     return true;
1553   } else if (avail_frames == 0) {  // no frame is available now
1554     UnLock();
1555 
1556     // maximum time in milliseconds to wait, a negative value means infinity
1557     err = LATE(snd_pcm_wait)(_handleRecord, ALSA_CAPTURE_WAIT_TIMEOUT);
1558     if (err == 0)  // timeout occured
1559       RTC_LOG(LS_VERBOSE) << "capture snd_pcm_wait timeout";
1560 
1561     return true;
1562   }
1563 
1564   if (static_cast<uint32_t>(avail_frames) > _recordingFramesLeft)
1565     avail_frames = _recordingFramesLeft;
1566 
1567   frames = LATE(snd_pcm_readi)(_handleRecord, buffer,
1568                                avail_frames);  // frames to be written
1569   if (frames < 0) {
1570     RTC_LOG(LS_ERROR) << "capture snd_pcm_readi error: "
1571                       << LATE(snd_strerror)(frames);
1572     ErrorRecovery(frames, _handleRecord);
1573     UnLock();
1574     return true;
1575   } else if (frames > 0) {
1576     assert(frames == avail_frames);
1577 
1578     int left_size =
1579         LATE(snd_pcm_frames_to_bytes)(_handleRecord, _recordingFramesLeft);
1580     int size = LATE(snd_pcm_frames_to_bytes)(_handleRecord, frames);
1581 
1582     memcpy(&_recordingBuffer[_recordingBufferSizeIn10MS - left_size], buffer,
1583            size);
1584     _recordingFramesLeft -= frames;
1585 
1586     if (!_recordingFramesLeft) {  // buf is full
1587       _recordingFramesLeft = _recordingFramesIn10MS;
1588 
1589       // store the recorded buffer (no action will be taken if the
1590       // #recorded samples is not a full buffer)
1591       _ptrAudioBuffer->SetRecordedBuffer(_recordingBuffer,
1592                                          _recordingFramesIn10MS);
1593 
1594       // calculate delay
1595       _playoutDelay = 0;
1596       _recordingDelay = 0;
1597       if (_handlePlayout) {
1598         err = LATE(snd_pcm_delay)(_handlePlayout,
1599                                   &_playoutDelay);  // returned delay in frames
1600         if (err < 0) {
1601           // TODO(xians): Shall we call ErrorRecovery() here?
1602           _playoutDelay = 0;
1603           RTC_LOG(LS_ERROR)
1604               << "playout snd_pcm_delay: " << LATE(snd_strerror)(err);
1605         }
1606       }
1607 
1608       err = LATE(snd_pcm_delay)(_handleRecord,
1609                                 &_recordingDelay);  // returned delay in frames
1610       if (err < 0) {
1611         // TODO(xians): Shall we call ErrorRecovery() here?
1612         _recordingDelay = 0;
1613         RTC_LOG(LS_ERROR) << "capture snd_pcm_delay: "
1614                           << LATE(snd_strerror)(err);
1615       }
1616 
1617       // TODO(xians): Shall we add 10ms buffer delay to the record delay?
1618       _ptrAudioBuffer->SetVQEData(_playoutDelay * 1000 / _playoutFreq,
1619                                   _recordingDelay * 1000 / _recordingFreq);
1620 
1621       _ptrAudioBuffer->SetTypingStatus(KeyPressed());
1622 
1623       // Deliver recorded samples at specified sample rate, mic level etc.
1624       // to the observer using callback.
1625       UnLock();
1626       _ptrAudioBuffer->DeliverRecordedData();
1627       Lock();
1628     }
1629   }
1630 
1631   UnLock();
1632   return true;
1633 }
1634 
KeyPressed() const1635 bool AudioDeviceLinuxALSA::KeyPressed() const {
1636 #if defined(WEBRTC_USE_X11)
1637   char szKey[32];
1638   unsigned int i = 0;
1639   char state = 0;
1640 
1641   if (!_XDisplay)
1642     return false;
1643 
1644   // Check key map status
1645   XQueryKeymap(_XDisplay, szKey);
1646 
1647   // A bit change in keymap means a key is pressed
1648   for (i = 0; i < sizeof(szKey); i++)
1649     state |= (szKey[i] ^ _oldKeyState[i]) & szKey[i];
1650 
1651   // Save old state
1652   memcpy((char*)_oldKeyState, (char*)szKey, sizeof(_oldKeyState));
1653   return (state != 0);
1654 #else
1655   return false;
1656 #endif
1657 }
1658 }  // namespace webrtc
1659