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