• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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