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