blob: d0f3de1e0570bd2d65e72f91fdcb4a2081d40d2b [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
xians@webrtc.org3ab6dda2012-02-16 18:15:54 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
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.org956aa7e2013-05-21 13:52:32 +000011#include "webrtc/voice_engine/voe_volume_control_impl.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000012
pbos@webrtc.org956aa7e2013-05-21 13:52:32 +000013#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"
niklase@google.com470e71d2011-07-07 08:21:25 +000020
21namespace webrtc {
22
Jelena Marusic0d266052015-05-04 14:15:32 +020023VoEVolumeControl* VoEVolumeControl::GetInterface(VoiceEngine* voiceEngine) {
niklase@google.com470e71d2011-07-07 08:21:25 +000024#ifndef WEBRTC_VOICE_ENGINE_VOLUME_CONTROL_API
Jelena Marusic0d266052015-05-04 14:15:32 +020025 return NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +000026#else
Jelena Marusic0d266052015-05-04 14:15:32 +020027 if (NULL == voiceEngine) {
28 return NULL;
29 }
30 VoiceEngineImpl* s = static_cast<VoiceEngineImpl*>(voiceEngine);
31 s->AddRef();
32 return s;
niklase@google.com470e71d2011-07-07 08:21:25 +000033#endif
34}
35
36#ifdef WEBRTC_VOICE_ENGINE_VOLUME_CONTROL_API
37
tommi@webrtc.org851becd2012-04-04 14:57:19 +000038VoEVolumeControlImpl::VoEVolumeControlImpl(voe::SharedData* shared)
Jelena Marusic0d266052015-05-04 14:15:32 +020039 : _shared(shared) {
40 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +000041 "VoEVolumeControlImpl::VoEVolumeControlImpl() - ctor");
42}
43
Jelena Marusic0d266052015-05-04 14:15:32 +020044VoEVolumeControlImpl::~VoEVolumeControlImpl() {
45 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +000046 "VoEVolumeControlImpl::~VoEVolumeControlImpl() - dtor");
47}
48
Jelena Marusic0d266052015-05-04 14:15:32 +020049int VoEVolumeControlImpl::SetSpeakerVolume(unsigned int volume) {
50 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +000051 "SetSpeakerVolume(volume=%u)", volume);
niklase@google.com470e71d2011-07-07 08:21:25 +000052
Jelena Marusic0d266052015-05-04 14:15:32 +020053 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 }
niklase@google.com470e71d2011-07-07 08:21:25 +000062
Jelena Marusic0d266052015-05-04 14:15:32 +020063 uint32_t maxVol(0);
64 uint32_t spkrVol(0);
niklase@google.com470e71d2011-07-07 08:21:25 +000065
Jelena Marusic0d266052015-05-04 14:15:32 +020066 // 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));
niklase@google.com470e71d2011-07-07 08:21:25 +000075
Jelena Marusic0d266052015-05-04 14:15:32 +020076 // 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;
niklase@google.com470e71d2011-07-07 08:21:25 +000083}
84
Jelena Marusic0d266052015-05-04 14:15:32 +020085int VoEVolumeControlImpl::GetSpeakerVolume(unsigned int& volume) {
niklase@google.com470e71d2011-07-07 08:21:25 +000086
Jelena Marusic0d266052015-05-04 14:15:32 +020087 if (!_shared->statistics().Initialized()) {
88 _shared->SetLastError(VE_NOT_INITED, kTraceError);
89 return -1;
90 }
niklase@google.com470e71d2011-07-07 08:21:25 +000091
Jelena Marusic0d266052015-05-04 14:15:32 +020092 uint32_t spkrVol(0);
93 uint32_t maxVol(0);
niklase@google.com470e71d2011-07-07 08:21:25 +000094
Jelena Marusic0d266052015-05-04 14:15:32 +020095 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 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000100
Jelena Marusic0d266052015-05-04 14:15:32 +0200101 // 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));
niklase@google.com470e71d2011-07-07 08:21:25 +0000111
Jelena Marusic0d266052015-05-04 14:15:32 +0200112 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000113}
114
Jelena Marusic0d266052015-05-04 14:15:32 +0200115int VoEVolumeControlImpl::SetMicVolume(unsigned int volume) {
116 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000117 "SetMicVolume(volume=%u)", volume);
niklase@google.com470e71d2011-07-07 08:21:25 +0000118
Jelena Marusic0d266052015-05-04 14:15:32 +0200119 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 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000128
Jelena Marusic0d266052015-05-04 14:15:32 +0200129 uint32_t maxVol(0);
130 uint32_t micVol(0);
niklase@google.com470e71d2011-07-07 08:21:25 +0000131
Jelena Marusic0d266052015-05-04 14:15:32 +0200132 // 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;
niklase@google.com470e71d2011-07-07 08:21:25 +0000149 }
Jelena Marusic0d266052015-05-04 14:15:32 +0200150 if (micVol >= maxVol)
151 return 0;
152 }
xians@webrtc.org3ab6dda2012-02-16 18:15:54 +0000153
Jelena Marusic0d266052015-05-04 14:15:32 +0200154 // Round the value and avoid floating point computation.
155 micVol = (uint32_t)((volume * maxVol + (int)(kMaxVolumeLevel / 2)) /
156 (kMaxVolumeLevel));
xians@webrtc.org3ab6dda2012-02-16 18:15:54 +0000157
Jelena Marusic0d266052015-05-04 14:15:32 +0200158 // 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;
niklase@google.com470e71d2011-07-07 08:21:25 +0000165}
166
Jelena Marusic0d266052015-05-04 14:15:32 +0200167int VoEVolumeControlImpl::GetMicVolume(unsigned int& volume) {
Jelena Marusic0d266052015-05-04 14:15:32 +0200168 if (!_shared->statistics().Initialized()) {
169 _shared->SetLastError(VE_NOT_INITED, kTraceError);
170 return -1;
171 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000172
Jelena Marusic0d266052015-05-04 14:15:32 +0200173 uint32_t micVol(0);
174 uint32_t maxVol(0);
niklase@google.com470e71d2011-07-07 08:21:25 +0000175
Jelena Marusic0d266052015-05-04 14:15:32 +0200176 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 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000181
Jelena Marusic0d266052015-05-04 14:15:32 +0200182 // 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 }
Jelena Marusic0d266052015-05-04 14:15:32 +0200196 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000197}
198
Jelena Marusic0d266052015-05-04 14:15:32 +0200199int VoEVolumeControlImpl::SetInputMute(int channel, bool enable) {
200 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000201 "SetInputMute(channel=%d, enable=%d)", channel, enable);
202
Jelena Marusic0d266052015-05-04 14:15:32 +0200203 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);
niklase@google.com470e71d2011-07-07 08:21:25 +0000220}
221
Jelena Marusic0d266052015-05-04 14:15:32 +0200222int VoEVolumeControlImpl::GetInputMute(int channel, bool& enabled) {
Jelena Marusic0d266052015-05-04 14:15:32 +0200223 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;
niklase@google.com470e71d2011-07-07 08:21:25 +0000236 }
Jelena Marusic0d266052015-05-04 14:15:32 +0200237 enabled = channelPtr->Mute();
238 }
Jelena Marusic0d266052015-05-04 14:15:32 +0200239 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000240}
241
Jelena Marusic0d266052015-05-04 14:15:32 +0200242int VoEVolumeControlImpl::GetSpeechInputLevel(unsigned int& level) {
Jelena Marusic0d266052015-05-04 14:15:32 +0200243 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);
Jelena Marusic0d266052015-05-04 14:15:32 +0200249 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000250}
251
252int VoEVolumeControlImpl::GetSpeechOutputLevel(int channel,
Jelena Marusic0d266052015-05-04 14:15:32 +0200253 unsigned int& level) {
Jelena Marusic0d266052015-05-04 14:15:32 +0200254 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;
niklase@google.com470e71d2011-07-07 08:21:25 +0000267 }
Jelena Marusic0d266052015-05-04 14:15:32 +0200268 channelPtr->GetSpeechOutputLevel((uint32_t&)level);
269 }
270 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000271}
272
Jelena Marusic0d266052015-05-04 14:15:32 +0200273int VoEVolumeControlImpl::GetSpeechInputLevelFullRange(unsigned int& level) {
Jelena Marusic0d266052015-05-04 14:15:32 +0200274 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);
Jelena Marusic0d266052015-05-04 14:15:32 +0200280 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000281}
282
283int VoEVolumeControlImpl::GetSpeechOutputLevelFullRange(int channel,
Jelena Marusic0d266052015-05-04 14:15:32 +0200284 unsigned int& level) {
Jelena Marusic0d266052015-05-04 14:15:32 +0200285 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;
niklase@google.com470e71d2011-07-07 08:21:25 +0000300 }
Jelena Marusic0d266052015-05-04 14:15:32 +0200301 channelPtr->GetSpeechOutputLevelFullRange((uint32_t&)level);
302 }
303 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000304}
305
306int VoEVolumeControlImpl::SetChannelOutputVolumeScaling(int channel,
Jelena Marusic0d266052015-05-04 14:15:32 +0200307 float scaling) {
308 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000309 "SetChannelOutputVolumeScaling(channel=%d, scaling=%3.2f)",
310 channel, scaling);
Jelena Marusic0d266052015-05-04 14:15:32 +0200311 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);
niklase@google.com470e71d2011-07-07 08:21:25 +0000329}
330
331int VoEVolumeControlImpl::GetChannelOutputVolumeScaling(int channel,
Jelena Marusic0d266052015-05-04 14:15:32 +0200332 float& scaling) {
Jelena Marusic0d266052015-05-04 14:15:32 +0200333 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);
niklase@google.com470e71d2011-07-07 08:21:25 +0000346}
347
348int VoEVolumeControlImpl::SetOutputVolumePan(int channel,
349 float left,
Jelena Marusic0d266052015-05-04 14:15:32 +0200350 float right) {
351 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
niklase@google.com470e71d2011-07-07 08:21:25 +0000352 "SetOutputVolumePan(channel=%d, left=%2.1f, right=%2.1f)",
353 channel, left, right);
niklase@google.com470e71d2011-07-07 08:21:25 +0000354
Jelena Marusic0d266052015-05-04 14:15:32 +0200355 if (!_shared->statistics().Initialized()) {
356 _shared->SetLastError(VE_NOT_INITED, kTraceError);
357 return -1;
358 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000359
Jelena Marusic0d266052015-05-04 14:15:32 +0200360 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 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000373
Jelena Marusic0d266052015-05-04 14:15:32 +0200374 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);
niklase@google.com470e71d2011-07-07 08:21:25 +0000387}
388
389int VoEVolumeControlImpl::GetOutputVolumePan(int channel,
390 float& left,
Jelena Marusic0d266052015-05-04 14:15:32 +0200391 float& right) {
Jelena Marusic0d266052015-05-04 14:15:32 +0200392 if (!_shared->statistics().Initialized()) {
393 _shared->SetLastError(VE_NOT_INITED, kTraceError);
394 return -1;
395 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000396
Jelena Marusic0d266052015-05-04 14:15:32 +0200397 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 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000404
Jelena Marusic0d266052015-05-04 14:15:32 +0200405 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);
niklase@google.com470e71d2011-07-07 08:21:25 +0000416}
417
418#endif // #ifdef WEBRTC_VOICE_ENGINE_VOLUME_CONTROL_API
419
420} // namespace webrtc