1 /*
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include <assert.h>
12
13 #include "webrtc/modules/audio_device/linux/audio_mixer_manager_alsa_linux.h"
14 #include "webrtc/system_wrappers/include/trace.h"
15
16 extern webrtc_adm_linux_alsa::AlsaSymbolTable AlsaSymbolTable;
17
18 // Accesses ALSA functions through our late-binding symbol table instead of
19 // directly. This way we don't have to link to libalsa, which means our binary
20 // will work on systems that don't have it.
21 #define LATE(sym) \
22 LATESYM_GET(webrtc_adm_linux_alsa::AlsaSymbolTable, &AlsaSymbolTable, sym)
23
24 namespace webrtc
25 {
26
AudioMixerManagerLinuxALSA(const int32_t id)27 AudioMixerManagerLinuxALSA::AudioMixerManagerLinuxALSA(const int32_t id) :
28 _critSect(*CriticalSectionWrapper::CreateCriticalSection()),
29 _id(id),
30 _outputMixerHandle(NULL),
31 _inputMixerHandle(NULL),
32 _outputMixerElement(NULL),
33 _inputMixerElement(NULL)
34 {
35 WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id,
36 "%s constructed", __FUNCTION__);
37
38 memset(_outputMixerStr, 0, kAdmMaxDeviceNameSize);
39 memset(_inputMixerStr, 0, kAdmMaxDeviceNameSize);
40 }
41
~AudioMixerManagerLinuxALSA()42 AudioMixerManagerLinuxALSA::~AudioMixerManagerLinuxALSA()
43 {
44 WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id,
45 "%s destructed", __FUNCTION__);
46
47 Close();
48
49 delete &_critSect;
50 }
51
52 // ============================================================================
53 // PUBLIC METHODS
54 // ============================================================================
55
Close()56 int32_t AudioMixerManagerLinuxALSA::Close()
57 {
58 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s",
59 __FUNCTION__);
60
61 CriticalSectionScoped lock(&_critSect);
62
63 CloseSpeaker();
64 CloseMicrophone();
65
66 return 0;
67
68 }
69
CloseSpeaker()70 int32_t AudioMixerManagerLinuxALSA::CloseSpeaker()
71 {
72 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s",
73 __FUNCTION__);
74
75 CriticalSectionScoped lock(&_critSect);
76
77 int errVal = 0;
78
79 if (_outputMixerHandle != NULL)
80 {
81 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
82 "Closing playout mixer");
83 LATE(snd_mixer_free)(_outputMixerHandle);
84 if (errVal < 0)
85 {
86 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
87 " Error freeing playout mixer: %s",
88 LATE(snd_strerror)(errVal));
89 }
90 errVal = LATE(snd_mixer_detach)(_outputMixerHandle, _outputMixerStr);
91 if (errVal < 0)
92 {
93 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
94 " Error detachinging playout mixer: %s",
95 LATE(snd_strerror)(errVal));
96 }
97 errVal = LATE(snd_mixer_close)(_outputMixerHandle);
98 if (errVal < 0)
99 {
100 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
101 " Error snd_mixer_close(handleMixer) errVal=%d",
102 errVal);
103 }
104 _outputMixerHandle = NULL;
105 _outputMixerElement = NULL;
106 }
107 memset(_outputMixerStr, 0, kAdmMaxDeviceNameSize);
108
109 return 0;
110 }
111
CloseMicrophone()112 int32_t AudioMixerManagerLinuxALSA::CloseMicrophone()
113 {
114 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", __FUNCTION__);
115
116 CriticalSectionScoped lock(&_critSect);
117
118 int errVal = 0;
119
120 if (_inputMixerHandle != NULL)
121 {
122 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
123 "Closing record mixer");
124
125 LATE(snd_mixer_free)(_inputMixerHandle);
126 if (errVal < 0)
127 {
128 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
129 " Error freeing record mixer: %s",
130 LATE(snd_strerror)(errVal));
131 }
132 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
133 "Closing record mixer 2");
134
135 errVal = LATE(snd_mixer_detach)(_inputMixerHandle, _inputMixerStr);
136 if (errVal < 0)
137 {
138 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
139 " Error detachinging record mixer: %s",
140 LATE(snd_strerror)(errVal));
141 }
142 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
143 "Closing record mixer 3");
144
145 errVal = LATE(snd_mixer_close)(_inputMixerHandle);
146 if (errVal < 0)
147 {
148 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
149 " Error snd_mixer_close(handleMixer) errVal=%d",
150 errVal);
151 }
152
153 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
154 "Closing record mixer 4");
155 _inputMixerHandle = NULL;
156 _inputMixerElement = NULL;
157 }
158 memset(_inputMixerStr, 0, kAdmMaxDeviceNameSize);
159
160 return 0;
161 }
162
OpenSpeaker(char * deviceName)163 int32_t AudioMixerManagerLinuxALSA::OpenSpeaker(char* deviceName)
164 {
165 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
166 "AudioMixerManagerLinuxALSA::OpenSpeaker(name=%s)", deviceName);
167
168 CriticalSectionScoped lock(&_critSect);
169
170 int errVal = 0;
171
172 // Close any existing output mixer handle
173 //
174 if (_outputMixerHandle != NULL)
175 {
176 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
177 "Closing playout mixer");
178
179 LATE(snd_mixer_free)(_outputMixerHandle);
180 if (errVal < 0)
181 {
182 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
183 " Error freeing playout mixer: %s",
184 LATE(snd_strerror)(errVal));
185 }
186 errVal = LATE(snd_mixer_detach)(_outputMixerHandle, _outputMixerStr);
187 if (errVal < 0)
188 {
189 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
190 " Error detachinging playout mixer: %s",
191 LATE(snd_strerror)(errVal));
192 }
193 errVal = LATE(snd_mixer_close)(_outputMixerHandle);
194 if (errVal < 0)
195 {
196 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
197 " Error snd_mixer_close(handleMixer) errVal=%d",
198 errVal);
199 }
200 }
201 _outputMixerHandle = NULL;
202 _outputMixerElement = NULL;
203
204 errVal = LATE(snd_mixer_open)(&_outputMixerHandle, 0);
205 if (errVal < 0)
206 {
207 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
208 "snd_mixer_open(&_outputMixerHandle, 0) - error");
209 return -1;
210 }
211
212 char controlName[kAdmMaxDeviceNameSize] = { 0 };
213 GetControlName(controlName, deviceName);
214
215 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
216 " snd_mixer_attach(_outputMixerHandle, %s)", controlName);
217
218 errVal = LATE(snd_mixer_attach)(_outputMixerHandle, controlName);
219 if (errVal < 0)
220 {
221 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
222 " snd_mixer_attach(_outputMixerHandle, %s) error: %s",
223 controlName, LATE(snd_strerror)(errVal));
224 _outputMixerHandle = NULL;
225 return -1;
226 }
227 strcpy(_outputMixerStr, controlName);
228
229 errVal = LATE(snd_mixer_selem_register)(_outputMixerHandle, NULL, NULL);
230 if (errVal < 0)
231 {
232 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
233 " snd_mixer_selem_register(_outputMixerHandle,"
234 " NULL, NULL), error: %s",
235 LATE(snd_strerror)(errVal));
236 _outputMixerHandle = NULL;
237 return -1;
238 }
239
240 // Load and find the proper mixer element
241 if (LoadSpeakerMixerElement() < 0)
242 {
243 return -1;
244 }
245
246 if (_outputMixerHandle != NULL)
247 {
248 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
249 " the output mixer device is now open (0x%x)",
250 _outputMixerHandle);
251 }
252
253 return 0;
254 }
255
OpenMicrophone(char * deviceName)256 int32_t AudioMixerManagerLinuxALSA::OpenMicrophone(char *deviceName)
257 {
258 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
259 "AudioMixerManagerLinuxALSA::OpenMicrophone(name=%s)",
260 deviceName);
261
262 CriticalSectionScoped lock(&_critSect);
263
264 int errVal = 0;
265
266 // Close any existing input mixer handle
267 //
268 if (_inputMixerHandle != NULL)
269 {
270 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
271 "Closing record mixer");
272
273 LATE(snd_mixer_free)(_inputMixerHandle);
274 if (errVal < 0)
275 {
276 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
277 " Error freeing record mixer: %s",
278 LATE(snd_strerror)(errVal));
279 }
280 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
281 "Closing record mixer");
282
283 errVal = LATE(snd_mixer_detach)(_inputMixerHandle, _inputMixerStr);
284 if (errVal < 0)
285 {
286 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
287 " Error detachinging record mixer: %s",
288 LATE(snd_strerror)(errVal));
289 }
290 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
291 "Closing record mixer");
292
293 errVal = LATE(snd_mixer_close)(_inputMixerHandle);
294 if (errVal < 0)
295 {
296 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
297 " Error snd_mixer_close(handleMixer) errVal=%d",
298 errVal);
299 }
300 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
301 "Closing record mixer");
302 }
303 _inputMixerHandle = NULL;
304 _inputMixerElement = NULL;
305
306 errVal = LATE(snd_mixer_open)(&_inputMixerHandle, 0);
307 if (errVal < 0)
308 {
309 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
310 " snd_mixer_open(&_inputMixerHandle, 0) - error");
311 return -1;
312 }
313
314 char controlName[kAdmMaxDeviceNameSize] = { 0 };
315 GetControlName(controlName, deviceName);
316
317 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
318 " snd_mixer_attach(_inputMixerHandle, %s)", controlName);
319
320 errVal = LATE(snd_mixer_attach)(_inputMixerHandle, controlName);
321 if (errVal < 0)
322 {
323 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
324 " snd_mixer_attach(_inputMixerHandle, %s) error: %s",
325 controlName, LATE(snd_strerror)(errVal));
326
327 _inputMixerHandle = NULL;
328 return -1;
329 }
330 strcpy(_inputMixerStr, controlName);
331
332 errVal = LATE(snd_mixer_selem_register)(_inputMixerHandle, NULL, NULL);
333 if (errVal < 0)
334 {
335 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
336 " snd_mixer_selem_register(_inputMixerHandle,"
337 " NULL, NULL), error: %s",
338 LATE(snd_strerror)(errVal));
339
340 _inputMixerHandle = NULL;
341 return -1;
342 }
343 // Load and find the proper mixer element
344 if (LoadMicMixerElement() < 0)
345 {
346 return -1;
347 }
348
349 if (_inputMixerHandle != NULL)
350 {
351 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
352 " the input mixer device is now open (0x%x)",
353 _inputMixerHandle);
354 }
355
356 return 0;
357 }
358
SpeakerIsInitialized() const359 bool AudioMixerManagerLinuxALSA::SpeakerIsInitialized() const
360 {
361 WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s", __FUNCTION__);
362
363 return (_outputMixerHandle != NULL);
364 }
365
MicrophoneIsInitialized() const366 bool AudioMixerManagerLinuxALSA::MicrophoneIsInitialized() const
367 {
368 WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s",
369 __FUNCTION__);
370
371 return (_inputMixerHandle != NULL);
372 }
373
SetSpeakerVolume(uint32_t volume)374 int32_t AudioMixerManagerLinuxALSA::SetSpeakerVolume(
375 uint32_t volume)
376 {
377 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
378 "AudioMixerManagerLinuxALSA::SetSpeakerVolume(volume=%u)",
379 volume);
380
381 CriticalSectionScoped lock(&_critSect);
382
383 if (_outputMixerElement == NULL)
384 {
385 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
386 " no avaliable output mixer element exists");
387 return -1;
388 }
389
390 int errVal =
391 LATE(snd_mixer_selem_set_playback_volume_all)(_outputMixerElement,
392 volume);
393 if (errVal < 0)
394 {
395 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
396 " Error changing master volume: %s",
397 LATE(snd_strerror)(errVal));
398 return -1;
399 }
400
401 return (0);
402 }
403
SpeakerVolume(uint32_t & volume) const404 int32_t AudioMixerManagerLinuxALSA::SpeakerVolume(
405 uint32_t& volume) const
406 {
407
408 if (_outputMixerElement == NULL)
409 {
410 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
411 " no avaliable output mixer element exists");
412 return -1;
413 }
414
415 long int vol(0);
416
417 int
418 errVal = LATE(snd_mixer_selem_get_playback_volume)(
419 _outputMixerElement,
420 (snd_mixer_selem_channel_id_t) 0,
421 &vol);
422 if (errVal < 0)
423 {
424 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
425 "Error getting outputvolume: %s",
426 LATE(snd_strerror)(errVal));
427 return -1;
428 }
429 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
430 " AudioMixerManagerLinuxALSA::SpeakerVolume() => vol=%i",
431 vol);
432
433 volume = static_cast<uint32_t> (vol);
434
435 return 0;
436 }
437
MaxSpeakerVolume(uint32_t & maxVolume) const438 int32_t AudioMixerManagerLinuxALSA::MaxSpeakerVolume(
439 uint32_t& maxVolume) const
440 {
441
442 if (_outputMixerElement == NULL)
443 {
444 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
445 " no avilable output mixer element exists");
446 return -1;
447 }
448
449 long int minVol(0);
450 long int maxVol(0);
451
452 int errVal =
453 LATE(snd_mixer_selem_get_playback_volume_range)(_outputMixerElement,
454 &minVol, &maxVol);
455
456 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
457 " Playout hardware volume range, min: %d, max: %d",
458 minVol, maxVol);
459
460 if (maxVol <= minVol)
461 {
462 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
463 " Error getting get_playback_volume_range: %s",
464 LATE(snd_strerror)(errVal));
465 }
466
467 maxVolume = static_cast<uint32_t> (maxVol);
468
469 return 0;
470 }
471
MinSpeakerVolume(uint32_t & minVolume) const472 int32_t AudioMixerManagerLinuxALSA::MinSpeakerVolume(
473 uint32_t& minVolume) const
474 {
475
476 if (_outputMixerElement == NULL)
477 {
478 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
479 " no avaliable output mixer element exists");
480 return -1;
481 }
482
483 long int minVol(0);
484 long int maxVol(0);
485
486 int errVal =
487 LATE(snd_mixer_selem_get_playback_volume_range)(_outputMixerElement,
488 &minVol, &maxVol);
489
490 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
491 " Playout hardware volume range, min: %d, max: %d",
492 minVol, maxVol);
493
494 if (maxVol <= minVol)
495 {
496 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
497 " Error getting get_playback_volume_range: %s",
498 LATE(snd_strerror)(errVal));
499 }
500
501 minVolume = static_cast<uint32_t> (minVol);
502
503 return 0;
504 }
505
506 // TL: Have done testnig with these but they don't seem reliable and
507 // they were therefore not added
508 /*
509 // ----------------------------------------------------------------------------
510 // SetMaxSpeakerVolume
511 // ----------------------------------------------------------------------------
512
513 int32_t AudioMixerManagerLinuxALSA::SetMaxSpeakerVolume(
514 uint32_t maxVolume)
515 {
516
517 if (_outputMixerElement == NULL)
518 {
519 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
520 " no avaliable output mixer element exists");
521 return -1;
522 }
523
524 long int minVol(0);
525 long int maxVol(0);
526
527 int errVal = snd_mixer_selem_get_playback_volume_range(
528 _outputMixerElement, &minVol, &maxVol);
529 if ((maxVol <= minVol) || (errVal != 0))
530 {
531 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
532 " Error getting playback volume range: %s", snd_strerror(errVal));
533 }
534
535 maxVol = maxVolume;
536 errVal = snd_mixer_selem_set_playback_volume_range(
537 _outputMixerElement, minVol, maxVol);
538 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
539 " Playout hardware volume range, min: %d, max: %d", minVol, maxVol);
540 if (errVal != 0)
541 {
542 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
543 " Error setting playback volume range: %s", snd_strerror(errVal));
544 return -1;
545 }
546
547 return 0;
548 }
549
550 // ----------------------------------------------------------------------------
551 // SetMinSpeakerVolume
552 // ----------------------------------------------------------------------------
553
554 int32_t AudioMixerManagerLinuxALSA::SetMinSpeakerVolume(
555 uint32_t minVolume)
556 {
557
558 if (_outputMixerElement == NULL)
559 {
560 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
561 " no avaliable output mixer element exists");
562 return -1;
563 }
564
565 long int minVol(0);
566 long int maxVol(0);
567
568 int errVal = snd_mixer_selem_get_playback_volume_range(
569 _outputMixerElement, &minVol, &maxVol);
570 if ((maxVol <= minVol) || (errVal != 0))
571 {
572 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
573 " Error getting playback volume range: %s", snd_strerror(errVal));
574 }
575
576 minVol = minVolume;
577 errVal = snd_mixer_selem_set_playback_volume_range(
578 _outputMixerElement, minVol, maxVol);
579 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
580 " Playout hardware volume range, min: %d, max: %d", minVol, maxVol);
581 if (errVal != 0)
582 {
583 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
584 " Error setting playback volume range: %s", snd_strerror(errVal));
585 return -1;
586 }
587
588 return 0;
589 }
590 */
591
SpeakerVolumeStepSize(uint16_t & stepSize) const592 int32_t AudioMixerManagerLinuxALSA::SpeakerVolumeStepSize(
593 uint16_t& stepSize) const
594 {
595
596 if (_outputMixerHandle == NULL)
597 {
598 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
599 " no avaliable output mixer exists");
600 return -1;
601 }
602
603 // The step size is always 1 for ALSA
604 stepSize = 1;
605
606 return 0;
607 }
608
SpeakerVolumeIsAvailable(bool & available)609 int32_t AudioMixerManagerLinuxALSA::SpeakerVolumeIsAvailable(
610 bool& available)
611 {
612 if (_outputMixerElement == NULL)
613 {
614 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
615 " no avaliable output mixer element exists");
616 return -1;
617 }
618
619 available = LATE(snd_mixer_selem_has_playback_volume)(_outputMixerElement);
620
621 return 0;
622 }
623
SpeakerMuteIsAvailable(bool & available)624 int32_t AudioMixerManagerLinuxALSA::SpeakerMuteIsAvailable(
625 bool& available)
626 {
627 if (_outputMixerElement == NULL)
628 {
629 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
630 " no avaliable output mixer element exists");
631 return -1;
632 }
633
634 available = LATE(snd_mixer_selem_has_playback_switch)(_outputMixerElement);
635
636 return 0;
637 }
638
SetSpeakerMute(bool enable)639 int32_t AudioMixerManagerLinuxALSA::SetSpeakerMute(bool enable)
640 {
641 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
642 "AudioMixerManagerLinuxALSA::SetSpeakerMute(enable=%u)",
643 enable);
644
645 CriticalSectionScoped lock(&_critSect);
646
647 if (_outputMixerElement == NULL)
648 {
649 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
650 " no avaliable output mixer element exists");
651 return -1;
652 }
653
654 // Ensure that the selected speaker destination has a valid mute control.
655 bool available(false);
656 SpeakerMuteIsAvailable(available);
657 if (!available)
658 {
659 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
660 " it is not possible to mute the speaker");
661 return -1;
662 }
663
664 // Note value = 0 (off) means muted
665 int errVal =
666 LATE(snd_mixer_selem_set_playback_switch_all)(_outputMixerElement,
667 !enable);
668 if (errVal < 0)
669 {
670 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
671 " Error setting playback switch: %s",
672 LATE(snd_strerror)(errVal));
673 return -1;
674 }
675
676 return (0);
677 }
678
SpeakerMute(bool & enabled) const679 int32_t AudioMixerManagerLinuxALSA::SpeakerMute(bool& enabled) const
680 {
681
682 if (_outputMixerElement == NULL)
683 {
684 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
685 " no avaliable output mixer exists");
686 return -1;
687 }
688
689 // Ensure that the selected speaker destination has a valid mute control.
690 bool available =
691 LATE(snd_mixer_selem_has_playback_switch)(_outputMixerElement);
692 if (!available)
693 {
694 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
695 " it is not possible to mute the speaker");
696 return -1;
697 }
698
699 int value(false);
700
701 // Retrieve one boolean control value for a specified mute-control
702 //
703 int
704 errVal = LATE(snd_mixer_selem_get_playback_switch)(
705 _outputMixerElement,
706 (snd_mixer_selem_channel_id_t) 0,
707 &value);
708 if (errVal < 0)
709 {
710 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
711 " Error getting playback switch: %s",
712 LATE(snd_strerror)(errVal));
713 return -1;
714 }
715
716 // Note value = 0 (off) means muted
717 enabled = (bool) !value;
718
719 return 0;
720 }
721
MicrophoneMuteIsAvailable(bool & available)722 int32_t AudioMixerManagerLinuxALSA::MicrophoneMuteIsAvailable(
723 bool& available)
724 {
725 if (_inputMixerElement == NULL)
726 {
727 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
728 " no avaliable input mixer element exists");
729 return -1;
730 }
731
732 available = LATE(snd_mixer_selem_has_capture_switch)(_inputMixerElement);
733 return 0;
734 }
735
SetMicrophoneMute(bool enable)736 int32_t AudioMixerManagerLinuxALSA::SetMicrophoneMute(bool enable)
737 {
738 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
739 "AudioMixerManagerLinuxALSA::SetMicrophoneMute(enable=%u)",
740 enable);
741
742 CriticalSectionScoped lock(&_critSect);
743
744 if (_inputMixerElement == NULL)
745 {
746 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
747 " no avaliable input mixer element exists");
748 return -1;
749 }
750
751 // Ensure that the selected microphone destination has a valid mute control.
752 bool available(false);
753 MicrophoneMuteIsAvailable(available);
754 if (!available)
755 {
756 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
757 " it is not possible to mute the microphone");
758 return -1;
759 }
760
761 // Note value = 0 (off) means muted
762 int errVal =
763 LATE(snd_mixer_selem_set_capture_switch_all)(_inputMixerElement,
764 !enable);
765 if (errVal < 0)
766 {
767 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
768 " Error setting capture switch: %s",
769 LATE(snd_strerror)(errVal));
770 return -1;
771 }
772
773 return (0);
774 }
775
MicrophoneMute(bool & enabled) const776 int32_t AudioMixerManagerLinuxALSA::MicrophoneMute(bool& enabled) const
777 {
778
779 if (_inputMixerElement == NULL)
780 {
781 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
782 " no avaliable input mixer exists");
783 return -1;
784 }
785
786 // Ensure that the selected microphone destination has a valid mute control.
787 bool available =
788 LATE(snd_mixer_selem_has_capture_switch)(_inputMixerElement);
789 if (!available)
790 {
791 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
792 " it is not possible to mute the microphone");
793 return -1;
794 }
795
796 int value(false);
797
798 // Retrieve one boolean control value for a specified mute-control
799 //
800 int
801 errVal = LATE(snd_mixer_selem_get_capture_switch)(
802 _inputMixerElement,
803 (snd_mixer_selem_channel_id_t) 0,
804 &value);
805 if (errVal < 0)
806 {
807 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
808 " Error getting capture switch: %s",
809 LATE(snd_strerror)(errVal));
810 return -1;
811 }
812
813 // Note value = 0 (off) means muted
814 enabled = (bool) !value;
815
816 return 0;
817 }
818
MicrophoneBoostIsAvailable(bool & available)819 int32_t AudioMixerManagerLinuxALSA::MicrophoneBoostIsAvailable(
820 bool& available)
821 {
822 if (_inputMixerHandle == NULL)
823 {
824 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
825 " no avaliable input mixer exists");
826 return -1;
827 }
828
829 // Microphone boost cannot be enabled through ALSA Simple Mixer Interface
830 available = false;
831
832 return 0;
833 }
834
SetMicrophoneBoost(bool enable)835 int32_t AudioMixerManagerLinuxALSA::SetMicrophoneBoost(bool enable)
836 {
837 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
838 "AudioMixerManagerLinuxALSA::SetMicrophoneBoost(enable=%u)",
839 enable);
840
841 CriticalSectionScoped lock(&_critSect);
842
843 if (_inputMixerHandle == NULL)
844 {
845 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
846 " no avaliable input mixer exists");
847 return -1;
848 }
849
850 // Ensure that the selected microphone destination has a valid mute control.
851 bool available(false);
852 MicrophoneMuteIsAvailable(available);
853 if (!available)
854 {
855 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
856 " it is not possible to enable microphone boost");
857 return -1;
858 }
859
860 // It is assumed that the call above fails!
861
862 return (0);
863 }
864
MicrophoneBoost(bool & enabled) const865 int32_t AudioMixerManagerLinuxALSA::MicrophoneBoost(bool& enabled) const
866 {
867
868 if (_inputMixerHandle == NULL)
869 {
870 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
871 " no avaliable input mixer exists");
872 return -1;
873 }
874
875 // Microphone boost cannot be enabled on this platform!
876 enabled = false;
877
878 return 0;
879 }
880
MicrophoneVolumeIsAvailable(bool & available)881 int32_t AudioMixerManagerLinuxALSA::MicrophoneVolumeIsAvailable(
882 bool& available)
883 {
884 if (_inputMixerElement == NULL)
885 {
886 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
887 " no avaliable input mixer element exists");
888 return -1;
889 }
890
891 available = LATE(snd_mixer_selem_has_capture_volume)(_inputMixerElement);
892
893 return 0;
894 }
895
SetMicrophoneVolume(uint32_t volume)896 int32_t AudioMixerManagerLinuxALSA::SetMicrophoneVolume(
897 uint32_t volume)
898 {
899 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
900 "AudioMixerManagerLinuxALSA::SetMicrophoneVolume(volume=%u)",
901 volume);
902
903 CriticalSectionScoped lock(&_critSect);
904
905 if (_inputMixerElement == NULL)
906 {
907 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
908 " no avaliable input mixer element exists");
909 return -1;
910 }
911
912 int
913 errVal =
914 LATE(snd_mixer_selem_set_capture_volume_all)(_inputMixerElement,
915 volume);
916 if (errVal < 0)
917 {
918 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
919 " Error changing microphone volume: %s",
920 LATE(snd_strerror)(errVal));
921 return -1;
922 }
923
924 return (0);
925 }
926
927 // TL: Have done testnig with these but they don't seem reliable and
928 // they were therefore not added
929 /*
930 // ----------------------------------------------------------------------------
931 // SetMaxMicrophoneVolume
932 // ----------------------------------------------------------------------------
933
934 int32_t AudioMixerManagerLinuxALSA::SetMaxMicrophoneVolume(
935 uint32_t maxVolume)
936 {
937
938 if (_inputMixerElement == NULL)
939 {
940 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
941 " no avaliable output mixer element exists");
942 return -1;
943 }
944
945 long int minVol(0);
946 long int maxVol(0);
947
948 int errVal = snd_mixer_selem_get_capture_volume_range(_inputMixerElement,
949 &minVol, &maxVol);
950 if ((maxVol <= minVol) || (errVal != 0))
951 {
952 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
953 " Error getting capture volume range: %s", snd_strerror(errVal));
954 }
955
956 maxVol = (long int)maxVolume;
957 printf("min %d max %d", minVol, maxVol);
958 errVal = snd_mixer_selem_set_capture_volume_range(_inputMixerElement, minVol, maxVol);
959 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
960 " Capture hardware volume range, min: %d, max: %d", minVol, maxVol);
961 if (errVal != 0)
962 {
963 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
964 " Error setting capture volume range: %s", snd_strerror(errVal));
965 return -1;
966 }
967
968 return 0;
969 }
970
971 // ----------------------------------------------------------------------------
972 // SetMinMicrophoneVolume
973 // ----------------------------------------------------------------------------
974
975 int32_t AudioMixerManagerLinuxALSA::SetMinMicrophoneVolume(
976 uint32_t minVolume)
977 {
978
979 if (_inputMixerElement == NULL)
980 {
981 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
982 " no avaliable output mixer element exists");
983 return -1;
984 }
985
986 long int minVol(0);
987 long int maxVol(0);
988
989 int errVal = snd_mixer_selem_get_capture_volume_range(
990 _inputMixerElement, &minVol, &maxVol);
991 if (maxVol <= minVol)
992 {
993 //maxVol = 255;
994 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
995 " Error getting capture volume range: %s", snd_strerror(errVal));
996 }
997
998 printf("min %d max %d", minVol, maxVol);
999 minVol = (long int)minVolume;
1000 errVal = snd_mixer_selem_set_capture_volume_range(
1001 _inputMixerElement, minVol, maxVol);
1002 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
1003 " Capture hardware volume range, min: %d, max: %d", minVol, maxVol);
1004 if (errVal != 0)
1005 {
1006 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
1007 " Error setting capture volume range: %s", snd_strerror(errVal));
1008 return -1;
1009 }
1010
1011 return 0;
1012 }
1013 */
1014
MicrophoneVolume(uint32_t & volume) const1015 int32_t AudioMixerManagerLinuxALSA::MicrophoneVolume(
1016 uint32_t& volume) const
1017 {
1018
1019 if (_inputMixerElement == NULL)
1020 {
1021 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
1022 " no avaliable input mixer element exists");
1023 return -1;
1024 }
1025
1026 long int vol(0);
1027
1028 int
1029 errVal =
1030 LATE(snd_mixer_selem_get_capture_volume)(
1031 _inputMixerElement,
1032 (snd_mixer_selem_channel_id_t) 0,
1033 &vol);
1034 if (errVal < 0)
1035 {
1036 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
1037 "Error getting inputvolume: %s",
1038 LATE(snd_strerror)(errVal));
1039 return -1;
1040 }
1041 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
1042 " AudioMixerManagerLinuxALSA::MicrophoneVolume() => vol=%i",
1043 vol);
1044
1045 volume = static_cast<uint32_t> (vol);
1046
1047 return 0;
1048 }
1049
MaxMicrophoneVolume(uint32_t & maxVolume) const1050 int32_t AudioMixerManagerLinuxALSA::MaxMicrophoneVolume(
1051 uint32_t& maxVolume) const
1052 {
1053
1054 if (_inputMixerElement == NULL)
1055 {
1056 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
1057 " no avaliable input mixer element exists");
1058 return -1;
1059 }
1060
1061 long int minVol(0);
1062 long int maxVol(0);
1063
1064 // check if we have mic volume at all
1065 if (!LATE(snd_mixer_selem_has_capture_volume)(_inputMixerElement))
1066 {
1067 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
1068 " No microphone volume available");
1069 return -1;
1070 }
1071
1072 int errVal =
1073 LATE(snd_mixer_selem_get_capture_volume_range)(_inputMixerElement,
1074 &minVol, &maxVol);
1075
1076 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
1077 " Microphone hardware volume range, min: %d, max: %d",
1078 minVol, maxVol);
1079 if (maxVol <= minVol)
1080 {
1081 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
1082 " Error getting microphone volume range: %s",
1083 LATE(snd_strerror)(errVal));
1084 }
1085
1086 maxVolume = static_cast<uint32_t> (maxVol);
1087
1088 return 0;
1089 }
1090
MinMicrophoneVolume(uint32_t & minVolume) const1091 int32_t AudioMixerManagerLinuxALSA::MinMicrophoneVolume(
1092 uint32_t& minVolume) const
1093 {
1094
1095 if (_inputMixerElement == NULL)
1096 {
1097 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
1098 " no avaliable input mixer element exists");
1099 return -1;
1100 }
1101
1102 long int minVol(0);
1103 long int maxVol(0);
1104
1105 int errVal =
1106 LATE(snd_mixer_selem_get_capture_volume_range)(_inputMixerElement,
1107 &minVol, &maxVol);
1108
1109 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
1110 " Microphone hardware volume range, min: %d, max: %d",
1111 minVol, maxVol);
1112 if (maxVol <= minVol)
1113 {
1114 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
1115 " Error getting microphone volume range: %s",
1116 LATE(snd_strerror)(errVal));
1117 }
1118
1119 minVolume = static_cast<uint32_t> (minVol);
1120
1121 return 0;
1122 }
1123
MicrophoneVolumeStepSize(uint16_t & stepSize) const1124 int32_t AudioMixerManagerLinuxALSA::MicrophoneVolumeStepSize(
1125 uint16_t& stepSize) const
1126 {
1127
1128 if (_inputMixerHandle == NULL)
1129 {
1130 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
1131 " no avaliable input mixer exists");
1132 return -1;
1133 }
1134
1135 // The step size is always 1 for ALSA
1136 stepSize = 1;
1137
1138 return 0;
1139 }
1140
1141 // ============================================================================
1142 // Private Methods
1143 // ============================================================================
1144
LoadMicMixerElement() const1145 int32_t AudioMixerManagerLinuxALSA::LoadMicMixerElement() const
1146 {
1147 int errVal = LATE(snd_mixer_load)(_inputMixerHandle);
1148 if (errVal < 0)
1149 {
1150 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
1151 "snd_mixer_load(_inputMixerHandle), error: %s",
1152 LATE(snd_strerror)(errVal));
1153 _inputMixerHandle = NULL;
1154 return -1;
1155 }
1156
1157 snd_mixer_elem_t *elem = NULL;
1158 snd_mixer_elem_t *micElem = NULL;
1159 unsigned mixerIdx = 0;
1160 const char *selemName = NULL;
1161
1162 // Find and store handles to the right mixer elements
1163 for (elem = LATE(snd_mixer_first_elem)(_inputMixerHandle); elem; elem
1164 = LATE(snd_mixer_elem_next)(elem), mixerIdx++)
1165 {
1166 if (LATE(snd_mixer_selem_is_active)(elem))
1167 {
1168 selemName = LATE(snd_mixer_selem_get_name)(elem);
1169 if (strcmp(selemName, "Capture") == 0) // "Capture", "Mic"
1170 {
1171 _inputMixerElement = elem;
1172 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice,
1173 _id, " Capture element set");
1174 } else if (strcmp(selemName, "Mic") == 0)
1175 {
1176 micElem = elem;
1177 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice,
1178 _id, " Mic element found");
1179 }
1180 }
1181
1182 if (_inputMixerElement)
1183 {
1184 // Use the first Capture element that is found
1185 // The second one may not work
1186 break;
1187 }
1188 }
1189
1190 if (_inputMixerElement == NULL)
1191 {
1192 // We didn't find a Capture handle, use Mic.
1193 if (micElem != NULL)
1194 {
1195 _inputMixerElement = micElem;
1196 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
1197 " Using Mic as capture volume.");
1198 } else
1199 {
1200 _inputMixerElement = NULL;
1201 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
1202 "Could not find capture volume on the mixer.");
1203
1204 return -1;
1205 }
1206 }
1207
1208 return 0;
1209 }
1210
LoadSpeakerMixerElement() const1211 int32_t AudioMixerManagerLinuxALSA::LoadSpeakerMixerElement() const
1212 {
1213 int errVal = LATE(snd_mixer_load)(_outputMixerHandle);
1214 if (errVal < 0)
1215 {
1216 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
1217 " snd_mixer_load(_outputMixerHandle), error: %s",
1218 LATE(snd_strerror)(errVal));
1219 _outputMixerHandle = NULL;
1220 return -1;
1221 }
1222
1223 snd_mixer_elem_t *elem = NULL;
1224 snd_mixer_elem_t *masterElem = NULL;
1225 snd_mixer_elem_t *speakerElem = NULL;
1226 unsigned mixerIdx = 0;
1227 const char *selemName = NULL;
1228
1229 // Find and store handles to the right mixer elements
1230 for (elem = LATE(snd_mixer_first_elem)(_outputMixerHandle); elem; elem
1231 = LATE(snd_mixer_elem_next)(elem), mixerIdx++)
1232 {
1233 if (LATE(snd_mixer_selem_is_active)(elem))
1234 {
1235 selemName = LATE(snd_mixer_selem_get_name)(elem);
1236 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
1237 "snd_mixer_selem_get_name %d: %s =%x", mixerIdx,
1238 selemName, elem);
1239
1240 // "Master", "PCM", "Wave", "Master Mono", "PC Speaker", "PCM", "Wave"
1241 if (strcmp(selemName, "PCM") == 0)
1242 {
1243 _outputMixerElement = elem;
1244 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice,
1245 _id, " PCM element set");
1246 } else if (strcmp(selemName, "Master") == 0)
1247 {
1248 masterElem = elem;
1249 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice,
1250 _id, " Master element found");
1251 } else if (strcmp(selemName, "Speaker") == 0)
1252 {
1253 speakerElem = elem;
1254 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice,
1255 _id, " Speaker element found");
1256 }
1257 }
1258
1259 if (_outputMixerElement)
1260 {
1261 // We have found the element we want
1262 break;
1263 }
1264 }
1265
1266 // If we didn't find a PCM Handle, use Master or Speaker
1267 if (_outputMixerElement == NULL)
1268 {
1269 if (masterElem != NULL)
1270 {
1271 _outputMixerElement = masterElem;
1272 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
1273 " Using Master as output volume.");
1274 } else if (speakerElem != NULL)
1275 {
1276 _outputMixerElement = speakerElem;
1277 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
1278 " Using Speaker as output volume.");
1279 } else
1280 {
1281 _outputMixerElement = NULL;
1282 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
1283 "Could not find output volume in the mixer.");
1284 return -1;
1285 }
1286 }
1287
1288 return 0;
1289 }
1290
GetControlName(char * controlName,char * deviceName) const1291 void AudioMixerManagerLinuxALSA::GetControlName(char* controlName,
1292 char* deviceName) const
1293 {
1294 // Example
1295 // deviceName: "front:CARD=Intel,DEV=0"
1296 // controlName: "hw:CARD=Intel"
1297 char* pos1 = strchr(deviceName, ':');
1298 char* pos2 = strchr(deviceName, ',');
1299 if (!pos2)
1300 {
1301 // Can also be default:CARD=Intel
1302 pos2 = &deviceName[strlen(deviceName)];
1303 }
1304 if (pos1 && pos2)
1305 {
1306 strcpy(controlName, "hw");
1307 int nChar = (int) (pos2 - pos1);
1308 strncpy(&controlName[2], pos1, nChar);
1309 controlName[2 + nChar] = '\0';
1310 } else
1311 {
1312 strcpy(controlName, deviceName);
1313 }
1314
1315 }
1316
1317 }
1318