tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

audio_device_alsa_linux.cc (47286B)


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