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