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/base/checks.h"
     14 
     15 #include "webrtc/modules/audio_device/audio_device_config.h"
     16 #include "webrtc/modules/audio_device/linux/audio_device_pulse_linux.h"
     17 
     18 #include "webrtc/system_wrappers/include/event_wrapper.h"
     19 #include "webrtc/system_wrappers/include/trace.h"
     20 
     21 webrtc_adm_linux_pulse::PulseAudioSymbolTable PaSymbolTable;
     22 
     23 // Accesses Pulse functions through our late-binding symbol table instead of
     24 // directly. This way we don't have to link to libpulse, which means our binary
     25 // will work on systems that don't have it.
     26 #define LATE(sym) \
     27   LATESYM_GET(webrtc_adm_linux_pulse::PulseAudioSymbolTable, &PaSymbolTable, sym)
     28 
     29 namespace webrtc
     30 {
     31 
     32 AudioDeviceLinuxPulse::AudioDeviceLinuxPulse(const int32_t id) :
     33     _ptrAudioBuffer(NULL),
     34     _critSect(*CriticalSectionWrapper::CreateCriticalSection()),
     35     _timeEventRec(*EventWrapper::Create()),
     36     _timeEventPlay(*EventWrapper::Create()),
     37     _recStartEvent(*EventWrapper::Create()),
     38     _playStartEvent(*EventWrapper::Create()),
     39     _id(id),
     40     _mixerManager(id),
     41     _inputDeviceIndex(0),
     42     _outputDeviceIndex(0),
     43     _inputDeviceIsSpecified(false),
     44     _outputDeviceIsSpecified(false),
     45     sample_rate_hz_(0),
     46     _recChannels(1),
     47     _playChannels(1),
     48     _playBufType(AudioDeviceModule::kFixedBufferSize),
     49     _initialized(false),
     50     _recording(false),
     51     _playing(false),
     52     _recIsInitialized(false),
     53     _playIsInitialized(false),
     54     _startRec(false),
     55     _stopRec(false),
     56     _startPlay(false),
     57     _stopPlay(false),
     58     _AGC(false),
     59     update_speaker_volume_at_startup_(false),
     60     _playBufDelayFixed(20),
     61     _sndCardPlayDelay(0),
     62     _sndCardRecDelay(0),
     63     _writeErrors(0),
     64     _playWarning(0),
     65     _playError(0),
     66     _recWarning(0),
     67     _recError(0),
     68     _deviceIndex(-1),
     69     _numPlayDevices(0),
     70     _numRecDevices(0),
     71     _playDeviceName(NULL),
     72     _recDeviceName(NULL),
     73     _playDisplayDeviceName(NULL),
     74     _recDisplayDeviceName(NULL),
     75     _playBuffer(NULL),
     76     _playbackBufferSize(0),
     77     _playbackBufferUnused(0),
     78     _tempBufferSpace(0),
     79     _recBuffer(NULL),
     80     _recordBufferSize(0),
     81     _recordBufferUsed(0),
     82     _tempSampleData(NULL),
     83     _tempSampleDataSize(0),
     84     _configuredLatencyPlay(0),
     85     _configuredLatencyRec(0),
     86     _paDeviceIndex(-1),
     87     _paStateChanged(false),
     88     _paMainloop(NULL),
     89     _paMainloopApi(NULL),
     90     _paContext(NULL),
     91     _recStream(NULL),
     92     _playStream(NULL),
     93     _recStreamFlags(0),
     94     _playStreamFlags(0)
     95 {
     96     WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, id,
     97                  "%s created", __FUNCTION__);
     98 
     99     memset(_paServerVersion, 0, sizeof(_paServerVersion));
    100     memset(&_playBufferAttr, 0, sizeof(_playBufferAttr));
    101     memset(&_recBufferAttr, 0, sizeof(_recBufferAttr));
    102     memset(_oldKeyState, 0, sizeof(_oldKeyState));
    103 }
    104 
    105 AudioDeviceLinuxPulse::~AudioDeviceLinuxPulse()
    106 {
    107     WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id,
    108                  "%s destroyed", __FUNCTION__);
    109     RTC_DCHECK(thread_checker_.CalledOnValidThread());
    110     Terminate();
    111 
    112     if (_recBuffer)
    113     {
    114         delete [] _recBuffer;
    115         _recBuffer = NULL;
    116     }
    117     if (_playBuffer)
    118     {
    119         delete [] _playBuffer;
    120         _playBuffer = NULL;
    121     }
    122     if (_playDeviceName)
    123     {
    124         delete [] _playDeviceName;
    125         _playDeviceName = NULL;
    126     }
    127     if (_recDeviceName)
    128     {
    129         delete [] _recDeviceName;
    130         _recDeviceName = NULL;
    131     }
    132 
    133     delete &_recStartEvent;
    134     delete &_playStartEvent;
    135     delete &_timeEventRec;
    136     delete &_timeEventPlay;
    137     delete &_critSect;
    138 }
    139 
    140 void AudioDeviceLinuxPulse::AttachAudioBuffer(AudioDeviceBuffer* audioBuffer)
    141 {
    142     RTC_DCHECK(thread_checker_.CalledOnValidThread());
    143 
    144     _ptrAudioBuffer = audioBuffer;
    145 
    146     // Inform the AudioBuffer about default settings for this implementation.
    147     // Set all values to zero here since the actual settings will be done by
    148     // InitPlayout and InitRecording later.
    149     _ptrAudioBuffer->SetRecordingSampleRate(0);
    150     _ptrAudioBuffer->SetPlayoutSampleRate(0);
    151     _ptrAudioBuffer->SetRecordingChannels(0);
    152     _ptrAudioBuffer->SetPlayoutChannels(0);
    153 }
    154 
    155 // ----------------------------------------------------------------------------
    156 //  ActiveAudioLayer
    157 // ----------------------------------------------------------------------------
    158 
    159 int32_t AudioDeviceLinuxPulse::ActiveAudioLayer(
    160     AudioDeviceModule::AudioLayer& audioLayer) const
    161 {
    162     audioLayer = AudioDeviceModule::kLinuxPulseAudio;
    163     return 0;
    164 }
    165 
    166 int32_t AudioDeviceLinuxPulse::Init()
    167 {
    168     RTC_DCHECK(thread_checker_.CalledOnValidThread());
    169     if (_initialized)
    170     {
    171         return 0;
    172     }
    173 
    174     // Initialize PulseAudio
    175     if (InitPulseAudio() < 0)
    176     {
    177         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
    178                      "  failed to initialize PulseAudio");
    179 
    180         if (TerminatePulseAudio() < 0)
    181         {
    182             WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
    183                          "  failed to terminate PulseAudio");
    184         }
    185 
    186         return -1;
    187     }
    188 
    189     _playWarning = 0;
    190     _playError = 0;
    191     _recWarning = 0;
    192     _recError = 0;
    193 
    194     //Get X display handle for typing detection
    195     _XDisplay = XOpenDisplay(NULL);
    196     if (!_XDisplay)
    197     {
    198         WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
    199           "  failed to open X display, typing detection will not work");
    200     }
    201 
    202     // RECORDING
    203     _ptrThreadRec.reset(new rtc::PlatformThread(
    204         RecThreadFunc, this, "webrtc_audio_module_rec_thread"));
    205 
    206     _ptrThreadRec->Start();
    207     _ptrThreadRec->SetPriority(rtc::kRealtimePriority);
    208 
    209     // PLAYOUT
    210     _ptrThreadPlay.reset(new rtc::PlatformThread(
    211         PlayThreadFunc, this, "webrtc_audio_module_play_thread"));
    212     _ptrThreadPlay->Start();
    213     _ptrThreadPlay->SetPriority(rtc::kRealtimePriority);
    214 
    215     _initialized = true;
    216 
    217     return 0;
    218 }
    219 
    220 int32_t AudioDeviceLinuxPulse::Terminate()
    221 {
    222     RTC_DCHECK(thread_checker_.CalledOnValidThread());
    223     if (!_initialized)
    224     {
    225         return 0;
    226     }
    227 
    228     _mixerManager.Close();
    229 
    230     // RECORDING
    231     if (_ptrThreadRec)
    232     {
    233         rtc::PlatformThread* tmpThread = _ptrThreadRec.release();
    234 
    235         _timeEventRec.Set();
    236         tmpThread->Stop();
    237         delete tmpThread;
    238     }
    239 
    240     // PLAYOUT
    241     if (_ptrThreadPlay)
    242     {
    243         rtc::PlatformThread* tmpThread = _ptrThreadPlay.release();
    244 
    245         _timeEventPlay.Set();
    246         tmpThread->Stop();
    247         delete tmpThread;
    248     }
    249 
    250     // Terminate PulseAudio
    251     if (TerminatePulseAudio() < 0)
    252     {
    253         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
    254                      "  failed to terminate PulseAudio");
    255         return -1;
    256     }
    257 
    258     if (_XDisplay)
    259     {
    260       XCloseDisplay(_XDisplay);
    261       _XDisplay = NULL;
    262     }
    263 
    264     _initialized = false;
    265     _outputDeviceIsSpecified = false;
    266     _inputDeviceIsSpecified = false;
    267 
    268     return 0;
    269 }
    270 
    271 bool AudioDeviceLinuxPulse::Initialized() const
    272 {
    273     RTC_DCHECK(thread_checker_.CalledOnValidThread());
    274     return (_initialized);
    275 }
    276 
    277 int32_t AudioDeviceLinuxPulse::InitSpeaker()
    278 {
    279     RTC_DCHECK(thread_checker_.CalledOnValidThread());
    280 
    281     if (_playing)
    282     {
    283         return -1;
    284     }
    285 
    286     if (!_outputDeviceIsSpecified)
    287     {
    288         return -1;
    289     }
    290 
    291     // check if default device
    292     if (_outputDeviceIndex == 0)
    293     {
    294         uint16_t deviceIndex = 0;
    295         GetDefaultDeviceInfo(false, NULL, deviceIndex);
    296         _paDeviceIndex = deviceIndex;
    297     } else
    298     {
    299         // get the PA device index from
    300         // the callback
    301         _deviceIndex = _outputDeviceIndex;
    302 
    303         // get playout devices
    304         PlayoutDevices();
    305     }
    306 
    307     // the callback has now set the _paDeviceIndex to
    308     // the PulseAudio index of the device
    309     if (_mixerManager.OpenSpeaker(_paDeviceIndex) == -1)
    310     {
    311         return -1;
    312     }
    313 
    314     // clear _deviceIndex
    315     _deviceIndex = -1;
    316     _paDeviceIndex = -1;
    317 
    318     return 0;
    319 }
    320 
    321 int32_t AudioDeviceLinuxPulse::InitMicrophone()
    322 {
    323     RTC_DCHECK(thread_checker_.CalledOnValidThread());
    324     if (_recording)
    325     {
    326         return -1;
    327     }
    328 
    329     if (!_inputDeviceIsSpecified)
    330     {
    331         return -1;
    332     }
    333 
    334     // Check if default device
    335     if (_inputDeviceIndex == 0)
    336     {
    337         uint16_t deviceIndex = 0;
    338         GetDefaultDeviceInfo(true, NULL, deviceIndex);
    339         _paDeviceIndex = deviceIndex;
    340     } else
    341     {
    342         // Get the PA device index from
    343         // the callback
    344         _deviceIndex = _inputDeviceIndex;
    345 
    346         // get recording devices
    347         RecordingDevices();
    348     }
    349 
    350     // The callback has now set the _paDeviceIndex to
    351     // the PulseAudio index of the device
    352     if (_mixerManager.OpenMicrophone(_paDeviceIndex) == -1)
    353     {
    354         return -1;
    355     }
    356 
    357     // Clear _deviceIndex
    358     _deviceIndex = -1;
    359     _paDeviceIndex = -1;
    360 
    361     return 0;
    362 }
    363 
    364 bool AudioDeviceLinuxPulse::SpeakerIsInitialized() const
    365 {
    366     RTC_DCHECK(thread_checker_.CalledOnValidThread());
    367     return (_mixerManager.SpeakerIsInitialized());
    368 }
    369 
    370 bool AudioDeviceLinuxPulse::MicrophoneIsInitialized() const
    371 {
    372     RTC_DCHECK(thread_checker_.CalledOnValidThread());
    373     return (_mixerManager.MicrophoneIsInitialized());
    374 }
    375 
    376 int32_t AudioDeviceLinuxPulse::SpeakerVolumeIsAvailable(bool& available)
    377 {
    378     RTC_DCHECK(thread_checker_.CalledOnValidThread());
    379     bool wasInitialized = _mixerManager.SpeakerIsInitialized();
    380 
    381     // Make an attempt to open up the
    382     // output mixer corresponding to the currently selected output device.
    383     if (!wasInitialized && InitSpeaker() == -1)
    384     {
    385         // If we end up here it means that the selected speaker has no volume
    386         // control.
    387         available = false;
    388         return 0;
    389     }
    390 
    391     // Given that InitSpeaker was successful, we know volume control exists.
    392     available = true;
    393 
    394     // Close the initialized output mixer
    395     if (!wasInitialized)
    396     {
    397         _mixerManager.CloseSpeaker();
    398     }
    399 
    400     return 0;
    401 }
    402 
    403 int32_t AudioDeviceLinuxPulse::SetSpeakerVolume(uint32_t volume)
    404 {
    405     RTC_DCHECK(thread_checker_.CalledOnValidThread());
    406     if (!_playing) {
    407       // Only update the volume if it's been set while we weren't playing.
    408       update_speaker_volume_at_startup_ = true;
    409     }
    410     return (_mixerManager.SetSpeakerVolume(volume));
    411 }
    412 
    413 int32_t AudioDeviceLinuxPulse::SpeakerVolume(uint32_t& volume) const
    414 {
    415     RTC_DCHECK(thread_checker_.CalledOnValidThread());
    416     uint32_t level(0);
    417 
    418     if (_mixerManager.SpeakerVolume(level) == -1)
    419     {
    420         return -1;
    421     }
    422 
    423     volume = level;
    424 
    425     return 0;
    426 }
    427 
    428 int32_t AudioDeviceLinuxPulse::SetWaveOutVolume(
    429     uint16_t volumeLeft,
    430     uint16_t volumeRight)
    431 {
    432 
    433     WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
    434                  "  API call not supported on this platform");
    435     return -1;
    436 }
    437 
    438 int32_t AudioDeviceLinuxPulse::WaveOutVolume(
    439     uint16_t& /*volumeLeft*/,
    440     uint16_t& /*volumeRight*/) const
    441 {
    442 
    443     WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
    444                  "  API call not supported on this platform");
    445     return -1;
    446 }
    447 
    448 int32_t AudioDeviceLinuxPulse::MaxSpeakerVolume(
    449     uint32_t& maxVolume) const
    450 {
    451     RTC_DCHECK(thread_checker_.CalledOnValidThread());
    452     uint32_t maxVol(0);
    453 
    454     if (_mixerManager.MaxSpeakerVolume(maxVol) == -1)
    455     {
    456         return -1;
    457     }
    458 
    459     maxVolume = maxVol;
    460 
    461     return 0;
    462 }
    463 
    464 int32_t AudioDeviceLinuxPulse::MinSpeakerVolume(
    465     uint32_t& minVolume) const
    466 {
    467     RTC_DCHECK(thread_checker_.CalledOnValidThread());
    468     uint32_t minVol(0);
    469 
    470     if (_mixerManager.MinSpeakerVolume(minVol) == -1)
    471     {
    472         return -1;
    473     }
    474 
    475     minVolume = minVol;
    476 
    477     return 0;
    478 }
    479 
    480 int32_t AudioDeviceLinuxPulse::SpeakerVolumeStepSize(
    481     uint16_t& stepSize) const
    482 {
    483     RTC_DCHECK(thread_checker_.CalledOnValidThread());
    484     uint16_t delta(0);
    485 
    486     if (_mixerManager.SpeakerVolumeStepSize(delta) == -1)
    487     {
    488         return -1;
    489     }
    490 
    491     stepSize = delta;
    492 
    493     return 0;
    494 }
    495 
    496 int32_t AudioDeviceLinuxPulse::SpeakerMuteIsAvailable(bool& available)
    497 {
    498     RTC_DCHECK(thread_checker_.CalledOnValidThread());
    499     bool isAvailable(false);
    500     bool wasInitialized = _mixerManager.SpeakerIsInitialized();
    501 
    502     // Make an attempt to open up the
    503     // output mixer corresponding to the currently selected output device.
    504     //
    505     if (!wasInitialized && InitSpeaker() == -1)
    506     {
    507         // If we end up here it means that the selected speaker has no volume
    508         // control, hence it is safe to state that there is no mute control
    509         // already at this stage.
    510         available = false;
    511         return 0;
    512     }
    513 
    514     // Check if the selected speaker has a mute control
    515     _mixerManager.SpeakerMuteIsAvailable(isAvailable);
    516 
    517     available = isAvailable;
    518 
    519     // Close the initialized output mixer
    520     if (!wasInitialized)
    521     {
    522         _mixerManager.CloseSpeaker();
    523     }
    524 
    525     return 0;
    526 }
    527 
    528 int32_t AudioDeviceLinuxPulse::SetSpeakerMute(bool enable)
    529 {
    530     RTC_DCHECK(thread_checker_.CalledOnValidThread());
    531     return (_mixerManager.SetSpeakerMute(enable));
    532 }
    533 
    534 int32_t AudioDeviceLinuxPulse::SpeakerMute(bool& enabled) const
    535 {
    536     RTC_DCHECK(thread_checker_.CalledOnValidThread());
    537     bool muted(0);
    538     if (_mixerManager.SpeakerMute(muted) == -1)
    539     {
    540         return -1;
    541     }
    542 
    543     enabled = muted;
    544     return 0;
    545 }
    546 
    547 int32_t AudioDeviceLinuxPulse::MicrophoneMuteIsAvailable(bool& available)
    548 {
    549     RTC_DCHECK(thread_checker_.CalledOnValidThread());
    550     bool isAvailable(false);
    551     bool wasInitialized = _mixerManager.MicrophoneIsInitialized();
    552 
    553     // Make an attempt to open up the
    554     // input mixer corresponding to the currently selected input device.
    555     //
    556     if (!wasInitialized && InitMicrophone() == -1)
    557     {
    558         // If we end up here it means that the selected microphone has no
    559         // volume control, hence it is safe to state that there is no
    560         // boost control already at this stage.
    561         available = false;
    562         return 0;
    563     }
    564 
    565     // Check if the selected microphone has a mute control
    566     //
    567     _mixerManager.MicrophoneMuteIsAvailable(isAvailable);
    568     available = isAvailable;
    569 
    570     // Close the initialized input mixer
    571     //
    572     if (!wasInitialized)
    573     {
    574         _mixerManager.CloseMicrophone();
    575     }
    576 
    577     return 0;
    578 }
    579 
    580 int32_t AudioDeviceLinuxPulse::SetMicrophoneMute(bool enable)
    581 {
    582     RTC_DCHECK(thread_checker_.CalledOnValidThread());
    583     return (_mixerManager.SetMicrophoneMute(enable));
    584 }
    585 
    586 int32_t AudioDeviceLinuxPulse::MicrophoneMute(bool& enabled) const
    587 {
    588     RTC_DCHECK(thread_checker_.CalledOnValidThread());
    589     bool muted(0);
    590     if (_mixerManager.MicrophoneMute(muted) == -1)
    591     {
    592         return -1;
    593     }
    594 
    595     enabled = muted;
    596     return 0;
    597 }
    598 
    599 int32_t AudioDeviceLinuxPulse::MicrophoneBoostIsAvailable(bool& available)
    600 {
    601     RTC_DCHECK(thread_checker_.CalledOnValidThread());
    602     bool isAvailable(false);
    603     bool wasInitialized = _mixerManager.MicrophoneIsInitialized();
    604 
    605     // Enumerate all avaliable microphone and make an attempt to open up the
    606     // input mixer corresponding to the currently selected input device.
    607     //
    608     if (!wasInitialized && InitMicrophone() == -1)
    609     {
    610         // If we end up here it means that the selected microphone has no
    611         // volume control, hence it is safe to state that there is no
    612         // boost control already at this stage.
    613         available = false;
    614         return 0;
    615     }
    616 
    617     // Check if the selected microphone has a boost control
    618     _mixerManager.MicrophoneBoostIsAvailable(isAvailable);
    619     available = isAvailable;
    620 
    621     // Close the initialized input mixer
    622     if (!wasInitialized)
    623     {
    624         _mixerManager.CloseMicrophone();
    625     }
    626 
    627     return 0;
    628 }
    629 
    630 int32_t AudioDeviceLinuxPulse::SetMicrophoneBoost(bool enable)
    631 {
    632     RTC_DCHECK(thread_checker_.CalledOnValidThread());
    633     return (_mixerManager.SetMicrophoneBoost(enable));
    634 }
    635 
    636 int32_t AudioDeviceLinuxPulse::MicrophoneBoost(bool& enabled) const
    637 {
    638     RTC_DCHECK(thread_checker_.CalledOnValidThread());
    639     bool onOff(0);
    640 
    641     if (_mixerManager.MicrophoneBoost(onOff) == -1)
    642     {
    643         return -1;
    644     }
    645 
    646     enabled = onOff;
    647 
    648     return 0;
    649 }
    650 
    651 int32_t AudioDeviceLinuxPulse::StereoRecordingIsAvailable(bool& available)
    652 {
    653     RTC_DCHECK(thread_checker_.CalledOnValidThread());
    654     if (_recChannels == 2 && _recording) {
    655       available = true;
    656       return 0;
    657     }
    658 
    659     available = false;
    660     bool wasInitialized = _mixerManager.MicrophoneIsInitialized();
    661     int error = 0;
    662 
    663     if (!wasInitialized && InitMicrophone() == -1)
    664     {
    665         // Cannot open the specified device
    666         available = false;
    667         return 0;
    668     }
    669 
    670     // Check if the selected microphone can record stereo.
    671     bool isAvailable(false);
    672     error = _mixerManager.StereoRecordingIsAvailable(isAvailable);
    673     if (!error)
    674       available = isAvailable;
    675 
    676     // Close the initialized input mixer
    677     if (!wasInitialized)
    678     {
    679         _mixerManager.CloseMicrophone();
    680     }
    681 
    682     return error;
    683 }
    684 
    685 int32_t AudioDeviceLinuxPulse::SetStereoRecording(bool enable)
    686 {
    687     RTC_DCHECK(thread_checker_.CalledOnValidThread());
    688     if (enable)
    689         _recChannels = 2;
    690     else
    691         _recChannels = 1;
    692 
    693     return 0;
    694 }
    695 
    696 int32_t AudioDeviceLinuxPulse::StereoRecording(bool& enabled) const
    697 {
    698     RTC_DCHECK(thread_checker_.CalledOnValidThread());
    699     if (_recChannels == 2)
    700         enabled = true;
    701     else
    702         enabled = false;
    703 
    704     return 0;
    705 }
    706 
    707 int32_t AudioDeviceLinuxPulse::StereoPlayoutIsAvailable(bool& available)
    708 {
    709     RTC_DCHECK(thread_checker_.CalledOnValidThread());
    710     if (_playChannels == 2 && _playing) {
    711       available = true;
    712       return 0;
    713     }
    714 
    715     available = false;
    716     bool wasInitialized = _mixerManager.SpeakerIsInitialized();
    717     int error = 0;
    718 
    719     if (!wasInitialized && InitSpeaker() == -1)
    720     {
    721         // Cannot open the specified device.
    722         return -1;
    723     }
    724 
    725     // Check if the selected speaker can play stereo.
    726     bool isAvailable(false);
    727     error = _mixerManager.StereoPlayoutIsAvailable(isAvailable);
    728     if (!error)
    729       available = isAvailable;
    730 
    731     // Close the initialized input mixer
    732     if (!wasInitialized)
    733     {
    734         _mixerManager.CloseSpeaker();
    735     }
    736 
    737     return error;
    738 }
    739 
    740 int32_t AudioDeviceLinuxPulse::SetStereoPlayout(bool enable)
    741 {
    742     RTC_DCHECK(thread_checker_.CalledOnValidThread());
    743     if (enable)
    744         _playChannels = 2;
    745     else
    746         _playChannels = 1;
    747 
    748     return 0;
    749 }
    750 
    751 int32_t AudioDeviceLinuxPulse::StereoPlayout(bool& enabled) const
    752 {
    753     RTC_DCHECK(thread_checker_.CalledOnValidThread());
    754     if (_playChannels == 2)
    755         enabled = true;
    756     else
    757         enabled = false;
    758 
    759     return 0;
    760 }
    761 
    762 int32_t AudioDeviceLinuxPulse::SetAGC(bool enable)
    763 {
    764     CriticalSectionScoped lock(&_critSect);
    765     _AGC = enable;
    766 
    767     return 0;
    768 }
    769 
    770 bool AudioDeviceLinuxPulse::AGC() const
    771 {
    772     CriticalSectionScoped lock(&_critSect);
    773     return _AGC;
    774 }
    775 
    776 int32_t AudioDeviceLinuxPulse::MicrophoneVolumeIsAvailable(
    777     bool& available)
    778 {
    779     RTC_DCHECK(thread_checker_.CalledOnValidThread());
    780     bool wasInitialized = _mixerManager.MicrophoneIsInitialized();
    781 
    782     // Make an attempt to open up the
    783     // input mixer corresponding to the currently selected output device.
    784     if (!wasInitialized && InitMicrophone() == -1)
    785     {
    786         // If we end up here it means that the selected microphone has no
    787         // volume control.
    788         available = false;
    789         return 0;
    790     }
    791 
    792     // Given that InitMicrophone was successful, we know that a volume control
    793     // exists.
    794     available = true;
    795 
    796     // Close the initialized input mixer
    797     if (!wasInitialized)
    798     {
    799         _mixerManager.CloseMicrophone();
    800     }
    801 
    802     return 0;
    803 }
    804 
    805 int32_t AudioDeviceLinuxPulse::SetMicrophoneVolume(uint32_t volume)
    806 {
    807     return (_mixerManager.SetMicrophoneVolume(volume));
    808 }
    809 
    810 int32_t AudioDeviceLinuxPulse::MicrophoneVolume(
    811     uint32_t& volume) const
    812 {
    813 
    814     uint32_t level(0);
    815 
    816     if (_mixerManager.MicrophoneVolume(level) == -1)
    817     {
    818         WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
    819                      "  failed to retrive current microphone level");
    820         return -1;
    821     }
    822 
    823     volume = level;
    824 
    825     return 0;
    826 }
    827 
    828 int32_t AudioDeviceLinuxPulse::MaxMicrophoneVolume(
    829     uint32_t& maxVolume) const
    830 {
    831 
    832     uint32_t maxVol(0);
    833 
    834     if (_mixerManager.MaxMicrophoneVolume(maxVol) == -1)
    835     {
    836         return -1;
    837     }
    838 
    839     maxVolume = maxVol;
    840 
    841     return 0;
    842 }
    843 
    844 int32_t AudioDeviceLinuxPulse::MinMicrophoneVolume(
    845     uint32_t& minVolume) const
    846 {
    847 
    848     uint32_t minVol(0);
    849 
    850     if (_mixerManager.MinMicrophoneVolume(minVol) == -1)
    851     {
    852         return -1;
    853     }
    854 
    855     minVolume = minVol;
    856 
    857     return 0;
    858 }
    859 
    860 int32_t AudioDeviceLinuxPulse::MicrophoneVolumeStepSize(
    861     uint16_t& stepSize) const
    862 {
    863     RTC_DCHECK(thread_checker_.CalledOnValidThread());
    864     uint16_t delta(0);
    865 
    866     if (_mixerManager.MicrophoneVolumeStepSize(delta) == -1)
    867     {
    868         return -1;
    869     }
    870 
    871     stepSize = delta;
    872 
    873     return 0;
    874 }
    875 
    876 int16_t AudioDeviceLinuxPulse::PlayoutDevices()
    877 {
    878     PaLock();
    879 
    880     pa_operation* paOperation = NULL;
    881     _numPlayDevices = 1; // init to 1 to account for "default"
    882 
    883     // get the whole list of devices and update _numPlayDevices
    884     paOperation = LATE(pa_context_get_sink_info_list)(_paContext,
    885                                                       PaSinkInfoCallback,
    886                                                       this);
    887 
    888     WaitForOperationCompletion(paOperation);
    889 
    890     PaUnLock();
    891 
    892     return _numPlayDevices;
    893 }
    894 
    895 int32_t AudioDeviceLinuxPulse::SetPlayoutDevice(uint16_t index)
    896 {
    897     RTC_DCHECK(thread_checker_.CalledOnValidThread());
    898     if (_playIsInitialized)
    899     {
    900         return -1;
    901     }
    902 
    903     const uint16_t nDevices = PlayoutDevices();
    904 
    905     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
    906                  "  number of availiable output devices is %u", nDevices);
    907 
    908     if (index > (nDevices - 1))
    909     {
    910         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
    911                      "  device index is out of range [0,%u]", (nDevices - 1));
    912         return -1;
    913     }
    914 
    915     _outputDeviceIndex = index;
    916     _outputDeviceIsSpecified = true;
    917 
    918     return 0;
    919 }
    920 
    921 int32_t AudioDeviceLinuxPulse::SetPlayoutDevice(
    922     AudioDeviceModule::WindowsDeviceType /*device*/)
    923 {
    924     WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
    925                  "WindowsDeviceType not supported");
    926     return -1;
    927 }
    928 
    929 int32_t AudioDeviceLinuxPulse::PlayoutDeviceName(
    930     uint16_t index,
    931     char name[kAdmMaxDeviceNameSize],
    932     char guid[kAdmMaxGuidSize])
    933 {
    934     RTC_DCHECK(thread_checker_.CalledOnValidThread());
    935     const uint16_t nDevices = PlayoutDevices();
    936 
    937     if ((index > (nDevices - 1)) || (name == NULL))
    938     {
    939         return -1;
    940     }
    941 
    942     memset(name, 0, kAdmMaxDeviceNameSize);
    943 
    944     if (guid != NULL)
    945     {
    946         memset(guid, 0, kAdmMaxGuidSize);
    947     }
    948 
    949     // Check if default device
    950     if (index == 0)
    951     {
    952         uint16_t deviceIndex = 0;
    953         return GetDefaultDeviceInfo(false, name, deviceIndex);
    954     }
    955 
    956     // Tell the callback that we want
    957     // The name for this device
    958     _playDisplayDeviceName = name;
    959     _deviceIndex = index;
    960 
    961     // get playout devices
    962     PlayoutDevices();
    963 
    964     // clear device name and index
    965     _playDisplayDeviceName = NULL;
    966     _deviceIndex = -1;
    967 
    968     return 0;
    969 }
    970 
    971 int32_t AudioDeviceLinuxPulse::RecordingDeviceName(
    972     uint16_t index,
    973     char name[kAdmMaxDeviceNameSize],
    974     char guid[kAdmMaxGuidSize])
    975 {
    976     RTC_DCHECK(thread_checker_.CalledOnValidThread());
    977     const uint16_t nDevices(RecordingDevices());
    978 
    979     if ((index > (nDevices - 1)) || (name == NULL))
    980     {
    981         return -1;
    982     }
    983 
    984     memset(name, 0, kAdmMaxDeviceNameSize);
    985 
    986     if (guid != NULL)
    987     {
    988         memset(guid, 0, kAdmMaxGuidSize);
    989     }
    990 
    991     // Check if default device
    992     if (index == 0)
    993     {
    994         uint16_t deviceIndex = 0;
    995         return GetDefaultDeviceInfo(true, name, deviceIndex);
    996     }
    997 
    998     // Tell the callback that we want
    999     // the name for this device
   1000     _recDisplayDeviceName = name;
   1001     _deviceIndex = index;
   1002 
   1003     // Get recording devices
   1004     RecordingDevices();
   1005 
   1006     // Clear device name and index
   1007     _recDisplayDeviceName = NULL;
   1008     _deviceIndex = -1;
   1009 
   1010     return 0;
   1011 }
   1012 
   1013 int16_t AudioDeviceLinuxPulse::RecordingDevices()
   1014 {
   1015     PaLock();
   1016 
   1017     pa_operation* paOperation = NULL;
   1018     _numRecDevices = 1; // Init to 1 to account for "default"
   1019 
   1020     // Get the whole list of devices and update _numRecDevices
   1021     paOperation = LATE(pa_context_get_source_info_list)(_paContext,
   1022                                                         PaSourceInfoCallback,
   1023                                                         this);
   1024 
   1025     WaitForOperationCompletion(paOperation);
   1026 
   1027     PaUnLock();
   1028 
   1029     return _numRecDevices;
   1030 }
   1031 
   1032 int32_t AudioDeviceLinuxPulse::SetRecordingDevice(uint16_t index)
   1033 {
   1034     RTC_DCHECK(thread_checker_.CalledOnValidThread());
   1035     if (_recIsInitialized)
   1036     {
   1037         return -1;
   1038     }
   1039 
   1040     const uint16_t nDevices(RecordingDevices());
   1041 
   1042     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
   1043                  "  number of availiable input devices is %u", nDevices);
   1044 
   1045     if (index > (nDevices - 1))
   1046     {
   1047         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   1048                      "  device index is out of range [0,%u]", (nDevices - 1));
   1049         return -1;
   1050     }
   1051 
   1052     _inputDeviceIndex = index;
   1053     _inputDeviceIsSpecified = true;
   1054 
   1055     return 0;
   1056 }
   1057 
   1058 int32_t AudioDeviceLinuxPulse::SetRecordingDevice(
   1059     AudioDeviceModule::WindowsDeviceType /*device*/)
   1060 {
   1061     WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   1062                  "WindowsDeviceType not supported");
   1063     return -1;
   1064 }
   1065 
   1066 int32_t AudioDeviceLinuxPulse::PlayoutIsAvailable(bool& available)
   1067 {
   1068     RTC_DCHECK(thread_checker_.CalledOnValidThread());
   1069     available = false;
   1070 
   1071     // Try to initialize the playout side
   1072     int32_t res = InitPlayout();
   1073 
   1074     // Cancel effect of initialization
   1075     StopPlayout();
   1076 
   1077     if (res != -1)
   1078     {
   1079         available = true;
   1080     }
   1081 
   1082     return res;
   1083 }
   1084 
   1085 int32_t AudioDeviceLinuxPulse::RecordingIsAvailable(bool& available)
   1086 {
   1087     RTC_DCHECK(thread_checker_.CalledOnValidThread());
   1088     available = false;
   1089 
   1090     // Try to initialize the playout side
   1091     int32_t res = InitRecording();
   1092 
   1093     // Cancel effect of initialization
   1094     StopRecording();
   1095 
   1096     if (res != -1)
   1097     {
   1098         available = true;
   1099     }
   1100 
   1101     return res;
   1102 }
   1103 
   1104 int32_t AudioDeviceLinuxPulse::InitPlayout()
   1105 {
   1106     RTC_DCHECK(thread_checker_.CalledOnValidThread());
   1107 
   1108     if (_playing)
   1109     {
   1110         return -1;
   1111     }
   1112 
   1113     if (!_outputDeviceIsSpecified)
   1114     {
   1115         return -1;
   1116     }
   1117 
   1118     if (_playIsInitialized)
   1119     {
   1120         return 0;
   1121     }
   1122 
   1123     // Initialize the speaker (devices might have been added or removed)
   1124     if (InitSpeaker() == -1)
   1125     {
   1126         WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
   1127                      "  InitSpeaker() failed");
   1128     }
   1129 
   1130     // Set the play sample specification
   1131     pa_sample_spec playSampleSpec;
   1132     playSampleSpec.channels = _playChannels;
   1133     playSampleSpec.format = PA_SAMPLE_S16LE;
   1134     playSampleSpec.rate = sample_rate_hz_;
   1135 
   1136     // Create a new play stream
   1137     _playStream = LATE(pa_stream_new)(_paContext, "playStream",
   1138                                       &playSampleSpec, NULL);
   1139 
   1140     if (!_playStream)
   1141     {
   1142         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   1143                      "  failed to create play stream, err=%d",
   1144                      LATE(pa_context_errno)(_paContext));
   1145         return -1;
   1146     }
   1147 
   1148     // Provide the playStream to the mixer
   1149     _mixerManager.SetPlayStream(_playStream);
   1150 
   1151     if (_ptrAudioBuffer)
   1152     {
   1153         // Update audio buffer with the selected parameters
   1154         _ptrAudioBuffer->SetPlayoutSampleRate(sample_rate_hz_);
   1155         _ptrAudioBuffer->SetPlayoutChannels((uint8_t) _playChannels);
   1156     }
   1157 
   1158     WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id,
   1159                  "  stream state %d\n",
   1160                  LATE(pa_stream_get_state)(_playStream));
   1161 
   1162     // Set stream flags
   1163     _playStreamFlags = (pa_stream_flags_t) (PA_STREAM_AUTO_TIMING_UPDATE
   1164         | PA_STREAM_INTERPOLATE_TIMING);
   1165 
   1166     if (_configuredLatencyPlay != WEBRTC_PA_NO_LATENCY_REQUIREMENTS)
   1167     {
   1168         // If configuring a specific latency then we want to specify
   1169         // PA_STREAM_ADJUST_LATENCY to make the server adjust parameters
   1170         // automatically to reach that target latency. However, that flag
   1171         // doesn't exist in Ubuntu 8.04 and many people still use that,
   1172         // so we have to check the protocol version of libpulse.
   1173         if (LATE(pa_context_get_protocol_version)(_paContext)
   1174             >= WEBRTC_PA_ADJUST_LATENCY_PROTOCOL_VERSION)
   1175         {
   1176             _playStreamFlags |= PA_STREAM_ADJUST_LATENCY;
   1177         }
   1178 
   1179         const pa_sample_spec *spec =
   1180             LATE(pa_stream_get_sample_spec)(_playStream);
   1181         if (!spec)
   1182         {
   1183             WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   1184                          "  pa_stream_get_sample_spec()");
   1185             return -1;
   1186         }
   1187 
   1188         size_t bytesPerSec = LATE(pa_bytes_per_second)(spec);
   1189         uint32_t latency = bytesPerSec *
   1190                            WEBRTC_PA_PLAYBACK_LATENCY_MINIMUM_MSECS /
   1191                            WEBRTC_PA_MSECS_PER_SEC;
   1192 
   1193         // Set the play buffer attributes
   1194         _playBufferAttr.maxlength = latency; // num bytes stored in the buffer
   1195         _playBufferAttr.tlength = latency; // target fill level of play buffer
   1196         // minimum free num bytes before server request more data
   1197         _playBufferAttr.minreq = latency / WEBRTC_PA_PLAYBACK_REQUEST_FACTOR;
   1198         // prebuffer tlength before starting playout
   1199         _playBufferAttr.prebuf = _playBufferAttr.tlength -
   1200                                  _playBufferAttr.minreq;
   1201 
   1202         _configuredLatencyPlay = latency;
   1203     }
   1204 
   1205     // num samples in bytes * num channels
   1206     _playbackBufferSize = sample_rate_hz_ / 100 * 2 * _playChannels;
   1207     _playbackBufferUnused = _playbackBufferSize;
   1208     _playBuffer = new int8_t[_playbackBufferSize];
   1209 
   1210     // Enable underflow callback
   1211     LATE(pa_stream_set_underflow_callback)(_playStream,
   1212                                            PaStreamUnderflowCallback, this);
   1213 
   1214     // Set the state callback function for the stream
   1215     LATE(pa_stream_set_state_callback)(_playStream,
   1216                                        PaStreamStateCallback, this);
   1217 
   1218     // Mark playout side as initialized
   1219     _playIsInitialized = true;
   1220     _sndCardPlayDelay = 0;
   1221     _sndCardRecDelay = 0;
   1222 
   1223     return 0;
   1224 }
   1225 
   1226 int32_t AudioDeviceLinuxPulse::InitRecording()
   1227 {
   1228     RTC_DCHECK(thread_checker_.CalledOnValidThread());
   1229 
   1230     if (_recording)
   1231     {
   1232         return -1;
   1233     }
   1234 
   1235     if (!_inputDeviceIsSpecified)
   1236     {
   1237         return -1;
   1238     }
   1239 
   1240     if (_recIsInitialized)
   1241     {
   1242         return 0;
   1243     }
   1244 
   1245     // Initialize the microphone (devices might have been added or removed)
   1246     if (InitMicrophone() == -1)
   1247     {
   1248         WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
   1249                      "  InitMicrophone() failed");
   1250     }
   1251 
   1252     // Set the rec sample specification
   1253     pa_sample_spec recSampleSpec;
   1254     recSampleSpec.channels = _recChannels;
   1255     recSampleSpec.format = PA_SAMPLE_S16LE;
   1256     recSampleSpec.rate = sample_rate_hz_;
   1257 
   1258     // Create a new rec stream
   1259     _recStream = LATE(pa_stream_new)(_paContext, "recStream", &recSampleSpec,
   1260                                      NULL);
   1261     if (!_recStream)
   1262     {
   1263         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   1264                      "  failed to create rec stream, err=%d",
   1265                      LATE(pa_context_errno)(_paContext));
   1266         return -1;
   1267     }
   1268 
   1269     // Provide the recStream to the mixer
   1270     _mixerManager.SetRecStream(_recStream);
   1271 
   1272     if (_ptrAudioBuffer)
   1273     {
   1274         // Update audio buffer with the selected parameters
   1275         _ptrAudioBuffer->SetRecordingSampleRate(sample_rate_hz_);
   1276         _ptrAudioBuffer->SetRecordingChannels((uint8_t) _recChannels);
   1277     }
   1278 
   1279     if (_configuredLatencyRec != WEBRTC_PA_NO_LATENCY_REQUIREMENTS)
   1280     {
   1281         _recStreamFlags = (pa_stream_flags_t) (PA_STREAM_AUTO_TIMING_UPDATE
   1282             | PA_STREAM_INTERPOLATE_TIMING);
   1283 
   1284         // If configuring a specific latency then we want to specify
   1285         // PA_STREAM_ADJUST_LATENCY to make the server adjust parameters
   1286         // automatically to reach that target latency. However, that flag
   1287         // doesn't exist in Ubuntu 8.04 and many people still use that,
   1288         //  so we have to check the protocol version of libpulse.
   1289         if (LATE(pa_context_get_protocol_version)(_paContext)
   1290             >= WEBRTC_PA_ADJUST_LATENCY_PROTOCOL_VERSION)
   1291         {
   1292             _recStreamFlags |= PA_STREAM_ADJUST_LATENCY;
   1293         }
   1294 
   1295         const pa_sample_spec *spec =
   1296             LATE(pa_stream_get_sample_spec)(_recStream);
   1297         if (!spec)
   1298         {
   1299             WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   1300                          "  pa_stream_get_sample_spec(rec)");
   1301             return -1;
   1302         }
   1303 
   1304         size_t bytesPerSec = LATE(pa_bytes_per_second)(spec);
   1305         uint32_t latency = bytesPerSec
   1306             * WEBRTC_PA_LOW_CAPTURE_LATENCY_MSECS / WEBRTC_PA_MSECS_PER_SEC;
   1307 
   1308         // Set the rec buffer attributes
   1309         // Note: fragsize specifies a maximum transfer size, not a minimum, so
   1310         // it is not possible to force a high latency setting, only a low one.
   1311         _recBufferAttr.fragsize = latency; // size of fragment
   1312         _recBufferAttr.maxlength = latency + bytesPerSec
   1313             * WEBRTC_PA_CAPTURE_BUFFER_EXTRA_MSECS / WEBRTC_PA_MSECS_PER_SEC;
   1314 
   1315         _configuredLatencyRec = latency;
   1316     }
   1317 
   1318     _recordBufferSize = sample_rate_hz_ / 100 * 2 * _recChannels;
   1319     _recordBufferUsed = 0;
   1320     _recBuffer = new int8_t[_recordBufferSize];
   1321 
   1322     // Enable overflow callback
   1323     LATE(pa_stream_set_overflow_callback)(_recStream,
   1324                                           PaStreamOverflowCallback,
   1325                                           this);
   1326 
   1327     // Set the state callback function for the stream
   1328     LATE(pa_stream_set_state_callback)(_recStream,
   1329                                        PaStreamStateCallback,
   1330                                        this);
   1331 
   1332     // Mark recording side as initialized
   1333     _recIsInitialized = true;
   1334 
   1335     return 0;
   1336 }
   1337 
   1338 int32_t AudioDeviceLinuxPulse::StartRecording()
   1339 {
   1340     RTC_DCHECK(thread_checker_.CalledOnValidThread());
   1341     if (!_recIsInitialized)
   1342     {
   1343         return -1;
   1344     }
   1345 
   1346     if (_recording)
   1347     {
   1348         return 0;
   1349     }
   1350 
   1351     // Set state to ensure that the recording starts from the audio thread.
   1352     _startRec = true;
   1353 
   1354     // The audio thread will signal when recording has started.
   1355     _timeEventRec.Set();
   1356     if (kEventTimeout == _recStartEvent.Wait(10000))
   1357     {
   1358         {
   1359             CriticalSectionScoped lock(&_critSect);
   1360             _startRec = false;
   1361         }
   1362         StopRecording();
   1363         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   1364                      "  failed to activate recording");
   1365         return -1;
   1366     }
   1367 
   1368     {
   1369         CriticalSectionScoped lock(&_critSect);
   1370         if (_recording)
   1371         {
   1372             // The recording state is set by the audio thread after recording
   1373             // has started.
   1374         } else
   1375         {
   1376             WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   1377                          "  failed to activate recording");
   1378             return -1;
   1379         }
   1380     }
   1381 
   1382     return 0;
   1383 }
   1384 
   1385 int32_t AudioDeviceLinuxPulse::StopRecording()
   1386 {
   1387     RTC_DCHECK(thread_checker_.CalledOnValidThread());
   1388     CriticalSectionScoped lock(&_critSect);
   1389 
   1390     if (!_recIsInitialized)
   1391     {
   1392         return 0;
   1393     }
   1394 
   1395     if (_recStream == NULL)
   1396     {
   1397         return -1;
   1398     }
   1399 
   1400     _recIsInitialized = false;
   1401     _recording = false;
   1402 
   1403     WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id,
   1404                  "  stopping recording");
   1405 
   1406     // Stop Recording
   1407     PaLock();
   1408 
   1409     DisableReadCallback();
   1410     LATE(pa_stream_set_overflow_callback)(_recStream, NULL, NULL);
   1411 
   1412     // Unset this here so that we don't get a TERMINATED callback
   1413     LATE(pa_stream_set_state_callback)(_recStream, NULL, NULL);
   1414 
   1415     if (LATE(pa_stream_get_state)(_recStream) != PA_STREAM_UNCONNECTED)
   1416     {
   1417         // Disconnect the stream
   1418         if (LATE(pa_stream_disconnect)(_recStream) != PA_OK)
   1419         {
   1420             WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   1421                          "  failed to disconnect rec stream, err=%d\n",
   1422                          LATE(pa_context_errno)(_paContext));
   1423             PaUnLock();
   1424             return -1;
   1425         }
   1426 
   1427         WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id,
   1428                      "  disconnected recording");
   1429     }
   1430 
   1431     LATE(pa_stream_unref)(_recStream);
   1432     _recStream = NULL;
   1433 
   1434     PaUnLock();
   1435 
   1436     // Provide the recStream to the mixer
   1437     _mixerManager.SetRecStream(_recStream);
   1438 
   1439     if (_recBuffer)
   1440     {
   1441         delete [] _recBuffer;
   1442         _recBuffer = NULL;
   1443     }
   1444 
   1445     return 0;
   1446 }
   1447 
   1448 bool AudioDeviceLinuxPulse::RecordingIsInitialized() const
   1449 {
   1450     RTC_DCHECK(thread_checker_.CalledOnValidThread());
   1451     return (_recIsInitialized);
   1452 }
   1453 
   1454 bool AudioDeviceLinuxPulse::Recording() const
   1455 {
   1456     RTC_DCHECK(thread_checker_.CalledOnValidThread());
   1457     return (_recording);
   1458 }
   1459 
   1460 bool AudioDeviceLinuxPulse::PlayoutIsInitialized() const
   1461 {
   1462     RTC_DCHECK(thread_checker_.CalledOnValidThread());
   1463     return (_playIsInitialized);
   1464 }
   1465 
   1466 int32_t AudioDeviceLinuxPulse::StartPlayout()
   1467 {
   1468     RTC_DCHECK(thread_checker_.CalledOnValidThread());
   1469 
   1470     if (!_playIsInitialized)
   1471     {
   1472         return -1;
   1473     }
   1474 
   1475     if (_playing)
   1476     {
   1477         return 0;
   1478     }
   1479 
   1480     // Set state to ensure that playout starts from the audio thread.
   1481     {
   1482         CriticalSectionScoped lock(&_critSect);
   1483         _startPlay = true;
   1484     }
   1485 
   1486     // Both |_startPlay| and |_playing| needs protction since they are also
   1487     // accessed on the playout thread.
   1488 
   1489     // The audio thread will signal when playout has started.
   1490     _timeEventPlay.Set();
   1491     if (kEventTimeout == _playStartEvent.Wait(10000))
   1492     {
   1493         {
   1494             CriticalSectionScoped lock(&_critSect);
   1495             _startPlay = false;
   1496         }
   1497         StopPlayout();
   1498         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   1499                      "  failed to activate playout");
   1500         return -1;
   1501     }
   1502 
   1503     {
   1504         CriticalSectionScoped lock(&_critSect);
   1505         if (_playing)
   1506         {
   1507             // The playing state is set by the audio thread after playout
   1508             // has started.
   1509         } else
   1510         {
   1511             WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   1512                          "  failed to activate playing");
   1513             return -1;
   1514         }
   1515     }
   1516 
   1517     return 0;
   1518 }
   1519 
   1520 int32_t AudioDeviceLinuxPulse::StopPlayout()
   1521 {
   1522     RTC_DCHECK(thread_checker_.CalledOnValidThread());
   1523     CriticalSectionScoped lock(&_critSect);
   1524 
   1525     if (!_playIsInitialized)
   1526     {
   1527         return 0;
   1528     }
   1529 
   1530     if (_playStream == NULL)
   1531     {
   1532         return -1;
   1533     }
   1534 
   1535     _playIsInitialized = false;
   1536     _playing = false;
   1537     _sndCardPlayDelay = 0;
   1538     _sndCardRecDelay = 0;
   1539 
   1540     WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id,
   1541                  "  stopping playback");
   1542 
   1543     // Stop Playout
   1544     PaLock();
   1545 
   1546     DisableWriteCallback();
   1547     LATE(pa_stream_set_underflow_callback)(_playStream, NULL, NULL);
   1548 
   1549     // Unset this here so that we don't get a TERMINATED callback
   1550     LATE(pa_stream_set_state_callback)(_playStream, NULL, NULL);
   1551 
   1552     if (LATE(pa_stream_get_state)(_playStream) != PA_STREAM_UNCONNECTED)
   1553     {
   1554         // Disconnect the stream
   1555         if (LATE(pa_stream_disconnect)(_playStream) != PA_OK)
   1556         {
   1557             WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   1558                          "  failed to disconnect play stream, err=%d",
   1559                          LATE(pa_context_errno)(_paContext));
   1560             PaUnLock();
   1561             return -1;
   1562         }
   1563 
   1564         WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id,
   1565                      "  disconnected playback");
   1566     }
   1567 
   1568     LATE(pa_stream_unref)(_playStream);
   1569     _playStream = NULL;
   1570 
   1571     PaUnLock();
   1572 
   1573     // Provide the playStream to the mixer
   1574     _mixerManager.SetPlayStream(_playStream);
   1575 
   1576     if (_playBuffer)
   1577     {
   1578         delete [] _playBuffer;
   1579         _playBuffer = NULL;
   1580     }
   1581 
   1582     return 0;
   1583 }
   1584 
   1585 int32_t AudioDeviceLinuxPulse::PlayoutDelay(uint16_t& delayMS) const
   1586 {
   1587     CriticalSectionScoped lock(&_critSect);
   1588     delayMS = (uint16_t) _sndCardPlayDelay;
   1589     return 0;
   1590 }
   1591 
   1592 int32_t AudioDeviceLinuxPulse::RecordingDelay(uint16_t& delayMS) const
   1593 {
   1594     RTC_DCHECK(thread_checker_.CalledOnValidThread());
   1595     delayMS = (uint16_t) _sndCardRecDelay;
   1596     return 0;
   1597 }
   1598 
   1599 bool AudioDeviceLinuxPulse::Playing() const
   1600 {
   1601     RTC_DCHECK(thread_checker_.CalledOnValidThread());
   1602     return (_playing);
   1603 }
   1604 
   1605 int32_t AudioDeviceLinuxPulse::SetPlayoutBuffer(
   1606     const AudioDeviceModule::BufferType type,
   1607     uint16_t sizeMS)
   1608 {
   1609     RTC_DCHECK(thread_checker_.CalledOnValidThread());
   1610     if (type != AudioDeviceModule::kFixedBufferSize)
   1611     {
   1612         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   1613                      " Adaptive buffer size not supported on this platform");
   1614         return -1;
   1615     }
   1616 
   1617     _playBufType = type;
   1618     _playBufDelayFixed = sizeMS;
   1619 
   1620     return 0;
   1621 }
   1622 
   1623 int32_t AudioDeviceLinuxPulse::PlayoutBuffer(
   1624     AudioDeviceModule::BufferType& type,
   1625     uint16_t& sizeMS) const
   1626 {
   1627     RTC_DCHECK(thread_checker_.CalledOnValidThread());
   1628     type = _playBufType;
   1629     sizeMS = _playBufDelayFixed;
   1630 
   1631     return 0;
   1632 }
   1633 
   1634 int32_t AudioDeviceLinuxPulse::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 AudioDeviceLinuxPulse::PlayoutWarning() const
   1643 {
   1644   CriticalSectionScoped lock(&_critSect);
   1645   return (_playWarning > 0);
   1646 }
   1647 
   1648 bool AudioDeviceLinuxPulse::PlayoutError() const
   1649 {
   1650   CriticalSectionScoped lock(&_critSect);
   1651   return (_playError > 0);
   1652 }
   1653 
   1654 bool AudioDeviceLinuxPulse::RecordingWarning() const
   1655 {
   1656   CriticalSectionScoped lock(&_critSect);
   1657   return (_recWarning > 0);
   1658 }
   1659 
   1660 bool AudioDeviceLinuxPulse::RecordingError() const
   1661 {
   1662   CriticalSectionScoped lock(&_critSect);
   1663   return (_recError > 0);
   1664 }
   1665 
   1666 void AudioDeviceLinuxPulse::ClearPlayoutWarning()
   1667 {
   1668   CriticalSectionScoped lock(&_critSect);
   1669   _playWarning = 0;
   1670 }
   1671 
   1672 void AudioDeviceLinuxPulse::ClearPlayoutError()
   1673 {
   1674   CriticalSectionScoped lock(&_critSect);
   1675   _playError = 0;
   1676 }
   1677 
   1678 void AudioDeviceLinuxPulse::ClearRecordingWarning()
   1679 {
   1680   CriticalSectionScoped lock(&_critSect);
   1681   _recWarning = 0;
   1682 }
   1683 
   1684 void AudioDeviceLinuxPulse::ClearRecordingError()
   1685 {
   1686   CriticalSectionScoped lock(&_critSect);
   1687   _recError = 0;
   1688 }
   1689 
   1690 // ============================================================================
   1691 //                                 Private Methods
   1692 // ============================================================================
   1693 
   1694 void AudioDeviceLinuxPulse::PaContextStateCallback(pa_context *c, void *pThis)
   1695 {
   1696     static_cast<AudioDeviceLinuxPulse*> (pThis)->
   1697         PaContextStateCallbackHandler(c);
   1698 }
   1699 
   1700 // ----------------------------------------------------------------------------
   1701 //  PaSinkInfoCallback
   1702 // ----------------------------------------------------------------------------
   1703 
   1704 void AudioDeviceLinuxPulse::PaSinkInfoCallback(pa_context */*c*/,
   1705                                                const pa_sink_info *i, int eol,
   1706                                                void *pThis)
   1707 {
   1708     static_cast<AudioDeviceLinuxPulse*> (pThis)->PaSinkInfoCallbackHandler(
   1709         i, eol);
   1710 }
   1711 
   1712 void AudioDeviceLinuxPulse::PaSourceInfoCallback(pa_context */*c*/,
   1713                                                  const pa_source_info *i,
   1714                                                  int eol, void *pThis)
   1715 {
   1716     static_cast<AudioDeviceLinuxPulse*> (pThis)->PaSourceInfoCallbackHandler(
   1717         i, eol);
   1718 }
   1719 
   1720 void AudioDeviceLinuxPulse::PaServerInfoCallback(pa_context */*c*/,
   1721                                                  const pa_server_info *i,
   1722                                                  void *pThis)
   1723 {
   1724     static_cast<AudioDeviceLinuxPulse*> (pThis)->
   1725         PaServerInfoCallbackHandler(i);
   1726 }
   1727 
   1728 void AudioDeviceLinuxPulse::PaStreamStateCallback(pa_stream *p, void *pThis)
   1729 {
   1730     static_cast<AudioDeviceLinuxPulse*> (pThis)->
   1731         PaStreamStateCallbackHandler(p);
   1732 }
   1733 
   1734 void AudioDeviceLinuxPulse::PaContextStateCallbackHandler(pa_context *c)
   1735 {
   1736     WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id,
   1737                  "  context state cb");
   1738 
   1739     pa_context_state_t state = LATE(pa_context_get_state)(c);
   1740     switch (state)
   1741     {
   1742         case PA_CONTEXT_UNCONNECTED:
   1743             WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id,
   1744                          "  unconnected");
   1745             break;
   1746         case PA_CONTEXT_CONNECTING:
   1747         case PA_CONTEXT_AUTHORIZING:
   1748         case PA_CONTEXT_SETTING_NAME:
   1749             WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id,
   1750                          "  no state");
   1751             break;
   1752         case PA_CONTEXT_FAILED:
   1753         case PA_CONTEXT_TERMINATED:
   1754             WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id,
   1755                          "  failed");
   1756             _paStateChanged = true;
   1757             LATE(pa_threaded_mainloop_signal)(_paMainloop, 0);
   1758             break;
   1759         case PA_CONTEXT_READY:
   1760             WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id,
   1761                          "  ready");
   1762             _paStateChanged = true;
   1763             LATE(pa_threaded_mainloop_signal)(_paMainloop, 0);
   1764             break;
   1765     }
   1766 }
   1767 
   1768 void AudioDeviceLinuxPulse::PaSinkInfoCallbackHandler(const pa_sink_info *i,
   1769                                                       int eol)
   1770 {
   1771     if (eol)
   1772     {
   1773         // Signal that we are done
   1774         LATE(pa_threaded_mainloop_signal)(_paMainloop, 0);
   1775         return;
   1776     }
   1777 
   1778     if (_numPlayDevices == _deviceIndex)
   1779     {
   1780         // Convert the device index to the one of the sink
   1781         _paDeviceIndex = i->index;
   1782 
   1783         if (_playDeviceName)
   1784         {
   1785             // Copy the sink name
   1786             strncpy(_playDeviceName, i->name, kAdmMaxDeviceNameSize);
   1787             _playDeviceName[kAdmMaxDeviceNameSize - 1] = '\0';
   1788         }
   1789         if (_playDisplayDeviceName)
   1790         {
   1791             // Copy the sink display name
   1792             strncpy(_playDisplayDeviceName, i->description,
   1793                     kAdmMaxDeviceNameSize);
   1794             _playDisplayDeviceName[kAdmMaxDeviceNameSize - 1] = '\0';
   1795         }
   1796     }
   1797 
   1798     _numPlayDevices++;
   1799 }
   1800 
   1801 void AudioDeviceLinuxPulse::PaSourceInfoCallbackHandler(
   1802     const pa_source_info *i,
   1803     int eol)
   1804 {
   1805     if (eol)
   1806     {
   1807         // Signal that we are done
   1808         LATE(pa_threaded_mainloop_signal)(_paMainloop, 0);
   1809         return;
   1810     }
   1811 
   1812     // We don't want to list output devices
   1813      if (i->monitor_of_sink == PA_INVALID_INDEX)
   1814     {
   1815         if (_numRecDevices == _deviceIndex)
   1816         {
   1817             // Convert the device index to the one of the source
   1818             _paDeviceIndex = i->index;
   1819 
   1820             if (_recDeviceName)
   1821             {
   1822                 // copy the source name
   1823                 strncpy(_recDeviceName, i->name, kAdmMaxDeviceNameSize);
   1824                 _recDeviceName[kAdmMaxDeviceNameSize - 1] = '\0';
   1825             }
   1826             if (_recDisplayDeviceName)
   1827             {
   1828                 // Copy the source display name
   1829                 strncpy(_recDisplayDeviceName, i->description,
   1830                         kAdmMaxDeviceNameSize);
   1831                 _recDisplayDeviceName[kAdmMaxDeviceNameSize - 1] = '\0';
   1832             }
   1833         }
   1834 
   1835         _numRecDevices++;
   1836     }
   1837 }
   1838 
   1839 void AudioDeviceLinuxPulse::PaServerInfoCallbackHandler(
   1840     const pa_server_info *i)
   1841 {
   1842     // Use PA native sampling rate
   1843     sample_rate_hz_ = i->sample_spec.rate;
   1844 
   1845     // Copy the PA server version
   1846     strncpy(_paServerVersion, i->server_version, 31);
   1847     _paServerVersion[31] = '\0';
   1848 
   1849     if (_recDisplayDeviceName)
   1850     {
   1851         // Copy the source name
   1852         strncpy(_recDisplayDeviceName, i->default_source_name,
   1853                 kAdmMaxDeviceNameSize);
   1854         _recDisplayDeviceName[kAdmMaxDeviceNameSize - 1] = '\0';
   1855     }
   1856 
   1857     if (_playDisplayDeviceName)
   1858     {
   1859         // Copy the sink name
   1860         strncpy(_playDisplayDeviceName, i->default_sink_name,
   1861                 kAdmMaxDeviceNameSize);
   1862         _playDisplayDeviceName[kAdmMaxDeviceNameSize - 1] = '\0';
   1863     }
   1864 
   1865     LATE(pa_threaded_mainloop_signal)(_paMainloop, 0);
   1866 }
   1867 
   1868 void AudioDeviceLinuxPulse::PaStreamStateCallbackHandler(pa_stream *p)
   1869 {
   1870     WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id,
   1871                  "  stream state cb");
   1872 
   1873     pa_stream_state_t state = LATE(pa_stream_get_state)(p);
   1874     switch (state)
   1875     {
   1876         case PA_STREAM_UNCONNECTED:
   1877             WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id,
   1878                          "  unconnected");
   1879             break;
   1880         case PA_STREAM_CREATING:
   1881             WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id,
   1882                          "  creating");
   1883             break;
   1884         case PA_STREAM_FAILED:
   1885         case PA_STREAM_TERMINATED:
   1886             WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id,
   1887                          "  failed");
   1888             break;
   1889         case PA_STREAM_READY:
   1890             WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id,
   1891                          "  ready");
   1892             break;
   1893     }
   1894 
   1895     LATE(pa_threaded_mainloop_signal)(_paMainloop, 0);
   1896 }
   1897 
   1898 int32_t AudioDeviceLinuxPulse::CheckPulseAudioVersion()
   1899 {
   1900     PaLock();
   1901 
   1902     pa_operation* paOperation = NULL;
   1903 
   1904     // get the server info and update deviceName
   1905     paOperation = LATE(pa_context_get_server_info)(_paContext,
   1906                                                    PaServerInfoCallback,
   1907                                                    this);
   1908 
   1909     WaitForOperationCompletion(paOperation);
   1910 
   1911     PaUnLock();
   1912 
   1913     WEBRTC_TRACE(kTraceStateInfo, kTraceAudioDevice, -1,
   1914                  "  checking PulseAudio version: %s", _paServerVersion);
   1915 
   1916     return 0;
   1917 }
   1918 
   1919 int32_t AudioDeviceLinuxPulse::InitSamplingFrequency()
   1920 {
   1921     PaLock();
   1922 
   1923     pa_operation* paOperation = NULL;
   1924 
   1925     // Get the server info and update sample_rate_hz_
   1926     paOperation = LATE(pa_context_get_server_info)(_paContext,
   1927                                                    PaServerInfoCallback,
   1928                                                    this);
   1929 
   1930     WaitForOperationCompletion(paOperation);
   1931 
   1932     PaUnLock();
   1933 
   1934     return 0;
   1935 }
   1936 
   1937 int32_t AudioDeviceLinuxPulse::GetDefaultDeviceInfo(bool recDevice,
   1938                                                     char* name,
   1939                                                     uint16_t& index)
   1940 {
   1941     char tmpName[kAdmMaxDeviceNameSize] = {0};
   1942     // subtract length of "default: "
   1943     uint16_t nameLen = kAdmMaxDeviceNameSize - 9;
   1944     char* pName = NULL;
   1945 
   1946     if (name)
   1947     {
   1948         // Add "default: "
   1949         strcpy(name, "default: ");
   1950         pName = &name[9];
   1951     }
   1952 
   1953     // Tell the callback that we want
   1954     // the name for this device
   1955     if (recDevice)
   1956     {
   1957         _recDisplayDeviceName = tmpName;
   1958     } else
   1959     {
   1960         _playDisplayDeviceName = tmpName;
   1961     }
   1962 
   1963     // Set members
   1964     _paDeviceIndex = -1;
   1965     _deviceIndex = 0;
   1966     _numPlayDevices = 0;
   1967     _numRecDevices = 0;
   1968 
   1969     PaLock();
   1970 
   1971     pa_operation* paOperation = NULL;
   1972 
   1973     // Get the server info and update deviceName
   1974     paOperation = LATE(pa_context_get_server_info)(_paContext,
   1975                                                    PaServerInfoCallback,
   1976                                                    this);
   1977 
   1978     WaitForOperationCompletion(paOperation);
   1979 
   1980     // Get the device index
   1981     if (recDevice)
   1982     {
   1983         paOperation
   1984             = LATE(pa_context_get_source_info_by_name)(_paContext,
   1985                                                        (char *) tmpName,
   1986                                                        PaSourceInfoCallback,
   1987                                                        this);
   1988     } else
   1989     {
   1990         paOperation
   1991             = LATE(pa_context_get_sink_info_by_name)(_paContext,
   1992                                                      (char *) tmpName,
   1993                                                      PaSinkInfoCallback,
   1994                                                      this);
   1995     }
   1996 
   1997     WaitForOperationCompletion(paOperation);
   1998 
   1999     PaUnLock();
   2000 
   2001     // Set the index
   2002     index = _paDeviceIndex;
   2003 
   2004     if (name)
   2005     {
   2006         // Copy to name string
   2007         strncpy(pName, tmpName, nameLen);
   2008     }
   2009 
   2010     // Clear members
   2011     _playDisplayDeviceName = NULL;
   2012     _recDisplayDeviceName = NULL;
   2013     _paDeviceIndex = -1;
   2014     _deviceIndex = -1;
   2015     _numPlayDevices = 0;
   2016     _numRecDevices = 0;
   2017 
   2018     return 0;
   2019 }
   2020 
   2021 int32_t AudioDeviceLinuxPulse::InitPulseAudio()
   2022 {
   2023     int retVal = 0;
   2024 
   2025     // Load libpulse
   2026     if (!PaSymbolTable.Load())
   2027     {
   2028         // Most likely the Pulse library and sound server are not installed on
   2029         // this system
   2030         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   2031                      "  failed to load symbol table");
   2032         return -1;
   2033     }
   2034 
   2035     // Create a mainloop API and connection to the default server
   2036     // the mainloop is the internal asynchronous API event loop
   2037     if (_paMainloop) {
   2038         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   2039                      "  PA mainloop has already existed");
   2040         return -1;
   2041     }
   2042     _paMainloop = LATE(pa_threaded_mainloop_new)();
   2043     if (!_paMainloop)
   2044     {
   2045         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   2046                      "  could not create mainloop");
   2047         return -1;
   2048     }
   2049 
   2050     // Start the threaded main loop
   2051     retVal = LATE(pa_threaded_mainloop_start)(_paMainloop);
   2052     if (retVal != PA_OK)
   2053     {
   2054         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   2055                      "  failed to start main loop, error=%d", retVal);
   2056         return -1;
   2057     }
   2058 
   2059     WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id,
   2060                  "  mainloop running!");
   2061 
   2062     PaLock();
   2063 
   2064     _paMainloopApi = LATE(pa_threaded_mainloop_get_api)(_paMainloop);
   2065     if (!_paMainloopApi)
   2066     {
   2067         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   2068                      "  could not create mainloop API");
   2069         PaUnLock();
   2070         return -1;
   2071     }
   2072 
   2073     // Create a new PulseAudio context
   2074     if (_paContext){
   2075         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   2076                      "  PA context has already existed");
   2077         PaUnLock();
   2078         return -1;
   2079     }
   2080     _paContext = LATE(pa_context_new)(_paMainloopApi, "WEBRTC VoiceEngine");
   2081 
   2082     if (!_paContext)
   2083     {
   2084         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   2085                      "  could not create context");
   2086         PaUnLock();
   2087         return -1;
   2088     }
   2089 
   2090     // Set state callback function
   2091     LATE(pa_context_set_state_callback)(_paContext, PaContextStateCallback,
   2092                                         this);
   2093 
   2094     // Connect the context to a server (default)
   2095     _paStateChanged = false;
   2096     retVal = LATE(pa_context_connect)(_paContext,
   2097                                       NULL,
   2098                                       PA_CONTEXT_NOAUTOSPAWN,
   2099                                       NULL);
   2100 
   2101     if (retVal != PA_OK)
   2102     {
   2103         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   2104                      "  failed to connect context, error=%d", retVal);
   2105         PaUnLock();
   2106         return -1;
   2107     }
   2108 
   2109     // Wait for state change
   2110     while (!_paStateChanged)
   2111     {
   2112         LATE(pa_threaded_mainloop_wait)(_paMainloop);
   2113     }
   2114 
   2115     // Now check to see what final state we reached.
   2116     pa_context_state_t state = LATE(pa_context_get_state)(_paContext);
   2117 
   2118     if (state != PA_CONTEXT_READY)
   2119     {
   2120         if (state == PA_CONTEXT_FAILED)
   2121         {
   2122             WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   2123                          "  failed to connect to PulseAudio sound server");
   2124         } else if (state == PA_CONTEXT_TERMINATED)
   2125         {
   2126             WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   2127                          "  PulseAudio connection terminated early");
   2128         } else
   2129         {
   2130             // Shouldn't happen, because we only signal on one of those three
   2131             // states
   2132             WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   2133                          "  unknown problem connecting to PulseAudio");
   2134         }
   2135         PaUnLock();
   2136         return -1;
   2137     }
   2138 
   2139     PaUnLock();
   2140 
   2141     // Give the objects to the mixer manager
   2142     _mixerManager.SetPulseAudioObjects(_paMainloop, _paContext);
   2143 
   2144     // Check the version
   2145     if (CheckPulseAudioVersion() < 0)
   2146     {
   2147         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   2148                      "  PulseAudio version %s not supported",
   2149                      _paServerVersion);
   2150         return -1;
   2151     }
   2152 
   2153     // Initialize sampling frequency
   2154     if (InitSamplingFrequency() < 0 || sample_rate_hz_ == 0)
   2155     {
   2156         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   2157                      "  failed to initialize sampling frequency,"
   2158                      " set to %d Hz",
   2159                      sample_rate_hz_);
   2160         return -1;
   2161     }
   2162 
   2163     return 0;
   2164 }
   2165 
   2166 int32_t AudioDeviceLinuxPulse::TerminatePulseAudio()
   2167 {
   2168     // Do nothing if the instance doesn't exist
   2169     // likely PaSymbolTable.Load() fails
   2170     if (!_paMainloop) {
   2171         return 0;
   2172     }
   2173 
   2174     PaLock();
   2175 
   2176     // Disconnect the context
   2177     if (_paContext)
   2178     {
   2179         LATE(pa_context_disconnect)(_paContext);
   2180     }
   2181 
   2182     // Unreference the context
   2183     if (_paContext)
   2184     {
   2185         LATE(pa_context_unref)(_paContext);
   2186     }
   2187 
   2188     PaUnLock();
   2189     _paContext = NULL;
   2190 
   2191     // Stop the threaded main loop
   2192     if (_paMainloop)
   2193     {
   2194         LATE(pa_threaded_mainloop_stop)(_paMainloop);
   2195     }
   2196 
   2197     // Free the mainloop
   2198     if (_paMainloop)
   2199     {
   2200         LATE(pa_threaded_mainloop_free)(_paMainloop);
   2201     }
   2202 
   2203     _paMainloop = NULL;
   2204 
   2205     WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id,
   2206                  "  PulseAudio terminated");
   2207 
   2208     return 0;
   2209 }
   2210 
   2211 void AudioDeviceLinuxPulse::PaLock()
   2212 {
   2213     LATE(pa_threaded_mainloop_lock)(_paMainloop);
   2214 }
   2215 
   2216 void AudioDeviceLinuxPulse::PaUnLock()
   2217 {
   2218     LATE(pa_threaded_mainloop_unlock)(_paMainloop);
   2219 }
   2220 
   2221 void AudioDeviceLinuxPulse::WaitForOperationCompletion(
   2222     pa_operation* paOperation) const
   2223 {
   2224     if (!paOperation)
   2225     {
   2226         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   2227                      "paOperation NULL in WaitForOperationCompletion");
   2228         return;
   2229     }
   2230 
   2231     while (LATE(pa_operation_get_state)(paOperation) == PA_OPERATION_RUNNING)
   2232     {
   2233         LATE(pa_threaded_mainloop_wait)(_paMainloop);
   2234     }
   2235 
   2236     LATE(pa_operation_unref)(paOperation);
   2237 }
   2238 
   2239 // ============================================================================
   2240 //                                  Thread Methods
   2241 // ============================================================================
   2242 
   2243 void AudioDeviceLinuxPulse::EnableWriteCallback()
   2244 {
   2245     if (LATE(pa_stream_get_state)(_playStream) == PA_STREAM_READY)
   2246     {
   2247         // May already have available space. Must check.
   2248         _tempBufferSpace = LATE(pa_stream_writable_size)(_playStream);
   2249         if (_tempBufferSpace > 0)
   2250         {
   2251             // Yup, there is already space available, so if we register a
   2252             // write callback then it will not receive any event. So dispatch
   2253             // one ourself instead.
   2254             _timeEventPlay.Set();
   2255             return;
   2256         }
   2257     }
   2258 
   2259     LATE(pa_stream_set_write_callback)(_playStream, &PaStreamWriteCallback,
   2260                                        this);
   2261 }
   2262 
   2263 void AudioDeviceLinuxPulse::DisableWriteCallback()
   2264 {
   2265     LATE(pa_stream_set_write_callback)(_playStream, NULL, NULL);
   2266 }
   2267 
   2268 void AudioDeviceLinuxPulse::PaStreamWriteCallback(pa_stream */*unused*/,
   2269                                                   size_t buffer_space,
   2270                                                   void *pThis)
   2271 {
   2272     static_cast<AudioDeviceLinuxPulse*> (pThis)->PaStreamWriteCallbackHandler(
   2273         buffer_space);
   2274 }
   2275 
   2276 void AudioDeviceLinuxPulse::PaStreamWriteCallbackHandler(size_t bufferSpace)
   2277 {
   2278     _tempBufferSpace = bufferSpace;
   2279 
   2280     // Since we write the data asynchronously on a different thread, we have
   2281     // to temporarily disable the write callback or else Pulse will call it
   2282     // continuously until we write the data. We re-enable it below.
   2283     DisableWriteCallback();
   2284     _timeEventPlay.Set();
   2285 }
   2286 
   2287 void AudioDeviceLinuxPulse::PaStreamUnderflowCallback(pa_stream */*unused*/,
   2288                                                       void *pThis)
   2289 {
   2290     static_cast<AudioDeviceLinuxPulse*> (pThis)->
   2291         PaStreamUnderflowCallbackHandler();
   2292 }
   2293 
   2294 void AudioDeviceLinuxPulse::PaStreamUnderflowCallbackHandler()
   2295 {
   2296     WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
   2297                  "  Playout underflow");
   2298 
   2299     if (_configuredLatencyPlay == WEBRTC_PA_NO_LATENCY_REQUIREMENTS)
   2300     {
   2301         // We didn't configure a pa_buffer_attr before, so switching to
   2302         // one now would be questionable.
   2303         return;
   2304     }
   2305 
   2306     // Otherwise reconfigure the stream with a higher target latency.
   2307 
   2308     const pa_sample_spec *spec = LATE(pa_stream_get_sample_spec)(_playStream);
   2309     if (!spec)
   2310     {
   2311         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   2312                      "  pa_stream_get_sample_spec()");
   2313         return;
   2314     }
   2315 
   2316     size_t bytesPerSec = LATE(pa_bytes_per_second)(spec);
   2317     uint32_t newLatency = _configuredLatencyPlay + bytesPerSec *
   2318                           WEBRTC_PA_PLAYBACK_LATENCY_INCREMENT_MSECS /
   2319                           WEBRTC_PA_MSECS_PER_SEC;
   2320 
   2321     // Set the play buffer attributes
   2322     _playBufferAttr.maxlength = newLatency;
   2323     _playBufferAttr.tlength = newLatency;
   2324     _playBufferAttr.minreq = newLatency / WEBRTC_PA_PLAYBACK_REQUEST_FACTOR;
   2325     _playBufferAttr.prebuf = _playBufferAttr.tlength - _playBufferAttr.minreq;
   2326 
   2327     pa_operation *op = LATE(pa_stream_set_buffer_attr)(_playStream,
   2328                                                        &_playBufferAttr, NULL,
   2329                                                        NULL);
   2330     if (!op)
   2331     {
   2332         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   2333                      "  pa_stream_set_buffer_attr()");
   2334         return;
   2335     }
   2336 
   2337     // Don't need to wait for this to complete.
   2338     LATE(pa_operation_unref)(op);
   2339 
   2340     // Save the new latency in case we underflow again.
   2341     _configuredLatencyPlay = newLatency;
   2342 }
   2343 
   2344 void AudioDeviceLinuxPulse::EnableReadCallback()
   2345 {
   2346     LATE(pa_stream_set_read_callback)(_recStream,
   2347                                       &PaStreamReadCallback,
   2348                                       this);
   2349 }
   2350 
   2351 void AudioDeviceLinuxPulse::DisableReadCallback()
   2352 {
   2353     LATE(pa_stream_set_read_callback)(_recStream, NULL, NULL);
   2354 }
   2355 
   2356 void AudioDeviceLinuxPulse::PaStreamReadCallback(pa_stream */*unused1*/,
   2357                                                  size_t /*unused2*/,
   2358                                                  void *pThis)
   2359 {
   2360     static_cast<AudioDeviceLinuxPulse*> (pThis)->
   2361         PaStreamReadCallbackHandler();
   2362 }
   2363 
   2364 void AudioDeviceLinuxPulse::PaStreamReadCallbackHandler()
   2365 {
   2366     // We get the data pointer and size now in order to save one Lock/Unlock
   2367     // in the worker thread.
   2368     if (LATE(pa_stream_peek)(_recStream,
   2369                              &_tempSampleData,
   2370                              &_tempSampleDataSize) != 0)
   2371     {
   2372         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   2373                      "  Can't read data!");
   2374         return;
   2375     }
   2376 
   2377     // Since we consume the data asynchronously on a different thread, we have
   2378     // to temporarily disable the read callback or else Pulse will call it
   2379     // continuously until we consume the data. We re-enable it below.
   2380     DisableReadCallback();
   2381     _timeEventRec.Set();
   2382 }
   2383 
   2384 void AudioDeviceLinuxPulse::PaStreamOverflowCallback(pa_stream */*unused*/,
   2385                                                      void *pThis)
   2386 {
   2387     static_cast<AudioDeviceLinuxPulse*> (pThis)->
   2388         PaStreamOverflowCallbackHandler();
   2389 }
   2390 
   2391 void AudioDeviceLinuxPulse::PaStreamOverflowCallbackHandler()
   2392 {
   2393     WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
   2394                  "  Recording overflow");
   2395 }
   2396 
   2397 int32_t AudioDeviceLinuxPulse::LatencyUsecs(pa_stream *stream)
   2398 {
   2399     if (!WEBRTC_PA_REPORT_LATENCY)
   2400     {
   2401         return 0;
   2402     }
   2403 
   2404     if (!stream)
   2405     {
   2406         return 0;
   2407     }
   2408 
   2409     pa_usec_t latency;
   2410     int negative;
   2411     if (LATE(pa_stream_get_latency)(stream, &latency, &negative) != 0)
   2412     {
   2413         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   2414                      "  Can't query latency");
   2415         // We'd rather continue playout/capture with an incorrect delay than
   2416         // stop it altogether, so return a valid value.
   2417         return 0;
   2418     }
   2419 
   2420     if (negative)
   2421     {
   2422         WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id,
   2423                      "  warning: pa_stream_get_latency reported negative "
   2424                      "delay");
   2425 
   2426         // The delay can be negative for monitoring streams if the captured
   2427         // samples haven't been played yet. In such a case, "latency"
   2428         // contains the magnitude, so we must negate it to get the real value.
   2429         int32_t tmpLatency = (int32_t) -latency;
   2430         if (tmpLatency < 0)
   2431         {
   2432             // Make sure that we don't use a negative delay.
   2433             tmpLatency = 0;
   2434         }
   2435 
   2436         return tmpLatency;
   2437     } else
   2438     {
   2439         return (int32_t) latency;
   2440     }
   2441 }
   2442 
   2443 int32_t AudioDeviceLinuxPulse::ReadRecordedData(
   2444     const void* bufferData,
   2445     size_t bufferSize)  EXCLUSIVE_LOCKS_REQUIRED(_critSect)
   2446 {
   2447     size_t size = bufferSize;
   2448     uint32_t numRecSamples = _recordBufferSize / (2 * _recChannels);
   2449 
   2450     // Account for the peeked data and the used data.
   2451     uint32_t recDelay = (uint32_t) ((LatencyUsecs(_recStream)
   2452         / 1000) + 10 * ((size + _recordBufferUsed) / _recordBufferSize));
   2453 
   2454     _sndCardRecDelay = recDelay;
   2455 
   2456     if (_playStream)
   2457     {
   2458         // Get the playout delay.
   2459         _sndCardPlayDelay = (uint32_t) (LatencyUsecs(_playStream) / 1000);
   2460     }
   2461 
   2462     if (_recordBufferUsed > 0)
   2463     {
   2464         // Have to copy to the buffer until it is full.
   2465         size_t copy = _recordBufferSize - _recordBufferUsed;
   2466         if (size < copy)
   2467         {
   2468             copy = size;
   2469         }
   2470 
   2471         memcpy(&_recBuffer[_recordBufferUsed], bufferData, copy);
   2472         _recordBufferUsed += copy;
   2473         bufferData = static_cast<const char *> (bufferData) + copy;
   2474         size -= copy;
   2475 
   2476         if (_recordBufferUsed != _recordBufferSize)
   2477         {
   2478             // Not enough data yet to pass to VoE.
   2479             return 0;
   2480         }
   2481 
   2482         // Provide data to VoiceEngine.
   2483         if (ProcessRecordedData(_recBuffer, numRecSamples, recDelay) == -1)
   2484         {
   2485             // We have stopped recording.
   2486             return -1;
   2487         }
   2488 
   2489         _recordBufferUsed = 0;
   2490     }
   2491 
   2492     // Now process full 10ms sample sets directly from the input.
   2493     while (size >= _recordBufferSize)
   2494     {
   2495         // Provide data to VoiceEngine.
   2496         if (ProcessRecordedData(
   2497             static_cast<int8_t *> (const_cast<void *> (bufferData)),
   2498             numRecSamples, recDelay) == -1)
   2499         {
   2500             // We have stopped recording.
   2501             return -1;
   2502         }
   2503 
   2504         bufferData = static_cast<const char *> (bufferData) +
   2505                      _recordBufferSize;
   2506         size -= _recordBufferSize;
   2507 
   2508         // We have consumed 10ms of data.
   2509         recDelay -= 10;
   2510     }
   2511 
   2512     // Now save any leftovers for later.
   2513     if (size > 0)
   2514     {
   2515         memcpy(_recBuffer, bufferData, size);
   2516         _recordBufferUsed = size;
   2517     }
   2518 
   2519     return 0;
   2520 }
   2521 
   2522 int32_t AudioDeviceLinuxPulse::ProcessRecordedData(
   2523     int8_t *bufferData,
   2524     uint32_t bufferSizeInSamples,
   2525     uint32_t recDelay) EXCLUSIVE_LOCKS_REQUIRED(_critSect)
   2526 {
   2527     uint32_t currentMicLevel(0);
   2528     uint32_t newMicLevel(0);
   2529 
   2530     _ptrAudioBuffer->SetRecordedBuffer(bufferData, bufferSizeInSamples);
   2531 
   2532     if (AGC())
   2533     {
   2534         // Store current mic level in the audio buffer if AGC is enabled
   2535         if (MicrophoneVolume(currentMicLevel) == 0)
   2536         {
   2537             // This call does not affect the actual microphone volume
   2538             _ptrAudioBuffer->SetCurrentMicLevel(currentMicLevel);
   2539         }
   2540     }
   2541 
   2542     const uint32_t clockDrift(0);
   2543     // TODO(andrew): this is a temporary hack, to avoid non-causal far- and
   2544     // near-end signals at the AEC for PulseAudio. I think the system delay is
   2545     // being correctly calculated here, but for legacy reasons we add +10 ms
   2546     // to the value in the AEC. The real fix will be part of a larger
   2547     // investigation into managing system delay in the AEC.
   2548     if (recDelay > 10)
   2549         recDelay -= 10;
   2550     else
   2551         recDelay = 0;
   2552     _ptrAudioBuffer->SetVQEData(_sndCardPlayDelay, recDelay, clockDrift);
   2553     _ptrAudioBuffer->SetTypingStatus(KeyPressed());
   2554     // Deliver recorded samples at specified sample rate,
   2555     // mic level etc. to the observer using callback.
   2556     UnLock();
   2557     _ptrAudioBuffer->DeliverRecordedData();
   2558     Lock();
   2559 
   2560     // We have been unlocked - check the flag again.
   2561     if (!_recording)
   2562     {
   2563         return -1;
   2564     }
   2565 
   2566     if (AGC())
   2567     {
   2568         newMicLevel = _ptrAudioBuffer->NewMicLevel();
   2569         if (newMicLevel != 0)
   2570         {
   2571             // The VQE will only deliver non-zero microphone levels when a
   2572             // change is needed.
   2573             // Set this new mic level (received from the observer as return
   2574             // value in the callback).
   2575             WEBRTC_TRACE(kTraceStream, kTraceAudioDevice, _id,
   2576                          "  AGC change of volume: old=%u => new=%u",
   2577                          currentMicLevel, newMicLevel);
   2578             if (SetMicrophoneVolume(newMicLevel) == -1)
   2579             {
   2580                 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice,
   2581                              _id,
   2582                              "  the required modification of the microphone "
   2583                              "volume failed");
   2584             }
   2585         }
   2586     }
   2587 
   2588     return 0;
   2589 }
   2590 
   2591 bool AudioDeviceLinuxPulse::PlayThreadFunc(void* pThis)
   2592 {
   2593     return (static_cast<AudioDeviceLinuxPulse*> (pThis)->PlayThreadProcess());
   2594 }
   2595 
   2596 bool AudioDeviceLinuxPulse::RecThreadFunc(void* pThis)
   2597 {
   2598     return (static_cast<AudioDeviceLinuxPulse*> (pThis)->RecThreadProcess());
   2599 }
   2600 
   2601 bool AudioDeviceLinuxPulse::PlayThreadProcess()
   2602 {
   2603     switch (_timeEventPlay.Wait(1000))
   2604     {
   2605         case kEventSignaled:
   2606             break;
   2607         case kEventError:
   2608             WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
   2609                          "EventWrapper::Wait() failed");
   2610             return true;
   2611         case kEventTimeout:
   2612             return true;
   2613     }
   2614 
   2615     CriticalSectionScoped lock(&_critSect);
   2616 
   2617     if (_startPlay)
   2618     {
   2619         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
   2620                      "_startPlay true, performing initial actions");
   2621 
   2622         _startPlay = false;
   2623         _playDeviceName = NULL;
   2624 
   2625         // Set if not default device
   2626         if (_outputDeviceIndex > 0)
   2627         {
   2628             // Get the playout device name
   2629             _playDeviceName = new char[kAdmMaxDeviceNameSize];
   2630             _deviceIndex = _outputDeviceIndex;
   2631             PlayoutDevices();
   2632         }
   2633 
   2634         // Start muted only supported on 0.9.11 and up
   2635         if (LATE(pa_context_get_protocol_version)(_paContext)
   2636             >= WEBRTC_PA_ADJUST_LATENCY_PROTOCOL_VERSION)
   2637         {
   2638             // Get the currently saved speaker mute status
   2639             // and set the initial mute status accordingly
   2640             bool enabled(false);
   2641             _mixerManager.SpeakerMute(enabled);
   2642             if (enabled)
   2643             {
   2644                 _playStreamFlags |= PA_STREAM_START_MUTED;
   2645             }
   2646         }
   2647 
   2648         // Get the currently saved speaker volume
   2649         uint32_t volume = 0;
   2650         if (update_speaker_volume_at_startup_)
   2651           _mixerManager.SpeakerVolume(volume);
   2652 
   2653         PaLock();
   2654 
   2655         // NULL gives PA the choice of startup volume.
   2656         pa_cvolume* ptr_cvolume = NULL;
   2657         if (update_speaker_volume_at_startup_) {
   2658           pa_cvolume cVolumes;
   2659           ptr_cvolume = &cVolumes;
   2660 
   2661           // Set the same volume for all channels
   2662           const pa_sample_spec *spec =
   2663               LATE(pa_stream_get_sample_spec)(_playStream);
   2664           LATE(pa_cvolume_set)(&cVolumes, spec->channels, volume);
   2665           update_speaker_volume_at_startup_ = false;
   2666         }
   2667 
   2668         // Connect the stream to a sink
   2669         if (LATE(pa_stream_connect_playback)(
   2670             _playStream,
   2671             _playDeviceName,
   2672             &_playBufferAttr,
   2673             (pa_stream_flags_t) _playStreamFlags,
   2674             ptr_cvolume, NULL) != PA_OK)
   2675         {
   2676             WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   2677                          "  failed to connect play stream, err=%d",
   2678                          LATE(pa_context_errno)(_paContext));
   2679         }
   2680 
   2681         WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id,
   2682                      "  play stream connected");
   2683 
   2684         // Wait for state change
   2685         while (LATE(pa_stream_get_state)(_playStream) != PA_STREAM_READY)
   2686         {
   2687             LATE(pa_threaded_mainloop_wait)(_paMainloop);
   2688         }
   2689 
   2690         WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id,
   2691                      "  play stream ready");
   2692 
   2693         // We can now handle write callbacks
   2694         EnableWriteCallback();
   2695 
   2696         PaUnLock();
   2697 
   2698         // Clear device name
   2699         if (_playDeviceName)
   2700         {
   2701             delete [] _playDeviceName;
   2702             _playDeviceName = NULL;
   2703         }
   2704 
   2705         _playing = true;
   2706         _playStartEvent.Set();
   2707 
   2708         return true;
   2709     }
   2710 
   2711     if (_playing)
   2712     {
   2713         if (!_recording)
   2714         {
   2715             // Update the playout delay
   2716             _sndCardPlayDelay = (uint32_t) (LatencyUsecs(_playStream)
   2717                 / 1000);
   2718         }
   2719 
   2720         if (_playbackBufferUnused < _playbackBufferSize)
   2721         {
   2722 
   2723             size_t write = _playbackBufferSize - _playbackBufferUnused;
   2724             if (_tempBufferSpace < write)
   2725             {
   2726                 write = _tempBufferSpace;
   2727             }
   2728 
   2729             PaLock();
   2730             if (LATE(pa_stream_write)(
   2731                 _playStream,
   2732                 (void *) &_playBuffer[_playbackBufferUnused],
   2733                 write, NULL, (int64_t) 0,
   2734                 PA_SEEK_RELATIVE) != PA_OK)
   2735             {
   2736                 _writeErrors++;
   2737                 if (_writeErrors > 10)
   2738                 {
   2739                     if (_playError == 1)
   2740                     {
   2741                         WEBRTC_TRACE(kTraceWarning,
   2742                                      kTraceUtility, _id,
   2743                                      "  pending playout error exists");
   2744                     }
   2745                     // Triggers callback from module process thread.
   2746                     _playError = 1;
   2747                     WEBRTC_TRACE(
   2748                                  kTraceError,
   2749                                  kTraceUtility,
   2750                                  _id,
   2751                                  "  kPlayoutError message posted: "
   2752                                  "_writeErrors=%u, error=%d",
   2753                                  _writeErrors,
   2754                                  LATE(pa_context_errno)(_paContext));
   2755                     _writeErrors = 0;
   2756                 }
   2757             }
   2758             PaUnLock();
   2759 
   2760             _playbackBufferUnused += write;
   2761             _tempBufferSpace -= write;
   2762         }
   2763 
   2764         uint32_t numPlaySamples = _playbackBufferSize / (2 * _playChannels);
   2765         // Might have been reduced to zero by the above.
   2766         if (_tempBufferSpace > 0)
   2767         {
   2768             // Ask for new PCM data to be played out using the
   2769             // AudioDeviceBuffer ensure that this callback is executed
   2770             // without taking the audio-thread lock.
   2771             UnLock();
   2772             WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id,
   2773                          "  requesting data");
   2774             uint32_t nSamples =
   2775                 _ptrAudioBuffer->RequestPlayoutData(numPlaySamples);
   2776             Lock();
   2777 
   2778             // We have been unlocked - check the flag again.
   2779             if (!_playing)
   2780             {
   2781                 return true;
   2782             }
   2783 
   2784             nSamples = _ptrAudioBuffer->GetPlayoutData(_playBuffer);
   2785             if (nSamples != numPlaySamples)
   2786             {
   2787                 WEBRTC_TRACE(kTraceError, kTraceAudioDevice,
   2788                              _id, "  invalid number of output samples(%d)",
   2789                              nSamples);
   2790             }
   2791 
   2792             size_t write = _playbackBufferSize;
   2793             if (_tempBufferSpace < write)
   2794             {
   2795                 write = _tempBufferSpace;
   2796             }
   2797 
   2798             WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id,
   2799                          "  will write");
   2800             PaLock();
   2801             if (LATE(pa_stream_write)(_playStream, (void *) &_playBuffer[0],
   2802                                       write, NULL, (int64_t) 0,
   2803                                       PA_SEEK_RELATIVE) != PA_OK)
   2804             {
   2805                 _writeErrors++;
   2806                 if (_writeErrors > 10)
   2807                 {
   2808                     if (_playError == 1)
   2809                     {
   2810                         WEBRTC_TRACE(kTraceWarning,
   2811                                      kTraceUtility, _id,
   2812                                      "  pending playout error exists");
   2813                     }
   2814                      // Triggers callback from module process thread.
   2815                     _playError = 1;
   2816                     WEBRTC_TRACE(
   2817                                  kTraceError,
   2818                                  kTraceUtility,
   2819                                  _id,
   2820                                  "  kPlayoutError message posted: "
   2821                                  "_writeErrors=%u, error=%d",
   2822                                  _writeErrors,
   2823                                  LATE(pa_context_errno)(_paContext));
   2824                     _writeErrors = 0;
   2825                 }
   2826             }
   2827             PaUnLock();
   2828 
   2829             _playbackBufferUnused = write;
   2830         }
   2831 
   2832         _tempBufferSpace = 0;
   2833         PaLock();
   2834         EnableWriteCallback();
   2835         PaUnLock();
   2836 
   2837     }  // _playing
   2838 
   2839     return true;
   2840 }
   2841 
   2842 bool AudioDeviceLinuxPulse::RecThreadProcess()
   2843 {
   2844     switch (_timeEventRec.Wait(1000))
   2845     {
   2846         case kEventSignaled:
   2847             break;
   2848         case kEventError:
   2849             WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
   2850                          "EventWrapper::Wait() failed");
   2851             return true;
   2852         case kEventTimeout:
   2853             return true;
   2854     }
   2855 
   2856     CriticalSectionScoped lock(&_critSect);
   2857 
   2858     if (_startRec)
   2859     {
   2860         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
   2861                      "_startRec true, performing initial actions");
   2862 
   2863         _recDeviceName = NULL;
   2864 
   2865         // Set if not default device
   2866         if (_inputDeviceIndex > 0)
   2867         {
   2868             // Get the recording device name
   2869             _recDeviceName = new char[kAdmMaxDeviceNameSize];
   2870             _deviceIndex = _inputDeviceIndex;
   2871             RecordingDevices();
   2872         }
   2873 
   2874         PaLock();
   2875 
   2876         WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id,
   2877                      "  connecting stream");
   2878 
   2879         // Connect the stream to a source
   2880         if (LATE(pa_stream_connect_record)(_recStream,
   2881             _recDeviceName,
   2882             &_recBufferAttr,
   2883             (pa_stream_flags_t) _recStreamFlags) != PA_OK)
   2884         {
   2885             WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   2886                          "  failed to connect rec stream, err=%d",
   2887                          LATE(pa_context_errno)(_paContext));
   2888         }
   2889 
   2890         WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id,
   2891                      "  connected");
   2892 
   2893         // Wait for state change
   2894         while (LATE(pa_stream_get_state)(_recStream) != PA_STREAM_READY)
   2895         {
   2896             LATE(pa_threaded_mainloop_wait)(_paMainloop);
   2897         }
   2898 
   2899         WEBRTC_TRACE(kTraceDebug, kTraceAudioDevice, _id,
   2900                      "  done");
   2901 
   2902         // We can now handle read callbacks
   2903         EnableReadCallback();
   2904 
   2905         PaUnLock();
   2906 
   2907         // Clear device name
   2908         if (_recDeviceName)
   2909         {
   2910             delete [] _recDeviceName;
   2911             _recDeviceName = NULL;
   2912         }
   2913 
   2914         _startRec = false;
   2915         _recording = true;
   2916         _recStartEvent.Set();
   2917 
   2918         return true;
   2919     }
   2920 
   2921     if (_recording)
   2922     {
   2923         // Read data and provide it to VoiceEngine
   2924         if (ReadRecordedData(_tempSampleData, _tempSampleDataSize) == -1)
   2925         {
   2926             return true;
   2927         }
   2928 
   2929         _tempSampleData = NULL;
   2930         _tempSampleDataSize = 0;
   2931 
   2932         PaLock();
   2933         while (true)
   2934         {
   2935             // Ack the last thing we read
   2936             if (LATE(pa_stream_drop)(_recStream) != 0)
   2937             {
   2938                 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice,
   2939                              _id, "  failed to drop, err=%d\n",
   2940                              LATE(pa_context_errno)(_paContext));
   2941             }
   2942 
   2943             if (LATE(pa_stream_readable_size)(_recStream) <= 0)
   2944             {
   2945                 // Then that was all the data
   2946                 break;
   2947             }
   2948 
   2949             // Else more data.
   2950             const void *sampleData;
   2951             size_t sampleDataSize;
   2952 
   2953             if (LATE(pa_stream_peek)(_recStream, &sampleData, &sampleDataSize)
   2954                 != 0)
   2955             {
   2956                 _recError = 1; // triggers callback from module process thread
   2957                 WEBRTC_TRACE(kTraceError, kTraceAudioDevice,
   2958                              _id, "  RECORD_ERROR message posted, error = %d",
   2959                              LATE(pa_context_errno)(_paContext));
   2960                 break;
   2961             }
   2962 
   2963             _sndCardRecDelay = (uint32_t) (LatencyUsecs(_recStream)
   2964                 / 1000);
   2965 
   2966             // Drop lock for sigslot dispatch, which could take a while.
   2967             PaUnLock();
   2968             // Read data and provide it to VoiceEngine
   2969             if (ReadRecordedData(sampleData, sampleDataSize) == -1)
   2970             {
   2971                 return true;
   2972             }
   2973             PaLock();
   2974 
   2975             // Return to top of loop for the ack and the check for more data.
   2976         }
   2977 
   2978         EnableReadCallback();
   2979         PaUnLock();
   2980 
   2981     }  // _recording
   2982 
   2983     return true;
   2984 }
   2985 
   2986 bool AudioDeviceLinuxPulse::KeyPressed() const{
   2987 
   2988   char szKey[32];
   2989   unsigned int i = 0;
   2990   char state = 0;
   2991 
   2992   if (!_XDisplay)
   2993     return false;
   2994 
   2995   // Check key map status
   2996   XQueryKeymap(_XDisplay, szKey);
   2997 
   2998   // A bit change in keymap means a key is pressed
   2999   for (i = 0; i < sizeof(szKey); i++)
   3000     state |= (szKey[i] ^ _oldKeyState[i]) & szKey[i];
   3001 
   3002   // Save old state
   3003   memcpy((char*)_oldKeyState, (char*)szKey, sizeof(_oldKeyState));
   3004   return (state != 0);
   3005 }
   3006 }
   3007