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