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