LCOV - code coverage report
Current view: top level - media/webrtc/trunk/webrtc/modules/audio_device/linux - audio_mixer_manager_pulse_linux.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 0 375 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 48 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
       3             :  *
       4             :  *  Use of this source code is governed by a BSD-style license
       5             :  *  that can be found in the LICENSE file in the root of the source
       6             :  *  tree. An additional intellectual property rights grant can be found
       7             :  *  in the file PATENTS.  All contributing project authors may
       8             :  *  be found in the AUTHORS file in the root of the source tree.
       9             :  */
      10             : 
      11             : #include <assert.h>
      12             : 
      13             : #include "webrtc/modules/audio_device/linux/audio_mixer_manager_pulse_linux.h"
      14             : #include "webrtc/system_wrappers/include/trace.h"
      15             : #include "webrtc/base/checks.h"
      16             : 
      17             : extern webrtc_adm_linux_pulse::PulseAudioSymbolTable PaSymbolTable;
      18             : 
      19             : // Accesses Pulse functions through our late-binding symbol table instead of
      20             : // directly. This way we don't have to link to libpulse, which means our
      21             : // binary will work on systems that don't have it.
      22             : #define LATE(sym) \
      23             :   LATESYM_GET(webrtc_adm_linux_pulse::PulseAudioSymbolTable, \
      24             :               &PaSymbolTable, sym)
      25             : 
      26             : namespace webrtc
      27             : {
      28             : 
      29             : class AutoPulseLock {
      30             :  public:
      31           0 :   explicit AutoPulseLock(pa_threaded_mainloop* pa_mainloop)
      32           0 :       : pa_mainloop_(pa_mainloop) {
      33           0 :     LATE(pa_threaded_mainloop_lock)(pa_mainloop_);
      34           0 :   }
      35             : 
      36           0 :   ~AutoPulseLock() {
      37           0 :     LATE(pa_threaded_mainloop_unlock)(pa_mainloop_);
      38           0 :   }
      39             : 
      40             :  private:
      41             :   pa_threaded_mainloop* const pa_mainloop_;
      42             : };
      43             : 
      44           0 : AudioMixerManagerLinuxPulse::AudioMixerManagerLinuxPulse(const int32_t id) :
      45             :     _id(id),
      46             :     _paOutputDeviceIndex(-1),
      47             :     _paInputDeviceIndex(-1),
      48             :     _paPlayStream(NULL),
      49             :     _paRecStream(NULL),
      50             :     _paMainloop(NULL),
      51             :     _paContext(NULL),
      52             :     _paVolume(0),
      53             :     _paMute(0),
      54             :     _paVolSteps(0),
      55             :     _paSpeakerMute(false),
      56             :     _paSpeakerVolume(PA_VOLUME_NORM),
      57             :     _paChannels(0),
      58           0 :     _paObjectsSet(false)
      59             : {
      60             :     WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id,
      61             :                  "%s constructed", __FUNCTION__);
      62           0 : }
      63             : 
      64           0 : AudioMixerManagerLinuxPulse::~AudioMixerManagerLinuxPulse()
      65             : {
      66           0 :     RTC_DCHECK(thread_checker_.CalledOnValidThread());
      67             :     WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id,
      68             :                  "%s destructed", __FUNCTION__);
      69             : 
      70           0 :     Close();
      71           0 : }
      72             : 
      73             : // ===========================================================================
      74             : //                                    PUBLIC METHODS
      75             : // ===========================================================================
      76             : 
      77           0 : int32_t AudioMixerManagerLinuxPulse::SetPulseAudioObjects(
      78             :     pa_threaded_mainloop* mainloop,
      79             :     pa_context* context)
      80             : {
      81           0 :     RTC_DCHECK(thread_checker_.CalledOnValidThread());
      82             :     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s",
      83             :                  __FUNCTION__);
      84             : 
      85           0 :     if (!mainloop || !context)
      86             :     {
      87             :         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
      88             :                      "  could not set PulseAudio objects for mixer");
      89           0 :         return -1;
      90             :     }
      91             : 
      92           0 :     _paMainloop = mainloop;
      93           0 :     _paContext = context;
      94           0 :     _paObjectsSet = true;
      95             : 
      96             :     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
      97             :                  "  the PulseAudio objects for the mixer has been set");
      98             : 
      99           0 :     return 0;
     100             : }
     101             : 
     102           0 : int32_t AudioMixerManagerLinuxPulse::Close()
     103             : {
     104           0 :     RTC_DCHECK(thread_checker_.CalledOnValidThread());
     105             :     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s",
     106             :                  __FUNCTION__);
     107             : 
     108           0 :     CloseSpeaker();
     109           0 :     CloseMicrophone();
     110             : 
     111           0 :     _paMainloop = NULL;
     112           0 :     _paContext = NULL;
     113           0 :     _paObjectsSet = false;
     114             : 
     115           0 :     return 0;
     116             : 
     117             : }
     118             : 
     119           0 : int32_t AudioMixerManagerLinuxPulse::CloseSpeaker()
     120             : {
     121           0 :     RTC_DCHECK(thread_checker_.CalledOnValidThread());
     122             :     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s",
     123             :                  __FUNCTION__);
     124             : 
     125             :     // Reset the index to -1
     126           0 :     _paOutputDeviceIndex = -1;
     127           0 :     _paPlayStream = NULL;
     128             : 
     129           0 :     return 0;
     130             : }
     131             : 
     132           0 : int32_t AudioMixerManagerLinuxPulse::CloseMicrophone()
     133             : {
     134           0 :     RTC_DCHECK(thread_checker_.CalledOnValidThread());
     135             :     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s",
     136             :                  __FUNCTION__);
     137             : 
     138             :     // Reset the index to -1
     139           0 :     _paInputDeviceIndex = -1;
     140           0 :     _paRecStream = NULL;
     141             : 
     142           0 :     return 0;
     143             : }
     144             : 
     145           0 : int32_t AudioMixerManagerLinuxPulse::SetPlayStream(pa_stream* playStream)
     146             : {
     147           0 :     RTC_DCHECK(thread_checker_.CalledOnValidThread());
     148             :     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
     149             :                  "AudioMixerManagerLinuxPulse::SetPlayStream(playStream)");
     150             : 
     151           0 :     _paPlayStream = playStream;
     152           0 :     return 0;
     153             : }
     154             : 
     155           0 : int32_t AudioMixerManagerLinuxPulse::SetRecStream(pa_stream* recStream)
     156             : {
     157           0 :     RTC_DCHECK(thread_checker_.CalledOnValidThread());
     158             :     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
     159             :                  "AudioMixerManagerLinuxPulse::SetRecStream(recStream)");
     160             : 
     161           0 :     _paRecStream = recStream;
     162           0 :     return 0;
     163             : }
     164             : 
     165           0 : int32_t AudioMixerManagerLinuxPulse::OpenSpeaker(
     166             :     uint16_t deviceIndex)
     167             : {
     168           0 :     RTC_DCHECK(thread_checker_.CalledOnValidThread());
     169             :     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
     170             :                  "AudioMixerManagerLinuxPulse::OpenSpeaker(deviceIndex=%d)",
     171             :                  deviceIndex);
     172             : 
     173             :     // No point in opening the speaker
     174             :     // if PA objects have not been set
     175           0 :     if (!_paObjectsSet)
     176             :     {
     177             :         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
     178             :                      "  PulseAudio objects has not been set");
     179           0 :         return -1;
     180             :     }
     181             : 
     182             :     // Set the index for the PulseAudio
     183             :     // output device to control
     184           0 :     _paOutputDeviceIndex = deviceIndex;
     185             : 
     186             :     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
     187             :                  "  the output mixer device is now open");
     188             : 
     189           0 :     return 0;
     190             : }
     191             : 
     192           0 : int32_t AudioMixerManagerLinuxPulse::OpenMicrophone(
     193             :     uint16_t deviceIndex)
     194             : {
     195           0 :     RTC_DCHECK(thread_checker_.CalledOnValidThread());
     196             :     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
     197             :                  "AudioMixerManagerLinuxPulse::OpenMicrophone"
     198             :                  "(deviceIndex=%d)", deviceIndex);
     199             : 
     200             :     // No point in opening the microphone
     201             :     // if PA objects have not been set
     202           0 :     if (!_paObjectsSet)
     203             :     {
     204             :         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
     205             :                      "  PulseAudio objects have not been set");
     206           0 :         return -1;
     207             :     }
     208             : 
     209             :     // Set the index for the PulseAudio
     210             :     // input device to control
     211           0 :     _paInputDeviceIndex = deviceIndex;
     212             : 
     213             :     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
     214             :                  "  the input mixer device is now open");
     215             : 
     216           0 :     return 0;
     217             : }
     218             : 
     219           0 : bool AudioMixerManagerLinuxPulse::SpeakerIsInitialized() const
     220             : {
     221           0 :     RTC_DCHECK(thread_checker_.CalledOnValidThread());
     222             :     WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s",
     223             :                  __FUNCTION__);
     224             : 
     225           0 :     return (_paOutputDeviceIndex != -1);
     226             : }
     227             : 
     228           0 : bool AudioMixerManagerLinuxPulse::MicrophoneIsInitialized() const
     229             : {
     230           0 :     RTC_DCHECK(thread_checker_.CalledOnValidThread());
     231             :     WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s",
     232             :                  __FUNCTION__);
     233             : 
     234           0 :     return (_paInputDeviceIndex != -1);
     235             : }
     236             : 
     237           0 : int32_t AudioMixerManagerLinuxPulse::SetSpeakerVolume(
     238             :     uint32_t volume)
     239             : {
     240           0 :     RTC_DCHECK(thread_checker_.CalledOnValidThread());
     241             :     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
     242             :                  "AudioMixerManagerLinuxPulse::SetSpeakerVolume(volume=%u)",
     243             :                  volume);
     244             : 
     245           0 :     if (_paOutputDeviceIndex == -1)
     246             :     {
     247             :         WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
     248             :                      "  output device index has not been set");
     249           0 :         return -1;
     250             :     }
     251             : 
     252           0 :     bool setFailed(false);
     253             : 
     254           0 :     if (_paPlayStream && (LATE(pa_stream_get_state)(_paPlayStream)
     255             :         != PA_STREAM_UNCONNECTED))
     256             :     {
     257             :         // We can only really set the volume if we have a connected stream
     258           0 :         AutoPulseLock auto_lock(_paMainloop);
     259             : 
     260             :         // Get the number of channels from the sample specification
     261             :         const pa_sample_spec *spec =
     262           0 :             LATE(pa_stream_get_sample_spec)(_paPlayStream);
     263           0 :         if (!spec)
     264             :         {
     265             :             WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
     266             :                          "  could not get sample specification");
     267           0 :             return -1;
     268             :         }
     269             : 
     270             :         // Set the same volume for all channels
     271             :         pa_cvolume cVolumes;
     272           0 :         LATE(pa_cvolume_set)(&cVolumes, spec->channels, volume);
     273             : 
     274           0 :         pa_operation* paOperation = NULL;
     275           0 :         paOperation = LATE(pa_context_set_sink_input_volume)(
     276             :             _paContext,
     277           0 :             LATE(pa_stream_get_index)(_paPlayStream),
     278             :             &cVolumes,
     279           0 :             PaSetVolumeCallback, NULL);
     280           0 :         if (!paOperation)
     281             :         {
     282           0 :             setFailed = true;
     283             :         }
     284             : 
     285             :         // Don't need to wait for the completion
     286           0 :         LATE(pa_operation_unref)(paOperation);
     287             :     } else
     288             :     {
     289             :         // We have not created a stream or it's not connected to the sink
     290             :         // Save the volume to be set at connection
     291           0 :         _paSpeakerVolume = volume;
     292             :     }
     293             : 
     294           0 :     if (setFailed)
     295             :     {
     296             :         WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
     297             :                      " could not set speaker volume, error%d",
     298             :                      LATE(pa_context_errno)(_paContext));
     299             : 
     300           0 :         return -1;
     301             :     }
     302             : 
     303           0 :     return 0;
     304             : }
     305             : 
     306             : int32_t
     307           0 : AudioMixerManagerLinuxPulse::SpeakerVolume(uint32_t& volume) const
     308             : {
     309           0 :     if (_paOutputDeviceIndex == -1)
     310             :     {
     311             :         WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
     312             :                      "  output device index has not been set");
     313           0 :         return -1;
     314             :     }
     315             : 
     316           0 :     if (_paPlayStream && (LATE(pa_stream_get_state)(_paPlayStream)
     317             :         != PA_STREAM_UNCONNECTED))
     318             :     {
     319             :         // We can only get the volume if we have a connected stream
     320           0 :         if (!GetSinkInputInfo())
     321           0 :           return -1;
     322             : 
     323           0 :         AutoPulseLock auto_lock(_paMainloop);
     324           0 :         volume = static_cast<uint32_t> (_paVolume);
     325             :     } else
     326             :     {
     327           0 :         AutoPulseLock auto_lock(_paMainloop);
     328           0 :         volume = _paSpeakerVolume;
     329             :     }
     330             : 
     331             :     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
     332             :                  "\tAudioMixerManagerLinuxPulse::SpeakerVolume() => vol=%i",
     333             :                  volume);
     334             : 
     335           0 :     return 0;
     336             : }
     337             : 
     338             : int32_t
     339           0 : AudioMixerManagerLinuxPulse::MaxSpeakerVolume(uint32_t& maxVolume) const
     340             : {
     341             : 
     342           0 :     if (_paOutputDeviceIndex == -1)
     343             :     {
     344             :         WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
     345             :                      "  output device index has not been set");
     346           0 :         return -1;
     347             :     }
     348             : 
     349             :     // PA_VOLUME_NORM corresponds to 100% (0db)
     350             :     // but PA allows up to 150 db amplification
     351           0 :     maxVolume = static_cast<uint32_t> (PA_VOLUME_NORM);
     352             : 
     353           0 :     return 0;
     354             : }
     355             : 
     356             : int32_t
     357           0 : AudioMixerManagerLinuxPulse::MinSpeakerVolume(uint32_t& minVolume) const
     358             : {
     359             : 
     360           0 :     if (_paOutputDeviceIndex == -1)
     361             :     {
     362             :         WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
     363             :                      "  output device index has not been set");
     364           0 :         return -1;
     365             :     }
     366             : 
     367           0 :     minVolume = static_cast<uint32_t> (PA_VOLUME_MUTED);
     368             : 
     369           0 :     return 0;
     370             : }
     371             : 
     372             : int32_t
     373           0 : AudioMixerManagerLinuxPulse::SpeakerVolumeStepSize(uint16_t& stepSize) const
     374             : {
     375           0 :     RTC_DCHECK(thread_checker_.CalledOnValidThread());
     376           0 :     if (_paOutputDeviceIndex == -1)
     377             :     {
     378             :         WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
     379             :                      "  output device index has not been set");
     380           0 :         return -1;
     381             :     }
     382             : 
     383             :     // The sink input (stream) will always have step size = 1
     384             :     // There are PA_VOLUME_NORM+1 steps
     385           0 :     stepSize = 1;
     386             : 
     387             :     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
     388             :                  "\tAudioMixerManagerLinuxPulse::SpeakerVolumeStepSize() => "
     389             :                  "size=%i", stepSize);
     390             : 
     391           0 :     return 0;
     392             : }
     393             : 
     394             : int32_t
     395           0 : AudioMixerManagerLinuxPulse::SpeakerVolumeIsAvailable(bool& available)
     396             : {
     397           0 :     RTC_DCHECK(thread_checker_.CalledOnValidThread());
     398           0 :     if (_paOutputDeviceIndex == -1)
     399             :     {
     400             :         WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
     401             :                      "  output device index has not been set");
     402           0 :         return -1;
     403             :     }
     404             : 
     405             :     // Always available in Pulse Audio
     406           0 :     available = true;
     407             : 
     408           0 :     return 0;
     409             : }
     410             : 
     411             : int32_t
     412           0 : AudioMixerManagerLinuxPulse::SpeakerMuteIsAvailable(bool& available)
     413             : {
     414           0 :     RTC_DCHECK(thread_checker_.CalledOnValidThread());
     415           0 :     if (_paOutputDeviceIndex == -1)
     416             :     {
     417             :         WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
     418             :                      "  output device index has not been set");
     419           0 :         return -1;
     420             :     }
     421             : 
     422             :     // Always available in Pulse Audio
     423           0 :     available = true;
     424             : 
     425           0 :     return 0;
     426             : }
     427             : 
     428           0 : int32_t AudioMixerManagerLinuxPulse::SetSpeakerMute(bool enable)
     429             : {
     430           0 :     RTC_DCHECK(thread_checker_.CalledOnValidThread());
     431             :     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
     432             :                  "AudioMixerManagerLinuxPulse::SetSpeakerMute(enable=%u)",
     433             :                  enable);
     434             : 
     435           0 :     if (_paOutputDeviceIndex == -1)
     436             :     {
     437             :         WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
     438             :                      "  output device index has not been set");
     439           0 :         return -1;
     440             :     }
     441             : 
     442           0 :     bool setFailed(false);
     443             : 
     444           0 :     if (_paPlayStream && (LATE(pa_stream_get_state)(_paPlayStream)
     445             :         != PA_STREAM_UNCONNECTED))
     446             :     {
     447             :         // We can only really mute if we have a connected stream
     448           0 :         AutoPulseLock auto_lock(_paMainloop);
     449             : 
     450           0 :         pa_operation* paOperation = NULL;
     451           0 :         paOperation = LATE(pa_context_set_sink_input_mute)(
     452             :             _paContext,
     453           0 :             LATE(pa_stream_get_index)(_paPlayStream),
     454             :             (int) enable,
     455             :             PaSetVolumeCallback,
     456           0 :             NULL);
     457           0 :         if (!paOperation)
     458             :         {
     459           0 :             setFailed = true;
     460             :         }
     461             : 
     462             :         // Don't need to wait for the completion
     463           0 :         LATE(pa_operation_unref)(paOperation);
     464             :     } else
     465             :     {
     466             :         // We have not created a stream or it's not connected to the sink
     467             :         // Save the mute status to be set at connection
     468           0 :         _paSpeakerMute = enable;
     469             :     }
     470             : 
     471           0 :     if (setFailed)
     472             :     {
     473             :         WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
     474             :                      " could not mute speaker, error%d",
     475             :                      LATE(pa_context_errno)(_paContext));
     476           0 :         return -1;
     477             :     }
     478             : 
     479           0 :     return 0;
     480             : }
     481             : 
     482           0 : int32_t AudioMixerManagerLinuxPulse::SpeakerMute(bool& enabled) const
     483             : {
     484             : 
     485           0 :     if (_paOutputDeviceIndex == -1)
     486             :     {
     487             :         WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
     488             :                      "  output device index has not been set");
     489           0 :         return -1;
     490             :     }
     491             : 
     492           0 :     if (_paPlayStream && (LATE(pa_stream_get_state)(_paPlayStream)
     493             :         != PA_STREAM_UNCONNECTED))
     494             :     {
     495             :         // We can only get the mute status if we have a connected stream
     496           0 :         if (!GetSinkInputInfo())
     497           0 :           return -1;
     498             : 
     499           0 :         enabled = static_cast<bool> (_paMute);
     500             :     } else
     501             :     {
     502           0 :         enabled = _paSpeakerMute;
     503             :     }
     504             : 
     505             :     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
     506             :                  "     AudioMixerManagerLinuxPulse::SpeakerMute() => "
     507             :                  "enabled=%i, enabled");
     508             : 
     509           0 :     return 0;
     510             : }
     511             : 
     512             : int32_t
     513           0 : AudioMixerManagerLinuxPulse::StereoPlayoutIsAvailable(bool& available)
     514             : {
     515           0 :     RTC_DCHECK(thread_checker_.CalledOnValidThread());
     516           0 :     if (_paOutputDeviceIndex == -1)
     517             :     {
     518             :         WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
     519             :                      "  output device index has not been set");
     520           0 :         return -1;
     521             :     }
     522             : 
     523           0 :     uint32_t deviceIndex = (uint32_t) _paOutputDeviceIndex;
     524             : 
     525             :     {
     526           0 :         AutoPulseLock auto_lock(_paMainloop);
     527             : 
     528             :         // Get the actual stream device index if we have a connected stream
     529             :         // The device used by the stream can be changed
     530             :         // during the call
     531           0 :         if (_paPlayStream && (LATE(pa_stream_get_state)(_paPlayStream)
     532             :             != PA_STREAM_UNCONNECTED))
     533             :         {
     534           0 :             deviceIndex = LATE(pa_stream_get_device_index)(_paPlayStream);
     535             :         }
     536             :     }
     537             : 
     538           0 :     if (!GetSinkInfoByIndex(deviceIndex))
     539           0 :       return -1;
     540             : 
     541           0 :     available = static_cast<bool> (_paChannels == 2);
     542             : 
     543           0 :     return 0;
     544             : }
     545             : 
     546             : int32_t
     547           0 : AudioMixerManagerLinuxPulse::StereoRecordingIsAvailable(bool& available)
     548             : {
     549           0 :     RTC_DCHECK(thread_checker_.CalledOnValidThread());
     550           0 :     if (_paInputDeviceIndex == -1)
     551             :     {
     552             :         WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
     553             :                      "  input device index has not been set");
     554           0 :         return -1;
     555             :     }
     556             : 
     557           0 :     uint32_t deviceIndex = (uint32_t) _paInputDeviceIndex;
     558             : 
     559           0 :     AutoPulseLock auto_lock(_paMainloop);
     560             : 
     561             :     // Get the actual stream device index if we have a connected stream
     562             :     // The device used by the stream can be changed
     563             :     // during the call
     564           0 :     if (_paRecStream && (LATE(pa_stream_get_state)(_paRecStream)
     565             :         != PA_STREAM_UNCONNECTED))
     566             :     {
     567           0 :         deviceIndex = LATE(pa_stream_get_device_index)(_paRecStream);
     568             :     }
     569             : 
     570           0 :     pa_operation* paOperation = NULL;
     571             : 
     572             :     // Get info for this source
     573             :     // We want to know if the actual device can record in stereo
     574           0 :     paOperation = LATE(pa_context_get_source_info_by_index)(
     575             :         _paContext, deviceIndex,
     576             :         PaSourceInfoCallback,
     577           0 :         (void*) this);
     578             : 
     579           0 :     WaitForOperationCompletion(paOperation);
     580             : 
     581           0 :     available = static_cast<bool> (_paChannels == 2);
     582             : 
     583             :     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
     584             :                  " AudioMixerManagerLinuxPulse::StereoRecordingIsAvailable()"
     585             :                  " => available=%i, available");
     586             : 
     587           0 :     return 0;
     588             : }
     589             : 
     590           0 : int32_t AudioMixerManagerLinuxPulse::MicrophoneMuteIsAvailable(
     591             :     bool& available)
     592             : {
     593           0 :     RTC_DCHECK(thread_checker_.CalledOnValidThread());
     594           0 :     if (_paInputDeviceIndex == -1)
     595             :     {
     596             :         WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
     597             :                      "  input device index has not been set");
     598           0 :         return -1;
     599             :     }
     600             : 
     601             :     // Always available in Pulse Audio
     602           0 :     available = true;
     603             : 
     604           0 :     return 0;
     605             : }
     606             : 
     607           0 : int32_t AudioMixerManagerLinuxPulse::SetMicrophoneMute(bool enable)
     608             : {
     609           0 :     RTC_DCHECK(thread_checker_.CalledOnValidThread());
     610             :     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
     611             :                  "AudioMixerManagerLinuxPulse::SetMicrophoneMute(enable=%u)",
     612             :                  enable);
     613             : 
     614           0 :     if (_paInputDeviceIndex == -1)
     615             :     {
     616             :         WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
     617             :                      "  input device index has not been set");
     618           0 :         return -1;
     619             :     }
     620             : 
     621           0 :     bool setFailed(false);
     622           0 :     pa_operation* paOperation = NULL;
     623             : 
     624           0 :     uint32_t deviceIndex = (uint32_t) _paInputDeviceIndex;
     625             : 
     626           0 :     AutoPulseLock auto_lock(_paMainloop);
     627             : 
     628             :     // Get the actual stream device index if we have a connected stream
     629             :     // The device used by the stream can be changed
     630             :     // during the call
     631           0 :     if (_paRecStream && (LATE(pa_stream_get_state)(_paRecStream)
     632             :         != PA_STREAM_UNCONNECTED))
     633             :     {
     634           0 :         deviceIndex = LATE(pa_stream_get_device_index)(_paRecStream);
     635             :     }
     636             : 
     637             :     // Set mute switch for the source
     638           0 :     paOperation = LATE(pa_context_set_source_mute_by_index)(
     639             :         _paContext, deviceIndex,
     640             :         enable,
     641           0 :         PaSetVolumeCallback, NULL);
     642             : 
     643           0 :     if (!paOperation)
     644             :     {
     645           0 :         setFailed = true;
     646             :     }
     647             : 
     648             :     // Don't need to wait for this to complete.
     649           0 :     LATE(pa_operation_unref)(paOperation);
     650             : 
     651           0 :     if (setFailed)
     652             :     {
     653             :         WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
     654             :                      " could not mute microphone, error%d",
     655             :                      LATE(pa_context_errno)(_paContext));
     656           0 :         return -1;
     657             :     }
     658             : 
     659           0 :     return 0;
     660             : }
     661             : 
     662           0 : int32_t AudioMixerManagerLinuxPulse::MicrophoneMute(bool& enabled) const
     663             : {
     664           0 :     RTC_DCHECK(thread_checker_.CalledOnValidThread());
     665           0 :     if (_paInputDeviceIndex == -1)
     666             :     {
     667             :         WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
     668             :                      "  input device index has not been set");
     669           0 :         return -1;
     670             :     }
     671             : 
     672           0 :     uint32_t deviceIndex = (uint32_t) _paInputDeviceIndex;
     673             : 
     674             :     {
     675           0 :         AutoPulseLock auto_lock(_paMainloop);
     676             :         // Get the actual stream device index if we have a connected stream
     677             :         // The device used by the stream can be changed
     678             :         // during the call
     679           0 :         if (_paRecStream && (LATE(pa_stream_get_state)(_paRecStream)
     680             :             != PA_STREAM_UNCONNECTED))
     681             :         {
     682           0 :             deviceIndex = LATE(pa_stream_get_device_index)(_paRecStream);
     683             :         }
     684             :     }
     685             : 
     686           0 :     if (!GetSourceInfoByIndex(deviceIndex))
     687           0 :       return -1;
     688             : 
     689           0 :     enabled = static_cast<bool> (_paMute);
     690             : 
     691             :     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
     692             :                  "\tAudioMixerManagerLinuxPulse::MicrophoneMute() =>"
     693             :                  " enabled=%i", enabled);
     694             : 
     695           0 :     return 0;
     696             : }
     697             : 
     698             : int32_t
     699           0 : AudioMixerManagerLinuxPulse::MicrophoneBoostIsAvailable(bool& available)
     700             : {
     701           0 :     RTC_DCHECK(thread_checker_.CalledOnValidThread());
     702           0 :     if (_paInputDeviceIndex == -1)
     703             :     {
     704             :         WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
     705             :                      "  input device index has not been set");
     706           0 :         return -1;
     707             :     }
     708             : 
     709             :     // Always unavailable in Pulse Audio
     710             :     // Could make it possible to use PA_VOLUME_MAX
     711             :     // but that gives bad audio with some sound cards
     712           0 :     available = false;
     713             : 
     714           0 :     return 0;
     715             : }
     716             : 
     717           0 : int32_t AudioMixerManagerLinuxPulse::SetMicrophoneBoost(bool enable)
     718             : {
     719           0 :     RTC_DCHECK(thread_checker_.CalledOnValidThread());
     720             :     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
     721             :                  "AudioMixerManagerLinuxPulse::SetMicrophoneBoost(enable=%u)",
     722             :                  enable);
     723             : 
     724           0 :     if (_paInputDeviceIndex == -1)
     725             :     {
     726             :         WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
     727             :                      "  input device index has not been set");
     728           0 :         return -1;
     729             :     }
     730             : 
     731             :     // Ensure the selected microphone destination has a valid boost control
     732           0 :     bool available(false);
     733           0 :     MicrophoneBoostIsAvailable(available);
     734           0 :     if (!available)
     735             :     {
     736             :         WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
     737             :                      "  it is not possible to enable microphone boost");
     738           0 :         return -1;
     739             :     }
     740             : 
     741             :     // It is assumed that the call above fails!
     742             : 
     743           0 :     return 0;
     744             : }
     745             : 
     746           0 : int32_t AudioMixerManagerLinuxPulse::MicrophoneBoost(bool& enabled) const
     747             : {
     748           0 :     RTC_DCHECK(thread_checker_.CalledOnValidThread());
     749           0 :     if (_paInputDeviceIndex == -1)
     750             :     {
     751             :         WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
     752             :                      "  input device index has not been set");
     753           0 :         return -1;
     754             :     }
     755             : 
     756             :     // Microphone boost cannot be enabled on this platform!
     757           0 :     enabled = false;
     758             : 
     759           0 :     return 0;
     760             : }
     761             : 
     762           0 : int32_t AudioMixerManagerLinuxPulse::MicrophoneVolumeIsAvailable(
     763             :     bool& available)
     764             : {
     765           0 :     RTC_DCHECK(thread_checker_.CalledOnValidThread());
     766           0 :     if (_paInputDeviceIndex == -1)
     767             :     {
     768             :         WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
     769             :                      "  input device index has not been set");
     770           0 :         return -1;
     771             :     }
     772             : 
     773             :     // Always available in Pulse Audio
     774           0 :     available = true;
     775             : 
     776           0 :     return 0;
     777             : }
     778             : 
     779             : int32_t
     780           0 : AudioMixerManagerLinuxPulse::SetMicrophoneVolume(uint32_t volume)
     781             : {
     782             :     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
     783             :                  "AudioMixerManagerLinuxPulse::SetMicrophoneVolume"
     784             :                  "(volume=%u)", volume);
     785             : 
     786           0 :     if (_paInputDeviceIndex == -1)
     787             :     {
     788             :         WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
     789             :                      "  input device index has not been set");
     790           0 :         return -1;
     791             :     }
     792             : 
     793             :     // Unlike output streams, input streams have no concept of a stream
     794             :     // volume, only a device volume. So we have to change the volume of the
     795             :     // device itself.
     796             : 
     797             :     // The device may have a different number of channels than the stream and
     798             :     // their mapping may be different, so we don't want to use the channel
     799             :     // count from our sample spec. We could use PA_CHANNELS_MAX to cover our
     800             :     // bases, and the server allows that even if the device's channel count
     801             :     // is lower, but some buggy PA clients don't like that (the pavucontrol
     802             :     // on Hardy dies in an assert if the channel count is different). So
     803             :     // instead we look up the actual number of channels that the device has.
     804           0 :     AutoPulseLock auto_lock(_paMainloop);
     805           0 :     uint32_t deviceIndex = (uint32_t) _paInputDeviceIndex;
     806             : 
     807             :     // Get the actual stream device index if we have a connected stream
     808             :     // The device used by the stream can be changed
     809             :     // during the call
     810           0 :     if (_paRecStream && (LATE(pa_stream_get_state)(_paRecStream)
     811             :         != PA_STREAM_UNCONNECTED))
     812             :     {
     813           0 :         deviceIndex = LATE(pa_stream_get_device_index)(_paRecStream);
     814             :     }
     815             : 
     816           0 :     bool setFailed(false);
     817           0 :     pa_operation* paOperation = NULL;
     818             : 
     819             :     // Get the number of channels for this source
     820             :     paOperation
     821           0 :         = LATE(pa_context_get_source_info_by_index)(_paContext, deviceIndex,
     822             :                                                     PaSourceInfoCallback,
     823           0 :                                                     (void*) this);
     824             : 
     825           0 :     WaitForOperationCompletion(paOperation);
     826             : 
     827           0 :     uint8_t channels = _paChannels;
     828             :     pa_cvolume cVolumes;
     829           0 :     LATE(pa_cvolume_set)(&cVolumes, channels, volume);
     830             : 
     831             :     // Set the volume for the source
     832             :     paOperation
     833           0 :         = LATE(pa_context_set_source_volume_by_index)(_paContext, deviceIndex,
     834             :                                                       &cVolumes,
     835             :                                                       PaSetVolumeCallback,
     836           0 :                                                       NULL);
     837             : 
     838           0 :     if (!paOperation)
     839             :     {
     840           0 :         setFailed = true;
     841             :     }
     842             : 
     843             :     // Don't need to wait for this to complete.
     844           0 :     LATE(pa_operation_unref)(paOperation);
     845             : 
     846           0 :     if (setFailed)
     847             :     {
     848             :         WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
     849             :                      " could not set microphone volume, error%d",
     850             :                      LATE(pa_context_errno)(_paContext));
     851           0 :         return -1;
     852             :     }
     853             : 
     854           0 :     return 0;
     855             : }
     856             : 
     857             : int32_t
     858           0 : AudioMixerManagerLinuxPulse::MicrophoneVolume(uint32_t& volume) const
     859             : {
     860             : 
     861           0 :     if (_paInputDeviceIndex == -1)
     862             :     {
     863             :         WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
     864             :                      "  input device index has not been set");
     865           0 :         return -1;
     866             :     }
     867             : 
     868           0 :     uint32_t deviceIndex = (uint32_t) _paInputDeviceIndex;
     869             : 
     870             :     {
     871           0 :       AutoPulseLock auto_lock(_paMainloop);
     872             :       // Get the actual stream device index if we have a connected stream.
     873             :       // The device used by the stream can be changed during the call.
     874           0 :       if (_paRecStream && (LATE(pa_stream_get_state)(_paRecStream)
     875             :           != PA_STREAM_UNCONNECTED))
     876             :       {
     877           0 :           deviceIndex = LATE(pa_stream_get_device_index)(_paRecStream);
     878             :       }
     879             :     }
     880             : 
     881           0 :     if (!GetSourceInfoByIndex(deviceIndex))
     882           0 :         return -1;
     883             : 
     884             :     {
     885           0 :         AutoPulseLock auto_lock(_paMainloop);
     886           0 :         volume = static_cast<uint32_t> (_paVolume);
     887             :     }
     888             : 
     889             :     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
     890             :                  "     AudioMixerManagerLinuxPulse::MicrophoneVolume()"
     891             :                  " => vol=%i, volume");
     892             : 
     893           0 :     return 0;
     894             : }
     895             : 
     896             : int32_t
     897           0 : AudioMixerManagerLinuxPulse::MaxMicrophoneVolume(uint32_t& maxVolume) const
     898             : {
     899             : 
     900           0 :     if (_paInputDeviceIndex == -1)
     901             :     {
     902             :         WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
     903             :                      "  input device index has not been set");
     904           0 :         return -1;
     905             :     }
     906             : 
     907             :     // PA_VOLUME_NORM corresponds to 100% (0db)
     908             :     // PA allows up to 150 db amplification (PA_VOLUME_MAX)
     909             :     // but that doesn't work well for all sound cards
     910           0 :     maxVolume = static_cast<uint32_t> (PA_VOLUME_NORM);
     911             : 
     912           0 :     return 0;
     913             : }
     914             : 
     915             : int32_t
     916           0 : AudioMixerManagerLinuxPulse::MinMicrophoneVolume(uint32_t& minVolume) const
     917             : {
     918             : 
     919           0 :     if (_paInputDeviceIndex == -1)
     920             :     {
     921             :         WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
     922             :                      "  input device index has not been set");
     923           0 :         return -1;
     924             :     }
     925             : 
     926           0 :     minVolume = static_cast<uint32_t> (PA_VOLUME_MUTED);
     927             : 
     928           0 :     return 0;
     929             : }
     930             : 
     931           0 : int32_t AudioMixerManagerLinuxPulse::MicrophoneVolumeStepSize(
     932             :     uint16_t& stepSize) const
     933             : {
     934           0 :     RTC_DCHECK(thread_checker_.CalledOnValidThread());
     935           0 :     if (_paInputDeviceIndex == -1)
     936             :     {
     937             :         WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
     938             :                      "  input device index has not been set");
     939           0 :         return -1;
     940             :     }
     941             : 
     942           0 :     uint32_t deviceIndex = (uint32_t) _paInputDeviceIndex;
     943             : 
     944           0 :     AutoPulseLock auto_lock(_paMainloop);
     945             : 
     946             :     // Get the actual stream device index if we have a connected stream
     947             :     // The device used by the stream can be changed
     948             :     // during the call
     949           0 :     if (_paRecStream && (LATE(pa_stream_get_state)(_paRecStream)
     950             :         != PA_STREAM_UNCONNECTED))
     951             :     {
     952           0 :         deviceIndex = LATE(pa_stream_get_device_index)(_paRecStream);
     953             :     }
     954             : 
     955           0 :     pa_operation* paOperation = NULL;
     956             : 
     957             :     // Get info for this source
     958             :     paOperation
     959           0 :         = LATE(pa_context_get_source_info_by_index)(_paContext, deviceIndex,
     960             :                                                     PaSourceInfoCallback,
     961           0 :                                                     (void*) this);
     962             : 
     963           0 :     WaitForOperationCompletion(paOperation);
     964             : 
     965           0 :     stepSize = static_cast<uint16_t> ((PA_VOLUME_NORM + 1) / _paVolSteps);
     966             : 
     967             :     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
     968             :                  "\tAudioMixerManagerLinuxPulse::MicrophoneVolumeStepSize()"
     969             :                  " => size=%i", stepSize);
     970             : 
     971           0 :     return 0;
     972             : }
     973             : 
     974             : // ===========================================================================
     975             : //                                 Private Methods
     976             : // ===========================================================================
     977             : 
     978             : void
     979           0 : AudioMixerManagerLinuxPulse::PaSinkInfoCallback(pa_context */*c*/,
     980             :                                                 const pa_sink_info *i,
     981             :                                                 int eol,
     982             :                                                 void *pThis)
     983             : {
     984             :     static_cast<AudioMixerManagerLinuxPulse*> (pThis)->
     985           0 :         PaSinkInfoCallbackHandler(i, eol);
     986           0 : }
     987             : 
     988             : void
     989           0 : AudioMixerManagerLinuxPulse::PaSinkInputInfoCallback(
     990             :     pa_context */*c*/,
     991             :     const pa_sink_input_info *i,
     992             :     int eol,
     993             :     void *pThis)
     994             : {
     995             :     static_cast<AudioMixerManagerLinuxPulse*> (pThis)->
     996           0 :         PaSinkInputInfoCallbackHandler(i, eol);
     997           0 : }
     998             : 
     999             : 
    1000             : void
    1001           0 : AudioMixerManagerLinuxPulse::PaSourceInfoCallback(pa_context */*c*/,
    1002             :                                                   const pa_source_info *i,
    1003             :                                                   int eol,
    1004             :                                                   void *pThis)
    1005             : {
    1006             :     static_cast<AudioMixerManagerLinuxPulse*> (pThis)->
    1007           0 :         PaSourceInfoCallbackHandler(i, eol);
    1008           0 : }
    1009             : 
    1010             : void
    1011           0 : AudioMixerManagerLinuxPulse::PaSetVolumeCallback(pa_context * c,
    1012             :                                                  int success,
    1013             :                                                  void */*pThis*/)
    1014             : {
    1015             :     if (!success)
    1016             :     {
    1017             :         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, -1,
    1018             :                      " failed to set volume");
    1019             :     }
    1020           0 : }
    1021             : 
    1022           0 : void AudioMixerManagerLinuxPulse::PaSinkInfoCallbackHandler(
    1023             :     const pa_sink_info *i,
    1024             :     int eol)
    1025             : {
    1026           0 :     if (eol)
    1027             :     {
    1028             :         // Signal that we are done
    1029           0 :         LATE(pa_threaded_mainloop_signal)(_paMainloop, 0);
    1030           0 :         return;
    1031             :     }
    1032             : 
    1033           0 :     _paChannels = i->channel_map.channels; // Get number of channels
    1034           0 :     pa_volume_t paVolume = PA_VOLUME_MUTED; // Minimum possible value.
    1035           0 :     for (int j = 0; j < _paChannels; ++j)
    1036             :     {
    1037           0 :         if (paVolume < i->volume.values[j])
    1038             :         {
    1039           0 :             paVolume = i->volume.values[j];
    1040             :         }
    1041             :     }
    1042           0 :     _paVolume = paVolume; // get the max volume for any channel
    1043           0 :     _paMute = i->mute; // get mute status
    1044             : 
    1045             :     // supported since PA 0.9.15
    1046             :     //_paVolSteps = i->n_volume_steps; // get the number of volume steps
    1047             :     // default value is PA_VOLUME_NORM+1
    1048           0 :     _paVolSteps = PA_VOLUME_NORM + 1;
    1049             : }
    1050             : 
    1051           0 : void AudioMixerManagerLinuxPulse::PaSinkInputInfoCallbackHandler(
    1052             :     const pa_sink_input_info *i,
    1053             :     int eol)
    1054             : {
    1055           0 :     if (eol)
    1056             :     {
    1057             :         // Signal that we are done
    1058           0 :         LATE(pa_threaded_mainloop_signal)(_paMainloop, 0);
    1059           0 :         return;
    1060             :     }
    1061             : 
    1062           0 :     _paChannels = i->channel_map.channels; // Get number of channels
    1063           0 :     pa_volume_t paVolume = PA_VOLUME_MUTED; // Minimum possible value.
    1064           0 :     for (int j = 0; j < _paChannels; ++j)
    1065             :     {
    1066           0 :         if (paVolume < i->volume.values[j])
    1067             :         {
    1068           0 :             paVolume = i->volume.values[j];
    1069             :         }
    1070             :     }
    1071           0 :     _paVolume = paVolume; // Get the max volume for any channel
    1072           0 :     _paMute = i->mute; // Get mute status
    1073             : }
    1074             : 
    1075           0 : void AudioMixerManagerLinuxPulse::PaSourceInfoCallbackHandler(
    1076             :     const pa_source_info *i,
    1077             :     int eol)
    1078             : {
    1079           0 :     if (eol)
    1080             :     {
    1081             :         // Signal that we are done
    1082           0 :         LATE(pa_threaded_mainloop_signal)(_paMainloop, 0);
    1083           0 :         return;
    1084             :     }
    1085             : 
    1086           0 :     _paChannels = i->channel_map.channels; // Get number of channels
    1087           0 :     pa_volume_t paVolume = PA_VOLUME_MUTED; // Minimum possible value.
    1088           0 :     for (int j = 0; j < _paChannels; ++j)
    1089             :     {
    1090           0 :         if (paVolume < i->volume.values[j])
    1091             :         {
    1092           0 :             paVolume = i->volume.values[j];
    1093             :         }
    1094             :     }
    1095           0 :     _paVolume = paVolume; // Get the max volume for any channel
    1096           0 :     _paMute = i->mute; // Get mute status
    1097             : 
    1098             :     // supported since PA 0.9.15
    1099             :     //_paVolSteps = i->n_volume_steps; // Get the number of volume steps
    1100             :     // default value is PA_VOLUME_NORM+1
    1101           0 :     _paVolSteps = PA_VOLUME_NORM + 1;
    1102             : }
    1103             : 
    1104           0 : void AudioMixerManagerLinuxPulse::WaitForOperationCompletion(
    1105             :     pa_operation* paOperation) const
    1106             : {
    1107           0 :     while (LATE(pa_operation_get_state)(paOperation) == PA_OPERATION_RUNNING)
    1108             :     {
    1109           0 :         LATE(pa_threaded_mainloop_wait)(_paMainloop);
    1110             :     }
    1111             : 
    1112           0 :     LATE(pa_operation_unref)(paOperation);
    1113           0 : }
    1114             : 
    1115           0 : bool AudioMixerManagerLinuxPulse::GetSinkInputInfo() const {
    1116           0 :   pa_operation* paOperation = NULL;
    1117             : 
    1118           0 :   AutoPulseLock auto_lock(_paMainloop);
    1119             :   // Get info for this stream (sink input).
    1120           0 :   paOperation = LATE(pa_context_get_sink_input_info)(
    1121           0 :       _paContext,
    1122           0 :       LATE(pa_stream_get_index)(_paPlayStream),
    1123             :       PaSinkInputInfoCallback,
    1124           0 :       (void*) this);
    1125             : 
    1126           0 :   WaitForOperationCompletion(paOperation);
    1127           0 :   return true;
    1128             : }
    1129             : 
    1130           0 : bool AudioMixerManagerLinuxPulse::GetSinkInfoByIndex(
    1131             :     int device_index) const {
    1132           0 :   pa_operation* paOperation = NULL;
    1133             : 
    1134           0 :   AutoPulseLock auto_lock(_paMainloop);
    1135           0 :   paOperation = LATE(pa_context_get_sink_info_by_index)(_paContext,
    1136           0 :       device_index, PaSinkInfoCallback, (void*) this);
    1137             : 
    1138           0 :   WaitForOperationCompletion(paOperation);
    1139           0 :   return true;
    1140             : }
    1141             : 
    1142           0 : bool AudioMixerManagerLinuxPulse::GetSourceInfoByIndex(
    1143             :     int device_index) const {
    1144           0 :   pa_operation* paOperation = NULL;
    1145             : 
    1146           0 :   AutoPulseLock auto_lock(_paMainloop);
    1147           0 :   paOperation  = LATE(pa_context_get_source_info_by_index)(
    1148           0 :       _paContext, device_index, PaSourceInfoCallback, (void*) this);
    1149             : 
    1150           0 :   WaitForOperationCompletion(paOperation);
    1151           0 :   return true;
    1152             : }
    1153             : 
    1154             : }

Generated by: LCOV version 1.13