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