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