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