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