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