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