blob: b2dcf377712db2898aa03dc117e32905afecbfb3 [file] [log] [blame]
/*
* Copyright (c) 2011 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 "voe_volume_control_impl.h"
#include "channel.h"
#include "critical_section_wrapper.h"
#include "output_mixer.h"
#include "trace.h"
#include "transmit_mixer.h"
#include "voe_errors.h"
#include "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 =
reinterpret_cast<VoiceEngineImpl*> (voiceEngine);
VoEVolumeControlImpl* d = s;
(*d)++;
return (d);
#endif
}
#ifdef WEBRTC_VOICE_ENGINE_VOLUME_CONTROL_API
VoEVolumeControlImpl::VoEVolumeControlImpl()
{
WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,-1),
"VoEVolumeControlImpl::VoEVolumeControlImpl() - ctor");
}
VoEVolumeControlImpl::~VoEVolumeControlImpl()
{
WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,-1),
"VoEVolumeControlImpl::~VoEVolumeControlImpl() - dtor");
}
int VoEVolumeControlImpl::Release()
{
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_instanceId,-1),
"VoEVolumeControl::Release()");
(*this)--;
int refCount = GetCount();
if (refCount < 0)
{
Reset(); // reset reference counter to zero => OK to delete VE
_engineStatistics.SetLastError(
VE_INTERFACE_NOT_FOUND, kTraceWarning);
return (-1);
}
WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,-1),
"VoEVolumeControl reference counter = %d", refCount);
return (refCount);
}
int VoEVolumeControlImpl::SetSpeakerVolume(unsigned int volume)
{
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_instanceId,-1),
"SetSpeakerVolume(volume=%u)", volume);
IPHONE_NOT_SUPPORTED();
if (!_engineStatistics.Initialized())
{
_engineStatistics.SetLastError(VE_NOT_INITED, kTraceError);
return -1;
}
if (volume > kMaxVolumeLevel)
{
_engineStatistics.SetLastError(
VE_INVALID_ARGUMENT, kTraceError,
"SetSpeakerVolume() invalid argument");
return -1;
}
WebRtc_UWord32 maxVol(0);
WebRtc_UWord32 spkrVol(0);
// scale: [0,kMaxVolumeLevel] -> [0,MaxSpeakerVolume]
if (_audioDevicePtr->MaxSpeakerVolume(&maxVol) != 0)
{
_engineStatistics.SetLastError(
VE_MIC_VOL_ERROR, kTraceError,
"SetSpeakerVolume() failed to get max volume");
return -1;
}
// round the value and avoid floating computation
spkrVol = (WebRtc_UWord32)((volume * maxVol +
(int)(kMaxVolumeLevel / 2)) / (kMaxVolumeLevel));
// set the actual volume using the audio mixer
if (_audioDevicePtr->SetSpeakerVolume(spkrVol) != 0)
{
_engineStatistics.SetLastError(
VE_MIC_VOL_ERROR, kTraceError,
"SetSpeakerVolume() failed to set speaker volume");
return -1;
}
return 0;
}
int VoEVolumeControlImpl::GetSpeakerVolume(unsigned int& volume)
{
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_instanceId,-1),
"GetSpeakerVolume()");
IPHONE_NOT_SUPPORTED();
if (!_engineStatistics.Initialized())
{
_engineStatistics.SetLastError(VE_NOT_INITED, kTraceError);
return -1;
}
WebRtc_UWord32 spkrVol(0);
WebRtc_UWord32 maxVol(0);
if (_audioDevicePtr->SpeakerVolume(&spkrVol) != 0)
{
_engineStatistics.SetLastError(
VE_GET_MIC_VOL_ERROR, kTraceError,
"GetSpeakerVolume() unable to get speaker volume");
return -1;
}
// scale: [0, MaxSpeakerVolume] -> [0, kMaxVolumeLevel]
if (_audioDevicePtr->MaxSpeakerVolume(&maxVol) != 0)
{
_engineStatistics.SetLastError(
VE_GET_MIC_VOL_ERROR, kTraceError,
"GetSpeakerVolume() unable to get max speaker volume");
return -1;
}
// round the value and avoid floating computation
volume = (WebRtc_UWord32) ((spkrVol * kMaxVolumeLevel +
(int)(maxVol / 2)) / (maxVol));
WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,-1),
"GetSpeakerVolume() => volume=%d", volume);
return 0;
}
int VoEVolumeControlImpl::SetSystemOutputMute(bool enable)
{
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_instanceId,-1),
"GetSystemOutputMute(enabled=%d)", enable);
if (!_engineStatistics.Initialized())
{
_engineStatistics.SetLastError(VE_NOT_INITED, kTraceError);
return -1;
}
if (_audioDevicePtr->SetSpeakerMute(enable) != 0)
{
_engineStatistics.SetLastError(
VE_GET_MIC_VOL_ERROR, kTraceError,
"SpeakerMute() unable to Set speaker mute");
return -1;
}
return 0;
}
int VoEVolumeControlImpl::GetSystemOutputMute(bool& enabled)
{
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_instanceId,-1),
"GetSystemOutputMute(enabled=?)");
if (!_engineStatistics.Initialized())
{
_engineStatistics.SetLastError(VE_NOT_INITED, kTraceError);
return -1;
}
if (_audioDevicePtr->SpeakerMute(&enabled) != 0)
{
_engineStatistics.SetLastError(
VE_GET_MIC_VOL_ERROR, kTraceError,
"SpeakerMute() unable to get speaker mute state");
return -1;
}
WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,-1),
"GetSystemOutputMute() => %d", enabled);
return 0;
}
int VoEVolumeControlImpl::SetMicVolume(unsigned int volume)
{
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_instanceId,-1),
"SetMicVolume(volume=%u)", volume);
ANDROID_NOT_SUPPORTED(_engineStatistics);
IPHONE_NOT_SUPPORTED();
if (!_engineStatistics.Initialized())
{
_engineStatistics.SetLastError(VE_NOT_INITED, kTraceError);
return -1;
}
if (volume > kMaxVolumeLevel)
{
_engineStatistics.SetLastError(
VE_INVALID_ARGUMENT, kTraceError,
"SetMicVolume() invalid argument");
return -1;
}
WebRtc_UWord32 maxVol(0);
WebRtc_UWord32 micVol(0);
// scale: [0, kMaxVolumeLevel] -> [0,MaxMicrophoneVolume]
if (_audioDevicePtr->MaxMicrophoneVolume(&maxVol) != 0)
{
_engineStatistics.SetLastError(
VE_MIC_VOL_ERROR, kTraceError,
"SetMicVolume() failed to get max volume");
return -1;
}
// round the value and avoid floating point computation
micVol = (WebRtc_UWord32) ((volume * maxVol +
(int)(kMaxVolumeLevel / 2)) / (kMaxVolumeLevel));
// set the actual volume using the audio mixer
if (_audioDevicePtr->SetMicrophoneVolume(micVol) != 0)
{
_engineStatistics.SetLastError(
VE_MIC_VOL_ERROR, kTraceError,
"SetMicVolume() failed to set mic volume");
return -1;
}
return 0;
}
int VoEVolumeControlImpl::GetMicVolume(unsigned int& volume)
{
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_instanceId,-1),
"GetMicVolume()");
ANDROID_NOT_SUPPORTED(_engineStatistics);
IPHONE_NOT_SUPPORTED();
if (!_engineStatistics.Initialized())
{
_engineStatistics.SetLastError(VE_NOT_INITED, kTraceError);
return -1;
}
WebRtc_UWord32 micVol(0);
WebRtc_UWord32 maxVol(0);
if (_audioDevicePtr->MicrophoneVolume(&micVol) != 0)
{
_engineStatistics.SetLastError(
VE_GET_MIC_VOL_ERROR, kTraceError,
"GetMicVolume() unable to get microphone volume");
return -1;
}
// scale: [0, MaxMicrophoneVolume] -> [0, kMaxVolumeLevel]
if (_audioDevicePtr->MaxMicrophoneVolume(&maxVol) != 0)
{
_engineStatistics.SetLastError(
VE_GET_MIC_VOL_ERROR, kTraceError,
"GetMicVolume() unable to get max microphone volume");
return -1;
}
// round the value and avoid floating point calculation
volume = (WebRtc_UWord32) ((micVol * kMaxVolumeLevel +
(int)(maxVol / 2)) / (maxVol));
WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,-1),
"GetMicVolume() => volume=%d", volume);
return 0;
}
int VoEVolumeControlImpl::SetInputMute(int channel, bool enable)
{
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_instanceId,-1),
"SetInputMute(channel=%d, enable=%d)", channel, enable);
if (!_engineStatistics.Initialized())
{
_engineStatistics.SetLastError(VE_NOT_INITED, kTraceError);
return -1;
}
if (channel == -1)
{
// Mute before demultiplexing <=> affects all channels
return _transmitMixerPtr->SetMute(enable);
}
else
{
// Mute after demultiplexing <=> affects one channel only
voe::ScopedChannel sc(_channelManager, channel);
voe::Channel* channelPtr = sc.ChannelPtr();
if (channelPtr == NULL)
{
_engineStatistics.SetLastError(
VE_CHANNEL_NOT_VALID, kTraceError,
"SetInputMute() failed to locate channel");
return -1;
}
return channelPtr->SetMute(enable);
}
return 0;
}
int VoEVolumeControlImpl::GetInputMute(int channel, bool& enabled)
{
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_instanceId,-1),
"GetInputMute(channel=%d)", channel);
if (!_engineStatistics.Initialized())
{
_engineStatistics.SetLastError(VE_NOT_INITED, kTraceError);
return -1;
}
if (channel == -1)
{
enabled = _transmitMixerPtr->Mute();
}
else
{
voe::ScopedChannel sc(_channelManager, channel);
voe::Channel* channelPtr = sc.ChannelPtr();
if (channelPtr == NULL)
{
_engineStatistics.SetLastError(
VE_CHANNEL_NOT_VALID, kTraceError,
"SetInputMute() failed to locate channel");
return -1;
}
enabled = channelPtr->Mute();
}
WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,-1),
"GetInputMute() => enabled = %d", (int)enabled);
return 0;
}
int VoEVolumeControlImpl::SetSystemInputMute(bool enable)
{
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_instanceId,-1),
"SetSystemInputMute(enabled=%d)", enable);
if (!_engineStatistics.Initialized())
{
_engineStatistics.SetLastError(VE_NOT_INITED, kTraceError);
return -1;
}
if (_audioDevicePtr->SetMicrophoneMute(enable) != 0)
{
_engineStatistics.SetLastError(
VE_GET_MIC_VOL_ERROR, kTraceError,
"MicrophoneMute() unable to set microphone mute state");
return -1;
}
return 0;
}
int VoEVolumeControlImpl::GetSystemInputMute(bool& enabled)
{
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_instanceId,-1),
"GetSystemInputMute(enabled=?)");
if (!_engineStatistics.Initialized())
{
_engineStatistics.SetLastError(VE_NOT_INITED, kTraceError);
return -1;
}
if (_audioDevicePtr->MicrophoneMute(&enabled) != 0)
{
_engineStatistics.SetLastError(
VE_GET_MIC_VOL_ERROR, kTraceError,
"MicrophoneMute() unable to get microphone mute state");
return -1;
}
WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,-1),
"GetSystemInputMute() => %d", enabled);
return 0;
}
int VoEVolumeControlImpl::GetSpeechInputLevel(unsigned int& level)
{
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_instanceId,-1),
"GetSpeechInputLevel()");
if (!_engineStatistics.Initialized())
{
_engineStatistics.SetLastError(VE_NOT_INITED, kTraceError);
return -1;
}
WebRtc_Word8 currentLevel = _transmitMixerPtr->AudioLevel();
level = static_cast<unsigned int> (currentLevel);
WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,-1),
"GetSpeechInputLevel() => %d", level);
return 0;
}
int VoEVolumeControlImpl::GetSpeechOutputLevel(int channel,
unsigned int& level)
{
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_instanceId,-1),
"GetSpeechOutputLevel(channel=%d, level=?)", channel);
if (!_engineStatistics.Initialized())
{
_engineStatistics.SetLastError(VE_NOT_INITED, kTraceError);
return -1;
}
if (channel == -1)
{
return _outputMixerPtr->GetSpeechOutputLevel((WebRtc_UWord32&)level);
}
else
{
voe::ScopedChannel sc(_channelManager, channel);
voe::Channel* channelPtr = sc.ChannelPtr();
if (channelPtr == NULL)
{
_engineStatistics.SetLastError(
VE_CHANNEL_NOT_VALID, kTraceError,
"GetSpeechOutputLevel() failed to locate channel");
return -1;
}
channelPtr->GetSpeechOutputLevel((WebRtc_UWord32&)level);
}
return 0;
}
int VoEVolumeControlImpl::GetSpeechInputLevelFullRange(unsigned int& level)
{
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_instanceId,-1),
"GetSpeechInputLevelFullRange(level=?)");
if (!_engineStatistics.Initialized())
{
_engineStatistics.SetLastError(VE_NOT_INITED, kTraceError);
return -1;
}
WebRtc_Word16 currentLevel = _transmitMixerPtr->AudioLevelFullRange();
level = static_cast<unsigned int> (currentLevel);
WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,-1),
"GetSpeechInputLevelFullRange() => %d", level);
return 0;
}
int VoEVolumeControlImpl::GetSpeechOutputLevelFullRange(int channel,
unsigned int& level)
{
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_instanceId,-1),
"GetSpeechOutputLevelFullRange(channel=%d, level=?)", channel);
if (!_engineStatistics.Initialized())
{
_engineStatistics.SetLastError(VE_NOT_INITED, kTraceError);
return -1;
}
if (channel == -1)
{
return _outputMixerPtr->GetSpeechOutputLevelFullRange(
(WebRtc_UWord32&)level);
}
else
{
voe::ScopedChannel sc(_channelManager, channel);
voe::Channel* channelPtr = sc.ChannelPtr();
if (channelPtr == NULL)
{
_engineStatistics.SetLastError(
VE_CHANNEL_NOT_VALID, kTraceError,
"GetSpeechOutputLevelFullRange() failed to locate channel");
return -1;
}
channelPtr->GetSpeechOutputLevelFullRange((WebRtc_UWord32&)level);
}
return 0;
}
int VoEVolumeControlImpl::SetChannelOutputVolumeScaling(int channel,
float scaling)
{
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_instanceId,-1),
"SetChannelOutputVolumeScaling(channel=%d, scaling=%3.2f)",
channel, scaling);
IPHONE_NOT_SUPPORTED();
if (!_engineStatistics.Initialized())
{
_engineStatistics.SetLastError(VE_NOT_INITED, kTraceError);
return -1;
}
if (scaling < kMinOutputVolumeScaling ||
scaling > kMaxOutputVolumeScaling)
{
_engineStatistics.SetLastError(
VE_INVALID_ARGUMENT, kTraceError,
"SetChannelOutputVolumeScaling() invalid parameter");
return -1;
}
voe::ScopedChannel sc(_channelManager, channel);
voe::Channel* channelPtr = sc.ChannelPtr();
if (channelPtr == NULL)
{
_engineStatistics.SetLastError(
VE_CHANNEL_NOT_VALID, kTraceError,
"SetChannelOutputVolumeScaling() failed to locate channel");
return -1;
}
return channelPtr->SetChannelOutputVolumeScaling(scaling);
}
int VoEVolumeControlImpl::GetChannelOutputVolumeScaling(int channel,
float& scaling)
{
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_instanceId,-1),
"GetChannelOutputVolumeScaling(channel=%d, scaling=?)", channel);
IPHONE_NOT_SUPPORTED();
if (!_engineStatistics.Initialized())
{
_engineStatistics.SetLastError(VE_NOT_INITED, kTraceError);
return -1;
}
voe::ScopedChannel sc(_channelManager, channel);
voe::Channel* channelPtr = sc.ChannelPtr();
if (channelPtr == NULL)
{
_engineStatistics.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(_instanceId,-1),
"SetOutputVolumePan(channel=%d, left=%2.1f, right=%2.1f)",
channel, left, right);
ANDROID_NOT_SUPPORTED(_engineStatistics);
IPHONE_NOT_SUPPORTED();
if (!_engineStatistics.Initialized())
{
_engineStatistics.SetLastError(VE_NOT_INITED, kTraceError);
return -1;
}
bool available(false);
_audioDevicePtr->StereoPlayoutIsAvailable(&available);
if (!available)
{
_engineStatistics.SetLastError(
VE_FUNC_NO_STEREO, kTraceError,
"SetOutputVolumePan() stereo playout not supported");
return -1;
}
if ((left < kMinOutputVolumePanning) ||
(left > kMaxOutputVolumePanning) ||
(right < kMinOutputVolumePanning) ||
(right > kMaxOutputVolumePanning))
{
_engineStatistics.SetLastError(
VE_INVALID_ARGUMENT, kTraceError,
"SetOutputVolumePan() invalid parameter");
return -1;
}
if (channel == -1)
{
// Master balance (affectes the signal after output mixing)
return _outputMixerPtr->SetOutputVolumePan(left, right);
}
else
{
// Per-channel balance (affects the signal before output mixing)
voe::ScopedChannel sc(_channelManager, channel);
voe::Channel* channelPtr = sc.ChannelPtr();
if (channelPtr == NULL)
{
_engineStatistics.SetLastError(
VE_CHANNEL_NOT_VALID, kTraceError,
"SetOutputVolumePan() failed to locate channel");
return -1;
}
return channelPtr->SetOutputVolumePan(left, right);
}
return 0;
}
int VoEVolumeControlImpl::GetOutputVolumePan(int channel,
float& left,
float& right)
{
WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_instanceId,-1),
"GetOutputVolumePan(channel=%d, left=?, right=?)", channel);
ANDROID_NOT_SUPPORTED(_engineStatistics);
IPHONE_NOT_SUPPORTED();
if (!_engineStatistics.Initialized())
{
_engineStatistics.SetLastError(VE_NOT_INITED, kTraceError);
return -1;
}
bool available(false);
_audioDevicePtr->StereoPlayoutIsAvailable(&available);
if (!available)
{
_engineStatistics.SetLastError(
VE_FUNC_NO_STEREO, kTraceError,
"GetOutputVolumePan() stereo playout not supported");
return -1;
}
if (channel == -1)
{
return _outputMixerPtr->GetOutputVolumePan(left, right);
}
else
{
voe::ScopedChannel sc(_channelManager, channel);
voe::Channel* channelPtr = sc.ChannelPtr();
if (channelPtr == NULL)
{
_engineStatistics.SetLastError(
VE_CHANNEL_NOT_VALID, kTraceError,
"GetOutputVolumePan() failed to locate channel");
return -1;
}
return channelPtr->GetOutputVolumePan(left, right);
}
return 0;
}
#endif // #ifdef WEBRTC_VOICE_ENGINE_VOLUME_CONTROL_API
} // namespace webrtc