Home | History | Annotate | Download | only in linux
      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 <assert.h>
     12 
     13 #include "webrtc/modules/audio_device/audio_device_config.h"
     14 #include "webrtc/modules/audio_device/linux/audio_device_alsa_linux.h"
     15 
     16 #include "webrtc/system_wrappers/include/event_wrapper.h"
     17 #include "webrtc/system_wrappers/include/sleep.h"
     18 #include "webrtc/system_wrappers/include/trace.h"
     19 
     20 webrtc_adm_linux_alsa::AlsaSymbolTable AlsaSymbolTable;
     21 
     22 // Accesses ALSA functions through our late-binding symbol table instead of
     23 // directly. This way we don't have to link to libasound, which means our binary
     24 // will work on systems that don't have it.
     25 #define LATE(sym) \
     26   LATESYM_GET(webrtc_adm_linux_alsa::AlsaSymbolTable, &AlsaSymbolTable, sym)
     27 
     28 // Redefine these here to be able to do late-binding
     29 #undef snd_ctl_card_info_alloca
     30 #define snd_ctl_card_info_alloca(ptr) \
     31         do { *ptr = (snd_ctl_card_info_t *) \
     32             __builtin_alloca (LATE(snd_ctl_card_info_sizeof)()); \
     33             memset(*ptr, 0, LATE(snd_ctl_card_info_sizeof)()); } while (0)
     34 
     35 #undef snd_pcm_info_alloca
     36 #define snd_pcm_info_alloca(pInfo) \
     37        do { *pInfo = (snd_pcm_info_t *) \
     38        __builtin_alloca (LATE(snd_pcm_info_sizeof)()); \
     39        memset(*pInfo, 0, LATE(snd_pcm_info_sizeof)()); } while (0)
     40 
     41 // snd_lib_error_handler_t
     42 void WebrtcAlsaErrorHandler(const char *file,
     43                           int line,
     44                           const char *function,
     45                           int err,
     46                           const char *fmt,...){};
     47 
     48 namespace webrtc
     49 {
     50 static const unsigned int ALSA_PLAYOUT_FREQ = 48000;
     51 static const unsigned int ALSA_PLAYOUT_CH = 2;
     52 static const unsigned int ALSA_PLAYOUT_LATENCY = 40*1000; // in us
     53 static const unsigned int ALSA_CAPTURE_FREQ = 48000;
     54 static const unsigned int ALSA_CAPTURE_CH = 2;
     55 static const unsigned int ALSA_CAPTURE_LATENCY = 40*1000; // in us
     56 static const unsigned int ALSA_CAPTURE_WAIT_TIMEOUT = 5; // in ms
     57 
     58 #define FUNC_GET_NUM_OF_DEVICE 0
     59 #define FUNC_GET_DEVICE_NAME 1
     60 #define FUNC_GET_DEVICE_NAME_FOR_AN_ENUM 2
     61 
     62 AudioDeviceLinuxALSA::AudioDeviceLinuxALSA(const int32_t id) :
     63     _ptrAudioBuffer(NULL),
     64     _critSect(*CriticalSectionWrapper::CreateCriticalSection()),
     65     _id(id),
     66     _mixerManager(id),
     67     _inputDeviceIndex(0),
     68     _outputDeviceIndex(0),
     69     _inputDeviceIsSpecified(false),
     70     _outputDeviceIsSpecified(false),
     71     _handleRecord(NULL),
     72     _handlePlayout(NULL),
     73     _recordingBuffersizeInFrame(0),
     74     _recordingPeriodSizeInFrame(0),
     75     _playoutBufferSizeInFrame(0),
     76     _playoutPeriodSizeInFrame(0),
     77     _recordingBufferSizeIn10MS(0),
     78     _playoutBufferSizeIn10MS(0),
     79     _recordingFramesIn10MS(0),
     80     _playoutFramesIn10MS(0),
     81     _recordingFreq(ALSA_CAPTURE_FREQ),
     82     _playoutFreq(ALSA_PLAYOUT_FREQ),
     83     _recChannels(ALSA_CAPTURE_CH),
     84     _playChannels(ALSA_PLAYOUT_CH),
     85     _recordingBuffer(NULL),
     86     _playoutBuffer(NULL),
     87     _recordingFramesLeft(0),
     88     _playoutFramesLeft(0),
     89     _playBufType(AudioDeviceModule::kFixedBufferSize),
     90     _initialized(false),
     91     _recording(false),
     92     _playing(false),
     93     _recIsInitialized(false),
     94     _playIsInitialized(false),
     95     _AGC(false),
     96     _recordingDelay(0),
     97     _playoutDelay(0),
     98     _playWarning(0),
     99     _playError(0),
    100     _recWarning(0),
    101     _recError(0),
    102     _playBufDelay(80),
    103     _playBufDelayFixed(80)
    104 {
    105     memset(_oldKeyState, 0, sizeof(_oldKeyState));
    106     WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, id,
    107                  "%s created", __FUNCTION__);
    108 }
    109 
    110 // ----------------------------------------------------------------------------
    111 //  AudioDeviceLinuxALSA - dtor
    112 // ----------------------------------------------------------------------------
    113 
    114 AudioDeviceLinuxALSA::~AudioDeviceLinuxALSA()
    115 {
    116     WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id,
    117                  "%s destroyed", __FUNCTION__);
    118 
    119     Terminate();
    120 
    121     // Clean up the recording buffer and playout buffer.
    122     if (_recordingBuffer)
    123     {
    124         delete [] _recordingBuffer;
    125         _recordingBuffer = NULL;
    126     }
    127     if (_playoutBuffer)
    128     {
    129         delete [] _playoutBuffer;
    130         _playoutBuffer = NULL;
    131     }
    132     delete &_critSect;
    133 }
    134 
    135 void AudioDeviceLinuxALSA::AttachAudioBuffer(AudioDeviceBuffer* audioBuffer)
    136 {
    137 
    138     CriticalSectionScoped lock(&_critSect);
    139 
    140     _ptrAudioBuffer = audioBuffer;
    141 
    142     // Inform the AudioBuffer about default settings for this implementation.
    143     // Set all values to zero here since the actual settings will be done by
    144     // InitPlayout and InitRecording later.
    145     _ptrAudioBuffer->SetRecordingSampleRate(0);
    146     _ptrAudioBuffer->SetPlayoutSampleRate(0);
    147     _ptrAudioBuffer->SetRecordingChannels(0);
    148     _ptrAudioBuffer->SetPlayoutChannels(0);
    149 }
    150 
    151 int32_t AudioDeviceLinuxALSA::ActiveAudioLayer(
    152     AudioDeviceModule::AudioLayer& audioLayer) const
    153 {
    154     audioLayer = AudioDeviceModule::kLinuxAlsaAudio;
    155     return 0;
    156 }
    157 
    158 int32_t AudioDeviceLinuxALSA::Init()
    159 {
    160 
    161     CriticalSectionScoped lock(&_critSect);
    162 
    163     // Load libasound
    164     if (!AlsaSymbolTable.Load())
    165     {
    166         // Alsa is not installed on
    167         // this system
    168         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
    169                    "  failed to load symbol table");
    170         return -1;
    171     }
    172 
    173     if (_initialized)
    174     {
    175         return 0;
    176     }
    177 #if defined(USE_X11)
    178     //Get X display handle for typing detection
    179     _XDisplay = XOpenDisplay(NULL);
    180     if (!_XDisplay)
    181     {
    182         WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
    183           "  failed to open X display, typing detection will not work");
    184     }
    185 #endif
    186     _playWarning = 0;
    187     _playError = 0;
    188     _recWarning = 0;
    189     _recError = 0;
    190 
    191     _initialized = true;
    192 
    193     return 0;
    194 }
    195 
    196 int32_t AudioDeviceLinuxALSA::Terminate()
    197 {
    198     if (!_initialized)
    199     {
    200         return 0;
    201     }
    202 
    203     CriticalSectionScoped lock(&_critSect);
    204 
    205     _mixerManager.Close();
    206 
    207     // RECORDING
    208     if (_ptrThreadRec)
    209     {
    210         rtc::PlatformThread* tmpThread = _ptrThreadRec.release();
    211         _critSect.Leave();
    212 
    213         tmpThread->Stop();
    214         delete tmpThread;
    215 
    216         _critSect.Enter();
    217     }
    218 
    219     // PLAYOUT
    220     if (_ptrThreadPlay)
    221     {
    222         rtc::PlatformThread* tmpThread = _ptrThreadPlay.release();
    223         _critSect.Leave();
    224 
    225         tmpThread->Stop();
    226         delete tmpThread;
    227 
    228         _critSect.Enter();
    229     }
    230 #if defined(USE_X11)
    231     if (_XDisplay)
    232     {
    233       XCloseDisplay(_XDisplay);
    234       _XDisplay = NULL;
    235     }
    236 #endif
    237     _initialized = false;
    238     _outputDeviceIsSpecified = false;
    239     _inputDeviceIsSpecified = false;
    240 
    241     return 0;
    242 }
    243 
    244 bool AudioDeviceLinuxALSA::Initialized() const
    245 {
    246     return (_initialized);
    247 }
    248 
    249 int32_t AudioDeviceLinuxALSA::InitSpeaker()
    250 {
    251 
    252     CriticalSectionScoped lock(&_critSect);
    253 
    254     if (_playing)
    255     {
    256         return -1;
    257     }
    258 
    259     char devName[kAdmMaxDeviceNameSize] = {0};
    260     GetDevicesInfo(2, true, _outputDeviceIndex, devName, kAdmMaxDeviceNameSize);
    261     return _mixerManager.OpenSpeaker(devName);
    262 }
    263 
    264 int32_t AudioDeviceLinuxALSA::InitMicrophone()
    265 {
    266 
    267     CriticalSectionScoped lock(&_critSect);
    268 
    269     if (_recording)
    270     {
    271         return -1;
    272     }
    273 
    274     char devName[kAdmMaxDeviceNameSize] = {0};
    275     GetDevicesInfo(2, false, _inputDeviceIndex, devName, kAdmMaxDeviceNameSize);
    276     return _mixerManager.OpenMicrophone(devName);
    277 }
    278 
    279 bool AudioDeviceLinuxALSA::SpeakerIsInitialized() const
    280 {
    281     return (_mixerManager.SpeakerIsInitialized());
    282 }
    283 
    284 bool AudioDeviceLinuxALSA::MicrophoneIsInitialized() const
    285 {
    286     return (_mixerManager.MicrophoneIsInitialized());
    287 }
    288 
    289 int32_t AudioDeviceLinuxALSA::SpeakerVolumeIsAvailable(bool& available)
    290 {
    291 
    292     bool wasInitialized = _mixerManager.SpeakerIsInitialized();
    293 
    294     // Make an attempt to open up the
    295     // output mixer corresponding to the currently selected output device.
    296     if (!wasInitialized && InitSpeaker() == -1)
    297     {
    298         // If we end up here it means that the selected speaker has no volume
    299         // control.
    300         available = false;
    301         return 0;
    302     }
    303 
    304     // Given that InitSpeaker was successful, we know that a volume control
    305     // exists
    306     available = true;
    307 
    308     // Close the initialized output mixer
    309     if (!wasInitialized)
    310     {
    311         _mixerManager.CloseSpeaker();
    312     }
    313 
    314     return 0;
    315 }
    316 
    317 int32_t AudioDeviceLinuxALSA::SetSpeakerVolume(uint32_t volume)
    318 {
    319 
    320     return (_mixerManager.SetSpeakerVolume(volume));
    321 }
    322 
    323 int32_t AudioDeviceLinuxALSA::SpeakerVolume(uint32_t& volume) const
    324 {
    325 
    326     uint32_t level(0);
    327 
    328     if (_mixerManager.SpeakerVolume(level) == -1)
    329     {
    330         return -1;
    331     }
    332 
    333     volume = level;
    334 
    335     return 0;
    336 }
    337 
    338 
    339 int32_t AudioDeviceLinuxALSA::SetWaveOutVolume(uint16_t volumeLeft,
    340                                                uint16_t volumeRight)
    341 {
    342 
    343     WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
    344                  "  API call not supported on this platform");
    345     return -1;
    346 }
    347 
    348 int32_t AudioDeviceLinuxALSA::WaveOutVolume(
    349     uint16_t& /*volumeLeft*/,
    350     uint16_t& /*volumeRight*/) const
    351 {
    352 
    353     WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
    354                  "  API call not supported on this platform");
    355     return -1;
    356 }
    357 
    358 int32_t AudioDeviceLinuxALSA::MaxSpeakerVolume(
    359     uint32_t& maxVolume) const
    360 {
    361 
    362     uint32_t maxVol(0);
    363 
    364     if (_mixerManager.MaxSpeakerVolume(maxVol) == -1)
    365     {
    366         return -1;
    367     }
    368 
    369     maxVolume = maxVol;
    370 
    371     return 0;
    372 }
    373 
    374 int32_t AudioDeviceLinuxALSA::MinSpeakerVolume(
    375     uint32_t& minVolume) const
    376 {
    377 
    378     uint32_t minVol(0);
    379 
    380     if (_mixerManager.MinSpeakerVolume(minVol) == -1)
    381     {
    382         return -1;
    383     }
    384 
    385     minVolume = minVol;
    386 
    387     return 0;
    388 }
    389 
    390 int32_t AudioDeviceLinuxALSA::SpeakerVolumeStepSize(
    391     uint16_t& stepSize) const
    392 {
    393 
    394     uint16_t delta(0);
    395 
    396     if (_mixerManager.SpeakerVolumeStepSize(delta) == -1)
    397     {
    398         return -1;
    399     }
    400 
    401     stepSize = delta;
    402 
    403     return 0;
    404 }
    405 
    406 int32_t AudioDeviceLinuxALSA::SpeakerMuteIsAvailable(bool& available)
    407 {
    408 
    409     bool isAvailable(false);
    410     bool wasInitialized = _mixerManager.SpeakerIsInitialized();
    411 
    412     // Make an attempt to open up the
    413     // output mixer corresponding to the currently selected output device.
    414     //
    415     if (!wasInitialized && InitSpeaker() == -1)
    416     {
    417         // If we end up here it means that the selected speaker has no volume
    418         // control, hence it is safe to state that there is no mute control
    419         // already at this stage.
    420         available = false;
    421         return 0;
    422     }
    423 
    424     // Check if the selected speaker has a mute control
    425     _mixerManager.SpeakerMuteIsAvailable(isAvailable);
    426 
    427     available = isAvailable;
    428 
    429     // Close the initialized output mixer
    430     if (!wasInitialized)
    431     {
    432         _mixerManager.CloseSpeaker();
    433     }
    434 
    435     return 0;
    436 }
    437 
    438 int32_t AudioDeviceLinuxALSA::SetSpeakerMute(bool enable)
    439 {
    440     return (_mixerManager.SetSpeakerMute(enable));
    441 }
    442 
    443 int32_t AudioDeviceLinuxALSA::SpeakerMute(bool& enabled) const
    444 {
    445 
    446     bool muted(0);
    447 
    448     if (_mixerManager.SpeakerMute(muted) == -1)
    449     {
    450         return -1;
    451     }
    452 
    453     enabled = muted;
    454 
    455     return 0;
    456 }
    457 
    458 int32_t AudioDeviceLinuxALSA::MicrophoneMuteIsAvailable(bool& available)
    459 {
    460 
    461     bool isAvailable(false);
    462     bool wasInitialized = _mixerManager.MicrophoneIsInitialized();
    463 
    464     // Make an attempt to open up the
    465     // input mixer corresponding to the currently selected input device.
    466     //
    467     if (!wasInitialized && InitMicrophone() == -1)
    468     {
    469         // If we end up here it means that the selected microphone has no volume
    470         // control, hence it is safe to state that there is no mute control
    471         // already at this stage.
    472         available = false;
    473         return 0;
    474     }
    475 
    476     // Check if the selected microphone has a mute control
    477     //
    478     _mixerManager.MicrophoneMuteIsAvailable(isAvailable);
    479     available = isAvailable;
    480 
    481     // Close the initialized input mixer
    482     //
    483     if (!wasInitialized)
    484     {
    485         _mixerManager.CloseMicrophone();
    486     }
    487 
    488     return 0;
    489 }
    490 
    491 int32_t AudioDeviceLinuxALSA::SetMicrophoneMute(bool enable)
    492 {
    493     return (_mixerManager.SetMicrophoneMute(enable));
    494 }
    495 
    496 // ----------------------------------------------------------------------------
    497 //  MicrophoneMute
    498 // ----------------------------------------------------------------------------
    499 
    500 int32_t AudioDeviceLinuxALSA::MicrophoneMute(bool& enabled) const
    501 {
    502 
    503     bool muted(0);
    504 
    505     if (_mixerManager.MicrophoneMute(muted) == -1)
    506     {
    507         return -1;
    508     }
    509 
    510     enabled = muted;
    511     return 0;
    512 }
    513 
    514 int32_t AudioDeviceLinuxALSA::MicrophoneBoostIsAvailable(bool& available)
    515 {
    516 
    517     bool isAvailable(false);
    518     bool wasInitialized = _mixerManager.MicrophoneIsInitialized();
    519 
    520     // Enumerate all avaliable microphone and make an attempt to open up the
    521     // input mixer corresponding to the currently selected input device.
    522     //
    523     if (!wasInitialized && InitMicrophone() == -1)
    524     {
    525         // If we end up here it means that the selected microphone has no volume
    526         // control, hence it is safe to state that there is no boost control
    527         // already at this stage.
    528         available = false;
    529         return 0;
    530     }
    531 
    532     // Check if the selected microphone has a boost control
    533     _mixerManager.MicrophoneBoostIsAvailable(isAvailable);
    534     available = isAvailable;
    535 
    536     // Close the initialized input mixer
    537     if (!wasInitialized)
    538     {
    539         _mixerManager.CloseMicrophone();
    540     }
    541 
    542     return 0;
    543 }
    544 
    545 int32_t AudioDeviceLinuxALSA::SetMicrophoneBoost(bool enable)
    546 {
    547 
    548     return (_mixerManager.SetMicrophoneBoost(enable));
    549 }
    550 
    551 int32_t AudioDeviceLinuxALSA::MicrophoneBoost(bool& enabled) const
    552 {
    553 
    554     bool onOff(0);
    555 
    556     if (_mixerManager.MicrophoneBoost(onOff) == -1)
    557     {
    558         return -1;
    559     }
    560 
    561     enabled = onOff;
    562 
    563     return 0;
    564 }
    565 
    566 int32_t AudioDeviceLinuxALSA::StereoRecordingIsAvailable(bool& available)
    567 {
    568 
    569     CriticalSectionScoped lock(&_critSect);
    570 
    571     // If we already have initialized in stereo it's obviously available
    572     if (_recIsInitialized && (2 == _recChannels))
    573     {
    574         available = true;
    575         return 0;
    576     }
    577 
    578     // Save rec states and the number of rec channels
    579     bool recIsInitialized = _recIsInitialized;
    580     bool recording = _recording;
    581     int recChannels = _recChannels;
    582 
    583     available = false;
    584 
    585     // Stop/uninitialize recording if initialized (and possibly started)
    586     if (_recIsInitialized)
    587     {
    588         StopRecording();
    589     }
    590 
    591     // Try init in stereo;
    592     _recChannels = 2;
    593     if (InitRecording() == 0)
    594     {
    595         available = true;
    596     }
    597 
    598     // Stop/uninitialize recording
    599     StopRecording();
    600 
    601     // Recover previous states
    602     _recChannels = recChannels;
    603     if (recIsInitialized)
    604     {
    605         InitRecording();
    606     }
    607     if (recording)
    608     {
    609         StartRecording();
    610     }
    611 
    612     return 0;
    613 }
    614 
    615 int32_t AudioDeviceLinuxALSA::SetStereoRecording(bool enable)
    616 {
    617 
    618     if (enable)
    619         _recChannels = 2;
    620     else
    621         _recChannels = 1;
    622 
    623     return 0;
    624 }
    625 
    626 int32_t AudioDeviceLinuxALSA::StereoRecording(bool& enabled) const
    627 {
    628 
    629     if (_recChannels == 2)
    630         enabled = true;
    631     else
    632         enabled = false;
    633 
    634     return 0;
    635 }
    636 
    637 int32_t AudioDeviceLinuxALSA::StereoPlayoutIsAvailable(bool& available)
    638 {
    639 
    640     CriticalSectionScoped lock(&_critSect);
    641 
    642     // If we already have initialized in stereo it's obviously available
    643     if (_playIsInitialized && (2 == _playChannels))
    644     {
    645         available = true;
    646         return 0;
    647     }
    648 
    649     // Save rec states and the number of rec channels
    650     bool playIsInitialized = _playIsInitialized;
    651     bool playing = _playing;
    652     int playChannels = _playChannels;
    653 
    654     available = false;
    655 
    656     // Stop/uninitialize recording if initialized (and possibly started)
    657     if (_playIsInitialized)
    658     {
    659         StopPlayout();
    660     }
    661 
    662     // Try init in stereo;
    663     _playChannels = 2;
    664     if (InitPlayout() == 0)
    665     {
    666         available = true;
    667     }
    668 
    669     // Stop/uninitialize recording
    670     StopPlayout();
    671 
    672     // Recover previous states
    673     _playChannels = playChannels;
    674     if (playIsInitialized)
    675     {
    676         InitPlayout();
    677     }
    678     if (playing)
    679     {
    680         StartPlayout();
    681     }
    682 
    683     return 0;
    684 }
    685 
    686 int32_t AudioDeviceLinuxALSA::SetStereoPlayout(bool enable)
    687 {
    688 
    689     if (enable)
    690         _playChannels = 2;
    691     else
    692         _playChannels = 1;
    693 
    694     return 0;
    695 }
    696 
    697 int32_t AudioDeviceLinuxALSA::StereoPlayout(bool& enabled) const
    698 {
    699 
    700     if (_playChannels == 2)
    701         enabled = true;
    702     else
    703         enabled = false;
    704 
    705     return 0;
    706 }
    707 
    708 int32_t AudioDeviceLinuxALSA::SetAGC(bool enable)
    709 {
    710 
    711     _AGC = enable;
    712 
    713     return 0;
    714 }
    715 
    716 bool AudioDeviceLinuxALSA::AGC() const
    717 {
    718 
    719     return _AGC;
    720 }
    721 
    722 int32_t AudioDeviceLinuxALSA::MicrophoneVolumeIsAvailable(bool& available)
    723 {
    724 
    725     bool wasInitialized = _mixerManager.MicrophoneIsInitialized();
    726 
    727     // Make an attempt to open up the
    728     // input mixer corresponding to the currently selected output device.
    729     if (!wasInitialized && InitMicrophone() == -1)
    730     {
    731         // If we end up here it means that the selected microphone has no volume
    732         // control.
    733         available = false;
    734         return 0;
    735     }
    736 
    737     // Given that InitMicrophone was successful, we know that a volume control
    738     // exists
    739     available = true;
    740 
    741     // Close the initialized input mixer
    742     if (!wasInitialized)
    743     {
    744         _mixerManager.CloseMicrophone();
    745     }
    746 
    747     return 0;
    748 }
    749 
    750 int32_t AudioDeviceLinuxALSA::SetMicrophoneVolume(uint32_t volume)
    751 {
    752 
    753     return (_mixerManager.SetMicrophoneVolume(volume));
    754 
    755     return 0;
    756 }
    757 
    758 int32_t AudioDeviceLinuxALSA::MicrophoneVolume(uint32_t& volume) const
    759 {
    760 
    761     uint32_t level(0);
    762 
    763     if (_mixerManager.MicrophoneVolume(level) == -1)
    764     {
    765         WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
    766                      "  failed to retrive current microphone level");
    767         return -1;
    768     }
    769 
    770     volume = level;
    771 
    772     return 0;
    773 }
    774 
    775 int32_t AudioDeviceLinuxALSA::MaxMicrophoneVolume(
    776     uint32_t& maxVolume) const
    777 {
    778 
    779     uint32_t maxVol(0);
    780 
    781     if (_mixerManager.MaxMicrophoneVolume(maxVol) == -1)
    782     {
    783         return -1;
    784     }
    785 
    786     maxVolume = maxVol;
    787 
    788     return 0;
    789 }
    790 
    791 int32_t AudioDeviceLinuxALSA::MinMicrophoneVolume(
    792     uint32_t& minVolume) const
    793 {
    794 
    795     uint32_t minVol(0);
    796 
    797     if (_mixerManager.MinMicrophoneVolume(minVol) == -1)
    798     {
    799         return -1;
    800     }
    801 
    802     minVolume = minVol;
    803 
    804     return 0;
    805 }
    806 
    807 int32_t AudioDeviceLinuxALSA::MicrophoneVolumeStepSize(
    808     uint16_t& stepSize) const
    809 {
    810 
    811     uint16_t delta(0);
    812 
    813     if (_mixerManager.MicrophoneVolumeStepSize(delta) == -1)
    814     {
    815         return -1;
    816     }
    817 
    818     stepSize = delta;
    819 
    820     return 0;
    821 }
    822 
    823 int16_t AudioDeviceLinuxALSA::PlayoutDevices()
    824 {
    825 
    826     return (int16_t)GetDevicesInfo(0, true);
    827 }
    828 
    829 int32_t AudioDeviceLinuxALSA::SetPlayoutDevice(uint16_t index)
    830 {
    831 
    832     if (_playIsInitialized)
    833     {
    834         return -1;
    835     }
    836 
    837     uint32_t nDevices = GetDevicesInfo(0, true);
    838     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
    839                  "  number of availiable audio output devices is %u", nDevices);
    840 
    841     if (index > (nDevices-1))
    842     {
    843         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
    844                      "  device index is out of range [0,%u]", (nDevices-1));
    845         return -1;
    846     }
    847 
    848     _outputDeviceIndex = index;
    849     _outputDeviceIsSpecified = true;
    850 
    851     return 0;
    852 }
    853 
    854 int32_t AudioDeviceLinuxALSA::SetPlayoutDevice(
    855     AudioDeviceModule::WindowsDeviceType /*device*/)
    856 {
    857     WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
    858                  "WindowsDeviceType not supported");
    859     return -1;
    860 }
    861 
    862 int32_t AudioDeviceLinuxALSA::PlayoutDeviceName(
    863     uint16_t index,
    864     char name[kAdmMaxDeviceNameSize],
    865     char guid[kAdmMaxGuidSize])
    866 {
    867 
    868     const uint16_t nDevices(PlayoutDevices());
    869 
    870     if ((index > (nDevices-1)) || (name == NULL))
    871     {
    872         return -1;
    873     }
    874 
    875     memset(name, 0, kAdmMaxDeviceNameSize);
    876 
    877     if (guid != NULL)
    878     {
    879         memset(guid, 0, kAdmMaxGuidSize);
    880     }
    881 
    882     return GetDevicesInfo(1, true, index, name, kAdmMaxDeviceNameSize);
    883 }
    884 
    885 int32_t AudioDeviceLinuxALSA::RecordingDeviceName(
    886     uint16_t index,
    887     char name[kAdmMaxDeviceNameSize],
    888     char guid[kAdmMaxGuidSize])
    889 {
    890 
    891     const uint16_t nDevices(RecordingDevices());
    892 
    893     if ((index > (nDevices-1)) || (name == NULL))
    894     {
    895         return -1;
    896     }
    897 
    898     memset(name, 0, kAdmMaxDeviceNameSize);
    899 
    900     if (guid != NULL)
    901     {
    902         memset(guid, 0, kAdmMaxGuidSize);
    903     }
    904 
    905     return GetDevicesInfo(1, false, index, name, kAdmMaxDeviceNameSize);
    906 }
    907 
    908 int16_t AudioDeviceLinuxALSA::RecordingDevices()
    909 {
    910 
    911     return (int16_t)GetDevicesInfo(0, false);
    912 }
    913 
    914 int32_t AudioDeviceLinuxALSA::SetRecordingDevice(uint16_t index)
    915 {
    916 
    917     if (_recIsInitialized)
    918     {
    919         return -1;
    920     }
    921 
    922     uint32_t nDevices = GetDevicesInfo(0, false);
    923     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
    924                  "  number of availiable audio input devices is %u", nDevices);
    925 
    926     if (index > (nDevices-1))
    927     {
    928         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
    929                      "  device index is out of range [0,%u]", (nDevices-1));
    930         return -1;
    931     }
    932 
    933     _inputDeviceIndex = index;
    934     _inputDeviceIsSpecified = true;
    935 
    936     return 0;
    937 }
    938 
    939 // ----------------------------------------------------------------------------
    940 //  SetRecordingDevice II (II)
    941 // ----------------------------------------------------------------------------
    942 
    943 int32_t AudioDeviceLinuxALSA::SetRecordingDevice(
    944     AudioDeviceModule::WindowsDeviceType /*device*/)
    945 {
    946     WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
    947                  "WindowsDeviceType not supported");
    948     return -1;
    949 }
    950 
    951 int32_t AudioDeviceLinuxALSA::PlayoutIsAvailable(bool& available)
    952 {
    953 
    954     available = false;
    955 
    956     // Try to initialize the playout side with mono
    957     // Assumes that user set num channels after calling this function
    958     _playChannels = 1;
    959     int32_t res = InitPlayout();
    960 
    961     // Cancel effect of initialization
    962     StopPlayout();
    963 
    964     if (res != -1)
    965     {
    966         available = true;
    967     }
    968     else
    969     {
    970         // It may be possible to play out in stereo
    971         res = StereoPlayoutIsAvailable(available);
    972         if (available)
    973         {
    974             // Then set channels to 2 so InitPlayout doesn't fail
    975             _playChannels = 2;
    976         }
    977     }
    978 
    979     return res;
    980 }
    981 
    982 int32_t AudioDeviceLinuxALSA::RecordingIsAvailable(bool& available)
    983 {
    984 
    985     available = false;
    986 
    987     // Try to initialize the recording side with mono
    988     // Assumes that user set num channels after calling this function
    989     _recChannels = 1;
    990     int32_t res = InitRecording();
    991 
    992     // Cancel effect of initialization
    993     StopRecording();
    994 
    995     if (res != -1)
    996     {
    997         available = true;
    998     }
    999     else
   1000     {
   1001         // It may be possible to record in stereo
   1002         res = StereoRecordingIsAvailable(available);
   1003         if (available)
   1004         {
   1005             // Then set channels to 2 so InitPlayout doesn't fail
   1006             _recChannels = 2;
   1007         }
   1008     }
   1009 
   1010     return res;
   1011 }
   1012 
   1013 int32_t AudioDeviceLinuxALSA::InitPlayout()
   1014 {
   1015 
   1016     int errVal = 0;
   1017 
   1018     CriticalSectionScoped lock(&_critSect);
   1019     if (_playing)
   1020     {
   1021         return -1;
   1022     }
   1023 
   1024     if (!_outputDeviceIsSpecified)
   1025     {
   1026         return -1;
   1027     }
   1028 
   1029     if (_playIsInitialized)
   1030     {
   1031         return 0;
   1032     }
   1033     // Initialize the speaker (devices might have been added or removed)
   1034     if (InitSpeaker() == -1)
   1035     {
   1036         WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
   1037                      "  InitSpeaker() failed");
   1038     }
   1039 
   1040     // Start by closing any existing wave-output devices
   1041     //
   1042     if (_handlePlayout != NULL)
   1043     {
   1044         LATE(snd_pcm_close)(_handlePlayout);
   1045         _handlePlayout = NULL;
   1046         _playIsInitialized = false;
   1047         if (errVal < 0)
   1048         {
   1049             WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   1050                          "  Error closing current playout sound device, error:"
   1051                          " %s", LATE(snd_strerror)(errVal));
   1052         }
   1053     }
   1054 
   1055     // Open PCM device for playout
   1056     char deviceName[kAdmMaxDeviceNameSize] = {0};
   1057     GetDevicesInfo(2, true, _outputDeviceIndex, deviceName,
   1058                    kAdmMaxDeviceNameSize);
   1059 
   1060     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
   1061                  "  InitPlayout open (%s)", deviceName);
   1062 
   1063     errVal = LATE(snd_pcm_open)
   1064                  (&_handlePlayout,
   1065                   deviceName,
   1066                   SND_PCM_STREAM_PLAYBACK,
   1067                   SND_PCM_NONBLOCK);
   1068 
   1069     if (errVal == -EBUSY) // Device busy - try some more!
   1070     {
   1071         for (int i=0; i < 5; i++)
   1072         {
   1073             SleepMs(1000);
   1074             errVal = LATE(snd_pcm_open)
   1075                          (&_handlePlayout,
   1076                           deviceName,
   1077                           SND_PCM_STREAM_PLAYBACK,
   1078                           SND_PCM_NONBLOCK);
   1079             if (errVal == 0)
   1080             {
   1081                 break;
   1082             }
   1083         }
   1084     }
   1085     if (errVal < 0)
   1086     {
   1087         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   1088                      "     unable to open playback device: %s (%d)",
   1089                      LATE(snd_strerror)(errVal),
   1090                      errVal);
   1091         _handlePlayout = NULL;
   1092         return -1;
   1093     }
   1094 
   1095     _playoutFramesIn10MS = _playoutFreq/100;
   1096     if ((errVal = LATE(snd_pcm_set_params)( _handlePlayout,
   1097 #if defined(WEBRTC_ARCH_BIG_ENDIAN)
   1098         SND_PCM_FORMAT_S16_BE,
   1099 #else
   1100         SND_PCM_FORMAT_S16_LE, //format
   1101 #endif
   1102         SND_PCM_ACCESS_RW_INTERLEAVED, //access
   1103         _playChannels, //channels
   1104         _playoutFreq, //rate
   1105         1, //soft_resample
   1106         ALSA_PLAYOUT_LATENCY //40*1000 //latency required overall latency in us
   1107     )) < 0)
   1108     {   /* 0.5sec */
   1109         _playoutFramesIn10MS = 0;
   1110         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   1111                      "     unable to set playback device: %s (%d)",
   1112                      LATE(snd_strerror)(errVal),
   1113                      errVal);
   1114         ErrorRecovery(errVal, _handlePlayout);
   1115         errVal = LATE(snd_pcm_close)(_handlePlayout);
   1116         _handlePlayout = NULL;
   1117         return -1;
   1118     }
   1119 
   1120     errVal = LATE(snd_pcm_get_params)(_handlePlayout,
   1121         &_playoutBufferSizeInFrame, &_playoutPeriodSizeInFrame);
   1122     if (errVal < 0)
   1123     {
   1124         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   1125                      "    snd_pcm_get_params %s",
   1126                      LATE(snd_strerror)(errVal),
   1127                      errVal);
   1128         _playoutBufferSizeInFrame = 0;
   1129         _playoutPeriodSizeInFrame = 0;
   1130     }
   1131     else {
   1132         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
   1133                      "    playout snd_pcm_get_params "
   1134                      "buffer_size:%d period_size :%d",
   1135                      _playoutBufferSizeInFrame, _playoutPeriodSizeInFrame);
   1136     }
   1137 
   1138     if (_ptrAudioBuffer)
   1139     {
   1140         // Update webrtc audio buffer with the selected parameters
   1141         _ptrAudioBuffer->SetPlayoutSampleRate(_playoutFreq);
   1142         _ptrAudioBuffer->SetPlayoutChannels(_playChannels);
   1143     }
   1144 
   1145     // Set play buffer size
   1146     _playoutBufferSizeIn10MS = LATE(snd_pcm_frames_to_bytes)(
   1147         _handlePlayout, _playoutFramesIn10MS);
   1148 
   1149     // Init varaibles used for play
   1150     _playWarning = 0;
   1151     _playError = 0;
   1152 
   1153     if (_handlePlayout != NULL)
   1154     {
   1155         _playIsInitialized = true;
   1156         return 0;
   1157     }
   1158     else
   1159     {
   1160         return -1;
   1161     }
   1162 
   1163     return 0;
   1164 }
   1165 
   1166 int32_t AudioDeviceLinuxALSA::InitRecording()
   1167 {
   1168 
   1169     int errVal = 0;
   1170 
   1171     CriticalSectionScoped lock(&_critSect);
   1172 
   1173     if (_recording)
   1174     {
   1175         return -1;
   1176     }
   1177 
   1178     if (!_inputDeviceIsSpecified)
   1179     {
   1180         return -1;
   1181     }
   1182 
   1183     if (_recIsInitialized)
   1184     {
   1185         return 0;
   1186     }
   1187 
   1188     // Initialize the microphone (devices might have been added or removed)
   1189     if (InitMicrophone() == -1)
   1190     {
   1191         WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
   1192                    "  InitMicrophone() failed");
   1193     }
   1194 
   1195     // Start by closing any existing pcm-input devices
   1196     //
   1197     if (_handleRecord != NULL)
   1198     {
   1199         int errVal = LATE(snd_pcm_close)(_handleRecord);
   1200         _handleRecord = NULL;
   1201         _recIsInitialized = false;
   1202         if (errVal < 0)
   1203         {
   1204             WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   1205                          "     Error closing current recording sound device,"
   1206                          " error: %s",
   1207                          LATE(snd_strerror)(errVal));
   1208         }
   1209     }
   1210 
   1211     // Open PCM device for recording
   1212     // The corresponding settings for playout are made after the record settings
   1213     char deviceName[kAdmMaxDeviceNameSize] = {0};
   1214     GetDevicesInfo(2, false, _inputDeviceIndex, deviceName,
   1215                    kAdmMaxDeviceNameSize);
   1216 
   1217     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
   1218                  "InitRecording open (%s)", deviceName);
   1219     errVal = LATE(snd_pcm_open)
   1220                  (&_handleRecord,
   1221                   deviceName,
   1222                   SND_PCM_STREAM_CAPTURE,
   1223                   SND_PCM_NONBLOCK);
   1224 
   1225     // Available modes: 0 = blocking, SND_PCM_NONBLOCK, SND_PCM_ASYNC
   1226     if (errVal == -EBUSY) // Device busy - try some more!
   1227     {
   1228         for (int i=0; i < 5; i++)
   1229         {
   1230             SleepMs(1000);
   1231             errVal = LATE(snd_pcm_open)
   1232                          (&_handleRecord,
   1233                           deviceName,
   1234                           SND_PCM_STREAM_CAPTURE,
   1235                           SND_PCM_NONBLOCK);
   1236             if (errVal == 0)
   1237             {
   1238                 break;
   1239             }
   1240         }
   1241     }
   1242     if (errVal < 0)
   1243     {
   1244         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   1245                      "    unable to open record device: %s",
   1246                      LATE(snd_strerror)(errVal));
   1247         _handleRecord = NULL;
   1248         return -1;
   1249     }
   1250 
   1251     _recordingFramesIn10MS = _recordingFreq/100;
   1252     if ((errVal = LATE(snd_pcm_set_params)(_handleRecord,
   1253 #if defined(WEBRTC_ARCH_BIG_ENDIAN)
   1254         SND_PCM_FORMAT_S16_BE, //format
   1255 #else
   1256         SND_PCM_FORMAT_S16_LE, //format
   1257 #endif
   1258         SND_PCM_ACCESS_RW_INTERLEAVED, //access
   1259         _recChannels, //channels
   1260         _recordingFreq, //rate
   1261         1, //soft_resample
   1262         ALSA_CAPTURE_LATENCY //latency in us
   1263     )) < 0)
   1264     {
   1265          // Fall back to another mode then.
   1266          if (_recChannels == 1)
   1267            _recChannels = 2;
   1268          else
   1269            _recChannels = 1;
   1270 
   1271          if ((errVal = LATE(snd_pcm_set_params)(_handleRecord,
   1272 #if defined(WEBRTC_ARCH_BIG_ENDIAN)
   1273              SND_PCM_FORMAT_S16_BE, //format
   1274 #else
   1275              SND_PCM_FORMAT_S16_LE, //format
   1276 #endif
   1277              SND_PCM_ACCESS_RW_INTERLEAVED, //access
   1278              _recChannels, //channels
   1279              _recordingFreq, //rate
   1280              1, //soft_resample
   1281              ALSA_CAPTURE_LATENCY //latency in us
   1282          )) < 0)
   1283          {
   1284              _recordingFramesIn10MS = 0;
   1285              WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   1286                           "    unable to set record settings: %s (%d)",
   1287                           LATE(snd_strerror)(errVal), errVal);
   1288              ErrorRecovery(errVal, _handleRecord);
   1289              errVal = LATE(snd_pcm_close)(_handleRecord);
   1290              _handleRecord = NULL;
   1291              return -1;
   1292          }
   1293     }
   1294 
   1295     errVal = LATE(snd_pcm_get_params)(_handleRecord,
   1296         &_recordingBuffersizeInFrame, &_recordingPeriodSizeInFrame);
   1297     if (errVal < 0)
   1298     {
   1299         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   1300                      "    snd_pcm_get_params %s",
   1301                      LATE(snd_strerror)(errVal), errVal);
   1302         _recordingBuffersizeInFrame = 0;
   1303         _recordingPeriodSizeInFrame = 0;
   1304     }
   1305     else {
   1306         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
   1307                      "    capture snd_pcm_get_params "
   1308                      "buffer_size:%d period_size:%d",
   1309                      _recordingBuffersizeInFrame, _recordingPeriodSizeInFrame);
   1310     }
   1311 
   1312     if (_ptrAudioBuffer)
   1313     {
   1314         // Update webrtc audio buffer with the selected parameters
   1315         _ptrAudioBuffer->SetRecordingSampleRate(_recordingFreq);
   1316         _ptrAudioBuffer->SetRecordingChannels(_recChannels);
   1317     }
   1318 
   1319     // Set rec buffer size and create buffer
   1320     _recordingBufferSizeIn10MS = LATE(snd_pcm_frames_to_bytes)(
   1321         _handleRecord, _recordingFramesIn10MS);
   1322 
   1323     if (_handleRecord != NULL)
   1324     {
   1325         // Mark recording side as initialized
   1326         _recIsInitialized = true;
   1327         return 0;
   1328     }
   1329     else
   1330     {
   1331         return -1;
   1332     }
   1333 
   1334     return 0;
   1335 }
   1336 
   1337 int32_t AudioDeviceLinuxALSA::StartRecording()
   1338 {
   1339 
   1340     if (!_recIsInitialized)
   1341     {
   1342         return -1;
   1343     }
   1344 
   1345     if (_recording)
   1346     {
   1347         return 0;
   1348     }
   1349 
   1350     _recording = true;
   1351 
   1352     int errVal = 0;
   1353     _recordingFramesLeft = _recordingFramesIn10MS;
   1354 
   1355     // Make sure we only create the buffer once.
   1356     if (!_recordingBuffer)
   1357         _recordingBuffer = new int8_t[_recordingBufferSizeIn10MS];
   1358     if (!_recordingBuffer)
   1359     {
   1360         WEBRTC_TRACE(kTraceCritical, kTraceAudioDevice, _id,
   1361                      "   failed to alloc recording buffer");
   1362         _recording = false;
   1363         return -1;
   1364     }
   1365     // RECORDING
   1366     _ptrThreadRec.reset(new rtc::PlatformThread(
   1367         RecThreadFunc, this, "webrtc_audio_module_capture_thread"));
   1368 
   1369     _ptrThreadRec->Start();
   1370     _ptrThreadRec->SetPriority(rtc::kRealtimePriority);
   1371 
   1372     errVal = LATE(snd_pcm_prepare)(_handleRecord);
   1373     if (errVal < 0)
   1374     {
   1375         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   1376                      "     capture snd_pcm_prepare failed (%s)\n",
   1377                      LATE(snd_strerror)(errVal));
   1378         // just log error
   1379         // if snd_pcm_open fails will return -1
   1380     }
   1381 
   1382     errVal = LATE(snd_pcm_start)(_handleRecord);
   1383     if (errVal < 0)
   1384     {
   1385         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   1386                      "     capture snd_pcm_start err: %s",
   1387                      LATE(snd_strerror)(errVal));
   1388         errVal = LATE(snd_pcm_start)(_handleRecord);
   1389         if (errVal < 0)
   1390         {
   1391             WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   1392                          "     capture snd_pcm_start 2nd try err: %s",
   1393                          LATE(snd_strerror)(errVal));
   1394             StopRecording();
   1395             return -1;
   1396         }
   1397     }
   1398 
   1399     return 0;
   1400 }
   1401 
   1402 int32_t AudioDeviceLinuxALSA::StopRecording()
   1403 {
   1404 
   1405     {
   1406       CriticalSectionScoped lock(&_critSect);
   1407 
   1408       if (!_recIsInitialized)
   1409       {
   1410           return 0;
   1411       }
   1412 
   1413       if (_handleRecord == NULL)
   1414       {
   1415           return -1;
   1416       }
   1417 
   1418       // Make sure we don't start recording (it's asynchronous).
   1419       _recIsInitialized = false;
   1420       _recording = false;
   1421     }
   1422 
   1423     if (_ptrThreadRec)
   1424     {
   1425         _ptrThreadRec->Stop();
   1426         _ptrThreadRec.reset();
   1427     }
   1428 
   1429     CriticalSectionScoped lock(&_critSect);
   1430     _recordingFramesLeft = 0;
   1431     if (_recordingBuffer)
   1432     {
   1433         delete [] _recordingBuffer;
   1434         _recordingBuffer = NULL;
   1435     }
   1436 
   1437     // Stop and close pcm recording device.
   1438     int errVal = LATE(snd_pcm_drop)(_handleRecord);
   1439     if (errVal < 0)
   1440     {
   1441         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   1442                      "     Error stop recording: %s",
   1443                      LATE(snd_strerror)(errVal));
   1444         return -1;
   1445     }
   1446 
   1447     errVal = LATE(snd_pcm_close)(_handleRecord);
   1448     if (errVal < 0)
   1449     {
   1450         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   1451                      "     Error closing record sound device, error: %s",
   1452                      LATE(snd_strerror)(errVal));
   1453         return -1;
   1454     }
   1455 
   1456     // Check if we have muted and unmute if so.
   1457     bool muteEnabled = false;
   1458     MicrophoneMute(muteEnabled);
   1459     if (muteEnabled)
   1460     {
   1461         SetMicrophoneMute(false);
   1462     }
   1463 
   1464     // set the pcm input handle to NULL
   1465     _handleRecord = NULL;
   1466     return 0;
   1467 }
   1468 
   1469 bool AudioDeviceLinuxALSA::RecordingIsInitialized() const
   1470 {
   1471     return (_recIsInitialized);
   1472 }
   1473 
   1474 bool AudioDeviceLinuxALSA::Recording() const
   1475 {
   1476     return (_recording);
   1477 }
   1478 
   1479 bool AudioDeviceLinuxALSA::PlayoutIsInitialized() const
   1480 {
   1481     return (_playIsInitialized);
   1482 }
   1483 
   1484 int32_t AudioDeviceLinuxALSA::StartPlayout()
   1485 {
   1486     if (!_playIsInitialized)
   1487     {
   1488         return -1;
   1489     }
   1490 
   1491     if (_playing)
   1492     {
   1493         return 0;
   1494     }
   1495 
   1496     _playing = true;
   1497 
   1498     _playoutFramesLeft = 0;
   1499     if (!_playoutBuffer)
   1500         _playoutBuffer = new int8_t[_playoutBufferSizeIn10MS];
   1501     if (!_playoutBuffer)
   1502     {
   1503       WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   1504                    "    failed to alloc playout buf");
   1505       _playing = false;
   1506       return -1;
   1507     }
   1508 
   1509     // PLAYOUT
   1510     _ptrThreadPlay.reset(new rtc::PlatformThread(
   1511         PlayThreadFunc, this, "webrtc_audio_module_play_thread"));
   1512     _ptrThreadPlay->Start();
   1513     _ptrThreadPlay->SetPriority(rtc::kRealtimePriority);
   1514 
   1515     int errVal = LATE(snd_pcm_prepare)(_handlePlayout);
   1516     if (errVal < 0)
   1517     {
   1518         WEBRTC_TRACE(kTraceCritical, kTraceAudioDevice, _id,
   1519                      "     playout snd_pcm_prepare failed (%s)\n",
   1520                      LATE(snd_strerror)(errVal));
   1521         // just log error
   1522         // if snd_pcm_open fails will return -1
   1523     }
   1524 
   1525     return 0;
   1526 }
   1527 
   1528 int32_t AudioDeviceLinuxALSA::StopPlayout()
   1529 {
   1530 
   1531     {
   1532         CriticalSectionScoped lock(&_critSect);
   1533 
   1534         if (!_playIsInitialized)
   1535         {
   1536             return 0;
   1537         }
   1538 
   1539         if (_handlePlayout == NULL)
   1540         {
   1541             return -1;
   1542         }
   1543 
   1544         _playing = false;
   1545     }
   1546 
   1547     // stop playout thread first
   1548     if (_ptrThreadPlay)
   1549     {
   1550         _ptrThreadPlay->Stop();
   1551         _ptrThreadPlay.reset();
   1552     }
   1553 
   1554     CriticalSectionScoped lock(&_critSect);
   1555 
   1556     _playoutFramesLeft = 0;
   1557     delete [] _playoutBuffer;
   1558     _playoutBuffer = NULL;
   1559 
   1560     // stop and close pcm playout device
   1561     int errVal = LATE(snd_pcm_drop)(_handlePlayout);
   1562     if (errVal < 0)
   1563     {
   1564         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   1565                      "    Error stop playing: %s",
   1566                      LATE(snd_strerror)(errVal));
   1567     }
   1568 
   1569     errVal = LATE(snd_pcm_close)(_handlePlayout);
   1570      if (errVal < 0)
   1571          WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   1572                       "    Error closing playout sound device, error: %s",
   1573                       LATE(snd_strerror)(errVal));
   1574 
   1575      // set the pcm input handle to NULL
   1576      _playIsInitialized = false;
   1577      _handlePlayout = NULL;
   1578      WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
   1579                   "  handle_playout is now set to NULL");
   1580 
   1581      return 0;
   1582 }
   1583 
   1584 int32_t AudioDeviceLinuxALSA::PlayoutDelay(uint16_t& delayMS) const
   1585 {
   1586     delayMS = (uint16_t)_playoutDelay * 1000 / _playoutFreq;
   1587     return 0;
   1588 }
   1589 
   1590 int32_t AudioDeviceLinuxALSA::RecordingDelay(uint16_t& delayMS) const
   1591 {
   1592     // Adding 10ms adjusted value to the record delay due to 10ms buffering.
   1593     delayMS = (uint16_t)(10 + _recordingDelay * 1000 / _recordingFreq);
   1594     return 0;
   1595 }
   1596 
   1597 bool AudioDeviceLinuxALSA::Playing() const
   1598 {
   1599     return (_playing);
   1600 }
   1601 // ----------------------------------------------------------------------------
   1602 //  SetPlayoutBuffer
   1603 // ----------------------------------------------------------------------------
   1604 
   1605 int32_t AudioDeviceLinuxALSA::SetPlayoutBuffer(
   1606     const AudioDeviceModule::BufferType type,
   1607     uint16_t sizeMS)
   1608 {
   1609     _playBufType = type;
   1610     if (type == AudioDeviceModule::kFixedBufferSize)
   1611     {
   1612         _playBufDelayFixed = sizeMS;
   1613     }
   1614     return 0;
   1615 }
   1616 
   1617 int32_t AudioDeviceLinuxALSA::PlayoutBuffer(
   1618     AudioDeviceModule::BufferType& type,
   1619     uint16_t& sizeMS) const
   1620 {
   1621     type = _playBufType;
   1622     if (type == AudioDeviceModule::kFixedBufferSize)
   1623     {
   1624         sizeMS = _playBufDelayFixed;
   1625     }
   1626     else
   1627     {
   1628         sizeMS = _playBufDelay;
   1629     }
   1630 
   1631     return 0;
   1632 }
   1633 
   1634 int32_t AudioDeviceLinuxALSA::CPULoad(uint16_t& load) const
   1635 {
   1636 
   1637     WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
   1638                "  API call not supported on this platform");
   1639     return -1;
   1640 }
   1641 
   1642 bool AudioDeviceLinuxALSA::PlayoutWarning() const
   1643 {
   1644     CriticalSectionScoped lock(&_critSect);
   1645     return (_playWarning > 0);
   1646 }
   1647 
   1648 bool AudioDeviceLinuxALSA::PlayoutError() const
   1649 {
   1650     CriticalSectionScoped lock(&_critSect);
   1651     return (_playError > 0);
   1652 }
   1653 
   1654 bool AudioDeviceLinuxALSA::RecordingWarning() const
   1655 {
   1656     CriticalSectionScoped lock(&_critSect);
   1657     return (_recWarning > 0);
   1658 }
   1659 
   1660 bool AudioDeviceLinuxALSA::RecordingError() const
   1661 {
   1662     CriticalSectionScoped lock(&_critSect);
   1663     return (_recError > 0);
   1664 }
   1665 
   1666 void AudioDeviceLinuxALSA::ClearPlayoutWarning()
   1667 {
   1668     CriticalSectionScoped lock(&_critSect);
   1669     _playWarning = 0;
   1670 }
   1671 
   1672 void AudioDeviceLinuxALSA::ClearPlayoutError()
   1673 {
   1674     CriticalSectionScoped lock(&_critSect);
   1675     _playError = 0;
   1676 }
   1677 
   1678 void AudioDeviceLinuxALSA::ClearRecordingWarning()
   1679 {
   1680     CriticalSectionScoped lock(&_critSect);
   1681     _recWarning = 0;
   1682 }
   1683 
   1684 void AudioDeviceLinuxALSA::ClearRecordingError()
   1685 {
   1686     CriticalSectionScoped lock(&_critSect);
   1687     _recError = 0;
   1688 }
   1689 
   1690 // ============================================================================
   1691 //                                 Private Methods
   1692 // ============================================================================
   1693 
   1694 int32_t AudioDeviceLinuxALSA::GetDevicesInfo(
   1695     const int32_t function,
   1696     const bool playback,
   1697     const int32_t enumDeviceNo,
   1698     char* enumDeviceName,
   1699     const int32_t ednLen) const
   1700 {
   1701 
   1702     // Device enumeration based on libjingle implementation
   1703     // by Tristan Schmelcher at Google Inc.
   1704 
   1705     const char *type = playback ? "Output" : "Input";
   1706     // dmix and dsnoop are only for playback and capture, respectively, but ALSA
   1707     // stupidly includes them in both lists.
   1708     const char *ignorePrefix = playback ? "dsnoop:" : "dmix:" ;
   1709     // (ALSA lists many more "devices" of questionable interest, but we show them
   1710     // just in case the weird devices may actually be desirable for some
   1711     // users/systems.)
   1712 
   1713     int err;
   1714     int enumCount(0);
   1715     bool keepSearching(true);
   1716 
   1717     // From Chromium issue 95797
   1718     // Loop through the sound cards to get Alsa device hints.
   1719     // Don't use snd_device_name_hint(-1,..) since there is a access violation
   1720     // inside this ALSA API with libasound.so.2.0.0.
   1721     int card = -1;
   1722     while (!(LATE(snd_card_next)(&card)) && (card >= 0) && keepSearching) {
   1723         void **hints;
   1724         err = LATE(snd_device_name_hint)(card, "pcm", &hints);
   1725         if (err != 0)
   1726         {
   1727             WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   1728                          "GetDevicesInfo - device name hint error: %s",
   1729                          LATE(snd_strerror)(err));
   1730             return -1;
   1731         }
   1732 
   1733         enumCount++; // default is 0
   1734         if ((function == FUNC_GET_DEVICE_NAME ||
   1735             function == FUNC_GET_DEVICE_NAME_FOR_AN_ENUM) && enumDeviceNo == 0)
   1736         {
   1737             strcpy(enumDeviceName, "default");
   1738 
   1739             err = LATE(snd_device_name_free_hint)(hints);
   1740             if (err != 0)
   1741             {
   1742                 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   1743                              "GetDevicesInfo - device name free hint error: %s",
   1744                              LATE(snd_strerror)(err));
   1745             }
   1746 
   1747             return 0;
   1748         }
   1749 
   1750         for (void **list = hints; *list != NULL; ++list)
   1751         {
   1752             char *actualType = LATE(snd_device_name_get_hint)(*list, "IOID");
   1753             if (actualType)
   1754             {   // NULL means it's both.
   1755                 bool wrongType = (strcmp(actualType, type) != 0);
   1756                 free(actualType);
   1757                 if (wrongType)
   1758                 {
   1759                     // Wrong type of device (i.e., input vs. output).
   1760                     continue;
   1761                 }
   1762             }
   1763 
   1764             char *name = LATE(snd_device_name_get_hint)(*list, "NAME");
   1765             if (!name)
   1766             {
   1767                 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   1768                              "Device has no name");
   1769                 // Skip it.
   1770                 continue;
   1771             }
   1772 
   1773             // Now check if we actually want to show this device.
   1774             if (strcmp(name, "default") != 0 &&
   1775                 strcmp(name, "null") != 0 &&
   1776                 strcmp(name, "pulse") != 0 &&
   1777                 strncmp(name, ignorePrefix, strlen(ignorePrefix)) != 0)
   1778             {
   1779                 // Yes, we do.
   1780                 char *desc = LATE(snd_device_name_get_hint)(*list, "DESC");
   1781                 if (!desc)
   1782                 {
   1783                     // Virtual devices don't necessarily have descriptions.
   1784                     // Use their names instead.
   1785                     desc = name;
   1786                 }
   1787 
   1788                 if (FUNC_GET_NUM_OF_DEVICE == function)
   1789                 {
   1790                     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
   1791                                  "    Enum device %d - %s", enumCount, name);
   1792 
   1793                 }
   1794                 if ((FUNC_GET_DEVICE_NAME == function) &&
   1795                     (enumDeviceNo == enumCount))
   1796                 {
   1797                     // We have found the enum device, copy the name to buffer.
   1798                     strncpy(enumDeviceName, desc, ednLen);
   1799                     enumDeviceName[ednLen-1] = '\0';
   1800                     keepSearching = false;
   1801                     // Replace '\n' with '-'.
   1802                     char * pret = strchr(enumDeviceName, '\n'/*0xa*/); //LF
   1803                     if (pret)
   1804                         *pret = '-';
   1805                 }
   1806                 if ((FUNC_GET_DEVICE_NAME_FOR_AN_ENUM == function) &&
   1807                     (enumDeviceNo == enumCount))
   1808                 {
   1809                     // We have found the enum device, copy the name to buffer.
   1810                     strncpy(enumDeviceName, name, ednLen);
   1811                     enumDeviceName[ednLen-1] = '\0';
   1812                     keepSearching = false;
   1813                 }
   1814 
   1815                 if (keepSearching)
   1816                     ++enumCount;
   1817 
   1818                 if (desc != name)
   1819                     free(desc);
   1820             }
   1821 
   1822             free(name);
   1823 
   1824             if (!keepSearching)
   1825                 break;
   1826         }
   1827 
   1828         err = LATE(snd_device_name_free_hint)(hints);
   1829         if (err != 0)
   1830         {
   1831             WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   1832                          "GetDevicesInfo - device name free hint error: %s",
   1833                          LATE(snd_strerror)(err));
   1834             // Continue and return true anyway, since we did get the whole list.
   1835         }
   1836     }
   1837 
   1838     if (FUNC_GET_NUM_OF_DEVICE == function)
   1839     {
   1840         if (enumCount == 1) // only default?
   1841             enumCount = 0;
   1842         return enumCount; // Normal return point for function 0
   1843     }
   1844 
   1845     if (keepSearching)
   1846     {
   1847         // If we get here for function 1 and 2, we didn't find the specified
   1848         // enum device.
   1849         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   1850                      "GetDevicesInfo - Could not find device name or numbers");
   1851         return -1;
   1852     }
   1853 
   1854     return 0;
   1855 }
   1856 
   1857 int32_t AudioDeviceLinuxALSA::InputSanityCheckAfterUnlockedPeriod() const
   1858 {
   1859     if (_handleRecord == NULL)
   1860     {
   1861         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   1862                      "  input state has been modified during unlocked period");
   1863         return -1;
   1864     }
   1865     return 0;
   1866 }
   1867 
   1868 int32_t AudioDeviceLinuxALSA::OutputSanityCheckAfterUnlockedPeriod() const
   1869 {
   1870     if (_handlePlayout == NULL)
   1871     {
   1872         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   1873                      "  output state has been modified during unlocked period");
   1874         return -1;
   1875     }
   1876     return 0;
   1877 }
   1878 
   1879 int32_t AudioDeviceLinuxALSA::ErrorRecovery(int32_t error,
   1880                                             snd_pcm_t* deviceHandle)
   1881 {
   1882     int st = LATE(snd_pcm_state)(deviceHandle);
   1883     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
   1884                "Trying to recover from error: %s (%d) (state %d)",
   1885                (LATE(snd_pcm_stream)(deviceHandle) == SND_PCM_STREAM_CAPTURE) ?
   1886                    "capture" : "playout", LATE(snd_strerror)(error), error, st);
   1887 
   1888     // It is recommended to use snd_pcm_recover for all errors. If that function
   1889     // cannot handle the error, the input error code will be returned, otherwise
   1890     // 0 is returned. From snd_pcm_recover API doc: "This functions handles
   1891     // -EINTR (4) (interrupted system call), -EPIPE (32) (playout overrun or
   1892     // capture underrun) and -ESTRPIPE (86) (stream is suspended) error codes
   1893     // trying to prepare given stream for next I/O."
   1894 
   1895     /** Open */
   1896     //    SND_PCM_STATE_OPEN = 0,
   1897     /** Setup installed */
   1898     //    SND_PCM_STATE_SETUP,
   1899     /** Ready to start */
   1900     //    SND_PCM_STATE_PREPARED,
   1901     /** Running */
   1902     //    SND_PCM_STATE_RUNNING,
   1903     /** Stopped: underrun (playback) or overrun (capture) detected */
   1904     //    SND_PCM_STATE_XRUN,= 4
   1905     /** Draining: running (playback) or stopped (capture) */
   1906     //    SND_PCM_STATE_DRAINING,
   1907     /** Paused */
   1908     //    SND_PCM_STATE_PAUSED,
   1909     /** Hardware is suspended */
   1910     //    SND_PCM_STATE_SUSPENDED,
   1911     //  ** Hardware is disconnected */
   1912     //    SND_PCM_STATE_DISCONNECTED,
   1913     //    SND_PCM_STATE_LAST = SND_PCM_STATE_DISCONNECTED
   1914 
   1915     // snd_pcm_recover isn't available in older alsa, e.g. on the FC4 machine
   1916     // in Sthlm lab.
   1917 
   1918     int res = LATE(snd_pcm_recover)(deviceHandle, error, 1);
   1919     if (0 == res)
   1920     {
   1921         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
   1922                    "    Recovery - snd_pcm_recover OK");
   1923 
   1924         if ((error == -EPIPE || error == -ESTRPIPE) && // Buf underrun/overrun.
   1925             _recording &&
   1926             LATE(snd_pcm_stream)(deviceHandle) == SND_PCM_STREAM_CAPTURE)
   1927         {
   1928             // For capture streams we also have to repeat the explicit start()
   1929             // to get data flowing again.
   1930             int err = LATE(snd_pcm_start)(deviceHandle);
   1931             if (err != 0)
   1932             {
   1933                 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   1934                              "  Recovery - snd_pcm_start error: %u", err);
   1935                 return -1;
   1936             }
   1937         }
   1938 
   1939         if ((error == -EPIPE || error == -ESTRPIPE) &&  // Buf underrun/overrun.
   1940             _playing &&
   1941             LATE(snd_pcm_stream)(deviceHandle) == SND_PCM_STREAM_PLAYBACK)
   1942         {
   1943             // For capture streams we also have to repeat the explicit start() to get
   1944             // data flowing again.
   1945             int err = LATE(snd_pcm_start)(deviceHandle);
   1946             if (err != 0)
   1947             {
   1948               WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   1949                        "    Recovery - snd_pcm_start error: %s",
   1950                        LATE(snd_strerror)(err));
   1951               return -1;
   1952             }
   1953         }
   1954 
   1955         return -EPIPE == error ? 1 : 0;
   1956     }
   1957     else {
   1958         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   1959                      "  Unrecoverable alsa stream error: %d", res);
   1960     }
   1961 
   1962     return res;
   1963 }
   1964 
   1965 // ============================================================================
   1966 //                                  Thread Methods
   1967 // ============================================================================
   1968 
   1969 bool AudioDeviceLinuxALSA::PlayThreadFunc(void* pThis)
   1970 {
   1971     return (static_cast<AudioDeviceLinuxALSA*>(pThis)->PlayThreadProcess());
   1972 }
   1973 
   1974 bool AudioDeviceLinuxALSA::RecThreadFunc(void* pThis)
   1975 {
   1976     return (static_cast<AudioDeviceLinuxALSA*>(pThis)->RecThreadProcess());
   1977 }
   1978 
   1979 bool AudioDeviceLinuxALSA::PlayThreadProcess()
   1980 {
   1981     if(!_playing)
   1982         return false;
   1983 
   1984     int err;
   1985     snd_pcm_sframes_t frames;
   1986     snd_pcm_sframes_t avail_frames;
   1987 
   1988     Lock();
   1989     //return a positive number of frames ready otherwise a negative error code
   1990     avail_frames = LATE(snd_pcm_avail_update)(_handlePlayout);
   1991     if (avail_frames < 0)
   1992     {
   1993         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   1994                    "playout snd_pcm_avail_update error: %s",
   1995                    LATE(snd_strerror)(avail_frames));
   1996         ErrorRecovery(avail_frames, _handlePlayout);
   1997         UnLock();
   1998         return true;
   1999     }
   2000     else if (avail_frames == 0)
   2001     {
   2002         UnLock();
   2003 
   2004         //maximum tixe in milliseconds to wait, a negative value means infinity
   2005         err = LATE(snd_pcm_wait)(_handlePlayout, 2);
   2006         if (err == 0)
   2007         { //timeout occured
   2008             WEBRTC_TRACE(kTraceStream, kTraceAudioDevice, _id,
   2009                          "playout snd_pcm_wait timeout");
   2010         }
   2011 
   2012         return true;
   2013     }
   2014 
   2015     if (_playoutFramesLeft <= 0)
   2016     {
   2017         UnLock();
   2018         _ptrAudioBuffer->RequestPlayoutData(_playoutFramesIn10MS);
   2019         Lock();
   2020 
   2021         _playoutFramesLeft = _ptrAudioBuffer->GetPlayoutData(_playoutBuffer);
   2022         assert(_playoutFramesLeft == _playoutFramesIn10MS);
   2023     }
   2024 
   2025     if (static_cast<uint32_t>(avail_frames) > _playoutFramesLeft)
   2026         avail_frames = _playoutFramesLeft;
   2027 
   2028     int size = LATE(snd_pcm_frames_to_bytes)(_handlePlayout,
   2029         _playoutFramesLeft);
   2030     frames = LATE(snd_pcm_writei)(
   2031         _handlePlayout,
   2032         &_playoutBuffer[_playoutBufferSizeIn10MS - size],
   2033         avail_frames);
   2034 
   2035     if (frames < 0)
   2036     {
   2037         WEBRTC_TRACE(kTraceStream, kTraceAudioDevice, _id,
   2038                      "playout snd_pcm_writei error: %s",
   2039                      LATE(snd_strerror)(frames));
   2040         _playoutFramesLeft = 0;
   2041         ErrorRecovery(frames, _handlePlayout);
   2042         UnLock();
   2043         return true;
   2044     }
   2045     else {
   2046         assert(frames==avail_frames);
   2047         _playoutFramesLeft -= frames;
   2048     }
   2049 
   2050     UnLock();
   2051     return true;
   2052 }
   2053 
   2054 bool AudioDeviceLinuxALSA::RecThreadProcess()
   2055 {
   2056     if (!_recording)
   2057         return false;
   2058 
   2059     int err;
   2060     snd_pcm_sframes_t frames;
   2061     snd_pcm_sframes_t avail_frames;
   2062     int8_t buffer[_recordingBufferSizeIn10MS];
   2063 
   2064     Lock();
   2065 
   2066     //return a positive number of frames ready otherwise a negative error code
   2067     avail_frames = LATE(snd_pcm_avail_update)(_handleRecord);
   2068     if (avail_frames < 0)
   2069     {
   2070         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   2071                      "capture snd_pcm_avail_update error: %s",
   2072                      LATE(snd_strerror)(avail_frames));
   2073         ErrorRecovery(avail_frames, _handleRecord);
   2074         UnLock();
   2075         return true;
   2076     }
   2077     else if (avail_frames == 0)
   2078     { // no frame is available now
   2079         UnLock();
   2080 
   2081         //maximum time in milliseconds to wait, a negative value means infinity
   2082         err = LATE(snd_pcm_wait)(_handleRecord,
   2083             ALSA_CAPTURE_WAIT_TIMEOUT);
   2084         if (err == 0) //timeout occured
   2085             WEBRTC_TRACE(kTraceStream, kTraceAudioDevice, _id,
   2086                          "capture snd_pcm_wait timeout");
   2087 
   2088         return true;
   2089     }
   2090 
   2091     if (static_cast<uint32_t>(avail_frames) > _recordingFramesLeft)
   2092         avail_frames = _recordingFramesLeft;
   2093 
   2094     frames = LATE(snd_pcm_readi)(_handleRecord,
   2095         buffer, avail_frames); // frames to be written
   2096     if (frames < 0)
   2097     {
   2098         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   2099                      "capture snd_pcm_readi error: %s",
   2100                      LATE(snd_strerror)(frames));
   2101         ErrorRecovery(frames, _handleRecord);
   2102         UnLock();
   2103         return true;
   2104     }
   2105     else if (frames > 0)
   2106     {
   2107         assert(frames == avail_frames);
   2108 
   2109         int left_size = LATE(snd_pcm_frames_to_bytes)(_handleRecord,
   2110             _recordingFramesLeft);
   2111         int size = LATE(snd_pcm_frames_to_bytes)(_handleRecord, frames);
   2112 
   2113         memcpy(&_recordingBuffer[_recordingBufferSizeIn10MS - left_size],
   2114                buffer, size);
   2115         _recordingFramesLeft -= frames;
   2116 
   2117         if (!_recordingFramesLeft)
   2118         { // buf is full
   2119             _recordingFramesLeft = _recordingFramesIn10MS;
   2120 
   2121             // store the recorded buffer (no action will be taken if the
   2122             // #recorded samples is not a full buffer)
   2123             _ptrAudioBuffer->SetRecordedBuffer(_recordingBuffer,
   2124                                                _recordingFramesIn10MS);
   2125 
   2126             uint32_t currentMicLevel = 0;
   2127             uint32_t newMicLevel = 0;
   2128 
   2129             if (AGC())
   2130             {
   2131                 // store current mic level in the audio buffer if AGC is enabled
   2132                 if (MicrophoneVolume(currentMicLevel) == 0)
   2133                 {
   2134                     if (currentMicLevel == 0xffffffff)
   2135                         currentMicLevel = 100;
   2136                     // this call does not affect the actual microphone volume
   2137                     _ptrAudioBuffer->SetCurrentMicLevel(currentMicLevel);
   2138                 }
   2139             }
   2140 
   2141             // calculate delay
   2142             _playoutDelay = 0;
   2143             _recordingDelay = 0;
   2144             if (_handlePlayout)
   2145             {
   2146                 err = LATE(snd_pcm_delay)(_handlePlayout,
   2147                     &_playoutDelay); // returned delay in frames
   2148                 if (err < 0)
   2149                 {
   2150                     // TODO(xians): Shall we call ErrorRecovery() here?
   2151                     _playoutDelay = 0;
   2152                     WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   2153                                  "playout snd_pcm_delay: %s",
   2154                                  LATE(snd_strerror)(err));
   2155                 }
   2156             }
   2157 
   2158             err = LATE(snd_pcm_delay)(_handleRecord,
   2159                 &_recordingDelay); // returned delay in frames
   2160             if (err < 0)
   2161             {
   2162                 // TODO(xians): Shall we call ErrorRecovery() here?
   2163                 _recordingDelay = 0;
   2164                 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   2165                              "capture snd_pcm_delay: %s",
   2166                              LATE(snd_strerror)(err));
   2167             }
   2168 
   2169            // TODO(xians): Shall we add 10ms buffer delay to the record delay?
   2170             _ptrAudioBuffer->SetVQEData(
   2171                 _playoutDelay * 1000 / _playoutFreq,
   2172                 _recordingDelay * 1000 / _recordingFreq, 0);
   2173 
   2174             _ptrAudioBuffer->SetTypingStatus(KeyPressed());
   2175 
   2176             // Deliver recorded samples at specified sample rate, mic level etc.
   2177             // to the observer using callback.
   2178             UnLock();
   2179             _ptrAudioBuffer->DeliverRecordedData();
   2180             Lock();
   2181 
   2182             if (AGC())
   2183             {
   2184                 newMicLevel = _ptrAudioBuffer->NewMicLevel();
   2185                 if (newMicLevel != 0)
   2186                 {
   2187                     // The VQE will only deliver non-zero microphone levels when a
   2188                     // change is needed. Set this new mic level (received from the
   2189                     // observer as return value in the callback).
   2190                     if (SetMicrophoneVolume(newMicLevel) == -1)
   2191                         WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
   2192                                      "  the required modification of the "
   2193                                      "microphone volume failed");
   2194                 }
   2195             }
   2196         }
   2197     }
   2198 
   2199     UnLock();
   2200     return true;
   2201 }
   2202 
   2203 
   2204 bool AudioDeviceLinuxALSA::KeyPressed() const{
   2205 #if defined(USE_X11)
   2206   char szKey[32];
   2207   unsigned int i = 0;
   2208   char state = 0;
   2209 
   2210   if (!_XDisplay)
   2211     return false;
   2212 
   2213   // Check key map status
   2214   XQueryKeymap(_XDisplay, szKey);
   2215 
   2216   // A bit change in keymap means a key is pressed
   2217   for (i = 0; i < sizeof(szKey); i++)
   2218     state |= (szKey[i] ^ _oldKeyState[i]) & szKey[i];
   2219 
   2220   // Save old state
   2221   memcpy((char*)_oldKeyState, (char*)szKey, sizeof(_oldKeyState));
   2222   return (state != 0);
   2223 #else
   2224   return false;
   2225 #endif
   2226 }
   2227 }  // namespace webrtc
   2228