blob: eb17db3219baca15497c5ec13be065694fafa6d3 [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) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:2323#ifndef WEBRTC_VOICE_ENGINE_VOLUME_CONTROL_API
Jelena Marusic0705a022015-05-04 12:15:3224 return NULL;
andrew@webrtc.orgb015cbe2012-10-22 18:19:2325#else
Jelena Marusic0705a022015-05-04 12:15:3226 if (NULL == voiceEngine) {
27 return NULL;
28 }
29 VoiceEngineImpl* s = static_cast<VoiceEngineImpl*>(voiceEngine);
30 s->AddRef();
31 return s;
andrew@webrtc.orgb015cbe2012-10-22 18:19:2332#endif
33}
34
35#ifdef WEBRTC_VOICE_ENGINE_VOLUME_CONTROL_API
36
37VoEVolumeControlImpl::VoEVolumeControlImpl(voe::SharedData* shared)
Jelena Marusic0705a022015-05-04 12:15:3238 : _shared(shared) {
39 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
andrew@webrtc.orgb015cbe2012-10-22 18:19:2340 "VoEVolumeControlImpl::VoEVolumeControlImpl() - ctor");
41}
42
Jelena Marusic0705a022015-05-04 12:15:3243VoEVolumeControlImpl::~VoEVolumeControlImpl() {
44 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
andrew@webrtc.orgb015cbe2012-10-22 18:19:2345 "VoEVolumeControlImpl::~VoEVolumeControlImpl() - dtor");
46}
47
Jelena Marusic0705a022015-05-04 12:15:3248int VoEVolumeControlImpl::SetSpeakerVolume(unsigned int volume) {
49 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
andrew@webrtc.orgb015cbe2012-10-22 18:19:2350 "SetSpeakerVolume(volume=%u)", volume);
andrew@webrtc.orgb015cbe2012-10-22 18:19:2351
Jelena Marusic0705a022015-05-04 12:15:3252 if (!_shared->statistics().Initialized()) {
53 _shared->SetLastError(VE_NOT_INITED, kTraceError);
54 return -1;
55 }
56 if (volume > kMaxVolumeLevel) {
57 _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
58 "SetSpeakerVolume() invalid argument");
59 return -1;
60 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:2361
Jelena Marusic0705a022015-05-04 12:15:3262 uint32_t maxVol(0);
63 uint32_t spkrVol(0);
andrew@webrtc.orgb015cbe2012-10-22 18:19:2364
Jelena Marusic0705a022015-05-04 12:15:3265 // scale: [0,kMaxVolumeLevel] -> [0,MaxSpeakerVolume]
66 if (_shared->audio_device()->MaxSpeakerVolume(&maxVol) != 0) {
67 _shared->SetLastError(VE_MIC_VOL_ERROR, kTraceError,
68 "SetSpeakerVolume() failed to get max volume");
69 return -1;
70 }
71 // Round the value and avoid floating computation.
72 spkrVol = (uint32_t)((volume * maxVol + (int)(kMaxVolumeLevel / 2)) /
73 (kMaxVolumeLevel));
andrew@webrtc.orgb015cbe2012-10-22 18:19:2374
Jelena Marusic0705a022015-05-04 12:15:3275 // set the actual volume using the audio mixer
76 if (_shared->audio_device()->SetSpeakerVolume(spkrVol) != 0) {
77 _shared->SetLastError(VE_MIC_VOL_ERROR, kTraceError,
78 "SetSpeakerVolume() failed to set speaker volume");
79 return -1;
80 }
81 return 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:2382}
83
Jelena Marusic0705a022015-05-04 12:15:3284int VoEVolumeControlImpl::GetSpeakerVolume(unsigned int& volume) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:2385
Jelena Marusic0705a022015-05-04 12:15:3286 if (!_shared->statistics().Initialized()) {
87 _shared->SetLastError(VE_NOT_INITED, kTraceError);
88 return -1;
89 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:2390
Jelena Marusic0705a022015-05-04 12:15:3291 uint32_t spkrVol(0);
92 uint32_t maxVol(0);
andrew@webrtc.orgb015cbe2012-10-22 18:19:2393
Jelena Marusic0705a022015-05-04 12:15:3294 if (_shared->audio_device()->SpeakerVolume(&spkrVol) != 0) {
95 _shared->SetLastError(VE_GET_MIC_VOL_ERROR, kTraceError,
96 "GetSpeakerVolume() unable to get speaker volume");
97 return -1;
98 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:2399
Jelena Marusic0705a022015-05-04 12:15:32100 // scale: [0, MaxSpeakerVolume] -> [0, kMaxVolumeLevel]
101 if (_shared->audio_device()->MaxSpeakerVolume(&maxVol) != 0) {
102 _shared->SetLastError(
103 VE_GET_MIC_VOL_ERROR, kTraceError,
104 "GetSpeakerVolume() unable to get max speaker volume");
105 return -1;
106 }
107 // Round the value and avoid floating computation.
108 volume =
109 (uint32_t)((spkrVol * kMaxVolumeLevel + (int)(maxVol / 2)) / (maxVol));
andrew@webrtc.orgb015cbe2012-10-22 18:19:23110
Jelena Marusic0705a022015-05-04 12:15:32111 return 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23112}
113
Jelena Marusic0705a022015-05-04 12:15:32114int VoEVolumeControlImpl::SetMicVolume(unsigned int volume) {
115 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23116 "SetMicVolume(volume=%u)", volume);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23117
Jelena Marusic0705a022015-05-04 12:15:32118 if (!_shared->statistics().Initialized()) {
119 _shared->SetLastError(VE_NOT_INITED, kTraceError);
120 return -1;
121 }
122 if (volume > kMaxVolumeLevel) {
123 _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
124 "SetMicVolume() invalid argument");
125 return -1;
126 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23127
Jelena Marusic0705a022015-05-04 12:15:32128 uint32_t maxVol(0);
129 uint32_t micVol(0);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23130
Jelena Marusic0705a022015-05-04 12:15:32131 // scale: [0, kMaxVolumeLevel] -> [0,MaxMicrophoneVolume]
132 if (_shared->audio_device()->MaxMicrophoneVolume(&maxVol) != 0) {
133 _shared->SetLastError(VE_MIC_VOL_ERROR, kTraceError,
134 "SetMicVolume() failed to get max volume");
135 return -1;
136 }
137
138 if (volume == kMaxVolumeLevel) {
139 // On Linux running pulse, users are able to set the volume above 100%
140 // through the volume control panel, where the +100% range is digital
141 // scaling. WebRTC does not support setting the volume above 100%, and
142 // simply ignores changing the volume if the user tries to set it to
143 // |kMaxVolumeLevel| while the current volume is higher than |maxVol|.
144 if (_shared->audio_device()->MicrophoneVolume(&micVol) != 0) {
145 _shared->SetLastError(VE_GET_MIC_VOL_ERROR, kTraceError,
146 "SetMicVolume() unable to get microphone volume");
147 return -1;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23148 }
Jelena Marusic0705a022015-05-04 12:15:32149 if (micVol >= maxVol)
150 return 0;
151 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23152
Jelena Marusic0705a022015-05-04 12:15:32153 // Round the value and avoid floating point computation.
154 micVol = (uint32_t)((volume * maxVol + (int)(kMaxVolumeLevel / 2)) /
155 (kMaxVolumeLevel));
andrew@webrtc.orgb015cbe2012-10-22 18:19:23156
Jelena Marusic0705a022015-05-04 12:15:32157 // set the actual volume using the audio mixer
158 if (_shared->audio_device()->SetMicrophoneVolume(micVol) != 0) {
159 _shared->SetLastError(VE_MIC_VOL_ERROR, kTraceError,
160 "SetMicVolume() failed to set mic volume");
161 return -1;
162 }
163 return 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23164}
165
Jelena Marusic0705a022015-05-04 12:15:32166int VoEVolumeControlImpl::GetMicVolume(unsigned int& volume) {
Jelena Marusic0705a022015-05-04 12:15:32167 if (!_shared->statistics().Initialized()) {
168 _shared->SetLastError(VE_NOT_INITED, kTraceError);
169 return -1;
170 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23171
Jelena Marusic0705a022015-05-04 12:15:32172 uint32_t micVol(0);
173 uint32_t maxVol(0);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23174
Jelena Marusic0705a022015-05-04 12:15:32175 if (_shared->audio_device()->MicrophoneVolume(&micVol) != 0) {
176 _shared->SetLastError(VE_GET_MIC_VOL_ERROR, kTraceError,
177 "GetMicVolume() unable to get microphone volume");
178 return -1;
179 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23180
Jelena Marusic0705a022015-05-04 12:15:32181 // scale: [0, MaxMicrophoneVolume] -> [0, kMaxVolumeLevel]
182 if (_shared->audio_device()->MaxMicrophoneVolume(&maxVol) != 0) {
183 _shared->SetLastError(VE_GET_MIC_VOL_ERROR, kTraceError,
184 "GetMicVolume() unable to get max microphone volume");
185 return -1;
186 }
187 if (micVol < maxVol) {
188 // Round the value and avoid floating point calculation.
189 volume =
190 (uint32_t)((micVol * kMaxVolumeLevel + (int)(maxVol / 2)) / (maxVol));
191 } else {
192 // Truncate the value to the kMaxVolumeLevel.
193 volume = kMaxVolumeLevel;
194 }
Jelena Marusic0705a022015-05-04 12:15:32195 return 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23196}
197
Jelena Marusic0705a022015-05-04 12:15:32198int VoEVolumeControlImpl::SetInputMute(int channel, bool enable) {
199 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23200 "SetInputMute(channel=%d, enable=%d)", channel, enable);
201
Jelena Marusic0705a022015-05-04 12:15:32202 if (!_shared->statistics().Initialized()) {
203 _shared->SetLastError(VE_NOT_INITED, kTraceError);
204 return -1;
205 }
206 if (channel == -1) {
207 // Mute before demultiplexing <=> affects all channels
208 return _shared->transmit_mixer()->SetMute(enable);
209 }
210 // Mute after demultiplexing <=> affects one channel only
211 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
212 voe::Channel* channelPtr = ch.channel();
213 if (channelPtr == NULL) {
214 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
215 "SetInputMute() failed to locate channel");
216 return -1;
217 }
solenbergb120b5b2016-03-24 17:36:00218 return channelPtr->SetInputMute(enable);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23219}
220
Jelena Marusic0705a022015-05-04 12:15:32221int VoEVolumeControlImpl::GetInputMute(int channel, bool& enabled) {
Jelena Marusic0705a022015-05-04 12:15:32222 if (!_shared->statistics().Initialized()) {
223 _shared->SetLastError(VE_NOT_INITED, kTraceError);
224 return -1;
225 }
226 if (channel == -1) {
227 enabled = _shared->transmit_mixer()->Mute();
228 } else {
229 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
230 voe::Channel* channelPtr = ch.channel();
231 if (channelPtr == NULL) {
232 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
233 "SetInputMute() failed to locate channel");
234 return -1;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23235 }
solenbergb120b5b2016-03-24 17:36:00236 enabled = channelPtr->InputMute();
Jelena Marusic0705a022015-05-04 12:15:32237 }
Jelena Marusic0705a022015-05-04 12:15:32238 return 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23239}
240
Jelena Marusic0705a022015-05-04 12:15:32241int VoEVolumeControlImpl::GetSpeechInputLevel(unsigned int& level) {
Jelena Marusic0705a022015-05-04 12:15:32242 if (!_shared->statistics().Initialized()) {
243 _shared->SetLastError(VE_NOT_INITED, kTraceError);
244 return -1;
245 }
246 int8_t currentLevel = _shared->transmit_mixer()->AudioLevel();
247 level = static_cast<unsigned int>(currentLevel);
Jelena Marusic0705a022015-05-04 12:15:32248 return 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23249}
250
251int VoEVolumeControlImpl::GetSpeechOutputLevel(int channel,
Jelena Marusic0705a022015-05-04 12:15:32252 unsigned int& level) {
Jelena Marusic0705a022015-05-04 12:15:32253 if (!_shared->statistics().Initialized()) {
254 _shared->SetLastError(VE_NOT_INITED, kTraceError);
255 return -1;
256 }
257 if (channel == -1) {
258 return _shared->output_mixer()->GetSpeechOutputLevel((uint32_t&)level);
259 } else {
260 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
261 voe::Channel* channelPtr = ch.channel();
262 if (channelPtr == NULL) {
263 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
264 "GetSpeechOutputLevel() failed to locate channel");
265 return -1;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23266 }
Jelena Marusic0705a022015-05-04 12:15:32267 channelPtr->GetSpeechOutputLevel((uint32_t&)level);
268 }
269 return 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23270}
271
Jelena Marusic0705a022015-05-04 12:15:32272int VoEVolumeControlImpl::GetSpeechInputLevelFullRange(unsigned int& level) {
Jelena Marusic0705a022015-05-04 12:15:32273 if (!_shared->statistics().Initialized()) {
274 _shared->SetLastError(VE_NOT_INITED, kTraceError);
275 return -1;
276 }
277 int16_t currentLevel = _shared->transmit_mixer()->AudioLevelFullRange();
278 level = static_cast<unsigned int>(currentLevel);
Jelena Marusic0705a022015-05-04 12:15:32279 return 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23280}
281
282int VoEVolumeControlImpl::GetSpeechOutputLevelFullRange(int channel,
Jelena Marusic0705a022015-05-04 12:15:32283 unsigned int& level) {
Jelena Marusic0705a022015-05-04 12:15:32284 if (!_shared->statistics().Initialized()) {
285 _shared->SetLastError(VE_NOT_INITED, kTraceError);
286 return -1;
287 }
288 if (channel == -1) {
289 return _shared->output_mixer()->GetSpeechOutputLevelFullRange(
290 (uint32_t&)level);
291 } else {
292 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
293 voe::Channel* channelPtr = ch.channel();
294 if (channelPtr == NULL) {
295 _shared->SetLastError(
296 VE_CHANNEL_NOT_VALID, kTraceError,
297 "GetSpeechOutputLevelFullRange() failed to locate channel");
298 return -1;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23299 }
Jelena Marusic0705a022015-05-04 12:15:32300 channelPtr->GetSpeechOutputLevelFullRange((uint32_t&)level);
301 }
302 return 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23303}
304
305int VoEVolumeControlImpl::SetChannelOutputVolumeScaling(int channel,
Jelena Marusic0705a022015-05-04 12:15:32306 float scaling) {
307 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23308 "SetChannelOutputVolumeScaling(channel=%d, scaling=%3.2f)",
309 channel, scaling);
Jelena Marusic0705a022015-05-04 12:15:32310 if (!_shared->statistics().Initialized()) {
311 _shared->SetLastError(VE_NOT_INITED, kTraceError);
312 return -1;
313 }
314 if (scaling < kMinOutputVolumeScaling || scaling > kMaxOutputVolumeScaling) {
315 _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
316 "SetChannelOutputVolumeScaling() invalid parameter");
317 return -1;
318 }
319 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
320 voe::Channel* channelPtr = ch.channel();
321 if (channelPtr == NULL) {
322 _shared->SetLastError(
323 VE_CHANNEL_NOT_VALID, kTraceError,
324 "SetChannelOutputVolumeScaling() failed to locate channel");
325 return -1;
326 }
327 return channelPtr->SetChannelOutputVolumeScaling(scaling);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23328}
329
330int VoEVolumeControlImpl::GetChannelOutputVolumeScaling(int channel,
Jelena Marusic0705a022015-05-04 12:15:32331 float& scaling) {
Jelena Marusic0705a022015-05-04 12:15:32332 if (!_shared->statistics().Initialized()) {
333 _shared->SetLastError(VE_NOT_INITED, kTraceError);
334 return -1;
335 }
336 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
337 voe::Channel* channelPtr = ch.channel();
338 if (channelPtr == NULL) {
339 _shared->SetLastError(
340 VE_CHANNEL_NOT_VALID, kTraceError,
341 "GetChannelOutputVolumeScaling() failed to locate channel");
342 return -1;
343 }
344 return channelPtr->GetChannelOutputVolumeScaling(scaling);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23345}
346
347int VoEVolumeControlImpl::SetOutputVolumePan(int channel,
348 float left,
Jelena Marusic0705a022015-05-04 12:15:32349 float right) {
350 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23351 "SetOutputVolumePan(channel=%d, left=%2.1f, right=%2.1f)",
352 channel, left, right);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23353
Jelena Marusic0705a022015-05-04 12:15:32354 if (!_shared->statistics().Initialized()) {
355 _shared->SetLastError(VE_NOT_INITED, kTraceError);
356 return -1;
357 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23358
Jelena Marusic0705a022015-05-04 12:15:32359 bool available(false);
360 _shared->audio_device()->StereoPlayoutIsAvailable(&available);
361 if (!available) {
362 _shared->SetLastError(VE_FUNC_NO_STEREO, kTraceError,
363 "SetOutputVolumePan() stereo playout not supported");
364 return -1;
365 }
366 if ((left < kMinOutputVolumePanning) || (left > kMaxOutputVolumePanning) ||
367 (right < kMinOutputVolumePanning) || (right > kMaxOutputVolumePanning)) {
368 _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
369 "SetOutputVolumePan() invalid parameter");
370 return -1;
371 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23372
Jelena Marusic0705a022015-05-04 12:15:32373 if (channel == -1) {
374 // Master balance (affectes the signal after output mixing)
375 return _shared->output_mixer()->SetOutputVolumePan(left, right);
376 }
377 // Per-channel balance (affects the signal before output mixing)
378 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
379 voe::Channel* channelPtr = ch.channel();
380 if (channelPtr == NULL) {
381 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
382 "SetOutputVolumePan() failed to locate channel");
383 return -1;
384 }
385 return channelPtr->SetOutputVolumePan(left, right);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23386}
387
388int VoEVolumeControlImpl::GetOutputVolumePan(int channel,
389 float& left,
Jelena Marusic0705a022015-05-04 12:15:32390 float& right) {
Jelena Marusic0705a022015-05-04 12:15:32391 if (!_shared->statistics().Initialized()) {
392 _shared->SetLastError(VE_NOT_INITED, kTraceError);
393 return -1;
394 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23395
Jelena Marusic0705a022015-05-04 12:15:32396 bool available(false);
397 _shared->audio_device()->StereoPlayoutIsAvailable(&available);
398 if (!available) {
399 _shared->SetLastError(VE_FUNC_NO_STEREO, kTraceError,
400 "GetOutputVolumePan() stereo playout not supported");
401 return -1;
402 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23403
Jelena Marusic0705a022015-05-04 12:15:32404 if (channel == -1) {
405 return _shared->output_mixer()->GetOutputVolumePan(left, right);
406 }
407 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
408 voe::Channel* channelPtr = ch.channel();
409 if (channelPtr == NULL) {
410 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
411 "GetOutputVolumePan() failed to locate channel");
412 return -1;
413 }
414 return channelPtr->GetOutputVolumePan(left, right);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23415}
416
417#endif // #ifdef WEBRTC_VOICE_ENGINE_VOLUME_CONTROL_API
418
419} // namespace webrtc