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