Home | History | Annotate | Download | only in voice_engine
      1 /*
      2  *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
      3  *
      4  *  Use of this source code is governed by a BSD-style license
      5  *  that can be found in the LICENSE file in the root of the source
      6  *  tree. An additional intellectual property rights grant can be found
      7  *  in the file PATENTS.  All contributing project authors may
      8  *  be found in the AUTHORS file in the root of the source tree.
      9  */
     10 
     11 #include "webrtc/voice_engine/voe_volume_control_impl.h"
     12 
     13 #include "webrtc/system_wrappers/include/critical_section_wrapper.h"
     14 #include "webrtc/system_wrappers/include/trace.h"
     15 #include "webrtc/voice_engine/channel.h"
     16 #include "webrtc/voice_engine/include/voe_errors.h"
     17 #include "webrtc/voice_engine/output_mixer.h"
     18 #include "webrtc/voice_engine/transmit_mixer.h"
     19 #include "webrtc/voice_engine/voice_engine_impl.h"
     20 
     21 namespace webrtc {
     22 
     23 VoEVolumeControl* VoEVolumeControl::GetInterface(VoiceEngine* voiceEngine) {
     24 #ifndef WEBRTC_VOICE_ENGINE_VOLUME_CONTROL_API
     25   return NULL;
     26 #else
     27   if (NULL == voiceEngine) {
     28     return NULL;
     29   }
     30   VoiceEngineImpl* s = static_cast<VoiceEngineImpl*>(voiceEngine);
     31   s->AddRef();
     32   return s;
     33 #endif
     34 }
     35 
     36 #ifdef WEBRTC_VOICE_ENGINE_VOLUME_CONTROL_API
     37 
     38 VoEVolumeControlImpl::VoEVolumeControlImpl(voe::SharedData* shared)
     39     : _shared(shared) {
     40   WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
     41                "VoEVolumeControlImpl::VoEVolumeControlImpl() - ctor");
     42 }
     43 
     44 VoEVolumeControlImpl::~VoEVolumeControlImpl() {
     45   WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
     46                "VoEVolumeControlImpl::~VoEVolumeControlImpl() - dtor");
     47 }
     48 
     49 int VoEVolumeControlImpl::SetSpeakerVolume(unsigned int volume) {
     50   WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
     51                "SetSpeakerVolume(volume=%u)", volume);
     52 
     53   if (!_shared->statistics().Initialized()) {
     54     _shared->SetLastError(VE_NOT_INITED, kTraceError);
     55     return -1;
     56   }
     57   if (volume > kMaxVolumeLevel) {
     58     _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
     59                           "SetSpeakerVolume() invalid argument");
     60     return -1;
     61   }
     62 
     63   uint32_t maxVol(0);
     64   uint32_t spkrVol(0);
     65 
     66   // scale: [0,kMaxVolumeLevel] -> [0,MaxSpeakerVolume]
     67   if (_shared->audio_device()->MaxSpeakerVolume(&maxVol) != 0) {
     68     _shared->SetLastError(VE_MIC_VOL_ERROR, kTraceError,
     69                           "SetSpeakerVolume() failed to get max volume");
     70     return -1;
     71   }
     72   // Round the value and avoid floating computation.
     73   spkrVol = (uint32_t)((volume * maxVol + (int)(kMaxVolumeLevel / 2)) /
     74                        (kMaxVolumeLevel));
     75 
     76   // set the actual volume using the audio mixer
     77   if (_shared->audio_device()->SetSpeakerVolume(spkrVol) != 0) {
     78     _shared->SetLastError(VE_MIC_VOL_ERROR, kTraceError,
     79                           "SetSpeakerVolume() failed to set speaker volume");
     80     return -1;
     81   }
     82   return 0;
     83 }
     84 
     85 int VoEVolumeControlImpl::GetSpeakerVolume(unsigned int& volume) {
     86 
     87   if (!_shared->statistics().Initialized()) {
     88     _shared->SetLastError(VE_NOT_INITED, kTraceError);
     89     return -1;
     90   }
     91 
     92   uint32_t spkrVol(0);
     93   uint32_t maxVol(0);
     94 
     95   if (_shared->audio_device()->SpeakerVolume(&spkrVol) != 0) {
     96     _shared->SetLastError(VE_GET_MIC_VOL_ERROR, kTraceError,
     97                           "GetSpeakerVolume() unable to get speaker volume");
     98     return -1;
     99   }
    100 
    101   // scale: [0, MaxSpeakerVolume] -> [0, kMaxVolumeLevel]
    102   if (_shared->audio_device()->MaxSpeakerVolume(&maxVol) != 0) {
    103     _shared->SetLastError(
    104         VE_GET_MIC_VOL_ERROR, kTraceError,
    105         "GetSpeakerVolume() unable to get max speaker volume");
    106     return -1;
    107   }
    108   // Round the value and avoid floating computation.
    109   volume =
    110       (uint32_t)((spkrVol * kMaxVolumeLevel + (int)(maxVol / 2)) / (maxVol));
    111 
    112   return 0;
    113 }
    114 
    115 int VoEVolumeControlImpl::SetMicVolume(unsigned int volume) {
    116   WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
    117                "SetMicVolume(volume=%u)", volume);
    118 
    119   if (!_shared->statistics().Initialized()) {
    120     _shared->SetLastError(VE_NOT_INITED, kTraceError);
    121     return -1;
    122   }
    123   if (volume > kMaxVolumeLevel) {
    124     _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
    125                           "SetMicVolume() invalid argument");
    126     return -1;
    127   }
    128 
    129   uint32_t maxVol(0);
    130   uint32_t micVol(0);
    131 
    132   // scale: [0, kMaxVolumeLevel] -> [0,MaxMicrophoneVolume]
    133   if (_shared->audio_device()->MaxMicrophoneVolume(&maxVol) != 0) {
    134     _shared->SetLastError(VE_MIC_VOL_ERROR, kTraceError,
    135                           "SetMicVolume() failed to get max volume");
    136     return -1;
    137   }
    138 
    139   if (volume == kMaxVolumeLevel) {
    140     // On Linux running pulse, users are able to set the volume above 100%
    141     // through the volume control panel, where the +100% range is digital
    142     // scaling. WebRTC does not support setting the volume above 100%, and
    143     // simply ignores changing the volume if the user tries to set it to
    144     // |kMaxVolumeLevel| while the current volume is higher than |maxVol|.
    145     if (_shared->audio_device()->MicrophoneVolume(&micVol) != 0) {
    146       _shared->SetLastError(VE_GET_MIC_VOL_ERROR, kTraceError,
    147                             "SetMicVolume() unable to get microphone volume");
    148       return -1;
    149     }
    150     if (micVol >= maxVol)
    151       return 0;
    152   }
    153 
    154   // Round the value and avoid floating point computation.
    155   micVol = (uint32_t)((volume * maxVol + (int)(kMaxVolumeLevel / 2)) /
    156                       (kMaxVolumeLevel));
    157 
    158   // set the actual volume using the audio mixer
    159   if (_shared->audio_device()->SetMicrophoneVolume(micVol) != 0) {
    160     _shared->SetLastError(VE_MIC_VOL_ERROR, kTraceError,
    161                           "SetMicVolume() failed to set mic volume");
    162     return -1;
    163   }
    164   return 0;
    165 }
    166 
    167 int VoEVolumeControlImpl::GetMicVolume(unsigned int& volume) {
    168   if (!_shared->statistics().Initialized()) {
    169     _shared->SetLastError(VE_NOT_INITED, kTraceError);
    170     return -1;
    171   }
    172 
    173   uint32_t micVol(0);
    174   uint32_t maxVol(0);
    175 
    176   if (_shared->audio_device()->MicrophoneVolume(&micVol) != 0) {
    177     _shared->SetLastError(VE_GET_MIC_VOL_ERROR, kTraceError,
    178                           "GetMicVolume() unable to get microphone volume");
    179     return -1;
    180   }
    181 
    182   // scale: [0, MaxMicrophoneVolume] -> [0, kMaxVolumeLevel]
    183   if (_shared->audio_device()->MaxMicrophoneVolume(&maxVol) != 0) {
    184     _shared->SetLastError(VE_GET_MIC_VOL_ERROR, kTraceError,
    185                           "GetMicVolume() unable to get max microphone volume");
    186     return -1;
    187   }
    188   if (micVol < maxVol) {
    189     // Round the value and avoid floating point calculation.
    190     volume =
    191         (uint32_t)((micVol * kMaxVolumeLevel + (int)(maxVol / 2)) / (maxVol));
    192   } else {
    193     // Truncate the value to the kMaxVolumeLevel.
    194     volume = kMaxVolumeLevel;
    195   }
    196   return 0;
    197 }
    198 
    199 int VoEVolumeControlImpl::SetInputMute(int channel, bool enable) {
    200   WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
    201                "SetInputMute(channel=%d, enable=%d)", channel, enable);
    202 
    203   if (!_shared->statistics().Initialized()) {
    204     _shared->SetLastError(VE_NOT_INITED, kTraceError);
    205     return -1;
    206   }
    207   if (channel == -1) {
    208     // Mute before demultiplexing <=> affects all channels
    209     return _shared->transmit_mixer()->SetMute(enable);
    210   }
    211   // Mute after demultiplexing <=> affects one channel only
    212   voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
    213   voe::Channel* channelPtr = ch.channel();
    214   if (channelPtr == NULL) {
    215     _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
    216                           "SetInputMute() failed to locate channel");
    217     return -1;
    218   }
    219   return channelPtr->SetMute(enable);
    220 }
    221 
    222 int VoEVolumeControlImpl::GetInputMute(int channel, bool& enabled) {
    223   if (!_shared->statistics().Initialized()) {
    224     _shared->SetLastError(VE_NOT_INITED, kTraceError);
    225     return -1;
    226   }
    227   if (channel == -1) {
    228     enabled = _shared->transmit_mixer()->Mute();
    229   } else {
    230     voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
    231     voe::Channel* channelPtr = ch.channel();
    232     if (channelPtr == NULL) {
    233       _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
    234                             "SetInputMute() failed to locate channel");
    235       return -1;
    236     }
    237     enabled = channelPtr->Mute();
    238   }
    239   return 0;
    240 }
    241 
    242 int VoEVolumeControlImpl::GetSpeechInputLevel(unsigned int& level) {
    243   if (!_shared->statistics().Initialized()) {
    244     _shared->SetLastError(VE_NOT_INITED, kTraceError);
    245     return -1;
    246   }
    247   int8_t currentLevel = _shared->transmit_mixer()->AudioLevel();
    248   level = static_cast<unsigned int>(currentLevel);
    249   return 0;
    250 }
    251 
    252 int VoEVolumeControlImpl::GetSpeechOutputLevel(int channel,
    253                                                unsigned int& level) {
    254   if (!_shared->statistics().Initialized()) {
    255     _shared->SetLastError(VE_NOT_INITED, kTraceError);
    256     return -1;
    257   }
    258   if (channel == -1) {
    259     return _shared->output_mixer()->GetSpeechOutputLevel((uint32_t&)level);
    260   } else {
    261     voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
    262     voe::Channel* channelPtr = ch.channel();
    263     if (channelPtr == NULL) {
    264       _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
    265                             "GetSpeechOutputLevel() failed to locate channel");
    266       return -1;
    267     }
    268     channelPtr->GetSpeechOutputLevel((uint32_t&)level);
    269   }
    270   return 0;
    271 }
    272 
    273 int VoEVolumeControlImpl::GetSpeechInputLevelFullRange(unsigned int& level) {
    274   if (!_shared->statistics().Initialized()) {
    275     _shared->SetLastError(VE_NOT_INITED, kTraceError);
    276     return -1;
    277   }
    278   int16_t currentLevel = _shared->transmit_mixer()->AudioLevelFullRange();
    279   level = static_cast<unsigned int>(currentLevel);
    280   return 0;
    281 }
    282 
    283 int VoEVolumeControlImpl::GetSpeechOutputLevelFullRange(int channel,
    284                                                         unsigned int& level) {
    285   if (!_shared->statistics().Initialized()) {
    286     _shared->SetLastError(VE_NOT_INITED, kTraceError);
    287     return -1;
    288   }
    289   if (channel == -1) {
    290     return _shared->output_mixer()->GetSpeechOutputLevelFullRange(
    291         (uint32_t&)level);
    292   } else {
    293     voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
    294     voe::Channel* channelPtr = ch.channel();
    295     if (channelPtr == NULL) {
    296       _shared->SetLastError(
    297           VE_CHANNEL_NOT_VALID, kTraceError,
    298           "GetSpeechOutputLevelFullRange() failed to locate channel");
    299       return -1;
    300     }
    301     channelPtr->GetSpeechOutputLevelFullRange((uint32_t&)level);
    302   }
    303   return 0;
    304 }
    305 
    306 int VoEVolumeControlImpl::SetChannelOutputVolumeScaling(int channel,
    307                                                         float scaling) {
    308   WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
    309                "SetChannelOutputVolumeScaling(channel=%d, scaling=%3.2f)",
    310                channel, scaling);
    311   if (!_shared->statistics().Initialized()) {
    312     _shared->SetLastError(VE_NOT_INITED, kTraceError);
    313     return -1;
    314   }
    315   if (scaling < kMinOutputVolumeScaling || scaling > kMaxOutputVolumeScaling) {
    316     _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
    317                           "SetChannelOutputVolumeScaling() invalid parameter");
    318     return -1;
    319   }
    320   voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
    321   voe::Channel* channelPtr = ch.channel();
    322   if (channelPtr == NULL) {
    323     _shared->SetLastError(
    324         VE_CHANNEL_NOT_VALID, kTraceError,
    325         "SetChannelOutputVolumeScaling() failed to locate channel");
    326     return -1;
    327   }
    328   return channelPtr->SetChannelOutputVolumeScaling(scaling);
    329 }
    330 
    331 int VoEVolumeControlImpl::GetChannelOutputVolumeScaling(int channel,
    332                                                         float& scaling) {
    333   if (!_shared->statistics().Initialized()) {
    334     _shared->SetLastError(VE_NOT_INITED, kTraceError);
    335     return -1;
    336   }
    337   voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
    338   voe::Channel* channelPtr = ch.channel();
    339   if (channelPtr == NULL) {
    340     _shared->SetLastError(
    341         VE_CHANNEL_NOT_VALID, kTraceError,
    342         "GetChannelOutputVolumeScaling() failed to locate channel");
    343     return -1;
    344   }
    345   return channelPtr->GetChannelOutputVolumeScaling(scaling);
    346 }
    347 
    348 int VoEVolumeControlImpl::SetOutputVolumePan(int channel,
    349                                              float left,
    350                                              float right) {
    351   WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
    352                "SetOutputVolumePan(channel=%d, left=%2.1f, right=%2.1f)",
    353                channel, left, right);
    354 
    355   if (!_shared->statistics().Initialized()) {
    356     _shared->SetLastError(VE_NOT_INITED, kTraceError);
    357     return -1;
    358   }
    359 
    360   bool available(false);
    361   _shared->audio_device()->StereoPlayoutIsAvailable(&available);
    362   if (!available) {
    363     _shared->SetLastError(VE_FUNC_NO_STEREO, kTraceError,
    364                           "SetOutputVolumePan() stereo playout not supported");
    365     return -1;
    366   }
    367   if ((left < kMinOutputVolumePanning) || (left > kMaxOutputVolumePanning) ||
    368       (right < kMinOutputVolumePanning) || (right > kMaxOutputVolumePanning)) {
    369     _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
    370                           "SetOutputVolumePan() invalid parameter");
    371     return -1;
    372   }
    373 
    374   if (channel == -1) {
    375     // Master balance (affectes the signal after output mixing)
    376     return _shared->output_mixer()->SetOutputVolumePan(left, right);
    377   }
    378   // Per-channel balance (affects the signal before output mixing)
    379   voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
    380   voe::Channel* channelPtr = ch.channel();
    381   if (channelPtr == NULL) {
    382     _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
    383                           "SetOutputVolumePan() failed to locate channel");
    384     return -1;
    385   }
    386   return channelPtr->SetOutputVolumePan(left, right);
    387 }
    388 
    389 int VoEVolumeControlImpl::GetOutputVolumePan(int channel,
    390                                              float& left,
    391                                              float& right) {
    392   if (!_shared->statistics().Initialized()) {
    393     _shared->SetLastError(VE_NOT_INITED, kTraceError);
    394     return -1;
    395   }
    396 
    397   bool available(false);
    398   _shared->audio_device()->StereoPlayoutIsAvailable(&available);
    399   if (!available) {
    400     _shared->SetLastError(VE_FUNC_NO_STEREO, kTraceError,
    401                           "GetOutputVolumePan() stereo playout not supported");
    402     return -1;
    403   }
    404 
    405   if (channel == -1) {
    406     return _shared->output_mixer()->GetOutputVolumePan(left, right);
    407   }
    408   voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
    409   voe::Channel* channelPtr = ch.channel();
    410   if (channelPtr == NULL) {
    411     _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
    412                           "GetOutputVolumePan() failed to locate channel");
    413     return -1;
    414   }
    415   return channelPtr->GetOutputVolumePan(left, right);
    416 }
    417 
    418 #endif  // #ifdef WEBRTC_VOICE_ENGINE_VOLUME_CONTROL_API
    419 
    420 }  // namespace webrtc
    421