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
GetInterface(VoiceEngine * voiceEngine)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
VoEVolumeControlImpl(voe::SharedData * shared)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
~VoEVolumeControlImpl()47 VoEVolumeControlImpl::~VoEVolumeControlImpl()
48 {
49 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
50 "VoEVolumeControlImpl::~VoEVolumeControlImpl() - dtor");
51 }
52
SetSpeakerVolume(unsigned int volume)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
GetSpeakerVolume(unsigned int & volume)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
SetMicVolume(unsigned int volume)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
GetMicVolume(unsigned int & volume)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
SetInputMute(int channel,bool enable)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
GetInputMute(int channel,bool & enabled)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
GetSpeechInputLevel(unsigned int & level)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
GetSpeechOutputLevel(int channel,unsigned int & level)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
GetSpeechInputLevelFullRange(unsigned int & level)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
GetSpeechOutputLevelFullRange(int channel,unsigned int & level)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
SetChannelOutputVolumeScaling(int channel,float scaling)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
GetChannelOutputVolumeScaling(int channel,float & scaling)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
SetOutputVolumePan(int channel,float left,float right)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
GetOutputVolumePan(int channel,float & left,float & right)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