• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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