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