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