1 /*
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include <assert.h>
12
13 #include "modules/audio_device/linux/audio_mixer_manager_pulse_linux.h"
14 #include "rtc_base/checks.h"
15 #include "rtc_base/logging.h"
16
17 extern webrtc::adm_linux_pulse::PulseAudioSymbolTable PaSymbolTable;
18
19 // Accesses Pulse functions through our late-binding symbol table instead of
20 // directly. This way we don't have to link to libpulse, which means our
21 // binary will work on systems that don't have it.
22 #define LATE(sym) \
23 LATESYM_GET(webrtc::adm_linux_pulse::PulseAudioSymbolTable, &PaSymbolTable, \
24 sym)
25
26 namespace webrtc {
27
28 class AutoPulseLock {
29 public:
AutoPulseLock(pa_threaded_mainloop * pa_mainloop)30 explicit AutoPulseLock(pa_threaded_mainloop* pa_mainloop)
31 : pa_mainloop_(pa_mainloop) {
32 LATE(pa_threaded_mainloop_lock)(pa_mainloop_);
33 }
34
~AutoPulseLock()35 ~AutoPulseLock() { LATE(pa_threaded_mainloop_unlock)(pa_mainloop_); }
36
37 private:
38 pa_threaded_mainloop* const pa_mainloop_;
39 };
40
AudioMixerManagerLinuxPulse()41 AudioMixerManagerLinuxPulse::AudioMixerManagerLinuxPulse()
42 : _paOutputDeviceIndex(-1),
43 _paInputDeviceIndex(-1),
44 _paPlayStream(NULL),
45 _paRecStream(NULL),
46 _paMainloop(NULL),
47 _paContext(NULL),
48 _paVolume(0),
49 _paMute(0),
50 _paVolSteps(0),
51 _paSpeakerMute(false),
52 _paSpeakerVolume(PA_VOLUME_NORM),
53 _paChannels(0),
54 _paObjectsSet(false) {
55 RTC_LOG(LS_INFO) << __FUNCTION__ << " created";
56 }
57
~AudioMixerManagerLinuxPulse()58 AudioMixerManagerLinuxPulse::~AudioMixerManagerLinuxPulse() {
59 RTC_DCHECK(thread_checker_.CalledOnValidThread());
60 RTC_LOG(LS_INFO) << __FUNCTION__ << " destroyed";
61
62 Close();
63 }
64
65 // ===========================================================================
66 // PUBLIC METHODS
67 // ===========================================================================
68
SetPulseAudioObjects(pa_threaded_mainloop * mainloop,pa_context * context)69 int32_t AudioMixerManagerLinuxPulse::SetPulseAudioObjects(
70 pa_threaded_mainloop* mainloop,
71 pa_context* context) {
72 RTC_DCHECK(thread_checker_.CalledOnValidThread());
73 RTC_LOG(LS_VERBOSE) << __FUNCTION__;
74
75 if (!mainloop || !context) {
76 RTC_LOG(LS_ERROR) << "could not set PulseAudio objects for mixer";
77 return -1;
78 }
79
80 _paMainloop = mainloop;
81 _paContext = context;
82 _paObjectsSet = true;
83
84 RTC_LOG(LS_VERBOSE) << "the PulseAudio objects for the mixer has been set";
85
86 return 0;
87 }
88
Close()89 int32_t AudioMixerManagerLinuxPulse::Close() {
90 RTC_DCHECK(thread_checker_.CalledOnValidThread());
91 RTC_LOG(LS_VERBOSE) << __FUNCTION__;
92
93 CloseSpeaker();
94 CloseMicrophone();
95
96 _paMainloop = NULL;
97 _paContext = NULL;
98 _paObjectsSet = false;
99
100 return 0;
101 }
102
CloseSpeaker()103 int32_t AudioMixerManagerLinuxPulse::CloseSpeaker() {
104 RTC_DCHECK(thread_checker_.CalledOnValidThread());
105 RTC_LOG(LS_VERBOSE) << __FUNCTION__;
106
107 // Reset the index to -1
108 _paOutputDeviceIndex = -1;
109 _paPlayStream = NULL;
110
111 return 0;
112 }
113
CloseMicrophone()114 int32_t AudioMixerManagerLinuxPulse::CloseMicrophone() {
115 RTC_DCHECK(thread_checker_.CalledOnValidThread());
116 RTC_LOG(LS_VERBOSE) << __FUNCTION__;
117
118 // Reset the index to -1
119 _paInputDeviceIndex = -1;
120 _paRecStream = NULL;
121
122 return 0;
123 }
124
SetPlayStream(pa_stream * playStream)125 int32_t AudioMixerManagerLinuxPulse::SetPlayStream(pa_stream* playStream) {
126 RTC_DCHECK(thread_checker_.CalledOnValidThread());
127 RTC_LOG(LS_VERBOSE)
128 << "AudioMixerManagerLinuxPulse::SetPlayStream(playStream)";
129
130 _paPlayStream = playStream;
131 return 0;
132 }
133
SetRecStream(pa_stream * recStream)134 int32_t AudioMixerManagerLinuxPulse::SetRecStream(pa_stream* recStream) {
135 RTC_DCHECK(thread_checker_.CalledOnValidThread());
136 RTC_LOG(LS_VERBOSE) << "AudioMixerManagerLinuxPulse::SetRecStream(recStream)";
137
138 _paRecStream = recStream;
139 return 0;
140 }
141
OpenSpeaker(uint16_t deviceIndex)142 int32_t AudioMixerManagerLinuxPulse::OpenSpeaker(uint16_t deviceIndex) {
143 RTC_DCHECK(thread_checker_.CalledOnValidThread());
144 RTC_LOG(LS_VERBOSE) << "AudioMixerManagerLinuxPulse::OpenSpeaker(deviceIndex="
145 << deviceIndex << ")";
146
147 // No point in opening the speaker
148 // if PA objects have not been set
149 if (!_paObjectsSet) {
150 RTC_LOG(LS_ERROR) << "PulseAudio objects has not been set";
151 return -1;
152 }
153
154 // Set the index for the PulseAudio
155 // output device to control
156 _paOutputDeviceIndex = deviceIndex;
157
158 RTC_LOG(LS_VERBOSE) << "the output mixer device is now open";
159
160 return 0;
161 }
162
OpenMicrophone(uint16_t deviceIndex)163 int32_t AudioMixerManagerLinuxPulse::OpenMicrophone(uint16_t deviceIndex) {
164 RTC_DCHECK(thread_checker_.CalledOnValidThread());
165 RTC_LOG(LS_VERBOSE)
166 << "AudioMixerManagerLinuxPulse::OpenMicrophone(deviceIndex="
167 << deviceIndex << ")";
168
169 // No point in opening the microphone
170 // if PA objects have not been set
171 if (!_paObjectsSet) {
172 RTC_LOG(LS_ERROR) << "PulseAudio objects have not been set";
173 return -1;
174 }
175
176 // Set the index for the PulseAudio
177 // input device to control
178 _paInputDeviceIndex = deviceIndex;
179
180 RTC_LOG(LS_VERBOSE) << "the input mixer device is now open";
181
182 return 0;
183 }
184
SpeakerIsInitialized() const185 bool AudioMixerManagerLinuxPulse::SpeakerIsInitialized() const {
186 RTC_DCHECK(thread_checker_.CalledOnValidThread());
187 RTC_LOG(LS_INFO) << __FUNCTION__;
188
189 return (_paOutputDeviceIndex != -1);
190 }
191
MicrophoneIsInitialized() const192 bool AudioMixerManagerLinuxPulse::MicrophoneIsInitialized() const {
193 RTC_DCHECK(thread_checker_.CalledOnValidThread());
194 RTC_LOG(LS_INFO) << __FUNCTION__;
195
196 return (_paInputDeviceIndex != -1);
197 }
198
SetSpeakerVolume(uint32_t volume)199 int32_t AudioMixerManagerLinuxPulse::SetSpeakerVolume(uint32_t volume) {
200 RTC_DCHECK(thread_checker_.CalledOnValidThread());
201 RTC_LOG(LS_VERBOSE) << "AudioMixerManagerLinuxPulse::SetSpeakerVolume(volume="
202 << volume << ")";
203
204 if (_paOutputDeviceIndex == -1) {
205 RTC_LOG(LS_WARNING) << "output device index has not been set";
206 return -1;
207 }
208
209 bool setFailed(false);
210
211 if (_paPlayStream &&
212 (LATE(pa_stream_get_state)(_paPlayStream) != PA_STREAM_UNCONNECTED)) {
213 // We can only really set the volume if we have a connected stream
214 AutoPulseLock auto_lock(_paMainloop);
215
216 // Get the number of channels from the sample specification
217 const pa_sample_spec* spec = LATE(pa_stream_get_sample_spec)(_paPlayStream);
218 if (!spec) {
219 RTC_LOG(LS_ERROR) << "could not get sample specification";
220 return -1;
221 }
222
223 // Set the same volume for all channels
224 pa_cvolume cVolumes;
225 LATE(pa_cvolume_set)(&cVolumes, spec->channels, volume);
226
227 pa_operation* paOperation = NULL;
228 paOperation = LATE(pa_context_set_sink_input_volume)(
229 _paContext, LATE(pa_stream_get_index)(_paPlayStream), &cVolumes,
230 PaSetVolumeCallback, NULL);
231 if (!paOperation) {
232 setFailed = true;
233 }
234
235 // Don't need to wait for the completion
236 LATE(pa_operation_unref)(paOperation);
237 } else {
238 // We have not created a stream or it's not connected to the sink
239 // Save the volume to be set at connection
240 _paSpeakerVolume = volume;
241 }
242
243 if (setFailed) {
244 RTC_LOG(LS_WARNING) << "could not set speaker volume, error="
245 << LATE(pa_context_errno)(_paContext);
246
247 return -1;
248 }
249
250 return 0;
251 }
252
SpeakerVolume(uint32_t & volume) const253 int32_t AudioMixerManagerLinuxPulse::SpeakerVolume(uint32_t& volume) const {
254 if (_paOutputDeviceIndex == -1) {
255 RTC_LOG(LS_WARNING) << "output device index has not been set";
256 return -1;
257 }
258
259 if (_paPlayStream &&
260 (LATE(pa_stream_get_state)(_paPlayStream) != PA_STREAM_UNCONNECTED)) {
261 // We can only get the volume if we have a connected stream
262 if (!GetSinkInputInfo())
263 return -1;
264
265 AutoPulseLock auto_lock(_paMainloop);
266 volume = static_cast<uint32_t>(_paVolume);
267 } else {
268 AutoPulseLock auto_lock(_paMainloop);
269 volume = _paSpeakerVolume;
270 }
271
272 RTC_LOG(LS_VERBOSE) << "AudioMixerManagerLinuxPulse::SpeakerVolume() => vol="
273 << volume;
274
275 return 0;
276 }
277
MaxSpeakerVolume(uint32_t & maxVolume) const278 int32_t AudioMixerManagerLinuxPulse::MaxSpeakerVolume(
279 uint32_t& maxVolume) const {
280 if (_paOutputDeviceIndex == -1) {
281 RTC_LOG(LS_WARNING) << "output device index has not been set";
282 return -1;
283 }
284
285 // PA_VOLUME_NORM corresponds to 100% (0db)
286 // but PA allows up to 150 db amplification
287 maxVolume = static_cast<uint32_t>(PA_VOLUME_NORM);
288
289 return 0;
290 }
291
MinSpeakerVolume(uint32_t & minVolume) const292 int32_t AudioMixerManagerLinuxPulse::MinSpeakerVolume(
293 uint32_t& minVolume) const {
294 if (_paOutputDeviceIndex == -1) {
295 RTC_LOG(LS_WARNING) << "output device index has not been set";
296 return -1;
297 }
298
299 minVolume = static_cast<uint32_t>(PA_VOLUME_MUTED);
300
301 return 0;
302 }
303
SpeakerVolumeIsAvailable(bool & available)304 int32_t AudioMixerManagerLinuxPulse::SpeakerVolumeIsAvailable(bool& available) {
305 RTC_DCHECK(thread_checker_.CalledOnValidThread());
306 if (_paOutputDeviceIndex == -1) {
307 RTC_LOG(LS_WARNING) << "output device index has not been set";
308 return -1;
309 }
310
311 // Always available in Pulse Audio
312 available = true;
313
314 return 0;
315 }
316
SpeakerMuteIsAvailable(bool & available)317 int32_t AudioMixerManagerLinuxPulse::SpeakerMuteIsAvailable(bool& available) {
318 RTC_DCHECK(thread_checker_.CalledOnValidThread());
319 if (_paOutputDeviceIndex == -1) {
320 RTC_LOG(LS_WARNING) << "output device index has not been set";
321 return -1;
322 }
323
324 // Always available in Pulse Audio
325 available = true;
326
327 return 0;
328 }
329
SetSpeakerMute(bool enable)330 int32_t AudioMixerManagerLinuxPulse::SetSpeakerMute(bool enable) {
331 RTC_DCHECK(thread_checker_.CalledOnValidThread());
332 RTC_LOG(LS_VERBOSE) << "AudioMixerManagerLinuxPulse::SetSpeakerMute(enable="
333 << enable << ")";
334
335 if (_paOutputDeviceIndex == -1) {
336 RTC_LOG(LS_WARNING) << "output device index has not been set";
337 return -1;
338 }
339
340 bool setFailed(false);
341
342 if (_paPlayStream &&
343 (LATE(pa_stream_get_state)(_paPlayStream) != PA_STREAM_UNCONNECTED)) {
344 // We can only really mute if we have a connected stream
345 AutoPulseLock auto_lock(_paMainloop);
346
347 pa_operation* paOperation = NULL;
348 paOperation = LATE(pa_context_set_sink_input_mute)(
349 _paContext, LATE(pa_stream_get_index)(_paPlayStream), (int)enable,
350 PaSetVolumeCallback, NULL);
351 if (!paOperation) {
352 setFailed = true;
353 }
354
355 // Don't need to wait for the completion
356 LATE(pa_operation_unref)(paOperation);
357 } else {
358 // We have not created a stream or it's not connected to the sink
359 // Save the mute status to be set at connection
360 _paSpeakerMute = enable;
361 }
362
363 if (setFailed) {
364 RTC_LOG(LS_WARNING) << "could not mute speaker, error="
365 << LATE(pa_context_errno)(_paContext);
366 return -1;
367 }
368
369 return 0;
370 }
371
SpeakerMute(bool & enabled) const372 int32_t AudioMixerManagerLinuxPulse::SpeakerMute(bool& enabled) const {
373 if (_paOutputDeviceIndex == -1) {
374 RTC_LOG(LS_WARNING) << "output device index has not been set";
375 return -1;
376 }
377
378 if (_paPlayStream &&
379 (LATE(pa_stream_get_state)(_paPlayStream) != PA_STREAM_UNCONNECTED)) {
380 // We can only get the mute status if we have a connected stream
381 if (!GetSinkInputInfo())
382 return -1;
383
384 enabled = static_cast<bool>(_paMute);
385 } else {
386 enabled = _paSpeakerMute;
387 }
388 RTC_LOG(LS_VERBOSE)
389 << "AudioMixerManagerLinuxPulse::SpeakerMute() => enabled=" << enabled;
390
391 return 0;
392 }
393
StereoPlayoutIsAvailable(bool & available)394 int32_t AudioMixerManagerLinuxPulse::StereoPlayoutIsAvailable(bool& available) {
395 RTC_DCHECK(thread_checker_.CalledOnValidThread());
396 if (_paOutputDeviceIndex == -1) {
397 RTC_LOG(LS_WARNING) << "output device index has not been set";
398 return -1;
399 }
400
401 uint32_t deviceIndex = (uint32_t)_paOutputDeviceIndex;
402
403 {
404 AutoPulseLock auto_lock(_paMainloop);
405
406 // Get the actual stream device index if we have a connected stream
407 // The device used by the stream can be changed
408 // during the call
409 if (_paPlayStream &&
410 (LATE(pa_stream_get_state)(_paPlayStream) != PA_STREAM_UNCONNECTED)) {
411 deviceIndex = LATE(pa_stream_get_device_index)(_paPlayStream);
412 }
413 }
414
415 if (!GetSinkInfoByIndex(deviceIndex))
416 return -1;
417
418 available = static_cast<bool>(_paChannels == 2);
419
420 return 0;
421 }
422
StereoRecordingIsAvailable(bool & available)423 int32_t AudioMixerManagerLinuxPulse::StereoRecordingIsAvailable(
424 bool& available) {
425 RTC_DCHECK(thread_checker_.CalledOnValidThread());
426 if (_paInputDeviceIndex == -1) {
427 RTC_LOG(LS_WARNING) << "input device index has not been set";
428 return -1;
429 }
430
431 uint32_t deviceIndex = (uint32_t)_paInputDeviceIndex;
432
433 AutoPulseLock auto_lock(_paMainloop);
434
435 // Get the actual stream device index if we have a connected stream
436 // The device used by the stream can be changed
437 // during the call
438 if (_paRecStream &&
439 (LATE(pa_stream_get_state)(_paRecStream) != PA_STREAM_UNCONNECTED)) {
440 deviceIndex = LATE(pa_stream_get_device_index)(_paRecStream);
441 }
442
443 pa_operation* paOperation = NULL;
444
445 // Get info for this source
446 // We want to know if the actual device can record in stereo
447 paOperation = LATE(pa_context_get_source_info_by_index)(
448 _paContext, deviceIndex, PaSourceInfoCallback, (void*)this);
449
450 WaitForOperationCompletion(paOperation);
451
452 available = static_cast<bool>(_paChannels == 2);
453
454 RTC_LOG(LS_VERBOSE)
455 << "AudioMixerManagerLinuxPulse::StereoRecordingIsAvailable()"
456 << " => available=" << available;
457
458 return 0;
459 }
460
MicrophoneMuteIsAvailable(bool & available)461 int32_t AudioMixerManagerLinuxPulse::MicrophoneMuteIsAvailable(
462 bool& available) {
463 RTC_DCHECK(thread_checker_.CalledOnValidThread());
464 if (_paInputDeviceIndex == -1) {
465 RTC_LOG(LS_WARNING) << "input device index has not been set";
466 return -1;
467 }
468
469 // Always available in Pulse Audio
470 available = true;
471
472 return 0;
473 }
474
SetMicrophoneMute(bool enable)475 int32_t AudioMixerManagerLinuxPulse::SetMicrophoneMute(bool enable) {
476 RTC_DCHECK(thread_checker_.CalledOnValidThread());
477 RTC_LOG(LS_VERBOSE)
478 << "AudioMixerManagerLinuxPulse::SetMicrophoneMute(enable=" << enable
479 << ")";
480
481 if (_paInputDeviceIndex == -1) {
482 RTC_LOG(LS_WARNING) << "input device index has not been set";
483 return -1;
484 }
485
486 bool setFailed(false);
487 pa_operation* paOperation = NULL;
488
489 uint32_t deviceIndex = (uint32_t)_paInputDeviceIndex;
490
491 AutoPulseLock auto_lock(_paMainloop);
492
493 // Get the actual stream device index if we have a connected stream
494 // The device used by the stream can be changed
495 // during the call
496 if (_paRecStream &&
497 (LATE(pa_stream_get_state)(_paRecStream) != PA_STREAM_UNCONNECTED)) {
498 deviceIndex = LATE(pa_stream_get_device_index)(_paRecStream);
499 }
500
501 // Set mute switch for the source
502 paOperation = LATE(pa_context_set_source_mute_by_index)(
503 _paContext, deviceIndex, enable, PaSetVolumeCallback, NULL);
504
505 if (!paOperation) {
506 setFailed = true;
507 }
508
509 // Don't need to wait for this to complete.
510 LATE(pa_operation_unref)(paOperation);
511
512 if (setFailed) {
513 RTC_LOG(LS_WARNING) << "could not mute microphone, error="
514 << LATE(pa_context_errno)(_paContext);
515 return -1;
516 }
517
518 return 0;
519 }
520
MicrophoneMute(bool & enabled) const521 int32_t AudioMixerManagerLinuxPulse::MicrophoneMute(bool& enabled) const {
522 RTC_DCHECK(thread_checker_.CalledOnValidThread());
523 if (_paInputDeviceIndex == -1) {
524 RTC_LOG(LS_WARNING) << "input device index has not been set";
525 return -1;
526 }
527
528 uint32_t deviceIndex = (uint32_t)_paInputDeviceIndex;
529
530 {
531 AutoPulseLock auto_lock(_paMainloop);
532 // Get the actual stream device index if we have a connected stream
533 // The device used by the stream can be changed
534 // during the call
535 if (_paRecStream &&
536 (LATE(pa_stream_get_state)(_paRecStream) != PA_STREAM_UNCONNECTED)) {
537 deviceIndex = LATE(pa_stream_get_device_index)(_paRecStream);
538 }
539 }
540
541 if (!GetSourceInfoByIndex(deviceIndex))
542 return -1;
543
544 enabled = static_cast<bool>(_paMute);
545
546 RTC_LOG(LS_VERBOSE)
547 << "AudioMixerManagerLinuxPulse::MicrophoneMute() => enabled=" << enabled;
548
549 return 0;
550 }
551
MicrophoneVolumeIsAvailable(bool & available)552 int32_t AudioMixerManagerLinuxPulse::MicrophoneVolumeIsAvailable(
553 bool& available) {
554 RTC_DCHECK(thread_checker_.CalledOnValidThread());
555 if (_paInputDeviceIndex == -1) {
556 RTC_LOG(LS_WARNING) << "input device index has not been set";
557 return -1;
558 }
559
560 // Always available in Pulse Audio
561 available = true;
562
563 return 0;
564 }
565
SetMicrophoneVolume(uint32_t volume)566 int32_t AudioMixerManagerLinuxPulse::SetMicrophoneVolume(uint32_t volume) {
567 RTC_LOG(LS_VERBOSE)
568 << "AudioMixerManagerLinuxPulse::SetMicrophoneVolume(volume=" << volume
569 << ")";
570
571 if (_paInputDeviceIndex == -1) {
572 RTC_LOG(LS_WARNING) << "input device index has not been set";
573 return -1;
574 }
575
576 // Unlike output streams, input streams have no concept of a stream
577 // volume, only a device volume. So we have to change the volume of the
578 // device itself.
579
580 // The device may have a different number of channels than the stream and
581 // their mapping may be different, so we don't want to use the channel
582 // count from our sample spec. We could use PA_CHANNELS_MAX to cover our
583 // bases, and the server allows that even if the device's channel count
584 // is lower, but some buggy PA clients don't like that (the pavucontrol
585 // on Hardy dies in an assert if the channel count is different). So
586 // instead we look up the actual number of channels that the device has.
587 AutoPulseLock auto_lock(_paMainloop);
588 uint32_t deviceIndex = (uint32_t)_paInputDeviceIndex;
589
590 // Get the actual stream device index if we have a connected stream
591 // The device used by the stream can be changed
592 // during the call
593 if (_paRecStream &&
594 (LATE(pa_stream_get_state)(_paRecStream) != PA_STREAM_UNCONNECTED)) {
595 deviceIndex = LATE(pa_stream_get_device_index)(_paRecStream);
596 }
597
598 bool setFailed(false);
599 pa_operation* paOperation = NULL;
600
601 // Get the number of channels for this source
602 paOperation = LATE(pa_context_get_source_info_by_index)(
603 _paContext, deviceIndex, PaSourceInfoCallback, (void*)this);
604
605 WaitForOperationCompletion(paOperation);
606
607 uint8_t channels = _paChannels;
608 pa_cvolume cVolumes;
609 LATE(pa_cvolume_set)(&cVolumes, channels, volume);
610
611 // Set the volume for the source
612 paOperation = LATE(pa_context_set_source_volume_by_index)(
613 _paContext, deviceIndex, &cVolumes, PaSetVolumeCallback, NULL);
614
615 if (!paOperation) {
616 setFailed = true;
617 }
618
619 // Don't need to wait for this to complete.
620 LATE(pa_operation_unref)(paOperation);
621
622 if (setFailed) {
623 RTC_LOG(LS_WARNING) << "could not set microphone volume, error="
624 << LATE(pa_context_errno)(_paContext);
625 return -1;
626 }
627
628 return 0;
629 }
630
MicrophoneVolume(uint32_t & volume) const631 int32_t AudioMixerManagerLinuxPulse::MicrophoneVolume(uint32_t& volume) const {
632 if (_paInputDeviceIndex == -1) {
633 RTC_LOG(LS_WARNING) << "input device index has not been set";
634 return -1;
635 }
636
637 uint32_t deviceIndex = (uint32_t)_paInputDeviceIndex;
638
639 {
640 AutoPulseLock auto_lock(_paMainloop);
641 // Get the actual stream device index if we have a connected stream.
642 // The device used by the stream can be changed during the call.
643 if (_paRecStream &&
644 (LATE(pa_stream_get_state)(_paRecStream) != PA_STREAM_UNCONNECTED)) {
645 deviceIndex = LATE(pa_stream_get_device_index)(_paRecStream);
646 }
647 }
648
649 if (!GetSourceInfoByIndex(deviceIndex))
650 return -1;
651
652 {
653 AutoPulseLock auto_lock(_paMainloop);
654 volume = static_cast<uint32_t>(_paVolume);
655 }
656
657 RTC_LOG(LS_VERBOSE)
658 << "AudioMixerManagerLinuxPulse::MicrophoneVolume() => vol=" << volume;
659
660 return 0;
661 }
662
MaxMicrophoneVolume(uint32_t & maxVolume) const663 int32_t AudioMixerManagerLinuxPulse::MaxMicrophoneVolume(
664 uint32_t& maxVolume) const {
665 if (_paInputDeviceIndex == -1) {
666 RTC_LOG(LS_WARNING) << "input device index has not been set";
667 return -1;
668 }
669
670 // PA_VOLUME_NORM corresponds to 100% (0db)
671 // PA allows up to 150 db amplification (PA_VOLUME_MAX)
672 // but that doesn't work well for all sound cards
673 maxVolume = static_cast<uint32_t>(PA_VOLUME_NORM);
674
675 return 0;
676 }
677
MinMicrophoneVolume(uint32_t & minVolume) const678 int32_t AudioMixerManagerLinuxPulse::MinMicrophoneVolume(
679 uint32_t& minVolume) const {
680 if (_paInputDeviceIndex == -1) {
681 RTC_LOG(LS_WARNING) << "input device index has not been set";
682 return -1;
683 }
684
685 minVolume = static_cast<uint32_t>(PA_VOLUME_MUTED);
686
687 return 0;
688 }
689
690 // ===========================================================================
691 // Private Methods
692 // ===========================================================================
693
PaSinkInfoCallback(pa_context *,const pa_sink_info * i,int eol,void * pThis)694 void AudioMixerManagerLinuxPulse::PaSinkInfoCallback(pa_context* /*c*/,
695 const pa_sink_info* i,
696 int eol,
697 void* pThis) {
698 static_cast<AudioMixerManagerLinuxPulse*>(pThis)->PaSinkInfoCallbackHandler(
699 i, eol);
700 }
701
PaSinkInputInfoCallback(pa_context *,const pa_sink_input_info * i,int eol,void * pThis)702 void AudioMixerManagerLinuxPulse::PaSinkInputInfoCallback(
703 pa_context* /*c*/,
704 const pa_sink_input_info* i,
705 int eol,
706 void* pThis) {
707 static_cast<AudioMixerManagerLinuxPulse*>(pThis)
708 ->PaSinkInputInfoCallbackHandler(i, eol);
709 }
710
PaSourceInfoCallback(pa_context *,const pa_source_info * i,int eol,void * pThis)711 void AudioMixerManagerLinuxPulse::PaSourceInfoCallback(pa_context* /*c*/,
712 const pa_source_info* i,
713 int eol,
714 void* pThis) {
715 static_cast<AudioMixerManagerLinuxPulse*>(pThis)->PaSourceInfoCallbackHandler(
716 i, eol);
717 }
718
PaSetVolumeCallback(pa_context * c,int success,void *)719 void AudioMixerManagerLinuxPulse::PaSetVolumeCallback(pa_context* c,
720 int success,
721 void* /*pThis*/) {
722 if (!success) {
723 RTC_LOG(LS_ERROR) << "failed to set volume";
724 }
725 }
726
PaSinkInfoCallbackHandler(const pa_sink_info * i,int eol)727 void AudioMixerManagerLinuxPulse::PaSinkInfoCallbackHandler(
728 const pa_sink_info* i,
729 int eol) {
730 if (eol) {
731 // Signal that we are done
732 LATE(pa_threaded_mainloop_signal)(_paMainloop, 0);
733 return;
734 }
735
736 _paChannels = i->channel_map.channels; // Get number of channels
737 pa_volume_t paVolume = PA_VOLUME_MUTED; // Minimum possible value.
738 for (int j = 0; j < _paChannels; ++j) {
739 if (paVolume < i->volume.values[j]) {
740 paVolume = i->volume.values[j];
741 }
742 }
743 _paVolume = paVolume; // get the max volume for any channel
744 _paMute = i->mute; // get mute status
745
746 // supported since PA 0.9.15
747 //_paVolSteps = i->n_volume_steps; // get the number of volume steps
748 // default value is PA_VOLUME_NORM+1
749 _paVolSteps = PA_VOLUME_NORM + 1;
750 }
751
PaSinkInputInfoCallbackHandler(const pa_sink_input_info * i,int eol)752 void AudioMixerManagerLinuxPulse::PaSinkInputInfoCallbackHandler(
753 const pa_sink_input_info* i,
754 int eol) {
755 if (eol) {
756 // Signal that we are done
757 LATE(pa_threaded_mainloop_signal)(_paMainloop, 0);
758 return;
759 }
760
761 _paChannels = i->channel_map.channels; // Get number of channels
762 pa_volume_t paVolume = PA_VOLUME_MUTED; // Minimum possible value.
763 for (int j = 0; j < _paChannels; ++j) {
764 if (paVolume < i->volume.values[j]) {
765 paVolume = i->volume.values[j];
766 }
767 }
768 _paVolume = paVolume; // Get the max volume for any channel
769 _paMute = i->mute; // Get mute status
770 }
771
PaSourceInfoCallbackHandler(const pa_source_info * i,int eol)772 void AudioMixerManagerLinuxPulse::PaSourceInfoCallbackHandler(
773 const pa_source_info* i,
774 int eol) {
775 if (eol) {
776 // Signal that we are done
777 LATE(pa_threaded_mainloop_signal)(_paMainloop, 0);
778 return;
779 }
780
781 _paChannels = i->channel_map.channels; // Get number of channels
782 pa_volume_t paVolume = PA_VOLUME_MUTED; // Minimum possible value.
783 for (int j = 0; j < _paChannels; ++j) {
784 if (paVolume < i->volume.values[j]) {
785 paVolume = i->volume.values[j];
786 }
787 }
788 _paVolume = paVolume; // Get the max volume for any channel
789 _paMute = i->mute; // Get mute status
790
791 // supported since PA 0.9.15
792 //_paVolSteps = i->n_volume_steps; // Get the number of volume steps
793 // default value is PA_VOLUME_NORM+1
794 _paVolSteps = PA_VOLUME_NORM + 1;
795 }
796
WaitForOperationCompletion(pa_operation * paOperation) const797 void AudioMixerManagerLinuxPulse::WaitForOperationCompletion(
798 pa_operation* paOperation) const {
799 while (LATE(pa_operation_get_state)(paOperation) == PA_OPERATION_RUNNING) {
800 LATE(pa_threaded_mainloop_wait)(_paMainloop);
801 }
802
803 LATE(pa_operation_unref)(paOperation);
804 }
805
GetSinkInputInfo() const806 bool AudioMixerManagerLinuxPulse::GetSinkInputInfo() const {
807 pa_operation* paOperation = NULL;
808
809 AutoPulseLock auto_lock(_paMainloop);
810 // Get info for this stream (sink input).
811 paOperation = LATE(pa_context_get_sink_input_info)(
812 _paContext, LATE(pa_stream_get_index)(_paPlayStream),
813 PaSinkInputInfoCallback, (void*)this);
814
815 WaitForOperationCompletion(paOperation);
816 return true;
817 }
818
GetSinkInfoByIndex(int device_index) const819 bool AudioMixerManagerLinuxPulse::GetSinkInfoByIndex(int device_index) const {
820 pa_operation* paOperation = NULL;
821
822 AutoPulseLock auto_lock(_paMainloop);
823 paOperation = LATE(pa_context_get_sink_info_by_index)(
824 _paContext, device_index, PaSinkInfoCallback, (void*)this);
825
826 WaitForOperationCompletion(paOperation);
827 return true;
828 }
829
GetSourceInfoByIndex(int device_index) const830 bool AudioMixerManagerLinuxPulse::GetSourceInfoByIndex(int device_index) const {
831 pa_operation* paOperation = NULL;
832
833 AutoPulseLock auto_lock(_paMainloop);
834 paOperation = LATE(pa_context_get_source_info_by_index)(
835 _paContext, device_index, PaSourceInfoCallback, (void*)this);
836
837 WaitForOperationCompletion(paOperation);
838 return true;
839 }
840
841 } // namespace webrtc
842