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/interface/critical_section_wrapper.h"
     14 #include "webrtc/system_wrappers/interface/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 {
     25 #ifndef WEBRTC_VOICE_ENGINE_VOLUME_CONTROL_API
     26     return NULL;
     27 #else
     28     if (NULL == voiceEngine)
     29     {
     30         return NULL;
     31     }
     32     VoiceEngineImpl* s = static_cast<VoiceEngineImpl*>(voiceEngine);
     33     s->AddRef();
     34     return s;
     35 #endif
     36 }
     37 
     38 #ifdef WEBRTC_VOICE_ENGINE_VOLUME_CONTROL_API
     39 
     40 VoEVolumeControlImpl::VoEVolumeControlImpl(voe::SharedData* shared)
     41     : _shared(shared)
     42 {
     43     WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
     44                "VoEVolumeControlImpl::VoEVolumeControlImpl() - ctor");
     45 }
     46 
     47 VoEVolumeControlImpl::~VoEVolumeControlImpl()
     48 {
     49     WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
     50                "VoEVolumeControlImpl::~VoEVolumeControlImpl() - dtor");
     51 }
     52 
     53 int VoEVolumeControlImpl::SetSpeakerVolume(unsigned int volume)
     54 {
     55     WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
     56                "SetSpeakerVolume(volume=%u)", volume);
     57 
     58     if (!_shared->statistics().Initialized())
     59     {
     60         _shared->SetLastError(VE_NOT_INITED, kTraceError);
     61         return -1;
     62     }
     63     if (volume > kMaxVolumeLevel)
     64     {
     65         _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
     66             "SetSpeakerVolume() invalid argument");
     67         return -1;
     68     }
     69 
     70     uint32_t maxVol(0);
     71     uint32_t spkrVol(0);
     72 
     73     // scale: [0,kMaxVolumeLevel] -> [0,MaxSpeakerVolume]
     74     if (_shared->audio_device()->MaxSpeakerVolume(&maxVol) != 0)
     75     {
     76         _shared->SetLastError(VE_MIC_VOL_ERROR, kTraceError,
     77             "SetSpeakerVolume() failed to get max volume");
     78         return -1;
     79     }
     80     // Round the value and avoid floating computation.
     81     spkrVol = (uint32_t)((volume * maxVol +
     82         (int)(kMaxVolumeLevel / 2)) / (kMaxVolumeLevel));
     83 
     84     // set the actual volume using the audio mixer
     85     if (_shared->audio_device()->SetSpeakerVolume(spkrVol) != 0)
     86     {
     87         _shared->SetLastError(VE_MIC_VOL_ERROR, kTraceError,
     88             "SetSpeakerVolume() failed to set speaker volume");
     89         return -1;
     90     }
     91     return 0;
     92 }
     93 
     94 int VoEVolumeControlImpl::GetSpeakerVolume(unsigned int& volume)
     95 {
     96     WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
     97                "GetSpeakerVolume()");
     98 
     99     if (!_shared->statistics().Initialized())
    100     {
    101         _shared->SetLastError(VE_NOT_INITED, kTraceError);
    102         return -1;
    103     }
    104 
    105     uint32_t spkrVol(0);
    106     uint32_t maxVol(0);
    107 
    108     if (_shared->audio_device()->SpeakerVolume(&spkrVol) != 0)
    109     {
    110         _shared->SetLastError(VE_GET_MIC_VOL_ERROR, kTraceError,
    111             "GetSpeakerVolume() unable to get speaker volume");
    112         return -1;
    113     }
    114 
    115     // scale: [0, MaxSpeakerVolume] -> [0, kMaxVolumeLevel]
    116     if (_shared->audio_device()->MaxSpeakerVolume(&maxVol) != 0)
    117     {
    118         _shared->SetLastError(VE_GET_MIC_VOL_ERROR, kTraceError,
    119             "GetSpeakerVolume() unable to get max speaker volume");
    120         return -1;
    121     }
    122     // Round the value and avoid floating computation.
    123     volume = (uint32_t) ((spkrVol * kMaxVolumeLevel +
    124         (int)(maxVol / 2)) / (maxVol));
    125 
    126     WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
    127         VoEId(_shared->instance_id(), -1),
    128         "GetSpeakerVolume() => volume=%d", volume);
    129     return 0;
    130 }
    131 
    132 int VoEVolumeControlImpl::SetMicVolume(unsigned int volume)
    133 {
    134     WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
    135                "SetMicVolume(volume=%u)", volume);
    136 
    137     if (!_shared->statistics().Initialized())
    138     {
    139         _shared->SetLastError(VE_NOT_INITED, kTraceError);
    140         return -1;
    141     }
    142     if (volume > kMaxVolumeLevel)
    143     {
    144         _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
    145             "SetMicVolume() invalid argument");
    146         return -1;
    147     }
    148 
    149     uint32_t maxVol(0);
    150     uint32_t micVol(0);
    151 
    152     // scale: [0, kMaxVolumeLevel] -> [0,MaxMicrophoneVolume]
    153     if (_shared->audio_device()->MaxMicrophoneVolume(&maxVol) != 0)
    154     {
    155         _shared->SetLastError(VE_MIC_VOL_ERROR, kTraceError,
    156             "SetMicVolume() failed to get max volume");
    157         return -1;
    158     }
    159 
    160     if (volume == kMaxVolumeLevel) {
    161       // On Linux running pulse, users are able to set the volume above 100%
    162       // through the volume control panel, where the +100% range is digital
    163       // scaling. WebRTC does not support setting the volume above 100%, and
    164       // simply ignores changing the volume if the user tries to set it to
    165       // |kMaxVolumeLevel| while the current volume is higher than |maxVol|.
    166       if (_shared->audio_device()->MicrophoneVolume(&micVol) != 0) {
    167         _shared->SetLastError(VE_GET_MIC_VOL_ERROR, kTraceError,
    168             "SetMicVolume() unable to get microphone volume");
    169         return -1;
    170       }
    171       if (micVol >= maxVol)
    172         return 0;
    173     }
    174 
    175     // Round the value and avoid floating point computation.
    176     micVol = (uint32_t) ((volume * maxVol +
    177         (int)(kMaxVolumeLevel / 2)) / (kMaxVolumeLevel));
    178 
    179     // set the actual volume using the audio mixer
    180     if (_shared->audio_device()->SetMicrophoneVolume(micVol) != 0)
    181     {
    182         _shared->SetLastError(VE_MIC_VOL_ERROR, kTraceError,
    183             "SetMicVolume() failed to set mic volume");
    184         return -1;
    185     }
    186     return 0;
    187 }
    188 
    189 int VoEVolumeControlImpl::GetMicVolume(unsigned int& volume)
    190 {
    191     WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
    192                "GetMicVolume()");
    193 
    194     if (!_shared->statistics().Initialized())
    195     {
    196         _shared->SetLastError(VE_NOT_INITED, kTraceError);
    197         return -1;
    198     }
    199 
    200     uint32_t micVol(0);
    201     uint32_t maxVol(0);
    202 
    203     if (_shared->audio_device()->MicrophoneVolume(&micVol) != 0)
    204     {
    205         _shared->SetLastError(VE_GET_MIC_VOL_ERROR, kTraceError,
    206             "GetMicVolume() unable to get microphone volume");
    207         return -1;
    208     }
    209 
    210     // scale: [0, MaxMicrophoneVolume] -> [0, kMaxVolumeLevel]
    211     if (_shared->audio_device()->MaxMicrophoneVolume(&maxVol) != 0)
    212     {
    213         _shared->SetLastError(VE_GET_MIC_VOL_ERROR, kTraceError,
    214             "GetMicVolume() unable to get max microphone volume");
    215         return -1;
    216     }
    217     if (micVol < maxVol) {
    218       // Round the value and avoid floating point calculation.
    219       volume = (uint32_t) ((micVol * kMaxVolumeLevel +
    220           (int)(maxVol / 2)) / (maxVol));
    221     } else {
    222       // Truncate the value to the kMaxVolumeLevel.
    223       volume = kMaxVolumeLevel;
    224     }
    225 
    226     WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
    227         VoEId(_shared->instance_id(), -1),
    228         "GetMicVolume() => volume=%d", volume);
    229     return 0;
    230 }
    231 
    232 int VoEVolumeControlImpl::SetInputMute(int channel, bool enable)
    233 {
    234     WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
    235                "SetInputMute(channel=%d, enable=%d)", channel, enable);
    236 
    237     if (!_shared->statistics().Initialized())
    238     {
    239         _shared->SetLastError(VE_NOT_INITED, kTraceError);
    240         return -1;
    241     }
    242     if (channel == -1)
    243     {
    244         // Mute before demultiplexing <=> affects all channels
    245         return _shared->transmit_mixer()->SetMute(enable);
    246     }
    247     // Mute after demultiplexing <=> affects one channel only
    248     voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
    249     voe::Channel* channelPtr = ch.channel();
    250     if (channelPtr == NULL)
    251     {
    252         _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
    253             "SetInputMute() failed to locate channel");
    254         return -1;
    255     }
    256     return channelPtr->SetMute(enable);
    257 }
    258 
    259 int VoEVolumeControlImpl::GetInputMute(int channel, bool& enabled)
    260 {
    261     WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
    262                "GetInputMute(channel=%d)", channel);
    263 
    264     if (!_shared->statistics().Initialized())
    265     {
    266         _shared->SetLastError(VE_NOT_INITED, kTraceError);
    267         return -1;
    268     }
    269     if (channel == -1)
    270     {
    271         enabled = _shared->transmit_mixer()->Mute();
    272     }
    273     else
    274     {
    275         voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
    276         voe::Channel* channelPtr = ch.channel();
    277         if (channelPtr == NULL)
    278         {
    279             _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
    280                 "SetInputMute() failed to locate channel");
    281             return -1;
    282         }
    283         enabled = channelPtr->Mute();
    284     }
    285     WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
    286         VoEId(_shared->instance_id(), -1),
    287         "GetInputMute() => enabled = %d", (int)enabled);
    288     return 0;
    289 }
    290 
    291 int VoEVolumeControlImpl::GetSpeechInputLevel(unsigned int& level)
    292 {
    293     WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
    294                "GetSpeechInputLevel()");
    295 
    296     if (!_shared->statistics().Initialized())
    297     {
    298         _shared->SetLastError(VE_NOT_INITED, kTraceError);
    299         return -1;
    300     }
    301     int8_t currentLevel = _shared->transmit_mixer()->AudioLevel();
    302     level = static_cast<unsigned int> (currentLevel);
    303     WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
    304         VoEId(_shared->instance_id(), -1),
    305         "GetSpeechInputLevel() => %d", level);
    306     return 0;
    307 }
    308 
    309 int VoEVolumeControlImpl::GetSpeechOutputLevel(int channel,
    310                                                unsigned int& level)
    311 {
    312     WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
    313                "GetSpeechOutputLevel(channel=%d, level=?)", channel);
    314 
    315     if (!_shared->statistics().Initialized())
    316     {
    317         _shared->SetLastError(VE_NOT_INITED, kTraceError);
    318         return -1;
    319     }
    320     if (channel == -1)
    321     {
    322         return _shared->output_mixer()->GetSpeechOutputLevel(
    323             (uint32_t&)level);
    324     }
    325     else
    326     {
    327         voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
    328         voe::Channel* channelPtr = ch.channel();
    329         if (channelPtr == NULL)
    330         {
    331             _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
    332                 "GetSpeechOutputLevel() failed to locate channel");
    333             return -1;
    334         }
    335         channelPtr->GetSpeechOutputLevel((uint32_t&)level);
    336     }
    337     return 0;
    338 }
    339 
    340 int VoEVolumeControlImpl::GetSpeechInputLevelFullRange(unsigned int& level)
    341 {
    342     WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
    343                "GetSpeechInputLevelFullRange(level=?)");
    344 
    345     if (!_shared->statistics().Initialized())
    346     {
    347         _shared->SetLastError(VE_NOT_INITED, kTraceError);
    348         return -1;
    349     }
    350     int16_t currentLevel = _shared->transmit_mixer()->
    351         AudioLevelFullRange();
    352     level = static_cast<unsigned int> (currentLevel);
    353     WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
    354         VoEId(_shared->instance_id(), -1),
    355         "GetSpeechInputLevelFullRange() => %d", level);
    356     return 0;
    357 }
    358 
    359 int VoEVolumeControlImpl::GetSpeechOutputLevelFullRange(int channel,
    360                                                         unsigned int& level)
    361 {
    362     WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
    363                "GetSpeechOutputLevelFullRange(channel=%d, level=?)", channel);
    364 
    365     if (!_shared->statistics().Initialized())
    366     {
    367         _shared->SetLastError(VE_NOT_INITED, kTraceError);
    368         return -1;
    369     }
    370     if (channel == -1)
    371     {
    372         return _shared->output_mixer()->GetSpeechOutputLevelFullRange(
    373             (uint32_t&)level);
    374     }
    375     else
    376     {
    377         voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
    378         voe::Channel* channelPtr = ch.channel();
    379         if (channelPtr == NULL)
    380         {
    381             _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
    382                 "GetSpeechOutputLevelFullRange() failed to locate channel");
    383             return -1;
    384         }
    385         channelPtr->GetSpeechOutputLevelFullRange((uint32_t&)level);
    386     }
    387     return 0;
    388 }
    389 
    390 int VoEVolumeControlImpl::SetChannelOutputVolumeScaling(int channel,
    391                                                         float scaling)
    392 {
    393     WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
    394                "SetChannelOutputVolumeScaling(channel=%d, scaling=%3.2f)",
    395                channel, scaling);
    396     if (!_shared->statistics().Initialized())
    397     {
    398         _shared->SetLastError(VE_NOT_INITED, kTraceError);
    399         return -1;
    400     }
    401     if (scaling < kMinOutputVolumeScaling ||
    402         scaling > kMaxOutputVolumeScaling)
    403     {
    404         _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
    405             "SetChannelOutputVolumeScaling() invalid parameter");
    406         return -1;
    407     }
    408     voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
    409     voe::Channel* channelPtr = ch.channel();
    410     if (channelPtr == NULL)
    411     {
    412         _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
    413             "SetChannelOutputVolumeScaling() failed to locate channel");
    414         return -1;
    415     }
    416     return channelPtr->SetChannelOutputVolumeScaling(scaling);
    417 }
    418 
    419 int VoEVolumeControlImpl::GetChannelOutputVolumeScaling(int channel,
    420                                                         float& scaling)
    421 {
    422     WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
    423                "GetChannelOutputVolumeScaling(channel=%d, scaling=?)", channel);
    424     if (!_shared->statistics().Initialized())
    425     {
    426         _shared->SetLastError(VE_NOT_INITED, kTraceError);
    427         return -1;
    428     }
    429     voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
    430     voe::Channel* channelPtr = ch.channel();
    431     if (channelPtr == NULL)
    432     {
    433         _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
    434             "GetChannelOutputVolumeScaling() failed to locate channel");
    435         return -1;
    436     }
    437     return channelPtr->GetChannelOutputVolumeScaling(scaling);
    438 }
    439 
    440 int VoEVolumeControlImpl::SetOutputVolumePan(int channel,
    441                                              float left,
    442                                              float right)
    443 {
    444     WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
    445                "SetOutputVolumePan(channel=%d, left=%2.1f, right=%2.1f)",
    446                channel, left, right);
    447 
    448     if (!_shared->statistics().Initialized())
    449     {
    450         _shared->SetLastError(VE_NOT_INITED, kTraceError);
    451         return -1;
    452     }
    453 
    454     bool available(false);
    455     _shared->audio_device()->StereoPlayoutIsAvailable(&available);
    456     if (!available)
    457     {
    458         _shared->SetLastError(VE_FUNC_NO_STEREO, kTraceError,
    459             "SetOutputVolumePan() stereo playout not supported");
    460         return -1;
    461     }
    462     if ((left < kMinOutputVolumePanning)  ||
    463         (left > kMaxOutputVolumePanning)  ||
    464         (right < kMinOutputVolumePanning) ||
    465         (right > kMaxOutputVolumePanning))
    466     {
    467         _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
    468             "SetOutputVolumePan() invalid parameter");
    469         return -1;
    470     }
    471 
    472     if (channel == -1)
    473     {
    474         // Master balance (affectes the signal after output mixing)
    475         return _shared->output_mixer()->SetOutputVolumePan(left, right);
    476     }
    477     // Per-channel balance (affects the signal before output mixing)
    478     voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
    479     voe::Channel* channelPtr = ch.channel();
    480     if (channelPtr == NULL)
    481     {
    482         _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
    483             "SetOutputVolumePan() failed to locate channel");
    484         return -1;
    485     }
    486     return channelPtr->SetOutputVolumePan(left, right);
    487 }
    488 
    489 int VoEVolumeControlImpl::GetOutputVolumePan(int channel,
    490                                              float& left,
    491                                              float& right)
    492 {
    493     WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
    494                "GetOutputVolumePan(channel=%d, left=?, right=?)", channel);
    495 
    496     if (!_shared->statistics().Initialized())
    497     {
    498         _shared->SetLastError(VE_NOT_INITED, kTraceError);
    499         return -1;
    500     }
    501 
    502     bool available(false);
    503     _shared->audio_device()->StereoPlayoutIsAvailable(&available);
    504     if (!available)
    505     {
    506         _shared->SetLastError(VE_FUNC_NO_STEREO, kTraceError,
    507             "GetOutputVolumePan() stereo playout not supported");
    508         return -1;
    509     }
    510 
    511     if (channel == -1)
    512     {
    513         return _shared->output_mixer()->GetOutputVolumePan(left, right);
    514     }
    515     voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
    516     voe::Channel* channelPtr = ch.channel();
    517     if (channelPtr == NULL)
    518     {
    519         _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
    520             "GetOutputVolumePan() failed to locate channel");
    521         return -1;
    522     }
    523     return channelPtr->GetOutputVolumePan(left, right);
    524 }
    525 
    526 #endif  // #ifdef WEBRTC_VOICE_ENGINE_VOLUME_CONTROL_API
    527 
    528 }  // namespace webrtc
    529