420 lines
14 KiB
C++
420 lines
14 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 "webrtc/voice_engine/voe_volume_control_impl.h"
|
|
|
|
#include "webrtc/system_wrappers/include/trace.h"
|
|
#include "webrtc/voice_engine/channel.h"
|
|
#include "webrtc/voice_engine/include/voe_errors.h"
|
|
#include "webrtc/voice_engine/output_mixer.h"
|
|
#include "webrtc/voice_engine/transmit_mixer.h"
|
|
#include "webrtc/voice_engine/voice_engine_impl.h"
|
|
|
|
namespace webrtc {
|
|
|
|
VoEVolumeControl* VoEVolumeControl::GetInterface(VoiceEngine* voiceEngine) {
|
|
#ifndef WEBRTC_VOICE_ENGINE_VOLUME_CONTROL_API
|
|
return NULL;
|
|
#else
|
|
if (NULL == voiceEngine) {
|
|
return NULL;
|
|
}
|
|
VoiceEngineImpl* s = static_cast<VoiceEngineImpl*>(voiceEngine);
|
|
s->AddRef();
|
|
return s;
|
|
#endif
|
|
}
|
|
|
|
#ifdef WEBRTC_VOICE_ENGINE_VOLUME_CONTROL_API
|
|
|
|
VoEVolumeControlImpl::VoEVolumeControlImpl(voe::SharedData* shared)
|
|
: _shared(shared) {
|
|
WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
|
"VoEVolumeControlImpl::VoEVolumeControlImpl() - ctor");
|
|
}
|
|
|
|
VoEVolumeControlImpl::~VoEVolumeControlImpl() {
|
|
WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
|
"VoEVolumeControlImpl::~VoEVolumeControlImpl() - dtor");
|
|
}
|
|
|
|
int VoEVolumeControlImpl::SetSpeakerVolume(unsigned int volume) {
|
|
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
|
"SetSpeakerVolume(volume=%u)", volume);
|
|
|
|
if (!_shared->statistics().Initialized()) {
|
|
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
|
return -1;
|
|
}
|
|
if (volume > kMaxVolumeLevel) {
|
|
_shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
|
|
"SetSpeakerVolume() invalid argument");
|
|
return -1;
|
|
}
|
|
|
|
uint32_t maxVol(0);
|
|
uint32_t spkrVol(0);
|
|
|
|
// scale: [0,kMaxVolumeLevel] -> [0,MaxSpeakerVolume]
|
|
if (_shared->audio_device()->MaxSpeakerVolume(&maxVol) != 0) {
|
|
_shared->SetLastError(VE_MIC_VOL_ERROR, kTraceError,
|
|
"SetSpeakerVolume() failed to get max volume");
|
|
return -1;
|
|
}
|
|
// Round the value and avoid floating computation.
|
|
spkrVol = (uint32_t)((volume * maxVol + (int)(kMaxVolumeLevel / 2)) /
|
|
(kMaxVolumeLevel));
|
|
|
|
// set the actual volume using the audio mixer
|
|
if (_shared->audio_device()->SetSpeakerVolume(spkrVol) != 0) {
|
|
_shared->SetLastError(VE_MIC_VOL_ERROR, kTraceError,
|
|
"SetSpeakerVolume() failed to set speaker volume");
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int VoEVolumeControlImpl::GetSpeakerVolume(unsigned int& volume) {
|
|
|
|
if (!_shared->statistics().Initialized()) {
|
|
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
|
return -1;
|
|
}
|
|
|
|
uint32_t spkrVol(0);
|
|
uint32_t maxVol(0);
|
|
|
|
if (_shared->audio_device()->SpeakerVolume(&spkrVol) != 0) {
|
|
_shared->SetLastError(VE_GET_MIC_VOL_ERROR, kTraceError,
|
|
"GetSpeakerVolume() unable to get speaker volume");
|
|
return -1;
|
|
}
|
|
|
|
// scale: [0, MaxSpeakerVolume] -> [0, kMaxVolumeLevel]
|
|
if (_shared->audio_device()->MaxSpeakerVolume(&maxVol) != 0) {
|
|
_shared->SetLastError(
|
|
VE_GET_MIC_VOL_ERROR, kTraceError,
|
|
"GetSpeakerVolume() unable to get max speaker volume");
|
|
return -1;
|
|
}
|
|
// Round the value and avoid floating computation.
|
|
volume =
|
|
(uint32_t)((spkrVol * kMaxVolumeLevel + (int)(maxVol / 2)) / (maxVol));
|
|
|
|
return 0;
|
|
}
|
|
|
|
int VoEVolumeControlImpl::SetMicVolume(unsigned int volume) {
|
|
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
|
"SetMicVolume(volume=%u)", volume);
|
|
|
|
if (!_shared->statistics().Initialized()) {
|
|
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
|
return -1;
|
|
}
|
|
if (volume > kMaxVolumeLevel) {
|
|
_shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
|
|
"SetMicVolume() invalid argument");
|
|
return -1;
|
|
}
|
|
|
|
uint32_t maxVol(0);
|
|
uint32_t micVol(0);
|
|
|
|
// scale: [0, kMaxVolumeLevel] -> [0,MaxMicrophoneVolume]
|
|
if (_shared->audio_device()->MaxMicrophoneVolume(&maxVol) != 0) {
|
|
_shared->SetLastError(VE_MIC_VOL_ERROR, kTraceError,
|
|
"SetMicVolume() failed to get max volume");
|
|
return -1;
|
|
}
|
|
|
|
if (volume == kMaxVolumeLevel) {
|
|
// On Linux running pulse, users are able to set the volume above 100%
|
|
// through the volume control panel, where the +100% range is digital
|
|
// scaling. WebRTC does not support setting the volume above 100%, and
|
|
// simply ignores changing the volume if the user tries to set it to
|
|
// |kMaxVolumeLevel| while the current volume is higher than |maxVol|.
|
|
if (_shared->audio_device()->MicrophoneVolume(&micVol) != 0) {
|
|
_shared->SetLastError(VE_GET_MIC_VOL_ERROR, kTraceError,
|
|
"SetMicVolume() unable to get microphone volume");
|
|
return -1;
|
|
}
|
|
if (micVol >= maxVol)
|
|
return 0;
|
|
}
|
|
|
|
// Round the value and avoid floating point computation.
|
|
micVol = (uint32_t)((volume * maxVol + (int)(kMaxVolumeLevel / 2)) /
|
|
(kMaxVolumeLevel));
|
|
|
|
// set the actual volume using the audio mixer
|
|
if (_shared->audio_device()->SetMicrophoneVolume(micVol) != 0) {
|
|
_shared->SetLastError(VE_MIC_VOL_ERROR, kTraceError,
|
|
"SetMicVolume() failed to set mic volume");
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int VoEVolumeControlImpl::GetMicVolume(unsigned int& volume) {
|
|
if (!_shared->statistics().Initialized()) {
|
|
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
|
return -1;
|
|
}
|
|
|
|
uint32_t micVol(0);
|
|
uint32_t maxVol(0);
|
|
|
|
if (_shared->audio_device()->MicrophoneVolume(&micVol) != 0) {
|
|
_shared->SetLastError(VE_GET_MIC_VOL_ERROR, kTraceError,
|
|
"GetMicVolume() unable to get microphone volume");
|
|
return -1;
|
|
}
|
|
|
|
// scale: [0, MaxMicrophoneVolume] -> [0, kMaxVolumeLevel]
|
|
if (_shared->audio_device()->MaxMicrophoneVolume(&maxVol) != 0) {
|
|
_shared->SetLastError(VE_GET_MIC_VOL_ERROR, kTraceError,
|
|
"GetMicVolume() unable to get max microphone volume");
|
|
return -1;
|
|
}
|
|
if (micVol < maxVol) {
|
|
// Round the value and avoid floating point calculation.
|
|
volume =
|
|
(uint32_t)((micVol * kMaxVolumeLevel + (int)(maxVol / 2)) / (maxVol));
|
|
} else {
|
|
// Truncate the value to the kMaxVolumeLevel.
|
|
volume = kMaxVolumeLevel;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int VoEVolumeControlImpl::SetInputMute(int channel, bool enable) {
|
|
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
|
"SetInputMute(channel=%d, enable=%d)", channel, enable);
|
|
|
|
if (!_shared->statistics().Initialized()) {
|
|
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
|
return -1;
|
|
}
|
|
if (channel == -1) {
|
|
// Mute before demultiplexing <=> affects all channels
|
|
return _shared->transmit_mixer()->SetMute(enable);
|
|
}
|
|
// Mute after demultiplexing <=> affects one channel only
|
|
voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
|
|
voe::Channel* channelPtr = ch.channel();
|
|
if (channelPtr == NULL) {
|
|
_shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
|
|
"SetInputMute() failed to locate channel");
|
|
return -1;
|
|
}
|
|
return channelPtr->SetInputMute(enable);
|
|
}
|
|
|
|
int VoEVolumeControlImpl::GetInputMute(int channel, bool& enabled) {
|
|
if (!_shared->statistics().Initialized()) {
|
|
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
|
return -1;
|
|
}
|
|
if (channel == -1) {
|
|
enabled = _shared->transmit_mixer()->Mute();
|
|
} else {
|
|
voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
|
|
voe::Channel* channelPtr = ch.channel();
|
|
if (channelPtr == NULL) {
|
|
_shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
|
|
"SetInputMute() failed to locate channel");
|
|
return -1;
|
|
}
|
|
enabled = channelPtr->InputMute();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int VoEVolumeControlImpl::GetSpeechInputLevel(unsigned int& level) {
|
|
if (!_shared->statistics().Initialized()) {
|
|
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
|
return -1;
|
|
}
|
|
int8_t currentLevel = _shared->transmit_mixer()->AudioLevel();
|
|
level = static_cast<unsigned int>(currentLevel);
|
|
return 0;
|
|
}
|
|
|
|
int VoEVolumeControlImpl::GetSpeechOutputLevel(int channel,
|
|
unsigned int& level) {
|
|
if (!_shared->statistics().Initialized()) {
|
|
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
|
return -1;
|
|
}
|
|
if (channel == -1) {
|
|
return _shared->output_mixer()->GetSpeechOutputLevel((uint32_t&)level);
|
|
} else {
|
|
voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
|
|
voe::Channel* channelPtr = ch.channel();
|
|
if (channelPtr == NULL) {
|
|
_shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
|
|
"GetSpeechOutputLevel() failed to locate channel");
|
|
return -1;
|
|
}
|
|
channelPtr->GetSpeechOutputLevel((uint32_t&)level);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int VoEVolumeControlImpl::GetSpeechInputLevelFullRange(unsigned int& level) {
|
|
if (!_shared->statistics().Initialized()) {
|
|
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
|
return -1;
|
|
}
|
|
int16_t currentLevel = _shared->transmit_mixer()->AudioLevelFullRange();
|
|
level = static_cast<unsigned int>(currentLevel);
|
|
return 0;
|
|
}
|
|
|
|
int VoEVolumeControlImpl::GetSpeechOutputLevelFullRange(int channel,
|
|
unsigned int& level) {
|
|
if (!_shared->statistics().Initialized()) {
|
|
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
|
return -1;
|
|
}
|
|
if (channel == -1) {
|
|
return _shared->output_mixer()->GetSpeechOutputLevelFullRange(
|
|
(uint32_t&)level);
|
|
} else {
|
|
voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
|
|
voe::Channel* channelPtr = ch.channel();
|
|
if (channelPtr == NULL) {
|
|
_shared->SetLastError(
|
|
VE_CHANNEL_NOT_VALID, kTraceError,
|
|
"GetSpeechOutputLevelFullRange() failed to locate channel");
|
|
return -1;
|
|
}
|
|
channelPtr->GetSpeechOutputLevelFullRange((uint32_t&)level);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int VoEVolumeControlImpl::SetChannelOutputVolumeScaling(int channel,
|
|
float scaling) {
|
|
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
|
"SetChannelOutputVolumeScaling(channel=%d, scaling=%3.2f)",
|
|
channel, scaling);
|
|
if (!_shared->statistics().Initialized()) {
|
|
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
|
return -1;
|
|
}
|
|
if (scaling < kMinOutputVolumeScaling || scaling > kMaxOutputVolumeScaling) {
|
|
_shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
|
|
"SetChannelOutputVolumeScaling() invalid parameter");
|
|
return -1;
|
|
}
|
|
voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
|
|
voe::Channel* channelPtr = ch.channel();
|
|
if (channelPtr == NULL) {
|
|
_shared->SetLastError(
|
|
VE_CHANNEL_NOT_VALID, kTraceError,
|
|
"SetChannelOutputVolumeScaling() failed to locate channel");
|
|
return -1;
|
|
}
|
|
return channelPtr->SetChannelOutputVolumeScaling(scaling);
|
|
}
|
|
|
|
int VoEVolumeControlImpl::GetChannelOutputVolumeScaling(int channel,
|
|
float& scaling) {
|
|
if (!_shared->statistics().Initialized()) {
|
|
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
|
return -1;
|
|
}
|
|
voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
|
|
voe::Channel* channelPtr = ch.channel();
|
|
if (channelPtr == NULL) {
|
|
_shared->SetLastError(
|
|
VE_CHANNEL_NOT_VALID, kTraceError,
|
|
"GetChannelOutputVolumeScaling() failed to locate channel");
|
|
return -1;
|
|
}
|
|
return channelPtr->GetChannelOutputVolumeScaling(scaling);
|
|
}
|
|
|
|
int VoEVolumeControlImpl::SetOutputVolumePan(int channel,
|
|
float left,
|
|
float right) {
|
|
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
|
|
"SetOutputVolumePan(channel=%d, left=%2.1f, right=%2.1f)",
|
|
channel, left, right);
|
|
|
|
if (!_shared->statistics().Initialized()) {
|
|
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
|
return -1;
|
|
}
|
|
|
|
bool available(false);
|
|
_shared->audio_device()->StereoPlayoutIsAvailable(&available);
|
|
if (!available) {
|
|
_shared->SetLastError(VE_FUNC_NO_STEREO, kTraceError,
|
|
"SetOutputVolumePan() stereo playout not supported");
|
|
return -1;
|
|
}
|
|
if ((left < kMinOutputVolumePanning) || (left > kMaxOutputVolumePanning) ||
|
|
(right < kMinOutputVolumePanning) || (right > kMaxOutputVolumePanning)) {
|
|
_shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
|
|
"SetOutputVolumePan() invalid parameter");
|
|
return -1;
|
|
}
|
|
|
|
if (channel == -1) {
|
|
// Master balance (affectes the signal after output mixing)
|
|
return _shared->output_mixer()->SetOutputVolumePan(left, right);
|
|
}
|
|
// Per-channel balance (affects the signal before output mixing)
|
|
voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
|
|
voe::Channel* channelPtr = ch.channel();
|
|
if (channelPtr == NULL) {
|
|
_shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
|
|
"SetOutputVolumePan() failed to locate channel");
|
|
return -1;
|
|
}
|
|
return channelPtr->SetOutputVolumePan(left, right);
|
|
}
|
|
|
|
int VoEVolumeControlImpl::GetOutputVolumePan(int channel,
|
|
float& left,
|
|
float& right) {
|
|
if (!_shared->statistics().Initialized()) {
|
|
_shared->SetLastError(VE_NOT_INITED, kTraceError);
|
|
return -1;
|
|
}
|
|
|
|
bool available(false);
|
|
_shared->audio_device()->StereoPlayoutIsAvailable(&available);
|
|
if (!available) {
|
|
_shared->SetLastError(VE_FUNC_NO_STEREO, kTraceError,
|
|
"GetOutputVolumePan() stereo playout not supported");
|
|
return -1;
|
|
}
|
|
|
|
if (channel == -1) {
|
|
return _shared->output_mixer()->GetOutputVolumePan(left, right);
|
|
}
|
|
voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
|
|
voe::Channel* channelPtr = ch.channel();
|
|
if (channelPtr == NULL) {
|
|
_shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
|
|
"GetOutputVolumePan() failed to locate channel");
|
|
return -1;
|
|
}
|
|
return channelPtr->GetOutputVolumePan(left, right);
|
|
}
|
|
|
|
#endif // #ifdef WEBRTC_VOICE_ENGINE_VOLUME_CONTROL_API
|
|
|
|
} // namespace webrtc
|