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