blob: 0d79c6c6812616a64f5e80feedb27d727803aac2 [file] [log] [blame]
andrew@webrtc.orgb015cbe2012-10-22 18:19:231/*
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
pbos@webrtc.org471ae722013-05-21 13:52:3211#include "webrtc/voice_engine/voe_volume_control_impl.h"
andrew@webrtc.orgb015cbe2012-10-22 18:19:2312
Henrik Kjellander78f65d02015-10-28 17:17:4013#include "webrtc/system_wrappers/include/trace.h"
pbos@webrtc.org471ae722013-05-21 13:52:3214#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"
andrew@webrtc.orgb015cbe2012-10-22 18:19:2319
20namespace webrtc {
21
Jelena Marusic0705a022015-05-04 12:15:3222VoEVolumeControl* VoEVolumeControl::GetInterface(VoiceEngine* voiceEngine) {
Jelena Marusic0705a022015-05-04 12:15:3223 if (NULL == voiceEngine) {
24 return NULL;
25 }
26 VoiceEngineImpl* s = static_cast<VoiceEngineImpl*>(voiceEngine);
27 s->AddRef();
28 return s;
andrew@webrtc.orgb015cbe2012-10-22 18:19:2329}
30
andrew@webrtc.orgb015cbe2012-10-22 18:19:2331VoEVolumeControlImpl::VoEVolumeControlImpl(voe::SharedData* shared)
Jelena Marusic0705a022015-05-04 12:15:3232 : _shared(shared) {
33 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
andrew@webrtc.orgb015cbe2012-10-22 18:19:2334 "VoEVolumeControlImpl::VoEVolumeControlImpl() - ctor");
35}
36
Jelena Marusic0705a022015-05-04 12:15:3237VoEVolumeControlImpl::~VoEVolumeControlImpl() {
38 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
andrew@webrtc.orgb015cbe2012-10-22 18:19:2339 "VoEVolumeControlImpl::~VoEVolumeControlImpl() - dtor");
40}
41
Jelena Marusic0705a022015-05-04 12:15:3242int VoEVolumeControlImpl::SetSpeakerVolume(unsigned int volume) {
43 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
andrew@webrtc.orgb015cbe2012-10-22 18:19:2344 "SetSpeakerVolume(volume=%u)", volume);
andrew@webrtc.orgb015cbe2012-10-22 18:19:2345
Jelena Marusic0705a022015-05-04 12:15:3246 if (!_shared->statistics().Initialized()) {
47 _shared->SetLastError(VE_NOT_INITED, kTraceError);
48 return -1;
49 }
50 if (volume > kMaxVolumeLevel) {
51 _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
52 "SetSpeakerVolume() invalid argument");
53 return -1;
54 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:2355
Jelena Marusic0705a022015-05-04 12:15:3256 uint32_t maxVol(0);
57 uint32_t spkrVol(0);
andrew@webrtc.orgb015cbe2012-10-22 18:19:2358
Jelena Marusic0705a022015-05-04 12:15:3259 // scale: [0,kMaxVolumeLevel] -> [0,MaxSpeakerVolume]
60 if (_shared->audio_device()->MaxSpeakerVolume(&maxVol) != 0) {
61 _shared->SetLastError(VE_MIC_VOL_ERROR, kTraceError,
62 "SetSpeakerVolume() failed to get max volume");
63 return -1;
64 }
65 // Round the value and avoid floating computation.
66 spkrVol = (uint32_t)((volume * maxVol + (int)(kMaxVolumeLevel / 2)) /
67 (kMaxVolumeLevel));
andrew@webrtc.orgb015cbe2012-10-22 18:19:2368
Jelena Marusic0705a022015-05-04 12:15:3269 // set the actual volume using the audio mixer
70 if (_shared->audio_device()->SetSpeakerVolume(spkrVol) != 0) {
71 _shared->SetLastError(VE_MIC_VOL_ERROR, kTraceError,
72 "SetSpeakerVolume() failed to set speaker volume");
73 return -1;
74 }
75 return 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:2376}
77
Jelena Marusic0705a022015-05-04 12:15:3278int VoEVolumeControlImpl::GetSpeakerVolume(unsigned int& volume) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:2379
Jelena Marusic0705a022015-05-04 12:15:3280 if (!_shared->statistics().Initialized()) {
81 _shared->SetLastError(VE_NOT_INITED, kTraceError);
82 return -1;
83 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:2384
Jelena Marusic0705a022015-05-04 12:15:3285 uint32_t spkrVol(0);
86 uint32_t maxVol(0);
andrew@webrtc.orgb015cbe2012-10-22 18:19:2387
Jelena Marusic0705a022015-05-04 12:15:3288 if (_shared->audio_device()->SpeakerVolume(&spkrVol) != 0) {
89 _shared->SetLastError(VE_GET_MIC_VOL_ERROR, kTraceError,
90 "GetSpeakerVolume() unable to get speaker volume");
91 return -1;
92 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:2393
Jelena Marusic0705a022015-05-04 12:15:3294 // scale: [0, MaxSpeakerVolume] -> [0, kMaxVolumeLevel]
95 if (_shared->audio_device()->MaxSpeakerVolume(&maxVol) != 0) {
96 _shared->SetLastError(
97 VE_GET_MIC_VOL_ERROR, kTraceError,
98 "GetSpeakerVolume() unable to get max speaker volume");
99 return -1;
100 }
101 // Round the value and avoid floating computation.
102 volume =
103 (uint32_t)((spkrVol * kMaxVolumeLevel + (int)(maxVol / 2)) / (maxVol));
andrew@webrtc.orgb015cbe2012-10-22 18:19:23104
Jelena Marusic0705a022015-05-04 12:15:32105 return 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23106}
107
Jelena Marusic0705a022015-05-04 12:15:32108int VoEVolumeControlImpl::SetMicVolume(unsigned int volume) {
109 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23110 "SetMicVolume(volume=%u)", volume);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23111
Jelena Marusic0705a022015-05-04 12:15:32112 if (!_shared->statistics().Initialized()) {
113 _shared->SetLastError(VE_NOT_INITED, kTraceError);
114 return -1;
115 }
116 if (volume > kMaxVolumeLevel) {
117 _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
118 "SetMicVolume() invalid argument");
119 return -1;
120 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23121
Jelena Marusic0705a022015-05-04 12:15:32122 uint32_t maxVol(0);
123 uint32_t micVol(0);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23124
Jelena Marusic0705a022015-05-04 12:15:32125 // scale: [0, kMaxVolumeLevel] -> [0,MaxMicrophoneVolume]
126 if (_shared->audio_device()->MaxMicrophoneVolume(&maxVol) != 0) {
127 _shared->SetLastError(VE_MIC_VOL_ERROR, kTraceError,
128 "SetMicVolume() failed to get max volume");
129 return -1;
130 }
131
132 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 if (_shared->audio_device()->MicrophoneVolume(&micVol) != 0) {
139 _shared->SetLastError(VE_GET_MIC_VOL_ERROR, kTraceError,
140 "SetMicVolume() unable to get microphone volume");
141 return -1;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23142 }
Jelena Marusic0705a022015-05-04 12:15:32143 if (micVol >= maxVol)
144 return 0;
145 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23146
Jelena Marusic0705a022015-05-04 12:15:32147 // Round the value and avoid floating point computation.
148 micVol = (uint32_t)((volume * maxVol + (int)(kMaxVolumeLevel / 2)) /
149 (kMaxVolumeLevel));
andrew@webrtc.orgb015cbe2012-10-22 18:19:23150
Jelena Marusic0705a022015-05-04 12:15:32151 // set the actual volume using the audio mixer
152 if (_shared->audio_device()->SetMicrophoneVolume(micVol) != 0) {
153 _shared->SetLastError(VE_MIC_VOL_ERROR, kTraceError,
154 "SetMicVolume() failed to set mic volume");
155 return -1;
156 }
157 return 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23158}
159
Jelena Marusic0705a022015-05-04 12:15:32160int VoEVolumeControlImpl::GetMicVolume(unsigned int& volume) {
Jelena Marusic0705a022015-05-04 12:15:32161 if (!_shared->statistics().Initialized()) {
162 _shared->SetLastError(VE_NOT_INITED, kTraceError);
163 return -1;
164 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23165
Jelena Marusic0705a022015-05-04 12:15:32166 uint32_t micVol(0);
167 uint32_t maxVol(0);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23168
Jelena Marusic0705a022015-05-04 12:15:32169 if (_shared->audio_device()->MicrophoneVolume(&micVol) != 0) {
170 _shared->SetLastError(VE_GET_MIC_VOL_ERROR, kTraceError,
171 "GetMicVolume() unable to get microphone volume");
172 return -1;
173 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23174
Jelena Marusic0705a022015-05-04 12:15:32175 // scale: [0, MaxMicrophoneVolume] -> [0, kMaxVolumeLevel]
176 if (_shared->audio_device()->MaxMicrophoneVolume(&maxVol) != 0) {
177 _shared->SetLastError(VE_GET_MIC_VOL_ERROR, kTraceError,
178 "GetMicVolume() unable to get max microphone volume");
179 return -1;
180 }
181 if (micVol < maxVol) {
182 // Round the value and avoid floating point calculation.
183 volume =
184 (uint32_t)((micVol * kMaxVolumeLevel + (int)(maxVol / 2)) / (maxVol));
185 } else {
186 // Truncate the value to the kMaxVolumeLevel.
187 volume = kMaxVolumeLevel;
188 }
Jelena Marusic0705a022015-05-04 12:15:32189 return 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23190}
191
Jelena Marusic0705a022015-05-04 12:15:32192int VoEVolumeControlImpl::SetInputMute(int channel, bool enable) {
193 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23194 "SetInputMute(channel=%d, enable=%d)", channel, enable);
195
Jelena Marusic0705a022015-05-04 12:15:32196 if (!_shared->statistics().Initialized()) {
197 _shared->SetLastError(VE_NOT_INITED, kTraceError);
198 return -1;
199 }
200 if (channel == -1) {
201 // Mute before demultiplexing <=> affects all channels
202 return _shared->transmit_mixer()->SetMute(enable);
203 }
204 // Mute after demultiplexing <=> affects one channel only
205 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
206 voe::Channel* channelPtr = ch.channel();
207 if (channelPtr == NULL) {
208 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
209 "SetInputMute() failed to locate channel");
210 return -1;
211 }
solenbergb120b5b2016-03-24 17:36:00212 return channelPtr->SetInputMute(enable);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23213}
214
Jelena Marusic0705a022015-05-04 12:15:32215int VoEVolumeControlImpl::GetInputMute(int channel, bool& enabled) {
Jelena Marusic0705a022015-05-04 12:15:32216 if (!_shared->statistics().Initialized()) {
217 _shared->SetLastError(VE_NOT_INITED, kTraceError);
218 return -1;
219 }
220 if (channel == -1) {
221 enabled = _shared->transmit_mixer()->Mute();
222 } else {
223 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
224 voe::Channel* channelPtr = ch.channel();
225 if (channelPtr == NULL) {
226 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
227 "SetInputMute() failed to locate channel");
228 return -1;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23229 }
solenbergb120b5b2016-03-24 17:36:00230 enabled = channelPtr->InputMute();
Jelena Marusic0705a022015-05-04 12:15:32231 }
Jelena Marusic0705a022015-05-04 12:15:32232 return 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23233}
234
Jelena Marusic0705a022015-05-04 12:15:32235int VoEVolumeControlImpl::GetSpeechInputLevel(unsigned int& level) {
Jelena Marusic0705a022015-05-04 12:15:32236 if (!_shared->statistics().Initialized()) {
237 _shared->SetLastError(VE_NOT_INITED, kTraceError);
238 return -1;
239 }
240 int8_t currentLevel = _shared->transmit_mixer()->AudioLevel();
241 level = static_cast<unsigned int>(currentLevel);
Jelena Marusic0705a022015-05-04 12:15:32242 return 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23243}
244
245int VoEVolumeControlImpl::GetSpeechOutputLevel(int channel,
Jelena Marusic0705a022015-05-04 12:15:32246 unsigned int& level) {
Jelena Marusic0705a022015-05-04 12:15:32247 if (!_shared->statistics().Initialized()) {
248 _shared->SetLastError(VE_NOT_INITED, kTraceError);
249 return -1;
250 }
251 if (channel == -1) {
252 return _shared->output_mixer()->GetSpeechOutputLevel((uint32_t&)level);
253 } else {
254 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
255 voe::Channel* channelPtr = ch.channel();
256 if (channelPtr == NULL) {
257 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
258 "GetSpeechOutputLevel() failed to locate channel");
259 return -1;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23260 }
Jelena Marusic0705a022015-05-04 12:15:32261 channelPtr->GetSpeechOutputLevel((uint32_t&)level);
262 }
263 return 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23264}
265
Jelena Marusic0705a022015-05-04 12:15:32266int VoEVolumeControlImpl::GetSpeechInputLevelFullRange(unsigned int& level) {
Jelena Marusic0705a022015-05-04 12:15:32267 if (!_shared->statistics().Initialized()) {
268 _shared->SetLastError(VE_NOT_INITED, kTraceError);
269 return -1;
270 }
271 int16_t currentLevel = _shared->transmit_mixer()->AudioLevelFullRange();
272 level = static_cast<unsigned int>(currentLevel);
Jelena Marusic0705a022015-05-04 12:15:32273 return 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23274}
275
276int VoEVolumeControlImpl::GetSpeechOutputLevelFullRange(int channel,
Jelena Marusic0705a022015-05-04 12:15:32277 unsigned int& level) {
Jelena Marusic0705a022015-05-04 12:15:32278 if (!_shared->statistics().Initialized()) {
279 _shared->SetLastError(VE_NOT_INITED, kTraceError);
280 return -1;
281 }
282 if (channel == -1) {
283 return _shared->output_mixer()->GetSpeechOutputLevelFullRange(
284 (uint32_t&)level);
285 } else {
286 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
287 voe::Channel* channelPtr = ch.channel();
288 if (channelPtr == NULL) {
289 _shared->SetLastError(
290 VE_CHANNEL_NOT_VALID, kTraceError,
291 "GetSpeechOutputLevelFullRange() failed to locate channel");
292 return -1;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23293 }
Jelena Marusic0705a022015-05-04 12:15:32294 channelPtr->GetSpeechOutputLevelFullRange((uint32_t&)level);
295 }
296 return 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23297}
298
299int VoEVolumeControlImpl::SetChannelOutputVolumeScaling(int channel,
Jelena Marusic0705a022015-05-04 12:15:32300 float scaling) {
301 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23302 "SetChannelOutputVolumeScaling(channel=%d, scaling=%3.2f)",
303 channel, scaling);
Jelena Marusic0705a022015-05-04 12:15:32304 if (!_shared->statistics().Initialized()) {
305 _shared->SetLastError(VE_NOT_INITED, kTraceError);
306 return -1;
307 }
308 if (scaling < kMinOutputVolumeScaling || scaling > kMaxOutputVolumeScaling) {
309 _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
310 "SetChannelOutputVolumeScaling() invalid parameter");
311 return -1;
312 }
313 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
314 voe::Channel* channelPtr = ch.channel();
315 if (channelPtr == NULL) {
316 _shared->SetLastError(
317 VE_CHANNEL_NOT_VALID, kTraceError,
318 "SetChannelOutputVolumeScaling() failed to locate channel");
319 return -1;
320 }
321 return channelPtr->SetChannelOutputVolumeScaling(scaling);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23322}
323
324int VoEVolumeControlImpl::GetChannelOutputVolumeScaling(int channel,
Jelena Marusic0705a022015-05-04 12:15:32325 float& scaling) {
Jelena Marusic0705a022015-05-04 12:15:32326 if (!_shared->statistics().Initialized()) {
327 _shared->SetLastError(VE_NOT_INITED, kTraceError);
328 return -1;
329 }
330 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
331 voe::Channel* channelPtr = ch.channel();
332 if (channelPtr == NULL) {
333 _shared->SetLastError(
334 VE_CHANNEL_NOT_VALID, kTraceError,
335 "GetChannelOutputVolumeScaling() failed to locate channel");
336 return -1;
337 }
338 return channelPtr->GetChannelOutputVolumeScaling(scaling);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23339}
340
341int VoEVolumeControlImpl::SetOutputVolumePan(int channel,
342 float left,
Jelena Marusic0705a022015-05-04 12:15:32343 float right) {
344 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23345 "SetOutputVolumePan(channel=%d, left=%2.1f, right=%2.1f)",
346 channel, left, right);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23347
Jelena Marusic0705a022015-05-04 12:15:32348 if (!_shared->statistics().Initialized()) {
349 _shared->SetLastError(VE_NOT_INITED, kTraceError);
350 return -1;
351 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23352
Jelena Marusic0705a022015-05-04 12:15:32353 bool available(false);
354 _shared->audio_device()->StereoPlayoutIsAvailable(&available);
355 if (!available) {
356 _shared->SetLastError(VE_FUNC_NO_STEREO, kTraceError,
357 "SetOutputVolumePan() stereo playout not supported");
358 return -1;
359 }
360 if ((left < kMinOutputVolumePanning) || (left > kMaxOutputVolumePanning) ||
361 (right < kMinOutputVolumePanning) || (right > kMaxOutputVolumePanning)) {
362 _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
363 "SetOutputVolumePan() invalid parameter");
364 return -1;
365 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23366
Jelena Marusic0705a022015-05-04 12:15:32367 if (channel == -1) {
368 // Master balance (affectes the signal after output mixing)
369 return _shared->output_mixer()->SetOutputVolumePan(left, right);
370 }
371 // Per-channel balance (affects the signal before output mixing)
372 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
373 voe::Channel* channelPtr = ch.channel();
374 if (channelPtr == NULL) {
375 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
376 "SetOutputVolumePan() failed to locate channel");
377 return -1;
378 }
379 return channelPtr->SetOutputVolumePan(left, right);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23380}
381
382int VoEVolumeControlImpl::GetOutputVolumePan(int channel,
383 float& left,
Jelena Marusic0705a022015-05-04 12:15:32384 float& right) {
Jelena Marusic0705a022015-05-04 12:15:32385 if (!_shared->statistics().Initialized()) {
386 _shared->SetLastError(VE_NOT_INITED, kTraceError);
387 return -1;
388 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23389
Jelena Marusic0705a022015-05-04 12:15:32390 bool available(false);
391 _shared->audio_device()->StereoPlayoutIsAvailable(&available);
392 if (!available) {
393 _shared->SetLastError(VE_FUNC_NO_STEREO, kTraceError,
394 "GetOutputVolumePan() stereo playout not supported");
395 return -1;
396 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23397
Jelena Marusic0705a022015-05-04 12:15:32398 if (channel == -1) {
399 return _shared->output_mixer()->GetOutputVolumePan(left, right);
400 }
401 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
402 voe::Channel* channelPtr = ch.channel();
403 if (channelPtr == NULL) {
404 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
405 "GetOutputVolumePan() failed to locate channel");
406 return -1;
407 }
408 return channelPtr->GetOutputVolumePan(left, right);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23409}
410
andrew@webrtc.orgb015cbe2012-10-22 18:19:23411} // namespace webrtc