mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-15 14:50:39 +01:00

In https://webrtc-review.googlesource.com/c/src/+/1560 we moved WebRTC from src/webrtc to src/ (in order to preserve an healthy git history). This CL takes care of fixing header guards, #include paths, etc... NOPRESUBMIT=true NOTREECHECKS=true NOTRY=true TBR=tommi@webrtc.org Bug: chromium:611808 Change-Id: Iea91618212bee0af16aa3f05071eab8f93706578 Reviewed-on: https://webrtc-review.googlesource.com/1561 Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org> Reviewed-by: Henrik Kjellander <kjellander@webrtc.org> Commit-Queue: Mirko Bonadei <mbonadei@webrtc.org> Cr-Commit-Position: refs/heads/master@{#19846}
1117 lines
30 KiB
C++
1117 lines
30 KiB
C++
/*
|
|
* 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 "modules/audio_device/linux/audio_mixer_manager_alsa_linux.h"
|
|
#include "rtc_base/logging.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() :
|
|
_outputMixerHandle(NULL),
|
|
_inputMixerHandle(NULL),
|
|
_outputMixerElement(NULL),
|
|
_inputMixerElement(NULL)
|
|
{
|
|
LOG(LS_INFO) << __FUNCTION__ << " created";
|
|
|
|
memset(_outputMixerStr, 0, kAdmMaxDeviceNameSize);
|
|
memset(_inputMixerStr, 0, kAdmMaxDeviceNameSize);
|
|
}
|
|
|
|
AudioMixerManagerLinuxALSA::~AudioMixerManagerLinuxALSA()
|
|
{
|
|
LOG(LS_INFO) << __FUNCTION__ << " destroyed";
|
|
Close();
|
|
}
|
|
|
|
// ============================================================================
|
|
// PUBLIC METHODS
|
|
// ============================================================================
|
|
|
|
int32_t AudioMixerManagerLinuxALSA::Close()
|
|
{
|
|
LOG(LS_VERBOSE) << __FUNCTION__;
|
|
|
|
rtc::CritScope lock(&_critSect);
|
|
|
|
CloseSpeaker();
|
|
CloseMicrophone();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
int32_t AudioMixerManagerLinuxALSA::CloseSpeaker()
|
|
{
|
|
LOG(LS_VERBOSE) << __FUNCTION__;
|
|
|
|
rtc::CritScope lock(&_critSect);
|
|
|
|
int errVal = 0;
|
|
|
|
if (_outputMixerHandle != NULL)
|
|
{
|
|
LOG(LS_VERBOSE) << "Closing playout mixer";
|
|
LATE(snd_mixer_free)(_outputMixerHandle);
|
|
if (errVal < 0)
|
|
{
|
|
LOG(LS_ERROR) << "Error freeing playout mixer: "
|
|
<< LATE(snd_strerror)(errVal);
|
|
}
|
|
errVal = LATE(snd_mixer_detach)(_outputMixerHandle, _outputMixerStr);
|
|
if (errVal < 0)
|
|
{
|
|
LOG(LS_ERROR) << "Error detaching playout mixer: "
|
|
<< LATE(snd_strerror)(errVal);
|
|
}
|
|
errVal = LATE(snd_mixer_close)(_outputMixerHandle);
|
|
if (errVal < 0)
|
|
{
|
|
LOG(LS_ERROR) << "Error snd_mixer_close(handleMixer) errVal="
|
|
<< errVal;
|
|
}
|
|
_outputMixerHandle = NULL;
|
|
_outputMixerElement = NULL;
|
|
}
|
|
memset(_outputMixerStr, 0, kAdmMaxDeviceNameSize);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int32_t AudioMixerManagerLinuxALSA::CloseMicrophone()
|
|
{
|
|
LOG(LS_VERBOSE) << __FUNCTION__;
|
|
|
|
rtc::CritScope lock(&_critSect);
|
|
|
|
int errVal = 0;
|
|
|
|
if (_inputMixerHandle != NULL)
|
|
{
|
|
LOG(LS_VERBOSE) << "Closing record mixer";
|
|
|
|
LATE(snd_mixer_free)(_inputMixerHandle);
|
|
if (errVal < 0)
|
|
{
|
|
LOG(LS_ERROR) << "Error freeing record mixer: "
|
|
<< LATE(snd_strerror)(errVal);
|
|
}
|
|
LOG(LS_VERBOSE) << "Closing record mixer 2";
|
|
|
|
errVal = LATE(snd_mixer_detach)(_inputMixerHandle, _inputMixerStr);
|
|
if (errVal < 0)
|
|
{
|
|
LOG(LS_ERROR) << "Error detaching record mixer: "
|
|
<< LATE(snd_strerror)(errVal);
|
|
}
|
|
LOG(LS_VERBOSE) << "Closing record mixer 3";
|
|
|
|
errVal = LATE(snd_mixer_close)(_inputMixerHandle);
|
|
if (errVal < 0)
|
|
{
|
|
LOG(LS_ERROR) << "Error snd_mixer_close(handleMixer) errVal="
|
|
<< errVal;
|
|
}
|
|
|
|
LOG(LS_VERBOSE) << "Closing record mixer 4";
|
|
_inputMixerHandle = NULL;
|
|
_inputMixerElement = NULL;
|
|
}
|
|
memset(_inputMixerStr, 0, kAdmMaxDeviceNameSize);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int32_t AudioMixerManagerLinuxALSA::OpenSpeaker(char* deviceName)
|
|
{
|
|
LOG(LS_VERBOSE) << "AudioMixerManagerLinuxALSA::OpenSpeaker(name="
|
|
<< deviceName << ")";
|
|
|
|
rtc::CritScope lock(&_critSect);
|
|
|
|
int errVal = 0;
|
|
|
|
// Close any existing output mixer handle
|
|
//
|
|
if (_outputMixerHandle != NULL)
|
|
{
|
|
LOG(LS_VERBOSE) << "Closing playout mixer";
|
|
|
|
LATE(snd_mixer_free)(_outputMixerHandle);
|
|
if (errVal < 0)
|
|
{
|
|
LOG(LS_ERROR) << "Error freeing playout mixer: "
|
|
<< LATE(snd_strerror)(errVal);
|
|
}
|
|
errVal = LATE(snd_mixer_detach)(_outputMixerHandle, _outputMixerStr);
|
|
if (errVal < 0)
|
|
{
|
|
LOG(LS_ERROR) << "Error detaching playout mixer: "
|
|
<< LATE(snd_strerror)(errVal);
|
|
}
|
|
errVal = LATE(snd_mixer_close)(_outputMixerHandle);
|
|
if (errVal < 0)
|
|
{
|
|
LOG(LS_ERROR) << "Error snd_mixer_close(handleMixer) errVal="
|
|
<< errVal;
|
|
}
|
|
}
|
|
_outputMixerHandle = NULL;
|
|
_outputMixerElement = NULL;
|
|
|
|
errVal = LATE(snd_mixer_open)(&_outputMixerHandle, 0);
|
|
if (errVal < 0)
|
|
{
|
|
LOG(LS_ERROR) << "snd_mixer_open(&_outputMixerHandle, 0) - error";
|
|
return -1;
|
|
}
|
|
|
|
char controlName[kAdmMaxDeviceNameSize] = { 0 };
|
|
GetControlName(controlName, deviceName);
|
|
|
|
LOG(LS_VERBOSE) << "snd_mixer_attach(_outputMixerHandle, " << controlName
|
|
<< ")";
|
|
|
|
errVal = LATE(snd_mixer_attach)(_outputMixerHandle, controlName);
|
|
if (errVal < 0)
|
|
{
|
|
LOG(LS_ERROR) << "snd_mixer_attach(_outputMixerHandle, " << controlName
|
|
<< ") error: " << LATE(snd_strerror)(errVal);
|
|
_outputMixerHandle = NULL;
|
|
return -1;
|
|
}
|
|
strcpy(_outputMixerStr, controlName);
|
|
|
|
errVal = LATE(snd_mixer_selem_register)(_outputMixerHandle, NULL, NULL);
|
|
if (errVal < 0)
|
|
{
|
|
LOG(LS_ERROR)
|
|
<< "snd_mixer_selem_register(_outputMixerHandle, NULL, NULL), "
|
|
<< "error: " << LATE(snd_strerror)(errVal);
|
|
_outputMixerHandle = NULL;
|
|
return -1;
|
|
}
|
|
|
|
// Load and find the proper mixer element
|
|
if (LoadSpeakerMixerElement() < 0)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
if (_outputMixerHandle != NULL)
|
|
{
|
|
LOG(LS_VERBOSE) << "the output mixer device is now open ("
|
|
<< _outputMixerHandle << ")";
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int32_t AudioMixerManagerLinuxALSA::OpenMicrophone(char *deviceName)
|
|
{
|
|
LOG(LS_VERBOSE) << "AudioMixerManagerLinuxALSA::OpenMicrophone(name="
|
|
<< deviceName << ")";
|
|
|
|
rtc::CritScope lock(&_critSect);
|
|
|
|
int errVal = 0;
|
|
|
|
// Close any existing input mixer handle
|
|
//
|
|
if (_inputMixerHandle != NULL)
|
|
{
|
|
LOG(LS_VERBOSE) << "Closing record mixer";
|
|
|
|
LATE(snd_mixer_free)(_inputMixerHandle);
|
|
if (errVal < 0)
|
|
{
|
|
LOG(LS_ERROR) << "Error freeing record mixer: "
|
|
<< LATE(snd_strerror)(errVal);
|
|
}
|
|
LOG(LS_VERBOSE) << "Closing record mixer";
|
|
|
|
errVal = LATE(snd_mixer_detach)(_inputMixerHandle, _inputMixerStr);
|
|
if (errVal < 0)
|
|
{
|
|
LOG(LS_ERROR) << "Error detaching record mixer: "
|
|
<< LATE(snd_strerror)(errVal);
|
|
}
|
|
LOG(LS_VERBOSE) << "Closing record mixer";
|
|
|
|
errVal = LATE(snd_mixer_close)(_inputMixerHandle);
|
|
if (errVal < 0)
|
|
{
|
|
LOG(LS_ERROR) << "Error snd_mixer_close(handleMixer) errVal="
|
|
<< errVal;
|
|
}
|
|
LOG(LS_VERBOSE) << "Closing record mixer";
|
|
}
|
|
_inputMixerHandle = NULL;
|
|
_inputMixerElement = NULL;
|
|
|
|
errVal = LATE(snd_mixer_open)(&_inputMixerHandle, 0);
|
|
if (errVal < 0)
|
|
{
|
|
LOG(LS_ERROR) << "snd_mixer_open(&_inputMixerHandle, 0) - error";
|
|
return -1;
|
|
}
|
|
|
|
char controlName[kAdmMaxDeviceNameSize] = { 0 };
|
|
GetControlName(controlName, deviceName);
|
|
|
|
LOG(LS_VERBOSE) << "snd_mixer_attach(_inputMixerHandle, " << controlName
|
|
<< ")";
|
|
|
|
errVal = LATE(snd_mixer_attach)(_inputMixerHandle, controlName);
|
|
if (errVal < 0)
|
|
{
|
|
LOG(LS_ERROR) << "snd_mixer_attach(_inputMixerHandle, " << controlName
|
|
<< ") error: " << LATE(snd_strerror)(errVal);
|
|
|
|
_inputMixerHandle = NULL;
|
|
return -1;
|
|
}
|
|
strcpy(_inputMixerStr, controlName);
|
|
|
|
errVal = LATE(snd_mixer_selem_register)(_inputMixerHandle, NULL, NULL);
|
|
if (errVal < 0)
|
|
{
|
|
LOG(LS_ERROR)
|
|
<< "snd_mixer_selem_register(_inputMixerHandle, NULL, NULL), "
|
|
<< "error: " << LATE(snd_strerror)(errVal);
|
|
|
|
_inputMixerHandle = NULL;
|
|
return -1;
|
|
}
|
|
// Load and find the proper mixer element
|
|
if (LoadMicMixerElement() < 0)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
if (_inputMixerHandle != NULL)
|
|
{
|
|
LOG(LS_VERBOSE) << "the input mixer device is now open ("
|
|
<< _inputMixerHandle << ")";
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
bool AudioMixerManagerLinuxALSA::SpeakerIsInitialized() const
|
|
{
|
|
LOG(LS_INFO) << __FUNCTION__;
|
|
|
|
return (_outputMixerHandle != NULL);
|
|
}
|
|
|
|
bool AudioMixerManagerLinuxALSA::MicrophoneIsInitialized() const
|
|
{
|
|
LOG(LS_INFO) << __FUNCTION__;
|
|
|
|
return (_inputMixerHandle != NULL);
|
|
}
|
|
|
|
int32_t AudioMixerManagerLinuxALSA::SetSpeakerVolume(
|
|
uint32_t volume)
|
|
{
|
|
LOG(LS_VERBOSE) << "AudioMixerManagerLinuxALSA::SetSpeakerVolume(volume="
|
|
<< volume << ")";
|
|
|
|
rtc::CritScope lock(&_critSect);
|
|
|
|
if (_outputMixerElement == NULL)
|
|
{
|
|
LOG(LS_WARNING) << "no avaliable output mixer element exists";
|
|
return -1;
|
|
}
|
|
|
|
int errVal =
|
|
LATE(snd_mixer_selem_set_playback_volume_all)(_outputMixerElement,
|
|
volume);
|
|
if (errVal < 0)
|
|
{
|
|
LOG(LS_ERROR) << "Error changing master volume: "
|
|
<< LATE(snd_strerror)(errVal);
|
|
return -1;
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
int32_t AudioMixerManagerLinuxALSA::SpeakerVolume(
|
|
uint32_t& volume) const
|
|
{
|
|
|
|
if (_outputMixerElement == NULL)
|
|
{
|
|
LOG(LS_WARNING) << "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)
|
|
{
|
|
LOG(LS_ERROR) << "Error getting outputvolume: "
|
|
<< LATE(snd_strerror)(errVal);
|
|
return -1;
|
|
}
|
|
LOG(LS_VERBOSE) << "AudioMixerManagerLinuxALSA::SpeakerVolume() => vol="
|
|
<< vol;
|
|
|
|
volume = static_cast<uint32_t> (vol);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int32_t AudioMixerManagerLinuxALSA::MaxSpeakerVolume(
|
|
uint32_t& maxVolume) const
|
|
{
|
|
|
|
if (_outputMixerElement == NULL)
|
|
{
|
|
LOG(LS_WARNING) << "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);
|
|
|
|
LOG(LS_VERBOSE) << "Playout hardware volume range, min: " << minVol
|
|
<< ", max: " << maxVol;
|
|
|
|
if (maxVol <= minVol)
|
|
{
|
|
LOG(LS_ERROR) << "Error getting get_playback_volume_range: "
|
|
<< LATE(snd_strerror)(errVal);
|
|
}
|
|
|
|
maxVolume = static_cast<uint32_t> (maxVol);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int32_t AudioMixerManagerLinuxALSA::MinSpeakerVolume(
|
|
uint32_t& minVolume) const
|
|
{
|
|
|
|
if (_outputMixerElement == NULL)
|
|
{
|
|
LOG(LS_WARNING) << "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);
|
|
|
|
LOG(LS_VERBOSE) << "Playout hardware volume range, min: " << minVol
|
|
<< ", max: " << maxVol;
|
|
|
|
if (maxVol <= minVol)
|
|
{
|
|
LOG(LS_ERROR) << "Error getting get_playback_volume_range: "
|
|
<< 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)
|
|
{
|
|
LOG(LS_WARNING) << "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))
|
|
{
|
|
LOG(LS_WARNING) << "Error getting playback volume range: "
|
|
<< snd_strerror(errVal);
|
|
}
|
|
|
|
maxVol = maxVolume;
|
|
errVal = snd_mixer_selem_set_playback_volume_range(
|
|
_outputMixerElement, minVol, maxVol);
|
|
LOG(LS_VERBOSE) << "Playout hardware volume range, min: " << minVol
|
|
<< ", max: " << maxVol;
|
|
if (errVal != 0)
|
|
{
|
|
LOG(LS_ERROR) << "Error setting playback volume range: "
|
|
<< snd_strerror(errVal);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// SetMinSpeakerVolume
|
|
// ----------------------------------------------------------------------------
|
|
|
|
int32_t AudioMixerManagerLinuxALSA::SetMinSpeakerVolume(
|
|
uint32_t minVolume)
|
|
{
|
|
|
|
if (_outputMixerElement == NULL)
|
|
{
|
|
LOG(LS_WARNING) << "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))
|
|
{
|
|
LOG(LS_WARNING) << "Error getting playback volume range: "
|
|
<< snd_strerror(errVal);
|
|
}
|
|
|
|
minVol = minVolume;
|
|
errVal = snd_mixer_selem_set_playback_volume_range(
|
|
_outputMixerElement, minVol, maxVol);
|
|
LOG(LS_VERBOSE) << "Playout hardware volume range, min: " << minVol
|
|
<< ", max: " << maxVol;
|
|
if (errVal != 0)
|
|
{
|
|
LOG(LS_ERROR) << "Error setting playback volume range: "
|
|
<< snd_strerror(errVal);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
*/
|
|
|
|
int32_t AudioMixerManagerLinuxALSA::SpeakerVolumeIsAvailable(
|
|
bool& available)
|
|
{
|
|
if (_outputMixerElement == NULL)
|
|
{
|
|
LOG(LS_WARNING) << "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)
|
|
{
|
|
LOG(LS_WARNING) << "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)
|
|
{
|
|
LOG(LS_VERBOSE) << "AudioMixerManagerLinuxALSA::SetSpeakerMute(enable="
|
|
<< enable << ")";
|
|
|
|
rtc::CritScope lock(&_critSect);
|
|
|
|
if (_outputMixerElement == NULL)
|
|
{
|
|
LOG(LS_WARNING) << "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)
|
|
{
|
|
LOG(LS_WARNING) << "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)
|
|
{
|
|
LOG(LS_ERROR) << "Error setting playback switch: "
|
|
<< LATE(snd_strerror)(errVal);
|
|
return -1;
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
int32_t AudioMixerManagerLinuxALSA::SpeakerMute(bool& enabled) const
|
|
{
|
|
|
|
if (_outputMixerElement == NULL)
|
|
{
|
|
LOG(LS_WARNING) << "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)
|
|
{
|
|
LOG(LS_WARNING) << "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)
|
|
{
|
|
LOG(LS_ERROR) << "Error getting playback switch: "
|
|
<< 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)
|
|
{
|
|
LOG(LS_WARNING) << "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)
|
|
{
|
|
LOG(LS_VERBOSE) << "AudioMixerManagerLinuxALSA::SetMicrophoneMute(enable="
|
|
<< enable << ")";
|
|
|
|
rtc::CritScope lock(&_critSect);
|
|
|
|
if (_inputMixerElement == NULL)
|
|
{
|
|
LOG(LS_WARNING) << "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)
|
|
{
|
|
LOG(LS_WARNING) << "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)
|
|
{
|
|
LOG(LS_ERROR) << "Error setting capture switch: "
|
|
<< LATE(snd_strerror)(errVal);
|
|
return -1;
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
int32_t AudioMixerManagerLinuxALSA::MicrophoneMute(bool& enabled) const
|
|
{
|
|
|
|
if (_inputMixerElement == NULL)
|
|
{
|
|
LOG(LS_WARNING) << "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)
|
|
{
|
|
LOG(LS_WARNING) << "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)
|
|
{
|
|
LOG(LS_ERROR) << "Error getting capture switch: "
|
|
<< LATE(snd_strerror)(errVal);
|
|
return -1;
|
|
}
|
|
|
|
// Note value = 0 (off) means muted
|
|
enabled = (bool) !value;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int32_t AudioMixerManagerLinuxALSA::MicrophoneVolumeIsAvailable(
|
|
bool& available)
|
|
{
|
|
if (_inputMixerElement == NULL)
|
|
{
|
|
LOG(LS_WARNING) << "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)
|
|
{
|
|
LOG(LS_VERBOSE) << "AudioMixerManagerLinuxALSA::SetMicrophoneVolume(volume="
|
|
<< volume << ")";
|
|
|
|
rtc::CritScope lock(&_critSect);
|
|
|
|
if (_inputMixerElement == NULL)
|
|
{
|
|
LOG(LS_WARNING) << "no avaliable input mixer element exists";
|
|
return -1;
|
|
}
|
|
|
|
int
|
|
errVal =
|
|
LATE(snd_mixer_selem_set_capture_volume_all)(_inputMixerElement,
|
|
volume);
|
|
if (errVal < 0)
|
|
{
|
|
LOG(LS_ERROR) << "Error changing microphone volume: "
|
|
<< 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)
|
|
{
|
|
LOG(LS_WARNING) << "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))
|
|
{
|
|
LOG(LS_WARNING) << "Error getting capture volume range: "
|
|
<< 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);
|
|
LOG(LS_VERBOSE) << "Capture hardware volume range, min: " << minVol
|
|
<< ", max: " << maxVol;
|
|
if (errVal != 0)
|
|
{
|
|
LOG(LS_ERROR) << "Error setting capture volume range: "
|
|
<< snd_strerror(errVal);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// SetMinMicrophoneVolume
|
|
// ----------------------------------------------------------------------------
|
|
|
|
int32_t AudioMixerManagerLinuxALSA::SetMinMicrophoneVolume(
|
|
uint32_t minVolume)
|
|
{
|
|
|
|
if (_inputMixerElement == NULL)
|
|
{
|
|
LOG(LS_WARNING) << "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;
|
|
LOG(LS_WARNING) << "Error getting capture volume range: "
|
|
<< 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);
|
|
LOG(LS_VERBOSE) << "Capture hardware volume range, min: " << minVol
|
|
<< ", max: " << maxVol;
|
|
if (errVal != 0)
|
|
{
|
|
LOG(LS_ERROR) << "Error setting capture volume range: "
|
|
<< snd_strerror(errVal);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
*/
|
|
|
|
int32_t AudioMixerManagerLinuxALSA::MicrophoneVolume(
|
|
uint32_t& volume) const
|
|
{
|
|
|
|
if (_inputMixerElement == NULL)
|
|
{
|
|
LOG(LS_WARNING) << "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)
|
|
{
|
|
LOG(LS_ERROR) << "Error getting inputvolume: "
|
|
<< LATE(snd_strerror)(errVal);
|
|
return -1;
|
|
}
|
|
LOG(LS_VERBOSE) << "AudioMixerManagerLinuxALSA::MicrophoneVolume() => vol="
|
|
<< vol;
|
|
|
|
volume = static_cast<uint32_t> (vol);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int32_t AudioMixerManagerLinuxALSA::MaxMicrophoneVolume(
|
|
uint32_t& maxVolume) const
|
|
{
|
|
|
|
if (_inputMixerElement == NULL)
|
|
{
|
|
LOG(LS_WARNING) << "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))
|
|
{
|
|
LOG(LS_ERROR) << "No microphone volume available";
|
|
return -1;
|
|
}
|
|
|
|
int errVal =
|
|
LATE(snd_mixer_selem_get_capture_volume_range)(_inputMixerElement,
|
|
&minVol, &maxVol);
|
|
|
|
LOG(LS_VERBOSE) << "Microphone hardware volume range, min: " << minVol
|
|
<< ", max: " << maxVol;
|
|
if (maxVol <= minVol)
|
|
{
|
|
LOG(LS_ERROR) << "Error getting microphone volume range: "
|
|
<< LATE(snd_strerror)(errVal);
|
|
}
|
|
|
|
maxVolume = static_cast<uint32_t> (maxVol);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int32_t AudioMixerManagerLinuxALSA::MinMicrophoneVolume(
|
|
uint32_t& minVolume) const
|
|
{
|
|
|
|
if (_inputMixerElement == NULL)
|
|
{
|
|
LOG(LS_WARNING) << "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);
|
|
|
|
LOG(LS_VERBOSE) << "Microphone hardware volume range, min: " << minVol
|
|
<< ", max: " << maxVol;
|
|
if (maxVol <= minVol)
|
|
{
|
|
LOG(LS_ERROR) << "Error getting microphone volume range: "
|
|
<< LATE(snd_strerror)(errVal);
|
|
}
|
|
|
|
minVolume = static_cast<uint32_t> (minVol);
|
|
|
|
return 0;
|
|
}
|
|
|
|
// ============================================================================
|
|
// Private Methods
|
|
// ============================================================================
|
|
|
|
int32_t AudioMixerManagerLinuxALSA::LoadMicMixerElement() const
|
|
{
|
|
int errVal = LATE(snd_mixer_load)(_inputMixerHandle);
|
|
if (errVal < 0)
|
|
{
|
|
LOG(LS_ERROR) << "snd_mixer_load(_inputMixerHandle), error: "
|
|
<< 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;
|
|
LOG(LS_VERBOSE) << "Capture element set";
|
|
} else if (strcmp(selemName, "Mic") == 0)
|
|
{
|
|
micElem = elem;
|
|
LOG(LS_VERBOSE) << "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;
|
|
LOG(LS_VERBOSE) << "Using Mic as capture volume.";
|
|
} else
|
|
{
|
|
_inputMixerElement = NULL;
|
|
LOG(LS_ERROR) << "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)
|
|
{
|
|
LOG(LS_ERROR) << "snd_mixer_load(_outputMixerHandle), error: "
|
|
<< 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);
|
|
LOG(LS_VERBOSE) << "snd_mixer_selem_get_name " << mixerIdx << ": "
|
|
<< selemName << " =" << elem;
|
|
|
|
// "Master", "PCM", "Wave", "Master Mono", "PC Speaker", "PCM", "Wave"
|
|
if (strcmp(selemName, "PCM") == 0)
|
|
{
|
|
_outputMixerElement = elem;
|
|
LOG(LS_VERBOSE) << "PCM element set";
|
|
} else if (strcmp(selemName, "Master") == 0)
|
|
{
|
|
masterElem = elem;
|
|
LOG(LS_VERBOSE) << "Master element found";
|
|
} else if (strcmp(selemName, "Speaker") == 0)
|
|
{
|
|
speakerElem = elem;
|
|
LOG(LS_VERBOSE) << "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;
|
|
LOG(LS_VERBOSE) << "Using Master as output volume.";
|
|
} else if (speakerElem != NULL)
|
|
{
|
|
_outputMixerElement = speakerElem;
|
|
LOG(LS_VERBOSE) << "Using Speaker as output volume.";
|
|
} else
|
|
{
|
|
_outputMixerElement = NULL;
|
|
LOG(LS_ERROR) << "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);
|
|
}
|
|
|
|
}
|
|
|
|
}
|