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/modules/audio_device/win/audio_mixer_manager_win.h"
12 #include "webrtc/system_wrappers/interface/trace.h"
13
14 #include <assert.h> // assert()
15 #include <strsafe.h> // StringCchCopy(), StringCchCat(), StringCchPrintf()
16
17 #ifdef _WIN32
18 // removes warning: "reinterpret_cast: conversion from 'UINT' to 'HMIXEROBJ'
19 // of greater size"
20 #pragma warning(disable:4312)
21 #endif
22
23 // Avoids the need of Windows 7 SDK
24 #ifndef WAVE_MAPPED_kDefaultCommunicationDevice
25 #define WAVE_MAPPED_kDefaultCommunicationDevice 0x0010
26 #endif
27
28 namespace webrtc {
29
30 // ============================================================================
31 // CONSTRUCTION/DESTRUCTION
32 // ============================================================================
33
AudioMixerManager(const int32_t id)34 AudioMixerManager::AudioMixerManager(const int32_t id) :
35 _critSect(*CriticalSectionWrapper::CreateCriticalSection()),
36 _id(id),
37 _inputMixerHandle(NULL),
38 _outputMixerHandle(NULL)
39 {
40 WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s constructed", __FUNCTION__);
41 ClearSpeakerState();
42 ClearMicrophoneState();
43 }
44
~AudioMixerManager()45 AudioMixerManager::~AudioMixerManager()
46 {
47 WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s destructed", __FUNCTION__);
48
49 Close();
50
51 delete &_critSect;
52 }
53
54 // ============================================================================
55 // PUBLIC METHODS
56 // ============================================================================
57
58 // ----------------------------------------------------------------------------
59 // Close
60 // ----------------------------------------------------------------------------
61
Close()62 int32_t AudioMixerManager::Close()
63 {
64 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", __FUNCTION__);
65
66 CriticalSectionScoped lock(&_critSect);
67
68 if (_outputMixerHandle != NULL)
69 {
70 mixerClose(_outputMixerHandle);
71 _outputMixerHandle = NULL;
72 }
73 if (_inputMixerHandle != NULL)
74 {
75 mixerClose(_inputMixerHandle);
76 _inputMixerHandle = NULL;
77 }
78 return 0;
79
80 }
81
82 // ----------------------------------------------------------------------------
83 // CloseSpeaker
84 // ----------------------------------------------------------------------------
85
CloseSpeaker()86 int32_t AudioMixerManager::CloseSpeaker()
87 {
88 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", __FUNCTION__);
89
90 CriticalSectionScoped lock(&_critSect);
91
92 if (_outputMixerHandle == NULL)
93 {
94 return -1;
95 }
96
97 ClearSpeakerState(_outputMixerID);
98
99 mixerClose(_outputMixerHandle);
100 _outputMixerHandle = NULL;
101
102 return 0;
103 }
104
105 // ----------------------------------------------------------------------------
106 // CloseMicrophone
107 // ----------------------------------------------------------------------------
108
CloseMicrophone()109 int32_t AudioMixerManager::CloseMicrophone()
110 {
111 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", __FUNCTION__);
112
113 CriticalSectionScoped lock(&_critSect);
114
115 if (_inputMixerHandle == NULL)
116 {
117 return -1;
118 }
119
120 ClearMicrophoneState(_inputMixerID);
121
122 mixerClose(_inputMixerHandle);
123 _inputMixerHandle = NULL;
124
125 return 0;
126 }
127
128 // ----------------------------------------------------------------------------
129 // EnumerateAll
130 // ----------------------------------------------------------------------------
131
EnumerateAll()132 int32_t AudioMixerManager::EnumerateAll()
133 {
134 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", __FUNCTION__);
135
136 UINT nDevices = mixerGetNumDevs();
137 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "#mixer devices: %u", nDevices);
138
139 MIXERCAPS caps;
140 MIXERLINE destLine;
141 MIXERLINE sourceLine;
142 MIXERCONTROL controlArray[MAX_NUMBER_OF_LINE_CONTROLS];
143
144 UINT mixId(0);
145 UINT destId(0);
146 UINT sourceId(0);
147
148 for (mixId = 0; mixId < nDevices; mixId++)
149 {
150 if (!GetCapabilities(mixId, caps, true))
151 continue;
152
153 for (destId = 0; destId < caps.cDestinations; destId++)
154 {
155 GetDestinationLineInfo(mixId, destId, destLine, true);
156 GetAllLineControls(mixId, destLine, controlArray, true);
157
158 for (sourceId = 0; sourceId < destLine.cConnections; sourceId++)
159 {
160 GetSourceLineInfo(mixId, destId, sourceId, sourceLine, true);
161 GetAllLineControls(mixId, sourceLine, controlArray, true);
162 }
163 }
164 }
165
166 return 0;
167 }
168
169 // ----------------------------------------------------------------------------
170 // EnumerateSpeakers
171 // ----------------------------------------------------------------------------
172
EnumerateSpeakers()173 int32_t AudioMixerManager::EnumerateSpeakers()
174 {
175 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", __FUNCTION__);
176
177 UINT nDevices = mixerGetNumDevs();
178 if (nDevices > MAX_NUMBER_MIXER_DEVICES)
179 {
180 assert(false);
181 return -1;
182 }
183 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "#mixer devices: %u", nDevices);
184
185 MIXERCAPS caps;
186 MIXERLINE destLine;
187 MIXERCONTROL controlArray[MAX_NUMBER_OF_LINE_CONTROLS];
188
189 UINT mixId(0);
190 UINT destId(0);
191
192 ClearSpeakerState();
193
194 // scan all avaliable mixer devices
195 for (mixId = 0; mixId < nDevices; mixId++)
196 {
197 // get capabilities for the specified mixer ID
198 GetCapabilities(mixId, caps);
199 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "[mixerID=%d] %s: ", mixId, WideToUTF8(caps.szPname));
200 // scan all avaliable destinations for this mixer
201 for (destId = 0; destId < caps.cDestinations; destId++)
202 {
203 GetDestinationLineInfo(mixId, destId, destLine);
204 if ((destLine.cControls == 0) || // no controls or
205 (destLine.cConnections == 0) || // no source lines or
206 (destLine.fdwLine & MIXERLINE_LINEF_DISCONNECTED) || // disconnected or
207 !(destLine.fdwLine & MIXERLINE_LINEF_ACTIVE)) // inactive
208 {
209 // don't store this line ID since it will not be possible to control
210 continue;
211 }
212 if ((destLine.dwComponentType == MIXERLINE_COMPONENTTYPE_DST_SPEAKERS) ||
213 (destLine.dwComponentType == MIXERLINE_COMPONENTTYPE_DST_HEADPHONES))
214 {
215 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "found valid speaker/headphone (name: %s, ID: %u)", WideToUTF8(destLine.szName), destLine.dwLineID);
216 _speakerState[mixId].dwLineID = destLine.dwLineID;
217 _speakerState[mixId].speakerIsValid = true;
218 // retrieve all controls for the speaker component
219 GetAllLineControls(mixId, destLine, controlArray);
220 for (UINT c = 0; c < destLine.cControls; c++)
221 {
222 if (controlArray[c].dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME)
223 {
224 _speakerState[mixId].dwVolumeControlID = controlArray[c].dwControlID;
225 _speakerState[mixId].volumeControlIsValid = true;
226 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "found volume control (name: %s, ID: %u)", WideToUTF8(controlArray[c].szName), controlArray[c].dwControlID);
227 }
228 else if (controlArray[c].dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE)
229 {
230 _speakerState[mixId].dwMuteControlID = controlArray[c].dwControlID;
231 _speakerState[mixId].muteControlIsValid = true;
232 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "found mute control (name: %s, ID: %u)", WideToUTF8(controlArray[c].szName), controlArray[c].dwControlID);
233 }
234 }
235 break;
236 }
237 }
238 if (!SpeakerIsValid(mixId))
239 {
240 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "unable to find a valid speaker destination line", mixId);
241 }
242 }
243
244 if (ValidSpeakers() == 0)
245 {
246 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "failed to locate any valid speaker line");
247 return -1;
248 }
249
250 return 0;
251 }
252
253 // ----------------------------------------------------------------------------
254 // EnumerateMicrophones
255 // ----------------------------------------------------------------------------
256
EnumerateMicrophones()257 int32_t AudioMixerManager::EnumerateMicrophones()
258 {
259 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", __FUNCTION__);
260
261 UINT nDevices = mixerGetNumDevs();
262 if (nDevices > MAX_NUMBER_MIXER_DEVICES)
263 {
264 assert(false);
265 return -1;
266 }
267 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "#mixer devices: %u", nDevices);
268
269 MIXERCAPS caps;
270 MIXERLINE destLine;
271 MIXERLINE sourceLine;
272 MIXERCONTROL controlArray[MAX_NUMBER_OF_LINE_CONTROLS];
273
274 UINT mixId(0);
275 UINT destId(0);
276
277 ClearMicrophoneState();
278
279 // scan all avaliable mixer devices
280 for (mixId = 0; mixId < nDevices; mixId++)
281 {
282 // get capabilities for the specified mixer ID
283 GetCapabilities(mixId, caps);
284 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "[mixerID=%d] %s: ", mixId, WideToUTF8(caps.szPname));
285 // scan all avaliable destinations for this mixer
286 for (destId = 0; destId < caps.cDestinations; destId++)
287 {
288 GetDestinationLineInfo(mixId, destId, destLine);
289
290 if ((destLine.cConnections == 0) || // no source lines or
291 (destLine.fdwLine & MIXERLINE_LINEF_DISCONNECTED) || // disconnected or
292 !(destLine.fdwLine & MIXERLINE_LINEF_ACTIVE)) // inactive
293 {
294 // Don't store this line ID since there are no sources connected to this destination.
295 // Compare with the speaker side where we also exclude lines with no controls.
296 continue;
297 }
298
299 if (destLine.dwComponentType == MIXERLINE_COMPONENTTYPE_DST_WAVEIN)
300 {
301 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "found valid Wave In destination (name: %s, ID: %u)", WideToUTF8(destLine.szName), destLine.dwLineID);
302 _microphoneState[mixId].dwLineID = destLine.dwLineID;
303 _microphoneState[mixId].microphoneIsValid = true;
304
305 // retrieve all controls for the identified wave-in destination
306 if (!GetAllLineControls(mixId, destLine, controlArray))
307 {
308 // This destination has no controls. We must try to control
309 // one of its sources instead.
310 // This is a rare state but has been found for some
311 // Logitech USB headsets.
312
313 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
314 "this destination has no controls => must control source");
315 for (DWORD sourceId = 0; sourceId < destLine.cConnections; sourceId++)
316 {
317 GetSourceLineInfo(mixId, destId, sourceId, sourceLine, false);
318 if (sourceLine.dwComponentType ==
319 MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE)
320 {
321 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
322 "found microphone source ( name: %s, ID: %u)",
323 WideToUTF8(sourceLine.szName), sourceId);
324 GetAllLineControls(mixId, sourceLine, controlArray, false);
325 // scan the controls for this source and search for volume,
326 // mute and on/off (<=> boost) controls
327 for (UINT sc = 0; sc < sourceLine.cControls; sc++)
328 {
329 if (controlArray[sc].dwControlType ==
330 MIXERCONTROL_CONTROLTYPE_VOLUME)
331 {
332 // store this volume control
333 _microphoneState[mixId].dwVolumeControlID =
334 controlArray[sc].dwControlID;
335 _microphoneState[mixId].volumeControlIsValid = true;
336 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
337 "found volume control (name: %s, ID: %u)",
338 WideToUTF8(controlArray[sc].szName),
339 controlArray[sc].dwControlID);
340 }
341 else if (controlArray[sc].dwControlType ==
342 MIXERCONTROL_CONTROLTYPE_MUTE)
343 {
344 // store this mute control
345 _microphoneState[mixId].dwMuteControlID =
346 controlArray[sc].dwControlID;
347 _microphoneState[mixId].muteControlIsValid = true;
348 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
349 "found mute control (name: %s, ID: %u)",
350 WideToUTF8(controlArray[sc].szName),
351 controlArray[sc].dwControlID);
352 }
353 else if (controlArray[sc].dwControlType ==
354 MIXERCONTROL_CONTROLTYPE_ONOFF ||
355 controlArray[sc].dwControlType ==
356 MIXERCONTROL_CONTROLTYPE_LOUDNESS)
357 {
358 // store this on/off control (most likely a Boost control)
359 _microphoneState[mixId].dwOnOffControlID =
360 controlArray[sc].dwControlID;
361 _microphoneState[mixId].onOffControlIsValid = true;
362 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
363 "found on/off control (name: %s, ID: %u)",
364 WideToUTF8(controlArray[sc].szName),
365 controlArray[sc].dwControlID);
366 }
367 }
368 }
369 }
370
371 break;
372 }
373
374 // It seems like there are three different configurations we can find in this state:
375 //
376 // (1) The Wave-in destination contains one MUX control only
377 // (2) The Wave-in destination contains one or more controls where one is a volume control
378 // (3) On Vista and Win 7, it seems like case 2 above is extended.
379 // It is common that a Wave-in destination has two master controls (volume and mute),
380 // AND a microphone source as well with its own volume and mute controls with unique
381 // identifiers. Initial tests have shown that it is sufficient to modify the master
382 // controls only. The source controls will "follow" the master settings, hence the
383 // source controls seem to be redundant.
384 //
385 // For case 1, we should locate the selected source and its controls. The MUX setting will
386 // give us the selected source. NOTE - the selecion might not be a microphone.
387 //
388 // For case 2, the volume control works as a master level control and we should use that one.
389 //
390 // For case 3, we use the master controls only and assume that the source control will "follow".
391 //
392 // Examples of case 1: - SigmaTel Audio (built-in)
393 // - add more..
394 //
395 // Examples of case 2: - Plantronics USB Headset
396 // - Eutectics IPP 200 USB phone
397 // - add more...
398 //
399 // Examples of case 3: - Realtek High Definition on Vista (TL)
400 // - add more...
401
402 if ((destLine.cControls == 1) &&
403 (controlArray[0].dwControlType == MIXERCONTROL_CONTROLTYPE_MUX))
404 {
405 // Case 1: MUX control detected => locate the selected source and its volume control
406 // Note that, the selecion might not be a microphone. A warning is given for
407 // this case only, i.e., it is OK to control a selected Line In source as long
408 // as it is connected to the wave-in destination.
409
410 UINT selection(0);
411 const DWORD nItemsInMux(controlArray[0].cMultipleItems);
412
413 // decide which source line that is selected in the mux
414 if (GetSelectedMuxSource(mixId, controlArray[0].dwControlID, nItemsInMux, selection))
415 {
416 // selection now contains the index of the selected source =>
417 // read the line information for this source
418 // if conditions listed below
419 // condition 1: invalid source
420 // condition 2: no controls
421 // condition 3: disconnected
422 // condition 4: inactive
423 if (!GetSourceLineInfo(mixId, destId, selection, sourceLine) ||
424 (sourceLine.cControls == 0) ||
425 (sourceLine.fdwLine & MIXERLINE_LINEF_DISCONNECTED) ||
426 !(sourceLine.fdwLine & MIXERLINE_LINEF_ACTIVE))
427 {
428 continue;
429 }
430
431 if (sourceLine.dwComponentType != MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE)
432 {
433 // add more details about the selected source (not a microphone)
434 TraceComponentType(sourceLine.dwComponentType);
435 // send a warning just to inform about the fact that a non-microphone source will be controlled
436 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "the selected (to be controlled) source is not a microphone type");
437 }
438
439 // retrieve all controls for the selected source
440 GetAllLineControls(mixId, sourceLine, controlArray);
441 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "MUX selection is %u [0,%u]", selection, nItemsInMux-1);
442
443 // scan the controls for this source and search for volume, mute and on/off (<=> boost) controls
444 for (UINT sc = 0; sc < sourceLine.cControls; sc++)
445 {
446 if (controlArray[sc].dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME)
447 {
448 // store this volume control
449 _microphoneState[mixId].dwVolumeControlID = controlArray[sc].dwControlID;
450 _microphoneState[mixId].volumeControlIsValid = true;
451 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "found volume control (name: %s, ID: %u)", WideToUTF8(controlArray[sc].szName), controlArray[sc].dwControlID);
452 }
453 else if (controlArray[sc].dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE)
454 {
455 // store this mute control
456 _microphoneState[mixId].dwMuteControlID = controlArray[sc].dwControlID;
457 _microphoneState[mixId].muteControlIsValid = true;
458 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "found mute control (name: %s, ID: %u)", WideToUTF8(controlArray[sc].szName), controlArray[sc].dwControlID);
459 }
460 else if (controlArray[sc].dwControlType == MIXERCONTROL_CONTROLTYPE_ONOFF ||
461 controlArray[sc].dwControlType == MIXERCONTROL_CONTROLTYPE_LOUDNESS)
462 {
463 // store this on/off control (most likely a Boost control)
464 _microphoneState[mixId].dwOnOffControlID = controlArray[sc].dwControlID;
465 _microphoneState[mixId].onOffControlIsValid = true;
466 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "found on/off control (name: %s, ID: %u)", WideToUTF8(controlArray[sc].szName), controlArray[sc].dwControlID);
467 }
468 }
469 }
470 else
471 {
472 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "failed to detect which source to control");
473 }
474
475 }
476 else if (destLine.cConnections == 1)
477 {
478 // Case 2 or Case 3:
479
480 GetSourceLineInfo(mixId, destId, 0, sourceLine);
481 if ((sourceLine.dwComponentType == MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE) &&
482 (sourceLine.cControls > 0))
483 {
484 // Case 3: same as Case 2 below but we have also detected a Microphone source
485 // with its own controls. So far, I have not been able to find any device
486 // where it is required to modify these controls. Until I have found such
487 // a device, this case will be handled as a Case 2 (see below).
488
489 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "microphone source controls will not be controlled");
490 }
491 else if ((sourceLine.dwComponentType == MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE) &&
492 (sourceLine.cControls == 0))
493 {
494 // default state on non Vista/Win 7 machines
495 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "microphone source has no controls => use master controls instead");
496 }
497 else
498 {
499 // add more details about the selected source (not a microphone)
500 TraceComponentType(sourceLine.dwComponentType);
501 // send a warning just to inform about the fact that a non-microphone source will be controlled
502 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "the connected (to be controlled) source is not a microphone type");
503 }
504
505 // Case 2 : one source only and no MUX control detected =>
506 // locate the master volume control (and mute + boost controls if possible)
507
508 // scan the controls for this wave-in destination and search for volume, mute and on/off (<=> boost) controls
509 for (UINT dc = 0; dc < destLine.cControls; dc++)
510 {
511 if (controlArray[dc].dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME)
512 {
513 // store this volume control
514 _microphoneState[mixId].dwVolumeControlID = controlArray[dc].dwControlID;
515 _microphoneState[mixId].volumeControlIsValid = true;
516 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "found volume control (name: %s, ID: %u)", WideToUTF8(controlArray[dc].szName), controlArray[dc].dwControlID);
517 }
518 else if (controlArray[dc].dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE)
519 {
520 // store this mute control
521 _microphoneState[mixId].dwMuteControlID = controlArray[dc].dwControlID;
522 _microphoneState[mixId].muteControlIsValid = true;
523 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "found mute control (name: %s, ID: %u)", WideToUTF8(controlArray[dc].szName), controlArray[dc].dwControlID);
524 }
525 else if (controlArray[dc].dwControlType == MIXERCONTROL_CONTROLTYPE_ONOFF ||
526 controlArray[dc].dwControlType == MIXERCONTROL_CONTROLTYPE_LOUDNESS ||
527 controlArray[dc].dwControlType == MIXERCONTROL_CONTROLTYPE_BOOLEAN)
528 {
529 // store this on/off control
530 _microphoneState[mixId].dwOnOffControlID = controlArray[dc].dwControlID;
531 _microphoneState[mixId].onOffControlIsValid = true;
532 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "found on/off control (name: %s, ID: %u)", WideToUTF8(controlArray[dc].szName), controlArray[dc].dwControlID);
533 }
534 }
535 }
536 else
537 {
538 // We are in a state where more than one source is connected to the wave-in destination.
539 // I am bailing out here for now until I understand this case better.
540 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "failed to locate valid microphone controls for this mixer");
541 }
542 break;
543 }
544 } // for (destId = 0; destId < caps.cDestinations; destId++)
545
546 if (!MicrophoneIsValid(mixId))
547 {
548 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "unable to find a valid microphone destination line", mixId);
549 }
550 } // for (mixId = 0; mixId < nDevices; mixId++)
551
552 if (ValidMicrophones() == 0)
553 {
554 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "failed to locate any valid microphone line");
555 return -1;
556 }
557
558 return 0;
559 }
560
561 // ----------------------------------------------------------------------------
562 // OpenSpeaker I(II)
563 //
564 // Verifies that the mixer contains a valid speaker destination line.
565 // Avoids opening the mixer if valid control has not been found.
566 // ----------------------------------------------------------------------------
567
OpenSpeaker(AudioDeviceModule::WindowsDeviceType device)568 int32_t AudioMixerManager::OpenSpeaker(AudioDeviceModule::WindowsDeviceType device)
569 {
570 if (device == AudioDeviceModule::kDefaultDevice)
571 {
572 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "AudioMixerManager::OpenSpeaker(kDefaultDevice)");
573 }
574 else if (device == AudioDeviceModule::kDefaultCommunicationDevice)
575 {
576 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "AudioMixerManager::OpenSpeaker(kDefaultCommunicationDevice)");
577 }
578
579 CriticalSectionScoped lock(&_critSect);
580
581 // Close any existing output mixer handle
582 //
583 if (_outputMixerHandle != NULL)
584 {
585 mixerClose(_outputMixerHandle);
586 _outputMixerHandle = NULL;
587 }
588
589 MMRESULT res;
590 WAVEFORMATEX waveFormat;
591 HWAVEOUT hWaveOut(NULL);
592
593 waveFormat.wFormatTag = WAVE_FORMAT_PCM ;
594 waveFormat.nChannels = 2;
595 waveFormat.nSamplesPerSec = 48000;
596 waveFormat.wBitsPerSample = 16;
597 waveFormat.nBlockAlign = waveFormat.nChannels * waveFormat.wBitsPerSample / 8;
598 waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;
599 waveFormat.cbSize = 0;
600
601 // We need a waveform-audio output handle for the currently selected output device.
602 // This handle will then give us the corresponding mixer identifier. Once the mixer
603 // ID is known, it is possible to open the output mixer.
604 //
605 if (device == AudioDeviceModule::kDefaultCommunicationDevice)
606 {
607 // check if it is possible to open the default communication device (supported on Windows 7)
608 res = waveOutOpen(NULL, WAVE_MAPPER, &waveFormat, 0, 0, CALLBACK_NULL |
609 WAVE_MAPPED_kDefaultCommunicationDevice | WAVE_FORMAT_QUERY);
610 if (MMSYSERR_NOERROR == res)
611 {
612 // if so, open the default communication device for real
613 res = waveOutOpen(&hWaveOut, WAVE_MAPPER, &waveFormat, 0, 0, CALLBACK_NULL | WAVE_MAPPED_kDefaultCommunicationDevice);
614 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "opening default communication device");
615 }
616 else
617 {
618 // use default device since default communication device was not avaliable
619 res = waveOutOpen(&hWaveOut, WAVE_MAPPER, &waveFormat, 0, 0, CALLBACK_NULL);
620 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
621 "unable to open default communication device => using default instead");
622 }
623 }
624 else if (device == AudioDeviceModule::kDefaultDevice)
625 {
626 // open default device since it has been requested
627 res = waveOutOpen(&hWaveOut, WAVE_MAPPER, &waveFormat, 0, 0, CALLBACK_NULL);
628 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "opening default output device");
629 }
630
631 if (MMSYSERR_NOERROR != res)
632 {
633 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "waveOutOpen() failed (err=%d)", res);
634 TraceWaveOutError(res);
635 }
636
637 UINT mixerId(0);
638 HMIXER hMixer(NULL);
639
640 // Retrieve the device identifier for a mixer device associated with the
641 // aquired waveform-audio output handle.
642 //
643 res = mixerGetID((HMIXEROBJ)hWaveOut, &mixerId, MIXER_OBJECTF_HWAVEOUT);
644 if (MMSYSERR_NOERROR != res)
645 {
646 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "mixerGetID(MIXER_OBJECTF_HWAVEOUT) failed (err=%d)", res);
647 // identification failed => use default mixer identifier (=0)
648 mixerId = 0;
649 }
650 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "specified output device <=> mixer ID %u", mixerId);
651
652 // The waveform-audio output handle is no longer needed.
653 //
654 waveOutClose(hWaveOut);
655
656 // Verify that the mixer contains a valid speaker destination line.
657 // Avoid opening the mixer if valid control has not been found.
658 //
659 if (!SpeakerIsValid(mixerId))
660 {
661 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "it is not possible to control the speaker volume for this mixer device");
662 return -1;
663 }
664
665 // Open the specified mixer device and ensure that the device will not
666 // be removed until the application closes the handle.
667 //
668 res = mixerOpen(&hMixer, mixerId, 0, 0, MIXER_OBJECTF_MIXER);
669 if (MMSYSERR_NOERROR != res)
670 {
671 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "mixerOpen() failed (err=%d)", res);
672 }
673
674 // Store the output mixer handle and active mixer identifier
675 //
676 _outputMixerHandle = hMixer;
677 _outputMixerID = mixerId;
678
679 if (_outputMixerHandle != NULL)
680 {
681 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "the output mixer device is now open (0x%x)", _outputMixerHandle);
682 }
683
684 return 0;
685 }
686
687 // ----------------------------------------------------------------------------
688 // OpenSpeaker II(II)
689 //
690 // Verifies that the mixer contains a valid speaker destination line.
691 // Avoids opening the mixer if valid control has not been found.
692 // ----------------------------------------------------------------------------
693
OpenSpeaker(uint16_t index)694 int32_t AudioMixerManager::OpenSpeaker(uint16_t index)
695 {
696 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "AudioMixerManager::OpenSpeaker(index=%d)", index);
697
698 CriticalSectionScoped lock(&_critSect);
699
700 // Close any existing output mixer handle
701 //
702 if (_outputMixerHandle != NULL)
703 {
704 mixerClose(_outputMixerHandle);
705 _outputMixerHandle = NULL;
706 }
707
708 MMRESULT res;
709 WAVEFORMATEX waveFormat;
710 HWAVEOUT hWaveOut(NULL);
711
712 const UINT deviceID(index); // use index parameter as device identifier
713
714 waveFormat.wFormatTag = WAVE_FORMAT_PCM ;
715 waveFormat.nChannels = 2;
716 waveFormat.nSamplesPerSec = 48000;
717 waveFormat.wBitsPerSample = 16;
718 waveFormat.nBlockAlign = waveFormat.nChannels * waveFormat.wBitsPerSample / 8;
719 waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;
720 waveFormat.cbSize = 0;
721
722 // We need a waveform-audio output handle for the currently selected output device.
723 // This handle will then give us the corresponding mixer identifier. Once the mixer
724 // ID is known, it is possible to open the output mixer.
725 //
726 res = waveOutOpen(&hWaveOut, deviceID, &waveFormat, 0, 0, CALLBACK_NULL);
727 if (MMSYSERR_NOERROR != res)
728 {
729 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "waveOutOpen(deviceID=%u) failed (err=%d)", index, res);
730 TraceWaveOutError(res);
731 }
732
733 UINT mixerId(0);
734 HMIXER hMixer(NULL);
735
736 // Retrieve the device identifier for a mixer device associated with the
737 // aquired waveform-audio output handle.
738 //
739 res = mixerGetID((HMIXEROBJ)hWaveOut, &mixerId, MIXER_OBJECTF_HWAVEOUT);
740 if (MMSYSERR_NOERROR != res)
741 {
742 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "mixerGetID(MIXER_OBJECTF_HWAVEOUT) failed (err=%d)", res);
743 // identification failed => use default mixer identifier (=0)
744 mixerId = 0;
745 }
746 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "specified output device <=> mixer ID %u", mixerId);
747
748 // The waveform-audio output handle is no longer needed.
749 //
750 waveOutClose(hWaveOut);
751
752 // Verify that the mixer contains a valid speaker destination line.
753 // Avoid opening the mixer if valid control has not been found.
754 //
755 if (!SpeakerIsValid(mixerId))
756 {
757 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "it is not possible to control the speaker volume for this mixer device");
758 return -1;
759 }
760
761 // Open the specified mixer device and ensure that the device will not
762 // be removed until the application closes the handle.
763 //
764 res = mixerOpen(&hMixer, mixerId, 0, 0, MIXER_OBJECTF_MIXER);
765 if (MMSYSERR_NOERROR != res)
766 {
767 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "mixerOpen() failed (err=%d)", res);
768 }
769
770 // Store the output mixer handle and active mixer identifier
771 //
772 _outputMixerHandle = hMixer;
773 _outputMixerID = mixerId;
774
775 if (_outputMixerHandle != NULL)
776 {
777 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "the output mixer device is now open (0x%x)", _outputMixerHandle);
778 }
779
780 return 0;
781 }
782
783 // ----------------------------------------------------------------------------
784 // OpenMicrophone I(II)
785 //
786 // Verifies that the mixer contains a valid wave-in destination line.
787 // Avoids opening the mixer if valid control has not been found.
788 // ----------------------------------------------------------------------------
789
OpenMicrophone(AudioDeviceModule::WindowsDeviceType device)790 int32_t AudioMixerManager::OpenMicrophone(AudioDeviceModule::WindowsDeviceType device)
791 {
792 if (device == AudioDeviceModule::kDefaultDevice)
793 {
794 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "AudioMixerManager::OpenMicrophone(kDefaultDevice)");
795 }
796 else if (device == AudioDeviceModule::kDefaultCommunicationDevice)
797 {
798 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "AudioMixerManager::OpenMicrophone(kDefaultCommunicationDevice)");
799 }
800
801 CriticalSectionScoped lock(&_critSect);
802
803 // Close any existing output mixer handle
804 //
805 if (_inputMixerHandle != NULL)
806 {
807 mixerClose(_inputMixerHandle);
808 _inputMixerHandle = NULL;
809 }
810
811 MMRESULT res;
812 WAVEFORMATEX waveFormat;
813 HWAVEIN hWaveIn(NULL);
814
815 waveFormat.wFormatTag = WAVE_FORMAT_PCM ;
816 waveFormat.nChannels = 1;
817 waveFormat.nSamplesPerSec = 48000;
818 waveFormat.wBitsPerSample = 16;
819 waveFormat.nBlockAlign = waveFormat.nChannels * waveFormat.wBitsPerSample / 8;
820 waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;
821 waveFormat.cbSize = 0 ;
822
823 // We need a waveform-audio input handle for the currently selected input device.
824 // This handle will then give us the corresponding mixer identifier. Once the mixer
825 // ID is known, it is possible to open the input mixer.
826 //
827 if (device == AudioDeviceModule::kDefaultCommunicationDevice)
828 {
829 // check if it is possible to open the default communication device (supported on Windows 7)
830 res = waveInOpen(NULL, WAVE_MAPPER, &waveFormat, 0, 0, CALLBACK_NULL |
831 WAVE_MAPPED_kDefaultCommunicationDevice | WAVE_FORMAT_QUERY);
832 if (MMSYSERR_NOERROR == res)
833 {
834 // if so, open the default communication device for real
835 res = waveInOpen(&hWaveIn, WAVE_MAPPER, &waveFormat, 0, 0, CALLBACK_NULL | WAVE_MAPPED_kDefaultCommunicationDevice);
836 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "opening default communication device");
837 }
838 else
839 {
840 // use default device since default communication device was not avaliable
841 res = waveInOpen(&hWaveIn, WAVE_MAPPER, &waveFormat, 0, 0, CALLBACK_NULL);
842 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
843 "unable to open default communication device => using default instead");
844 }
845 }
846 else if (device == AudioDeviceModule::kDefaultDevice)
847 {
848 // open default device since it has been requested
849 res = waveInOpen(&hWaveIn, WAVE_MAPPER, &waveFormat, 0, 0, CALLBACK_NULL);
850 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "opening default input device");
851 }
852
853 if (MMSYSERR_NOERROR != res)
854 {
855 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "waveInOpen() failed (err=%d)", res);
856 TraceWaveInError(res);
857 }
858
859 UINT mixerId(0);
860 HMIXER hMixer(NULL);
861
862 // Retrieve the device identifier for a mixer device associated with the
863 // aquired waveform-audio input handle.
864 //
865 res = mixerGetID((HMIXEROBJ)hWaveIn, &mixerId, MIXER_OBJECTF_HWAVEIN);
866 if (MMSYSERR_NOERROR != res)
867 {
868 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "mixerGetID(MIXER_OBJECTF_HWAVEIN) failed (err=%d)", res);
869 // identification failed => use default mixer identifier (=0)
870 mixerId = 0;
871 }
872 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "specified input device <=> mixer ID %u", mixerId);
873
874 // The waveform-audio input handle is no longer needed.
875 //
876 waveInClose(hWaveIn);
877
878 // Verify that the mixer contains a valid wave-in destination line and a volume control.
879 // Avoid opening the mixer if valid control has not been found.
880 //
881 if (!MicrophoneIsValid(mixerId))
882 {
883 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "it is not possible to control the microphone volume for this mixer device");
884 return -1;
885 }
886
887 // Open the specified mixer device and ensure that the device will not
888 // be removed until the application closes the handle.
889 //
890 res = mixerOpen(&hMixer, mixerId, 0, 0, MIXER_OBJECTF_MIXER);
891 if (MMSYSERR_NOERROR != res)
892 {
893 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "mixerOpen() failed (err=%d)", res);
894 }
895
896 // Store the input mixer handle and active mixer identifier
897 //
898 _inputMixerHandle = hMixer;
899 _inputMixerID = mixerId;
900
901 if (_inputMixerHandle != NULL)
902 {
903 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "the input mixer device is now open (0x%x)", _inputMixerHandle);
904 }
905
906 return 0;
907 }
908
909 // ----------------------------------------------------------------------------
910 // OpenMicrophone II(II)
911 //
912 // Verifies that the mixer contains a valid wave-in destination line.
913 // Avoids opening the mixer if valid control has not been found.
914 // ----------------------------------------------------------------------------
915
OpenMicrophone(uint16_t index)916 int32_t AudioMixerManager::OpenMicrophone(uint16_t index)
917 {
918 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "AudioMixerManager::OpenMicrophone(index=%d)", index);
919
920 CriticalSectionScoped lock(&_critSect);
921
922 // Close any existing input mixer handle
923 //
924 if (_inputMixerHandle != NULL)
925 {
926 mixerClose(_inputMixerHandle);
927 _inputMixerHandle = NULL;
928 }
929
930 MMRESULT res;
931 WAVEFORMATEX waveFormat;
932 HWAVEIN hWaveIn(NULL);
933
934 const UINT deviceID(index); // use index parameter as device identifier
935
936 waveFormat.wFormatTag = WAVE_FORMAT_PCM ;
937 waveFormat.nChannels = 1;
938 waveFormat.nSamplesPerSec = 48000;
939 waveFormat.wBitsPerSample = 16;
940 waveFormat.nBlockAlign = waveFormat.nChannels * waveFormat.wBitsPerSample / 8;
941 waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;
942 waveFormat.cbSize = 0;
943
944 // We need a waveform-audio input handle for the currently selected input device.
945 // This handle will then give us the corresponding mixer identifier. Once the mixer
946 // ID is known, it is possible to open the input mixer.
947 //
948 res = waveInOpen(&hWaveIn, deviceID, &waveFormat, 0, 0, CALLBACK_NULL);
949 if (MMSYSERR_NOERROR != res)
950 {
951 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "waveInOpen(deviceID=%u) failed (err=%d)", index, res);
952 TraceWaveInError(res);
953 }
954
955 UINT mixerId(0);
956 HMIXER hMixer(NULL);
957
958 // Retrieve the device identifier for a mixer device associated with the
959 // aquired waveform-audio input handle.
960 //
961 res = mixerGetID((HMIXEROBJ)hWaveIn, &mixerId, MIXER_OBJECTF_HWAVEIN);
962 if (MMSYSERR_NOERROR != res)
963 {
964 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "mixerGetID(MIXER_OBJECTF_HWAVEIN) failed (err=%d)", res);
965 // identification failed => use default mixer identifier (=0)
966 mixerId = 0;
967 }
968 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "specified input device <=> mixer ID %u", mixerId);
969
970 // The waveform-audio input handle is no longer needed.
971 //
972 waveInClose(hWaveIn);
973
974 // Verify that the mixer contains a valid wave-in destination line.
975 // Avoid opening the mixer if valid control has not been found.
976 //
977 if (!MicrophoneIsValid(mixerId))
978 {
979 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "it is not possible to control the microphone volume for this mixer device");
980 return -1;
981 }
982
983 // Open the specified mixer device and ensure that the device will not
984 // be removed until the application closes the handle.
985 //
986 res = mixerOpen(&hMixer, mixerId, 0, 0, MIXER_OBJECTF_MIXER);
987 if (MMSYSERR_NOERROR != res)
988 {
989 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "mixerOpen() failed (err=%d)", res);
990 }
991
992 // Store the input mixer handle and active mixer identifier
993 //
994 _inputMixerHandle = hMixer;
995 _inputMixerID = mixerId;
996
997 if (_inputMixerHandle != NULL)
998 {
999 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "the input mixer device is now open (0x%x)", _inputMixerHandle);
1000 }
1001
1002 return 0;
1003 }
1004
1005 // ----------------------------------------------------------------------------
1006 // SpeakerIsInitialized
1007 // ----------------------------------------------------------------------------
1008
SpeakerIsInitialized() const1009 bool AudioMixerManager::SpeakerIsInitialized() const
1010 {
1011 WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s", __FUNCTION__);
1012
1013 return (_outputMixerHandle != NULL);
1014 }
1015
1016 // ----------------------------------------------------------------------------
1017 // MicrophoneIsInitialized
1018 // ----------------------------------------------------------------------------
1019
MicrophoneIsInitialized() const1020 bool AudioMixerManager::MicrophoneIsInitialized() const
1021 {
1022 WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s", __FUNCTION__);
1023
1024 return (_inputMixerHandle != NULL);
1025 }
1026
1027 // ----------------------------------------------------------------------------
1028 // SetSpeakerVolume
1029 // ----------------------------------------------------------------------------
1030
SetSpeakerVolume(uint32_t volume)1031 int32_t AudioMixerManager::SetSpeakerVolume(uint32_t volume)
1032 {
1033 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "AudioMixerManager::SetSpeakerVolume(volume=%u)", volume);
1034
1035 CriticalSectionScoped lock(&_critSect);
1036
1037 if (_outputMixerHandle == NULL)
1038 {
1039 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "no avaliable output mixer exists");
1040 return -1;
1041 }
1042
1043 const UINT mixerID(_outputMixerID);
1044 const DWORD dwControlID(_speakerState[_outputMixerID].dwVolumeControlID);
1045 DWORD dwValue(volume);
1046
1047 // Set one unsigned control value for a specified volume-control identifier
1048 //
1049 if (!SetUnsignedControlValue(mixerID, dwControlID, dwValue))
1050 {
1051 return -1;
1052 }
1053
1054 return (0);
1055 }
1056
1057 // ----------------------------------------------------------------------------
1058 // SpeakerVolume
1059 //
1060 // Note that (MIXERCONTROL_CONTROLTYPE_VOLUME & MIXERCONTROL_CT_UNITS_MASK)
1061 // always equals MIXERCONTROL_CT_UNITS_UNSIGNED;
1062 // ----------------------------------------------------------------------------
1063
SpeakerVolume(uint32_t & volume) const1064 int32_t AudioMixerManager::SpeakerVolume(uint32_t& volume) const
1065 {
1066
1067 if (_outputMixerHandle == NULL)
1068 {
1069 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "no avaliable output mixer exists");
1070 return -1;
1071 }
1072
1073 const UINT mixerID(_outputMixerID);
1074 const DWORD dwControlID(_speakerState[_outputMixerID].dwVolumeControlID);
1075 DWORD dwValue(0);
1076
1077 // Retrieve one unsigned control value for a specified volume-control identifier
1078 //
1079 if (!GetUnsignedControlValue(mixerID, dwControlID, dwValue))
1080 {
1081 return -1;
1082 }
1083
1084 volume = dwValue;
1085
1086 return 0;
1087 }
1088
1089 // ----------------------------------------------------------------------------
1090 // MaxSpeakerVolume
1091 //
1092 // Note that (MIXERCONTROL_CONTROLTYPE_VOLUME & MIXERCONTROL_CT_UNITS_MASK)
1093 // always equals MIXERCONTROL_CT_UNITS_UNSIGNED
1094 // ----------------------------------------------------------------------------
1095
MaxSpeakerVolume(uint32_t & maxVolume) const1096 int32_t AudioMixerManager::MaxSpeakerVolume(uint32_t& maxVolume) const
1097 {
1098
1099 if (_outputMixerHandle == NULL)
1100 {
1101 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "no avaliable output mixer exists");
1102 return -1;
1103 }
1104
1105 const UINT mixerID(_outputMixerID);
1106 const DWORD dwControlID(_speakerState[_outputMixerID].dwVolumeControlID);
1107 MIXERCONTROL mixerControl;
1108
1109 // Retrieve one control line for a specified volume-control identifier
1110 //
1111 if (!GetLineControl(mixerID, dwControlID, mixerControl))
1112 {
1113 return -1;
1114 }
1115
1116 maxVolume = mixerControl.Bounds.dwMaximum;
1117
1118 return 0;
1119 }
1120
1121 // ----------------------------------------------------------------------------
1122 // MinSpeakerVolume
1123 // ----------------------------------------------------------------------------
1124
MinSpeakerVolume(uint32_t & minVolume) const1125 int32_t AudioMixerManager::MinSpeakerVolume(uint32_t& minVolume) const
1126 {
1127
1128 if (_outputMixerHandle == NULL)
1129 {
1130 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "no avaliable output mixer exists");
1131 return -1;
1132 }
1133
1134 const UINT mixerID(_outputMixerID);
1135 const DWORD dwControlID(_speakerState[_outputMixerID].dwVolumeControlID);
1136 MIXERCONTROL mixerControl;
1137
1138 // Retrieve one control line for a specified volume-control identifier
1139 //
1140 if (!GetLineControl(mixerID, dwControlID, mixerControl))
1141 {
1142 return -1;
1143 }
1144
1145 minVolume = mixerControl.Bounds.dwMinimum;
1146
1147 return 0;
1148 }
1149
1150 // ----------------------------------------------------------------------------
1151 // SpeakerVolumeStepSize
1152 // ----------------------------------------------------------------------------
1153
SpeakerVolumeStepSize(uint16_t & stepSize) const1154 int32_t AudioMixerManager::SpeakerVolumeStepSize(uint16_t& stepSize) const
1155 {
1156
1157 if (_outputMixerHandle == NULL)
1158 {
1159 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "no avaliable output mixer exists");
1160 return -1;
1161 }
1162
1163 const UINT mixerID(_outputMixerID);
1164 MIXERCONTROL mixerControl;
1165
1166 // Retrieve one control line for a specified volume-control identifier
1167 //
1168 if (!GetLineControl(mixerID, _speakerState[mixerID].dwVolumeControlID, mixerControl))
1169 {
1170 return -1;
1171 }
1172
1173 stepSize = static_cast<uint16_t> (mixerControl.Metrics.cSteps);
1174
1175 return 0;
1176 }
1177
1178 // ----------------------------------------------------------------------------
1179 // SpeakerVolumeIsAvailable
1180 // ----------------------------------------------------------------------------
1181
SpeakerVolumeIsAvailable(bool & available)1182 int32_t AudioMixerManager::SpeakerVolumeIsAvailable(bool& available)
1183 {
1184 if (_outputMixerHandle == NULL)
1185 {
1186 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "no avaliable output mixer exists");
1187 return -1;
1188 }
1189
1190 available = _speakerState[_outputMixerID].volumeControlIsValid;
1191
1192 return 0;
1193 }
1194
1195 // ----------------------------------------------------------------------------
1196 // SpeakerMuteIsAvailable
1197 // ----------------------------------------------------------------------------
1198
SpeakerMuteIsAvailable(bool & available)1199 int32_t AudioMixerManager::SpeakerMuteIsAvailable(bool& available)
1200 {
1201 if (_outputMixerHandle == NULL)
1202 {
1203 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "no avaliable output mixer exists");
1204 return -1;
1205 }
1206
1207 available = _speakerState[_outputMixerID].muteControlIsValid;
1208
1209 return 0;
1210 }
1211
1212 // ----------------------------------------------------------------------------
1213 // SetSpeakerMute
1214 //
1215 // This mute function works a master mute for the output speaker.
1216 // ----------------------------------------------------------------------------
1217
SetSpeakerMute(bool enable)1218 int32_t AudioMixerManager::SetSpeakerMute(bool enable)
1219 {
1220 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "AudioMixerManager::SetSpeakerMute(enable=%u)", enable);
1221
1222 CriticalSectionScoped lock(&_critSect);
1223
1224 if (_outputMixerHandle == NULL)
1225 {
1226 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "no avaliable output mixer exists");
1227 return -1;
1228 }
1229
1230 // Ensure that the selected speaker destination has a valid mute control.
1231 // If so, its identifier was stored during the enumeration phase which must
1232 // have taken place since the output mixer handle exists.
1233 //
1234 if (!_speakerState[_outputMixerID].muteControlIsValid)
1235 {
1236 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "it is not possible to mute this speaker line");
1237 return -1;
1238 }
1239
1240 const DWORD dwControlID(_speakerState[_outputMixerID].dwMuteControlID);
1241
1242 // Set one boolean control value for the specified mute-control
1243 //
1244 if (!SetBooleanControlValue(_outputMixerID, dwControlID, enable))
1245 {
1246 return -1;
1247 }
1248
1249 return (0);
1250 }
1251
1252 // ----------------------------------------------------------------------------
1253 // SpeakerMute
1254 // ----------------------------------------------------------------------------
1255
SpeakerMute(bool & enabled) const1256 int32_t AudioMixerManager::SpeakerMute(bool& enabled) const
1257 {
1258
1259 if (_outputMixerHandle == NULL)
1260 {
1261 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "no avaliable output mixer exists");
1262 return -1;
1263 }
1264
1265 // Ensure that the selected speaker destination has a valid mute control.
1266 // If so, its identifier was stored during the enumeration phase which must
1267 // have taken place since the output mixer handle exists.
1268 //
1269 if (!_speakerState[_outputMixerID].muteControlIsValid)
1270 {
1271 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "it is not possible to mute this speaker line");
1272 return -1;
1273 }
1274
1275 const DWORD dwControlID(_speakerState[_outputMixerID].dwMuteControlID);
1276 bool value(false);
1277
1278 // Retrieve one boolean control value for a specified mute-control identifier
1279 //
1280 if (!GetBooleanControlValue(_outputMixerID, dwControlID, value))
1281 {
1282 return -1;
1283 }
1284
1285 enabled = value;
1286
1287 return 0;
1288 }
1289
1290 // ----------------------------------------------------------------------------
1291 // MicrophoneMuteIsAvailable
1292 // ----------------------------------------------------------------------------
1293
MicrophoneMuteIsAvailable(bool & available)1294 int32_t AudioMixerManager::MicrophoneMuteIsAvailable(bool& available)
1295 {
1296 if (_inputMixerHandle == NULL)
1297 {
1298 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "no avaliable input mixer exists");
1299 return -1;
1300 }
1301
1302 available = _microphoneState[_inputMixerID].muteControlIsValid;
1303
1304 return 0;
1305 }
1306
1307 // ----------------------------------------------------------------------------
1308 // SetMicrophoneMute
1309 //
1310 // This mute function works a master mute for the input microphone.
1311 // ----------------------------------------------------------------------------
1312
SetMicrophoneMute(bool enable)1313 int32_t AudioMixerManager::SetMicrophoneMute(bool enable)
1314 {
1315 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "AudioMixerManager::SetMicrophoneMute(enable=%u)", enable);
1316
1317 CriticalSectionScoped lock(&_critSect);
1318
1319 if (_inputMixerHandle == NULL)
1320 {
1321 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "no avaliable input mixer exists");
1322 return -1;
1323 }
1324
1325 // Ensure that the selected wave-in destinationhas a valid mute control.
1326 // If so, its identifier was stored during the enumeration phase which must
1327 // have taken place since the input mixer handle exists.
1328 //
1329 if (!_microphoneState[_inputMixerID].muteControlIsValid)
1330 {
1331 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "it is not possible to mute this microphone line");
1332 return -1;
1333 }
1334
1335 const DWORD dwControlID(_microphoneState[_inputMixerID].dwMuteControlID);
1336
1337 // Set one boolean control value for the specified mute-control
1338 //
1339 if (!SetBooleanControlValue(_inputMixerID, dwControlID, enable))
1340 {
1341 return -1;
1342 }
1343
1344 return (0);
1345 }
1346
1347 // ----------------------------------------------------------------------------
1348 // MicrophoneMute
1349 // ----------------------------------------------------------------------------
1350
MicrophoneMute(bool & enabled) const1351 int32_t AudioMixerManager::MicrophoneMute(bool& enabled) const
1352 {
1353
1354 if (_inputMixerHandle == NULL)
1355 {
1356 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "no avaliable input mixer exists");
1357 return -1;
1358 }
1359
1360 // Ensure that the selected wave-in destinationhas a valid mute control.
1361 // If so, its identifier was stored during the enumeration phase which must
1362 // have taken place since the input mixer handle exists.
1363 //
1364 if (!_microphoneState[_inputMixerID].muteControlIsValid)
1365 {
1366 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "it is not possible to mute this microphone line");
1367 return -1;
1368 }
1369
1370 const DWORD dwControlID(_microphoneState[_inputMixerID].dwMuteControlID);
1371 bool value(false);
1372
1373 // Retrieve one boolean control value for a specified mute-control identifier
1374 //
1375 if (!GetBooleanControlValue(_inputMixerID, dwControlID, value))
1376 {
1377 return -1;
1378 }
1379
1380 enabled = value;
1381
1382 return 0;
1383 }
1384
1385 // ----------------------------------------------------------------------------
1386 // MicrophoneBoostIsAvailable
1387 // ----------------------------------------------------------------------------
1388
MicrophoneBoostIsAvailable(bool & available)1389 int32_t AudioMixerManager::MicrophoneBoostIsAvailable(bool& available)
1390 {
1391 if (_inputMixerHandle == NULL)
1392 {
1393 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "no avaliable input mixer exists");
1394 return -1;
1395 }
1396
1397 available = _microphoneState[_inputMixerID].onOffControlIsValid;
1398
1399 return 0;
1400 }
1401
1402 // ----------------------------------------------------------------------------
1403 // SetMicrophoneBoost
1404 // ----------------------------------------------------------------------------
1405
SetMicrophoneBoost(bool enable)1406 int32_t AudioMixerManager::SetMicrophoneBoost(bool enable)
1407 {
1408 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "AudioMixerManager::SetMicrophoneBoost(enable=%u)", enable);
1409
1410 CriticalSectionScoped lock(&_critSect);
1411
1412 if (_inputMixerHandle == NULL)
1413 {
1414 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "no avaliable input mixer exists");
1415 return -1;
1416 }
1417
1418 // Ensure that the selected wave-in destination has a valid boost (on/off) control.
1419 // If so, its identifier was stored during the enumeration phase which must
1420 // have taken place since the input mixer handle exists.
1421 //
1422 if (!_microphoneState[_inputMixerID].onOffControlIsValid)
1423 {
1424 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "no boost control exists for this wave-in line");
1425 return -1;
1426 }
1427
1428 const DWORD dwControlID(_microphoneState[_inputMixerID].dwOnOffControlID);
1429
1430 // Set one boolean control value for the specified boost (on/off) control
1431 //
1432 if (!SetBooleanControlValue(_inputMixerID, dwControlID, enable))
1433 {
1434 return -1;
1435 }
1436
1437 return (0);
1438 }
1439
1440 // ----------------------------------------------------------------------------
1441 // MicrophoneBoost
1442 // ----------------------------------------------------------------------------
1443
MicrophoneBoost(bool & enabled) const1444 int32_t AudioMixerManager::MicrophoneBoost(bool& enabled) const
1445 {
1446
1447 if (_inputMixerHandle == NULL)
1448 {
1449 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "no avaliable input mixer exists");
1450 return -1;
1451 }
1452
1453 // Ensure that the selected wave-in destination has a valid boost (on/off) control.
1454 // If so, its identifier was stored during the enumeration phase which must
1455 // have taken place since the input mixer handle exists.
1456 //
1457 if (!_microphoneState[_inputMixerID].onOffControlIsValid)
1458 {
1459 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "no boost control exists for this wave-in line");
1460 return -1;
1461 }
1462
1463 const DWORD dwControlID(_microphoneState[_inputMixerID].dwOnOffControlID);
1464 bool value(false);
1465
1466 // Retrieve one boolean control value for a specified boost-control identifier
1467 //
1468 if (!GetBooleanControlValue(_inputMixerID, dwControlID, value))
1469 {
1470 return -1;
1471 }
1472
1473 enabled = value;
1474
1475 return 0;
1476 }
1477
1478 // ----------------------------------------------------------------------------
1479 // MicrophoneVolumeIsAvailable
1480 // ----------------------------------------------------------------------------
1481
MicrophoneVolumeIsAvailable(bool & available)1482 int32_t AudioMixerManager::MicrophoneVolumeIsAvailable(bool& available)
1483 {
1484 if (_inputMixerHandle == NULL)
1485 {
1486 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "no avaliable input mixer exists");
1487 return -1;
1488 }
1489
1490 available = _microphoneState[_inputMixerID].volumeControlIsValid;
1491
1492 return 0;
1493 }
1494
1495 // ----------------------------------------------------------------------------
1496 // SetMicrophoneVolume
1497 // ----------------------------------------------------------------------------
1498
SetMicrophoneVolume(uint32_t volume)1499 int32_t AudioMixerManager::SetMicrophoneVolume(uint32_t volume)
1500 {
1501 CriticalSectionScoped lock(&_critSect);
1502
1503 if (_inputMixerHandle == NULL)
1504 {
1505 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "no avaliable input mixer exists");
1506 return -1;
1507 }
1508
1509 const UINT mixerID(_inputMixerID);
1510 const DWORD dwControlID(_microphoneState[_inputMixerID].dwVolumeControlID);
1511 DWORD dwValue(volume);
1512
1513 // Set one unsigned control value for a specified volume-control identifier
1514 //
1515 if (!SetUnsignedControlValue(mixerID, dwControlID, dwValue))
1516 {
1517 return -1;
1518 }
1519
1520 return (0);
1521 }
1522
1523 // ----------------------------------------------------------------------------
1524 // MicrophoneVolume
1525 // ----------------------------------------------------------------------------
1526
MicrophoneVolume(uint32_t & volume) const1527 int32_t AudioMixerManager::MicrophoneVolume(uint32_t& volume) const
1528 {
1529 CriticalSectionScoped lock(&_critSect);
1530
1531 if (_inputMixerHandle == NULL)
1532 {
1533 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "no avaliable input mixer exists");
1534 return -1;
1535 }
1536
1537 const UINT mixerID(_inputMixerID);
1538 const DWORD dwControlID(_microphoneState[_inputMixerID].dwVolumeControlID);
1539 DWORD dwValue(0);
1540
1541 // Retrieve one unsigned control value for a specified volume-control identifier
1542 //
1543 if (!GetUnsignedControlValue(mixerID, dwControlID, dwValue))
1544 {
1545 return -1;
1546 }
1547
1548 volume = dwValue;
1549
1550 return 0;
1551 }
1552
1553 // ----------------------------------------------------------------------------
1554 // MaxMicrophoneVolume
1555 // ----------------------------------------------------------------------------
1556
MaxMicrophoneVolume(uint32_t & maxVolume) const1557 int32_t AudioMixerManager::MaxMicrophoneVolume(uint32_t& maxVolume) const
1558 {
1559 WEBRTC_TRACE(kTraceStream, kTraceAudioDevice, _id, "%s", __FUNCTION__);
1560
1561 if (_inputMixerHandle == NULL)
1562 {
1563 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "no avaliable input mixer exists");
1564 return -1;
1565 }
1566
1567 const UINT mixerID(_inputMixerID);
1568 const DWORD dwControlID(_microphoneState[_inputMixerID].dwVolumeControlID);
1569 MIXERCONTROL mixerControl;
1570
1571 // Retrieve one control line for a specified volume-control identifier
1572 //
1573 if (!GetLineControl(mixerID, dwControlID, mixerControl))
1574 {
1575 return -1;
1576 }
1577
1578 maxVolume = mixerControl.Bounds.dwMaximum;
1579
1580 return 0;
1581 }
1582
1583 // ----------------------------------------------------------------------------
1584 // MinMicrophoneVolume
1585 // ----------------------------------------------------------------------------
1586
MinMicrophoneVolume(uint32_t & minVolume) const1587 int32_t AudioMixerManager::MinMicrophoneVolume(uint32_t& minVolume) const
1588 {
1589
1590 if (_inputMixerHandle == NULL)
1591 {
1592 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "no avaliable input mixer exists");
1593 return -1;
1594 }
1595
1596 const UINT mixerID(_inputMixerID);
1597 const DWORD dwControlID(_microphoneState[_inputMixerID].dwVolumeControlID);
1598 MIXERCONTROL mixerControl;
1599
1600 // Retrieve one control line for a specified volume-control identifier
1601 //
1602 if (!GetLineControl(mixerID, dwControlID, mixerControl))
1603 {
1604 return -1;
1605 }
1606
1607 minVolume = mixerControl.Bounds.dwMinimum;
1608
1609 return 0;
1610 }
1611
1612 // ----------------------------------------------------------------------------
1613 // MicrophoneVolumeStepSize
1614 // ----------------------------------------------------------------------------
1615
MicrophoneVolumeStepSize(uint16_t & stepSize) const1616 int32_t AudioMixerManager::MicrophoneVolumeStepSize(uint16_t& stepSize) const
1617 {
1618
1619 if (_inputMixerHandle == NULL)
1620 {
1621 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "no avaliable input mixer exists");
1622 return -1;
1623 }
1624
1625 const UINT mixerID(_inputMixerID);
1626 const DWORD dwControlID(_microphoneState[_inputMixerID].dwVolumeControlID);
1627 MIXERCONTROL mixerControl;
1628
1629 // Retrieve one control line for a specified volume-control identifier
1630 //
1631 if (!GetLineControl(mixerID, dwControlID, mixerControl))
1632 {
1633 return -1;
1634 }
1635
1636 stepSize = static_cast<uint16_t> (mixerControl.Metrics.cSteps);
1637
1638 return 0;
1639 }
1640
1641 // ============================================================================
1642 // PRIVATE METHODS
1643 // ============================================================================
1644
1645 // ----------------------------------------------------------------------------
1646 // Devices
1647 //
1648 // A given audio card has one Mixer device associated with it. All of the
1649 // various components on that card are controlled through that card's one
1650 // Mixer device.
1651 // ----------------------------------------------------------------------------
1652
Devices() const1653 UINT AudioMixerManager::Devices() const
1654 {
1655 UINT nDevs = mixerGetNumDevs();
1656 return nDevs;
1657 }
1658
1659 // ----------------------------------------------------------------------------
1660 // DestinationLines
1661 //
1662 // # destination lines given mixer ID.
1663 // ----------------------------------------------------------------------------
1664
DestinationLines(UINT mixId) const1665 UINT AudioMixerManager::DestinationLines(UINT mixId) const
1666 {
1667 MIXERCAPS caps;
1668 if (!GetCapabilities(mixId, caps))
1669 {
1670 return 0;
1671 }
1672 return (caps.cDestinations);
1673 }
1674 // ----------------------------------------------------------------------------
1675 // DestinationLines
1676 //
1677 // # source lines given mixer ID and destination ID.
1678 // ----------------------------------------------------------------------------
1679
SourceLines(UINT mixId,DWORD destId) const1680 UINT AudioMixerManager::SourceLines(UINT mixId, DWORD destId) const
1681 {
1682 MIXERLINE dline;
1683 if (!GetDestinationLineInfo(mixId, destId, dline))
1684 {
1685 return 0;
1686 }
1687 return (dline.cConnections);
1688 }
1689
1690 // ----------------------------------------------------------------------------
1691 // GetCapabilities
1692 //
1693 // Queries a specified mixer device to determine its capabilities.
1694 // ----------------------------------------------------------------------------
1695
GetCapabilities(UINT mixId,MIXERCAPS & caps,bool trace) const1696 bool AudioMixerManager::GetCapabilities(UINT mixId, MIXERCAPS& caps, bool trace) const
1697 {
1698 MMRESULT res;
1699 MIXERCAPS mcaps;
1700
1701 res = mixerGetDevCaps(mixId, &mcaps, sizeof(MIXERCAPS));
1702 if (res != MMSYSERR_NOERROR)
1703 {
1704 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "mixerGetDevCaps() failed (err=%d)", res);
1705 return false;
1706 }
1707
1708 memcpy(&caps, &mcaps, sizeof(MIXERCAPS));
1709
1710 if (trace)
1711 {
1712 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "===============================================================");
1713 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "Mixer ID %u:", mixId);
1714 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "manufacturer ID : %u", caps.wMid);
1715 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "product ID : %u", caps.wPid);
1716 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "version of driver : %u", caps.vDriverVersion);
1717 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "product name : %s", WideToUTF8(caps.szPname));
1718 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "misc. support bits : %u", caps.fdwSupport);
1719 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "count of destinations: %u (+)", caps.cDestinations);
1720 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "===============================================================");
1721 }
1722
1723 if (caps.cDestinations == 0)
1724 {
1725 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "invalid number of mixer destinations");
1726 return false;
1727 }
1728
1729 return true;
1730 }
1731
1732 // ----------------------------------------------------------------------------
1733 // GetDestinationLineInfo
1734 // ----------------------------------------------------------------------------
1735
GetDestinationLineInfo(UINT mixId,DWORD destId,MIXERLINE & line,bool trace) const1736 bool AudioMixerManager::GetDestinationLineInfo(UINT mixId, DWORD destId, MIXERLINE& line, bool trace) const
1737 {
1738 MMRESULT res;
1739 MIXERLINE mline;
1740
1741 mline.cbStruct = sizeof(MIXERLINE);
1742 mline.dwDestination = destId; // max destination index is cDestinations-1
1743 mline.dwSource = 0; // not set for MIXER_GETLINEINFOF_DESTINATION
1744
1745 // Retrieve information about the specified destination line of a mixer device.
1746 // Note that we use the mixer ID here and not a handle to an opened mixer.
1747 // It is not required to open the mixer for enumeration purposes only.
1748 //
1749 res = mixerGetLineInfo(reinterpret_cast<HMIXEROBJ>(mixId), &mline, MIXER_OBJECTF_MIXER | MIXER_GETLINEINFOF_DESTINATION);
1750 if (res != MMSYSERR_NOERROR)
1751 {
1752 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "mixerGetLineInfo(MIXER_GETLINEINFOF_DESTINATION) failed (err=%d)", res);
1753 return false;
1754 }
1755
1756 memcpy(&line, &mline, sizeof(MIXERLINE));
1757
1758 if (trace)
1759 {
1760 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "> Destination Line ID %u:", destId);
1761 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
1762 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "destination line index : %u", mline.dwDestination);
1763 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "dwLineID : %lu (unique)", mline.dwLineID);
1764 TraceStatusAndSupportFlags(mline.fdwLine);
1765 TraceComponentType(mline.dwComponentType);
1766 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "count of channels : %u", mline.cChannels);
1767 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "# audio source lines : %u (+)", mline.cConnections); // valid only for destinations
1768 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "# controls : %u (*)", mline.cControls); // can be zero
1769 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "short name : %s", WideToUTF8(mline.szShortName));
1770 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "full name : %s", WideToUTF8(mline.szName));
1771 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
1772 TraceTargetType(mline.Target.dwType);
1773 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "target device ID : %lu", mline.Target.dwDeviceID);
1774 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "manufacturer ID : %u", mline.Target.wMid);
1775 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "product ID : %u", mline.Target.wPid);
1776 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "driver version : %u", mline.Target.vDriverVersion);
1777 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "product name : %s", WideToUTF8(mline.Target.szPname));
1778 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "---------------------------------------------------------------");
1779 }
1780
1781 return true;
1782 }
1783
1784 // ----------------------------------------------------------------------------
1785 // GetSourceLineInfo
1786 // ----------------------------------------------------------------------------
1787
GetSourceLineInfo(UINT mixId,DWORD destId,DWORD srcId,MIXERLINE & line,bool trace) const1788 bool AudioMixerManager::GetSourceLineInfo(UINT mixId, DWORD destId, DWORD srcId, MIXERLINE& line, bool trace) const
1789 {
1790 MMRESULT res;
1791 MIXERLINE mline;
1792
1793 mline.cbStruct = sizeof(MIXERLINE);
1794 mline.dwDestination = destId; // we want the source info for this destination
1795 mline.dwSource = srcId; // source index (enumerate over these)
1796
1797 // Retrieve information about the specified source line of a mixer device.
1798 // Note that we use the mixer ID here and not a handle to an opened mixer.
1799 // It is not required to open the mixer for enumeration purposes only.
1800 //
1801 res = mixerGetLineInfo(reinterpret_cast<HMIXEROBJ>(mixId), &mline, MIXER_OBJECTF_MIXER | MIXER_GETLINEINFOF_SOURCE);
1802 if (res != MMSYSERR_NOERROR)
1803 {
1804 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "mixerGetLineInfo(MIXER_GETLINEINFOF_SOURCE) failed (err=%d)", res);
1805 return false;
1806 }
1807
1808 memcpy(&line, &mline, sizeof(MIXERLINE));
1809
1810 if (trace)
1811 {
1812 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, " >> Source Line ID %u:", srcId);
1813 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "destination line index : %u", mline.dwDestination);
1814 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "dwSource : %u", mline.dwSource);
1815 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "dwLineID : %lu (unique)", mline.dwLineID);
1816 TraceStatusAndSupportFlags(mline.fdwLine);
1817 TraceComponentType(mline.dwComponentType);
1818 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "# controls : %u (*)", mline.cControls);
1819 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "full name : %s", WideToUTF8(mline.szName));
1820 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
1821 TraceTargetType(mline.Target.dwType);
1822 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "---------------------------------------------------------------");
1823 }
1824
1825 return true;
1826 }
1827
1828 // ----------------------------------------------------------------------------
1829 // GetAllLineControls
1830 // ----------------------------------------------------------------------------
1831
GetAllLineControls(UINT mixId,const MIXERLINE & line,MIXERCONTROL * controlArray,bool trace) const1832 bool AudioMixerManager::GetAllLineControls(UINT mixId, const MIXERLINE& line, MIXERCONTROL* controlArray, bool trace) const
1833 {
1834 // Ensure that we don't try to aquire information if there are no controls for this line
1835 //
1836 if (line.cControls == 0)
1837 return false;
1838
1839 MMRESULT res;
1840 MIXERLINECONTROLS mlineControls; // contains information about the controls of an audio line
1841
1842 mlineControls.dwLineID = line.dwLineID; // unique audio line identifier
1843 mlineControls.cControls = line.cControls; // number of controls associated with the line
1844 mlineControls.pamxctrl = controlArray; // points to the first MIXERCONTROL structure to be filled
1845 mlineControls.cbStruct = sizeof(MIXERLINECONTROLS);
1846 mlineControls.cbmxctrl = sizeof(MIXERCONTROL);
1847
1848 // Get information on ALL controls associated with the specified audio line
1849 //
1850 res = mixerGetLineControls(reinterpret_cast<HMIXEROBJ>(mixId), &mlineControls, MIXER_OBJECTF_MIXER | MIXER_GETLINECONTROLSF_ALL);
1851 if (res != MMSYSERR_NOERROR)
1852 {
1853 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "mixerGetLineControls(MIXER_GETLINECONTROLSF_ALL) failed (err=%d)", res);
1854 return false;
1855 }
1856
1857 if (trace)
1858 {
1859 for (UINT c = 0; c < line.cControls; c++)
1860 {
1861 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, " >> Control ID %u:", c);
1862 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "dwControlID : %u (unique)", controlArray[c].dwControlID);
1863 TraceControlType(controlArray[c].dwControlType);
1864 TraceControlStatusAndSupportFlags(controlArray[c].fdwControl);
1865 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "cMultipleItems : %u", controlArray[c].cMultipleItems);
1866 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "short name : %s", WideToUTF8(controlArray[c].szShortName));
1867 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "full name : %s", WideToUTF8(controlArray[c].szName));
1868 if ((controlArray[c].dwControlType & MIXERCONTROL_CT_UNITS_MASK) == MIXERCONTROL_CT_UNITS_SIGNED)
1869 {
1870 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "min signed value : %d", controlArray[c].Bounds.lMinimum);
1871 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "max signed value : %d", controlArray[c].Bounds.lMaximum);
1872 }
1873 else if ((controlArray[c].dwControlType & MIXERCONTROL_CT_UNITS_MASK) == MIXERCONTROL_CT_UNITS_UNSIGNED ||
1874 (controlArray[c].dwControlType & MIXERCONTROL_CT_UNITS_MASK) == MIXERCONTROL_CT_UNITS_BOOLEAN)
1875 {
1876 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "min unsigned value : %u", controlArray[c].Bounds.dwMinimum);
1877 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "max unsigned value : %u", controlArray[c].Bounds.dwMaximum);
1878 }
1879 if (controlArray[c].dwControlType != MIXERCONTROL_CONTROLTYPE_CUSTOM)
1880 {
1881 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "cSteps : %u", controlArray[c].Metrics.cSteps);
1882 }
1883 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "...............................................................");
1884 GetControlDetails(mixId, controlArray[c], true);
1885 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "...............................................................");
1886
1887 }
1888 }
1889
1890 return true;
1891 }
1892
1893 // ----------------------------------------------------------------------------
1894 // GetLineControls
1895 // ----------------------------------------------------------------------------
1896
GetLineControl(UINT mixId,DWORD dwControlID,MIXERCONTROL & control) const1897 bool AudioMixerManager::GetLineControl(UINT mixId, DWORD dwControlID, MIXERCONTROL& control) const
1898 {
1899 MMRESULT res;
1900 MIXERLINECONTROLS mlineControl;
1901
1902 mlineControl.dwControlID = dwControlID;
1903 mlineControl.cControls = 1;
1904 mlineControl.pamxctrl = &control;
1905 mlineControl.cbStruct = sizeof(MIXERLINECONTROLS);
1906 mlineControl.cbmxctrl = sizeof(MIXERCONTROL);
1907
1908 // Get information on one controls associated with the specified conrol identifier
1909 //
1910 res = mixerGetLineControls(reinterpret_cast<HMIXEROBJ>(mixId), &mlineControl, MIXER_OBJECTF_MIXER | MIXER_GETLINECONTROLSF_ONEBYID);
1911 if (res != MMSYSERR_NOERROR)
1912 {
1913 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "mixerGetLineControls(MIXER_GETLINECONTROLSF_ONEBYID) failed (err=%d)", res);
1914 return false;
1915 }
1916
1917 return true;
1918 }
1919
1920 // ----------------------------------------------------------------------------
1921 // GetControlDetails
1922 // ----------------------------------------------------------------------------
1923
GetControlDetails(UINT mixId,MIXERCONTROL & controlArray,bool trace) const1924 bool AudioMixerManager::GetControlDetails(UINT mixId, MIXERCONTROL& controlArray, bool trace) const
1925 {
1926 assert(controlArray.cMultipleItems <= MAX_NUMBER_OF_MULTIPLE_ITEMS);
1927
1928 MMRESULT res;
1929 MIXERCONTROLDETAILS controlDetails;
1930
1931 MIXERCONTROLDETAILS_UNSIGNED valueUnsigned[MAX_NUMBER_OF_MULTIPLE_ITEMS];
1932 MIXERCONTROLDETAILS_SIGNED valueSigned[MAX_NUMBER_OF_MULTIPLE_ITEMS];
1933 MIXERCONTROLDETAILS_BOOLEAN valueBoolean[MAX_NUMBER_OF_MULTIPLE_ITEMS];
1934
1935 enum ControlType
1936 {
1937 CT_UNITS_UNSIGNED,
1938 CT_UNITS_SIGNED,
1939 CT_UNITS_BOOLEAN
1940 };
1941
1942 ControlType ctype(CT_UNITS_UNSIGNED);
1943
1944 controlDetails.cbStruct = sizeof(MIXERCONTROLDETAILS);
1945 controlDetails.dwControlID = controlArray.dwControlID; // control identifier
1946 controlDetails.cChannels = 1; // we need to set values as if they were uniform
1947 controlDetails.cMultipleItems = controlArray.cMultipleItems; // only nonzero for CONTROLF_MULTIPLE controls
1948 // can e.g. happen for CONTROLTYPE_MUX
1949 if (controlDetails.cMultipleItems > MAX_NUMBER_OF_MULTIPLE_ITEMS)
1950 {
1951 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "cMultipleItems > %d", MAX_NUMBER_OF_MULTIPLE_ITEMS);
1952 controlDetails.cMultipleItems = MAX_NUMBER_OF_MULTIPLE_ITEMS;
1953 }
1954
1955 if ((controlArray.dwControlType & MIXERCONTROL_CT_UNITS_MASK) == MIXERCONTROL_CT_UNITS_SIGNED)
1956 {
1957 ctype = CT_UNITS_SIGNED;
1958 controlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_SIGNED);
1959 controlDetails.paDetails = &valueSigned[0];
1960 }
1961 else if ((controlArray.dwControlType & MIXERCONTROL_CT_UNITS_MASK) == MIXERCONTROL_CT_UNITS_UNSIGNED)
1962 {
1963 ctype = CT_UNITS_UNSIGNED;
1964 controlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
1965 controlDetails.paDetails = &valueUnsigned[0];
1966 }
1967 else if ((controlArray.dwControlType & MIXERCONTROL_CT_UNITS_MASK) == MIXERCONTROL_CT_UNITS_BOOLEAN)
1968 {
1969 ctype = CT_UNITS_BOOLEAN;
1970 controlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
1971 controlDetails.paDetails = &valueBoolean[0];
1972 }
1973
1974 // Retrieve a control's value
1975 //
1976 res = mixerGetControlDetails(reinterpret_cast<HMIXEROBJ>(mixId), &controlDetails, MIXER_OBJECTF_MIXER | MIXER_GETCONTROLDETAILSF_VALUE);
1977 if (res != MMSYSERR_NOERROR)
1978 {
1979 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE) failed (err=%d)", res);
1980 return false;
1981 }
1982
1983 if (trace)
1984 {
1985 UINT nItems(1);
1986 nItems = (controlDetails.cMultipleItems > 0 ? controlDetails.cMultipleItems : 1);
1987 for (UINT i = 0; i < nItems; i++)
1988 {
1989 if (ctype == CT_UNITS_SIGNED)
1990 {
1991 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "signed value : %d", valueSigned[i].lValue);
1992 }
1993 else if (ctype == CT_UNITS_UNSIGNED)
1994 {
1995 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "unsigned value : %u", valueUnsigned[i].dwValue);
1996 }
1997 else if (ctype == CT_UNITS_BOOLEAN)
1998 {
1999 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "boolean value : %u", valueBoolean[i].fValue);
2000 }
2001 }
2002 }
2003
2004 return true;
2005 }
2006
2007 // ----------------------------------------------------------------------------
2008 // GetUnsignedControlValue
2009 // ----------------------------------------------------------------------------
2010
GetUnsignedControlValue(UINT mixId,DWORD dwControlID,DWORD & dwValue) const2011 bool AudioMixerManager::GetUnsignedControlValue(UINT mixId, DWORD dwControlID, DWORD& dwValue) const
2012 {
2013 MMRESULT res;
2014 MIXERCONTROLDETAILS controlDetails;
2015 MIXERCONTROLDETAILS_UNSIGNED valueUnsigned;
2016
2017 controlDetails.dwControlID = dwControlID;
2018 controlDetails.cbStruct = sizeof(MIXERCONTROLDETAILS);
2019 controlDetails.cChannels = 1;
2020 controlDetails.cMultipleItems = 0;
2021 controlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
2022 controlDetails.paDetails = &valueUnsigned;
2023
2024 // Retrieve the unsigned value
2025 //
2026 res = mixerGetControlDetails(reinterpret_cast<HMIXEROBJ>(mixId), &controlDetails, MIXER_OBJECTF_MIXER | MIXER_GETCONTROLDETAILSF_VALUE);
2027 if (res != MMSYSERR_NOERROR)
2028 {
2029 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE) failed (err=%d)", res);
2030 return false;
2031 }
2032
2033 // Deliver the retrieved value
2034 //
2035 dwValue = valueUnsigned.dwValue;
2036
2037 return true;
2038 }
2039
2040 // ----------------------------------------------------------------------------
2041 // SetUnsignedControlValue
2042 // ----------------------------------------------------------------------------
2043
SetUnsignedControlValue(UINT mixId,DWORD dwControlID,DWORD dwValue) const2044 bool AudioMixerManager::SetUnsignedControlValue(UINT mixId, DWORD dwControlID, DWORD dwValue) const
2045 {
2046 WEBRTC_TRACE(kTraceStream, kTraceAudioDevice, _id, "AudioMixerManager::SetUnsignedControlValue(mixId=%u, dwControlID=%d, dwValue=%d)", mixId, dwControlID, dwValue);
2047
2048 MMRESULT res;
2049 MIXERCONTROLDETAILS controlDetails;
2050 MIXERCONTROLDETAILS_UNSIGNED valueUnsigned;
2051
2052 controlDetails.dwControlID = dwControlID;
2053 controlDetails.cbStruct = sizeof(MIXERCONTROLDETAILS);
2054 controlDetails.cChannels = 1;
2055 controlDetails.cMultipleItems = 0;
2056 controlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
2057 controlDetails.paDetails = &valueUnsigned;
2058
2059 valueUnsigned.dwValue = dwValue;
2060
2061 // Set the unsigned value
2062 //
2063 res = mixerSetControlDetails(reinterpret_cast<HMIXEROBJ>(mixId), &controlDetails, MIXER_OBJECTF_MIXER | MIXER_GETCONTROLDETAILSF_VALUE);
2064 if (res != MMSYSERR_NOERROR)
2065 {
2066 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "mixerSetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE) failed (err=%d)", res);
2067 return false;
2068 }
2069
2070 return true;
2071 }
2072
2073 // ----------------------------------------------------------------------------
2074 // SetBooleanControlValue
2075 // ----------------------------------------------------------------------------
2076
SetBooleanControlValue(UINT mixId,DWORD dwControlID,bool value) const2077 bool AudioMixerManager::SetBooleanControlValue(UINT mixId, DWORD dwControlID, bool value) const
2078 {
2079 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "AudioMixerManager::SetBooleanControlValue(mixId=%u, dwControlID=%d, value=%d)", mixId, dwControlID, value);
2080
2081 MMRESULT res;
2082 MIXERCONTROLDETAILS controlDetails;
2083 MIXERCONTROLDETAILS_BOOLEAN valueBoolean;
2084
2085 controlDetails.dwControlID = dwControlID;
2086 controlDetails.cbStruct = sizeof(MIXERCONTROLDETAILS);
2087 controlDetails.cChannels = 1;
2088 controlDetails.cMultipleItems = 0;
2089 controlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
2090 controlDetails.paDetails = &valueBoolean;
2091
2092 if (value == true)
2093 valueBoolean.fValue = TRUE;
2094 else
2095 valueBoolean.fValue = FALSE;
2096
2097 // Set the boolean value
2098 //
2099 res = mixerSetControlDetails(reinterpret_cast<HMIXEROBJ>(mixId), &controlDetails, MIXER_OBJECTF_MIXER | MIXER_GETCONTROLDETAILSF_VALUE);
2100 if (res != MMSYSERR_NOERROR)
2101 {
2102 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "mixerSetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE) failed (err=%d)", res);
2103 return false;
2104 }
2105
2106 return true;
2107 }
2108
2109 // ----------------------------------------------------------------------------
2110 // GetBooleanControlValue
2111 // ----------------------------------------------------------------------------
2112
GetBooleanControlValue(UINT mixId,DWORD dwControlID,bool & value) const2113 bool AudioMixerManager::GetBooleanControlValue(UINT mixId, DWORD dwControlID, bool& value) const
2114 {
2115 MMRESULT res;
2116 MIXERCONTROLDETAILS controlDetails;
2117 MIXERCONTROLDETAILS_BOOLEAN valueBoolean;
2118
2119 controlDetails.dwControlID = dwControlID;
2120 controlDetails.cbStruct = sizeof(MIXERCONTROLDETAILS);
2121 controlDetails.cChannels = 1;
2122 controlDetails.cMultipleItems = 0;
2123 controlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
2124 controlDetails.paDetails = &valueBoolean;
2125
2126 // Retrieve the boolean value
2127 //
2128 res = mixerGetControlDetails(reinterpret_cast<HMIXEROBJ>(mixId), &controlDetails, MIXER_OBJECTF_MIXER | MIXER_GETCONTROLDETAILSF_VALUE);
2129 if (res != MMSYSERR_NOERROR)
2130 {
2131 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE) failed (err=%d)", res);
2132 return false;
2133 }
2134
2135 // Deliver the retrieved value
2136 //
2137 if (valueBoolean.fValue == 0)
2138 value = false;
2139 else
2140 value = true;
2141
2142 return true;
2143 }
2144
2145 // ----------------------------------------------------------------------------
2146 // GetSelectedMuxSource
2147 // ----------------------------------------------------------------------------
2148
GetSelectedMuxSource(UINT mixId,DWORD dwControlID,DWORD cMultipleItems,UINT & index) const2149 bool AudioMixerManager::GetSelectedMuxSource(UINT mixId, DWORD dwControlID, DWORD cMultipleItems, UINT& index) const
2150 {
2151 assert(cMultipleItems <= MAX_NUMBER_OF_MULTIPLE_ITEMS);
2152
2153 MMRESULT res;
2154 MIXERCONTROLDETAILS controlDetails;
2155 MIXERCONTROLDETAILS_BOOLEAN valueBoolean[MAX_NUMBER_OF_MULTIPLE_ITEMS];
2156 memset(&valueBoolean, 0, sizeof(valueBoolean));
2157
2158 controlDetails.dwControlID = dwControlID;
2159 controlDetails.cbStruct = sizeof(MIXERCONTROLDETAILS);
2160 controlDetails.cChannels = 1;
2161 controlDetails.cMultipleItems = cMultipleItems;
2162 controlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
2163 controlDetails.paDetails = &valueBoolean;
2164
2165 // Retrieve the boolean values
2166 //
2167 res = mixerGetControlDetails(reinterpret_cast<HMIXEROBJ>(mixId), &controlDetails, MIXER_OBJECTF_MIXER | MIXER_GETCONTROLDETAILSF_VALUE);
2168 if (res != MMSYSERR_NOERROR)
2169 {
2170 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "mixerGetControlDetails(MIXER_GETCONTROLDETAILSF_VALUE) failed (err=%d)", res);
2171 return false;
2172 }
2173
2174 // Map the current MUX setting to an index corresponding to a source index.
2175 // e.g. with cMultipleItems = 3,
2176 // valueBoolean[] = {1,0,0} => index = 2
2177 // valueBoolean[] = {0,1,0} => index = 1
2178 // valueBoolean[] = {0,0,1} => index = 0
2179 //
2180 // If there is no "1" in the array, we assume index should be 0.
2181 index = 0;
2182 for (DWORD i = 0; i < cMultipleItems; i++)
2183 {
2184 if (valueBoolean[i].fValue > 0)
2185 {
2186 index = (cMultipleItems - 1) - i;
2187 break;
2188 }
2189 }
2190
2191 return true;
2192 }
2193
2194 // ----------------------------------------------------------------------------
2195 // TraceStatusAndSupportFlags
2196 // ----------------------------------------------------------------------------
2197
TraceStatusAndSupportFlags(DWORD fdwLine) const2198 void AudioMixerManager::TraceStatusAndSupportFlags(DWORD fdwLine) const
2199 {
2200 TCHAR buf[128];
2201
2202 StringCchPrintf(buf, 128, TEXT("status & support flags : 0x%x "), fdwLine);
2203
2204 switch (fdwLine)
2205 {
2206 case MIXERLINE_LINEF_ACTIVE:
2207 StringCchCat(buf, 128, TEXT("(ACTIVE DESTINATION)"));
2208 break;
2209 case MIXERLINE_LINEF_DISCONNECTED:
2210 StringCchCat(buf, 128, TEXT("(DISCONNECTED)"));
2211 break;
2212 case MIXERLINE_LINEF_SOURCE:
2213 StringCchCat(buf, 128, TEXT("(INACTIVE SOURCE)"));
2214 break;
2215 case MIXERLINE_LINEF_SOURCE | MIXERLINE_LINEF_ACTIVE:
2216 StringCchCat(buf, 128, TEXT("(ACTIVE SOURCE)"));
2217 break;
2218 default:
2219 StringCchCat(buf, 128, TEXT("(INVALID)"));
2220 break;
2221 }
2222
2223 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", WideToUTF8(buf));
2224 }
2225
2226 // ----------------------------------------------------------------------------
2227 // TraceComponentType
2228 // ----------------------------------------------------------------------------
2229
TraceComponentType(DWORD dwComponentType) const2230 void AudioMixerManager::TraceComponentType(DWORD dwComponentType) const
2231 {
2232 TCHAR buf[128];
2233
2234 StringCchPrintf(buf, 128, TEXT("component type : 0x%x "), dwComponentType);
2235
2236 switch (dwComponentType)
2237 {
2238 // Destination
2239 case MIXERLINE_COMPONENTTYPE_DST_UNDEFINED:
2240 StringCchCat(buf, 128, TEXT("(DST_UNDEFINED)"));
2241 break;
2242 case MIXERLINE_COMPONENTTYPE_DST_DIGITAL:
2243 StringCchCat(buf, 128, TEXT("(DST_DIGITAL)"));
2244 break;
2245 case MIXERLINE_COMPONENTTYPE_DST_LINE:
2246 StringCchCat(buf, 128, TEXT("(DST_LINE)"));
2247 break;
2248 case MIXERLINE_COMPONENTTYPE_DST_MONITOR:
2249 StringCchCat(buf, 128, TEXT("(DST_MONITOR)"));
2250 break;
2251 case MIXERLINE_COMPONENTTYPE_DST_SPEAKERS:
2252 StringCchCat(buf, 128, TEXT("(DST_SPEAKERS)"));
2253 break;
2254 case MIXERLINE_COMPONENTTYPE_DST_HEADPHONES:
2255 StringCchCat(buf, 128, TEXT("(DST_HEADPHONES)"));
2256 break;
2257 case MIXERLINE_COMPONENTTYPE_DST_TELEPHONE:
2258 StringCchCat(buf, 128, TEXT("(DST_TELEPHONE)"));
2259 break;
2260 case MIXERLINE_COMPONENTTYPE_DST_WAVEIN:
2261 StringCchCat(buf, 128, TEXT("(DST_WAVEIN)"));
2262 break;
2263 case MIXERLINE_COMPONENTTYPE_DST_VOICEIN:
2264 StringCchCat(buf, 128, TEXT("(DST_VOICEIN)"));
2265 break;
2266 // Source
2267 case MIXERLINE_COMPONENTTYPE_SRC_UNDEFINED:
2268 StringCchCat(buf, 128, TEXT("(SRC_UNDEFINED)"));
2269 break;
2270 case MIXERLINE_COMPONENTTYPE_SRC_DIGITAL:
2271 StringCchCat(buf, 128, TEXT("(SRC_DIGITAL)"));
2272 break;
2273 case MIXERLINE_COMPONENTTYPE_SRC_LINE:
2274 StringCchCat(buf, 128, TEXT("(SRC_LINE)"));
2275 break;
2276 case MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE:
2277 StringCchCat(buf, 128, TEXT("(SRC_MICROPHONE)"));
2278 break;
2279 case MIXERLINE_COMPONENTTYPE_SRC_SYNTHESIZER:
2280 StringCchCat(buf, 128, TEXT("(SRC_SYNTHESIZER)"));
2281 break;
2282 case MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC:
2283 StringCchCat(buf, 128, TEXT("(SRC_COMPACTDISC)"));
2284 break;
2285 case MIXERLINE_COMPONENTTYPE_SRC_TELEPHONE:
2286 StringCchCat(buf, 128, TEXT("(SRC_TELEPHONE)"));
2287 break;
2288 case MIXERLINE_COMPONENTTYPE_SRC_PCSPEAKER:
2289 StringCchCat(buf, 128, TEXT("(SRC_PCSPEAKER)"));
2290 break;
2291 case MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT:
2292 StringCchCat(buf, 128, TEXT("(SRC_WAVEOUT)"));
2293 break;
2294 case MIXERLINE_COMPONENTTYPE_SRC_AUXILIARY:
2295 StringCchCat(buf, 128, TEXT("(SRC_AUXILIARY)"));
2296 break;
2297 case MIXERLINE_COMPONENTTYPE_SRC_ANALOG:
2298 StringCchCat(buf, 128, TEXT("(SRC_ANALOG)"));
2299 break;
2300 default:
2301 StringCchCat(buf, 128, TEXT("(INVALID)"));
2302 break;
2303 }
2304
2305 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", WideToUTF8(buf));
2306 }
2307
2308 // ----------------------------------------------------------------------------
2309 // TraceTargetType
2310 // ----------------------------------------------------------------------------
2311
TraceTargetType(DWORD dwType) const2312 void AudioMixerManager::TraceTargetType(DWORD dwType) const
2313 {
2314 TCHAR buf[128];
2315
2316 StringCchPrintf(buf, 128, TEXT("media device type : 0x%x "), dwType);
2317
2318 switch (dwType)
2319 {
2320 case MIXERLINE_TARGETTYPE_UNDEFINED:
2321 StringCchCat(buf, 128, TEXT("(UNDEFINED)"));
2322 break;
2323 case MIXERLINE_TARGETTYPE_WAVEOUT:
2324 StringCchCat(buf, 128, TEXT("(WAVEOUT)"));
2325 break;
2326 case MIXERLINE_TARGETTYPE_WAVEIN:
2327 StringCchCat(buf, 128, TEXT("(WAVEIN)"));
2328 break;
2329 case MIXERLINE_TARGETTYPE_MIDIOUT:
2330 StringCchCat(buf, 128, TEXT("(MIDIOUT)"));
2331 break;
2332 case MIXERLINE_TARGETTYPE_MIDIIN:
2333 StringCchCat(buf, 128, TEXT("(MIDIIN)"));
2334 break;
2335 default:
2336 StringCchCat(buf, 128, TEXT("(INVALID)"));
2337 break;
2338 }
2339
2340 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", WideToUTF8(buf));
2341 }
2342
2343 // ----------------------------------------------------------------------------
2344 // TraceControlType
2345 // ----------------------------------------------------------------------------
2346
TraceControlType(DWORD dwControlType) const2347 void AudioMixerManager::TraceControlType(DWORD dwControlType) const
2348 {
2349 TCHAR buf[128];
2350
2351 // Class type classification
2352 //
2353 StringCchPrintf(buf, 128, TEXT("class type : 0x%x "), dwControlType);
2354
2355 switch (dwControlType & MIXERCONTROL_CT_CLASS_MASK)
2356 {
2357 case MIXERCONTROL_CT_CLASS_CUSTOM:
2358 StringCchCat(buf, 128, TEXT("(CT_CLASS_CUSTOM)"));
2359 break;
2360 case MIXERCONTROL_CT_CLASS_METER:
2361 StringCchCat(buf, 128, TEXT("(CT_CLASS_METER)"));
2362 break;
2363 case MIXERCONTROL_CT_CLASS_SWITCH:
2364 StringCchCat(buf, 128, TEXT("(CT_CLASS_SWITCH)"));
2365 break;
2366 case MIXERCONTROL_CT_CLASS_NUMBER:
2367 StringCchCat(buf, 128, TEXT("(CT_CLASS_NUMBER)"));
2368 break;
2369 case MIXERCONTROL_CT_CLASS_SLIDER:
2370 StringCchCat(buf, 128, TEXT("(CT_CLASS_SLIDER)"));
2371 break;
2372 case MIXERCONTROL_CT_CLASS_FADER:
2373 StringCchCat(buf, 128, TEXT("(CT_CLASS_FADER)"));
2374 break;
2375 case MIXERCONTROL_CT_CLASS_TIME:
2376 StringCchCat(buf, 128, TEXT("(CT_CLASS_TIME)"));
2377 break;
2378 case MIXERCONTROL_CT_CLASS_LIST:
2379 StringCchCat(buf, 128, TEXT("(CT_CLASS_LIST)"));
2380 break;
2381 default:
2382 StringCchCat(buf, 128, TEXT("(INVALID)"));
2383 break;
2384 }
2385
2386 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", WideToUTF8(buf));
2387
2388 // Control type (for each class)
2389 //
2390 StringCchPrintf(buf, 128, TEXT("control type : 0x%x "), dwControlType);
2391
2392 switch (dwControlType)
2393 {
2394 case MIXERCONTROL_CONTROLTYPE_CUSTOM:
2395 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_CUSTOM)"));
2396 break;
2397 case MIXERCONTROL_CONTROLTYPE_BOOLEANMETER:
2398 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_BOOLEANMETER)"));
2399 break;
2400 case MIXERCONTROL_CONTROLTYPE_SIGNEDMETER:
2401 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_SIGNEDMETER)"));
2402 break;
2403 case MIXERCONTROL_CONTROLTYPE_PEAKMETER:
2404 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_PEAKMETER)"));
2405 break;
2406 case MIXERCONTROL_CONTROLTYPE_UNSIGNEDMETER:
2407 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_UNSIGNEDMETER)"));
2408 break;
2409 case MIXERCONTROL_CONTROLTYPE_BOOLEAN:
2410 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_BOOLEAN)"));
2411 break;
2412 case MIXERCONTROL_CONTROLTYPE_ONOFF:
2413 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_ONOFF)"));
2414 break;
2415 case MIXERCONTROL_CONTROLTYPE_MUTE:
2416 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_MUTE)"));
2417 break;
2418 case MIXERCONTROL_CONTROLTYPE_MONO:
2419 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_MONO)"));
2420 break;
2421 case MIXERCONTROL_CONTROLTYPE_LOUDNESS:
2422 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_LOUDNESS)"));
2423 break;
2424 case MIXERCONTROL_CONTROLTYPE_STEREOENH:
2425 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_STEREOENH)"));
2426 break;
2427 case MIXERCONTROL_CONTROLTYPE_BASS_BOOST:
2428 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_BASS_BOOST)"));
2429 break;
2430 case MIXERCONTROL_CONTROLTYPE_BUTTON:
2431 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_BUTTON)"));
2432 break;
2433 case MIXERCONTROL_CONTROLTYPE_DECIBELS:
2434 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_DECIBELS)"));
2435 break;
2436 case MIXERCONTROL_CONTROLTYPE_SIGNED:
2437 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_SIGNED)"));
2438 break;
2439 case MIXERCONTROL_CONTROLTYPE_UNSIGNED:
2440 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_UNSIGNED)"));
2441 break;
2442 case MIXERCONTROL_CONTROLTYPE_PERCENT:
2443 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_PERCENT)"));
2444 break;
2445 case MIXERCONTROL_CONTROLTYPE_SLIDER:
2446 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_SLIDER)"));
2447 break;
2448 case MIXERCONTROL_CONTROLTYPE_PAN:
2449 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_PAN)"));
2450 break;
2451 case MIXERCONTROL_CONTROLTYPE_QSOUNDPAN:
2452 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_QSOUNDPAN)"));
2453 break;
2454 case MIXERCONTROL_CONTROLTYPE_FADER:
2455 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_FADER)"));
2456 break;
2457 case MIXERCONTROL_CONTROLTYPE_VOLUME:
2458 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_VOLUME)"));
2459 break;
2460 case MIXERCONTROL_CONTROLTYPE_BASS:
2461 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_BASS)"));
2462 break;
2463 case MIXERCONTROL_CONTROLTYPE_TREBLE:
2464 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_TREBLE)"));
2465 break;
2466 case MIXERCONTROL_CONTROLTYPE_EQUALIZER:
2467 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_EQUALIZER)"));
2468 break;
2469 case MIXERCONTROL_CONTROLTYPE_SINGLESELECT:
2470 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_SINGLESELECT)"));
2471 break;
2472 case MIXERCONTROL_CONTROLTYPE_MUX:
2473 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_MUX)"));
2474 break;
2475 case MIXERCONTROL_CONTROLTYPE_MULTIPLESELECT:
2476 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_MULTIPLESELECT)"));
2477 break;
2478 case MIXERCONTROL_CONTROLTYPE_MIXER:
2479 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_MIXER)"));
2480 break;
2481 case MIXERCONTROL_CONTROLTYPE_MICROTIME:
2482 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_MICROTIME)"));
2483 break;
2484 case MIXERCONTROL_CONTROLTYPE_MILLITIME:
2485 StringCchCat(buf, 128, TEXT("(CONTROLTYPE_MILLITIME)"));
2486 break;
2487 default:
2488 StringCchCat(buf, 128, TEXT("(INVALID)"));
2489 break;
2490 }
2491
2492 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", WideToUTF8(buf));
2493 }
2494
2495 // ----------------------------------------------------------------------------
2496 // TraceControlStatusAndSupportFlags
2497 //
2498 // fdwControl
2499 //
2500 // Status and support flags for the audio line control. The following values
2501 // are defined:
2502 //
2503 // MIXERCONTROL_CONTROLF_DISABLED
2504 //
2505 // The control is disabled, perhaps due to other settings for the mixer hardware,
2506 // and cannot be used. An application can read current settings from a
2507 // disabled control, but it cannot apply settings.
2508 //
2509 // MIXERCONTROL_CONTROLF_MULTIPLE
2510 //
2511 // The control has two or more settings per channel. An equalizer, for example,
2512 // requires this flag because each frequency band can be set to a different value.
2513 // An equalizer that affects both channels of a stereo line in a uniform fashion
2514 // will also specify the MIXERCONTROL_CONTROLF_UNIFORM flag.
2515 //
2516 // MIXERCONTROL_CONTROLF_UNIFORM
2517 //
2518 // The control acts on all channels of a multichannel line in a uniform fashion.
2519 // For example, a control that mutes both channels of a stereo line would set
2520 // this flag. Most MIXERCONTROL_CONTROLTYPE_MUX and
2521 // MIXERCONTROL_CONTROLTYPE_MIXER controls also specify the
2522 // MIXERCONTROL_CONTROLF_UNIFORM flag.
2523 // ----------------------------------------------------------------------------
2524
TraceControlStatusAndSupportFlags(DWORD fdwControl) const2525 void AudioMixerManager::TraceControlStatusAndSupportFlags(DWORD fdwControl) const
2526 {
2527 TCHAR buf[128];
2528
2529 StringCchPrintf(buf, 128, TEXT("control support flags : 0x%x "), fdwControl);
2530
2531 if (fdwControl & MIXERCONTROL_CONTROLF_DISABLED)
2532 {
2533 // The control is disabled, perhaps due to other settings for the mixer hardware,
2534 // and cannot be used. An application can read current settings from a disabled
2535 // control, but it cannot apply settings.
2536 StringCchCat(buf, 128, TEXT("(CONTROLF_DISABLED)"));
2537 }
2538
2539 if (fdwControl & MIXERCONTROL_CONTROLF_MULTIPLE)
2540 {
2541 // The control has two or more settings per channel. An equalizer, for example,
2542 // requires this flag because each frequency band can be set to a different
2543 // value. An equalizer that affects both channels of a stereo line in a
2544 // uniform fashion will also specify the MIXERCONTROL_CONTROLF_UNIFORM flag.
2545 StringCchCat(buf, 128, TEXT("(CONTROLF_MULTIPLE)"));
2546 }
2547
2548 if (fdwControl & MIXERCONTROL_CONTROLF_UNIFORM)
2549 {
2550 // The control acts on all channels of a multichannel line in a uniform
2551 // fashion. For example, a control that mutes both channels of a stereo
2552 // line would set this flag. Most MIXERCONTROL_CONTROLTYPE_MUX and
2553 // MIXERCONTROL_CONTROLTYPE_MIXER controls also specify the
2554 // MIXERCONTROL_CONTROLF_UNIFORM flag.
2555 StringCchCat(buf, 128, TEXT("(CONTROLF_UNIFORM)"));
2556 }
2557
2558 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", WideToUTF8(buf));
2559 }
2560
2561 // ----------------------------------------------------------------------------
2562 // ClearSpeakerState I (II)
2563 // ----------------------------------------------------------------------------
2564
ClearSpeakerState(UINT idx)2565 void AudioMixerManager::ClearSpeakerState(UINT idx)
2566 {
2567 _speakerState[idx].dwLineID = 0L;
2568 _speakerState[idx].dwVolumeControlID = 0L;
2569 _speakerState[idx].dwMuteControlID = 0L;
2570 _speakerState[idx].speakerIsValid = false;
2571 _speakerState[idx].muteControlIsValid = false;
2572 _speakerState[idx].volumeControlIsValid = false;
2573 }
2574
2575 // ----------------------------------------------------------------------------
2576 // ClearSpeakerState II (II)
2577 // ----------------------------------------------------------------------------
2578
ClearSpeakerState()2579 void AudioMixerManager::ClearSpeakerState()
2580 {
2581 for (int i = 0; i < MAX_NUMBER_MIXER_DEVICES; i++)
2582 {
2583 ClearSpeakerState(i);
2584 }
2585 }
2586
2587 // ----------------------------------------------------------------------------
2588 // SpeakerIsValid
2589 // ----------------------------------------------------------------------------
2590
SpeakerIsValid(UINT idx) const2591 bool AudioMixerManager::SpeakerIsValid(UINT idx) const
2592 {
2593 return (_speakerState[idx].speakerIsValid);
2594 }
2595
2596 // ----------------------------------------------------------------------------
2597 // ValidSpeakers
2598 //
2599 // Counts number of valid speaker destinations for all mixer devices.
2600 // ----------------------------------------------------------------------------
2601
ValidSpeakers() const2602 UINT AudioMixerManager::ValidSpeakers() const
2603 {
2604 UINT nSpeakers(0);
2605 for (int i = 0; i < MAX_NUMBER_MIXER_DEVICES; i++)
2606 {
2607 if (SpeakerIsValid(i))
2608 nSpeakers++;
2609 }
2610 return nSpeakers;
2611 }
2612
2613 // ----------------------------------------------------------------------------
2614 // ClearMicrophoneState I (II)
2615 // ----------------------------------------------------------------------------
2616
ClearMicrophoneState(UINT idx)2617 void AudioMixerManager::ClearMicrophoneState(UINT idx)
2618 {
2619 _microphoneState[idx].dwLineID = 0L;
2620 _microphoneState[idx].dwVolumeControlID = 0L;
2621 _microphoneState[idx].dwMuteControlID = 0L;
2622 _microphoneState[idx].dwOnOffControlID = 0L;
2623 _microphoneState[idx].microphoneIsValid = false;
2624 _microphoneState[idx].muteControlIsValid = false;
2625 _microphoneState[idx].volumeControlIsValid = false;
2626 _microphoneState[idx].onOffControlIsValid = false;
2627 }
2628
2629 // ----------------------------------------------------------------------------
2630 // ClearMicrophoneState II (II)
2631 // ----------------------------------------------------------------------------
2632
ClearMicrophoneState()2633 void AudioMixerManager::ClearMicrophoneState()
2634 {
2635 for (int i = 0; i < MAX_NUMBER_MIXER_DEVICES; i++)
2636 {
2637 ClearMicrophoneState(i);
2638 }
2639 }
2640
2641 // ----------------------------------------------------------------------------
2642 // MicrophoneIsValid
2643 // ----------------------------------------------------------------------------
2644
MicrophoneIsValid(UINT idx) const2645 bool AudioMixerManager::MicrophoneIsValid(UINT idx) const
2646 {
2647 return (_microphoneState[idx].microphoneIsValid);
2648
2649 }
2650
2651 // ----------------------------------------------------------------------------
2652 // ValidMicrophones
2653 //
2654 // Counts number of valid speaker destinations for all mixer devices.
2655 // To be valid, a speaker destination line must exist.
2656 // ----------------------------------------------------------------------------
2657
ValidMicrophones() const2658 UINT AudioMixerManager::ValidMicrophones() const
2659 {
2660 UINT nMicrophones(0);
2661 for (int i = 0; i < MAX_NUMBER_MIXER_DEVICES; i++)
2662 {
2663 if (MicrophoneIsValid(i))
2664 nMicrophones++;
2665 }
2666 return nMicrophones;
2667 }
2668
2669 // ----------------------------------------------------------------------------
2670 // TraceWaveInError
2671 // ----------------------------------------------------------------------------
2672
TraceWaveInError(MMRESULT error) const2673 void AudioMixerManager::TraceWaveInError(MMRESULT error) const
2674 {
2675 TCHAR buf[MAXERRORLENGTH];
2676 TCHAR msg[MAXERRORLENGTH];
2677
2678 StringCchPrintf(buf, MAXERRORLENGTH, TEXT("Error details: "));
2679 waveInGetErrorText(error, msg, MAXERRORLENGTH);
2680 StringCchCat(buf, MAXERRORLENGTH, msg);
2681 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", WideToUTF8(buf));
2682 }
2683
2684 // ----------------------------------------------------------------------------
2685 // TraceWaveOutError
2686 // ----------------------------------------------------------------------------
2687
TraceWaveOutError(MMRESULT error) const2688 void AudioMixerManager::TraceWaveOutError(MMRESULT error) const
2689 {
2690 TCHAR buf[MAXERRORLENGTH];
2691 TCHAR msg[MAXERRORLENGTH];
2692
2693 StringCchPrintf(buf, MAXERRORLENGTH, TEXT("Error details: "));
2694 waveOutGetErrorText(error, msg, MAXERRORLENGTH);
2695 StringCchCat(buf, MAXERRORLENGTH, msg);
2696 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", WideToUTF8(buf));
2697 }
2698
2699 // ----------------------------------------------------------------------------
2700 // WideToUTF8
2701 // ----------------------------------------------------------------------------
2702
WideToUTF8(const TCHAR * src) const2703 char* AudioMixerManager::WideToUTF8(const TCHAR* src) const {
2704 #ifdef UNICODE
2705 const size_t kStrLen = sizeof(_str);
2706 memset(_str, 0, kStrLen);
2707 // Get required size (in bytes) to be able to complete the conversion.
2708 int required_size = WideCharToMultiByte(CP_UTF8, 0, src, -1, _str, 0, 0, 0);
2709 if (required_size <= kStrLen)
2710 {
2711 // Process the entire input string, including the terminating null char.
2712 if (WideCharToMultiByte(CP_UTF8, 0, src, -1, _str, kStrLen, 0, 0) == 0)
2713 memset(_str, 0, kStrLen);
2714 }
2715 return _str;
2716 #else
2717 return const_cast<char*>(src);
2718 #endif
2719 }
2720
2721 } // namespace webrtc
2722