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