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 "modules/audio_device/linux/audio_mixer_manager_alsa_linux.h"
12
13 #include "modules/audio_device/linux/audio_device_alsa_linux.h"
14 #include "rtc_base/logging.h"
15
16 // Accesses ALSA functions through our late-binding symbol table instead of
17 // directly. This way we don't have to link to libasound, which means our binary
18 // will work on systems that don't have it.
19 #define LATE(sym) \
20 LATESYM_GET(webrtc::adm_linux_alsa::AlsaSymbolTable, GetAlsaSymbolTable(), \
21 sym)
22
23 namespace webrtc {
24
AudioMixerManagerLinuxALSA()25 AudioMixerManagerLinuxALSA::AudioMixerManagerLinuxALSA()
26 : _outputMixerHandle(NULL),
27 _inputMixerHandle(NULL),
28 _outputMixerElement(NULL),
29 _inputMixerElement(NULL) {
30 RTC_DLOG(LS_INFO) << __FUNCTION__ << " created";
31
32 memset(_outputMixerStr, 0, kAdmMaxDeviceNameSize);
33 memset(_inputMixerStr, 0, kAdmMaxDeviceNameSize);
34 }
35
~AudioMixerManagerLinuxALSA()36 AudioMixerManagerLinuxALSA::~AudioMixerManagerLinuxALSA() {
37 RTC_DLOG(LS_INFO) << __FUNCTION__ << " destroyed";
38 Close();
39 }
40
41 // ============================================================================
42 // PUBLIC METHODS
43 // ============================================================================
44
Close()45 int32_t AudioMixerManagerLinuxALSA::Close() {
46 RTC_DLOG(LS_VERBOSE) << __FUNCTION__;
47
48 MutexLock lock(&mutex_);
49
50 CloseSpeakerLocked();
51 CloseMicrophoneLocked();
52
53 return 0;
54 }
55
CloseSpeaker()56 int32_t AudioMixerManagerLinuxALSA::CloseSpeaker() {
57 MutexLock lock(&mutex_);
58 return CloseSpeakerLocked();
59 }
60
CloseSpeakerLocked()61 int32_t AudioMixerManagerLinuxALSA::CloseSpeakerLocked() {
62 RTC_DLOG(LS_VERBOSE) << __FUNCTION__;
63
64 int errVal = 0;
65
66 if (_outputMixerHandle != NULL) {
67 RTC_LOG(LS_VERBOSE) << "Closing playout mixer";
68 LATE(snd_mixer_free)(_outputMixerHandle);
69 if (errVal < 0) {
70 RTC_LOG(LS_ERROR) << "Error freeing playout mixer: "
71 << LATE(snd_strerror)(errVal);
72 }
73 errVal = LATE(snd_mixer_detach)(_outputMixerHandle, _outputMixerStr);
74 if (errVal < 0) {
75 RTC_LOG(LS_ERROR) << "Error detaching playout mixer: "
76 << LATE(snd_strerror)(errVal);
77 }
78 errVal = LATE(snd_mixer_close)(_outputMixerHandle);
79 if (errVal < 0) {
80 RTC_LOG(LS_ERROR) << "Error snd_mixer_close(handleMixer) errVal="
81 << errVal;
82 }
83 _outputMixerHandle = NULL;
84 _outputMixerElement = NULL;
85 }
86 memset(_outputMixerStr, 0, kAdmMaxDeviceNameSize);
87
88 return 0;
89 }
90
CloseMicrophone()91 int32_t AudioMixerManagerLinuxALSA::CloseMicrophone() {
92 MutexLock lock(&mutex_);
93 return CloseMicrophoneLocked();
94 }
95
CloseMicrophoneLocked()96 int32_t AudioMixerManagerLinuxALSA::CloseMicrophoneLocked() {
97 RTC_DLOG(LS_VERBOSE) << __FUNCTION__;
98
99 int errVal = 0;
100
101 if (_inputMixerHandle != NULL) {
102 RTC_LOG(LS_VERBOSE) << "Closing record mixer";
103
104 LATE(snd_mixer_free)(_inputMixerHandle);
105 if (errVal < 0) {
106 RTC_LOG(LS_ERROR) << "Error freeing record mixer: "
107 << LATE(snd_strerror)(errVal);
108 }
109 RTC_LOG(LS_VERBOSE) << "Closing record mixer 2";
110
111 errVal = LATE(snd_mixer_detach)(_inputMixerHandle, _inputMixerStr);
112 if (errVal < 0) {
113 RTC_LOG(LS_ERROR) << "Error detaching record mixer: "
114 << LATE(snd_strerror)(errVal);
115 }
116 RTC_LOG(LS_VERBOSE) << "Closing record mixer 3";
117
118 errVal = LATE(snd_mixer_close)(_inputMixerHandle);
119 if (errVal < 0) {
120 RTC_LOG(LS_ERROR) << "Error snd_mixer_close(handleMixer) errVal="
121 << errVal;
122 }
123
124 RTC_LOG(LS_VERBOSE) << "Closing record mixer 4";
125 _inputMixerHandle = NULL;
126 _inputMixerElement = NULL;
127 }
128 memset(_inputMixerStr, 0, kAdmMaxDeviceNameSize);
129
130 return 0;
131 }
132
OpenSpeaker(char * deviceName)133 int32_t AudioMixerManagerLinuxALSA::OpenSpeaker(char* deviceName) {
134 RTC_LOG(LS_VERBOSE) << "AudioMixerManagerLinuxALSA::OpenSpeaker(name="
135 << deviceName << ")";
136
137 MutexLock lock(&mutex_);
138
139 int errVal = 0;
140
141 // Close any existing output mixer handle
142 //
143 if (_outputMixerHandle != NULL) {
144 RTC_LOG(LS_VERBOSE) << "Closing playout mixer";
145
146 LATE(snd_mixer_free)(_outputMixerHandle);
147 if (errVal < 0) {
148 RTC_LOG(LS_ERROR) << "Error freeing playout mixer: "
149 << LATE(snd_strerror)(errVal);
150 }
151 errVal = LATE(snd_mixer_detach)(_outputMixerHandle, _outputMixerStr);
152 if (errVal < 0) {
153 RTC_LOG(LS_ERROR) << "Error detaching playout mixer: "
154 << LATE(snd_strerror)(errVal);
155 }
156 errVal = LATE(snd_mixer_close)(_outputMixerHandle);
157 if (errVal < 0) {
158 RTC_LOG(LS_ERROR) << "Error snd_mixer_close(handleMixer) errVal="
159 << errVal;
160 }
161 }
162 _outputMixerHandle = NULL;
163 _outputMixerElement = NULL;
164
165 errVal = LATE(snd_mixer_open)(&_outputMixerHandle, 0);
166 if (errVal < 0) {
167 RTC_LOG(LS_ERROR) << "snd_mixer_open(&_outputMixerHandle, 0) - error";
168 return -1;
169 }
170
171 char controlName[kAdmMaxDeviceNameSize] = {0};
172 GetControlName(controlName, deviceName);
173
174 RTC_LOG(LS_VERBOSE) << "snd_mixer_attach(_outputMixerHandle, " << controlName
175 << ")";
176
177 errVal = LATE(snd_mixer_attach)(_outputMixerHandle, controlName);
178 if (errVal < 0) {
179 RTC_LOG(LS_ERROR) << "snd_mixer_attach(_outputMixerHandle, " << controlName
180 << ") error: " << LATE(snd_strerror)(errVal);
181 _outputMixerHandle = NULL;
182 return -1;
183 }
184 strcpy(_outputMixerStr, controlName);
185
186 errVal = LATE(snd_mixer_selem_register)(_outputMixerHandle, NULL, NULL);
187 if (errVal < 0) {
188 RTC_LOG(LS_ERROR)
189 << "snd_mixer_selem_register(_outputMixerHandle, NULL, NULL), "
190 "error: "
191 << LATE(snd_strerror)(errVal);
192 _outputMixerHandle = NULL;
193 return -1;
194 }
195
196 // Load and find the proper mixer element
197 if (LoadSpeakerMixerElement() < 0) {
198 return -1;
199 }
200
201 if (_outputMixerHandle != NULL) {
202 RTC_LOG(LS_VERBOSE) << "the output mixer device is now open ("
203 << _outputMixerHandle << ")";
204 }
205
206 return 0;
207 }
208
OpenMicrophone(char * deviceName)209 int32_t AudioMixerManagerLinuxALSA::OpenMicrophone(char* deviceName) {
210 RTC_LOG(LS_VERBOSE) << "AudioMixerManagerLinuxALSA::OpenMicrophone(name="
211 << deviceName << ")";
212
213 MutexLock lock(&mutex_);
214
215 int errVal = 0;
216
217 // Close any existing input mixer handle
218 //
219 if (_inputMixerHandle != NULL) {
220 RTC_LOG(LS_VERBOSE) << "Closing record mixer";
221
222 LATE(snd_mixer_free)(_inputMixerHandle);
223 if (errVal < 0) {
224 RTC_LOG(LS_ERROR) << "Error freeing record mixer: "
225 << LATE(snd_strerror)(errVal);
226 }
227 RTC_LOG(LS_VERBOSE) << "Closing record mixer";
228
229 errVal = LATE(snd_mixer_detach)(_inputMixerHandle, _inputMixerStr);
230 if (errVal < 0) {
231 RTC_LOG(LS_ERROR) << "Error detaching record mixer: "
232 << LATE(snd_strerror)(errVal);
233 }
234 RTC_LOG(LS_VERBOSE) << "Closing record mixer";
235
236 errVal = LATE(snd_mixer_close)(_inputMixerHandle);
237 if (errVal < 0) {
238 RTC_LOG(LS_ERROR) << "Error snd_mixer_close(handleMixer) errVal="
239 << errVal;
240 }
241 RTC_LOG(LS_VERBOSE) << "Closing record mixer";
242 }
243 _inputMixerHandle = NULL;
244 _inputMixerElement = NULL;
245
246 errVal = LATE(snd_mixer_open)(&_inputMixerHandle, 0);
247 if (errVal < 0) {
248 RTC_LOG(LS_ERROR) << "snd_mixer_open(&_inputMixerHandle, 0) - error";
249 return -1;
250 }
251
252 char controlName[kAdmMaxDeviceNameSize] = {0};
253 GetControlName(controlName, deviceName);
254
255 RTC_LOG(LS_VERBOSE) << "snd_mixer_attach(_inputMixerHandle, " << controlName
256 << ")";
257
258 errVal = LATE(snd_mixer_attach)(_inputMixerHandle, controlName);
259 if (errVal < 0) {
260 RTC_LOG(LS_ERROR) << "snd_mixer_attach(_inputMixerHandle, " << controlName
261 << ") error: " << LATE(snd_strerror)(errVal);
262
263 _inputMixerHandle = NULL;
264 return -1;
265 }
266 strcpy(_inputMixerStr, controlName);
267
268 errVal = LATE(snd_mixer_selem_register)(_inputMixerHandle, NULL, NULL);
269 if (errVal < 0) {
270 RTC_LOG(LS_ERROR)
271 << "snd_mixer_selem_register(_inputMixerHandle, NULL, NULL), "
272 "error: "
273 << LATE(snd_strerror)(errVal);
274
275 _inputMixerHandle = NULL;
276 return -1;
277 }
278 // Load and find the proper mixer element
279 if (LoadMicMixerElement() < 0) {
280 return -1;
281 }
282
283 if (_inputMixerHandle != NULL) {
284 RTC_LOG(LS_VERBOSE) << "the input mixer device is now open ("
285 << _inputMixerHandle << ")";
286 }
287
288 return 0;
289 }
290
SpeakerIsInitialized() const291 bool AudioMixerManagerLinuxALSA::SpeakerIsInitialized() const {
292 RTC_DLOG(LS_INFO) << __FUNCTION__;
293
294 return (_outputMixerHandle != NULL);
295 }
296
MicrophoneIsInitialized() const297 bool AudioMixerManagerLinuxALSA::MicrophoneIsInitialized() const {
298 RTC_DLOG(LS_INFO) << __FUNCTION__;
299
300 return (_inputMixerHandle != NULL);
301 }
302
SetSpeakerVolume(uint32_t volume)303 int32_t AudioMixerManagerLinuxALSA::SetSpeakerVolume(uint32_t volume) {
304 RTC_LOG(LS_VERBOSE) << "AudioMixerManagerLinuxALSA::SetSpeakerVolume(volume="
305 << volume << ")";
306
307 MutexLock lock(&mutex_);
308
309 if (_outputMixerElement == NULL) {
310 RTC_LOG(LS_WARNING) << "no avaliable output mixer element exists";
311 return -1;
312 }
313
314 int errVal = LATE(snd_mixer_selem_set_playback_volume_all)(
315 _outputMixerElement, volume);
316 if (errVal < 0) {
317 RTC_LOG(LS_ERROR) << "Error changing master volume: "
318 << LATE(snd_strerror)(errVal);
319 return -1;
320 }
321
322 return (0);
323 }
324
SpeakerVolume(uint32_t & volume) const325 int32_t AudioMixerManagerLinuxALSA::SpeakerVolume(uint32_t& volume) const {
326 if (_outputMixerElement == NULL) {
327 RTC_LOG(LS_WARNING) << "no avaliable output mixer element exists";
328 return -1;
329 }
330
331 long int vol(0);
332
333 int errVal = LATE(snd_mixer_selem_get_playback_volume)(
334 _outputMixerElement, (snd_mixer_selem_channel_id_t)0, &vol);
335 if (errVal < 0) {
336 RTC_LOG(LS_ERROR) << "Error getting outputvolume: "
337 << LATE(snd_strerror)(errVal);
338 return -1;
339 }
340 RTC_LOG(LS_VERBOSE) << "AudioMixerManagerLinuxALSA::SpeakerVolume() => vol="
341 << vol;
342
343 volume = static_cast<uint32_t>(vol);
344
345 return 0;
346 }
347
MaxSpeakerVolume(uint32_t & maxVolume) const348 int32_t AudioMixerManagerLinuxALSA::MaxSpeakerVolume(
349 uint32_t& maxVolume) const {
350 if (_outputMixerElement == NULL) {
351 RTC_LOG(LS_WARNING) << "no avilable output mixer element exists";
352 return -1;
353 }
354
355 long int minVol(0);
356 long int maxVol(0);
357
358 int errVal = LATE(snd_mixer_selem_get_playback_volume_range)(
359 _outputMixerElement, &minVol, &maxVol);
360
361 RTC_LOG(LS_VERBOSE) << "Playout hardware volume range, min: " << minVol
362 << ", max: " << maxVol;
363
364 if (maxVol <= minVol) {
365 RTC_LOG(LS_ERROR) << "Error getting get_playback_volume_range: "
366 << LATE(snd_strerror)(errVal);
367 }
368
369 maxVolume = static_cast<uint32_t>(maxVol);
370
371 return 0;
372 }
373
MinSpeakerVolume(uint32_t & minVolume) const374 int32_t AudioMixerManagerLinuxALSA::MinSpeakerVolume(
375 uint32_t& minVolume) const {
376 if (_outputMixerElement == NULL) {
377 RTC_LOG(LS_WARNING) << "no avaliable output mixer element exists";
378 return -1;
379 }
380
381 long int minVol(0);
382 long int maxVol(0);
383
384 int errVal = LATE(snd_mixer_selem_get_playback_volume_range)(
385 _outputMixerElement, &minVol, &maxVol);
386
387 RTC_LOG(LS_VERBOSE) << "Playout hardware volume range, min: " << minVol
388 << ", max: " << maxVol;
389
390 if (maxVol <= minVol) {
391 RTC_LOG(LS_ERROR) << "Error getting get_playback_volume_range: "
392 << LATE(snd_strerror)(errVal);
393 }
394
395 minVolume = static_cast<uint32_t>(minVol);
396
397 return 0;
398 }
399
400 // TL: Have done testnig with these but they don't seem reliable and
401 // they were therefore not added
402 /*
403 // ----------------------------------------------------------------------------
404 // SetMaxSpeakerVolume
405 // ----------------------------------------------------------------------------
406
407 int32_t AudioMixerManagerLinuxALSA::SetMaxSpeakerVolume(
408 uint32_t maxVolume)
409 {
410
411 if (_outputMixerElement == NULL)
412 {
413 RTC_LOG(LS_WARNING) << "no avaliable output mixer element exists";
414 return -1;
415 }
416
417 long int minVol(0);
418 long int maxVol(0);
419
420 int errVal = snd_mixer_selem_get_playback_volume_range(
421 _outputMixerElement, &minVol, &maxVol);
422 if ((maxVol <= minVol) || (errVal != 0))
423 {
424 RTC_LOG(LS_WARNING) << "Error getting playback volume range: "
425 << snd_strerror(errVal);
426 }
427
428 maxVol = maxVolume;
429 errVal = snd_mixer_selem_set_playback_volume_range(
430 _outputMixerElement, minVol, maxVol);
431 RTC_LOG(LS_VERBOSE) << "Playout hardware volume range, min: " << minVol
432 << ", max: " << maxVol;
433 if (errVal != 0)
434 {
435 RTC_LOG(LS_ERROR) << "Error setting playback volume range: "
436 << snd_strerror(errVal);
437 return -1;
438 }
439
440 return 0;
441 }
442
443 // ----------------------------------------------------------------------------
444 // SetMinSpeakerVolume
445 // ----------------------------------------------------------------------------
446
447 int32_t AudioMixerManagerLinuxALSA::SetMinSpeakerVolume(
448 uint32_t minVolume)
449 {
450
451 if (_outputMixerElement == NULL)
452 {
453 RTC_LOG(LS_WARNING) << "no avaliable output mixer element exists";
454 return -1;
455 }
456
457 long int minVol(0);
458 long int maxVol(0);
459
460 int errVal = snd_mixer_selem_get_playback_volume_range(
461 _outputMixerElement, &minVol, &maxVol);
462 if ((maxVol <= minVol) || (errVal != 0))
463 {
464 RTC_LOG(LS_WARNING) << "Error getting playback volume range: "
465 << snd_strerror(errVal);
466 }
467
468 minVol = minVolume;
469 errVal = snd_mixer_selem_set_playback_volume_range(
470 _outputMixerElement, minVol, maxVol);
471 RTC_LOG(LS_VERBOSE) << "Playout hardware volume range, min: " << minVol
472 << ", max: " << maxVol;
473 if (errVal != 0)
474 {
475 RTC_LOG(LS_ERROR) << "Error setting playback volume range: "
476 << snd_strerror(errVal);
477 return -1;
478 }
479
480 return 0;
481 }
482 */
483
SpeakerVolumeIsAvailable(bool & available)484 int32_t AudioMixerManagerLinuxALSA::SpeakerVolumeIsAvailable(bool& available) {
485 if (_outputMixerElement == NULL) {
486 RTC_LOG(LS_WARNING) << "no avaliable output mixer element exists";
487 return -1;
488 }
489
490 available = LATE(snd_mixer_selem_has_playback_volume)(_outputMixerElement);
491
492 return 0;
493 }
494
SpeakerMuteIsAvailable(bool & available)495 int32_t AudioMixerManagerLinuxALSA::SpeakerMuteIsAvailable(bool& available) {
496 if (_outputMixerElement == NULL) {
497 RTC_LOG(LS_WARNING) << "no avaliable output mixer element exists";
498 return -1;
499 }
500
501 available = LATE(snd_mixer_selem_has_playback_switch)(_outputMixerElement);
502
503 return 0;
504 }
505
SetSpeakerMute(bool enable)506 int32_t AudioMixerManagerLinuxALSA::SetSpeakerMute(bool enable) {
507 RTC_LOG(LS_VERBOSE) << "AudioMixerManagerLinuxALSA::SetSpeakerMute(enable="
508 << enable << ")";
509
510 MutexLock lock(&mutex_);
511
512 if (_outputMixerElement == NULL) {
513 RTC_LOG(LS_WARNING) << "no avaliable output mixer element exists";
514 return -1;
515 }
516
517 // Ensure that the selected speaker destination has a valid mute control.
518 bool available(false);
519 SpeakerMuteIsAvailable(available);
520 if (!available) {
521 RTC_LOG(LS_WARNING) << "it is not possible to mute the speaker";
522 return -1;
523 }
524
525 // Note value = 0 (off) means muted
526 int errVal = LATE(snd_mixer_selem_set_playback_switch_all)(
527 _outputMixerElement, !enable);
528 if (errVal < 0) {
529 RTC_LOG(LS_ERROR) << "Error setting playback switch: "
530 << LATE(snd_strerror)(errVal);
531 return -1;
532 }
533
534 return (0);
535 }
536
SpeakerMute(bool & enabled) const537 int32_t AudioMixerManagerLinuxALSA::SpeakerMute(bool& enabled) const {
538 if (_outputMixerElement == NULL) {
539 RTC_LOG(LS_WARNING) << "no avaliable output mixer exists";
540 return -1;
541 }
542
543 // Ensure that the selected speaker destination has a valid mute control.
544 bool available =
545 LATE(snd_mixer_selem_has_playback_switch)(_outputMixerElement);
546 if (!available) {
547 RTC_LOG(LS_WARNING) << "it is not possible to mute the speaker";
548 return -1;
549 }
550
551 int value(false);
552
553 // Retrieve one boolean control value for a specified mute-control
554 //
555 int errVal = LATE(snd_mixer_selem_get_playback_switch)(
556 _outputMixerElement, (snd_mixer_selem_channel_id_t)0, &value);
557 if (errVal < 0) {
558 RTC_LOG(LS_ERROR) << "Error getting playback switch: "
559 << LATE(snd_strerror)(errVal);
560 return -1;
561 }
562
563 // Note value = 0 (off) means muted
564 enabled = (bool)!value;
565
566 return 0;
567 }
568
MicrophoneMuteIsAvailable(bool & available)569 int32_t AudioMixerManagerLinuxALSA::MicrophoneMuteIsAvailable(bool& available) {
570 if (_inputMixerElement == NULL) {
571 RTC_LOG(LS_WARNING) << "no avaliable input mixer element exists";
572 return -1;
573 }
574
575 available = LATE(snd_mixer_selem_has_capture_switch)(_inputMixerElement);
576 return 0;
577 }
578
SetMicrophoneMute(bool enable)579 int32_t AudioMixerManagerLinuxALSA::SetMicrophoneMute(bool enable) {
580 RTC_LOG(LS_VERBOSE) << "AudioMixerManagerLinuxALSA::SetMicrophoneMute(enable="
581 << enable << ")";
582
583 MutexLock lock(&mutex_);
584
585 if (_inputMixerElement == NULL) {
586 RTC_LOG(LS_WARNING) << "no avaliable input mixer element exists";
587 return -1;
588 }
589
590 // Ensure that the selected microphone destination has a valid mute control.
591 bool available(false);
592 MicrophoneMuteIsAvailable(available);
593 if (!available) {
594 RTC_LOG(LS_WARNING) << "it is not possible to mute the microphone";
595 return -1;
596 }
597
598 // Note value = 0 (off) means muted
599 int errVal =
600 LATE(snd_mixer_selem_set_capture_switch_all)(_inputMixerElement, !enable);
601 if (errVal < 0) {
602 RTC_LOG(LS_ERROR) << "Error setting capture switch: "
603 << LATE(snd_strerror)(errVal);
604 return -1;
605 }
606
607 return (0);
608 }
609
MicrophoneMute(bool & enabled) const610 int32_t AudioMixerManagerLinuxALSA::MicrophoneMute(bool& enabled) const {
611 if (_inputMixerElement == NULL) {
612 RTC_LOG(LS_WARNING) << "no avaliable input mixer exists";
613 return -1;
614 }
615
616 // Ensure that the selected microphone destination has a valid mute control.
617 bool available = LATE(snd_mixer_selem_has_capture_switch)(_inputMixerElement);
618 if (!available) {
619 RTC_LOG(LS_WARNING) << "it is not possible to mute the microphone";
620 return -1;
621 }
622
623 int value(false);
624
625 // Retrieve one boolean control value for a specified mute-control
626 //
627 int errVal = LATE(snd_mixer_selem_get_capture_switch)(
628 _inputMixerElement, (snd_mixer_selem_channel_id_t)0, &value);
629 if (errVal < 0) {
630 RTC_LOG(LS_ERROR) << "Error getting capture switch: "
631 << LATE(snd_strerror)(errVal);
632 return -1;
633 }
634
635 // Note value = 0 (off) means muted
636 enabled = (bool)!value;
637
638 return 0;
639 }
640
MicrophoneVolumeIsAvailable(bool & available)641 int32_t AudioMixerManagerLinuxALSA::MicrophoneVolumeIsAvailable(
642 bool& available) {
643 if (_inputMixerElement == NULL) {
644 RTC_LOG(LS_WARNING) << "no avaliable input mixer element exists";
645 return -1;
646 }
647
648 available = LATE(snd_mixer_selem_has_capture_volume)(_inputMixerElement);
649
650 return 0;
651 }
652
SetMicrophoneVolume(uint32_t volume)653 int32_t AudioMixerManagerLinuxALSA::SetMicrophoneVolume(uint32_t volume) {
654 RTC_LOG(LS_VERBOSE)
655 << "AudioMixerManagerLinuxALSA::SetMicrophoneVolume(volume=" << volume
656 << ")";
657
658 MutexLock lock(&mutex_);
659
660 if (_inputMixerElement == NULL) {
661 RTC_LOG(LS_WARNING) << "no avaliable input mixer element exists";
662 return -1;
663 }
664
665 int errVal =
666 LATE(snd_mixer_selem_set_capture_volume_all)(_inputMixerElement, volume);
667 if (errVal < 0) {
668 RTC_LOG(LS_ERROR) << "Error changing microphone volume: "
669 << LATE(snd_strerror)(errVal);
670 return -1;
671 }
672
673 return (0);
674 }
675
676 // TL: Have done testnig with these but they don't seem reliable and
677 // they were therefore not added
678 /*
679 // ----------------------------------------------------------------------------
680 // SetMaxMicrophoneVolume
681 // ----------------------------------------------------------------------------
682
683 int32_t AudioMixerManagerLinuxALSA::SetMaxMicrophoneVolume(
684 uint32_t maxVolume)
685 {
686
687 if (_inputMixerElement == NULL)
688 {
689 RTC_LOG(LS_WARNING) << "no avaliable output mixer element exists";
690 return -1;
691 }
692
693 long int minVol(0);
694 long int maxVol(0);
695
696 int errVal = snd_mixer_selem_get_capture_volume_range(_inputMixerElement,
697 &minVol, &maxVol);
698 if ((maxVol <= minVol) || (errVal != 0))
699 {
700 RTC_LOG(LS_WARNING) << "Error getting capture volume range: "
701 << snd_strerror(errVal);
702 }
703
704 maxVol = (long int)maxVolume;
705 printf("min %d max %d", minVol, maxVol);
706 errVal = snd_mixer_selem_set_capture_volume_range(_inputMixerElement, minVol,
707 maxVol); RTC_LOG(LS_VERBOSE) << "Capture hardware volume range, min: " <<
708 minVol
709 << ", max: " << maxVol;
710 if (errVal != 0)
711 {
712 RTC_LOG(LS_ERROR) << "Error setting capture volume range: "
713 << snd_strerror(errVal);
714 return -1;
715 }
716
717 return 0;
718 }
719
720 // ----------------------------------------------------------------------------
721 // SetMinMicrophoneVolume
722 // ----------------------------------------------------------------------------
723
724 int32_t AudioMixerManagerLinuxALSA::SetMinMicrophoneVolume(
725 uint32_t minVolume)
726 {
727
728 if (_inputMixerElement == NULL)
729 {
730 RTC_LOG(LS_WARNING) << "no avaliable output mixer element exists";
731 return -1;
732 }
733
734 long int minVol(0);
735 long int maxVol(0);
736
737 int errVal = snd_mixer_selem_get_capture_volume_range(
738 _inputMixerElement, &minVol, &maxVol);
739 if (maxVol <= minVol)
740 {
741 //maxVol = 255;
742 RTC_LOG(LS_WARNING) << "Error getting capture volume range: "
743 << snd_strerror(errVal);
744 }
745
746 printf("min %d max %d", minVol, maxVol);
747 minVol = (long int)minVolume;
748 errVal = snd_mixer_selem_set_capture_volume_range(
749 _inputMixerElement, minVol, maxVol);
750 RTC_LOG(LS_VERBOSE) << "Capture hardware volume range, min: " << minVol
751 << ", max: " << maxVol;
752 if (errVal != 0)
753 {
754 RTC_LOG(LS_ERROR) << "Error setting capture volume range: "
755 << snd_strerror(errVal);
756 return -1;
757 }
758
759 return 0;
760 }
761 */
762
MicrophoneVolume(uint32_t & volume) const763 int32_t AudioMixerManagerLinuxALSA::MicrophoneVolume(uint32_t& volume) const {
764 if (_inputMixerElement == NULL) {
765 RTC_LOG(LS_WARNING) << "no avaliable input mixer element exists";
766 return -1;
767 }
768
769 long int vol(0);
770
771 int errVal = LATE(snd_mixer_selem_get_capture_volume)(
772 _inputMixerElement, (snd_mixer_selem_channel_id_t)0, &vol);
773 if (errVal < 0) {
774 RTC_LOG(LS_ERROR) << "Error getting inputvolume: "
775 << LATE(snd_strerror)(errVal);
776 return -1;
777 }
778 RTC_LOG(LS_VERBOSE)
779 << "AudioMixerManagerLinuxALSA::MicrophoneVolume() => vol=" << vol;
780
781 volume = static_cast<uint32_t>(vol);
782
783 return 0;
784 }
785
MaxMicrophoneVolume(uint32_t & maxVolume) const786 int32_t AudioMixerManagerLinuxALSA::MaxMicrophoneVolume(
787 uint32_t& maxVolume) const {
788 if (_inputMixerElement == NULL) {
789 RTC_LOG(LS_WARNING) << "no avaliable input mixer element exists";
790 return -1;
791 }
792
793 long int minVol(0);
794 long int maxVol(0);
795
796 // check if we have mic volume at all
797 if (!LATE(snd_mixer_selem_has_capture_volume)(_inputMixerElement)) {
798 RTC_LOG(LS_ERROR) << "No microphone volume available";
799 return -1;
800 }
801
802 int errVal = LATE(snd_mixer_selem_get_capture_volume_range)(
803 _inputMixerElement, &minVol, &maxVol);
804
805 RTC_LOG(LS_VERBOSE) << "Microphone hardware volume range, min: " << minVol
806 << ", max: " << maxVol;
807 if (maxVol <= minVol) {
808 RTC_LOG(LS_ERROR) << "Error getting microphone volume range: "
809 << LATE(snd_strerror)(errVal);
810 }
811
812 maxVolume = static_cast<uint32_t>(maxVol);
813
814 return 0;
815 }
816
MinMicrophoneVolume(uint32_t & minVolume) const817 int32_t AudioMixerManagerLinuxALSA::MinMicrophoneVolume(
818 uint32_t& minVolume) const {
819 if (_inputMixerElement == NULL) {
820 RTC_LOG(LS_WARNING) << "no avaliable input mixer element exists";
821 return -1;
822 }
823
824 long int minVol(0);
825 long int maxVol(0);
826
827 int errVal = LATE(snd_mixer_selem_get_capture_volume_range)(
828 _inputMixerElement, &minVol, &maxVol);
829
830 RTC_LOG(LS_VERBOSE) << "Microphone hardware volume range, min: " << minVol
831 << ", max: " << maxVol;
832 if (maxVol <= minVol) {
833 RTC_LOG(LS_ERROR) << "Error getting microphone volume range: "
834 << LATE(snd_strerror)(errVal);
835 }
836
837 minVolume = static_cast<uint32_t>(minVol);
838
839 return 0;
840 }
841
842 // ============================================================================
843 // Private Methods
844 // ============================================================================
845
LoadMicMixerElement() const846 int32_t AudioMixerManagerLinuxALSA::LoadMicMixerElement() const {
847 int errVal = LATE(snd_mixer_load)(_inputMixerHandle);
848 if (errVal < 0) {
849 RTC_LOG(LS_ERROR) << "snd_mixer_load(_inputMixerHandle), error: "
850 << LATE(snd_strerror)(errVal);
851 _inputMixerHandle = NULL;
852 return -1;
853 }
854
855 snd_mixer_elem_t* elem = NULL;
856 snd_mixer_elem_t* micElem = NULL;
857 unsigned mixerIdx = 0;
858 const char* selemName = NULL;
859
860 // Find and store handles to the right mixer elements
861 for (elem = LATE(snd_mixer_first_elem)(_inputMixerHandle); elem;
862 elem = LATE(snd_mixer_elem_next)(elem), mixerIdx++) {
863 if (LATE(snd_mixer_selem_is_active)(elem)) {
864 selemName = LATE(snd_mixer_selem_get_name)(elem);
865 if (strcmp(selemName, "Capture") == 0) // "Capture", "Mic"
866 {
867 _inputMixerElement = elem;
868 RTC_LOG(LS_VERBOSE) << "Capture element set";
869 } else if (strcmp(selemName, "Mic") == 0) {
870 micElem = elem;
871 RTC_LOG(LS_VERBOSE) << "Mic element found";
872 }
873 }
874
875 if (_inputMixerElement) {
876 // Use the first Capture element that is found
877 // The second one may not work
878 break;
879 }
880 }
881
882 if (_inputMixerElement == NULL) {
883 // We didn't find a Capture handle, use Mic.
884 if (micElem != NULL) {
885 _inputMixerElement = micElem;
886 RTC_LOG(LS_VERBOSE) << "Using Mic as capture volume.";
887 } else {
888 _inputMixerElement = NULL;
889 RTC_LOG(LS_ERROR) << "Could not find capture volume on the mixer.";
890
891 return -1;
892 }
893 }
894
895 return 0;
896 }
897
LoadSpeakerMixerElement() const898 int32_t AudioMixerManagerLinuxALSA::LoadSpeakerMixerElement() const {
899 int errVal = LATE(snd_mixer_load)(_outputMixerHandle);
900 if (errVal < 0) {
901 RTC_LOG(LS_ERROR) << "snd_mixer_load(_outputMixerHandle), error: "
902 << LATE(snd_strerror)(errVal);
903 _outputMixerHandle = NULL;
904 return -1;
905 }
906
907 snd_mixer_elem_t* elem = NULL;
908 snd_mixer_elem_t* masterElem = NULL;
909 snd_mixer_elem_t* speakerElem = NULL;
910 unsigned mixerIdx = 0;
911 const char* selemName = NULL;
912
913 // Find and store handles to the right mixer elements
914 for (elem = LATE(snd_mixer_first_elem)(_outputMixerHandle); elem;
915 elem = LATE(snd_mixer_elem_next)(elem), mixerIdx++) {
916 if (LATE(snd_mixer_selem_is_active)(elem)) {
917 selemName = LATE(snd_mixer_selem_get_name)(elem);
918 RTC_LOG(LS_VERBOSE) << "snd_mixer_selem_get_name " << mixerIdx << ": "
919 << selemName << " =" << elem;
920
921 // "Master", "PCM", "Wave", "Master Mono", "PC Speaker", "PCM", "Wave"
922 if (strcmp(selemName, "PCM") == 0) {
923 _outputMixerElement = elem;
924 RTC_LOG(LS_VERBOSE) << "PCM element set";
925 } else if (strcmp(selemName, "Master") == 0) {
926 masterElem = elem;
927 RTC_LOG(LS_VERBOSE) << "Master element found";
928 } else if (strcmp(selemName, "Speaker") == 0) {
929 speakerElem = elem;
930 RTC_LOG(LS_VERBOSE) << "Speaker element found";
931 }
932 }
933
934 if (_outputMixerElement) {
935 // We have found the element we want
936 break;
937 }
938 }
939
940 // If we didn't find a PCM Handle, use Master or Speaker
941 if (_outputMixerElement == NULL) {
942 if (masterElem != NULL) {
943 _outputMixerElement = masterElem;
944 RTC_LOG(LS_VERBOSE) << "Using Master as output volume.";
945 } else if (speakerElem != NULL) {
946 _outputMixerElement = speakerElem;
947 RTC_LOG(LS_VERBOSE) << "Using Speaker as output volume.";
948 } else {
949 _outputMixerElement = NULL;
950 RTC_LOG(LS_ERROR) << "Could not find output volume in the mixer.";
951 return -1;
952 }
953 }
954
955 return 0;
956 }
957
GetControlName(char * controlName,char * deviceName) const958 void AudioMixerManagerLinuxALSA::GetControlName(char* controlName,
959 char* deviceName) const {
960 // Example
961 // deviceName: "front:CARD=Intel,DEV=0"
962 // controlName: "hw:CARD=Intel"
963 char* pos1 = strchr(deviceName, ':');
964 char* pos2 = strchr(deviceName, ',');
965 if (!pos2) {
966 // Can also be default:CARD=Intel
967 pos2 = &deviceName[strlen(deviceName)];
968 }
969 if (pos1 && pos2) {
970 strcpy(controlName, "hw");
971 int nChar = (int)(pos2 - pos1);
972 strncpy(&controlName[2], pos1, nChar);
973 controlName[2 + nChar] = '\0';
974 } else {
975 strcpy(controlName, deviceName);
976 }
977 }
978
979 } // namespace webrtc
980