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 #pragma warning(disable: 4995)  // name was marked as #pragma deprecated
     12 
     13 #if (_MSC_VER >= 1310) && (_MSC_VER < 1400)
     14 // Reports the major and minor versions of the compiler.
     15 // For example, 1310 for Microsoft Visual C++ .NET 2003. 1310 represents version 13 and a 1.0 point release.
     16 // The Visual C++ 2005 compiler version is 1400.
     17 // Type cl /? at the command line to see the major and minor versions of your compiler along with the build number.
     18 #pragma message(">> INFO: Windows Core Audio is not supported in VS 2003")
     19 #endif
     20 
     21 #include "webrtc/modules/audio_device/audio_device_config.h"
     22 
     23 #if defined(WEBRTC_WINDOWS_CORE_AUDIO_BUILD)
     24 #pragma message(">> INFO: WEBRTC_WINDOWS_CORE_AUDIO_BUILD is defined")
     25 #else
     26 #pragma message(">> INFO: WEBRTC_WINDOWS_CORE_AUDIO_BUILD is *not* defined")
     27 #endif
     28 
     29 #ifdef WEBRTC_WINDOWS_CORE_AUDIO_BUILD
     30 
     31 #include "webrtc/modules/audio_device/win/audio_device_core_win.h"
     32 
     33 #include <assert.h>
     34 #include <string.h>
     35 
     36 #include <windows.h>
     37 #include <comdef.h>
     38 #include <dmo.h>
     39 #include <Functiondiscoverykeys_devpkey.h>
     40 #include <mmsystem.h>
     41 #include <strsafe.h>
     42 #include <uuids.h>
     43 
     44 #include "webrtc/modules/audio_device/audio_device_utility.h"
     45 #include "webrtc/system_wrappers/interface/sleep.h"
     46 #include "webrtc/system_wrappers/interface/trace.h"
     47 
     48 // Macro that calls a COM method returning HRESULT value.
     49 #define EXIT_ON_ERROR(hres)    do { if (FAILED(hres)) goto Exit; } while(0)
     50 
     51 // Macro that continues to a COM error.
     52 #define CONTINUE_ON_ERROR(hres) do { if (FAILED(hres)) goto Next; } while(0)
     53 
     54 // Macro that releases a COM object if not NULL.
     55 #define SAFE_RELEASE(p)     do { if ((p)) { (p)->Release(); (p) = NULL; } } while(0)
     56 
     57 #define ROUND(x) ((x) >=0 ? (int)((x) + 0.5) : (int)((x) - 0.5))
     58 
     59 // REFERENCE_TIME time units per millisecond
     60 #define REFTIMES_PER_MILLISEC  10000
     61 
     62 typedef struct tagTHREADNAME_INFO
     63 {
     64    DWORD dwType;        // must be 0x1000
     65    LPCSTR szName;       // pointer to name (in user addr space)
     66    DWORD dwThreadID;    // thread ID (-1=caller thread)
     67    DWORD dwFlags;       // reserved for future use, must be zero
     68 } THREADNAME_INFO;
     69 
     70 namespace webrtc {
     71 namespace {
     72 
     73 enum { COM_THREADING_MODEL = COINIT_MULTITHREADED };
     74 
     75 enum
     76 {
     77     kAecCaptureStreamIndex = 0,
     78     kAecRenderStreamIndex = 1
     79 };
     80 
     81 // An implementation of IMediaBuffer, as required for
     82 // IMediaObject::ProcessOutput(). After consuming data provided by
     83 // ProcessOutput(), call SetLength() to update the buffer availability.
     84 //
     85 // Example implementation:
     86 // http://msdn.microsoft.com/en-us/library/dd376684(v=vs.85).aspx
     87 class MediaBufferImpl : public IMediaBuffer
     88 {
     89 public:
     90     explicit MediaBufferImpl(DWORD maxLength)
     91         : _data(new BYTE[maxLength]),
     92           _length(0),
     93           _maxLength(maxLength),
     94           _refCount(0)
     95     {}
     96 
     97     // IMediaBuffer methods.
     98     STDMETHOD(GetBufferAndLength(BYTE** ppBuffer, DWORD* pcbLength))
     99     {
    100         if (!ppBuffer || !pcbLength)
    101         {
    102             return E_POINTER;
    103         }
    104 
    105         *ppBuffer = _data;
    106         *pcbLength = _length;
    107 
    108         return S_OK;
    109     }
    110 
    111     STDMETHOD(GetMaxLength(DWORD* pcbMaxLength))
    112     {
    113         if (!pcbMaxLength)
    114         {
    115             return E_POINTER;
    116         }
    117 
    118         *pcbMaxLength = _maxLength;
    119         return S_OK;
    120     }
    121 
    122     STDMETHOD(SetLength(DWORD cbLength))
    123     {
    124         if (cbLength > _maxLength)
    125         {
    126             return E_INVALIDARG;
    127         }
    128 
    129         _length = cbLength;
    130         return S_OK;
    131     }
    132 
    133     // IUnknown methods.
    134     STDMETHOD_(ULONG, AddRef())
    135     {
    136         return InterlockedIncrement(&_refCount);
    137     }
    138 
    139     STDMETHOD(QueryInterface(REFIID riid, void** ppv))
    140     {
    141         if (!ppv)
    142         {
    143             return E_POINTER;
    144         }
    145         else if (riid != IID_IMediaBuffer && riid != IID_IUnknown)
    146         {
    147             return E_NOINTERFACE;
    148         }
    149 
    150         *ppv = static_cast<IMediaBuffer*>(this);
    151         AddRef();
    152         return S_OK;
    153     }
    154 
    155     STDMETHOD_(ULONG, Release())
    156     {
    157         LONG refCount = InterlockedDecrement(&_refCount);
    158         if (refCount == 0)
    159         {
    160             delete this;
    161         }
    162 
    163         return refCount;
    164     }
    165 
    166 private:
    167     ~MediaBufferImpl()
    168     {
    169         delete [] _data;
    170     }
    171 
    172     BYTE* _data;
    173     DWORD _length;
    174     const DWORD _maxLength;
    175     LONG _refCount;
    176 };
    177 }  // namespace
    178 
    179 // ============================================================================
    180 //                              Static Methods
    181 // ============================================================================
    182 
    183 // ----------------------------------------------------------------------------
    184 //  CoreAudioIsSupported
    185 // ----------------------------------------------------------------------------
    186 
    187 bool AudioDeviceWindowsCore::CoreAudioIsSupported()
    188 {
    189     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, -1, "%s", __FUNCTION__);
    190 
    191     bool MMDeviceIsAvailable(false);
    192     bool coreAudioIsSupported(false);
    193 
    194     HRESULT hr(S_OK);
    195     TCHAR buf[MAXERRORLENGTH];
    196     TCHAR errorText[MAXERRORLENGTH];
    197 
    198     // 1) Check if Windows version is Vista SP1 or later.
    199     //
    200     // CoreAudio is only available on Vista SP1 and later.
    201     //
    202     OSVERSIONINFOEX osvi;
    203     DWORDLONG dwlConditionMask = 0;
    204     int op = VER_LESS_EQUAL;
    205 
    206     // Initialize the OSVERSIONINFOEX structure.
    207     ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
    208     osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
    209     osvi.dwMajorVersion = 6;
    210     osvi.dwMinorVersion = 0;
    211     osvi.wServicePackMajor = 0;
    212     osvi.wServicePackMinor = 0;
    213     osvi.wProductType = VER_NT_WORKSTATION;
    214 
    215     // Initialize the condition mask.
    216     VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION, op);
    217     VER_SET_CONDITION(dwlConditionMask, VER_MINORVERSION, op);
    218     VER_SET_CONDITION(dwlConditionMask, VER_SERVICEPACKMAJOR, op);
    219     VER_SET_CONDITION(dwlConditionMask, VER_SERVICEPACKMINOR, op);
    220     VER_SET_CONDITION(dwlConditionMask, VER_PRODUCT_TYPE, VER_EQUAL);
    221 
    222     DWORD dwTypeMask = VER_MAJORVERSION | VER_MINORVERSION |
    223                        VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR |
    224                        VER_PRODUCT_TYPE;
    225 
    226     // Perform the test.
    227     BOOL isVistaRTMorXP = VerifyVersionInfo(&osvi, dwTypeMask,
    228                                             dwlConditionMask);
    229     if (isVistaRTMorXP != 0)
    230     {
    231         WEBRTC_TRACE(kTraceStateInfo, kTraceAudioDevice, -1,
    232             "*** Windows Core Audio is only supported on Vista SP1 or later "
    233             "=> will revert to the Wave API ***");
    234         return false;
    235     }
    236 
    237     // 2) Initializes the COM library for use by the calling thread.
    238 
    239     // The COM init wrapper sets the thread's concurrency model to MTA,
    240     // and creates a new apartment for the thread if one is required. The
    241     // wrapper also ensures that each call to CoInitializeEx is balanced
    242     // by a corresponding call to CoUninitialize.
    243     //
    244     ScopedCOMInitializer comInit(ScopedCOMInitializer::kMTA);
    245     if (!comInit.succeeded()) {
    246       // Things will work even if an STA thread is calling this method but we
    247       // want to ensure that MTA is used and therefore return false here.
    248       return false;
    249     }
    250 
    251     // 3) Check if the MMDevice API is available.
    252     //
    253     // The Windows Multimedia Device (MMDevice) API enables audio clients to
    254     // discover audio endpoint devices, determine their capabilities, and create
    255     // driver instances for those devices.
    256     // Header file Mmdeviceapi.h defines the interfaces in the MMDevice API.
    257     // The MMDevice API consists of several interfaces. The first of these is the
    258     // IMMDeviceEnumerator interface. To access the interfaces in the MMDevice API,
    259     // a client obtains a reference to the IMMDeviceEnumerator interface of a
    260     // device-enumerator object by calling the CoCreateInstance function.
    261     //
    262     // Through the IMMDeviceEnumerator interface, the client can obtain references
    263     // to the other interfaces in the MMDevice API. The MMDevice API implements
    264     // the following interfaces:
    265     //
    266     // IMMDevice            Represents an audio device.
    267     // IMMDeviceCollection  Represents a collection of audio devices.
    268     // IMMDeviceEnumerator  Provides methods for enumerating audio devices.
    269     // IMMEndpoint          Represents an audio endpoint device.
    270     //
    271     IMMDeviceEnumerator* pIMMD(NULL);
    272     const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator);
    273     const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator);
    274 
    275     hr = CoCreateInstance(
    276             CLSID_MMDeviceEnumerator,   // GUID value of MMDeviceEnumerator coclass
    277             NULL,
    278             CLSCTX_ALL,
    279             IID_IMMDeviceEnumerator,    // GUID value of the IMMDeviceEnumerator interface
    280             (void**)&pIMMD );
    281 
    282     if (FAILED(hr))
    283     {
    284         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, -1,
    285             "AudioDeviceWindowsCore::CoreAudioIsSupported() Failed to create the required COM object", hr);
    286         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, -1,
    287             "AudioDeviceWindowsCore::CoreAudioIsSupported() CoCreateInstance(MMDeviceEnumerator) failed (hr=0x%x)", hr);
    288 
    289         const DWORD dwFlags = FORMAT_MESSAGE_FROM_SYSTEM |
    290                               FORMAT_MESSAGE_IGNORE_INSERTS;
    291         const DWORD dwLangID = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
    292 
    293         // Gets the system's human readable message string for this HRESULT.
    294         // All error message in English by default.
    295         DWORD messageLength = ::FormatMessageW(dwFlags,
    296                                                0,
    297                                                hr,
    298                                                dwLangID,
    299                                                errorText,
    300                                                MAXERRORLENGTH,
    301                                                NULL);
    302 
    303         assert(messageLength <= MAXERRORLENGTH);
    304 
    305         // Trims tailing white space (FormatMessage() leaves a trailing cr-lf.).
    306         for (; messageLength && ::isspace(errorText[messageLength - 1]);
    307              --messageLength)
    308         {
    309             errorText[messageLength - 1] = '\0';
    310         }
    311 
    312         StringCchPrintf(buf, MAXERRORLENGTH, TEXT("Error details: "));
    313         StringCchCat(buf, MAXERRORLENGTH, errorText);
    314         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, -1, "%S", buf);
    315     }
    316     else
    317     {
    318         MMDeviceIsAvailable = true;
    319         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, -1,
    320             "AudioDeviceWindowsCore::CoreAudioIsSupported() CoCreateInstance(MMDeviceEnumerator) succeeded", hr);
    321         SAFE_RELEASE(pIMMD);
    322     }
    323 
    324     // 4) Verify that we can create and initialize our Core Audio class.
    325     //
    326     // Also, perform a limited "API test" to ensure that Core Audio is supported for all devices.
    327     //
    328     if (MMDeviceIsAvailable)
    329     {
    330         coreAudioIsSupported = false;
    331 
    332         AudioDeviceWindowsCore* p = new AudioDeviceWindowsCore(-1);
    333         if (p == NULL)
    334         {
    335             return false;
    336         }
    337 
    338         int ok(0);
    339         int temp_ok(0);
    340         bool available(false);
    341 
    342         ok |= p->Init();
    343 
    344         int16_t numDevsRec = p->RecordingDevices();
    345         for (uint16_t i = 0; i < numDevsRec; i++)
    346         {
    347             ok |= p->SetRecordingDevice(i);
    348             temp_ok = p->RecordingIsAvailable(available);
    349             ok |= temp_ok;
    350             ok |= (available == false);
    351             if (available)
    352             {
    353                 ok |= p->InitMicrophone();
    354             }
    355             if (ok)
    356             {
    357                 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, -1,
    358                     "AudioDeviceWindowsCore::CoreAudioIsSupported() Failed to use Core Audio Recording for device id=%i", i);
    359             }
    360         }
    361 
    362         int16_t numDevsPlay = p->PlayoutDevices();
    363         for (uint16_t i = 0; i < numDevsPlay; i++)
    364         {
    365             ok |= p->SetPlayoutDevice(i);
    366             temp_ok = p->PlayoutIsAvailable(available);
    367             ok |= temp_ok;
    368             ok |= (available == false);
    369             if (available)
    370             {
    371                 ok |= p->InitSpeaker();
    372             }
    373             if (ok)
    374             {
    375                 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, -1 ,
    376                     "AudioDeviceWindowsCore::CoreAudioIsSupported() Failed to use Core Audio Playout for device id=%i", i);
    377             }
    378         }
    379 
    380         ok |= p->Terminate();
    381 
    382         if (ok == 0)
    383         {
    384             coreAudioIsSupported = true;
    385         }
    386 
    387         delete p;
    388     }
    389 
    390     if (coreAudioIsSupported)
    391     {
    392         WEBRTC_TRACE(kTraceStateInfo, kTraceAudioDevice, -1, "*** Windows Core Audio is supported ***");
    393     }
    394     else
    395     {
    396         WEBRTC_TRACE(kTraceStateInfo, kTraceAudioDevice, -1, "*** Windows Core Audio is NOT supported => will revert to the Wave API ***");
    397     }
    398 
    399     return (coreAudioIsSupported);
    400 }
    401 
    402 // ============================================================================
    403 //                            Construction & Destruction
    404 // ============================================================================
    405 
    406 // ----------------------------------------------------------------------------
    407 //  AudioDeviceWindowsCore() - ctor
    408 // ----------------------------------------------------------------------------
    409 
    410 AudioDeviceWindowsCore::AudioDeviceWindowsCore(const int32_t id) :
    411     _comInit(ScopedCOMInitializer::kMTA),
    412     _critSect(*CriticalSectionWrapper::CreateCriticalSection()),
    413     _volumeMutex(*CriticalSectionWrapper::CreateCriticalSection()),
    414     _id(id),
    415     _ptrAudioBuffer(NULL),
    416     _ptrEnumerator(NULL),
    417     _ptrRenderCollection(NULL),
    418     _ptrCaptureCollection(NULL),
    419     _ptrDeviceOut(NULL),
    420     _ptrDeviceIn(NULL),
    421     _ptrClientOut(NULL),
    422     _ptrClientIn(NULL),
    423     _ptrRenderClient(NULL),
    424     _ptrCaptureClient(NULL),
    425     _ptrCaptureVolume(NULL),
    426     _ptrRenderSimpleVolume(NULL),
    427     _dmo(NULL),
    428     _mediaBuffer(NULL),
    429     _builtInAecEnabled(false),
    430     _playAudioFrameSize(0),
    431     _playSampleRate(0),
    432     _playBlockSize(0),
    433     _playChannels(2),
    434     _sndCardPlayDelay(0),
    435     _sndCardRecDelay(0),
    436     _writtenSamples(0),
    437     _readSamples(0),
    438     _playAcc(0),
    439     _recAudioFrameSize(0),
    440     _recSampleRate(0),
    441     _recBlockSize(0),
    442     _recChannels(2),
    443     _avrtLibrary(NULL),
    444     _winSupportAvrt(false),
    445     _hRenderSamplesReadyEvent(NULL),
    446     _hPlayThread(NULL),
    447     _hCaptureSamplesReadyEvent(NULL),
    448     _hRecThread(NULL),
    449     _hShutdownRenderEvent(NULL),
    450     _hShutdownCaptureEvent(NULL),
    451     _hRenderStartedEvent(NULL),
    452     _hCaptureStartedEvent(NULL),
    453     _hGetCaptureVolumeThread(NULL),
    454     _hSetCaptureVolumeThread(NULL),
    455     _hSetCaptureVolumeEvent(NULL),
    456     _hMmTask(NULL),
    457     _initialized(false),
    458     _recording(false),
    459     _playing(false),
    460     _recIsInitialized(false),
    461     _playIsInitialized(false),
    462     _speakerIsInitialized(false),
    463     _microphoneIsInitialized(false),
    464     _AGC(false),
    465     _playWarning(0),
    466     _playError(0),
    467     _recWarning(0),
    468     _recError(0),
    469     _playBufType(AudioDeviceModule::kAdaptiveBufferSize),
    470     _playBufDelay(80),
    471     _playBufDelayFixed(80),
    472     _usingInputDeviceIndex(false),
    473     _usingOutputDeviceIndex(false),
    474     _inputDevice(AudioDeviceModule::kDefaultCommunicationDevice),
    475     _outputDevice(AudioDeviceModule::kDefaultCommunicationDevice),
    476     _inputDeviceIndex(0),
    477     _outputDeviceIndex(0),
    478     _newMicLevel(0)
    479 {
    480     WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, id, "%s created", __FUNCTION__);
    481     assert(_comInit.succeeded());
    482 
    483     // Try to load the Avrt DLL
    484     if (!_avrtLibrary)
    485     {
    486         // Get handle to the Avrt DLL module.
    487         _avrtLibrary = LoadLibrary(TEXT("Avrt.dll"));
    488         if (_avrtLibrary)
    489         {
    490             // Handle is valid (should only happen if OS larger than vista & win7).
    491             // Try to get the function addresses.
    492             WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "AudioDeviceWindowsCore::AudioDeviceWindowsCore() The Avrt DLL module is now loaded");
    493 
    494             _PAvRevertMmThreadCharacteristics = (PAvRevertMmThreadCharacteristics)GetProcAddress(_avrtLibrary, "AvRevertMmThreadCharacteristics");
    495             _PAvSetMmThreadCharacteristicsA = (PAvSetMmThreadCharacteristicsA)GetProcAddress(_avrtLibrary, "AvSetMmThreadCharacteristicsA");
    496             _PAvSetMmThreadPriority = (PAvSetMmThreadPriority)GetProcAddress(_avrtLibrary, "AvSetMmThreadPriority");
    497 
    498             if ( _PAvRevertMmThreadCharacteristics &&
    499                  _PAvSetMmThreadCharacteristicsA &&
    500                  _PAvSetMmThreadPriority)
    501             {
    502                 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "AudioDeviceWindowsCore::AudioDeviceWindowsCore() AvRevertMmThreadCharacteristics() is OK");
    503                 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "AudioDeviceWindowsCore::AudioDeviceWindowsCore() AvSetMmThreadCharacteristicsA() is OK");
    504                 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "AudioDeviceWindowsCore::AudioDeviceWindowsCore() AvSetMmThreadPriority() is OK");
    505                 _winSupportAvrt = true;
    506             }
    507         }
    508     }
    509 
    510     // Create our samples ready events - we want auto reset events that start in the not-signaled state.
    511     // The state of an auto-reset event object remains signaled until a single waiting thread is released,
    512     // at which time the system automatically sets the state to nonsignaled. If no threads are waiting,
    513     // the event object's state remains signaled.
    514     // (Except for _hShutdownCaptureEvent, which is used to shutdown multiple threads).
    515     _hRenderSamplesReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    516     _hCaptureSamplesReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    517     _hShutdownRenderEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    518     _hShutdownCaptureEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    519     _hRenderStartedEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    520     _hCaptureStartedEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    521     _hSetCaptureVolumeEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    522 
    523     _perfCounterFreq.QuadPart = 1;
    524     _perfCounterFactor = 0.0;
    525     _avgCPULoad = 0.0;
    526 
    527     // list of number of channels to use on recording side
    528     _recChannelsPrioList[0] = 2;    // stereo is prio 1
    529     _recChannelsPrioList[1] = 1;    // mono is prio 2
    530 
    531     // list of number of channels to use on playout side
    532     _playChannelsPrioList[0] = 2;    // stereo is prio 1
    533     _playChannelsPrioList[1] = 1;    // mono is prio 2
    534 
    535     HRESULT hr;
    536 
    537     // We know that this API will work since it has already been verified in
    538     // CoreAudioIsSupported, hence no need to check for errors here as well.
    539 
    540     // Retrive the IMMDeviceEnumerator API (should load the MMDevAPI.dll)
    541     // TODO(henrika): we should probably move this allocation to Init() instead
    542     // and deallocate in Terminate() to make the implementation more symmetric.
    543     CoCreateInstance(
    544       __uuidof(MMDeviceEnumerator),
    545       NULL,
    546       CLSCTX_ALL,
    547       __uuidof(IMMDeviceEnumerator),
    548       reinterpret_cast<void**>(&_ptrEnumerator));
    549     assert(NULL != _ptrEnumerator);
    550 
    551     // DMO initialization for built-in WASAPI AEC.
    552     {
    553         IMediaObject* ptrDMO = NULL;
    554         hr = CoCreateInstance(CLSID_CWMAudioAEC,
    555                               NULL,
    556                               CLSCTX_INPROC_SERVER,
    557                               IID_IMediaObject,
    558                               reinterpret_cast<void**>(&ptrDMO));
    559         if (FAILED(hr) || ptrDMO == NULL)
    560         {
    561             // Since we check that _dmo is non-NULL in EnableBuiltInAEC(), the
    562             // feature is prevented from being enabled.
    563             _builtInAecEnabled = false;
    564             _TraceCOMError(hr);
    565         }
    566         _dmo = ptrDMO;
    567         SAFE_RELEASE(ptrDMO);
    568     }
    569 }
    570 
    571 // ----------------------------------------------------------------------------
    572 //  AudioDeviceWindowsCore() - dtor
    573 // ----------------------------------------------------------------------------
    574 
    575 AudioDeviceWindowsCore::~AudioDeviceWindowsCore()
    576 {
    577     WEBRTC_TRACE(kTraceMemory, kTraceAudioDevice, _id, "%s destroyed", __FUNCTION__);
    578 
    579     Terminate();
    580 
    581     // The IMMDeviceEnumerator is created during construction. Must release
    582     // it here and not in Terminate() since we don't recreate it in Init().
    583     SAFE_RELEASE(_ptrEnumerator);
    584 
    585     _ptrAudioBuffer = NULL;
    586 
    587     if (NULL != _hRenderSamplesReadyEvent)
    588     {
    589         CloseHandle(_hRenderSamplesReadyEvent);
    590         _hRenderSamplesReadyEvent = NULL;
    591     }
    592 
    593     if (NULL != _hCaptureSamplesReadyEvent)
    594     {
    595         CloseHandle(_hCaptureSamplesReadyEvent);
    596         _hCaptureSamplesReadyEvent = NULL;
    597     }
    598 
    599     if (NULL != _hRenderStartedEvent)
    600     {
    601         CloseHandle(_hRenderStartedEvent);
    602         _hRenderStartedEvent = NULL;
    603     }
    604 
    605     if (NULL != _hCaptureStartedEvent)
    606     {
    607         CloseHandle(_hCaptureStartedEvent);
    608         _hCaptureStartedEvent = NULL;
    609     }
    610 
    611     if (NULL != _hShutdownRenderEvent)
    612     {
    613         CloseHandle(_hShutdownRenderEvent);
    614         _hShutdownRenderEvent = NULL;
    615     }
    616 
    617     if (NULL != _hShutdownCaptureEvent)
    618     {
    619         CloseHandle(_hShutdownCaptureEvent);
    620         _hShutdownCaptureEvent = NULL;
    621     }
    622 
    623     if (NULL != _hSetCaptureVolumeEvent)
    624     {
    625         CloseHandle(_hSetCaptureVolumeEvent);
    626         _hSetCaptureVolumeEvent = NULL;
    627     }
    628 
    629     if (_avrtLibrary)
    630     {
    631         BOOL freeOK = FreeLibrary(_avrtLibrary);
    632         if (!freeOK)
    633         {
    634             WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
    635                 "AudioDeviceWindowsCore::~AudioDeviceWindowsCore() failed to free the loaded Avrt DLL module correctly");
    636         }
    637         else
    638         {
    639             WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
    640                 "AudioDeviceWindowsCore::~AudioDeviceWindowsCore() the Avrt DLL module is now unloaded");
    641         }
    642     }
    643 
    644     delete &_critSect;
    645     delete &_volumeMutex;
    646 }
    647 
    648 // ============================================================================
    649 //                                     API
    650 // ============================================================================
    651 
    652 // ----------------------------------------------------------------------------
    653 //  AttachAudioBuffer
    654 // ----------------------------------------------------------------------------
    655 
    656 void AudioDeviceWindowsCore::AttachAudioBuffer(AudioDeviceBuffer* audioBuffer)
    657 {
    658 
    659     _ptrAudioBuffer = audioBuffer;
    660 
    661     // Inform the AudioBuffer about default settings for this implementation.
    662     // Set all values to zero here since the actual settings will be done by
    663     // InitPlayout and InitRecording later.
    664     _ptrAudioBuffer->SetRecordingSampleRate(0);
    665     _ptrAudioBuffer->SetPlayoutSampleRate(0);
    666     _ptrAudioBuffer->SetRecordingChannels(0);
    667     _ptrAudioBuffer->SetPlayoutChannels(0);
    668 }
    669 
    670 // ----------------------------------------------------------------------------
    671 //  ActiveAudioLayer
    672 // ----------------------------------------------------------------------------
    673 
    674 int32_t AudioDeviceWindowsCore::ActiveAudioLayer(AudioDeviceModule::AudioLayer& audioLayer) const
    675 {
    676     audioLayer = AudioDeviceModule::kWindowsCoreAudio;
    677     return 0;
    678 }
    679 
    680 // ----------------------------------------------------------------------------
    681 //  Init
    682 // ----------------------------------------------------------------------------
    683 
    684 int32_t AudioDeviceWindowsCore::Init()
    685 {
    686 
    687     CriticalSectionScoped lock(&_critSect);
    688 
    689     if (_initialized)
    690     {
    691         return 0;
    692     }
    693 
    694     _playWarning = 0;
    695     _playError = 0;
    696     _recWarning = 0;
    697     _recError = 0;
    698 
    699     // Enumerate all audio rendering and capturing endpoint devices.
    700     // Note that, some of these will not be able to select by the user.
    701     // The complete collection is for internal use only.
    702     //
    703     _EnumerateEndpointDevicesAll(eRender);
    704     _EnumerateEndpointDevicesAll(eCapture);
    705 
    706     _initialized = true;
    707 
    708     return 0;
    709 }
    710 
    711 // ----------------------------------------------------------------------------
    712 //  Terminate
    713 // ----------------------------------------------------------------------------
    714 
    715 int32_t AudioDeviceWindowsCore::Terminate()
    716 {
    717 
    718     CriticalSectionScoped lock(&_critSect);
    719 
    720     if (!_initialized) {
    721         return 0;
    722     }
    723 
    724     _initialized = false;
    725     _speakerIsInitialized = false;
    726     _microphoneIsInitialized = false;
    727     _playing = false;
    728     _recording = false;
    729 
    730     SAFE_RELEASE(_ptrRenderCollection);
    731     SAFE_RELEASE(_ptrCaptureCollection);
    732     SAFE_RELEASE(_ptrDeviceOut);
    733     SAFE_RELEASE(_ptrDeviceIn);
    734     SAFE_RELEASE(_ptrClientOut);
    735     SAFE_RELEASE(_ptrClientIn);
    736     SAFE_RELEASE(_ptrRenderClient);
    737     SAFE_RELEASE(_ptrCaptureClient);
    738     SAFE_RELEASE(_ptrCaptureVolume);
    739     SAFE_RELEASE(_ptrRenderSimpleVolume);
    740 
    741     return 0;
    742 }
    743 
    744 // ----------------------------------------------------------------------------
    745 //  Initialized
    746 // ----------------------------------------------------------------------------
    747 
    748 bool AudioDeviceWindowsCore::Initialized() const
    749 {
    750     return (_initialized);
    751 }
    752 
    753 // ----------------------------------------------------------------------------
    754 //  InitSpeaker
    755 // ----------------------------------------------------------------------------
    756 
    757 int32_t AudioDeviceWindowsCore::InitSpeaker()
    758 {
    759 
    760     CriticalSectionScoped lock(&_critSect);
    761 
    762     if (_playing)
    763     {
    764         return -1;
    765     }
    766 
    767     if (_ptrDeviceOut == NULL)
    768     {
    769         return -1;
    770     }
    771 
    772     if (_usingOutputDeviceIndex)
    773     {
    774         int16_t nDevices = PlayoutDevices();
    775         if (_outputDeviceIndex > (nDevices - 1))
    776         {
    777             WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "current device selection is invalid => unable to initialize");
    778             return -1;
    779         }
    780     }
    781 
    782     int32_t ret(0);
    783 
    784     SAFE_RELEASE(_ptrDeviceOut);
    785     if (_usingOutputDeviceIndex)
    786     {
    787         // Refresh the selected rendering endpoint device using current index
    788         ret = _GetListDevice(eRender, _outputDeviceIndex, &_ptrDeviceOut);
    789     }
    790     else
    791     {
    792         ERole role;
    793         (_outputDevice == AudioDeviceModule::kDefaultDevice) ? role = eConsole : role = eCommunications;
    794         // Refresh the selected rendering endpoint device using role
    795         ret = _GetDefaultDevice(eRender, role, &_ptrDeviceOut);
    796     }
    797 
    798     if (ret != 0 || (_ptrDeviceOut == NULL))
    799     {
    800         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "failed to initialize the rendering enpoint device");
    801         SAFE_RELEASE(_ptrDeviceOut);
    802         return -1;
    803     }
    804 
    805     IAudioSessionManager* pManager = NULL;
    806     ret = _ptrDeviceOut->Activate(__uuidof(IAudioSessionManager),
    807                                   CLSCTX_ALL,
    808                                   NULL,
    809                                   (void**)&pManager);
    810     if (ret != 0 || pManager == NULL)
    811     {
    812         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
    813                     "  failed to initialize the render manager");
    814         SAFE_RELEASE(pManager);
    815         return -1;
    816     }
    817 
    818     SAFE_RELEASE(_ptrRenderSimpleVolume);
    819     ret = pManager->GetSimpleAudioVolume(NULL, FALSE, &_ptrRenderSimpleVolume);
    820     if (ret != 0 || _ptrRenderSimpleVolume == NULL)
    821     {
    822         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
    823                     "  failed to initialize the render simple volume");
    824         SAFE_RELEASE(pManager);
    825         SAFE_RELEASE(_ptrRenderSimpleVolume);
    826         return -1;
    827     }
    828     SAFE_RELEASE(pManager);
    829 
    830     _speakerIsInitialized = true;
    831 
    832     return 0;
    833 }
    834 
    835 // ----------------------------------------------------------------------------
    836 //  InitMicrophone
    837 // ----------------------------------------------------------------------------
    838 
    839 int32_t AudioDeviceWindowsCore::InitMicrophone()
    840 {
    841 
    842     CriticalSectionScoped lock(&_critSect);
    843 
    844     if (_recording)
    845     {
    846         return -1;
    847     }
    848 
    849     if (_ptrDeviceIn == NULL)
    850     {
    851         return -1;
    852     }
    853 
    854     if (_usingInputDeviceIndex)
    855     {
    856         int16_t nDevices = RecordingDevices();
    857         if (_inputDeviceIndex > (nDevices - 1))
    858         {
    859             WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "current device selection is invalid => unable to initialize");
    860             return -1;
    861         }
    862     }
    863 
    864     int32_t ret(0);
    865 
    866     SAFE_RELEASE(_ptrDeviceIn);
    867     if (_usingInputDeviceIndex)
    868     {
    869         // Refresh the selected capture endpoint device using current index
    870         ret = _GetListDevice(eCapture, _inputDeviceIndex, &_ptrDeviceIn);
    871     }
    872     else
    873     {
    874         ERole role;
    875         (_inputDevice == AudioDeviceModule::kDefaultDevice) ? role = eConsole : role = eCommunications;
    876         // Refresh the selected capture endpoint device using role
    877         ret = _GetDefaultDevice(eCapture, role, &_ptrDeviceIn);
    878     }
    879 
    880     if (ret != 0 || (_ptrDeviceIn == NULL))
    881     {
    882         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "failed to initialize the capturing enpoint device");
    883         SAFE_RELEASE(_ptrDeviceIn);
    884         return -1;
    885     }
    886 
    887     ret = _ptrDeviceIn->Activate(__uuidof(IAudioEndpointVolume),
    888                                  CLSCTX_ALL,
    889                                  NULL,
    890                                  reinterpret_cast<void **>(&_ptrCaptureVolume));
    891     if (ret != 0 || _ptrCaptureVolume == NULL)
    892     {
    893         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
    894                     "  failed to initialize the capture volume");
    895         SAFE_RELEASE(_ptrCaptureVolume);
    896         return -1;
    897     }
    898 
    899     _microphoneIsInitialized = true;
    900 
    901     return 0;
    902 }
    903 
    904 // ----------------------------------------------------------------------------
    905 //  SpeakerIsInitialized
    906 // ----------------------------------------------------------------------------
    907 
    908 bool AudioDeviceWindowsCore::SpeakerIsInitialized() const
    909 {
    910 
    911     return (_speakerIsInitialized);
    912 }
    913 
    914 // ----------------------------------------------------------------------------
    915 //  MicrophoneIsInitialized
    916 // ----------------------------------------------------------------------------
    917 
    918 bool AudioDeviceWindowsCore::MicrophoneIsInitialized() const
    919 {
    920 
    921     return (_microphoneIsInitialized);
    922 }
    923 
    924 // ----------------------------------------------------------------------------
    925 //  SpeakerVolumeIsAvailable
    926 // ----------------------------------------------------------------------------
    927 
    928 int32_t AudioDeviceWindowsCore::SpeakerVolumeIsAvailable(bool& available)
    929 {
    930 
    931     CriticalSectionScoped lock(&_critSect);
    932 
    933     if (_ptrDeviceOut == NULL)
    934     {
    935         return -1;
    936     }
    937 
    938     HRESULT hr = S_OK;
    939     IAudioSessionManager* pManager = NULL;
    940     ISimpleAudioVolume* pVolume = NULL;
    941 
    942     hr = _ptrDeviceOut->Activate(__uuidof(IAudioSessionManager), CLSCTX_ALL, NULL, (void**)&pManager);
    943     EXIT_ON_ERROR(hr);
    944 
    945     hr = pManager->GetSimpleAudioVolume(NULL, FALSE, &pVolume);
    946     EXIT_ON_ERROR(hr);
    947 
    948     float volume(0.0f);
    949     hr = pVolume->GetMasterVolume(&volume);
    950     if (FAILED(hr))
    951     {
    952         available = false;
    953     }
    954     available = true;
    955 
    956     SAFE_RELEASE(pManager);
    957     SAFE_RELEASE(pVolume);
    958 
    959     return 0;
    960 
    961 Exit:
    962     _TraceCOMError(hr);
    963     SAFE_RELEASE(pManager);
    964     SAFE_RELEASE(pVolume);
    965     return -1;
    966 }
    967 
    968 // ----------------------------------------------------------------------------
    969 //  SetSpeakerVolume
    970 // ----------------------------------------------------------------------------
    971 
    972 int32_t AudioDeviceWindowsCore::SetSpeakerVolume(uint32_t volume)
    973 {
    974 
    975     {
    976         CriticalSectionScoped lock(&_critSect);
    977 
    978         if (!_speakerIsInitialized)
    979         {
    980         return -1;
    981         }
    982 
    983         if (_ptrDeviceOut == NULL)
    984         {
    985             return -1;
    986         }
    987     }
    988 
    989     if (volume < (uint32_t)MIN_CORE_SPEAKER_VOLUME ||
    990         volume > (uint32_t)MAX_CORE_SPEAKER_VOLUME)
    991     {
    992         return -1;
    993     }
    994 
    995     HRESULT hr = S_OK;
    996 
    997     // scale input volume to valid range (0.0 to 1.0)
    998     const float fLevel = (float)volume/MAX_CORE_SPEAKER_VOLUME;
    999     _volumeMutex.Enter();
   1000     hr = _ptrRenderSimpleVolume->SetMasterVolume(fLevel,NULL);
   1001     _volumeMutex.Leave();
   1002     EXIT_ON_ERROR(hr);
   1003 
   1004     return 0;
   1005 
   1006 Exit:
   1007     _TraceCOMError(hr);
   1008     return -1;
   1009 }
   1010 
   1011 // ----------------------------------------------------------------------------
   1012 //  SpeakerVolume
   1013 // ----------------------------------------------------------------------------
   1014 
   1015 int32_t AudioDeviceWindowsCore::SpeakerVolume(uint32_t& volume) const
   1016 {
   1017 
   1018     {
   1019         CriticalSectionScoped lock(&_critSect);
   1020 
   1021         if (!_speakerIsInitialized)
   1022         {
   1023             return -1;
   1024         }
   1025 
   1026         if (_ptrDeviceOut == NULL)
   1027         {
   1028             return -1;
   1029         }
   1030     }
   1031 
   1032     HRESULT hr = S_OK;
   1033     float fLevel(0.0f);
   1034 
   1035     _volumeMutex.Enter();
   1036     hr = _ptrRenderSimpleVolume->GetMasterVolume(&fLevel);
   1037     _volumeMutex.Leave();
   1038     EXIT_ON_ERROR(hr);
   1039 
   1040     // scale input volume range [0.0,1.0] to valid output range
   1041     volume = static_cast<uint32_t> (fLevel*MAX_CORE_SPEAKER_VOLUME);
   1042 
   1043     return 0;
   1044 
   1045 Exit:
   1046     _TraceCOMError(hr);
   1047     return -1;
   1048 }
   1049 
   1050 // ----------------------------------------------------------------------------
   1051 //  SetWaveOutVolume
   1052 // ----------------------------------------------------------------------------
   1053 
   1054 int32_t AudioDeviceWindowsCore::SetWaveOutVolume(uint16_t volumeLeft, uint16_t volumeRight)
   1055 {
   1056     return -1;
   1057 }
   1058 
   1059 // ----------------------------------------------------------------------------
   1060 //  WaveOutVolume
   1061 // ----------------------------------------------------------------------------
   1062 
   1063 int32_t AudioDeviceWindowsCore::WaveOutVolume(uint16_t& volumeLeft, uint16_t& volumeRight) const
   1064 {
   1065     return -1;
   1066 }
   1067 
   1068 // ----------------------------------------------------------------------------
   1069 //  MaxSpeakerVolume
   1070 //
   1071 //  The internal range for Core Audio is 0.0 to 1.0, where 0.0 indicates
   1072 //  silence and 1.0 indicates full volume (no attenuation).
   1073 //  We add our (webrtc-internal) own max level to match the Wave API and
   1074 //  how it is used today in VoE.
   1075 // ----------------------------------------------------------------------------
   1076 
   1077 int32_t AudioDeviceWindowsCore::MaxSpeakerVolume(uint32_t& maxVolume) const
   1078 {
   1079 
   1080     if (!_speakerIsInitialized)
   1081     {
   1082         return -1;
   1083     }
   1084 
   1085     maxVolume = static_cast<uint32_t> (MAX_CORE_SPEAKER_VOLUME);
   1086 
   1087     return 0;
   1088 }
   1089 
   1090 // ----------------------------------------------------------------------------
   1091 //  MinSpeakerVolume
   1092 // ----------------------------------------------------------------------------
   1093 
   1094 int32_t AudioDeviceWindowsCore::MinSpeakerVolume(uint32_t& minVolume) const
   1095 {
   1096 
   1097     if (!_speakerIsInitialized)
   1098     {
   1099         return -1;
   1100     }
   1101 
   1102     minVolume = static_cast<uint32_t> (MIN_CORE_SPEAKER_VOLUME);
   1103 
   1104     return 0;
   1105 }
   1106 
   1107 // ----------------------------------------------------------------------------
   1108 //  SpeakerVolumeStepSize
   1109 // ----------------------------------------------------------------------------
   1110 
   1111 int32_t AudioDeviceWindowsCore::SpeakerVolumeStepSize(uint16_t& stepSize) const
   1112 {
   1113 
   1114     if (!_speakerIsInitialized)
   1115     {
   1116         return -1;
   1117     }
   1118 
   1119     stepSize = CORE_SPEAKER_VOLUME_STEP_SIZE;
   1120 
   1121     return 0;
   1122 }
   1123 
   1124 // ----------------------------------------------------------------------------
   1125 //  SpeakerMuteIsAvailable
   1126 // ----------------------------------------------------------------------------
   1127 
   1128 int32_t AudioDeviceWindowsCore::SpeakerMuteIsAvailable(bool& available)
   1129 {
   1130 
   1131     CriticalSectionScoped lock(&_critSect);
   1132 
   1133     if (_ptrDeviceOut == NULL)
   1134     {
   1135         return -1;
   1136     }
   1137 
   1138     HRESULT hr = S_OK;
   1139     IAudioEndpointVolume* pVolume = NULL;
   1140 
   1141     // Query the speaker system mute state.
   1142     hr = _ptrDeviceOut->Activate(__uuidof(IAudioEndpointVolume),
   1143         CLSCTX_ALL, NULL,  reinterpret_cast<void**>(&pVolume));
   1144     EXIT_ON_ERROR(hr);
   1145 
   1146     BOOL mute;
   1147     hr = pVolume->GetMute(&mute);
   1148     if (FAILED(hr))
   1149         available = false;
   1150     else
   1151         available = true;
   1152 
   1153     SAFE_RELEASE(pVolume);
   1154 
   1155     return 0;
   1156 
   1157 Exit:
   1158     _TraceCOMError(hr);
   1159     SAFE_RELEASE(pVolume);
   1160     return -1;
   1161 }
   1162 
   1163 // ----------------------------------------------------------------------------
   1164 //  SetSpeakerMute
   1165 // ----------------------------------------------------------------------------
   1166 
   1167 int32_t AudioDeviceWindowsCore::SetSpeakerMute(bool enable)
   1168 {
   1169 
   1170     CriticalSectionScoped lock(&_critSect);
   1171 
   1172     if (!_speakerIsInitialized)
   1173     {
   1174         return -1;
   1175     }
   1176 
   1177     if (_ptrDeviceOut == NULL)
   1178     {
   1179         return -1;
   1180     }
   1181 
   1182     HRESULT hr = S_OK;
   1183     IAudioEndpointVolume* pVolume = NULL;
   1184 
   1185     // Set the speaker system mute state.
   1186     hr = _ptrDeviceOut->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_ALL, NULL,  reinterpret_cast<void**>(&pVolume));
   1187     EXIT_ON_ERROR(hr);
   1188 
   1189     const BOOL mute(enable);
   1190     hr = pVolume->SetMute(mute, NULL);
   1191     EXIT_ON_ERROR(hr);
   1192 
   1193     SAFE_RELEASE(pVolume);
   1194 
   1195     return 0;
   1196 
   1197 Exit:
   1198     _TraceCOMError(hr);
   1199     SAFE_RELEASE(pVolume);
   1200     return -1;
   1201 }
   1202 
   1203 // ----------------------------------------------------------------------------
   1204 //  SpeakerMute
   1205 // ----------------------------------------------------------------------------
   1206 
   1207 int32_t AudioDeviceWindowsCore::SpeakerMute(bool& enabled) const
   1208 {
   1209 
   1210     if (!_speakerIsInitialized)
   1211     {
   1212         return -1;
   1213     }
   1214 
   1215     if (_ptrDeviceOut == NULL)
   1216     {
   1217         return -1;
   1218     }
   1219 
   1220     HRESULT hr = S_OK;
   1221     IAudioEndpointVolume* pVolume = NULL;
   1222 
   1223     // Query the speaker system mute state.
   1224     hr = _ptrDeviceOut->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_ALL, NULL,  reinterpret_cast<void**>(&pVolume));
   1225     EXIT_ON_ERROR(hr);
   1226 
   1227     BOOL mute;
   1228     hr = pVolume->GetMute(&mute);
   1229     EXIT_ON_ERROR(hr);
   1230 
   1231     enabled = (mute == TRUE) ? true : false;
   1232 
   1233     SAFE_RELEASE(pVolume);
   1234 
   1235     return 0;
   1236 
   1237 Exit:
   1238     _TraceCOMError(hr);
   1239     SAFE_RELEASE(pVolume);
   1240     return -1;
   1241 }
   1242 
   1243 // ----------------------------------------------------------------------------
   1244 //  MicrophoneMuteIsAvailable
   1245 // ----------------------------------------------------------------------------
   1246 
   1247 int32_t AudioDeviceWindowsCore::MicrophoneMuteIsAvailable(bool& available)
   1248 {
   1249 
   1250     CriticalSectionScoped lock(&_critSect);
   1251 
   1252     if (_ptrDeviceIn == NULL)
   1253     {
   1254         return -1;
   1255     }
   1256 
   1257     HRESULT hr = S_OK;
   1258     IAudioEndpointVolume* pVolume = NULL;
   1259 
   1260     // Query the microphone system mute state.
   1261     hr = _ptrDeviceIn->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_ALL, NULL,  reinterpret_cast<void**>(&pVolume));
   1262     EXIT_ON_ERROR(hr);
   1263 
   1264     BOOL mute;
   1265     hr = pVolume->GetMute(&mute);
   1266     if (FAILED(hr))
   1267         available = false;
   1268     else
   1269         available = true;
   1270 
   1271     SAFE_RELEASE(pVolume);
   1272     return 0;
   1273 
   1274 Exit:
   1275     _TraceCOMError(hr);
   1276     SAFE_RELEASE(pVolume);
   1277     return -1;
   1278 }
   1279 
   1280 // ----------------------------------------------------------------------------
   1281 //  SetMicrophoneMute
   1282 // ----------------------------------------------------------------------------
   1283 
   1284 int32_t AudioDeviceWindowsCore::SetMicrophoneMute(bool enable)
   1285 {
   1286 
   1287     if (!_microphoneIsInitialized)
   1288     {
   1289         return -1;
   1290     }
   1291 
   1292     if (_ptrDeviceIn == NULL)
   1293     {
   1294         return -1;
   1295     }
   1296 
   1297     HRESULT hr = S_OK;
   1298     IAudioEndpointVolume* pVolume = NULL;
   1299 
   1300     // Set the microphone system mute state.
   1301     hr = _ptrDeviceIn->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_ALL, NULL,  reinterpret_cast<void**>(&pVolume));
   1302     EXIT_ON_ERROR(hr);
   1303 
   1304     const BOOL mute(enable);
   1305     hr = pVolume->SetMute(mute, NULL);
   1306     EXIT_ON_ERROR(hr);
   1307 
   1308     SAFE_RELEASE(pVolume);
   1309     return 0;
   1310 
   1311 Exit:
   1312     _TraceCOMError(hr);
   1313     SAFE_RELEASE(pVolume);
   1314     return -1;
   1315 }
   1316 
   1317 // ----------------------------------------------------------------------------
   1318 //  MicrophoneMute
   1319 // ----------------------------------------------------------------------------
   1320 
   1321 int32_t AudioDeviceWindowsCore::MicrophoneMute(bool& enabled) const
   1322 {
   1323 
   1324     if (!_microphoneIsInitialized)
   1325     {
   1326         return -1;
   1327     }
   1328 
   1329     HRESULT hr = S_OK;
   1330     IAudioEndpointVolume* pVolume = NULL;
   1331 
   1332     // Query the microphone system mute state.
   1333     hr = _ptrDeviceIn->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_ALL, NULL,  reinterpret_cast<void**>(&pVolume));
   1334     EXIT_ON_ERROR(hr);
   1335 
   1336     BOOL mute;
   1337     hr = pVolume->GetMute(&mute);
   1338     EXIT_ON_ERROR(hr);
   1339 
   1340     enabled = (mute == TRUE) ? true : false;
   1341 
   1342     SAFE_RELEASE(pVolume);
   1343     return 0;
   1344 
   1345 Exit:
   1346     _TraceCOMError(hr);
   1347     SAFE_RELEASE(pVolume);
   1348     return -1;
   1349 }
   1350 
   1351 // ----------------------------------------------------------------------------
   1352 //  MicrophoneBoostIsAvailable
   1353 // ----------------------------------------------------------------------------
   1354 
   1355 int32_t AudioDeviceWindowsCore::MicrophoneBoostIsAvailable(bool& available)
   1356 {
   1357 
   1358     available = false;
   1359     return 0;
   1360 }
   1361 
   1362 // ----------------------------------------------------------------------------
   1363 //  SetMicrophoneBoost
   1364 // ----------------------------------------------------------------------------
   1365 
   1366 int32_t AudioDeviceWindowsCore::SetMicrophoneBoost(bool enable)
   1367 {
   1368 
   1369     if (!_microphoneIsInitialized)
   1370     {
   1371         return -1;
   1372     }
   1373 
   1374     return -1;
   1375 }
   1376 
   1377 // ----------------------------------------------------------------------------
   1378 //  MicrophoneBoost
   1379 // ----------------------------------------------------------------------------
   1380 
   1381 int32_t AudioDeviceWindowsCore::MicrophoneBoost(bool& enabled) const
   1382 {
   1383 
   1384     if (!_microphoneIsInitialized)
   1385     {
   1386         return -1;
   1387     }
   1388 
   1389     return -1;
   1390 }
   1391 
   1392 // ----------------------------------------------------------------------------
   1393 //  StereoRecordingIsAvailable
   1394 // ----------------------------------------------------------------------------
   1395 
   1396 int32_t AudioDeviceWindowsCore::StereoRecordingIsAvailable(bool& available)
   1397 {
   1398 
   1399     available = true;
   1400     return 0;
   1401 }
   1402 
   1403 // ----------------------------------------------------------------------------
   1404 //  SetStereoRecording
   1405 // ----------------------------------------------------------------------------
   1406 
   1407 int32_t AudioDeviceWindowsCore::SetStereoRecording(bool enable)
   1408 {
   1409 
   1410     CriticalSectionScoped lock(&_critSect);
   1411 
   1412     if (enable)
   1413     {
   1414         _recChannelsPrioList[0] = 2;    // try stereo first
   1415         _recChannelsPrioList[1] = 1;
   1416         _recChannels = 2;
   1417     }
   1418     else
   1419     {
   1420         _recChannelsPrioList[0] = 1;    // try mono first
   1421         _recChannelsPrioList[1] = 2;
   1422         _recChannels = 1;
   1423     }
   1424 
   1425     return 0;
   1426 }
   1427 
   1428 // ----------------------------------------------------------------------------
   1429 //  StereoRecording
   1430 // ----------------------------------------------------------------------------
   1431 
   1432 int32_t AudioDeviceWindowsCore::StereoRecording(bool& enabled) const
   1433 {
   1434 
   1435     if (_recChannels == 2)
   1436         enabled = true;
   1437     else
   1438         enabled = false;
   1439 
   1440     return 0;
   1441 }
   1442 
   1443 // ----------------------------------------------------------------------------
   1444 //  StereoPlayoutIsAvailable
   1445 // ----------------------------------------------------------------------------
   1446 
   1447 int32_t AudioDeviceWindowsCore::StereoPlayoutIsAvailable(bool& available)
   1448 {
   1449 
   1450     available = true;
   1451     return 0;
   1452 }
   1453 
   1454 // ----------------------------------------------------------------------------
   1455 //  SetStereoPlayout
   1456 // ----------------------------------------------------------------------------
   1457 
   1458 int32_t AudioDeviceWindowsCore::SetStereoPlayout(bool enable)
   1459 {
   1460 
   1461     CriticalSectionScoped lock(&_critSect);
   1462 
   1463     if (enable)
   1464     {
   1465         _playChannelsPrioList[0] = 2;    // try stereo first
   1466         _playChannelsPrioList[1] = 1;
   1467         _playChannels = 2;
   1468     }
   1469     else
   1470     {
   1471         _playChannelsPrioList[0] = 1;    // try mono first
   1472         _playChannelsPrioList[1] = 2;
   1473         _playChannels = 1;
   1474     }
   1475 
   1476     return 0;
   1477 }
   1478 
   1479 // ----------------------------------------------------------------------------
   1480 //  StereoPlayout
   1481 // ----------------------------------------------------------------------------
   1482 
   1483 int32_t AudioDeviceWindowsCore::StereoPlayout(bool& enabled) const
   1484 {
   1485 
   1486     if (_playChannels == 2)
   1487         enabled = true;
   1488     else
   1489         enabled = false;
   1490 
   1491     return 0;
   1492 }
   1493 
   1494 // ----------------------------------------------------------------------------
   1495 //  SetAGC
   1496 // ----------------------------------------------------------------------------
   1497 
   1498 int32_t AudioDeviceWindowsCore::SetAGC(bool enable)
   1499 {
   1500     CriticalSectionScoped lock(&_critSect);
   1501     _AGC = enable;
   1502     return 0;
   1503 }
   1504 
   1505 // ----------------------------------------------------------------------------
   1506 //  AGC
   1507 // ----------------------------------------------------------------------------
   1508 
   1509 bool AudioDeviceWindowsCore::AGC() const
   1510 {
   1511     CriticalSectionScoped lock(&_critSect);
   1512     return _AGC;
   1513 }
   1514 
   1515 // ----------------------------------------------------------------------------
   1516 //  MicrophoneVolumeIsAvailable
   1517 // ----------------------------------------------------------------------------
   1518 
   1519 int32_t AudioDeviceWindowsCore::MicrophoneVolumeIsAvailable(bool& available)
   1520 {
   1521 
   1522     CriticalSectionScoped lock(&_critSect);
   1523 
   1524     if (_ptrDeviceIn == NULL)
   1525     {
   1526         return -1;
   1527     }
   1528 
   1529     HRESULT hr = S_OK;
   1530     IAudioEndpointVolume* pVolume = NULL;
   1531 
   1532     hr = _ptrDeviceIn->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_ALL, NULL, reinterpret_cast<void**>(&pVolume));
   1533     EXIT_ON_ERROR(hr);
   1534 
   1535     float volume(0.0f);
   1536     hr = pVolume->GetMasterVolumeLevelScalar(&volume);
   1537     if (FAILED(hr))
   1538     {
   1539         available = false;
   1540     }
   1541     available = true;
   1542 
   1543     SAFE_RELEASE(pVolume);
   1544     return 0;
   1545 
   1546 Exit:
   1547     _TraceCOMError(hr);
   1548     SAFE_RELEASE(pVolume);
   1549     return -1;
   1550 }
   1551 
   1552 // ----------------------------------------------------------------------------
   1553 //  SetMicrophoneVolume
   1554 // ----------------------------------------------------------------------------
   1555 
   1556 int32_t AudioDeviceWindowsCore::SetMicrophoneVolume(uint32_t volume)
   1557 {
   1558     WEBRTC_TRACE(kTraceStream, kTraceAudioDevice, _id, "AudioDeviceWindowsCore::SetMicrophoneVolume(volume=%u)", volume);
   1559 
   1560     {
   1561         CriticalSectionScoped lock(&_critSect);
   1562 
   1563         if (!_microphoneIsInitialized)
   1564         {
   1565             return -1;
   1566         }
   1567 
   1568         if (_ptrDeviceIn == NULL)
   1569         {
   1570             return -1;
   1571         }
   1572     }
   1573 
   1574     if (volume < static_cast<uint32_t>(MIN_CORE_MICROPHONE_VOLUME) ||
   1575         volume > static_cast<uint32_t>(MAX_CORE_MICROPHONE_VOLUME))
   1576     {
   1577         return -1;
   1578     }
   1579 
   1580     HRESULT hr = S_OK;
   1581     // scale input volume to valid range (0.0 to 1.0)
   1582     const float fLevel = static_cast<float>(volume)/MAX_CORE_MICROPHONE_VOLUME;
   1583     _volumeMutex.Enter();
   1584     _ptrCaptureVolume->SetMasterVolumeLevelScalar(fLevel, NULL);
   1585     _volumeMutex.Leave();
   1586     EXIT_ON_ERROR(hr);
   1587 
   1588     return 0;
   1589 
   1590 Exit:
   1591     _TraceCOMError(hr);
   1592     return -1;
   1593 }
   1594 
   1595 // ----------------------------------------------------------------------------
   1596 //  MicrophoneVolume
   1597 // ----------------------------------------------------------------------------
   1598 
   1599 int32_t AudioDeviceWindowsCore::MicrophoneVolume(uint32_t& volume) const
   1600 {
   1601     {
   1602         CriticalSectionScoped lock(&_critSect);
   1603 
   1604         if (!_microphoneIsInitialized)
   1605         {
   1606             return -1;
   1607         }
   1608 
   1609         if (_ptrDeviceIn == NULL)
   1610         {
   1611             return -1;
   1612         }
   1613     }
   1614 
   1615     HRESULT hr = S_OK;
   1616     float fLevel(0.0f);
   1617     volume = 0;
   1618     _volumeMutex.Enter();
   1619     hr = _ptrCaptureVolume->GetMasterVolumeLevelScalar(&fLevel);
   1620     _volumeMutex.Leave();
   1621     EXIT_ON_ERROR(hr);
   1622 
   1623     // scale input volume range [0.0,1.0] to valid output range
   1624     volume = static_cast<uint32_t> (fLevel*MAX_CORE_MICROPHONE_VOLUME);
   1625 
   1626     return 0;
   1627 
   1628 Exit:
   1629     _TraceCOMError(hr);
   1630     return -1;
   1631 }
   1632 
   1633 // ----------------------------------------------------------------------------
   1634 //  MaxMicrophoneVolume
   1635 //
   1636 //  The internal range for Core Audio is 0.0 to 1.0, where 0.0 indicates
   1637 //  silence and 1.0 indicates full volume (no attenuation).
   1638 //  We add our (webrtc-internal) own max level to match the Wave API and
   1639 //  how it is used today in VoE.
   1640 // ----------------------------------------------------------------------------
   1641 
   1642 int32_t AudioDeviceWindowsCore::MaxMicrophoneVolume(uint32_t& maxVolume) const
   1643 {
   1644     WEBRTC_TRACE(kTraceStream, kTraceAudioDevice, _id, "%s", __FUNCTION__);
   1645 
   1646     if (!_microphoneIsInitialized)
   1647     {
   1648         return -1;
   1649     }
   1650 
   1651     maxVolume = static_cast<uint32_t> (MAX_CORE_MICROPHONE_VOLUME);
   1652 
   1653     return 0;
   1654 }
   1655 
   1656 // ----------------------------------------------------------------------------
   1657 //  MinMicrophoneVolume
   1658 // ----------------------------------------------------------------------------
   1659 
   1660 int32_t AudioDeviceWindowsCore::MinMicrophoneVolume(uint32_t& minVolume) const
   1661 {
   1662 
   1663     if (!_microphoneIsInitialized)
   1664     {
   1665         return -1;
   1666     }
   1667 
   1668     minVolume = static_cast<uint32_t> (MIN_CORE_MICROPHONE_VOLUME);
   1669 
   1670     return 0;
   1671 }
   1672 
   1673 // ----------------------------------------------------------------------------
   1674 //  MicrophoneVolumeStepSize
   1675 // ----------------------------------------------------------------------------
   1676 
   1677 int32_t AudioDeviceWindowsCore::MicrophoneVolumeStepSize(uint16_t& stepSize) const
   1678 {
   1679 
   1680     if (!_microphoneIsInitialized)
   1681     {
   1682         return -1;
   1683     }
   1684 
   1685     stepSize = CORE_MICROPHONE_VOLUME_STEP_SIZE;
   1686 
   1687     return 0;
   1688 }
   1689 
   1690 // ----------------------------------------------------------------------------
   1691 //  PlayoutDevices
   1692 // ----------------------------------------------------------------------------
   1693 
   1694 int16_t AudioDeviceWindowsCore::PlayoutDevices()
   1695 {
   1696 
   1697     CriticalSectionScoped lock(&_critSect);
   1698 
   1699     if (_RefreshDeviceList(eRender) != -1)
   1700     {
   1701         return (_DeviceListCount(eRender));
   1702     }
   1703 
   1704     return -1;
   1705 }
   1706 
   1707 // ----------------------------------------------------------------------------
   1708 //  SetPlayoutDevice I (II)
   1709 // ----------------------------------------------------------------------------
   1710 
   1711 int32_t AudioDeviceWindowsCore::SetPlayoutDevice(uint16_t index)
   1712 {
   1713 
   1714     if (_playIsInitialized)
   1715     {
   1716         return -1;
   1717     }
   1718 
   1719     // Get current number of available rendering endpoint devices and refresh the rendering collection.
   1720     UINT nDevices = PlayoutDevices();
   1721 
   1722     if (index < 0 || index > (nDevices-1))
   1723     {
   1724         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "device index is out of range [0,%u]", (nDevices-1));
   1725         return -1;
   1726     }
   1727 
   1728     CriticalSectionScoped lock(&_critSect);
   1729 
   1730     HRESULT hr(S_OK);
   1731 
   1732     assert(_ptrRenderCollection != NULL);
   1733 
   1734     //  Select an endpoint rendering device given the specified index
   1735     SAFE_RELEASE(_ptrDeviceOut);
   1736     hr = _ptrRenderCollection->Item(
   1737                                  index,
   1738                                  &_ptrDeviceOut);
   1739     if (FAILED(hr))
   1740     {
   1741         _TraceCOMError(hr);
   1742         SAFE_RELEASE(_ptrDeviceOut);
   1743         return -1;
   1744     }
   1745 
   1746     WCHAR szDeviceName[MAX_PATH];
   1747     const int bufferLen = sizeof(szDeviceName)/sizeof(szDeviceName)[0];
   1748 
   1749     // Get the endpoint device's friendly-name
   1750     if (_GetDeviceName(_ptrDeviceOut, szDeviceName, bufferLen) == 0)
   1751     {
   1752         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "friendly name: \"%S\"", szDeviceName);
   1753     }
   1754 
   1755     _usingOutputDeviceIndex = true;
   1756     _outputDeviceIndex = index;
   1757 
   1758     return 0;
   1759 }
   1760 
   1761 // ----------------------------------------------------------------------------
   1762 //  SetPlayoutDevice II (II)
   1763 // ----------------------------------------------------------------------------
   1764 
   1765 int32_t AudioDeviceWindowsCore::SetPlayoutDevice(AudioDeviceModule::WindowsDeviceType device)
   1766 {
   1767     if (_playIsInitialized)
   1768     {
   1769         return -1;
   1770     }
   1771 
   1772     ERole role(eCommunications);
   1773 
   1774     if (device == AudioDeviceModule::kDefaultDevice)
   1775     {
   1776         role = eConsole;
   1777     }
   1778     else if (device == AudioDeviceModule::kDefaultCommunicationDevice)
   1779     {
   1780         role = eCommunications;
   1781     }
   1782 
   1783     CriticalSectionScoped lock(&_critSect);
   1784 
   1785     // Refresh the list of rendering endpoint devices
   1786     _RefreshDeviceList(eRender);
   1787 
   1788     HRESULT hr(S_OK);
   1789 
   1790     assert(_ptrEnumerator != NULL);
   1791 
   1792     //  Select an endpoint rendering device given the specified role
   1793     SAFE_RELEASE(_ptrDeviceOut);
   1794     hr = _ptrEnumerator->GetDefaultAudioEndpoint(
   1795                            eRender,
   1796                            role,
   1797                            &_ptrDeviceOut);
   1798     if (FAILED(hr))
   1799     {
   1800         _TraceCOMError(hr);
   1801         SAFE_RELEASE(_ptrDeviceOut);
   1802         return -1;
   1803     }
   1804 
   1805     WCHAR szDeviceName[MAX_PATH];
   1806     const int bufferLen = sizeof(szDeviceName)/sizeof(szDeviceName)[0];
   1807 
   1808     // Get the endpoint device's friendly-name
   1809     if (_GetDeviceName(_ptrDeviceOut, szDeviceName, bufferLen) == 0)
   1810     {
   1811         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "friendly name: \"%S\"", szDeviceName);
   1812     }
   1813 
   1814     _usingOutputDeviceIndex = false;
   1815     _outputDevice = device;
   1816 
   1817     return 0;
   1818 }
   1819 
   1820 // ----------------------------------------------------------------------------
   1821 //  PlayoutDeviceName
   1822 // ----------------------------------------------------------------------------
   1823 
   1824 int32_t AudioDeviceWindowsCore::PlayoutDeviceName(
   1825     uint16_t index,
   1826     char name[kAdmMaxDeviceNameSize],
   1827     char guid[kAdmMaxGuidSize])
   1828 {
   1829 
   1830     bool defaultCommunicationDevice(false);
   1831     const int16_t nDevices(PlayoutDevices());  // also updates the list of devices
   1832 
   1833     // Special fix for the case when the user selects '-1' as index (<=> Default Communication Device)
   1834     if (index == (uint16_t)(-1))
   1835     {
   1836         defaultCommunicationDevice = true;
   1837         index = 0;
   1838         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "Default Communication endpoint device will be used");
   1839     }
   1840 
   1841     if ((index > (nDevices-1)) || (name == NULL))
   1842     {
   1843         return -1;
   1844     }
   1845 
   1846     memset(name, 0, kAdmMaxDeviceNameSize);
   1847 
   1848     if (guid != NULL)
   1849     {
   1850         memset(guid, 0, kAdmMaxGuidSize);
   1851     }
   1852 
   1853     CriticalSectionScoped lock(&_critSect);
   1854 
   1855     int32_t ret(-1);
   1856     WCHAR szDeviceName[MAX_PATH];
   1857     const int bufferLen = sizeof(szDeviceName)/sizeof(szDeviceName)[0];
   1858 
   1859     // Get the endpoint device's friendly-name
   1860     if (defaultCommunicationDevice)
   1861     {
   1862         ret = _GetDefaultDeviceName(eRender, eCommunications, szDeviceName, bufferLen);
   1863     }
   1864     else
   1865     {
   1866         ret = _GetListDeviceName(eRender, index, szDeviceName, bufferLen);
   1867     }
   1868 
   1869     if (ret == 0)
   1870     {
   1871         // Convert the endpoint device's friendly-name to UTF-8
   1872         if (WideCharToMultiByte(CP_UTF8, 0, szDeviceName, -1, name, kAdmMaxDeviceNameSize, NULL, NULL) == 0)
   1873         {
   1874             WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "WideCharToMultiByte(CP_UTF8) failed with error code %d", GetLastError());
   1875         }
   1876     }
   1877 
   1878     // Get the endpoint ID string (uniquely identifies the device among all audio endpoint devices)
   1879     if (defaultCommunicationDevice)
   1880     {
   1881         ret = _GetDefaultDeviceID(eRender, eCommunications, szDeviceName, bufferLen);
   1882     }
   1883     else
   1884     {
   1885         ret = _GetListDeviceID(eRender, index, szDeviceName, bufferLen);
   1886     }
   1887 
   1888     if (guid != NULL && ret == 0)
   1889     {
   1890         // Convert the endpoint device's ID string to UTF-8
   1891         if (WideCharToMultiByte(CP_UTF8, 0, szDeviceName, -1, guid, kAdmMaxGuidSize, NULL, NULL) == 0)
   1892         {
   1893             WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "WideCharToMultiByte(CP_UTF8) failed with error code %d", GetLastError());
   1894         }
   1895     }
   1896 
   1897     return ret;
   1898 }
   1899 
   1900 // ----------------------------------------------------------------------------
   1901 //  RecordingDeviceName
   1902 // ----------------------------------------------------------------------------
   1903 
   1904 int32_t AudioDeviceWindowsCore::RecordingDeviceName(
   1905     uint16_t index,
   1906     char name[kAdmMaxDeviceNameSize],
   1907     char guid[kAdmMaxGuidSize])
   1908 {
   1909 
   1910     bool defaultCommunicationDevice(false);
   1911     const int16_t nDevices(RecordingDevices());  // also updates the list of devices
   1912 
   1913     // Special fix for the case when the user selects '-1' as index (<=> Default Communication Device)
   1914     if (index == (uint16_t)(-1))
   1915     {
   1916         defaultCommunicationDevice = true;
   1917         index = 0;
   1918         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "Default Communication endpoint device will be used");
   1919     }
   1920 
   1921     if ((index > (nDevices-1)) || (name == NULL))
   1922     {
   1923         return -1;
   1924     }
   1925 
   1926     memset(name, 0, kAdmMaxDeviceNameSize);
   1927 
   1928     if (guid != NULL)
   1929     {
   1930         memset(guid, 0, kAdmMaxGuidSize);
   1931     }
   1932 
   1933     CriticalSectionScoped lock(&_critSect);
   1934 
   1935     int32_t ret(-1);
   1936     WCHAR szDeviceName[MAX_PATH];
   1937     const int bufferLen = sizeof(szDeviceName)/sizeof(szDeviceName)[0];
   1938 
   1939     // Get the endpoint device's friendly-name
   1940     if (defaultCommunicationDevice)
   1941     {
   1942         ret = _GetDefaultDeviceName(eCapture, eCommunications, szDeviceName, bufferLen);
   1943     }
   1944     else
   1945     {
   1946         ret = _GetListDeviceName(eCapture, index, szDeviceName, bufferLen);
   1947     }
   1948 
   1949     if (ret == 0)
   1950     {
   1951         // Convert the endpoint device's friendly-name to UTF-8
   1952         if (WideCharToMultiByte(CP_UTF8, 0, szDeviceName, -1, name, kAdmMaxDeviceNameSize, NULL, NULL) == 0)
   1953         {
   1954             WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "WideCharToMultiByte(CP_UTF8) failed with error code %d", GetLastError());
   1955         }
   1956     }
   1957 
   1958     // Get the endpoint ID string (uniquely identifies the device among all audio endpoint devices)
   1959     if (defaultCommunicationDevice)
   1960     {
   1961         ret = _GetDefaultDeviceID(eCapture, eCommunications, szDeviceName, bufferLen);
   1962     }
   1963     else
   1964     {
   1965         ret = _GetListDeviceID(eCapture, index, szDeviceName, bufferLen);
   1966     }
   1967 
   1968     if (guid != NULL && ret == 0)
   1969     {
   1970         // Convert the endpoint device's ID string to UTF-8
   1971         if (WideCharToMultiByte(CP_UTF8, 0, szDeviceName, -1, guid, kAdmMaxGuidSize, NULL, NULL) == 0)
   1972         {
   1973             WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "WideCharToMultiByte(CP_UTF8) failed with error code %d", GetLastError());
   1974         }
   1975     }
   1976 
   1977     return ret;
   1978 }
   1979 
   1980 // ----------------------------------------------------------------------------
   1981 //  RecordingDevices
   1982 // ----------------------------------------------------------------------------
   1983 
   1984 int16_t AudioDeviceWindowsCore::RecordingDevices()
   1985 {
   1986 
   1987     CriticalSectionScoped lock(&_critSect);
   1988 
   1989     if (_RefreshDeviceList(eCapture) != -1)
   1990     {
   1991         return (_DeviceListCount(eCapture));
   1992     }
   1993 
   1994     return -1;
   1995 }
   1996 
   1997 // ----------------------------------------------------------------------------
   1998 //  SetRecordingDevice I (II)
   1999 // ----------------------------------------------------------------------------
   2000 
   2001 int32_t AudioDeviceWindowsCore::SetRecordingDevice(uint16_t index)
   2002 {
   2003 
   2004     if (_recIsInitialized)
   2005     {
   2006         return -1;
   2007     }
   2008 
   2009     // Get current number of available capture endpoint devices and refresh the capture collection.
   2010     UINT nDevices = RecordingDevices();
   2011 
   2012     if (index < 0 || index > (nDevices-1))
   2013     {
   2014         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "device index is out of range [0,%u]", (nDevices-1));
   2015         return -1;
   2016     }
   2017 
   2018     CriticalSectionScoped lock(&_critSect);
   2019 
   2020     HRESULT hr(S_OK);
   2021 
   2022     assert(_ptrCaptureCollection != NULL);
   2023 
   2024     // Select an endpoint capture device given the specified index
   2025     SAFE_RELEASE(_ptrDeviceIn);
   2026     hr = _ptrCaptureCollection->Item(
   2027                                  index,
   2028                                  &_ptrDeviceIn);
   2029     if (FAILED(hr))
   2030     {
   2031         _TraceCOMError(hr);
   2032         SAFE_RELEASE(_ptrDeviceIn);
   2033         return -1;
   2034     }
   2035 
   2036     WCHAR szDeviceName[MAX_PATH];
   2037     const int bufferLen = sizeof(szDeviceName)/sizeof(szDeviceName)[0];
   2038 
   2039     // Get the endpoint device's friendly-name
   2040     if (_GetDeviceName(_ptrDeviceIn, szDeviceName, bufferLen) == 0)
   2041     {
   2042         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "friendly name: \"%S\"", szDeviceName);
   2043     }
   2044 
   2045     _usingInputDeviceIndex = true;
   2046     _inputDeviceIndex = index;
   2047 
   2048     return 0;
   2049 }
   2050 
   2051 // ----------------------------------------------------------------------------
   2052 //  SetRecordingDevice II (II)
   2053 // ----------------------------------------------------------------------------
   2054 
   2055 int32_t AudioDeviceWindowsCore::SetRecordingDevice(AudioDeviceModule::WindowsDeviceType device)
   2056 {
   2057     if (_recIsInitialized)
   2058     {
   2059         return -1;
   2060     }
   2061 
   2062     ERole role(eCommunications);
   2063 
   2064     if (device == AudioDeviceModule::kDefaultDevice)
   2065     {
   2066         role = eConsole;
   2067     }
   2068     else if (device == AudioDeviceModule::kDefaultCommunicationDevice)
   2069     {
   2070         role = eCommunications;
   2071     }
   2072 
   2073     CriticalSectionScoped lock(&_critSect);
   2074 
   2075     // Refresh the list of capture endpoint devices
   2076     _RefreshDeviceList(eCapture);
   2077 
   2078     HRESULT hr(S_OK);
   2079 
   2080     assert(_ptrEnumerator != NULL);
   2081 
   2082     //  Select an endpoint capture device given the specified role
   2083     SAFE_RELEASE(_ptrDeviceIn);
   2084     hr = _ptrEnumerator->GetDefaultAudioEndpoint(
   2085                            eCapture,
   2086                            role,
   2087                            &_ptrDeviceIn);
   2088     if (FAILED(hr))
   2089     {
   2090         _TraceCOMError(hr);
   2091         SAFE_RELEASE(_ptrDeviceIn);
   2092         return -1;
   2093     }
   2094 
   2095     WCHAR szDeviceName[MAX_PATH];
   2096     const int bufferLen = sizeof(szDeviceName)/sizeof(szDeviceName)[0];
   2097 
   2098     // Get the endpoint device's friendly-name
   2099     if (_GetDeviceName(_ptrDeviceIn, szDeviceName, bufferLen) == 0)
   2100     {
   2101         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "friendly name: \"%S\"", szDeviceName);
   2102     }
   2103 
   2104     _usingInputDeviceIndex = false;
   2105     _inputDevice = device;
   2106 
   2107     return 0;
   2108 }
   2109 
   2110 // ----------------------------------------------------------------------------
   2111 //  PlayoutIsAvailable
   2112 // ----------------------------------------------------------------------------
   2113 
   2114 int32_t AudioDeviceWindowsCore::PlayoutIsAvailable(bool& available)
   2115 {
   2116 
   2117     available = false;
   2118 
   2119     // Try to initialize the playout side
   2120     int32_t res = InitPlayout();
   2121 
   2122     // Cancel effect of initialization
   2123     StopPlayout();
   2124 
   2125     if (res != -1)
   2126     {
   2127         available = true;
   2128     }
   2129 
   2130     return 0;
   2131 }
   2132 
   2133 // ----------------------------------------------------------------------------
   2134 //  RecordingIsAvailable
   2135 // ----------------------------------------------------------------------------
   2136 
   2137 int32_t AudioDeviceWindowsCore::RecordingIsAvailable(bool& available)
   2138 {
   2139 
   2140     available = false;
   2141 
   2142     // Try to initialize the recording side
   2143     int32_t res = InitRecording();
   2144 
   2145     // Cancel effect of initialization
   2146     StopRecording();
   2147 
   2148     if (res != -1)
   2149     {
   2150         available = true;
   2151     }
   2152 
   2153     return 0;
   2154 }
   2155 
   2156 // ----------------------------------------------------------------------------
   2157 //  InitPlayout
   2158 // ----------------------------------------------------------------------------
   2159 
   2160 int32_t AudioDeviceWindowsCore::InitPlayout()
   2161 {
   2162 
   2163     CriticalSectionScoped lock(&_critSect);
   2164 
   2165     if (_playing)
   2166     {
   2167         return -1;
   2168     }
   2169 
   2170     if (_playIsInitialized)
   2171     {
   2172         return 0;
   2173     }
   2174 
   2175     if (_ptrDeviceOut == NULL)
   2176     {
   2177         return -1;
   2178     }
   2179 
   2180     // Initialize the speaker (devices might have been added or removed)
   2181     if (InitSpeaker() == -1)
   2182     {
   2183         WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "InitSpeaker() failed");
   2184     }
   2185 
   2186     // Ensure that the updated rendering endpoint device is valid
   2187     if (_ptrDeviceOut == NULL)
   2188     {
   2189         return -1;
   2190     }
   2191 
   2192     if (_builtInAecEnabled && _recIsInitialized)
   2193     {
   2194         // Ensure the correct render device is configured in case
   2195         // InitRecording() was called before InitPlayout().
   2196         if (SetDMOProperties() == -1)
   2197         {
   2198             return -1;
   2199         }
   2200     }
   2201 
   2202     HRESULT hr = S_OK;
   2203     WAVEFORMATEX* pWfxOut = NULL;
   2204     WAVEFORMATEX Wfx;
   2205     WAVEFORMATEX* pWfxClosestMatch = NULL;
   2206 
   2207     // Create COM object with IAudioClient interface.
   2208     SAFE_RELEASE(_ptrClientOut);
   2209     hr = _ptrDeviceOut->Activate(
   2210                           __uuidof(IAudioClient),
   2211                           CLSCTX_ALL,
   2212                           NULL,
   2213                           (void**)&_ptrClientOut);
   2214     EXIT_ON_ERROR(hr);
   2215 
   2216     // Retrieve the stream format that the audio engine uses for its internal
   2217     // processing (mixing) of shared-mode streams.
   2218     hr = _ptrClientOut->GetMixFormat(&pWfxOut);
   2219     if (SUCCEEDED(hr))
   2220     {
   2221         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "Audio Engine's current rendering mix format:");
   2222         // format type
   2223         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "wFormatTag     : 0x%X (%u)", pWfxOut->wFormatTag, pWfxOut->wFormatTag);
   2224         // number of channels (i.e. mono, stereo...)
   2225         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "nChannels      : %d", pWfxOut->nChannels);
   2226         // sample rate
   2227         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "nSamplesPerSec : %d", pWfxOut->nSamplesPerSec);
   2228         // for buffer estimation
   2229         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "nAvgBytesPerSec: %d", pWfxOut->nAvgBytesPerSec);
   2230         // block size of data
   2231         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "nBlockAlign    : %d", pWfxOut->nBlockAlign);
   2232         // number of bits per sample of mono data
   2233         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "wBitsPerSample : %d", pWfxOut->wBitsPerSample);
   2234         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "cbSize         : %d", pWfxOut->cbSize);
   2235     }
   2236 
   2237     // Set wave format
   2238     Wfx.wFormatTag = WAVE_FORMAT_PCM;
   2239     Wfx.wBitsPerSample = 16;
   2240     Wfx.cbSize = 0;
   2241 
   2242     const int freqs[] = {48000, 44100, 16000, 96000, 32000, 8000};
   2243     hr = S_FALSE;
   2244 
   2245     // Iterate over frequencies and channels, in order of priority
   2246     for (int freq = 0; freq < sizeof(freqs)/sizeof(freqs[0]); freq++)
   2247     {
   2248         for (int chan = 0; chan < sizeof(_playChannelsPrioList)/sizeof(_playChannelsPrioList[0]); chan++)
   2249         {
   2250             Wfx.nChannels = _playChannelsPrioList[chan];
   2251             Wfx.nSamplesPerSec = freqs[freq];
   2252             Wfx.nBlockAlign = Wfx.nChannels * Wfx.wBitsPerSample / 8;
   2253             Wfx.nAvgBytesPerSec = Wfx.nSamplesPerSec * Wfx.nBlockAlign;
   2254             // If the method succeeds and the audio endpoint device supports the specified stream format,
   2255             // it returns S_OK. If the method succeeds and provides a closest match to the specified format,
   2256             // it returns S_FALSE.
   2257             hr = _ptrClientOut->IsFormatSupported(
   2258                                   AUDCLNT_SHAREMODE_SHARED,
   2259                                   &Wfx,
   2260                                   &pWfxClosestMatch);
   2261             if (hr == S_OK)
   2262             {
   2263                 break;
   2264             }
   2265             else
   2266             {
   2267                 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "nChannels=%d, nSamplesPerSec=%d is not supported",
   2268                     Wfx.nChannels, Wfx.nSamplesPerSec);
   2269             }
   2270         }
   2271         if (hr == S_OK)
   2272             break;
   2273     }
   2274 
   2275     // TODO(andrew): what happens in the event of failure in the above loop?
   2276     //   Is _ptrClientOut->Initialize expected to fail?
   2277     //   Same in InitRecording().
   2278     if (hr == S_OK)
   2279     {
   2280         _playAudioFrameSize = Wfx.nBlockAlign;
   2281         _playBlockSize = Wfx.nSamplesPerSec/100;
   2282         _playSampleRate = Wfx.nSamplesPerSec;
   2283         _devicePlaySampleRate = Wfx.nSamplesPerSec; // The device itself continues to run at 44.1 kHz.
   2284         _devicePlayBlockSize = Wfx.nSamplesPerSec/100;
   2285         _playChannels = Wfx.nChannels;
   2286 
   2287         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "VoE selected this rendering format:");
   2288         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "wFormatTag         : 0x%X (%u)", Wfx.wFormatTag, Wfx.wFormatTag);
   2289         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "nChannels          : %d", Wfx.nChannels);
   2290         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "nSamplesPerSec     : %d", Wfx.nSamplesPerSec);
   2291         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "nAvgBytesPerSec    : %d", Wfx.nAvgBytesPerSec);
   2292         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "nBlockAlign        : %d", Wfx.nBlockAlign);
   2293         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "wBitsPerSample     : %d", Wfx.wBitsPerSample);
   2294         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "cbSize             : %d", Wfx.cbSize);
   2295         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "Additional settings:");
   2296         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "_playAudioFrameSize: %d", _playAudioFrameSize);
   2297         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "_playBlockSize     : %d", _playBlockSize);
   2298         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "_playChannels      : %d", _playChannels);
   2299     }
   2300 
   2301     // Create a rendering stream.
   2302     //
   2303     // ****************************************************************************
   2304     // For a shared-mode stream that uses event-driven buffering, the caller must
   2305     // set both hnsPeriodicity and hnsBufferDuration to 0. The Initialize method
   2306     // determines how large a buffer to allocate based on the scheduling period
   2307     // of the audio engine. Although the client's buffer processing thread is
   2308     // event driven, the basic buffer management process, as described previously,
   2309     // is unaltered.
   2310     // Each time the thread awakens, it should call IAudioClient::GetCurrentPadding
   2311     // to determine how much data to write to a rendering buffer or read from a capture
   2312     // buffer. In contrast to the two buffers that the Initialize method allocates
   2313     // for an exclusive-mode stream that uses event-driven buffering, a shared-mode
   2314     // stream requires a single buffer.
   2315     // ****************************************************************************
   2316     //
   2317     REFERENCE_TIME hnsBufferDuration = 0;  // ask for minimum buffer size (default)
   2318     if (_devicePlaySampleRate == 44100)
   2319     {
   2320         // Ask for a larger buffer size (30ms) when using 44.1kHz as render rate.
   2321         // There seems to be a larger risk of underruns for 44.1 compared
   2322         // with the default rate (48kHz). When using default, we set the requested
   2323         // buffer duration to 0, which sets the buffer to the minimum size
   2324         // required by the engine thread. The actual buffer size can then be
   2325         // read by GetBufferSize() and it is 20ms on most machines.
   2326         hnsBufferDuration = 30*10000;
   2327     }
   2328     hr = _ptrClientOut->Initialize(
   2329                           AUDCLNT_SHAREMODE_SHARED,             // share Audio Engine with other applications
   2330                           AUDCLNT_STREAMFLAGS_EVENTCALLBACK,    // processing of the audio buffer by the client will be event driven
   2331                           hnsBufferDuration,                    // requested buffer capacity as a time value (in 100-nanosecond units)
   2332                           0,                                    // periodicity
   2333                           &Wfx,                                 // selected wave format
   2334                           NULL);                                // session GUID
   2335 
   2336     if (FAILED(hr))
   2337     {
   2338         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "IAudioClient::Initialize() failed:");
   2339         if (pWfxClosestMatch != NULL)
   2340         {
   2341             WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "closest mix format: #channels=%d, samples/sec=%d, bits/sample=%d",
   2342                 pWfxClosestMatch->nChannels, pWfxClosestMatch->nSamplesPerSec, pWfxClosestMatch->wBitsPerSample);
   2343         }
   2344         else
   2345         {
   2346             WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "no format suggested");
   2347         }
   2348     }
   2349     EXIT_ON_ERROR(hr);
   2350 
   2351     if (_ptrAudioBuffer)
   2352     {
   2353         // Update the audio buffer with the selected parameters
   2354         _ptrAudioBuffer->SetPlayoutSampleRate(_playSampleRate);
   2355         _ptrAudioBuffer->SetPlayoutChannels((uint8_t)_playChannels);
   2356     }
   2357     else
   2358     {
   2359         // We can enter this state during CoreAudioIsSupported() when no AudioDeviceImplementation
   2360         // has been created, hence the AudioDeviceBuffer does not exist.
   2361         // It is OK to end up here since we don't initiate any media in CoreAudioIsSupported().
   2362         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "AudioDeviceBuffer must be attached before streaming can start");
   2363     }
   2364 
   2365     // Get the actual size of the shared (endpoint buffer).
   2366     // Typical value is 960 audio frames <=> 20ms @ 48kHz sample rate.
   2367     UINT bufferFrameCount(0);
   2368     hr = _ptrClientOut->GetBufferSize(
   2369                           &bufferFrameCount);
   2370     if (SUCCEEDED(hr))
   2371     {
   2372         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "IAudioClient::GetBufferSize() => %u (<=> %u bytes)",
   2373             bufferFrameCount, bufferFrameCount*_playAudioFrameSize);
   2374     }
   2375 
   2376     // Set the event handle that the system signals when an audio buffer is ready
   2377     // to be processed by the client.
   2378     hr = _ptrClientOut->SetEventHandle(
   2379                           _hRenderSamplesReadyEvent);
   2380     EXIT_ON_ERROR(hr);
   2381 
   2382     // Get an IAudioRenderClient interface.
   2383     SAFE_RELEASE(_ptrRenderClient);
   2384     hr = _ptrClientOut->GetService(
   2385                           __uuidof(IAudioRenderClient),
   2386                           (void**)&_ptrRenderClient);
   2387     EXIT_ON_ERROR(hr);
   2388 
   2389     // Mark playout side as initialized
   2390     _playIsInitialized = true;
   2391 
   2392     CoTaskMemFree(pWfxOut);
   2393     CoTaskMemFree(pWfxClosestMatch);
   2394 
   2395     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "render side is now initialized");
   2396     return 0;
   2397 
   2398 Exit:
   2399     _TraceCOMError(hr);
   2400     CoTaskMemFree(pWfxOut);
   2401     CoTaskMemFree(pWfxClosestMatch);
   2402     SAFE_RELEASE(_ptrClientOut);
   2403     SAFE_RELEASE(_ptrRenderClient);
   2404     return -1;
   2405 }
   2406 
   2407 // Capture initialization when the built-in AEC DirectX Media Object (DMO) is
   2408 // used. Called from InitRecording(), most of which is skipped over. The DMO
   2409 // handles device initialization itself.
   2410 // Reference: http://msdn.microsoft.com/en-us/library/ff819492(v=vs.85).aspx
   2411 int32_t AudioDeviceWindowsCore::InitRecordingDMO()
   2412 {
   2413     assert(_builtInAecEnabled);
   2414     assert(_dmo != NULL);
   2415 
   2416     if (SetDMOProperties() == -1)
   2417     {
   2418         return -1;
   2419     }
   2420 
   2421     DMO_MEDIA_TYPE mt = {0};
   2422     HRESULT hr = MoInitMediaType(&mt, sizeof(WAVEFORMATEX));
   2423     if (FAILED(hr))
   2424     {
   2425         MoFreeMediaType(&mt);
   2426         _TraceCOMError(hr);
   2427         return -1;
   2428     }
   2429     mt.majortype = MEDIATYPE_Audio;
   2430     mt.subtype = MEDIASUBTYPE_PCM;
   2431     mt.formattype = FORMAT_WaveFormatEx;
   2432 
   2433     // Supported formats
   2434     // nChannels: 1 (in AEC-only mode)
   2435     // nSamplesPerSec: 8000, 11025, 16000, 22050
   2436     // wBitsPerSample: 16
   2437     WAVEFORMATEX* ptrWav = reinterpret_cast<WAVEFORMATEX*>(mt.pbFormat);
   2438     ptrWav->wFormatTag = WAVE_FORMAT_PCM;
   2439     ptrWav->nChannels = 1;
   2440     // 16000 is the highest we can support with our resampler.
   2441     ptrWav->nSamplesPerSec = 16000;
   2442     ptrWav->nAvgBytesPerSec = 32000;
   2443     ptrWav->nBlockAlign = 2;
   2444     ptrWav->wBitsPerSample = 16;
   2445     ptrWav->cbSize = 0;
   2446 
   2447     // Set the VoE format equal to the AEC output format.
   2448     _recAudioFrameSize = ptrWav->nBlockAlign;
   2449     _recSampleRate = ptrWav->nSamplesPerSec;
   2450     _recBlockSize = ptrWav->nSamplesPerSec / 100;
   2451     _recChannels = ptrWav->nChannels;
   2452 
   2453     // Set the DMO output format parameters.
   2454     hr = _dmo->SetOutputType(kAecCaptureStreamIndex, &mt, 0);
   2455     MoFreeMediaType(&mt);
   2456     if (FAILED(hr))
   2457     {
   2458         _TraceCOMError(hr);
   2459         return -1;
   2460     }
   2461 
   2462     if (_ptrAudioBuffer)
   2463     {
   2464         _ptrAudioBuffer->SetRecordingSampleRate(_recSampleRate);
   2465         _ptrAudioBuffer->SetRecordingChannels(_recChannels);
   2466     }
   2467     else
   2468     {
   2469         // Refer to InitRecording() for comments.
   2470         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
   2471             "AudioDeviceBuffer must be attached before streaming can start");
   2472     }
   2473 
   2474     _mediaBuffer = new MediaBufferImpl(_recBlockSize * _recAudioFrameSize);
   2475 
   2476     // Optional, but if called, must be after media types are set.
   2477     hr = _dmo->AllocateStreamingResources();
   2478     if (FAILED(hr))
   2479     {
   2480          _TraceCOMError(hr);
   2481         return -1;
   2482     }
   2483 
   2484     _recIsInitialized = true;
   2485     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
   2486         "Capture side is now initialized");
   2487 
   2488     return 0;
   2489 }
   2490 
   2491 // ----------------------------------------------------------------------------
   2492 //  InitRecording
   2493 // ----------------------------------------------------------------------------
   2494 
   2495 int32_t AudioDeviceWindowsCore::InitRecording()
   2496 {
   2497 
   2498     CriticalSectionScoped lock(&_critSect);
   2499 
   2500     if (_recording)
   2501     {
   2502         return -1;
   2503     }
   2504 
   2505     if (_recIsInitialized)
   2506     {
   2507         return 0;
   2508     }
   2509 
   2510     if (QueryPerformanceFrequency(&_perfCounterFreq) == 0)
   2511     {
   2512         return -1;
   2513     }
   2514     _perfCounterFactor = 10000000.0 / (double)_perfCounterFreq.QuadPart;
   2515 
   2516     if (_ptrDeviceIn == NULL)
   2517     {
   2518         return -1;
   2519     }
   2520 
   2521     // Initialize the microphone (devices might have been added or removed)
   2522     if (InitMicrophone() == -1)
   2523     {
   2524         WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "InitMicrophone() failed");
   2525     }
   2526 
   2527     // Ensure that the updated capturing endpoint device is valid
   2528     if (_ptrDeviceIn == NULL)
   2529     {
   2530         return -1;
   2531     }
   2532 
   2533     if (_builtInAecEnabled)
   2534     {
   2535         // The DMO will configure the capture device.
   2536         return InitRecordingDMO();
   2537     }
   2538 
   2539     HRESULT hr = S_OK;
   2540     WAVEFORMATEX* pWfxIn = NULL;
   2541     WAVEFORMATEX Wfx;
   2542     WAVEFORMATEX* pWfxClosestMatch = NULL;
   2543 
   2544     // Create COM object with IAudioClient interface.
   2545     SAFE_RELEASE(_ptrClientIn);
   2546     hr = _ptrDeviceIn->Activate(
   2547                           __uuidof(IAudioClient),
   2548                           CLSCTX_ALL,
   2549                           NULL,
   2550                           (void**)&_ptrClientIn);
   2551     EXIT_ON_ERROR(hr);
   2552 
   2553     // Retrieve the stream format that the audio engine uses for its internal
   2554     // processing (mixing) of shared-mode streams.
   2555     hr = _ptrClientIn->GetMixFormat(&pWfxIn);
   2556     if (SUCCEEDED(hr))
   2557     {
   2558         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "Audio Engine's current capturing mix format:");
   2559         // format type
   2560         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "wFormatTag     : 0x%X (%u)", pWfxIn->wFormatTag, pWfxIn->wFormatTag);
   2561         // number of channels (i.e. mono, stereo...)
   2562         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "nChannels      : %d", pWfxIn->nChannels);
   2563         // sample rate
   2564         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "nSamplesPerSec : %d", pWfxIn->nSamplesPerSec);
   2565         // for buffer estimation
   2566         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "nAvgBytesPerSec: %d", pWfxIn->nAvgBytesPerSec);
   2567         // block size of data
   2568         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "nBlockAlign    : %d", pWfxIn->nBlockAlign);
   2569         // number of bits per sample of mono data
   2570         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "wBitsPerSample : %d", pWfxIn->wBitsPerSample);
   2571         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "cbSize         : %d", pWfxIn->cbSize);
   2572     }
   2573 
   2574     // Set wave format
   2575     Wfx.wFormatTag = WAVE_FORMAT_PCM;
   2576     Wfx.wBitsPerSample = 16;
   2577     Wfx.cbSize = 0;
   2578 
   2579     const int freqs[6] = {48000, 44100, 16000, 96000, 32000, 8000};
   2580     hr = S_FALSE;
   2581 
   2582     // Iterate over frequencies and channels, in order of priority
   2583     for (int freq = 0; freq < sizeof(freqs)/sizeof(freqs[0]); freq++)
   2584     {
   2585         for (int chan = 0; chan < sizeof(_recChannelsPrioList)/sizeof(_recChannelsPrioList[0]); chan++)
   2586         {
   2587             Wfx.nChannels = _recChannelsPrioList[chan];
   2588             Wfx.nSamplesPerSec = freqs[freq];
   2589             Wfx.nBlockAlign = Wfx.nChannels * Wfx.wBitsPerSample / 8;
   2590             Wfx.nAvgBytesPerSec = Wfx.nSamplesPerSec * Wfx.nBlockAlign;
   2591             // If the method succeeds and the audio endpoint device supports the specified stream format,
   2592             // it returns S_OK. If the method succeeds and provides a closest match to the specified format,
   2593             // it returns S_FALSE.
   2594             hr = _ptrClientIn->IsFormatSupported(
   2595                                   AUDCLNT_SHAREMODE_SHARED,
   2596                                   &Wfx,
   2597                                   &pWfxClosestMatch);
   2598             if (hr == S_OK)
   2599             {
   2600                 break;
   2601             }
   2602             else
   2603             {
   2604                 WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "nChannels=%d, nSamplesPerSec=%d is not supported",
   2605                     Wfx.nChannels, Wfx.nSamplesPerSec);
   2606             }
   2607         }
   2608         if (hr == S_OK)
   2609             break;
   2610     }
   2611 
   2612     if (hr == S_OK)
   2613     {
   2614         _recAudioFrameSize = Wfx.nBlockAlign;
   2615         _recSampleRate = Wfx.nSamplesPerSec;
   2616         _recBlockSize = Wfx.nSamplesPerSec/100;
   2617         _recChannels = Wfx.nChannels;
   2618 
   2619         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "VoE selected this capturing format:");
   2620         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "wFormatTag        : 0x%X (%u)", Wfx.wFormatTag, Wfx.wFormatTag);
   2621         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "nChannels         : %d", Wfx.nChannels);
   2622         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "nSamplesPerSec    : %d", Wfx.nSamplesPerSec);
   2623         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "nAvgBytesPerSec   : %d", Wfx.nAvgBytesPerSec);
   2624         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "nBlockAlign       : %d", Wfx.nBlockAlign);
   2625         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "wBitsPerSample    : %d", Wfx.wBitsPerSample);
   2626         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "cbSize            : %d", Wfx.cbSize);
   2627         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "Additional settings:");
   2628         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "_recAudioFrameSize: %d", _recAudioFrameSize);
   2629         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "_recBlockSize     : %d", _recBlockSize);
   2630         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "_recChannels      : %d", _recChannels);
   2631     }
   2632 
   2633     // Create a capturing stream.
   2634     hr = _ptrClientIn->Initialize(
   2635                           AUDCLNT_SHAREMODE_SHARED,             // share Audio Engine with other applications
   2636                           AUDCLNT_STREAMFLAGS_EVENTCALLBACK |   // processing of the audio buffer by the client will be event driven
   2637                           AUDCLNT_STREAMFLAGS_NOPERSIST,        // volume and mute settings for an audio session will not persist across system restarts
   2638                           0,                                    // required for event-driven shared mode
   2639                           0,                                    // periodicity
   2640                           &Wfx,                                 // selected wave format
   2641                           NULL);                                // session GUID
   2642 
   2643 
   2644     if (hr != S_OK)
   2645     {
   2646         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "IAudioClient::Initialize() failed:");
   2647         if (pWfxClosestMatch != NULL)
   2648         {
   2649             WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "closest mix format: #channels=%d, samples/sec=%d, bits/sample=%d",
   2650                 pWfxClosestMatch->nChannels, pWfxClosestMatch->nSamplesPerSec, pWfxClosestMatch->wBitsPerSample);
   2651         }
   2652         else
   2653         {
   2654             WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "no format suggested");
   2655         }
   2656     }
   2657     EXIT_ON_ERROR(hr);
   2658 
   2659     if (_ptrAudioBuffer)
   2660     {
   2661         // Update the audio buffer with the selected parameters
   2662         _ptrAudioBuffer->SetRecordingSampleRate(_recSampleRate);
   2663         _ptrAudioBuffer->SetRecordingChannels((uint8_t)_recChannels);
   2664     }
   2665     else
   2666     {
   2667         // We can enter this state during CoreAudioIsSupported() when no AudioDeviceImplementation
   2668         // has been created, hence the AudioDeviceBuffer does not exist.
   2669         // It is OK to end up here since we don't initiate any media in CoreAudioIsSupported().
   2670         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "AudioDeviceBuffer must be attached before streaming can start");
   2671     }
   2672 
   2673     // Get the actual size of the shared (endpoint buffer).
   2674     // Typical value is 960 audio frames <=> 20ms @ 48kHz sample rate.
   2675     UINT bufferFrameCount(0);
   2676     hr = _ptrClientIn->GetBufferSize(
   2677                           &bufferFrameCount);
   2678     if (SUCCEEDED(hr))
   2679     {
   2680         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "IAudioClient::GetBufferSize() => %u (<=> %u bytes)",
   2681             bufferFrameCount, bufferFrameCount*_recAudioFrameSize);
   2682     }
   2683 
   2684     // Set the event handle that the system signals when an audio buffer is ready
   2685     // to be processed by the client.
   2686     hr = _ptrClientIn->SetEventHandle(
   2687                           _hCaptureSamplesReadyEvent);
   2688     EXIT_ON_ERROR(hr);
   2689 
   2690     // Get an IAudioCaptureClient interface.
   2691     SAFE_RELEASE(_ptrCaptureClient);
   2692     hr = _ptrClientIn->GetService(
   2693                           __uuidof(IAudioCaptureClient),
   2694                           (void**)&_ptrCaptureClient);
   2695     EXIT_ON_ERROR(hr);
   2696 
   2697     // Mark capture side as initialized
   2698     _recIsInitialized = true;
   2699 
   2700     CoTaskMemFree(pWfxIn);
   2701     CoTaskMemFree(pWfxClosestMatch);
   2702 
   2703     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "capture side is now initialized");
   2704     return 0;
   2705 
   2706 Exit:
   2707     _TraceCOMError(hr);
   2708     CoTaskMemFree(pWfxIn);
   2709     CoTaskMemFree(pWfxClosestMatch);
   2710     SAFE_RELEASE(_ptrClientIn);
   2711     SAFE_RELEASE(_ptrCaptureClient);
   2712     return -1;
   2713 }
   2714 
   2715 // ----------------------------------------------------------------------------
   2716 //  StartRecording
   2717 // ----------------------------------------------------------------------------
   2718 
   2719 int32_t AudioDeviceWindowsCore::StartRecording()
   2720 {
   2721 
   2722     if (!_recIsInitialized)
   2723     {
   2724         return -1;
   2725     }
   2726 
   2727     if (_hRecThread != NULL)
   2728     {
   2729         return 0;
   2730     }
   2731 
   2732     if (_recording)
   2733     {
   2734         return 0;
   2735     }
   2736 
   2737     {
   2738         CriticalSectionScoped critScoped(&_critSect);
   2739 
   2740         // Create thread which will drive the capturing
   2741         LPTHREAD_START_ROUTINE lpStartAddress = WSAPICaptureThread;
   2742         if (_builtInAecEnabled)
   2743         {
   2744             // Redirect to the DMO polling method.
   2745             lpStartAddress = WSAPICaptureThreadPollDMO;
   2746 
   2747             if (!_playing)
   2748             {
   2749                 // The DMO won't provide us captured output data unless we
   2750                 // give it render data to process.
   2751                 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   2752                     "Playout must be started before recording when using the "
   2753                     "built-in AEC");
   2754                 return -1;
   2755             }
   2756         }
   2757 
   2758         assert(_hRecThread == NULL);
   2759         _hRecThread = CreateThread(NULL,
   2760                                    0,
   2761                                    lpStartAddress,
   2762                                    this,
   2763                                    0,
   2764                                    NULL);
   2765         if (_hRecThread == NULL)
   2766         {
   2767             WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   2768                          "failed to create the recording thread");
   2769             return -1;
   2770         }
   2771 
   2772         // Set thread priority to highest possible
   2773         SetThreadPriority(_hRecThread, THREAD_PRIORITY_TIME_CRITICAL);
   2774 
   2775         assert(_hGetCaptureVolumeThread == NULL);
   2776         _hGetCaptureVolumeThread = CreateThread(NULL,
   2777                                                 0,
   2778                                                 GetCaptureVolumeThread,
   2779                                                 this,
   2780                                                 0,
   2781                                                 NULL);
   2782         if (_hGetCaptureVolumeThread == NULL)
   2783         {
   2784             WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   2785                          "  failed to create the volume getter thread");
   2786             return -1;
   2787         }
   2788 
   2789         assert(_hSetCaptureVolumeThread == NULL);
   2790         _hSetCaptureVolumeThread = CreateThread(NULL,
   2791                                                 0,
   2792                                                 SetCaptureVolumeThread,
   2793                                                 this,
   2794                                                 0,
   2795                                                 NULL);
   2796         if (_hSetCaptureVolumeThread == NULL)
   2797         {
   2798             WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   2799                          "  failed to create the volume setter thread");
   2800             return -1;
   2801         }
   2802     }  // critScoped
   2803 
   2804     DWORD ret = WaitForSingleObject(_hCaptureStartedEvent, 1000);
   2805     if (ret != WAIT_OBJECT_0)
   2806     {
   2807         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
   2808             "capturing did not start up properly");
   2809         return -1;
   2810     }
   2811     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
   2812         "capture audio stream has now started...");
   2813 
   2814     _avgCPULoad = 0.0f;
   2815     _playAcc = 0;
   2816     _recording = true;
   2817 
   2818     return 0;
   2819 }
   2820 
   2821 // ----------------------------------------------------------------------------
   2822 //  StopRecording
   2823 // ----------------------------------------------------------------------------
   2824 
   2825 int32_t AudioDeviceWindowsCore::StopRecording()
   2826 {
   2827     int32_t err = 0;
   2828 
   2829     if (!_recIsInitialized)
   2830     {
   2831         return 0;
   2832     }
   2833 
   2834     _Lock();
   2835 
   2836     if (_hRecThread == NULL)
   2837     {
   2838         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
   2839             "no capturing stream is active => close down WASAPI only");
   2840         SAFE_RELEASE(_ptrClientIn);
   2841         SAFE_RELEASE(_ptrCaptureClient);
   2842         _recIsInitialized = false;
   2843         _recording = false;
   2844         _UnLock();
   2845         return 0;
   2846     }
   2847 
   2848     // Stop the driving thread...
   2849     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
   2850         "closing down the webrtc_core_audio_capture_thread...");
   2851     // Manual-reset event; it will remain signalled to stop all capture threads.
   2852     SetEvent(_hShutdownCaptureEvent);
   2853 
   2854     _UnLock();
   2855     DWORD ret = WaitForSingleObject(_hRecThread, 2000);
   2856     if (ret != WAIT_OBJECT_0)
   2857     {
   2858         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   2859             "failed to close down webrtc_core_audio_capture_thread");
   2860         err = -1;
   2861     }
   2862     else
   2863     {
   2864         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
   2865             "webrtc_core_audio_capture_thread is now closed");
   2866     }
   2867 
   2868     ret = WaitForSingleObject(_hGetCaptureVolumeThread, 2000);
   2869     if (ret != WAIT_OBJECT_0)
   2870     {
   2871         // the thread did not stop as it should
   2872         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   2873                      "  failed to close down volume getter thread");
   2874         err = -1;
   2875     }
   2876     else
   2877     {
   2878         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
   2879             "  volume getter thread is now closed");
   2880     }
   2881 
   2882     ret = WaitForSingleObject(_hSetCaptureVolumeThread, 2000);
   2883     if (ret != WAIT_OBJECT_0)
   2884     {
   2885         // the thread did not stop as it should
   2886         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   2887                      "  failed to close down volume setter thread");
   2888         err = -1;
   2889     }
   2890     else
   2891     {
   2892         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
   2893             "  volume setter thread is now closed");
   2894     }
   2895     _Lock();
   2896 
   2897     ResetEvent(_hShutdownCaptureEvent); // Must be manually reset.
   2898     // Ensure that the thread has released these interfaces properly.
   2899     assert(err == -1 || _ptrClientIn == NULL);
   2900     assert(err == -1 || _ptrCaptureClient == NULL);
   2901 
   2902     _recIsInitialized = false;
   2903     _recording = false;
   2904 
   2905     // These will create thread leaks in the result of an error,
   2906     // but we can at least resume the call.
   2907     CloseHandle(_hRecThread);
   2908     _hRecThread = NULL;
   2909 
   2910     CloseHandle(_hGetCaptureVolumeThread);
   2911     _hGetCaptureVolumeThread = NULL;
   2912 
   2913     CloseHandle(_hSetCaptureVolumeThread);
   2914     _hSetCaptureVolumeThread = NULL;
   2915 
   2916     if (_builtInAecEnabled)
   2917     {
   2918         assert(_dmo != NULL);
   2919         // This is necessary. Otherwise the DMO can generate garbage render
   2920         // audio even after rendering has stopped.
   2921         HRESULT hr = _dmo->FreeStreamingResources();
   2922         if (FAILED(hr))
   2923         {
   2924             _TraceCOMError(hr);
   2925             err = -1;
   2926         }
   2927     }
   2928 
   2929     // Reset the recording delay value.
   2930     _sndCardRecDelay = 0;
   2931 
   2932     _UnLock();
   2933 
   2934     return err;
   2935 }
   2936 
   2937 // ----------------------------------------------------------------------------
   2938 //  RecordingIsInitialized
   2939 // ----------------------------------------------------------------------------
   2940 
   2941 bool AudioDeviceWindowsCore::RecordingIsInitialized() const
   2942 {
   2943     return (_recIsInitialized);
   2944 }
   2945 
   2946 // ----------------------------------------------------------------------------
   2947 //  Recording
   2948 // ----------------------------------------------------------------------------
   2949 
   2950 bool AudioDeviceWindowsCore::Recording() const
   2951 {
   2952     return (_recording);
   2953 }
   2954 
   2955 // ----------------------------------------------------------------------------
   2956 //  PlayoutIsInitialized
   2957 // ----------------------------------------------------------------------------
   2958 
   2959 bool AudioDeviceWindowsCore::PlayoutIsInitialized() const
   2960 {
   2961 
   2962     return (_playIsInitialized);
   2963 }
   2964 
   2965 // ----------------------------------------------------------------------------
   2966 //  StartPlayout
   2967 // ----------------------------------------------------------------------------
   2968 
   2969 int32_t AudioDeviceWindowsCore::StartPlayout()
   2970 {
   2971 
   2972     if (!_playIsInitialized)
   2973     {
   2974         return -1;
   2975     }
   2976 
   2977     if (_hPlayThread != NULL)
   2978     {
   2979         return 0;
   2980     }
   2981 
   2982     if (_playing)
   2983     {
   2984         return 0;
   2985     }
   2986 
   2987     {
   2988         CriticalSectionScoped critScoped(&_critSect);
   2989 
   2990         // Create thread which will drive the rendering.
   2991         assert(_hPlayThread == NULL);
   2992         _hPlayThread = CreateThread(
   2993                          NULL,
   2994                          0,
   2995                          WSAPIRenderThread,
   2996                          this,
   2997                          0,
   2998                          NULL);
   2999         if (_hPlayThread == NULL)
   3000         {
   3001             WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   3002                 "failed to create the playout thread");
   3003             return -1;
   3004         }
   3005 
   3006         // Set thread priority to highest possible.
   3007         SetThreadPriority(_hPlayThread, THREAD_PRIORITY_TIME_CRITICAL);
   3008     }  // critScoped
   3009 
   3010     DWORD ret = WaitForSingleObject(_hRenderStartedEvent, 1000);
   3011     if (ret != WAIT_OBJECT_0)
   3012     {
   3013         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
   3014             "rendering did not start up properly");
   3015         return -1;
   3016     }
   3017 
   3018     _playing = true;
   3019     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
   3020         "rendering audio stream has now started...");
   3021 
   3022     return 0;
   3023 }
   3024 
   3025 // ----------------------------------------------------------------------------
   3026 //  StopPlayout
   3027 // ----------------------------------------------------------------------------
   3028 
   3029 int32_t AudioDeviceWindowsCore::StopPlayout()
   3030 {
   3031 
   3032     if (!_playIsInitialized)
   3033     {
   3034         return 0;
   3035     }
   3036 
   3037     {
   3038         CriticalSectionScoped critScoped(&_critSect) ;
   3039 
   3040         if (_hPlayThread == NULL)
   3041         {
   3042             WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
   3043                 "no rendering stream is active => close down WASAPI only");
   3044             SAFE_RELEASE(_ptrClientOut);
   3045             SAFE_RELEASE(_ptrRenderClient);
   3046             _playIsInitialized = false;
   3047             _playing = false;
   3048             return 0;
   3049         }
   3050 
   3051         // stop the driving thread...
   3052         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
   3053             "closing down the webrtc_core_audio_render_thread...");
   3054         SetEvent(_hShutdownRenderEvent);
   3055     }  // critScoped
   3056 
   3057     DWORD ret = WaitForSingleObject(_hPlayThread, 2000);
   3058     if (ret != WAIT_OBJECT_0)
   3059     {
   3060         // the thread did not stop as it should
   3061         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   3062             "failed to close down webrtc_core_audio_render_thread");
   3063         CloseHandle(_hPlayThread);
   3064         _hPlayThread = NULL;
   3065         _playIsInitialized = false;
   3066         _playing = false;
   3067         return -1;
   3068     }
   3069 
   3070     {
   3071         CriticalSectionScoped critScoped(&_critSect);
   3072         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
   3073             "webrtc_core_audio_render_thread is now closed");
   3074 
   3075         // to reset this event manually at each time we finish with it,
   3076         // in case that the render thread has exited before StopPlayout(),
   3077         // this event might be caught by the new render thread within same VoE instance.
   3078         ResetEvent(_hShutdownRenderEvent);
   3079 
   3080         SAFE_RELEASE(_ptrClientOut);
   3081         SAFE_RELEASE(_ptrRenderClient);
   3082 
   3083         _playIsInitialized = false;
   3084         _playing = false;
   3085 
   3086         CloseHandle(_hPlayThread);
   3087         _hPlayThread = NULL;
   3088 
   3089         if (_builtInAecEnabled && _recording)
   3090         {
   3091             // The DMO won't provide us captured output data unless we
   3092             // give it render data to process.
   3093             //
   3094             // We still permit the playout to shutdown, and trace a warning.
   3095             // Otherwise, VoE can get into a state which will never permit
   3096             // playout to stop properly.
   3097             WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
   3098                 "Recording should be stopped before playout when using the "
   3099                 "built-in AEC");
   3100         }
   3101 
   3102         // Reset the playout delay value.
   3103         _sndCardPlayDelay = 0;
   3104     }  // critScoped
   3105 
   3106     return 0;
   3107 }
   3108 
   3109 // ----------------------------------------------------------------------------
   3110 //  PlayoutDelay
   3111 // ----------------------------------------------------------------------------
   3112 
   3113 int32_t AudioDeviceWindowsCore::PlayoutDelay(uint16_t& delayMS) const
   3114 {
   3115     CriticalSectionScoped critScoped(&_critSect);
   3116     delayMS = static_cast<uint16_t>(_sndCardPlayDelay);
   3117     return 0;
   3118 }
   3119 
   3120 // ----------------------------------------------------------------------------
   3121 //  RecordingDelay
   3122 // ----------------------------------------------------------------------------
   3123 
   3124 int32_t AudioDeviceWindowsCore::RecordingDelay(uint16_t& delayMS) const
   3125 {
   3126     CriticalSectionScoped critScoped(&_critSect);
   3127     delayMS = static_cast<uint16_t>(_sndCardRecDelay);
   3128     return 0;
   3129 }
   3130 
   3131 // ----------------------------------------------------------------------------
   3132 //  Playing
   3133 // ----------------------------------------------------------------------------
   3134 
   3135 bool AudioDeviceWindowsCore::Playing() const
   3136 {
   3137     return (_playing);
   3138 }
   3139 // ----------------------------------------------------------------------------
   3140 //  SetPlayoutBuffer
   3141 // ----------------------------------------------------------------------------
   3142 
   3143 int32_t AudioDeviceWindowsCore::SetPlayoutBuffer(const AudioDeviceModule::BufferType type, uint16_t sizeMS)
   3144 {
   3145 
   3146     CriticalSectionScoped lock(&_critSect);
   3147 
   3148     _playBufType = type;
   3149 
   3150     if (type == AudioDeviceModule::kFixedBufferSize)
   3151     {
   3152         _playBufDelayFixed = sizeMS;
   3153     }
   3154 
   3155     return 0;
   3156 }
   3157 
   3158 // ----------------------------------------------------------------------------
   3159 //  PlayoutBuffer
   3160 // ----------------------------------------------------------------------------
   3161 
   3162 int32_t AudioDeviceWindowsCore::PlayoutBuffer(AudioDeviceModule::BufferType& type, uint16_t& sizeMS) const
   3163 {
   3164     CriticalSectionScoped lock(&_critSect);
   3165     type = _playBufType;
   3166 
   3167     if (type == AudioDeviceModule::kFixedBufferSize)
   3168     {
   3169         sizeMS = _playBufDelayFixed;
   3170     }
   3171     else
   3172     {
   3173         // Use same value as for PlayoutDelay
   3174         sizeMS = static_cast<uint16_t>(_sndCardPlayDelay);
   3175     }
   3176 
   3177     return 0;
   3178 }
   3179 
   3180 // ----------------------------------------------------------------------------
   3181 //  CPULoad
   3182 // ----------------------------------------------------------------------------
   3183 
   3184 int32_t AudioDeviceWindowsCore::CPULoad(uint16_t& load) const
   3185 {
   3186 
   3187     load = static_cast<uint16_t> (100*_avgCPULoad);
   3188 
   3189     return 0;
   3190 }
   3191 
   3192 // ----------------------------------------------------------------------------
   3193 //  PlayoutWarning
   3194 // ----------------------------------------------------------------------------
   3195 
   3196 bool AudioDeviceWindowsCore::PlayoutWarning() const
   3197 {
   3198     return ( _playWarning > 0);
   3199 }
   3200 
   3201 // ----------------------------------------------------------------------------
   3202 //  PlayoutError
   3203 // ----------------------------------------------------------------------------
   3204 
   3205 bool AudioDeviceWindowsCore::PlayoutError() const
   3206 {
   3207     return ( _playError > 0);
   3208 }
   3209 
   3210 // ----------------------------------------------------------------------------
   3211 //  RecordingWarning
   3212 // ----------------------------------------------------------------------------
   3213 
   3214 bool AudioDeviceWindowsCore::RecordingWarning() const
   3215 {
   3216     return ( _recWarning > 0);
   3217 }
   3218 
   3219 // ----------------------------------------------------------------------------
   3220 //  RecordingError
   3221 // ----------------------------------------------------------------------------
   3222 
   3223 bool AudioDeviceWindowsCore::RecordingError() const
   3224 {
   3225     return ( _recError > 0);
   3226 }
   3227 
   3228 // ----------------------------------------------------------------------------
   3229 //  ClearPlayoutWarning
   3230 // ----------------------------------------------------------------------------
   3231 
   3232 void AudioDeviceWindowsCore::ClearPlayoutWarning()
   3233 {
   3234     _playWarning = 0;
   3235 }
   3236 
   3237 // ----------------------------------------------------------------------------
   3238 //  ClearPlayoutError
   3239 // ----------------------------------------------------------------------------
   3240 
   3241 void AudioDeviceWindowsCore::ClearPlayoutError()
   3242 {
   3243     _playError = 0;
   3244 }
   3245 
   3246 // ----------------------------------------------------------------------------
   3247 //  ClearRecordingWarning
   3248 // ----------------------------------------------------------------------------
   3249 
   3250 void AudioDeviceWindowsCore::ClearRecordingWarning()
   3251 {
   3252     _recWarning = 0;
   3253 }
   3254 
   3255 // ----------------------------------------------------------------------------
   3256 //  ClearRecordingError
   3257 // ----------------------------------------------------------------------------
   3258 
   3259 void AudioDeviceWindowsCore::ClearRecordingError()
   3260 {
   3261     _recError = 0;
   3262 }
   3263 
   3264 // ============================================================================
   3265 //                                 Private Methods
   3266 // ============================================================================
   3267 
   3268 // ----------------------------------------------------------------------------
   3269 //  [static] WSAPIRenderThread
   3270 // ----------------------------------------------------------------------------
   3271 
   3272 DWORD WINAPI AudioDeviceWindowsCore::WSAPIRenderThread(LPVOID context)
   3273 {
   3274     return reinterpret_cast<AudioDeviceWindowsCore*>(context)->
   3275         DoRenderThread();
   3276 }
   3277 
   3278 // ----------------------------------------------------------------------------
   3279 //  [static] WSAPICaptureThread
   3280 // ----------------------------------------------------------------------------
   3281 
   3282 DWORD WINAPI AudioDeviceWindowsCore::WSAPICaptureThread(LPVOID context)
   3283 {
   3284     return reinterpret_cast<AudioDeviceWindowsCore*>(context)->
   3285         DoCaptureThread();
   3286 }
   3287 
   3288 DWORD WINAPI AudioDeviceWindowsCore::WSAPICaptureThreadPollDMO(LPVOID context)
   3289 {
   3290     return reinterpret_cast<AudioDeviceWindowsCore*>(context)->
   3291         DoCaptureThreadPollDMO();
   3292 }
   3293 
   3294 DWORD WINAPI AudioDeviceWindowsCore::GetCaptureVolumeThread(LPVOID context)
   3295 {
   3296     return reinterpret_cast<AudioDeviceWindowsCore*>(context)->
   3297         DoGetCaptureVolumeThread();
   3298 }
   3299 
   3300 DWORD WINAPI AudioDeviceWindowsCore::SetCaptureVolumeThread(LPVOID context)
   3301 {
   3302     return reinterpret_cast<AudioDeviceWindowsCore*>(context)->
   3303         DoSetCaptureVolumeThread();
   3304 }
   3305 
   3306 DWORD AudioDeviceWindowsCore::DoGetCaptureVolumeThread()
   3307 {
   3308     HANDLE waitObject = _hShutdownCaptureEvent;
   3309 
   3310     while (1)
   3311     {
   3312         if (AGC())
   3313         {
   3314             uint32_t currentMicLevel = 0;
   3315             if (MicrophoneVolume(currentMicLevel) == 0)
   3316             {
   3317                 // This doesn't set the system volume, just stores it.
   3318                 _Lock();
   3319                 if (_ptrAudioBuffer)
   3320                 {
   3321                     _ptrAudioBuffer->SetCurrentMicLevel(currentMicLevel);
   3322                 }
   3323                 _UnLock();
   3324             }
   3325         }
   3326 
   3327         DWORD waitResult = WaitForSingleObject(waitObject,
   3328                                                GET_MIC_VOLUME_INTERVAL_MS);
   3329         switch (waitResult)
   3330         {
   3331             case WAIT_OBJECT_0: // _hShutdownCaptureEvent
   3332                 return 0;
   3333             case WAIT_TIMEOUT:  // timeout notification
   3334                 break;
   3335             default:            // unexpected error
   3336                 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
   3337                     "  unknown wait termination on get volume thread");
   3338                 return -1;
   3339         }
   3340     }
   3341 }
   3342 
   3343 DWORD AudioDeviceWindowsCore::DoSetCaptureVolumeThread()
   3344 {
   3345     HANDLE waitArray[2] = {_hShutdownCaptureEvent, _hSetCaptureVolumeEvent};
   3346 
   3347     while (1)
   3348     {
   3349         DWORD waitResult = WaitForMultipleObjects(2, waitArray, FALSE, INFINITE);
   3350         switch (waitResult)
   3351         {
   3352             case WAIT_OBJECT_0:      // _hShutdownCaptureEvent
   3353                 return 0;
   3354             case WAIT_OBJECT_0 + 1:  // _hSetCaptureVolumeEvent
   3355                 break;
   3356             default:                 // unexpected error
   3357                 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
   3358                     "  unknown wait termination on set volume thread");
   3359                     return -1;
   3360         }
   3361 
   3362         _Lock();
   3363         uint32_t newMicLevel = _newMicLevel;
   3364         _UnLock();
   3365 
   3366         if (SetMicrophoneVolume(newMicLevel) == -1)
   3367         {
   3368             WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
   3369                 "  the required modification of the microphone volume failed");
   3370         }
   3371     }
   3372 }
   3373 
   3374 // ----------------------------------------------------------------------------
   3375 //  DoRenderThread
   3376 // ----------------------------------------------------------------------------
   3377 
   3378 DWORD AudioDeviceWindowsCore::DoRenderThread()
   3379 {
   3380 
   3381     bool keepPlaying = true;
   3382     HANDLE waitArray[2] = {_hShutdownRenderEvent, _hRenderSamplesReadyEvent};
   3383     HRESULT hr = S_OK;
   3384     HANDLE hMmTask = NULL;
   3385 
   3386     LARGE_INTEGER t1;
   3387     LARGE_INTEGER t2;
   3388     int32_t time(0);
   3389 
   3390     // Initialize COM as MTA in this thread.
   3391     ScopedCOMInitializer comInit(ScopedCOMInitializer::kMTA);
   3392     if (!comInit.succeeded()) {
   3393       WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   3394           "failed to initialize COM in render thread");
   3395       return -1;
   3396     }
   3397 
   3398     _SetThreadName(-1, "webrtc_core_audio_render_thread");
   3399 
   3400     // Use Multimedia Class Scheduler Service (MMCSS) to boost the thread priority.
   3401     //
   3402     if (_winSupportAvrt)
   3403     {
   3404         DWORD taskIndex(0);
   3405         hMmTask = _PAvSetMmThreadCharacteristicsA("Pro Audio", &taskIndex);
   3406         if (hMmTask)
   3407         {
   3408             if (FALSE == _PAvSetMmThreadPriority(hMmTask, AVRT_PRIORITY_CRITICAL))
   3409             {
   3410                 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "failed to boost play-thread using MMCSS");
   3411             }
   3412             WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "render thread is now registered with MMCSS (taskIndex=%d)", taskIndex);
   3413         }
   3414         else
   3415         {
   3416             WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "failed to enable MMCSS on render thread (err=%d)", GetLastError());
   3417             _TraceCOMError(GetLastError());
   3418         }
   3419     }
   3420 
   3421     _Lock();
   3422 
   3423     IAudioClock* clock = NULL;
   3424 
   3425     // Get size of rendering buffer (length is expressed as the number of audio frames the buffer can hold).
   3426     // This value is fixed during the rendering session.
   3427     //
   3428     UINT32 bufferLength = 0;
   3429     hr = _ptrClientOut->GetBufferSize(&bufferLength);
   3430     EXIT_ON_ERROR(hr);
   3431     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "[REND] size of buffer       : %u", bufferLength);
   3432 
   3433     // Get maximum latency for the current stream (will not change for the lifetime  of the IAudioClient object).
   3434     //
   3435     REFERENCE_TIME latency;
   3436     _ptrClientOut->GetStreamLatency(&latency);
   3437     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "[REND] max stream latency   : %u (%3.2f ms)",
   3438         (DWORD)latency, (double)(latency/10000.0));
   3439 
   3440     // Get the length of the periodic interval separating successive processing passes by
   3441     // the audio engine on the data in the endpoint buffer.
   3442     //
   3443     // The period between processing passes by the audio engine is fixed for a particular
   3444     // audio endpoint device and represents the smallest processing quantum for the audio engine.
   3445     // This period plus the stream latency between the buffer and endpoint device represents
   3446     // the minimum possible latency that an audio application can achieve.
   3447     // Typical value: 100000 <=> 0.01 sec = 10ms.
   3448     //
   3449     REFERENCE_TIME devPeriod = 0;
   3450     REFERENCE_TIME devPeriodMin = 0;
   3451     _ptrClientOut->GetDevicePeriod(&devPeriod, &devPeriodMin);
   3452     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "[REND] device period        : %u (%3.2f ms)",
   3453         (DWORD)devPeriod, (double)(devPeriod/10000.0));
   3454 
   3455     // Derive initial rendering delay.
   3456     // Example: 10*(960/480) + 15 = 20 + 15 = 35ms
   3457     //
   3458     int playout_delay = 10 * (bufferLength / _playBlockSize) +
   3459         (int)((latency + devPeriod) / 10000);
   3460     _sndCardPlayDelay = playout_delay;
   3461     _writtenSamples = 0;
   3462     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
   3463                  "[REND] initial delay        : %u", playout_delay);
   3464 
   3465     double endpointBufferSizeMS = 10.0 * ((double)bufferLength / (double)_devicePlayBlockSize);
   3466     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "[REND] endpointBufferSizeMS : %3.2f", endpointBufferSizeMS);
   3467 
   3468     // Before starting the stream, fill the rendering buffer with silence.
   3469     //
   3470     BYTE *pData = NULL;
   3471     hr = _ptrRenderClient->GetBuffer(bufferLength, &pData);
   3472     EXIT_ON_ERROR(hr);
   3473 
   3474     hr = _ptrRenderClient->ReleaseBuffer(bufferLength, AUDCLNT_BUFFERFLAGS_SILENT);
   3475     EXIT_ON_ERROR(hr);
   3476 
   3477     _writtenSamples += bufferLength;
   3478 
   3479     hr = _ptrClientOut->GetService(__uuidof(IAudioClock), (void**)&clock);
   3480     if (FAILED(hr)) {
   3481       WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
   3482                    "failed to get IAudioClock interface from the IAudioClient");
   3483     }
   3484 
   3485     // Start up the rendering audio stream.
   3486     hr = _ptrClientOut->Start();
   3487     EXIT_ON_ERROR(hr);
   3488 
   3489     _UnLock();
   3490 
   3491     // Set event which will ensure that the calling thread modifies the playing state to true.
   3492     //
   3493     SetEvent(_hRenderStartedEvent);
   3494 
   3495     // >> ------------------ THREAD LOOP ------------------
   3496 
   3497     while (keepPlaying)
   3498     {
   3499         // Wait for a render notification event or a shutdown event
   3500         DWORD waitResult = WaitForMultipleObjects(2, waitArray, FALSE, 500);
   3501         switch (waitResult)
   3502         {
   3503         case WAIT_OBJECT_0 + 0:     // _hShutdownRenderEvent
   3504             keepPlaying = false;
   3505             break;
   3506         case WAIT_OBJECT_0 + 1:     // _hRenderSamplesReadyEvent
   3507             break;
   3508         case WAIT_TIMEOUT:          // timeout notification
   3509             WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "render event timed out after 0.5 seconds");
   3510             goto Exit;
   3511         default:                    // unexpected error
   3512             WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "unknown wait termination on render side");
   3513             goto Exit;
   3514         }
   3515 
   3516         while (keepPlaying)
   3517         {
   3518             _Lock();
   3519 
   3520             // Sanity check to ensure that essential states are not modified
   3521             // during the unlocked period.
   3522             if (_ptrRenderClient == NULL || _ptrClientOut == NULL)
   3523             {
   3524                 _UnLock();
   3525                 WEBRTC_TRACE(kTraceCritical, kTraceAudioDevice, _id,
   3526                     "output state has been modified during unlocked period");
   3527                 goto Exit;
   3528             }
   3529 
   3530             // Get the number of frames of padding (queued up to play) in the endpoint buffer.
   3531             UINT32 padding = 0;
   3532             hr = _ptrClientOut->GetCurrentPadding(&padding);
   3533             EXIT_ON_ERROR(hr);
   3534 
   3535             // Derive the amount of available space in the output buffer
   3536             uint32_t framesAvailable = bufferLength - padding;
   3537             // WEBRTC_TRACE(kTraceStream, kTraceAudioDevice, _id, "#avaliable audio frames = %u", framesAvailable);
   3538 
   3539             // Do we have 10 ms available in the render buffer?
   3540             if (framesAvailable < _playBlockSize)
   3541             {
   3542                 // Not enough space in render buffer to store next render packet.
   3543                 _UnLock();
   3544                 break;
   3545             }
   3546 
   3547             // Write n*10ms buffers to the render buffer
   3548             const uint32_t n10msBuffers = (framesAvailable / _playBlockSize);
   3549             for (uint32_t n = 0; n < n10msBuffers; n++)
   3550             {
   3551                 // Get pointer (i.e., grab the buffer) to next space in the shared render buffer.
   3552                 hr = _ptrRenderClient->GetBuffer(_playBlockSize, &pData);
   3553                 EXIT_ON_ERROR(hr);
   3554 
   3555                 QueryPerformanceCounter(&t1);    // measure time: START
   3556 
   3557                 if (_ptrAudioBuffer)
   3558                 {
   3559                     // Request data to be played out (#bytes = _playBlockSize*_audioFrameSize)
   3560                     _UnLock();
   3561                     int32_t nSamples =
   3562                     _ptrAudioBuffer->RequestPlayoutData(_playBlockSize);
   3563                     _Lock();
   3564 
   3565                     if (nSamples == -1)
   3566                     {
   3567                         _UnLock();
   3568                         WEBRTC_TRACE(kTraceCritical, kTraceAudioDevice, _id,
   3569                                      "failed to read data from render client");
   3570                         goto Exit;
   3571                     }
   3572 
   3573                     // Sanity check to ensure that essential states are not modified during the unlocked period
   3574                     if (_ptrRenderClient == NULL || _ptrClientOut == NULL)
   3575                     {
   3576                         _UnLock();
   3577                         WEBRTC_TRACE(kTraceCritical, kTraceAudioDevice, _id, "output state has been modified during unlocked period");
   3578                         goto Exit;
   3579                     }
   3580                     if (nSamples != static_cast<int32_t>(_playBlockSize))
   3581                     {
   3582                         WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "nSamples(%d) != _playBlockSize(%d)", nSamples, _playBlockSize);
   3583                     }
   3584 
   3585                     // Get the actual (stored) data
   3586                     nSamples = _ptrAudioBuffer->GetPlayoutData((int8_t*)pData);
   3587                 }
   3588 
   3589                 QueryPerformanceCounter(&t2);    // measure time: STOP
   3590                 time = (int)(t2.QuadPart-t1.QuadPart);
   3591                 _playAcc += time;
   3592 
   3593                 DWORD dwFlags(0);
   3594                 hr = _ptrRenderClient->ReleaseBuffer(_playBlockSize, dwFlags);
   3595                 // See http://msdn.microsoft.com/en-us/library/dd316605(VS.85).aspx
   3596                 // for more details regarding AUDCLNT_E_DEVICE_INVALIDATED.
   3597                 EXIT_ON_ERROR(hr);
   3598 
   3599                 _writtenSamples += _playBlockSize;
   3600             }
   3601 
   3602             // Check the current delay on the playout side.
   3603             if (clock) {
   3604               UINT64 pos = 0;
   3605               UINT64 freq = 1;
   3606               clock->GetPosition(&pos, NULL);
   3607               clock->GetFrequency(&freq);
   3608               playout_delay = ROUND((double(_writtenSamples) /
   3609                   _devicePlaySampleRate - double(pos) / freq) * 1000.0);
   3610               _sndCardPlayDelay = playout_delay;
   3611             }
   3612 
   3613             _UnLock();
   3614         }
   3615     }
   3616 
   3617     // ------------------ THREAD LOOP ------------------ <<
   3618 
   3619     SleepMs(static_cast<DWORD>(endpointBufferSizeMS+0.5));
   3620     hr = _ptrClientOut->Stop();
   3621 
   3622 Exit:
   3623     SAFE_RELEASE(clock);
   3624 
   3625     if (FAILED(hr))
   3626     {
   3627         _ptrClientOut->Stop();
   3628         _UnLock();
   3629         _TraceCOMError(hr);
   3630     }
   3631 
   3632     if (_winSupportAvrt)
   3633     {
   3634         if (NULL != hMmTask)
   3635         {
   3636             _PAvRevertMmThreadCharacteristics(hMmTask);
   3637         }
   3638     }
   3639 
   3640     _Lock();
   3641 
   3642     if (keepPlaying)
   3643     {
   3644         if (_ptrClientOut != NULL)
   3645         {
   3646             hr = _ptrClientOut->Stop();
   3647             if (FAILED(hr))
   3648             {
   3649                 _TraceCOMError(hr);
   3650             }
   3651             hr = _ptrClientOut->Reset();
   3652             if (FAILED(hr))
   3653             {
   3654                 _TraceCOMError(hr);
   3655             }
   3656         }
   3657         // Trigger callback from module process thread
   3658         _playError = 1;
   3659         WEBRTC_TRACE(kTraceError, kTraceUtility, _id, "kPlayoutError message posted: rendering thread has ended pre-maturely");
   3660     }
   3661     else
   3662     {
   3663         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "_Rendering thread is now terminated properly");
   3664     }
   3665 
   3666     _UnLock();
   3667 
   3668     return (DWORD)hr;
   3669 }
   3670 
   3671 DWORD AudioDeviceWindowsCore::InitCaptureThreadPriority()
   3672 {
   3673     _hMmTask = NULL;
   3674 
   3675     _SetThreadName(-1, "webrtc_core_audio_capture_thread");
   3676 
   3677     // Use Multimedia Class Scheduler Service (MMCSS) to boost the thread
   3678     // priority.
   3679     if (_winSupportAvrt)
   3680     {
   3681         DWORD taskIndex(0);
   3682         _hMmTask = _PAvSetMmThreadCharacteristicsA("Pro Audio", &taskIndex);
   3683         if (_hMmTask)
   3684         {
   3685             if (!_PAvSetMmThreadPriority(_hMmTask, AVRT_PRIORITY_CRITICAL))
   3686             {
   3687                 WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
   3688                     "failed to boost rec-thread using MMCSS");
   3689             }
   3690             WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
   3691                 "capture thread is now registered with MMCSS (taskIndex=%d)",
   3692                 taskIndex);
   3693         }
   3694         else
   3695         {
   3696             WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
   3697                 "failed to enable MMCSS on capture thread (err=%d)",
   3698                 GetLastError());
   3699             _TraceCOMError(GetLastError());
   3700         }
   3701     }
   3702 
   3703     return S_OK;
   3704 }
   3705 
   3706 void AudioDeviceWindowsCore::RevertCaptureThreadPriority()
   3707 {
   3708     if (_winSupportAvrt)
   3709     {
   3710         if (NULL != _hMmTask)
   3711         {
   3712             _PAvRevertMmThreadCharacteristics(_hMmTask);
   3713         }
   3714     }
   3715 
   3716     _hMmTask = NULL;
   3717 }
   3718 
   3719 DWORD AudioDeviceWindowsCore::DoCaptureThreadPollDMO()
   3720 {
   3721     assert(_mediaBuffer != NULL);
   3722     bool keepRecording = true;
   3723 
   3724     // Initialize COM as MTA in this thread.
   3725     ScopedCOMInitializer comInit(ScopedCOMInitializer::kMTA);
   3726     if (!comInit.succeeded()) {
   3727       WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   3728         "failed to initialize COM in polling DMO thread");
   3729       return -1;
   3730     }
   3731 
   3732     HRESULT hr = InitCaptureThreadPriority();
   3733     if (FAILED(hr))
   3734     {
   3735         return hr;
   3736     }
   3737 
   3738     // Set event which will ensure that the calling thread modifies the
   3739     // recording state to true.
   3740     SetEvent(_hCaptureStartedEvent);
   3741 
   3742     // >> ---------------------------- THREAD LOOP ----------------------------
   3743     while (keepRecording)
   3744     {
   3745         // Poll the DMO every 5 ms.
   3746         // (The same interval used in the Wave implementation.)
   3747         DWORD waitResult = WaitForSingleObject(_hShutdownCaptureEvent, 5);
   3748         switch (waitResult)
   3749         {
   3750         case WAIT_OBJECT_0:         // _hShutdownCaptureEvent
   3751             keepRecording = false;
   3752             break;
   3753         case WAIT_TIMEOUT:          // timeout notification
   3754             break;
   3755         default:                    // unexpected error
   3756             WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id,
   3757                 "Unknown wait termination on capture side");
   3758             hr = -1; // To signal an error callback.
   3759             keepRecording = false;
   3760             break;
   3761         }
   3762 
   3763         while (keepRecording)
   3764         {
   3765             CriticalSectionScoped critScoped(&_critSect);
   3766 
   3767             DWORD dwStatus = 0;
   3768             {
   3769                 DMO_OUTPUT_DATA_BUFFER dmoBuffer = {0};
   3770                 dmoBuffer.pBuffer = _mediaBuffer;
   3771                 dmoBuffer.pBuffer->AddRef();
   3772 
   3773                 // Poll the DMO for AEC processed capture data. The DMO will
   3774                 // copy available data to |dmoBuffer|, and should only return
   3775                 // 10 ms frames. The value of |dwStatus| should be ignored.
   3776                 hr = _dmo->ProcessOutput(0, 1, &dmoBuffer, &dwStatus);
   3777                 SAFE_RELEASE(dmoBuffer.pBuffer);
   3778                 dwStatus = dmoBuffer.dwStatus;
   3779             }
   3780             if (FAILED(hr))
   3781             {
   3782                 _TraceCOMError(hr);
   3783                 keepRecording = false;
   3784                 assert(false);
   3785                 break;
   3786             }
   3787 
   3788             ULONG bytesProduced = 0;
   3789             BYTE* data;
   3790             // Get a pointer to the data buffer. This should be valid until
   3791             // the next call to ProcessOutput.
   3792             hr = _mediaBuffer->GetBufferAndLength(&data, &bytesProduced);
   3793             if (FAILED(hr))
   3794             {
   3795                 _TraceCOMError(hr);
   3796                 keepRecording = false;
   3797                 assert(false);
   3798                 break;
   3799             }
   3800 
   3801             // TODO(andrew): handle AGC.
   3802 
   3803             if (bytesProduced > 0)
   3804             {
   3805                 const int kSamplesProduced = bytesProduced / _recAudioFrameSize;
   3806                 // TODO(andrew): verify that this is always satisfied. It might
   3807                 // be that ProcessOutput will try to return more than 10 ms if
   3808                 // we fail to call it frequently enough.
   3809                 assert(kSamplesProduced == static_cast<int>(_recBlockSize));
   3810                 assert(sizeof(BYTE) == sizeof(int8_t));
   3811                 _ptrAudioBuffer->SetRecordedBuffer(
   3812                     reinterpret_cast<int8_t*>(data),
   3813                     kSamplesProduced);
   3814                 _ptrAudioBuffer->SetVQEData(0, 0, 0);
   3815 
   3816                 _UnLock();  // Release lock while making the callback.
   3817                 _ptrAudioBuffer->DeliverRecordedData();
   3818                 _Lock();
   3819             }
   3820 
   3821             // Reset length to indicate buffer availability.
   3822             hr = _mediaBuffer->SetLength(0);
   3823             if (FAILED(hr))
   3824             {
   3825                 _TraceCOMError(hr);
   3826                 keepRecording = false;
   3827                 assert(false);
   3828                 break;
   3829             }
   3830 
   3831             if (!(dwStatus & DMO_OUTPUT_DATA_BUFFERF_INCOMPLETE))
   3832             {
   3833                 // The DMO cannot currently produce more data. This is the
   3834                 // normal case; otherwise it means the DMO had more than 10 ms
   3835                 // of data available and ProcessOutput should be called again.
   3836                 break;
   3837             }
   3838         }
   3839     }
   3840     // ---------------------------- THREAD LOOP ---------------------------- <<
   3841 
   3842     RevertCaptureThreadPriority();
   3843 
   3844     if (FAILED(hr))
   3845     {
   3846         // Trigger callback from module process thread
   3847         _recError = 1;
   3848         WEBRTC_TRACE(kTraceError, kTraceUtility, _id,
   3849             "kRecordingError message posted: capturing thread has ended "
   3850             "prematurely");
   3851     }
   3852     else
   3853     {
   3854         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
   3855             "Capturing thread is now terminated properly");
   3856     }
   3857 
   3858     return hr;
   3859 }
   3860 
   3861 
   3862 // ----------------------------------------------------------------------------
   3863 //  DoCaptureThread
   3864 // ----------------------------------------------------------------------------
   3865 
   3866 DWORD AudioDeviceWindowsCore::DoCaptureThread()
   3867 {
   3868 
   3869     bool keepRecording = true;
   3870     HANDLE waitArray[2] = {_hShutdownCaptureEvent, _hCaptureSamplesReadyEvent};
   3871     HRESULT hr = S_OK;
   3872 
   3873     LARGE_INTEGER t1;
   3874     LARGE_INTEGER t2;
   3875     int32_t time(0);
   3876 
   3877     BYTE* syncBuffer = NULL;
   3878     UINT32 syncBufIndex = 0;
   3879 
   3880     _readSamples = 0;
   3881 
   3882     // Initialize COM as MTA in this thread.
   3883     ScopedCOMInitializer comInit(ScopedCOMInitializer::kMTA);
   3884     if (!comInit.succeeded()) {
   3885       WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   3886         "failed to initialize COM in capture thread");
   3887       return -1;
   3888     }
   3889 
   3890     hr = InitCaptureThreadPriority();
   3891     if (FAILED(hr))
   3892     {
   3893         return hr;
   3894     }
   3895 
   3896     _Lock();
   3897 
   3898     // Get size of capturing buffer (length is expressed as the number of audio frames the buffer can hold).
   3899     // This value is fixed during the capturing session.
   3900     //
   3901     UINT32 bufferLength = 0;
   3902     hr = _ptrClientIn->GetBufferSize(&bufferLength);
   3903     EXIT_ON_ERROR(hr);
   3904     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "[CAPT] size of buffer       : %u", bufferLength);
   3905 
   3906     // Allocate memory for sync buffer.
   3907     // It is used for compensation between native 44.1 and internal 44.0 and
   3908     // for cases when the capture buffer is larger than 10ms.
   3909     //
   3910     const UINT32 syncBufferSize = 2*(bufferLength * _recAudioFrameSize);
   3911     syncBuffer = new BYTE[syncBufferSize];
   3912     if (syncBuffer == NULL)
   3913     {
   3914         return E_POINTER;
   3915     }
   3916     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "[CAPT] size of sync buffer  : %u [bytes]", syncBufferSize);
   3917 
   3918     // Get maximum latency for the current stream (will not change for the lifetime of the IAudioClient object).
   3919     //
   3920     REFERENCE_TIME latency;
   3921     _ptrClientIn->GetStreamLatency(&latency);
   3922     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "[CAPT] max stream latency   : %u (%3.2f ms)",
   3923         (DWORD)latency, (double)(latency / 10000.0));
   3924 
   3925     // Get the length of the periodic interval separating successive processing passes by
   3926     // the audio engine on the data in the endpoint buffer.
   3927     //
   3928     REFERENCE_TIME devPeriod = 0;
   3929     REFERENCE_TIME devPeriodMin = 0;
   3930     _ptrClientIn->GetDevicePeriod(&devPeriod, &devPeriodMin);
   3931     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "[CAPT] device period        : %u (%3.2f ms)",
   3932         (DWORD)devPeriod, (double)(devPeriod / 10000.0));
   3933 
   3934     double extraDelayMS = (double)((latency + devPeriod) / 10000.0);
   3935     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "[CAPT] extraDelayMS         : %3.2f", extraDelayMS);
   3936 
   3937     double endpointBufferSizeMS = 10.0 * ((double)bufferLength / (double)_recBlockSize);
   3938     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "[CAPT] endpointBufferSizeMS : %3.2f", endpointBufferSizeMS);
   3939 
   3940     // Start up the capturing stream.
   3941     //
   3942     hr = _ptrClientIn->Start();
   3943     EXIT_ON_ERROR(hr);
   3944 
   3945     _UnLock();
   3946 
   3947     // Set event which will ensure that the calling thread modifies the recording state to true.
   3948     //
   3949     SetEvent(_hCaptureStartedEvent);
   3950 
   3951     // >> ---------------------------- THREAD LOOP ----------------------------
   3952 
   3953     while (keepRecording)
   3954     {
   3955         // Wait for a capture notification event or a shutdown event
   3956         DWORD waitResult = WaitForMultipleObjects(2, waitArray, FALSE, 500);
   3957         switch (waitResult)
   3958         {
   3959         case WAIT_OBJECT_0 + 0:        // _hShutdownCaptureEvent
   3960             keepRecording = false;
   3961             break;
   3962         case WAIT_OBJECT_0 + 1:        // _hCaptureSamplesReadyEvent
   3963             break;
   3964         case WAIT_TIMEOUT:            // timeout notification
   3965             WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "capture event timed out after 0.5 seconds");
   3966             goto Exit;
   3967         default:                    // unexpected error
   3968             WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "unknown wait termination on capture side");
   3969             goto Exit;
   3970         }
   3971 
   3972         while (keepRecording)
   3973         {
   3974             BYTE *pData = 0;
   3975             UINT32 framesAvailable = 0;
   3976             DWORD flags = 0;
   3977             UINT64 recTime = 0;
   3978             UINT64 recPos = 0;
   3979 
   3980             _Lock();
   3981 
   3982             // Sanity check to ensure that essential states are not modified
   3983             // during the unlocked period.
   3984             if (_ptrCaptureClient == NULL || _ptrClientIn == NULL)
   3985             {
   3986                 _UnLock();
   3987                 WEBRTC_TRACE(kTraceCritical, kTraceAudioDevice, _id,
   3988                     "input state has been modified during unlocked period");
   3989                 goto Exit;
   3990             }
   3991 
   3992             //  Find out how much capture data is available
   3993             //
   3994             hr = _ptrCaptureClient->GetBuffer(&pData,           // packet which is ready to be read by used
   3995                                               &framesAvailable, // #frames in the captured packet (can be zero)
   3996                                               &flags,           // support flags (check)
   3997                                               &recPos,          // device position of first audio frame in data packet
   3998                                               &recTime);        // value of performance counter at the time of recording the first audio frame
   3999 
   4000             if (SUCCEEDED(hr))
   4001             {
   4002                 if (AUDCLNT_S_BUFFER_EMPTY == hr)
   4003                 {
   4004                     // Buffer was empty => start waiting for a new capture notification event
   4005                     _UnLock();
   4006                     break;
   4007                 }
   4008 
   4009                 if (flags & AUDCLNT_BUFFERFLAGS_SILENT)
   4010                 {
   4011                     // Treat all of the data in the packet as silence and ignore the actual data values.
   4012                     WEBRTC_TRACE(kTraceWarning, kTraceAudioDevice, _id, "AUDCLNT_BUFFERFLAGS_SILENT");
   4013                     pData = NULL;
   4014                 }
   4015 
   4016                 assert(framesAvailable != 0);
   4017 
   4018                 if (pData)
   4019                 {
   4020                     CopyMemory(&syncBuffer[syncBufIndex*_recAudioFrameSize], pData, framesAvailable*_recAudioFrameSize);
   4021                 }
   4022                 else
   4023                 {
   4024                     ZeroMemory(&syncBuffer[syncBufIndex*_recAudioFrameSize], framesAvailable*_recAudioFrameSize);
   4025                 }
   4026                 assert(syncBufferSize >= (syncBufIndex*_recAudioFrameSize)+framesAvailable*_recAudioFrameSize);
   4027 
   4028                 // Release the capture buffer
   4029                 //
   4030                 hr = _ptrCaptureClient->ReleaseBuffer(framesAvailable);
   4031                 EXIT_ON_ERROR(hr);
   4032 
   4033                 _readSamples += framesAvailable;
   4034                 syncBufIndex += framesAvailable;
   4035 
   4036                 QueryPerformanceCounter(&t1);
   4037 
   4038                 // Get the current recording and playout delay.
   4039                 uint32_t sndCardRecDelay = (uint32_t)
   4040                     (((((UINT64)t1.QuadPart * _perfCounterFactor) - recTime)
   4041                         / 10000) + (10*syncBufIndex) / _recBlockSize - 10);
   4042                 uint32_t sndCardPlayDelay =
   4043                     static_cast<uint32_t>(_sndCardPlayDelay);
   4044 
   4045                 _sndCardRecDelay = sndCardRecDelay;
   4046 
   4047                 while (syncBufIndex >= _recBlockSize)
   4048                 {
   4049                     if (_ptrAudioBuffer)
   4050                     {
   4051                         _ptrAudioBuffer->SetRecordedBuffer((const int8_t*)syncBuffer, _recBlockSize);
   4052                         _ptrAudioBuffer->SetVQEData(sndCardPlayDelay,
   4053                                                     sndCardRecDelay,
   4054                                                     0);
   4055 
   4056                         _ptrAudioBuffer->SetTypingStatus(KeyPressed());
   4057 
   4058                         QueryPerformanceCounter(&t1);    // measure time: START
   4059 
   4060                         _UnLock();  // release lock while making the callback
   4061                         _ptrAudioBuffer->DeliverRecordedData();
   4062                         _Lock();    // restore the lock
   4063 
   4064                         QueryPerformanceCounter(&t2);    // measure time: STOP
   4065 
   4066                         // Measure "average CPU load".
   4067                         // Basically what we do here is to measure how many percent of our 10ms period
   4068                         // is used for encoding and decoding. This value shuld be used as a warning indicator
   4069                         // only and not seen as an absolute value. Running at ~100% will lead to bad QoS.
   4070                         time = (int)(t2.QuadPart - t1.QuadPart);
   4071                         _avgCPULoad = (float)(_avgCPULoad*.99 + (time + _playAcc) / (double)(_perfCounterFreq.QuadPart));
   4072                         _playAcc = 0;
   4073 
   4074                         // Sanity check to ensure that essential states are not modified during the unlocked period
   4075                         if (_ptrCaptureClient == NULL || _ptrClientIn == NULL)
   4076                         {
   4077                             _UnLock();
   4078                             WEBRTC_TRACE(kTraceCritical, kTraceAudioDevice, _id, "input state has been modified during unlocked period");
   4079                             goto Exit;
   4080                         }
   4081                     }
   4082 
   4083                     // store remaining data which was not able to deliver as 10ms segment
   4084                     MoveMemory(&syncBuffer[0], &syncBuffer[_recBlockSize*_recAudioFrameSize], (syncBufIndex-_recBlockSize)*_recAudioFrameSize);
   4085                     syncBufIndex -= _recBlockSize;
   4086                     sndCardRecDelay -= 10;
   4087                 }
   4088 
   4089                 if (_AGC)
   4090                 {
   4091                     uint32_t newMicLevel = _ptrAudioBuffer->NewMicLevel();
   4092                     if (newMicLevel != 0)
   4093                     {
   4094                         // The VQE will only deliver non-zero microphone levels when a change is needed.
   4095                         // Set this new mic level (received from the observer as return value in the callback).
   4096                         WEBRTC_TRACE(kTraceStream, kTraceAudioDevice, _id, "AGC change of volume: new=%u",  newMicLevel);
   4097                         // We store this outside of the audio buffer to avoid
   4098                         // having it overwritten by the getter thread.
   4099                         _newMicLevel = newMicLevel;
   4100                         SetEvent(_hSetCaptureVolumeEvent);
   4101                     }
   4102                 }
   4103             }
   4104             else
   4105             {
   4106                 // If GetBuffer returns AUDCLNT_E_BUFFER_ERROR, the thread consuming the audio samples
   4107                 // must wait for the next processing pass. The client might benefit from keeping a count
   4108                 // of the failed GetBuffer calls. If GetBuffer returns this error repeatedly, the client
   4109                 // can start a new processing loop after shutting down the current client by calling
   4110                 // IAudioClient::Stop, IAudioClient::Reset, and releasing the audio client.
   4111                 WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   4112                     "IAudioCaptureClient::GetBuffer returned AUDCLNT_E_BUFFER_ERROR, hr = 0x%08X",  hr);
   4113                 goto Exit;
   4114             }
   4115 
   4116             _UnLock();
   4117         }
   4118     }
   4119 
   4120     // ---------------------------- THREAD LOOP ---------------------------- <<
   4121 
   4122     hr = _ptrClientIn->Stop();
   4123 
   4124 Exit:
   4125     if (FAILED(hr))
   4126     {
   4127         _ptrClientIn->Stop();
   4128         _UnLock();
   4129         _TraceCOMError(hr);
   4130     }
   4131 
   4132     RevertCaptureThreadPriority();
   4133 
   4134     _Lock();
   4135 
   4136     if (keepRecording)
   4137     {
   4138         if (_ptrClientIn != NULL)
   4139         {
   4140             hr = _ptrClientIn->Stop();
   4141             if (FAILED(hr))
   4142             {
   4143                 _TraceCOMError(hr);
   4144             }
   4145             hr = _ptrClientIn->Reset();
   4146             if (FAILED(hr))
   4147             {
   4148                 _TraceCOMError(hr);
   4149             }
   4150         }
   4151 
   4152         // Trigger callback from module process thread
   4153         _recError = 1;
   4154         WEBRTC_TRACE(kTraceError, kTraceUtility, _id, "kRecordingError message posted: capturing thread has ended pre-maturely");
   4155     }
   4156     else
   4157     {
   4158         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "_Capturing thread is now terminated properly");
   4159     }
   4160 
   4161     SAFE_RELEASE(_ptrClientIn);
   4162     SAFE_RELEASE(_ptrCaptureClient);
   4163 
   4164     _UnLock();
   4165 
   4166     if (syncBuffer)
   4167     {
   4168         delete [] syncBuffer;
   4169     }
   4170 
   4171     return (DWORD)hr;
   4172 }
   4173 
   4174 int32_t AudioDeviceWindowsCore::EnableBuiltInAEC(bool enable)
   4175 {
   4176 
   4177     if (_recIsInitialized)
   4178     {
   4179         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   4180             "Attempt to set Windows AEC with recording already initialized");
   4181         return -1;
   4182     }
   4183 
   4184     if (_dmo == NULL)
   4185     {
   4186         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   4187             "Built-in AEC DMO was not initialized properly at create time");
   4188         return -1;
   4189     }
   4190 
   4191     _builtInAecEnabled = enable;
   4192     return 0;
   4193 }
   4194 
   4195 bool AudioDeviceWindowsCore::BuiltInAECIsEnabled() const
   4196 {
   4197     return _builtInAecEnabled;
   4198 }
   4199 
   4200 int AudioDeviceWindowsCore::SetDMOProperties()
   4201 {
   4202     HRESULT hr = S_OK;
   4203     assert(_dmo != NULL);
   4204 
   4205     scoped_refptr<IPropertyStore> ps;
   4206     {
   4207         IPropertyStore* ptrPS = NULL;
   4208         hr = _dmo->QueryInterface(IID_IPropertyStore,
   4209                                   reinterpret_cast<void**>(&ptrPS));
   4210         if (FAILED(hr) || ptrPS == NULL)
   4211         {
   4212             _TraceCOMError(hr);
   4213             return -1;
   4214         }
   4215         ps = ptrPS;
   4216         SAFE_RELEASE(ptrPS);
   4217     }
   4218 
   4219     // Set the AEC system mode.
   4220     // SINGLE_CHANNEL_AEC - AEC processing only.
   4221     if (SetVtI4Property(ps,
   4222                         MFPKEY_WMAAECMA_SYSTEM_MODE,
   4223                         SINGLE_CHANNEL_AEC))
   4224     {
   4225         return -1;
   4226     }
   4227 
   4228     // Set the AEC source mode.
   4229     // VARIANT_TRUE - Source mode (we poll the AEC for captured data).
   4230     if (SetBoolProperty(ps,
   4231                         MFPKEY_WMAAECMA_DMO_SOURCE_MODE,
   4232                         VARIANT_TRUE) == -1)
   4233     {
   4234         return -1;
   4235     }
   4236 
   4237     // Enable the feature mode.
   4238     // This lets us override all the default processing settings below.
   4239     if (SetBoolProperty(ps,
   4240                         MFPKEY_WMAAECMA_FEATURE_MODE,
   4241                         VARIANT_TRUE) == -1)
   4242     {
   4243         return -1;
   4244     }
   4245 
   4246     // Disable analog AGC (default enabled).
   4247     if (SetBoolProperty(ps,
   4248                         MFPKEY_WMAAECMA_MIC_GAIN_BOUNDER,
   4249                         VARIANT_FALSE) == -1)
   4250     {
   4251         return -1;
   4252     }
   4253 
   4254     // Disable noise suppression (default enabled).
   4255     // 0 - Disabled, 1 - Enabled
   4256     if (SetVtI4Property(ps,
   4257                         MFPKEY_WMAAECMA_FEATR_NS,
   4258                         0) == -1)
   4259     {
   4260         return -1;
   4261     }
   4262 
   4263     // Relevant parameters to leave at default settings:
   4264     // MFPKEY_WMAAECMA_FEATR_AGC - Digital AGC (disabled).
   4265     // MFPKEY_WMAAECMA_FEATR_CENTER_CLIP - AEC center clipping (enabled).
   4266     // MFPKEY_WMAAECMA_FEATR_ECHO_LENGTH - Filter length (256 ms).
   4267     //   TODO(andrew): investigate decresing the length to 128 ms.
   4268     // MFPKEY_WMAAECMA_FEATR_FRAME_SIZE - Frame size (0).
   4269     //   0 is automatic; defaults to 160 samples (or 10 ms frames at the
   4270     //   selected 16 kHz) as long as mic array processing is disabled.
   4271     // MFPKEY_WMAAECMA_FEATR_NOISE_FILL - Comfort noise (enabled).
   4272     // MFPKEY_WMAAECMA_FEATR_VAD - VAD (disabled).
   4273 
   4274     // Set the devices selected by VoE. If using a default device, we need to
   4275     // search for the device index.
   4276     int inDevIndex = _inputDeviceIndex;
   4277     int outDevIndex = _outputDeviceIndex;
   4278     if (!_usingInputDeviceIndex)
   4279     {
   4280         ERole role = eCommunications;
   4281         if (_inputDevice == AudioDeviceModule::kDefaultDevice)
   4282         {
   4283             role = eConsole;
   4284         }
   4285 
   4286         if (_GetDefaultDeviceIndex(eCapture, role, &inDevIndex) == -1)
   4287         {
   4288             return -1;
   4289         }
   4290     }
   4291 
   4292     if (!_usingOutputDeviceIndex)
   4293     {
   4294         ERole role = eCommunications;
   4295         if (_outputDevice == AudioDeviceModule::kDefaultDevice)
   4296         {
   4297             role = eConsole;
   4298         }
   4299 
   4300         if (_GetDefaultDeviceIndex(eRender, role, &outDevIndex) == -1)
   4301         {
   4302             return -1;
   4303         }
   4304     }
   4305 
   4306     DWORD devIndex = static_cast<uint32_t>(outDevIndex << 16) +
   4307                      static_cast<uint32_t>(0x0000ffff & inDevIndex);
   4308     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
   4309         "Capture device index: %d, render device index: %d",
   4310         inDevIndex, outDevIndex);
   4311     if (SetVtI4Property(ps,
   4312                         MFPKEY_WMAAECMA_DEVICE_INDEXES,
   4313                         devIndex) == -1)
   4314     {
   4315         return -1;
   4316     }
   4317 
   4318     return 0;
   4319 }
   4320 
   4321 int AudioDeviceWindowsCore::SetBoolProperty(IPropertyStore* ptrPS,
   4322                                             REFPROPERTYKEY key,
   4323                                             VARIANT_BOOL value)
   4324 {
   4325     PROPVARIANT pv;
   4326     PropVariantInit(&pv);
   4327     pv.vt = VT_BOOL;
   4328     pv.boolVal = value;
   4329     HRESULT hr = ptrPS->SetValue(key, pv);
   4330     PropVariantClear(&pv);
   4331     if (FAILED(hr))
   4332     {
   4333         _TraceCOMError(hr);
   4334         return -1;
   4335     }
   4336     return 0;
   4337 }
   4338 
   4339 int AudioDeviceWindowsCore::SetVtI4Property(IPropertyStore* ptrPS,
   4340                                             REFPROPERTYKEY key,
   4341                                             LONG value)
   4342 {
   4343     PROPVARIANT pv;
   4344     PropVariantInit(&pv);
   4345     pv.vt = VT_I4;
   4346     pv.lVal = value;
   4347     HRESULT hr = ptrPS->SetValue(key, pv);
   4348     PropVariantClear(&pv);
   4349     if (FAILED(hr))
   4350     {
   4351         _TraceCOMError(hr);
   4352         return -1;
   4353     }
   4354     return 0;
   4355 }
   4356 
   4357 // ----------------------------------------------------------------------------
   4358 //  _RefreshDeviceList
   4359 //
   4360 //  Creates a new list of endpoint rendering or capture devices after
   4361 //  deleting any previously created (and possibly out-of-date) list of
   4362 //  such devices.
   4363 // ----------------------------------------------------------------------------
   4364 
   4365 int32_t AudioDeviceWindowsCore::_RefreshDeviceList(EDataFlow dir)
   4366 {
   4367     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", __FUNCTION__);
   4368 
   4369     HRESULT hr = S_OK;
   4370     IMMDeviceCollection *pCollection = NULL;
   4371 
   4372     assert(dir == eRender || dir == eCapture);
   4373     assert(_ptrEnumerator != NULL);
   4374 
   4375     // Create a fresh list of devices using the specified direction
   4376     hr = _ptrEnumerator->EnumAudioEndpoints(
   4377                            dir,
   4378                            DEVICE_STATE_ACTIVE,
   4379                            &pCollection);
   4380     if (FAILED(hr))
   4381     {
   4382         _TraceCOMError(hr);
   4383         SAFE_RELEASE(pCollection);
   4384         return -1;
   4385     }
   4386 
   4387     if (dir == eRender)
   4388     {
   4389         SAFE_RELEASE(_ptrRenderCollection);
   4390         _ptrRenderCollection = pCollection;
   4391     }
   4392     else
   4393     {
   4394         SAFE_RELEASE(_ptrCaptureCollection);
   4395         _ptrCaptureCollection = pCollection;
   4396     }
   4397 
   4398     return 0;
   4399 }
   4400 
   4401 // ----------------------------------------------------------------------------
   4402 //  _DeviceListCount
   4403 //
   4404 //  Gets a count of the endpoint rendering or capture devices in the
   4405 //  current list of such devices.
   4406 // ----------------------------------------------------------------------------
   4407 
   4408 int16_t AudioDeviceWindowsCore::_DeviceListCount(EDataFlow dir)
   4409 {
   4410     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", __FUNCTION__);
   4411 
   4412     HRESULT hr = S_OK;
   4413     UINT count = 0;
   4414 
   4415     assert(eRender == dir || eCapture == dir);
   4416 
   4417     if (eRender == dir && NULL != _ptrRenderCollection)
   4418     {
   4419         hr = _ptrRenderCollection->GetCount(&count);
   4420     }
   4421     else if (NULL != _ptrCaptureCollection)
   4422     {
   4423         hr = _ptrCaptureCollection->GetCount(&count);
   4424     }
   4425 
   4426     if (FAILED(hr))
   4427     {
   4428         _TraceCOMError(hr);
   4429         return -1;
   4430     }
   4431 
   4432     return static_cast<int16_t> (count);
   4433 }
   4434 
   4435 // ----------------------------------------------------------------------------
   4436 //  _GetListDeviceName
   4437 //
   4438 //  Gets the friendly name of an endpoint rendering or capture device
   4439 //  from the current list of such devices. The caller uses an index
   4440 //  into the list to identify the device.
   4441 //
   4442 //  Uses: _ptrRenderCollection or _ptrCaptureCollection which is updated
   4443 //  in _RefreshDeviceList().
   4444 // ----------------------------------------------------------------------------
   4445 
   4446 int32_t AudioDeviceWindowsCore::_GetListDeviceName(EDataFlow dir, int index, LPWSTR szBuffer, int bufferLen)
   4447 {
   4448     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", __FUNCTION__);
   4449 
   4450     HRESULT hr = S_OK;
   4451     IMMDevice *pDevice = NULL;
   4452 
   4453     assert(dir == eRender || dir == eCapture);
   4454 
   4455     if (eRender == dir && NULL != _ptrRenderCollection)
   4456     {
   4457         hr = _ptrRenderCollection->Item(index, &pDevice);
   4458     }
   4459     else if (NULL != _ptrCaptureCollection)
   4460     {
   4461         hr = _ptrCaptureCollection->Item(index, &pDevice);
   4462     }
   4463 
   4464     if (FAILED(hr))
   4465     {
   4466         _TraceCOMError(hr);
   4467         SAFE_RELEASE(pDevice);
   4468         return -1;
   4469     }
   4470 
   4471     int32_t res = _GetDeviceName(pDevice, szBuffer, bufferLen);
   4472     SAFE_RELEASE(pDevice);
   4473     return res;
   4474 }
   4475 
   4476 // ----------------------------------------------------------------------------
   4477 //  _GetDefaultDeviceName
   4478 //
   4479 //  Gets the friendly name of an endpoint rendering or capture device
   4480 //  given a specified device role.
   4481 //
   4482 //  Uses: _ptrEnumerator
   4483 // ----------------------------------------------------------------------------
   4484 
   4485 int32_t AudioDeviceWindowsCore::_GetDefaultDeviceName(EDataFlow dir, ERole role, LPWSTR szBuffer, int bufferLen)
   4486 {
   4487     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", __FUNCTION__);
   4488 
   4489     HRESULT hr = S_OK;
   4490     IMMDevice *pDevice = NULL;
   4491 
   4492     assert(dir == eRender || dir == eCapture);
   4493     assert(role == eConsole || role == eCommunications);
   4494     assert(_ptrEnumerator != NULL);
   4495 
   4496     hr = _ptrEnumerator->GetDefaultAudioEndpoint(
   4497                            dir,
   4498                            role,
   4499                            &pDevice);
   4500 
   4501     if (FAILED(hr))
   4502     {
   4503         _TraceCOMError(hr);
   4504         SAFE_RELEASE(pDevice);
   4505         return -1;
   4506     }
   4507 
   4508     int32_t res = _GetDeviceName(pDevice, szBuffer, bufferLen);
   4509     SAFE_RELEASE(pDevice);
   4510     return res;
   4511 }
   4512 
   4513 // ----------------------------------------------------------------------------
   4514 //  _GetListDeviceID
   4515 //
   4516 //  Gets the unique ID string of an endpoint rendering or capture device
   4517 //  from the current list of such devices. The caller uses an index
   4518 //  into the list to identify the device.
   4519 //
   4520 //  Uses: _ptrRenderCollection or _ptrCaptureCollection which is updated
   4521 //  in _RefreshDeviceList().
   4522 // ----------------------------------------------------------------------------
   4523 
   4524 int32_t AudioDeviceWindowsCore::_GetListDeviceID(EDataFlow dir, int index, LPWSTR szBuffer, int bufferLen)
   4525 {
   4526     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", __FUNCTION__);
   4527 
   4528     HRESULT hr = S_OK;
   4529     IMMDevice *pDevice = NULL;
   4530 
   4531     assert(dir == eRender || dir == eCapture);
   4532 
   4533     if (eRender == dir && NULL != _ptrRenderCollection)
   4534     {
   4535         hr = _ptrRenderCollection->Item(index, &pDevice);
   4536     }
   4537     else if (NULL != _ptrCaptureCollection)
   4538     {
   4539         hr = _ptrCaptureCollection->Item(index, &pDevice);
   4540     }
   4541 
   4542     if (FAILED(hr))
   4543     {
   4544         _TraceCOMError(hr);
   4545         SAFE_RELEASE(pDevice);
   4546         return -1;
   4547     }
   4548 
   4549     int32_t res = _GetDeviceID(pDevice, szBuffer, bufferLen);
   4550     SAFE_RELEASE(pDevice);
   4551     return res;
   4552 }
   4553 
   4554 // ----------------------------------------------------------------------------
   4555 //  _GetDefaultDeviceID
   4556 //
   4557 //  Gets the uniqe device ID of an endpoint rendering or capture device
   4558 //  given a specified device role.
   4559 //
   4560 //  Uses: _ptrEnumerator
   4561 // ----------------------------------------------------------------------------
   4562 
   4563 int32_t AudioDeviceWindowsCore::_GetDefaultDeviceID(EDataFlow dir, ERole role, LPWSTR szBuffer, int bufferLen)
   4564 {
   4565     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", __FUNCTION__);
   4566 
   4567     HRESULT hr = S_OK;
   4568     IMMDevice *pDevice = NULL;
   4569 
   4570     assert(dir == eRender || dir == eCapture);
   4571     assert(role == eConsole || role == eCommunications);
   4572     assert(_ptrEnumerator != NULL);
   4573 
   4574     hr = _ptrEnumerator->GetDefaultAudioEndpoint(
   4575                            dir,
   4576                            role,
   4577                            &pDevice);
   4578 
   4579     if (FAILED(hr))
   4580     {
   4581         _TraceCOMError(hr);
   4582         SAFE_RELEASE(pDevice);
   4583         return -1;
   4584     }
   4585 
   4586     int32_t res = _GetDeviceID(pDevice, szBuffer, bufferLen);
   4587     SAFE_RELEASE(pDevice);
   4588     return res;
   4589 }
   4590 
   4591 int32_t AudioDeviceWindowsCore::_GetDefaultDeviceIndex(EDataFlow dir,
   4592                                                        ERole role,
   4593                                                        int* index)
   4594 {
   4595     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", __FUNCTION__);
   4596 
   4597     HRESULT hr = S_OK;
   4598     WCHAR szDefaultDeviceID[MAX_PATH] = {0};
   4599     WCHAR szDeviceID[MAX_PATH] = {0};
   4600 
   4601     const size_t kDeviceIDLength = sizeof(szDeviceID)/sizeof(szDeviceID[0]);
   4602     assert(kDeviceIDLength ==
   4603         sizeof(szDefaultDeviceID) / sizeof(szDefaultDeviceID[0]));
   4604 
   4605     if (_GetDefaultDeviceID(dir,
   4606                             role,
   4607                             szDefaultDeviceID,
   4608                             kDeviceIDLength) == -1)
   4609     {
   4610         return -1;
   4611     }
   4612 
   4613     IMMDeviceCollection* collection = _ptrCaptureCollection;
   4614     if (dir == eRender)
   4615     {
   4616         collection = _ptrRenderCollection;
   4617     }
   4618 
   4619     if (!collection)
   4620     {
   4621         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   4622             "Device collection not valid");
   4623         return -1;
   4624     }
   4625 
   4626     UINT count = 0;
   4627     hr = collection->GetCount(&count);
   4628     if (FAILED(hr))
   4629     {
   4630         _TraceCOMError(hr);
   4631         return -1;
   4632     }
   4633 
   4634     *index = -1;
   4635     for (UINT i = 0; i < count; i++)
   4636     {
   4637         memset(szDeviceID, 0, sizeof(szDeviceID));
   4638         scoped_refptr<IMMDevice> device;
   4639         {
   4640             IMMDevice* ptrDevice = NULL;
   4641             hr = collection->Item(i, &ptrDevice);
   4642             if (FAILED(hr) || ptrDevice == NULL)
   4643             {
   4644                 _TraceCOMError(hr);
   4645                 return -1;
   4646             }
   4647             device = ptrDevice;
   4648             SAFE_RELEASE(ptrDevice);
   4649         }
   4650 
   4651         if (_GetDeviceID(device, szDeviceID, kDeviceIDLength) == -1)
   4652         {
   4653            return -1;
   4654         }
   4655 
   4656         if (wcsncmp(szDefaultDeviceID, szDeviceID, kDeviceIDLength) == 0)
   4657         {
   4658             // Found a match.
   4659             *index = i;
   4660             break;
   4661         }
   4662 
   4663     }
   4664 
   4665     if (*index == -1)
   4666     {
   4667         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   4668             "Unable to find collection index for default device");
   4669         return -1;
   4670     }
   4671 
   4672     return 0;
   4673 }
   4674 
   4675 // ----------------------------------------------------------------------------
   4676 //  _GetDeviceName
   4677 // ----------------------------------------------------------------------------
   4678 
   4679 int32_t AudioDeviceWindowsCore::_GetDeviceName(IMMDevice* pDevice,
   4680                                                LPWSTR pszBuffer,
   4681                                                int bufferLen)
   4682 {
   4683     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", __FUNCTION__);
   4684 
   4685     static const WCHAR szDefault[] = L"<Device not available>";
   4686 
   4687     HRESULT hr = E_FAIL;
   4688     IPropertyStore *pProps = NULL;
   4689     PROPVARIANT varName;
   4690 
   4691     assert(pszBuffer != NULL);
   4692     assert(bufferLen > 0);
   4693 
   4694     if (pDevice != NULL)
   4695     {
   4696         hr = pDevice->OpenPropertyStore(STGM_READ, &pProps);
   4697         if (FAILED(hr))
   4698         {
   4699             WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   4700                 "IMMDevice::OpenPropertyStore failed, hr = 0x%08X", hr);
   4701         }
   4702     }
   4703 
   4704     // Initialize container for property value.
   4705     PropVariantInit(&varName);
   4706 
   4707     if (SUCCEEDED(hr))
   4708     {
   4709         // Get the endpoint device's friendly-name property.
   4710         hr = pProps->GetValue(PKEY_Device_FriendlyName, &varName);
   4711         if (FAILED(hr))
   4712         {
   4713             WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   4714                 "IPropertyStore::GetValue failed, hr = 0x%08X", hr);
   4715         }
   4716     }
   4717 
   4718     if ((SUCCEEDED(hr)) && (VT_EMPTY == varName.vt))
   4719     {
   4720         hr = E_FAIL;
   4721         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   4722             "IPropertyStore::GetValue returned no value, hr = 0x%08X", hr);
   4723     }
   4724 
   4725     if ((SUCCEEDED(hr)) && (VT_LPWSTR != varName.vt))
   4726     {
   4727         // The returned value is not a wide null terminated string.
   4728         hr = E_UNEXPECTED;
   4729         WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   4730             "IPropertyStore::GetValue returned unexpected type, hr = 0x%08X", hr);
   4731     }
   4732 
   4733     if (SUCCEEDED(hr) && (varName.pwszVal != NULL))
   4734     {
   4735         // Copy the valid device name to the provided ouput buffer.
   4736         wcsncpy_s(pszBuffer, bufferLen, varName.pwszVal, _TRUNCATE);
   4737     }
   4738     else
   4739     {
   4740         // Failed to find the device name.
   4741         wcsncpy_s(pszBuffer, bufferLen, szDefault, _TRUNCATE);
   4742     }
   4743 
   4744     PropVariantClear(&varName);
   4745     SAFE_RELEASE(pProps);
   4746 
   4747     return 0;
   4748 }
   4749 
   4750 // ----------------------------------------------------------------------------
   4751 //  _GetDeviceID
   4752 // ----------------------------------------------------------------------------
   4753 
   4754 int32_t AudioDeviceWindowsCore::_GetDeviceID(IMMDevice* pDevice, LPWSTR pszBuffer, int bufferLen)
   4755 {
   4756     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", __FUNCTION__);
   4757 
   4758     static const WCHAR szDefault[] = L"<Device not available>";
   4759 
   4760     HRESULT hr = E_FAIL;
   4761     LPWSTR pwszID = NULL;
   4762 
   4763     assert(pszBuffer != NULL);
   4764     assert(bufferLen > 0);
   4765 
   4766     if (pDevice != NULL)
   4767     {
   4768         hr = pDevice->GetId(&pwszID);
   4769     }
   4770 
   4771     if (hr == S_OK)
   4772     {
   4773         // Found the device ID.
   4774         wcsncpy_s(pszBuffer, bufferLen, pwszID, _TRUNCATE);
   4775     }
   4776     else
   4777     {
   4778         // Failed to find the device ID.
   4779         wcsncpy_s(pszBuffer, bufferLen, szDefault, _TRUNCATE);
   4780     }
   4781 
   4782     CoTaskMemFree(pwszID);
   4783     return 0;
   4784 }
   4785 
   4786 // ----------------------------------------------------------------------------
   4787 //  _GetDefaultDevice
   4788 // ----------------------------------------------------------------------------
   4789 
   4790 int32_t AudioDeviceWindowsCore::_GetDefaultDevice(EDataFlow dir, ERole role, IMMDevice** ppDevice)
   4791 {
   4792     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", __FUNCTION__);
   4793 
   4794     HRESULT hr(S_OK);
   4795 
   4796     assert(_ptrEnumerator != NULL);
   4797 
   4798     hr = _ptrEnumerator->GetDefaultAudioEndpoint(
   4799                                    dir,
   4800                                    role,
   4801                                    ppDevice);
   4802     if (FAILED(hr))
   4803     {
   4804         _TraceCOMError(hr);
   4805         return -1;
   4806     }
   4807 
   4808     return 0;
   4809 }
   4810 
   4811 // ----------------------------------------------------------------------------
   4812 //  _GetListDevice
   4813 // ----------------------------------------------------------------------------
   4814 
   4815 int32_t AudioDeviceWindowsCore::_GetListDevice(EDataFlow dir, int index, IMMDevice** ppDevice)
   4816 {
   4817     HRESULT hr(S_OK);
   4818 
   4819     assert(_ptrEnumerator != NULL);
   4820 
   4821     IMMDeviceCollection *pCollection = NULL;
   4822 
   4823     hr = _ptrEnumerator->EnumAudioEndpoints(
   4824                                dir,
   4825                                DEVICE_STATE_ACTIVE,        // only active endpoints are OK
   4826                                &pCollection);
   4827     if (FAILED(hr))
   4828     {
   4829         _TraceCOMError(hr);
   4830         SAFE_RELEASE(pCollection);
   4831         return -1;
   4832     }
   4833 
   4834     hr = pCollection->Item(
   4835                         index,
   4836                         ppDevice);
   4837     if (FAILED(hr))
   4838     {
   4839         _TraceCOMError(hr);
   4840         SAFE_RELEASE(pCollection);
   4841         return -1;
   4842     }
   4843 
   4844     return 0;
   4845 }
   4846 
   4847 // ----------------------------------------------------------------------------
   4848 //  _EnumerateEndpointDevicesAll
   4849 // ----------------------------------------------------------------------------
   4850 
   4851 int32_t AudioDeviceWindowsCore::_EnumerateEndpointDevicesAll(EDataFlow dataFlow) const
   4852 {
   4853     WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "%s", __FUNCTION__);
   4854 
   4855     assert(_ptrEnumerator != NULL);
   4856 
   4857     HRESULT hr = S_OK;
   4858     IMMDeviceCollection *pCollection = NULL;
   4859     IMMDevice *pEndpoint = NULL;
   4860     IPropertyStore *pProps = NULL;
   4861     IAudioEndpointVolume* pEndpointVolume = NULL;
   4862     LPWSTR pwszID = NULL;
   4863 
   4864     // Generate a collection of audio endpoint devices in the system.
   4865     // Get states for *all* endpoint devices.
   4866     // Output: IMMDeviceCollection interface.
   4867     hr = _ptrEnumerator->EnumAudioEndpoints(
   4868                                  dataFlow,            // data-flow direction (input parameter)
   4869                                  DEVICE_STATE_ACTIVE | DEVICE_STATE_DISABLED | DEVICE_STATE_UNPLUGGED,
   4870                                  &pCollection);        // release interface when done
   4871 
   4872     EXIT_ON_ERROR(hr);
   4873 
   4874     // use the IMMDeviceCollection interface...
   4875 
   4876     UINT count = 0;
   4877 
   4878     // Retrieve a count of the devices in the device collection.
   4879     hr = pCollection->GetCount(&count);
   4880     EXIT_ON_ERROR(hr);
   4881     if (dataFlow == eRender)
   4882         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "#rendering endpoint devices (counting all): %u", count);
   4883     else if (dataFlow == eCapture)
   4884         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "#capturing endpoint devices (counting all): %u", count);
   4885 
   4886     if (count == 0)
   4887     {
   4888         return 0;
   4889     }
   4890 
   4891     // Each loop prints the name of an endpoint device.
   4892     for (ULONG i = 0; i < count; i++)
   4893     {
   4894         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "Endpoint %d:", i);
   4895 
   4896         // Get pointer to endpoint number i.
   4897         // Output: IMMDevice interface.
   4898         hr = pCollection->Item(
   4899                             i,
   4900                             &pEndpoint);
   4901         CONTINUE_ON_ERROR(hr);
   4902 
   4903         // use the IMMDevice interface of the specified endpoint device...
   4904 
   4905         // Get the endpoint ID string (uniquely identifies the device among all audio endpoint devices)
   4906         hr = pEndpoint->GetId(&pwszID);
   4907         CONTINUE_ON_ERROR(hr);
   4908         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "ID string    : %S", pwszID);
   4909 
   4910         // Retrieve an interface to the device's property store.
   4911         // Output: IPropertyStore interface.
   4912         hr = pEndpoint->OpenPropertyStore(
   4913                           STGM_READ,
   4914                           &pProps);
   4915         CONTINUE_ON_ERROR(hr);
   4916 
   4917         // use the IPropertyStore interface...
   4918 
   4919         PROPVARIANT varName;
   4920         // Initialize container for property value.
   4921         PropVariantInit(&varName);
   4922 
   4923         // Get the endpoint's friendly-name property.
   4924         // Example: "Speakers (Realtek High Definition Audio)"
   4925         hr = pProps->GetValue(
   4926                        PKEY_Device_FriendlyName,
   4927                        &varName);
   4928         CONTINUE_ON_ERROR(hr);
   4929         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "friendly name: \"%S\"", varName.pwszVal);
   4930 
   4931         // Get the endpoint's current device state
   4932         DWORD dwState;
   4933         hr = pEndpoint->GetState(&dwState);
   4934         CONTINUE_ON_ERROR(hr);
   4935         if (dwState & DEVICE_STATE_ACTIVE)
   4936             WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "state (0x%x)  : *ACTIVE*", dwState);
   4937         if (dwState & DEVICE_STATE_DISABLED)
   4938             WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "state (0x%x)  : DISABLED", dwState);
   4939         if (dwState & DEVICE_STATE_NOTPRESENT)
   4940             WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "state (0x%x)  : NOTPRESENT", dwState);
   4941         if (dwState & DEVICE_STATE_UNPLUGGED)
   4942             WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "state (0x%x)  : UNPLUGGED", dwState);
   4943 
   4944         // Check the hardware volume capabilities.
   4945         DWORD dwHwSupportMask = 0;
   4946         hr = pEndpoint->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_ALL,
   4947                                NULL, (void**)&pEndpointVolume);
   4948         CONTINUE_ON_ERROR(hr);
   4949         hr = pEndpointVolume->QueryHardwareSupport(&dwHwSupportMask);
   4950         CONTINUE_ON_ERROR(hr);
   4951         if (dwHwSupportMask & ENDPOINT_HARDWARE_SUPPORT_VOLUME)
   4952             // The audio endpoint device supports a hardware volume control
   4953             WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "hwmask (0x%x) : HARDWARE_SUPPORT_VOLUME", dwHwSupportMask);
   4954         if (dwHwSupportMask & ENDPOINT_HARDWARE_SUPPORT_MUTE)
   4955             // The audio endpoint device supports a hardware mute control
   4956             WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "hwmask (0x%x) : HARDWARE_SUPPORT_MUTE", dwHwSupportMask);
   4957         if (dwHwSupportMask & ENDPOINT_HARDWARE_SUPPORT_METER)
   4958             // The audio endpoint device supports a hardware peak meter
   4959             WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "hwmask (0x%x) : HARDWARE_SUPPORT_METER", dwHwSupportMask);
   4960 
   4961         // Check the channel count (#channels in the audio stream that enters or leaves the audio endpoint device)
   4962         UINT nChannelCount(0);
   4963         hr = pEndpointVolume->GetChannelCount(
   4964                                 &nChannelCount);
   4965         CONTINUE_ON_ERROR(hr);
   4966         WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "#channels    : %u", nChannelCount);
   4967 
   4968         if (dwHwSupportMask & ENDPOINT_HARDWARE_SUPPORT_VOLUME)
   4969         {
   4970             // Get the volume range.
   4971             float fLevelMinDB(0.0);
   4972             float fLevelMaxDB(0.0);
   4973             float fVolumeIncrementDB(0.0);
   4974             hr = pEndpointVolume->GetVolumeRange(
   4975                                     &fLevelMinDB,
   4976                                     &fLevelMaxDB,
   4977                                     &fVolumeIncrementDB);
   4978             CONTINUE_ON_ERROR(hr);
   4979             WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "volume range : %4.2f (min), %4.2f (max), %4.2f (inc) [dB]",
   4980                 fLevelMinDB, fLevelMaxDB, fVolumeIncrementDB);
   4981 
   4982             // The volume range from vmin = fLevelMinDB to vmax = fLevelMaxDB is divided
   4983             // into n uniform intervals of size vinc = fVolumeIncrementDB, where
   4984             // n = (vmax ?vmin) / vinc.
   4985             // The values vmin, vmax, and vinc are measured in decibels. The client can set
   4986             // the volume level to one of n + 1 discrete values in the range from vmin to vmax.
   4987             int n = (int)((fLevelMaxDB-fLevelMinDB)/fVolumeIncrementDB);
   4988             WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "#intervals   : %d", n);
   4989 
   4990             // Get information about the current step in the volume range.
   4991             // This method represents the volume level of the audio stream that enters or leaves
   4992             // the audio endpoint device as an index or "step" in a range of discrete volume levels.
   4993             // Output value nStepCount is the number of steps in the range. Output value nStep
   4994             // is the step index of the current volume level. If the number of steps is n = nStepCount,
   4995             // then step index nStep can assume values from 0 (minimum volume) to n ?1 (maximum volume).
   4996             UINT nStep(0);
   4997             UINT nStepCount(0);
   4998             hr = pEndpointVolume->GetVolumeStepInfo(
   4999                                     &nStep,
   5000                                     &nStepCount);
   5001             CONTINUE_ON_ERROR(hr);
   5002             WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id, "volume steps : %d (nStep), %d (nStepCount)", nStep, nStepCount);
   5003         }
   5004 Next:
   5005         if (FAILED(hr)) {
   5006           WEBRTC_TRACE(kTraceInfo, kTraceAudioDevice, _id,
   5007                        "Error when logging device information");
   5008         }
   5009         CoTaskMemFree(pwszID);
   5010         pwszID = NULL;
   5011         PropVariantClear(&varName);
   5012         SAFE_RELEASE(pProps);
   5013         SAFE_RELEASE(pEndpoint);
   5014         SAFE_RELEASE(pEndpointVolume);
   5015     }
   5016     SAFE_RELEASE(pCollection);
   5017     return 0;
   5018 
   5019 Exit:
   5020     _TraceCOMError(hr);
   5021     CoTaskMemFree(pwszID);
   5022     pwszID = NULL;
   5023     SAFE_RELEASE(pCollection);
   5024     SAFE_RELEASE(pEndpoint);
   5025     SAFE_RELEASE(pEndpointVolume);
   5026     SAFE_RELEASE(pProps);
   5027     return -1;
   5028 }
   5029 
   5030 // ----------------------------------------------------------------------------
   5031 //  _TraceCOMError
   5032 // ----------------------------------------------------------------------------
   5033 
   5034 void AudioDeviceWindowsCore::_TraceCOMError(HRESULT hr) const
   5035 {
   5036     TCHAR buf[MAXERRORLENGTH];
   5037     TCHAR errorText[MAXERRORLENGTH];
   5038 
   5039     const DWORD dwFlags = FORMAT_MESSAGE_FROM_SYSTEM |
   5040                           FORMAT_MESSAGE_IGNORE_INSERTS;
   5041     const DWORD dwLangID = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
   5042 
   5043     // Gets the system's human readable message string for this HRESULT.
   5044     // All error message in English by default.
   5045     DWORD messageLength = ::FormatMessageW(dwFlags,
   5046                                            0,
   5047                                            hr,
   5048                                            dwLangID,
   5049                                            errorText,
   5050                                            MAXERRORLENGTH,
   5051                                            NULL);
   5052 
   5053     assert(messageLength <= MAXERRORLENGTH);
   5054 
   5055     // Trims tailing white space (FormatMessage() leaves a trailing cr-lf.).
   5056     for (; messageLength && ::isspace(errorText[messageLength - 1]);
   5057          --messageLength)
   5058     {
   5059         errorText[messageLength - 1] = '\0';
   5060     }
   5061 
   5062     WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id,
   5063         "Core Audio method failed (hr=0x%x)", hr);
   5064     StringCchPrintf(buf, MAXERRORLENGTH, TEXT("Error details: "));
   5065     StringCchCat(buf, MAXERRORLENGTH, errorText);
   5066     WEBRTC_TRACE(kTraceError, kTraceAudioDevice, _id, "%s", WideToUTF8(buf));
   5067 }
   5068 
   5069 // ----------------------------------------------------------------------------
   5070 //  _SetThreadName
   5071 // ----------------------------------------------------------------------------
   5072 
   5073 void AudioDeviceWindowsCore::_SetThreadName(DWORD dwThreadID, LPCSTR szThreadName)
   5074 {
   5075     // See http://msdn.microsoft.com/en-us/library/xcb2z8hs(VS.71).aspx for details on the code
   5076     // in this function. Name of article is "Setting a Thread Name (Unmanaged)".
   5077 
   5078     THREADNAME_INFO info;
   5079     info.dwType = 0x1000;
   5080     info.szName = szThreadName;
   5081     info.dwThreadID = dwThreadID;
   5082     info.dwFlags = 0;
   5083 
   5084     __try
   5085     {
   5086         RaiseException( 0x406D1388, 0, sizeof(info)/sizeof(DWORD), (ULONG_PTR *)&info );
   5087     }
   5088     __except (EXCEPTION_CONTINUE_EXECUTION)
   5089     {
   5090     }
   5091 }
   5092 
   5093 // ----------------------------------------------------------------------------
   5094 //  WideToUTF8
   5095 // ----------------------------------------------------------------------------
   5096 
   5097 char* AudioDeviceWindowsCore::WideToUTF8(const TCHAR* src) const {
   5098 #ifdef UNICODE
   5099     const size_t kStrLen = sizeof(_str);
   5100     memset(_str, 0, kStrLen);
   5101     // Get required size (in bytes) to be able to complete the conversion.
   5102     int required_size = WideCharToMultiByte(CP_UTF8, 0, src, -1, _str, 0, 0, 0);
   5103     if (required_size <= kStrLen)
   5104     {
   5105         // Process the entire input string, including the terminating null char.
   5106         if (WideCharToMultiByte(CP_UTF8, 0, src, -1, _str, kStrLen, 0, 0) == 0)
   5107             memset(_str, 0, kStrLen);
   5108     }
   5109     return _str;
   5110 #else
   5111     return const_cast<char*>(src);
   5112 #endif
   5113 }
   5114 
   5115 
   5116 bool AudioDeviceWindowsCore::KeyPressed() const{
   5117 
   5118   int key_down = 0;
   5119   for (int key = VK_SPACE; key < VK_NUMLOCK; key++) {
   5120     short res = GetAsyncKeyState(key);
   5121     key_down |= res & 0x1; // Get the LSB
   5122   }
   5123   return (key_down > 0);
   5124 }
   5125 }  // namespace webrtc
   5126 
   5127 #endif  // WEBRTC_WINDOWS_CORE_AUDIO_BUILD
   5128