|  | /* | 
|  | *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | 
|  | * | 
|  | *  Use of this source code is governed by a BSD-style license | 
|  | *  that can be found in the LICENSE file in the root of the source | 
|  | *  tree. An additional intellectual property rights grant can be found | 
|  | *  in the file PATENTS.  All contributing project authors may | 
|  | *  be found in the AUTHORS file in the root of the source tree. | 
|  | */ | 
|  |  | 
|  | #include <assert.h> | 
|  |  | 
|  | #include "webrtc/modules/audio_device/linux/audio_mixer_manager_alsa_linux.h" | 
|  | #include "webrtc/system_wrappers/interface/trace.h" | 
|  |  | 
|  | extern webrtc_adm_linux_alsa::AlsaSymbolTable AlsaSymbolTable; | 
|  |  | 
|  | // Accesses ALSA functions through our late-binding symbol table instead of | 
|  | // directly. This way we don't have to link to libalsa, which means our binary | 
|  | // will work on systems that don't have it. | 
|  | #define LATE(sym) \ | 
|  | LATESYM_GET(webrtc_adm_linux_alsa::AlsaSymbolTable, &AlsaSymbolTable, sym) | 
|  |  | 
|  | namespace webrtc | 
|  | { | 
|  |  | 
|  | AudioMixerManagerLinuxALSA::AudioMixerManagerLinuxALSA(const int32_t id) : | 
|  | _critSect(*CriticalSectionWrapper::CreateCriticalSection()), | 
|  | _id(id), | 
|  | _outputMixerHandle(NULL), | 
|  | _inputMixerHandle(NULL), | 
|  | _outputMixerElement(NULL), | 
|  | _inputMixerElement(NULL) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, | 
|  | "%s constructed", __FUNCTION__); | 
|  |  | 
|  | memset(_outputMixerStr, 0, kAdmMaxDeviceNameSize); | 
|  | memset(_inputMixerStr, 0, kAdmMaxDeviceNameSize); | 
|  | } | 
|  |  | 
|  | AudioMixerManagerLinuxALSA::~AudioMixerManagerLinuxALSA() | 
|  | { | 
|  | WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, | 
|  | "%s destructed", __FUNCTION__); | 
|  |  | 
|  | Close(); | 
|  |  | 
|  | delete &_critSect; | 
|  | } | 
|  |  | 
|  | // ============================================================================ | 
|  | //                                    PUBLIC METHODS | 
|  | // ============================================================================ | 
|  |  | 
|  | int32_t AudioMixerManagerLinuxALSA::Close() | 
|  | { | 
|  | WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", | 
|  | __FUNCTION__); | 
|  |  | 
|  | CriticalSectionScoped lock(&_critSect); | 
|  |  | 
|  | CloseSpeaker(); | 
|  | CloseMicrophone(); | 
|  |  | 
|  | return 0; | 
|  |  | 
|  | } | 
|  |  | 
|  | int32_t AudioMixerManagerLinuxALSA::CloseSpeaker() | 
|  | { | 
|  | WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", | 
|  | __FUNCTION__); | 
|  |  | 
|  | CriticalSectionScoped lock(&_critSect); | 
|  |  | 
|  | int errVal = 0; | 
|  |  | 
|  | if (_outputMixerHandle != NULL) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, | 
|  | "Closing playout mixer"); | 
|  | LATE(snd_mixer_free)(_outputMixerHandle); | 
|  | if (errVal < 0) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, | 
|  | "     Error freeing playout mixer: %s", | 
|  | LATE(snd_strerror)(errVal)); | 
|  | } | 
|  | errVal = LATE(snd_mixer_detach)(_outputMixerHandle, _outputMixerStr); | 
|  | if (errVal < 0) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, | 
|  | "     Error detachinging playout mixer: %s", | 
|  | LATE(snd_strerror)(errVal)); | 
|  | } | 
|  | errVal = LATE(snd_mixer_close)(_outputMixerHandle); | 
|  | if (errVal < 0) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, | 
|  | "     Error snd_mixer_close(handleMixer) errVal=%d", | 
|  | errVal); | 
|  | } | 
|  | _outputMixerHandle = NULL; | 
|  | _outputMixerElement = NULL; | 
|  | } | 
|  | memset(_outputMixerStr, 0, kAdmMaxDeviceNameSize); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int32_t AudioMixerManagerLinuxALSA::CloseMicrophone() | 
|  | { | 
|  | WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", __FUNCTION__); | 
|  |  | 
|  | CriticalSectionScoped lock(&_critSect); | 
|  |  | 
|  | int errVal = 0; | 
|  |  | 
|  | if (_inputMixerHandle != NULL) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, | 
|  | "Closing record mixer"); | 
|  |  | 
|  | LATE(snd_mixer_free)(_inputMixerHandle); | 
|  | if (errVal < 0) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, | 
|  | "     Error freeing record mixer: %s", | 
|  | LATE(snd_strerror)(errVal)); | 
|  | } | 
|  | WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, | 
|  | "Closing record mixer 2"); | 
|  |  | 
|  | errVal = LATE(snd_mixer_detach)(_inputMixerHandle, _inputMixerStr); | 
|  | if (errVal < 0) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, | 
|  | "     Error detachinging record mixer: %s", | 
|  | LATE(snd_strerror)(errVal)); | 
|  | } | 
|  | WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, | 
|  | "Closing record mixer 3"); | 
|  |  | 
|  | errVal = LATE(snd_mixer_close)(_inputMixerHandle); | 
|  | if (errVal < 0) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, | 
|  | "     Error snd_mixer_close(handleMixer) errVal=%d", | 
|  | errVal); | 
|  | } | 
|  |  | 
|  | WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, | 
|  | "Closing record mixer 4"); | 
|  | _inputMixerHandle = NULL; | 
|  | _inputMixerElement = NULL; | 
|  | } | 
|  | memset(_inputMixerStr, 0, kAdmMaxDeviceNameSize); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int32_t AudioMixerManagerLinuxALSA::OpenSpeaker(char* deviceName) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, | 
|  | "AudioMixerManagerLinuxALSA::OpenSpeaker(name=%s)", deviceName); | 
|  |  | 
|  | CriticalSectionScoped lock(&_critSect); | 
|  |  | 
|  | int errVal = 0; | 
|  |  | 
|  | // Close any existing output mixer handle | 
|  | // | 
|  | if (_outputMixerHandle != NULL) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, | 
|  | "Closing playout mixer"); | 
|  |  | 
|  | LATE(snd_mixer_free)(_outputMixerHandle); | 
|  | if (errVal < 0) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, | 
|  | "     Error freeing playout mixer: %s", | 
|  | LATE(snd_strerror)(errVal)); | 
|  | } | 
|  | errVal = LATE(snd_mixer_detach)(_outputMixerHandle, _outputMixerStr); | 
|  | if (errVal < 0) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, | 
|  | "     Error detachinging playout mixer: %s", | 
|  | LATE(snd_strerror)(errVal)); | 
|  | } | 
|  | errVal = LATE(snd_mixer_close)(_outputMixerHandle); | 
|  | if (errVal < 0) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, | 
|  | "     Error snd_mixer_close(handleMixer) errVal=%d", | 
|  | errVal); | 
|  | } | 
|  | } | 
|  | _outputMixerHandle = NULL; | 
|  | _outputMixerElement = NULL; | 
|  |  | 
|  | errVal = LATE(snd_mixer_open)(&_outputMixerHandle, 0); | 
|  | if (errVal < 0) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, | 
|  | "snd_mixer_open(&_outputMixerHandle, 0) - error"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | char controlName[kAdmMaxDeviceNameSize] = { 0 }; | 
|  | GetControlName(controlName, deviceName); | 
|  |  | 
|  | WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, | 
|  | "     snd_mixer_attach(_outputMixerHandle, %s)", controlName); | 
|  |  | 
|  | errVal = LATE(snd_mixer_attach)(_outputMixerHandle, controlName); | 
|  | if (errVal < 0) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, | 
|  | "     snd_mixer_attach(_outputMixerHandle, %s) error: %s", | 
|  | controlName, LATE(snd_strerror)(errVal)); | 
|  | _outputMixerHandle = NULL; | 
|  | return -1; | 
|  | } | 
|  | strcpy(_outputMixerStr, controlName); | 
|  |  | 
|  | errVal = LATE(snd_mixer_selem_register)(_outputMixerHandle, NULL, NULL); | 
|  | if (errVal < 0) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, | 
|  | "     snd_mixer_selem_register(_outputMixerHandle," | 
|  | " NULL, NULL), error: %s", | 
|  | LATE(snd_strerror)(errVal)); | 
|  | _outputMixerHandle = NULL; | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | // Load and find the proper mixer element | 
|  | if (LoadSpeakerMixerElement() < 0) | 
|  | { | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | if (_outputMixerHandle != NULL) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, | 
|  | "  the output mixer device is now open (0x%x)", | 
|  | _outputMixerHandle); | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int32_t AudioMixerManagerLinuxALSA::OpenMicrophone(char *deviceName) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, | 
|  | "AudioMixerManagerLinuxALSA::OpenMicrophone(name=%s)", | 
|  | deviceName); | 
|  |  | 
|  | CriticalSectionScoped lock(&_critSect); | 
|  |  | 
|  | int errVal = 0; | 
|  |  | 
|  | // Close any existing input mixer handle | 
|  | // | 
|  | if (_inputMixerHandle != NULL) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, | 
|  | "Closing record mixer"); | 
|  |  | 
|  | LATE(snd_mixer_free)(_inputMixerHandle); | 
|  | if (errVal < 0) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, | 
|  | "     Error freeing record mixer: %s", | 
|  | LATE(snd_strerror)(errVal)); | 
|  | } | 
|  | WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, | 
|  | "Closing record mixer"); | 
|  |  | 
|  | errVal = LATE(snd_mixer_detach)(_inputMixerHandle, _inputMixerStr); | 
|  | if (errVal < 0) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, | 
|  | "     Error detachinging record mixer: %s", | 
|  | LATE(snd_strerror)(errVal)); | 
|  | } | 
|  | WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, | 
|  | "Closing record mixer"); | 
|  |  | 
|  | errVal = LATE(snd_mixer_close)(_inputMixerHandle); | 
|  | if (errVal < 0) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, | 
|  | "     Error snd_mixer_close(handleMixer) errVal=%d", | 
|  | errVal); | 
|  | } | 
|  | WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, | 
|  | "Closing record mixer"); | 
|  | } | 
|  | _inputMixerHandle = NULL; | 
|  | _inputMixerElement = NULL; | 
|  |  | 
|  | errVal = LATE(snd_mixer_open)(&_inputMixerHandle, 0); | 
|  | if (errVal < 0) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, | 
|  | "     snd_mixer_open(&_inputMixerHandle, 0) - error"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | char controlName[kAdmMaxDeviceNameSize] = { 0 }; | 
|  | GetControlName(controlName, deviceName); | 
|  |  | 
|  | WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, | 
|  | "     snd_mixer_attach(_inputMixerHandle, %s)", controlName); | 
|  |  | 
|  | errVal = LATE(snd_mixer_attach)(_inputMixerHandle, controlName); | 
|  | if (errVal < 0) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, | 
|  | "     snd_mixer_attach(_inputMixerHandle, %s) error: %s", | 
|  | controlName, LATE(snd_strerror)(errVal)); | 
|  |  | 
|  | _inputMixerHandle = NULL; | 
|  | return -1; | 
|  | } | 
|  | strcpy(_inputMixerStr, controlName); | 
|  |  | 
|  | errVal = LATE(snd_mixer_selem_register)(_inputMixerHandle, NULL, NULL); | 
|  | if (errVal < 0) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, | 
|  | "     snd_mixer_selem_register(_inputMixerHandle," | 
|  | " NULL, NULL), error: %s", | 
|  | LATE(snd_strerror)(errVal)); | 
|  |  | 
|  | _inputMixerHandle = NULL; | 
|  | return -1; | 
|  | } | 
|  | // Load and find the proper mixer element | 
|  | if (LoadMicMixerElement() < 0) | 
|  | { | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | if (_inputMixerHandle != NULL) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, | 
|  | "  the input mixer device is now open (0x%x)", | 
|  | _inputMixerHandle); | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | bool AudioMixerManagerLinuxALSA::SpeakerIsInitialized() const | 
|  | { | 
|  | WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s", __FUNCTION__); | 
|  |  | 
|  | return (_outputMixerHandle != NULL); | 
|  | } | 
|  |  | 
|  | bool AudioMixerManagerLinuxALSA::MicrophoneIsInitialized() const | 
|  | { | 
|  | WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s", | 
|  | __FUNCTION__); | 
|  |  | 
|  | return (_inputMixerHandle != NULL); | 
|  | } | 
|  |  | 
|  | int32_t AudioMixerManagerLinuxALSA::SetSpeakerVolume( | 
|  | uint32_t volume) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, | 
|  | "AudioMixerManagerLinuxALSA::SetSpeakerVolume(volume=%u)", | 
|  | volume); | 
|  |  | 
|  | CriticalSectionScoped lock(&_critSect); | 
|  |  | 
|  | if (_outputMixerElement == NULL) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | 
|  | "  no avaliable output mixer element exists"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | int errVal = | 
|  | LATE(snd_mixer_selem_set_playback_volume_all)(_outputMixerElement, | 
|  | volume); | 
|  | if (errVal < 0) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, | 
|  | "     Error changing master volume: %s", | 
|  | LATE(snd_strerror)(errVal)); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | return (0); | 
|  | } | 
|  |  | 
|  | int32_t AudioMixerManagerLinuxALSA::SpeakerVolume( | 
|  | uint32_t& volume) const | 
|  | { | 
|  |  | 
|  | if (_outputMixerElement == NULL) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | 
|  | "  no avaliable output mixer element exists"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | long int vol(0); | 
|  |  | 
|  | int | 
|  | errVal = LATE(snd_mixer_selem_get_playback_volume)( | 
|  | _outputMixerElement, | 
|  | (snd_mixer_selem_channel_id_t) 0, | 
|  | &vol); | 
|  | if (errVal < 0) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, | 
|  | "Error getting outputvolume: %s", | 
|  | LATE(snd_strerror)(errVal)); | 
|  | return -1; | 
|  | } | 
|  | WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, | 
|  | "     AudioMixerManagerLinuxALSA::SpeakerVolume() => vol=%i", | 
|  | vol); | 
|  |  | 
|  | volume = static_cast<uint32_t> (vol); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int32_t AudioMixerManagerLinuxALSA::MaxSpeakerVolume( | 
|  | uint32_t& maxVolume) const | 
|  | { | 
|  |  | 
|  | if (_outputMixerElement == NULL) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | 
|  | "  no avilable output mixer element exists"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | long int minVol(0); | 
|  | long int maxVol(0); | 
|  |  | 
|  | int errVal = | 
|  | LATE(snd_mixer_selem_get_playback_volume_range)(_outputMixerElement, | 
|  | &minVol, &maxVol); | 
|  |  | 
|  | WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, | 
|  | "     Playout hardware volume range, min: %d, max: %d", | 
|  | minVol, maxVol); | 
|  |  | 
|  | if (maxVol <= minVol) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, | 
|  | "     Error getting get_playback_volume_range: %s", | 
|  | LATE(snd_strerror)(errVal)); | 
|  | } | 
|  |  | 
|  | maxVolume = static_cast<uint32_t> (maxVol); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int32_t AudioMixerManagerLinuxALSA::MinSpeakerVolume( | 
|  | uint32_t& minVolume) const | 
|  | { | 
|  |  | 
|  | if (_outputMixerElement == NULL) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | 
|  | "  no avaliable output mixer element exists"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | long int minVol(0); | 
|  | long int maxVol(0); | 
|  |  | 
|  | int errVal = | 
|  | LATE(snd_mixer_selem_get_playback_volume_range)(_outputMixerElement, | 
|  | &minVol, &maxVol); | 
|  |  | 
|  | WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, | 
|  | "     Playout hardware volume range, min: %d, max: %d", | 
|  | minVol, maxVol); | 
|  |  | 
|  | if (maxVol <= minVol) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, | 
|  | "     Error getting get_playback_volume_range: %s", | 
|  | LATE(snd_strerror)(errVal)); | 
|  | } | 
|  |  | 
|  | minVolume = static_cast<uint32_t> (minVol); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | // TL: Have done testnig with these but they don't seem reliable and | 
|  | // they were therefore not added | 
|  | /* | 
|  | // ---------------------------------------------------------------------------- | 
|  | //    SetMaxSpeakerVolume | 
|  | // ---------------------------------------------------------------------------- | 
|  |  | 
|  | int32_t AudioMixerManagerLinuxALSA::SetMaxSpeakerVolume( | 
|  | uint32_t maxVolume) | 
|  | { | 
|  |  | 
|  | if (_outputMixerElement == NULL) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | 
|  | "  no avaliable output mixer element exists"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | long int minVol(0); | 
|  | long int maxVol(0); | 
|  |  | 
|  | int errVal = snd_mixer_selem_get_playback_volume_range( | 
|  | _outputMixerElement, &minVol, &maxVol); | 
|  | if ((maxVol <= minVol) || (errVal != 0)) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | 
|  | "     Error getting playback volume range: %s", snd_strerror(errVal)); | 
|  | } | 
|  |  | 
|  | maxVol = maxVolume; | 
|  | errVal = snd_mixer_selem_set_playback_volume_range( | 
|  | _outputMixerElement, minVol, maxVol); | 
|  | WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, | 
|  | "     Playout hardware volume range, min: %d, max: %d", minVol, maxVol); | 
|  | if (errVal != 0) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, | 
|  | "     Error setting playback volume range: %s", snd_strerror(errVal)); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | // ---------------------------------------------------------------------------- | 
|  | //    SetMinSpeakerVolume | 
|  | // ---------------------------------------------------------------------------- | 
|  |  | 
|  | int32_t AudioMixerManagerLinuxALSA::SetMinSpeakerVolume( | 
|  | uint32_t minVolume) | 
|  | { | 
|  |  | 
|  | if (_outputMixerElement == NULL) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | 
|  | "  no avaliable output mixer element exists"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | long int minVol(0); | 
|  | long int maxVol(0); | 
|  |  | 
|  | int errVal = snd_mixer_selem_get_playback_volume_range( | 
|  | _outputMixerElement, &minVol, &maxVol); | 
|  | if ((maxVol <= minVol) || (errVal != 0)) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | 
|  | "     Error getting playback volume range: %s", snd_strerror(errVal)); | 
|  | } | 
|  |  | 
|  | minVol = minVolume; | 
|  | errVal = snd_mixer_selem_set_playback_volume_range( | 
|  | _outputMixerElement, minVol, maxVol); | 
|  | WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, | 
|  | "     Playout hardware volume range, min: %d, max: %d", minVol, maxVol); | 
|  | if (errVal != 0) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, | 
|  | "     Error setting playback volume range: %s", snd_strerror(errVal)); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  | */ | 
|  |  | 
|  | int32_t AudioMixerManagerLinuxALSA::SpeakerVolumeStepSize( | 
|  | uint16_t& stepSize) const | 
|  | { | 
|  |  | 
|  | if (_outputMixerHandle == NULL) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | 
|  | "  no avaliable output mixer exists"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | // The step size is always 1 for ALSA | 
|  | stepSize = 1; | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int32_t AudioMixerManagerLinuxALSA::SpeakerVolumeIsAvailable( | 
|  | bool& available) | 
|  | { | 
|  | if (_outputMixerElement == NULL) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | 
|  | "  no avaliable output mixer element exists"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | available = LATE(snd_mixer_selem_has_playback_volume)(_outputMixerElement); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int32_t AudioMixerManagerLinuxALSA::SpeakerMuteIsAvailable( | 
|  | bool& available) | 
|  | { | 
|  | if (_outputMixerElement == NULL) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | 
|  | "  no avaliable output mixer element exists"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | available = LATE(snd_mixer_selem_has_playback_switch)(_outputMixerElement); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int32_t AudioMixerManagerLinuxALSA::SetSpeakerMute(bool enable) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, | 
|  | "AudioMixerManagerLinuxALSA::SetSpeakerMute(enable=%u)", | 
|  | enable); | 
|  |  | 
|  | CriticalSectionScoped lock(&_critSect); | 
|  |  | 
|  | if (_outputMixerElement == NULL) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | 
|  | "  no avaliable output mixer element exists"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | // Ensure that the selected speaker destination has a valid mute control. | 
|  | bool available(false); | 
|  | SpeakerMuteIsAvailable(available); | 
|  | if (!available) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | 
|  | "  it is not possible to mute the speaker"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | // Note value = 0 (off) means muted | 
|  | int errVal = | 
|  | LATE(snd_mixer_selem_set_playback_switch_all)(_outputMixerElement, | 
|  | !enable); | 
|  | if (errVal < 0) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, | 
|  | "     Error setting playback switch: %s", | 
|  | LATE(snd_strerror)(errVal)); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | return (0); | 
|  | } | 
|  |  | 
|  | int32_t AudioMixerManagerLinuxALSA::SpeakerMute(bool& enabled) const | 
|  | { | 
|  |  | 
|  | if (_outputMixerElement == NULL) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | 
|  | "  no avaliable output mixer exists"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | // Ensure that the selected speaker destination has a valid mute control. | 
|  | bool available = | 
|  | LATE(snd_mixer_selem_has_playback_switch)(_outputMixerElement); | 
|  | if (!available) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | 
|  | "  it is not possible to mute the speaker"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | int value(false); | 
|  |  | 
|  | // Retrieve one boolean control value for a specified mute-control | 
|  | // | 
|  | int | 
|  | errVal = LATE(snd_mixer_selem_get_playback_switch)( | 
|  | _outputMixerElement, | 
|  | (snd_mixer_selem_channel_id_t) 0, | 
|  | &value); | 
|  | if (errVal < 0) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, | 
|  | "     Error getting playback switch: %s", | 
|  | LATE(snd_strerror)(errVal)); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | // Note value = 0 (off) means muted | 
|  | enabled = (bool) !value; | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int32_t AudioMixerManagerLinuxALSA::MicrophoneMuteIsAvailable( | 
|  | bool& available) | 
|  | { | 
|  | if (_inputMixerElement == NULL) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | 
|  | "  no avaliable input mixer element exists"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | available = LATE(snd_mixer_selem_has_capture_switch)(_inputMixerElement); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int32_t AudioMixerManagerLinuxALSA::SetMicrophoneMute(bool enable) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, | 
|  | "AudioMixerManagerLinuxALSA::SetMicrophoneMute(enable=%u)", | 
|  | enable); | 
|  |  | 
|  | CriticalSectionScoped lock(&_critSect); | 
|  |  | 
|  | if (_inputMixerElement == NULL) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | 
|  | "  no avaliable input mixer element exists"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | // Ensure that the selected microphone destination has a valid mute control. | 
|  | bool available(false); | 
|  | MicrophoneMuteIsAvailable(available); | 
|  | if (!available) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | 
|  | "  it is not possible to mute the microphone"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | // Note value = 0 (off) means muted | 
|  | int errVal = | 
|  | LATE(snd_mixer_selem_set_capture_switch_all)(_inputMixerElement, | 
|  | !enable); | 
|  | if (errVal < 0) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, | 
|  | "     Error setting capture switch: %s", | 
|  | LATE(snd_strerror)(errVal)); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | return (0); | 
|  | } | 
|  |  | 
|  | int32_t AudioMixerManagerLinuxALSA::MicrophoneMute(bool& enabled) const | 
|  | { | 
|  |  | 
|  | if (_inputMixerElement == NULL) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | 
|  | "  no avaliable input mixer exists"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | // Ensure that the selected microphone destination has a valid mute control. | 
|  | bool available = | 
|  | LATE(snd_mixer_selem_has_capture_switch)(_inputMixerElement); | 
|  | if (!available) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | 
|  | "  it is not possible to mute the microphone"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | int value(false); | 
|  |  | 
|  | // Retrieve one boolean control value for a specified mute-control | 
|  | // | 
|  | int | 
|  | errVal = LATE(snd_mixer_selem_get_capture_switch)( | 
|  | _inputMixerElement, | 
|  | (snd_mixer_selem_channel_id_t) 0, | 
|  | &value); | 
|  | if (errVal < 0) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, | 
|  | "     Error getting capture switch: %s", | 
|  | LATE(snd_strerror)(errVal)); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | // Note value = 0 (off) means muted | 
|  | enabled = (bool) !value; | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int32_t AudioMixerManagerLinuxALSA::MicrophoneBoostIsAvailable( | 
|  | bool& available) | 
|  | { | 
|  | if (_inputMixerHandle == NULL) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | 
|  | "  no avaliable input mixer exists"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | // Microphone boost cannot be enabled through ALSA Simple Mixer Interface | 
|  | available = false; | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int32_t AudioMixerManagerLinuxALSA::SetMicrophoneBoost(bool enable) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, | 
|  | "AudioMixerManagerLinuxALSA::SetMicrophoneBoost(enable=%u)", | 
|  | enable); | 
|  |  | 
|  | CriticalSectionScoped lock(&_critSect); | 
|  |  | 
|  | if (_inputMixerHandle == NULL) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | 
|  | "  no avaliable input mixer exists"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | // Ensure that the selected microphone destination has a valid mute control. | 
|  | bool available(false); | 
|  | MicrophoneMuteIsAvailable(available); | 
|  | if (!available) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | 
|  | "  it is not possible to enable microphone boost"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | // It is assumed that the call above fails! | 
|  |  | 
|  | return (0); | 
|  | } | 
|  |  | 
|  | int32_t AudioMixerManagerLinuxALSA::MicrophoneBoost(bool& enabled) const | 
|  | { | 
|  |  | 
|  | if (_inputMixerHandle == NULL) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | 
|  | "  no avaliable input mixer exists"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | // Microphone boost cannot be enabled on this platform! | 
|  | enabled = false; | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int32_t AudioMixerManagerLinuxALSA::MicrophoneVolumeIsAvailable( | 
|  | bool& available) | 
|  | { | 
|  | if (_inputMixerElement == NULL) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | 
|  | "  no avaliable input mixer element exists"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | available = LATE(snd_mixer_selem_has_capture_volume)(_inputMixerElement); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int32_t AudioMixerManagerLinuxALSA::SetMicrophoneVolume( | 
|  | uint32_t volume) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, | 
|  | "AudioMixerManagerLinuxALSA::SetMicrophoneVolume(volume=%u)", | 
|  | volume); | 
|  |  | 
|  | CriticalSectionScoped lock(&_critSect); | 
|  |  | 
|  | if (_inputMixerElement == NULL) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | 
|  | "  no avaliable input mixer element exists"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | int | 
|  | errVal = | 
|  | LATE(snd_mixer_selem_set_capture_volume_all)(_inputMixerElement, | 
|  | volume); | 
|  | if (errVal < 0) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, | 
|  | "     Error changing microphone volume: %s", | 
|  | LATE(snd_strerror)(errVal)); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | return (0); | 
|  | } | 
|  |  | 
|  | // TL: Have done testnig with these but they don't seem reliable and | 
|  | // they were therefore not added | 
|  | /* | 
|  | // ---------------------------------------------------------------------------- | 
|  | //    SetMaxMicrophoneVolume | 
|  | // ---------------------------------------------------------------------------- | 
|  |  | 
|  | int32_t AudioMixerManagerLinuxALSA::SetMaxMicrophoneVolume( | 
|  | uint32_t maxVolume) | 
|  | { | 
|  |  | 
|  | if (_inputMixerElement == NULL) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | 
|  | "  no avaliable output mixer element exists"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | long int minVol(0); | 
|  | long int maxVol(0); | 
|  |  | 
|  | int errVal = snd_mixer_selem_get_capture_volume_range(_inputMixerElement, | 
|  | &minVol, &maxVol); | 
|  | if ((maxVol <= minVol) || (errVal != 0)) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | 
|  | "     Error getting capture volume range: %s", snd_strerror(errVal)); | 
|  | } | 
|  |  | 
|  | maxVol = (long int)maxVolume; | 
|  | printf("min %d max %d", minVol, maxVol); | 
|  | errVal = snd_mixer_selem_set_capture_volume_range(_inputMixerElement, minVol, maxVol); | 
|  | WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, | 
|  | "     Capture hardware volume range, min: %d, max: %d", minVol, maxVol); | 
|  | if (errVal != 0) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, | 
|  | "     Error setting capture volume range: %s", snd_strerror(errVal)); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | // ---------------------------------------------------------------------------- | 
|  | //    SetMinMicrophoneVolume | 
|  | // ---------------------------------------------------------------------------- | 
|  |  | 
|  | int32_t AudioMixerManagerLinuxALSA::SetMinMicrophoneVolume( | 
|  | uint32_t minVolume) | 
|  | { | 
|  |  | 
|  | if (_inputMixerElement == NULL) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | 
|  | "  no avaliable output mixer element exists"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | long int minVol(0); | 
|  | long int maxVol(0); | 
|  |  | 
|  | int errVal = snd_mixer_selem_get_capture_volume_range( | 
|  | _inputMixerElement, &minVol, &maxVol); | 
|  | if (maxVol <= minVol) | 
|  | { | 
|  | //maxVol = 255; | 
|  | WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | 
|  | "     Error getting capture volume range: %s", snd_strerror(errVal)); | 
|  | } | 
|  |  | 
|  | printf("min %d max %d", minVol, maxVol); | 
|  | minVol = (long int)minVolume; | 
|  | errVal = snd_mixer_selem_set_capture_volume_range( | 
|  | _inputMixerElement, minVol, maxVol); | 
|  | WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, | 
|  | "     Capture hardware volume range, min: %d, max: %d", minVol, maxVol); | 
|  | if (errVal != 0) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, | 
|  | "     Error setting capture volume range: %s", snd_strerror(errVal)); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  | */ | 
|  |  | 
|  | int32_t AudioMixerManagerLinuxALSA::MicrophoneVolume( | 
|  | uint32_t& volume) const | 
|  | { | 
|  |  | 
|  | if (_inputMixerElement == NULL) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | 
|  | "  no avaliable input mixer element exists"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | long int vol(0); | 
|  |  | 
|  | int | 
|  | errVal = | 
|  | LATE(snd_mixer_selem_get_capture_volume)( | 
|  | _inputMixerElement, | 
|  | (snd_mixer_selem_channel_id_t) 0, | 
|  | &vol); | 
|  | if (errVal < 0) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, | 
|  | "Error getting inputvolume: %s", | 
|  | LATE(snd_strerror)(errVal)); | 
|  | return -1; | 
|  | } | 
|  | WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, | 
|  | "     AudioMixerManagerLinuxALSA::MicrophoneVolume() => vol=%i", | 
|  | vol); | 
|  |  | 
|  | volume = static_cast<uint32_t> (vol); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int32_t AudioMixerManagerLinuxALSA::MaxMicrophoneVolume( | 
|  | uint32_t& maxVolume) const | 
|  | { | 
|  |  | 
|  | if (_inputMixerElement == NULL) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | 
|  | "  no avaliable input mixer element exists"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | long int minVol(0); | 
|  | long int maxVol(0); | 
|  |  | 
|  | // check if we have mic volume at all | 
|  | if (!LATE(snd_mixer_selem_has_capture_volume)(_inputMixerElement)) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, | 
|  | "     No microphone volume available"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | int errVal = | 
|  | LATE(snd_mixer_selem_get_capture_volume_range)(_inputMixerElement, | 
|  | &minVol, &maxVol); | 
|  |  | 
|  | WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, | 
|  | "     Microphone hardware volume range, min: %d, max: %d", | 
|  | minVol, maxVol); | 
|  | if (maxVol <= minVol) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, | 
|  | "     Error getting microphone volume range: %s", | 
|  | LATE(snd_strerror)(errVal)); | 
|  | } | 
|  |  | 
|  | maxVolume = static_cast<uint32_t> (maxVol); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int32_t AudioMixerManagerLinuxALSA::MinMicrophoneVolume( | 
|  | uint32_t& minVolume) const | 
|  | { | 
|  |  | 
|  | if (_inputMixerElement == NULL) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | 
|  | "  no avaliable input mixer element exists"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | long int minVol(0); | 
|  | long int maxVol(0); | 
|  |  | 
|  | int errVal = | 
|  | LATE(snd_mixer_selem_get_capture_volume_range)(_inputMixerElement, | 
|  | &minVol, &maxVol); | 
|  |  | 
|  | WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, | 
|  | "     Microphone hardware volume range, min: %d, max: %d", | 
|  | minVol, maxVol); | 
|  | if (maxVol <= minVol) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, | 
|  | "     Error getting microphone volume range: %s", | 
|  | LATE(snd_strerror)(errVal)); | 
|  | } | 
|  |  | 
|  | minVolume = static_cast<uint32_t> (minVol); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int32_t AudioMixerManagerLinuxALSA::MicrophoneVolumeStepSize( | 
|  | uint16_t& stepSize) const | 
|  | { | 
|  |  | 
|  | if (_inputMixerHandle == NULL) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, | 
|  | "  no avaliable input mixer exists"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | // The step size is always 1 for ALSA | 
|  | stepSize = 1; | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | // ============================================================================ | 
|  | //                                 Private Methods | 
|  | // ============================================================================ | 
|  |  | 
|  | int32_t AudioMixerManagerLinuxALSA::LoadMicMixerElement() const | 
|  | { | 
|  | int errVal = LATE(snd_mixer_load)(_inputMixerHandle); | 
|  | if (errVal < 0) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, | 
|  | "snd_mixer_load(_inputMixerHandle), error: %s", | 
|  | LATE(snd_strerror)(errVal)); | 
|  | _inputMixerHandle = NULL; | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | snd_mixer_elem_t *elem = NULL; | 
|  | snd_mixer_elem_t *micElem = NULL; | 
|  | unsigned mixerIdx = 0; | 
|  | const char *selemName = NULL; | 
|  |  | 
|  | // Find and store handles to the right mixer elements | 
|  | for (elem = LATE(snd_mixer_first_elem)(_inputMixerHandle); elem; elem | 
|  | = LATE(snd_mixer_elem_next)(elem), mixerIdx++) | 
|  | { | 
|  | if (LATE(snd_mixer_selem_is_active)(elem)) | 
|  | { | 
|  | selemName = LATE(snd_mixer_selem_get_name)(elem); | 
|  | if (strcmp(selemName, "Capture") == 0) // "Capture", "Mic" | 
|  | { | 
|  | _inputMixerElement = elem; | 
|  | WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, | 
|  | _id, "     Capture element set"); | 
|  | } else if (strcmp(selemName, "Mic") == 0) | 
|  | { | 
|  | micElem = elem; | 
|  | WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, | 
|  | _id, "     Mic element found"); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (_inputMixerElement) | 
|  | { | 
|  | // Use the first Capture element that is found | 
|  | // The second one may not work | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (_inputMixerElement == NULL) | 
|  | { | 
|  | // We didn't find a Capture handle, use Mic. | 
|  | if (micElem != NULL) | 
|  | { | 
|  | _inputMixerElement = micElem; | 
|  | WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, | 
|  | "     Using Mic as capture volume."); | 
|  | } else | 
|  | { | 
|  | _inputMixerElement = NULL; | 
|  | WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, | 
|  | "Could not find capture volume on the mixer."); | 
|  |  | 
|  | return -1; | 
|  | } | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int32_t AudioMixerManagerLinuxALSA::LoadSpeakerMixerElement() const | 
|  | { | 
|  | int errVal = LATE(snd_mixer_load)(_outputMixerHandle); | 
|  | if (errVal < 0) | 
|  | { | 
|  | WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, | 
|  | "     snd_mixer_load(_outputMixerHandle), error: %s", | 
|  | LATE(snd_strerror)(errVal)); | 
|  | _outputMixerHandle = NULL; | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | snd_mixer_elem_t *elem = NULL; | 
|  | snd_mixer_elem_t *masterElem = NULL; | 
|  | snd_mixer_elem_t *speakerElem = NULL; | 
|  | unsigned mixerIdx = 0; | 
|  | const char *selemName = NULL; | 
|  |  | 
|  | // Find and store handles to the right mixer elements | 
|  | for (elem = LATE(snd_mixer_first_elem)(_outputMixerHandle); elem; elem | 
|  | = LATE(snd_mixer_elem_next)(elem), mixerIdx++) | 
|  | { | 
|  | if (LATE(snd_mixer_selem_is_active)(elem)) | 
|  | { | 
|  | selemName = LATE(snd_mixer_selem_get_name)(elem); | 
|  | WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, | 
|  | "snd_mixer_selem_get_name %d: %s =%x", mixerIdx, | 
|  | selemName, elem); | 
|  |  | 
|  | // "Master", "PCM", "Wave", "Master Mono", "PC Speaker", "PCM", "Wave" | 
|  | if (strcmp(selemName, "PCM") == 0) | 
|  | { | 
|  | _outputMixerElement = elem; | 
|  | WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, | 
|  | _id, "     PCM element set"); | 
|  | } else if (strcmp(selemName, "Master") == 0) | 
|  | { | 
|  | masterElem = elem; | 
|  | WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, | 
|  | _id, "     Master element found"); | 
|  | } else if (strcmp(selemName, "Speaker") == 0) | 
|  | { | 
|  | speakerElem = elem; | 
|  | WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, | 
|  | _id, "     Speaker element found"); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (_outputMixerElement) | 
|  | { | 
|  | // We have found the element we want | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | // If we didn't find a PCM Handle, use Master or Speaker | 
|  | if (_outputMixerElement == NULL) | 
|  | { | 
|  | if (masterElem != NULL) | 
|  | { | 
|  | _outputMixerElement = masterElem; | 
|  | WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, | 
|  | "     Using Master as output volume."); | 
|  | } else if (speakerElem != NULL) | 
|  | { | 
|  | _outputMixerElement = speakerElem; | 
|  | WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, | 
|  | "     Using Speaker as output volume."); | 
|  | } else | 
|  | { | 
|  | _outputMixerElement = NULL; | 
|  | WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, | 
|  | "Could not find output volume in the mixer."); | 
|  | return -1; | 
|  | } | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | void AudioMixerManagerLinuxALSA::GetControlName(char* controlName, | 
|  | char* deviceName) const | 
|  | { | 
|  | // Example | 
|  | // deviceName: "front:CARD=Intel,DEV=0" | 
|  | // controlName: "hw:CARD=Intel" | 
|  | char* pos1 = strchr(deviceName, ':'); | 
|  | char* pos2 = strchr(deviceName, ','); | 
|  | if (!pos2) | 
|  | { | 
|  | // Can also be default:CARD=Intel | 
|  | pos2 = &deviceName[strlen(deviceName)]; | 
|  | } | 
|  | if (pos1 && pos2) | 
|  | { | 
|  | strcpy(controlName, "hw"); | 
|  | int nChar = (int) (pos2 - pos1); | 
|  | strncpy(&controlName[2], pos1, nChar); | 
|  | controlName[2 + nChar] = '\0'; | 
|  | } else | 
|  | { | 
|  | strcpy(controlName, deviceName); | 
|  | } | 
|  |  | 
|  | } | 
|  |  | 
|  | } |