2 * Copyright (C) 2010-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
21 #include "AESinkWASAPI.h"
22 #include <Audioclient.h>
28 #include "../Utils/AEUtil.h"
29 #include "settings/AdvancedSettings.h"
30 #include "utils/StdString.h"
31 #include "utils/log.h"
32 #include "threads/SingleLock.h"
33 #include "utils/CharsetConverter.h"
34 #include "../Utils/AEDeviceInfo.h"
36 #include <mmdeviceapi.h>
37 #include "utils/StringUtils.h"
39 #pragma comment(lib, "Avrt.lib")
41 const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator);
42 const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator);
43 const IID IID_IAudioClient = __uuidof(IAudioClient);
44 const IID IID_IAudioRenderClient = __uuidof(IAudioRenderClient);
46 static const unsigned int WASAPISampleRateCount = 10;
47 static const unsigned int WASAPISampleRates[] = {384000, 192000, 176400, 96000, 88200, 48000, 44100, 32000, 22050, 11025};
49 #define WASAPI_SPEAKER_COUNT 21
50 static const unsigned int WASAPIChannelOrder[] = {AE_CH_RAW,
51 SPEAKER_FRONT_LEFT, SPEAKER_FRONT_RIGHT, SPEAKER_FRONT_CENTER,
52 SPEAKER_LOW_FREQUENCY, SPEAKER_BACK_LEFT, SPEAKER_BACK_RIGHT,
53 SPEAKER_FRONT_LEFT_OF_CENTER, SPEAKER_FRONT_RIGHT_OF_CENTER,
54 SPEAKER_BACK_CENTER, SPEAKER_SIDE_LEFT, SPEAKER_SIDE_RIGHT,
55 SPEAKER_TOP_FRONT_LEFT, SPEAKER_TOP_FRONT_RIGHT, SPEAKER_TOP_FRONT_CENTER,
56 SPEAKER_TOP_CENTER, SPEAKER_TOP_BACK_LEFT, SPEAKER_TOP_BACK_RIGHT,
57 SPEAKER_TOP_BACK_CENTER, SPEAKER_RESERVED, SPEAKER_RESERVED};
59 static const enum AEChannel AEChannelNames[] = {AE_CH_RAW,
60 AE_CH_FL, AE_CH_FR, AE_CH_FC,
61 AE_CH_LFE, AE_CH_BL, AE_CH_BR,
62 AE_CH_FLOC, AE_CH_FROC,
63 AE_CH_BC, AE_CH_SL, AE_CH_SR,
64 AE_CH_TFL, AE_CH_TFR, AE_CH_TFC ,
65 AE_CH_TC , AE_CH_TBL, AE_CH_TBR,
66 AE_CH_TBC, AE_CH_BLOC, AE_CH_BROC};
68 static const enum AEChannel layoutsList[][16] =
70 /* Most common configurations */
71 {AE_CH_FC, AE_CH_NULL}, // Mono
72 {AE_CH_FL, AE_CH_FR, AE_CH_NULL}, // Stereo
73 {AE_CH_FL, AE_CH_FR, AE_CH_BL, AE_CH_BR, AE_CH_NULL}, // Quad
74 {AE_CH_FL, AE_CH_FR, AE_CH_FC, AE_CH_BC, AE_CH_NULL}, // Surround
75 {AE_CH_FL, AE_CH_FR, AE_CH_FC, AE_CH_LFE, AE_CH_SL, AE_CH_SR, AE_CH_NULL}, // Standard 5.1
76 {AE_CH_FL, AE_CH_FR, AE_CH_FC, AE_CH_LFE, AE_CH_SL, AE_CH_SR, AE_CH_BL, AE_CH_BR, AE_CH_NULL}, // Standard 7.1
77 /* Less common configurations */
78 {AE_CH_FL, AE_CH_FR, AE_CH_LFE, AE_CH_NULL}, // 2.1
79 {AE_CH_FL, AE_CH_FR, AE_CH_FC, AE_CH_LFE, AE_CH_BL, AE_CH_BR, AE_CH_NULL}, // 5.1 wide (obsolete)
80 {AE_CH_FL, AE_CH_FR, AE_CH_FC, AE_CH_LFE, AE_CH_BL, AE_CH_BR, AE_CH_FLOC,AE_CH_FROC,AE_CH_NULL}, // 7.1 wide (obsolete)
81 /* Exotic configurations */
82 {AE_CH_FL, AE_CH_FR, AE_CH_FC, AE_CH_NULL}, // 3 front speakers
83 {AE_CH_FL, AE_CH_FR, AE_CH_FC, AE_CH_LFE, AE_CH_NULL}, // 3 front speakers + LFE
84 {AE_CH_FL, AE_CH_FR, AE_CH_BL, AE_CH_BR, AE_CH_LFE, AE_CH_NULL}, // Quad + LFE
85 {AE_CH_FL, AE_CH_FR, AE_CH_FC, AE_CH_BC, AE_CH_LFE, AE_CH_NULL}, // Surround + LFE
86 {AE_CH_FL, AE_CH_FR, AE_CH_FC, AE_CH_SL, AE_CH_SR, AE_CH_NULL}, // Standard 5.1 w/o LFE
87 {AE_CH_FL, AE_CH_FR, AE_CH_FC, AE_CH_BL, AE_CH_BR, AE_CH_NULL}, // 5.1 wide w/o LFE
88 {AE_CH_FL, AE_CH_FR, AE_CH_FC, AE_CH_SL, AE_CH_SR, AE_CH_BC, AE_CH_NULL}, // Standard 5.1 w/o LFE + Back Center
89 {AE_CH_FL, AE_CH_FR, AE_CH_FC, AE_CH_BL, AE_CH_BC, AE_CH_BR, AE_CH_NULL}, // 5.1 wide w/o LFE + Back Center
90 {AE_CH_FL, AE_CH_FR, AE_CH_FC, AE_CH_LFE, AE_CH_BL, AE_CH_BR, AE_CH_TC, AE_CH_NULL}, // DVD speakers
91 {AE_CH_FL, AE_CH_FR, AE_CH_FC, AE_CH_BL, AE_CH_BR, AE_CH_BC, AE_CH_LFE, AE_CH_NULL}, // 5.1 wide + Back Center
92 {AE_CH_FL, AE_CH_FR, AE_CH_FC, AE_CH_SL, AE_CH_SR, AE_CH_BL, AE_CH_BR, AE_CH_NULL}, // Standard 7.1 w/o LFE
93 {AE_CH_FL, AE_CH_FR, AE_CH_FC, AE_CH_BL, AE_CH_BR, AE_CH_FLOC,AE_CH_FROC,AE_CH_NULL}, // 7.1 wide w/o LFE
94 {AE_CH_FL, AE_CH_FR, AE_CH_FC, AE_CH_LFE, AE_CH_SL, AE_CH_SR, AE_CH_BL, AE_CH_BC, AE_CH_BR, AE_CH_NULL}, // Standard 7.1 + Back Center
95 {AE_CH_FL, AE_CH_FR, AE_CH_FC, AE_CH_LFE, AE_CH_SL, AE_CH_SR, AE_CH_BL, AE_CH_BR, AE_CH_FLOC,AE_CH_FROC,AE_CH_NULL}, // Standard 7.1 + front wide
96 {AE_CH_FL, AE_CH_FR, AE_CH_FC, AE_CH_LFE, AE_CH_SL, AE_CH_SR, AE_CH_BL, AE_CH_BR, AE_CH_TFL, AE_CH_TFR, AE_CH_NULL}, // Standard 7.1 + 2 front top
97 {AE_CH_FL, AE_CH_FR, AE_CH_FC, AE_CH_LFE, AE_CH_SL, AE_CH_SR, AE_CH_BL, AE_CH_BR, AE_CH_TFL, AE_CH_TFR, AE_CH_TFC, AE_CH_NULL}, // Standard 7.1 + 3 front top
98 {AE_CH_FL, AE_CH_FR, AE_CH_FC, AE_CH_LFE, AE_CH_SL, AE_CH_SR, AE_CH_BL, AE_CH_BR, AE_CH_TFL, AE_CH_TFR, AE_CH_TBL, AE_CH_TBR, AE_CH_NULL}, // Standard 7.1 + 2 front top + 2 back top
99 {AE_CH_FL, AE_CH_FR, AE_CH_FC, AE_CH_LFE, AE_CH_SL, AE_CH_SR, AE_CH_BL, AE_CH_BR, AE_CH_TFL, AE_CH_TFR, AE_CH_TFC, AE_CH_TBL, AE_CH_TBR, AE_CH_NULL}, // Standard 7.1 + 3 front top + 2 back top
100 {AE_CH_FL, AE_CH_FR, AE_CH_FC, AE_CH_LFE, AE_CH_SL, AE_CH_SR, AE_CH_BL, AE_CH_BR, AE_CH_TFL, AE_CH_TFR, AE_CH_TFC, AE_CH_TBL, AE_CH_TBR, AE_CH_TBC, AE_CH_NULL}, // Standard 7.1 + 3 front top + 3 back top
101 {AE_CH_FL, AE_CH_FR, AE_CH_FC, AE_CH_LFE, AE_CH_SL, AE_CH_SR, AE_CH_BL, AE_CH_BR, AE_CH_TFL, AE_CH_TFR, AE_CH_TFC, AE_CH_TBL, AE_CH_TBR, AE_CH_TBC, AE_CH_TC, AE_CH_NULL} // Standard 7.1 + 3 front top + 3 back top + Top Center
107 unsigned int bitsPerSample;
108 unsigned int validBitsPerSample;
109 AEDataFormat subFormatType;
112 /* Sample formats go from float -> 32 bit int -> 24 bit int (packed in 32) -> -> 24 bit int -> 16 bit int */
113 static const sampleFormat testFormats[] = { {KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 32, 32, AE_FMT_FLOAT},
114 {KSDATAFORMAT_SUBTYPE_PCM, 32, 32, AE_FMT_S32NE},
115 {KSDATAFORMAT_SUBTYPE_PCM, 32, 24, AE_FMT_S24NE4},
116 {KSDATAFORMAT_SUBTYPE_PCM, 24, 24, AE_FMT_S24NE3},
117 {KSDATAFORMAT_SUBTYPE_PCM, 16, 16, AE_FMT_S16NE} };
119 struct winEndpointsToAEDeviceType
121 std::string winEndpointType;
122 AEDeviceType aeDeviceType;
125 static const winEndpointsToAEDeviceType winEndpoints[EndpointFormFactor_enum_count] =
127 {"Network Device - ", AE_DEVTYPE_PCM},
128 {"Speakers - ", AE_DEVTYPE_PCM},
129 {"LineLevel - ", AE_DEVTYPE_PCM},
130 {"Headphones - ", AE_DEVTYPE_PCM},
131 {"Microphone - ", AE_DEVTYPE_PCM},
132 {"Headset - ", AE_DEVTYPE_PCM},
133 {"Handset - ", AE_DEVTYPE_PCM},
134 {"Digital Passthrough - ", AE_DEVTYPE_IEC958},
135 {"SPDIF - ", AE_DEVTYPE_IEC958},
136 {"HDMI - ", AE_DEVTYPE_HDMI},
137 {"Unknown - ", AE_DEVTYPE_PCM},
140 AEDeviceInfoList DeviceInfoList;
142 #define EXIT_ON_FAILURE(hr, reason, ...) if(FAILED(hr)) {CLog::Log(LOGERROR, reason " - %s", __VA_ARGS__, WASAPIErrToStr(hr)); goto failed;}
144 #define ERRTOSTR(err) case err: return #err
146 DEFINE_PROPERTYKEY(PKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 14);
148 DWORD ChLayoutToChMask(const enum AEChannel * layout, unsigned int * numberOfChannels = NULL)
150 if (numberOfChannels)
151 *numberOfChannels = 0;
157 for (i = 0; layout[i] != AE_CH_NULL; i++)
158 mask |= WASAPIChannelOrder[layout[i]];
160 if (numberOfChannels)
161 *numberOfChannels = i;
166 CStdStringA localWideToUtf(LPCWSTR wstr)
170 int bufSize = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);
171 CStdStringA strA ("", bufSize);
172 if ( bufSize == 0 || WideCharToMultiByte(CP_UTF8, 0, wstr, -1, strA.GetBuf(bufSize), bufSize, NULL, NULL) != bufSize )
178 CAESinkWASAPI::CAESinkWASAPI() :
181 m_pAudioClient(NULL),
182 m_pRenderClient(NULL),
183 m_encodedFormat(AE_FMT_INVALID),
184 m_encodedChannels(0),
185 m_encodedSampleRate(0),
186 sinkReqFormat(AE_FMT_INVALID),
187 sinkRetFormat(AE_FMT_INVALID),
189 m_initialized(false),
190 m_isSuspended(false),
193 m_avgTimeWaiting(50),
195 m_lastWriteToBuffer(0),
199 m_channelLayout.Reset();
202 CAESinkWASAPI::~CAESinkWASAPI()
207 bool CAESinkWASAPI::Initialize(AEAudioFormat &format, std::string &device)
213 bool bdefault = false;
215 /* Save requested format */
216 /* Clear returned format */
217 sinkReqFormat = format.m_dataFormat;
218 sinkRetFormat = AE_FMT_INVALID;
220 IMMDeviceEnumerator* pEnumerator = NULL;
221 IMMDeviceCollection* pEnumDevices = NULL;
223 HRESULT hr = CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void**)&pEnumerator);
224 EXIT_ON_FAILURE(hr, __FUNCTION__": Could not allocate WASAPI device enumerator. CoCreateInstance error code: %li", hr)
226 /* Get our device. First try to find the named device. */
229 hr = pEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &pEnumDevices);
230 EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of audio endpoint enumeration failed.")
232 hr = pEnumDevices->GetCount(&uiCount);
233 EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of audio endpoint count failed.")
235 if(StringUtils::EndsWithNoCase(device, std::string("default")))
240 for (UINT i = 0; i < uiCount; i++)
242 IPropertyStore *pProperty = NULL;
245 hr = pEnumDevices->Item(i, &m_pDevice);
246 EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of WASAPI endpoint failed.")
248 hr = m_pDevice->OpenPropertyStore(STGM_READ, &pProperty);
249 EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of WASAPI endpoint properties failed.")
251 hr = pProperty->GetValue(PKEY_AudioEndpoint_GUID, &varName);
254 CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint GUID failed.");
255 SAFE_RELEASE(pProperty);
259 std::string strDevName = localWideToUtf(varName.pwszVal);
261 if (device == strDevName)
264 SAFE_RELEASE(m_pDevice);
266 PropVariantClear(&varName);
267 SAFE_RELEASE(pProperty);
270 SAFE_RELEASE(pEnumDevices);
275 CLog::Log(LOGINFO, __FUNCTION__": Could not locate the device named \"%s\" in the list of WASAPI endpoint devices. Trying the default device...", device.c_str());
276 hr = pEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &m_pDevice);
277 EXIT_ON_FAILURE(hr, __FUNCTION__": Could not retrieve the default WASAPI audio endpoint.")
279 IPropertyStore *pProperty = NULL;
282 hr = m_pDevice->OpenPropertyStore(STGM_READ, &pProperty);
283 EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of WASAPI endpoint properties failed.")
285 hr = pProperty->GetValue(PKEY_AudioEndpoint_GUID, &varName);
287 device = localWideToUtf(varName.pwszVal);
288 PropVariantClear(&varName);
289 SAFE_RELEASE(pProperty);
292 SAFE_RELEASE(pEnumerator);
294 hr = m_pDevice->Activate(IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&m_pAudioClient);
295 EXIT_ON_FAILURE(hr, __FUNCTION__": Activating the WASAPI endpoint device failed.")
297 if (!InitializeExclusive(format))
299 CLog::Log(LOGINFO, __FUNCTION__": Could not Initialize Exclusive with that format");
303 /* get the buffer size and calculate the frames for AE */
304 m_pAudioClient->GetBufferSize(&m_uiBufferLen);
306 format.m_frames = m_uiBufferLen;
307 format.m_frameSamples = format.m_frames * format.m_channelLayout.Count();
309 sinkRetFormat = format.m_dataFormat;
311 hr = m_pAudioClient->GetService(IID_IAudioRenderClient, (void**)&m_pRenderClient);
312 EXIT_ON_FAILURE(hr, __FUNCTION__": Could not initialize the WASAPI render client interface.")
314 m_needDataEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
315 hr = m_pAudioClient->SetEventHandle(m_needDataEvent);
316 EXIT_ON_FAILURE(hr, __FUNCTION__": Could not set the WASAPI event handler.");
318 m_initialized = true;
321 // allow feeding less samples than buffer size
322 // if the device is opened exclusive and event driven, provided samples must match buffersize
323 // ActiveAE tries to align provided samples with buffer size but cannot guarantee (e.g. transcoding)
324 // this can be avoided by dropping the event mode which has not much benefit; SoftAE polls anyway
326 m_pBuffer = new uint8_t[format.m_frames * format.m_frameSize];
332 CLog::Log(LOGERROR, __FUNCTION__": WASAPI initialization failed.");
333 SAFE_RELEASE(pEnumDevices);
334 SAFE_RELEASE(pEnumerator);
335 SAFE_RELEASE(m_pRenderClient);
336 SAFE_RELEASE(m_pAudioClient);
337 SAFE_RELEASE(m_pDevice);
340 CloseHandle(m_needDataEvent);
347 void CAESinkWASAPI::Deinitialize()
349 if (!m_initialized && !m_isDirty)
356 m_pAudioClient->Stop(); //stop the audio output
357 m_pAudioClient->Reset(); //flush buffer and reset audio clock stream position
361 CLog::Log(LOGDEBUG, __FUNCTION__, "Invalidated AudioClient - Releasing");
366 CloseHandle(m_needDataEvent);
368 SAFE_RELEASE(m_pRenderClient);
369 SAFE_RELEASE(m_pAudioClient);
370 SAFE_RELEASE(m_pDevice);
372 m_initialized = false;
378 double CAESinkWASAPI::GetDelay()
383 double time_played = 0.0;
386 unsigned int now = XbmcThreads::SystemClockMillis();
387 time_played = (double)(now-m_lastWriteToBuffer) / 1000;
390 double delay = m_sinkLatency - time_played + (double)m_bufferPtr / (double)m_format.m_sampleRate;
398 double CAESinkWASAPI::GetCacheTotal()
403 return m_sinkLatency;
406 unsigned int CAESinkWASAPI::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio, bool blocking)
416 LARGE_INTEGER timerStart;
417 LARGE_INTEGER timerStop;
418 LARGE_INTEGER timerFreq;
421 unsigned int NumFramesRequested = m_format.m_frames;
422 unsigned int FramesToCopy = std::min(m_format.m_frames - m_bufferPtr, frames);
423 if (m_bufferPtr != 0 || frames != m_format.m_frames)
425 memcpy(m_pBuffer+m_bufferPtr*m_format.m_frameSize, data, FramesToCopy*m_format.m_frameSize);
426 m_bufferPtr += FramesToCopy;
427 if (m_bufferPtr != m_format.m_frames)
431 if (!m_running) //first time called, pre-fill buffer then start audio client
433 hr = m_pAudioClient->Reset();
436 CLog::Log(LOGERROR, __FUNCTION__ " AudioClient reset failed due to %s", WASAPIErrToStr(hr));
439 hr = m_pRenderClient->GetBuffer(NumFramesRequested, &buf);
443 CLog::Log(LOGERROR, __FUNCTION__": GetBuffer failed due to %s", WASAPIErrToStr(hr));
445 m_isDirty = true; //flag new device or re-init needed
449 memset(buf, 0, NumFramesRequested * m_format.m_frameSize); //fill buffer with silence
451 hr = m_pRenderClient->ReleaseBuffer(NumFramesRequested, flags); //pass back to audio driver
455 CLog::Log(LOGDEBUG, __FUNCTION__": ReleaseBuffer failed due to %s.", WASAPIErrToStr(hr));
457 m_isDirty = true; //flag new device or re-init needed
460 hr = m_pAudioClient->Start(); //start the audio driver running
462 CLog::Log(LOGERROR, __FUNCTION__": AudioClient Start Failed");
463 m_running = true; //signal that we're processing frames
468 /* Get clock time for latency checks */
469 QueryPerformanceFrequency(&timerFreq);
470 QueryPerformanceCounter(&timerStart);
473 /* Wait for Audio Driver to tell us it's got a buffer available */
474 DWORD eventAudioCallback;
476 eventAudioCallback = WaitForSingleObject(m_needDataEvent, 0);
478 eventAudioCallback = WaitForSingleObject(m_needDataEvent, 1100);
482 if(eventAudioCallback != WAIT_OBJECT_0)
487 if(eventAudioCallback != WAIT_OBJECT_0 || !&buf)
489 CLog::Log(LOGERROR, __FUNCTION__": Endpoint Buffer timed out");
499 QueryPerformanceCounter(&timerStop);
500 LONGLONG timerDiff = timerStop.QuadPart - timerStart.QuadPart;
501 double timerElapsed = (double) timerDiff * 1000.0 / (double) timerFreq.QuadPart;
502 m_avgTimeWaiting += (timerElapsed - m_avgTimeWaiting) * 0.5;
504 if (m_avgTimeWaiting < 3.0)
506 CLog::Log(LOGDEBUG, __FUNCTION__": Possible AQ Loss: Avg. Time Waiting for Audio Driver callback : %dmsec", (int)m_avgTimeWaiting);
510 hr = m_pRenderClient->GetBuffer(NumFramesRequested, &buf);
514 CLog::Log(LOGERROR, __FUNCTION__": GetBuffer failed due to %s", WASAPIErrToStr(hr));
518 memcpy(buf, m_bufferPtr == 0 ? data : m_pBuffer, NumFramesRequested * m_format.m_frameSize); //fill buffer
520 hr = m_pRenderClient->ReleaseBuffer(NumFramesRequested, flags); //pass back to audio driver
524 CLog::Log(LOGDEBUG, __FUNCTION__": ReleaseBuffer failed due to %s.", WASAPIErrToStr(hr));
528 m_lastWriteToBuffer = XbmcThreads::SystemClockMillis();
530 if (FramesToCopy != frames)
532 m_bufferPtr = frames-FramesToCopy;
533 memcpy(m_pBuffer, data+FramesToCopy*m_format.m_frameSize, m_bufferPtr*m_format.m_frameSize);
539 void CAESinkWASAPI::EnumerateDevicesEx(AEDeviceInfoList &deviceInfoList, bool force)
541 IMMDeviceEnumerator* pEnumerator = NULL;
542 IMMDeviceCollection* pEnumDevices = NULL;
543 IMMDevice* pDefaultDevice = NULL;
544 CAEDeviceInfo deviceInfo;
545 CAEChannelInfo deviceChannels;
546 LPWSTR pwszID = NULL;
547 std::wstring wstrDDID;
549 WAVEFORMATEXTENSIBLE wfxex = {0};
552 hr = CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void**)&pEnumerator);
553 EXIT_ON_FAILURE(hr, __FUNCTION__": Could not allocate WASAPI device enumerator. CoCreateInstance error code: %li", hr)
557 // get the default audio endpoint
558 if(pEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &pDefaultDevice) == S_OK)
560 if(pDefaultDevice->GetId(&pwszID) == S_OK)
563 CoTaskMemFree(pwszID);
565 SAFE_RELEASE(pDefaultDevice);
568 // enumerate over all audio endpoints
569 hr = pEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &pEnumDevices);
570 EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of audio endpoint enumeration failed.")
572 hr = pEnumDevices->GetCount(&uiCount);
573 EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of audio endpoint count failed.")
575 for (UINT i = 0; i < uiCount; i++)
577 IMMDevice *pDevice = NULL;
578 IPropertyStore *pProperty = NULL;
580 PropVariantInit(&varName);
582 deviceInfo.m_channels.Reset();
583 deviceInfo.m_dataFormats.clear();
584 deviceInfo.m_sampleRates.clear();
586 hr = pEnumDevices->Item(i, &pDevice);
589 CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint failed.");
593 hr = pDevice->OpenPropertyStore(STGM_READ, &pProperty);
596 CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint properties failed.");
597 SAFE_RELEASE(pDevice);
601 hr = pProperty->GetValue(PKEY_Device_FriendlyName, &varName);
604 CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint device name failed.");
605 SAFE_RELEASE(pDevice);
606 SAFE_RELEASE(pProperty);
610 std::string strFriendlyName = localWideToUtf(varName.pwszVal);
611 PropVariantClear(&varName);
613 hr = pProperty->GetValue(PKEY_AudioEndpoint_GUID, &varName);
616 CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint GUID failed.");
617 SAFE_RELEASE(pDevice);
618 SAFE_RELEASE(pProperty);
622 std::string strDevName = localWideToUtf(varName.pwszVal);
623 PropVariantClear(&varName);
625 hr = pProperty->GetValue(PKEY_AudioEndpoint_FormFactor, &varName);
628 CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint form factor failed.");
629 SAFE_RELEASE(pDevice);
630 SAFE_RELEASE(pProperty);
633 std::string strWinDevType = winEndpoints[(EndpointFormFactor)varName.uiVal].winEndpointType;
634 AEDeviceType aeDeviceType = winEndpoints[(EndpointFormFactor)varName.uiVal].aeDeviceType;
636 PropVariantClear(&varName);
638 hr = pProperty->GetValue(PKEY_AudioEndpoint_PhysicalSpeakers, &varName);
641 CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint speaker layout failed.");
642 SAFE_RELEASE(pDevice);
643 SAFE_RELEASE(pProperty);
646 unsigned int uiChannelMask = std::max(varName.uintVal, (unsigned int) KSAUDIO_SPEAKER_STEREO);
648 deviceChannels.Reset();
650 for (unsigned int c = 0; c < WASAPI_SPEAKER_COUNT; c++)
652 if (uiChannelMask & WASAPIChannelOrder[c])
653 deviceChannels += AEChannelNames[c];
656 PropVariantClear(&varName);
658 IAudioClient *pClient;
659 hr = pDevice->Activate(IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&pClient);
662 /* Test format DTS-HD */
663 wfxex.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
664 wfxex.Format.nSamplesPerSec = 192000;
665 wfxex.dwChannelMask = KSAUDIO_SPEAKER_7POINT1_SURROUND;
666 wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
667 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DTS_HD;
668 wfxex.Format.wBitsPerSample = 16;
669 wfxex.Samples.wValidBitsPerSample = 16;
670 wfxex.Format.nChannels = 8;
671 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
672 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
673 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
675 deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_DTSHD));
677 /* Test format Dolby TrueHD */
678 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_MLP;
679 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
681 deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_TRUEHD));
683 /* Test format Dolby EAC3 */
684 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL_PLUS;
685 wfxex.Format.nChannels = 2;
686 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
687 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
688 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
690 deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_EAC3));
692 /* Test format DTS */
693 wfxex.Format.nSamplesPerSec = 48000;
694 wfxex.dwChannelMask = KSAUDIO_SPEAKER_5POINT1;
695 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DTS;
696 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
697 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
698 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
700 deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_DTS));
702 /* Test format Dolby AC3 */
703 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL;
704 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
706 deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_AC3));
708 /* Test format AAC */
709 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_AAC;
710 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
712 deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_AAC));
714 /* Test format for PCM format iteration */
715 wfxex.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
716 wfxex.dwChannelMask = KSAUDIO_SPEAKER_STEREO;
717 wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
718 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
720 for (int p = AE_FMT_FLOAT; p > AE_FMT_INVALID; p--)
722 if (p < AE_FMT_FLOAT)
723 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
724 wfxex.Format.wBitsPerSample = CAEUtil::DataFormatToBits((AEDataFormat) p);
725 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
726 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
727 if (p <= AE_FMT_S24NE4 && p >= AE_FMT_S24BE4)
729 wfxex.Samples.wValidBitsPerSample = 24;
733 wfxex.Samples.wValidBitsPerSample = wfxex.Format.wBitsPerSample;
736 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
738 deviceInfo.m_dataFormats.push_back((AEDataFormat) p);
741 /* Test format for sample rate iteration */
742 wfxex.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
743 wfxex.dwChannelMask = KSAUDIO_SPEAKER_STEREO;
744 wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
745 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
746 wfxex.Format.wBitsPerSample = 16;
747 wfxex.Samples.wValidBitsPerSample = 16;
748 wfxex.Format.nChannels = 2;
749 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
750 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
752 for (int j = 0; j < WASAPISampleRateCount; j++)
754 wfxex.Format.nSamplesPerSec = WASAPISampleRates[j];
755 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
756 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
758 deviceInfo.m_sampleRates.push_back(WASAPISampleRates[j]);
761 /* Test format for channels iteration */
762 wfxex.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
763 wfxex.dwChannelMask = KSAUDIO_SPEAKER_STEREO;
764 wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
765 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
766 wfxex.Format.nSamplesPerSec = 48000;
767 wfxex.Format.wBitsPerSample = 16;
768 wfxex.Samples.wValidBitsPerSample = 16;
769 wfxex.Format.nChannels = 2;
770 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
771 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
773 bool hasLpcm = false;
775 // Try with KSAUDIO_SPEAKER_DIRECTOUT
776 for (unsigned int k = WASAPI_SPEAKER_COUNT; k > 0; k--)
778 wfxex.dwChannelMask = KSAUDIO_SPEAKER_DIRECTOUT;
779 wfxex.Format.nChannels = k;
780 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
781 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
782 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
785 if (k > 3) // Add only multichannel LPCM
787 deviceInfo.m_dataFormats.push_back(AE_FMT_LPCM);
794 /* Try with reported channel mask */
795 for (unsigned int k = WASAPI_SPEAKER_COUNT; k > 0; k--)
797 wfxex.dwChannelMask = uiChannelMask;
798 wfxex.Format.nChannels = k;
799 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
800 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
801 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
804 if ( !hasLpcm && k > 3) // Add only multichannel LPCM
806 deviceInfo.m_dataFormats.push_back(AE_FMT_LPCM);
813 /* Try with specific speakers configurations */
814 for (unsigned int i = 0; i < ARRAYSIZE(layoutsList); i++)
816 unsigned int nmbOfCh;
817 wfxex.dwChannelMask = ChLayoutToChMask(layoutsList[i], &nmbOfCh);
818 wfxex.Format.nChannels = nmbOfCh;
819 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
820 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
821 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
824 if ( deviceChannels.Count() < nmbOfCh)
825 deviceChannels = layoutsList[i];
826 if ( !hasLpcm && nmbOfCh > 3) // Add only multichannel LPCM
828 deviceInfo.m_dataFormats.push_back(AE_FMT_LPCM);
837 CLog::Log(LOGDEBUG, __FUNCTION__": Failed to activate device for passthrough capability testing.");
840 deviceInfo.m_deviceName = strDevName;
841 deviceInfo.m_displayName = strWinDevType.append(strFriendlyName);
842 deviceInfo.m_displayNameExtra = std::string("WASAPI: ").append(strFriendlyName);
843 deviceInfo.m_deviceType = aeDeviceType;
844 deviceInfo.m_channels = deviceChannels;
846 /* Store the device info */
847 deviceInfoList.push_back(deviceInfo);
849 if(pDevice->GetId(&pwszID) == S_OK)
851 if(wstrDDID.compare(pwszID) == 0)
853 deviceInfo.m_deviceName = std::string("default");
854 deviceInfo.m_displayName = std::string("default");
855 deviceInfo.m_displayNameExtra = std::string("");
856 deviceInfoList.push_back(deviceInfo);
858 CoTaskMemFree(pwszID);
861 SAFE_RELEASE(pDevice);
862 SAFE_RELEASE(pProperty);
869 CLog::Log(LOGERROR, __FUNCTION__": Failed to enumerate WASAPI endpoint devices (%s).", WASAPIErrToStr(hr));
871 SAFE_RELEASE(pEnumDevices);
872 SAFE_RELEASE(pEnumerator);
875 //Private utility functions////////////////////////////////////////////////////
877 void CAESinkWASAPI::BuildWaveFormatExtensible(AEAudioFormat &format, WAVEFORMATEXTENSIBLE &wfxex)
879 wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
880 wfxex.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
883 if (!AE_IS_RAW(format.m_dataFormat)) // PCM data
885 wfxex.dwChannelMask = SpeakerMaskFromAEChannels(format.m_channelLayout);
886 wfxex.Format.nChannels = (WORD)format.m_channelLayout.Count();
887 wfxex.Format.nSamplesPerSec = format.m_sampleRate;
888 wfxex.Format.wBitsPerSample = CAEUtil::DataFormatToBits((AEDataFormat) format.m_dataFormat);
889 wfxex.SubFormat = format.m_dataFormat <= AE_FMT_FLOAT ? KSDATAFORMAT_SUBTYPE_PCM : KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
893 wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
894 if (format.m_dataFormat == AE_FMT_AC3 || format.m_dataFormat == AE_FMT_DTS)
896 wfxex.dwChannelMask = bool (format.m_channelLayout.Count() == 2) ? KSAUDIO_SPEAKER_STEREO : KSAUDIO_SPEAKER_5POINT1;
897 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL;
898 wfxex.Format.wBitsPerSample = 16;
899 wfxex.Samples.wValidBitsPerSample = 16;
900 wfxex.Format.nChannels = (WORD)format.m_channelLayout.Count();
901 wfxex.Format.nSamplesPerSec = format.m_sampleRate;
903 else if (format.m_dataFormat == AE_FMT_EAC3 || format.m_dataFormat == AE_FMT_TRUEHD || format.m_dataFormat == AE_FMT_DTSHD)
905 /* IEC 61937 transmissions over HDMI */
906 wfxex.Format.nSamplesPerSec = 192000L;
907 wfxex.Format.wBitsPerSample = 16;
908 wfxex.Samples.wValidBitsPerSample = 16;
909 wfxex.dwChannelMask = KSAUDIO_SPEAKER_7POINT1_SURROUND;
911 switch (format.m_dataFormat)
914 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL_PLUS;
915 wfxex.Format.nChannels = 2; // One IEC 60958 Line.
916 wfxex.dwChannelMask = KSAUDIO_SPEAKER_5POINT1;
919 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_MLP;
920 wfxex.Format.nChannels = 8; // Four IEC 60958 Lines.
921 wfxex.dwChannelMask = KSAUDIO_SPEAKER_7POINT1_SURROUND;
924 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DTS_HD;
925 wfxex.Format.nChannels = 8; // Four IEC 60958 Lines.
926 wfxex.dwChannelMask = KSAUDIO_SPEAKER_7POINT1_SURROUND;
930 if (format.m_channelLayout.Count() == 8)
931 wfxex.dwChannelMask = KSAUDIO_SPEAKER_7POINT1_SURROUND;
933 wfxex.dwChannelMask = KSAUDIO_SPEAKER_5POINT1;
937 if (wfxex.Format.wBitsPerSample == 32 && wfxex.SubFormat != KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)
938 wfxex.Samples.wValidBitsPerSample = 24;
940 wfxex.Samples.wValidBitsPerSample = wfxex.Format.wBitsPerSample;
942 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
943 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
946 void CAESinkWASAPI::BuildWaveFormatExtensibleIEC61397(AEAudioFormat &format, WAVEFORMATEXTENSIBLE_IEC61937 &wfxex)
948 /* Fill the common structure */
949 BuildWaveFormatExtensible(format, wfxex.FormatExt);
951 /* Code below kept for future use - preferred for later Windows versions */
952 /* but can cause problems on older Windows versions and drivers */
954 wfxex.FormatExt.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE_IEC61937)-sizeof(WAVEFORMATEX);
955 wfxex.dwEncodedChannelCount = format.m_channelLayout.Count();
956 wfxex.dwEncodedSamplesPerSec = bool(format.m_dataFormat == AE_FMT_TRUEHD ||
957 format.m_dataFormat == AE_FMT_DTSHD ||
958 format.m_dataFormat == AE_FMT_EAC3) ? 96000L : 48000L;
959 wfxex.dwAverageBytesPerSec = 0; //Ignored */
962 bool CAESinkWASAPI::InitializeExclusive(AEAudioFormat &format)
964 WAVEFORMATEXTENSIBLE_IEC61937 wfxex_iec61937;
965 WAVEFORMATEXTENSIBLE &wfxex = wfxex_iec61937.FormatExt;
967 if (format.m_dataFormat <= AE_FMT_FLOAT)
968 BuildWaveFormatExtensible(format, wfxex);
970 BuildWaveFormatExtensibleIEC61397(format, wfxex_iec61937);
972 /* Test for incomplete format and provide defaults */
973 if (format.m_sampleRate == 0 ||
974 format.m_channelLayout == NULL ||
975 format.m_dataFormat <= AE_FMT_INVALID ||
976 format.m_dataFormat >= AE_FMT_MAX ||
977 format.m_channelLayout.Count() == 0)
979 wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
980 wfxex.Format.nChannels = 2;
981 wfxex.Format.nSamplesPerSec = 44100L;
982 wfxex.Format.wBitsPerSample = 16;
983 wfxex.Format.nBlockAlign = 4;
984 wfxex.Samples.wValidBitsPerSample = 16;
985 wfxex.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
986 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nBlockAlign * wfxex.Format.nSamplesPerSec;
987 wfxex.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
988 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
991 HRESULT hr = m_pAudioClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
995 CLog::Log(LOGINFO, __FUNCTION__": Format is Supported - will attempt to Initialize");
998 else if (hr != AUDCLNT_E_UNSUPPORTED_FORMAT) //It failed for a reason unrelated to an unsupported format.
1000 CLog::Log(LOGERROR, __FUNCTION__": IsFormatSupported failed (%s)", WASAPIErrToStr(hr));
1003 else if (AE_IS_RAW(format.m_dataFormat)) //No sense in trying other formats for passthrough.
1006 CLog::Log(LOGERROR, __FUNCTION__": IsFormatSupported failed (%s) - trying to find a compatible format", WASAPIErrToStr(hr));
1009 unsigned int requestedChannels = wfxex.Format.nChannels;
1010 unsigned int noOfCh;
1012 /* The requested format is not supported by the device. Find something that works */
1013 for (int layout = -1; layout <= (int)ARRAYSIZE(layoutsList); layout++)
1015 // if requested layout is not suppported, try standard layouts with at least
1016 // the number of channels as requested
1017 // as the last resort try stereo
1018 if (layout == ARRAYSIZE(layoutsList))
1020 wfxex.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
1021 wfxex.Format.nChannels = 2;
1023 else if (layout >= 0)
1025 wfxex.dwChannelMask = ChLayoutToChMask(layoutsList[layout], &noOfCh);
1026 wfxex.Format.nChannels = noOfCh;
1027 if (noOfCh < requestedChannels)
1031 for (int j = 0; j < sizeof(testFormats)/sizeof(sampleFormat); j++)
1035 wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
1036 wfxex.SubFormat = testFormats[j].subFormat;
1037 wfxex.Format.wBitsPerSample = testFormats[j].bitsPerSample;
1038 wfxex.Samples.wValidBitsPerSample = testFormats[j].validBitsPerSample;
1039 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
1041 for (int i = 0 ; i < WASAPISampleRateCount; i++)
1043 wfxex.Format.nSamplesPerSec = WASAPISampleRates[i];
1044 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
1046 /* Trace format match iteration loop via log */
1048 CLog::Log(LOGDEBUG, "WASAPI: Trying Format: %s, %d, %d, %d", CAEUtil::DataFormatToStr(testFormats[j].subFormatType),
1049 wfxex.Format.nSamplesPerSec,
1050 wfxex.Format.wBitsPerSample,
1051 wfxex.Samples.wValidBitsPerSample);
1054 hr = m_pAudioClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
1058 /* If the current sample rate matches the source then stop looking and use it */
1059 if ((WASAPISampleRates[i] == format.m_sampleRate) && (testFormats[j].subFormatType <= format.m_dataFormat))
1061 /* If this rate is closer to the source then the previous one, save it */
1062 else if (closestMatch < 0 || abs((int)WASAPISampleRates[i] - (int)format.m_sampleRate) < abs((int)WASAPISampleRates[closestMatch] - (int)format.m_sampleRate))
1065 else if (hr != AUDCLNT_E_UNSUPPORTED_FORMAT)
1066 CLog::Log(LOGERROR, __FUNCTION__": IsFormatSupported failed (%s)", WASAPIErrToStr(hr));
1069 if (closestMatch >= 0)
1071 wfxex.Format.nSamplesPerSec = WASAPISampleRates[closestMatch];
1072 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
1078 CLog::Log(LOGERROR, __FUNCTION__": Unable to locate a supported output format for the device. Check the speaker settings in the control panel.");
1080 /* We couldn't find anything supported. This should never happen */
1081 /* unless the user set the wrong speaker setting in the control panel */
1086 AEChannelsFromSpeakerMask(wfxex.dwChannelMask);
1087 format.m_channelLayout = m_channelLayout;
1089 /* When the stream is raw, the values in the format structure are set to the link */
1090 /* parameters, so store the encoded stream values here for the IsCompatible function */
1091 m_encodedFormat = format.m_dataFormat;
1092 m_encodedChannels = wfxex.Format.nChannels;
1093 m_encodedSampleRate = format.m_encodedRate;
1094 wfxex_iec61937.dwEncodedChannelCount = wfxex.Format.nChannels;
1095 wfxex_iec61937.dwEncodedSamplesPerSec = m_encodedSampleRate;
1097 /* Set up returned sink format for engine */
1098 if (!AE_IS_RAW(format.m_dataFormat))
1100 if (wfxex.Format.wBitsPerSample == 32)
1102 if (wfxex.SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)
1103 format.m_dataFormat = AE_FMT_FLOAT;
1104 else if (wfxex.Samples.wValidBitsPerSample == 32)
1105 format.m_dataFormat = AE_FMT_S32NE;
1107 format.m_dataFormat = AE_FMT_S24NE4;
1109 else if (wfxex.Format.wBitsPerSample == 24)
1110 format.m_dataFormat = AE_FMT_S24NE3;
1112 format.m_dataFormat = AE_FMT_S16NE;
1115 format.m_sampleRate = wfxex.Format.nSamplesPerSec; //PCM: Sample rate. RAW: Link speed
1116 format.m_frameSize = (wfxex.Format.wBitsPerSample >> 3) * wfxex.Format.nChannels;
1118 REFERENCE_TIME audioSinkBufferDurationMsec, hnsLatency;
1120 audioSinkBufferDurationMsec = (REFERENCE_TIME)500000;
1121 audioSinkBufferDurationMsec = (REFERENCE_TIME)((audioSinkBufferDurationMsec / format.m_frameSize) * format.m_frameSize); //even number of frames
1123 if (AE_IS_RAW(format.m_dataFormat))
1124 format.m_dataFormat = AE_FMT_S16NE;
1126 hr = m_pAudioClient->Initialize(AUDCLNT_SHAREMODE_EXCLUSIVE, AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_NOPERSIST,
1127 audioSinkBufferDurationMsec, audioSinkBufferDurationMsec, &wfxex.Format, NULL);
1129 if (hr == AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED)
1131 /* WASAPI requires aligned buffer */
1132 /* Get the next aligned frame */
1133 hr = m_pAudioClient->GetBufferSize(&m_uiBufferLen);
1136 CLog::Log(LOGERROR, __FUNCTION__": GetBufferSize Failed : %s", WASAPIErrToStr(hr));
1140 audioSinkBufferDurationMsec = (REFERENCE_TIME) ((10000.0 * 1000 / wfxex.Format.nSamplesPerSec * m_uiBufferLen) + 0.5);
1142 /* Release the previous allocations */
1143 SAFE_RELEASE(m_pAudioClient);
1145 /* Create a new audio client */
1146 hr = m_pDevice->Activate(IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&m_pAudioClient);
1149 CLog::Log(LOGERROR, __FUNCTION__": Device Activation Failed : %s", WASAPIErrToStr(hr));
1153 /* Open the stream and associate it with an audio session */
1154 hr = m_pAudioClient->Initialize(AUDCLNT_SHAREMODE_EXCLUSIVE, AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_NOPERSIST,
1155 audioSinkBufferDurationMsec, audioSinkBufferDurationMsec, &wfxex.Format, NULL);
1159 CLog::Log(LOGERROR, __FUNCTION__": Failed to initialize WASAPI in exclusive mode %d - (%s).", HRESULT(hr), WASAPIErrToStr(hr));
1160 CLog::Log(LOGDEBUG, " Sample Rate : %d", wfxex.Format.nSamplesPerSec);
1161 CLog::Log(LOGDEBUG, " Sample Format : %s", CAEUtil::DataFormatToStr(format.m_dataFormat));
1162 CLog::Log(LOGDEBUG, " Bits Per Sample : %d", wfxex.Format.wBitsPerSample);
1163 CLog::Log(LOGDEBUG, " Valid Bits/Samp : %d", wfxex.Samples.wValidBitsPerSample);
1164 CLog::Log(LOGDEBUG, " Channel Count : %d", wfxex.Format.nChannels);
1165 CLog::Log(LOGDEBUG, " Block Align : %d", wfxex.Format.nBlockAlign);
1166 CLog::Log(LOGDEBUG, " Avg. Bytes Sec : %d", wfxex.Format.nAvgBytesPerSec);
1167 CLog::Log(LOGDEBUG, " Samples/Block : %d", wfxex.Samples.wSamplesPerBlock);
1168 CLog::Log(LOGDEBUG, " Format cBSize : %d", wfxex.Format.cbSize);
1169 CLog::Log(LOGDEBUG, " Channel Layout : %s", ((std::string)format.m_channelLayout).c_str());
1170 CLog::Log(LOGDEBUG, " Enc. Channels : %d", wfxex_iec61937.dwEncodedChannelCount);
1171 CLog::Log(LOGDEBUG, " Enc. Samples/Sec: %d", wfxex_iec61937.dwEncodedSamplesPerSec);
1172 CLog::Log(LOGDEBUG, " Channel Mask : %d", wfxex.dwChannelMask);
1173 CLog::Log(LOGDEBUG, " Periodicty : %d", audioSinkBufferDurationMsec);
1177 /* Latency of WASAPI buffers in event-driven mode is equal to the returned value */
1178 /* of GetStreamLatency converted from 100ns intervals to seconds then multiplied */
1179 /* by two as there are two equally-sized buffers and playback starts when the */
1180 /* second buffer is filled. Multiplying the returned 100ns intervals by 0.0000002 */
1181 /* is handles both the unit conversion and twin buffers. */
1182 hr = m_pAudioClient->GetStreamLatency(&hnsLatency);
1185 CLog::Log(LOGERROR, __FUNCTION__": GetStreamLatency Failed : %s", WASAPIErrToStr(hr));
1189 m_sinkLatency = hnsLatency * 0.0000002;
1191 CLog::Log(LOGINFO, __FUNCTION__": WASAPI Exclusive Mode Sink Initialized using: %s, %d, %d",
1192 CAEUtil::DataFormatToStr(format.m_dataFormat),
1193 wfxex.Format.nSamplesPerSec,
1194 wfxex.Format.nChannels);
1198 void CAESinkWASAPI::AEChannelsFromSpeakerMask(DWORD speakers)
1200 m_channelLayout.Reset();
1202 for (int i = 0; i < WASAPI_SPEAKER_COUNT; i++)
1204 if (speakers & WASAPIChannelOrder[i])
1205 m_channelLayout += AEChannelNames[i];
1209 DWORD CAESinkWASAPI::SpeakerMaskFromAEChannels(const CAEChannelInfo &channels)
1213 for (unsigned int i = 0; i < channels.Count(); i++)
1215 for (unsigned int j = 0; j < WASAPI_SPEAKER_COUNT; j++)
1216 if (channels[i] == AEChannelNames[j])
1217 mask |= WASAPIChannelOrder[j];
1222 const char *CAESinkWASAPI::WASAPIErrToStr(HRESULT err)
1226 ERRTOSTR(AUDCLNT_E_NOT_INITIALIZED);
1227 ERRTOSTR(AUDCLNT_E_ALREADY_INITIALIZED);
1228 ERRTOSTR(AUDCLNT_E_WRONG_ENDPOINT_TYPE);
1229 ERRTOSTR(AUDCLNT_E_DEVICE_INVALIDATED);
1230 ERRTOSTR(AUDCLNT_E_NOT_STOPPED);
1231 ERRTOSTR(AUDCLNT_E_BUFFER_TOO_LARGE);
1232 ERRTOSTR(AUDCLNT_E_OUT_OF_ORDER);
1233 ERRTOSTR(AUDCLNT_E_UNSUPPORTED_FORMAT);
1234 ERRTOSTR(AUDCLNT_E_INVALID_SIZE);
1235 ERRTOSTR(AUDCLNT_E_DEVICE_IN_USE);
1236 ERRTOSTR(AUDCLNT_E_BUFFER_OPERATION_PENDING);
1237 ERRTOSTR(AUDCLNT_E_THREAD_NOT_REGISTERED);
1238 ERRTOSTR(AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED);
1239 ERRTOSTR(AUDCLNT_E_ENDPOINT_CREATE_FAILED);
1240 ERRTOSTR(AUDCLNT_E_SERVICE_NOT_RUNNING);
1241 ERRTOSTR(AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED);
1242 ERRTOSTR(AUDCLNT_E_EXCLUSIVE_MODE_ONLY);
1243 ERRTOSTR(AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL);
1244 ERRTOSTR(AUDCLNT_E_EVENTHANDLE_NOT_SET);
1245 ERRTOSTR(AUDCLNT_E_INCORRECT_BUFFER_SIZE);
1246 ERRTOSTR(AUDCLNT_E_BUFFER_SIZE_ERROR);
1247 ERRTOSTR(AUDCLNT_E_CPUUSAGE_EXCEEDED);
1248 ERRTOSTR(AUDCLNT_E_BUFFER_ERROR);
1249 ERRTOSTR(AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED);
1250 ERRTOSTR(AUDCLNT_E_INVALID_DEVICE_PERIOD);
1251 ERRTOSTR(E_POINTER);
1252 ERRTOSTR(E_INVALIDARG);
1253 ERRTOSTR(E_OUTOFMEMORY);
1259 void CAESinkWASAPI::Drain()
1264 Sleep( (DWORD)(GetDelay()*500) );
1270 m_pAudioClient->Stop(); //stop the audio output
1271 m_pAudioClient->Reset(); //flush buffer and reset audio clock stream position
1275 CLog::Log(LOGDEBUG, __FUNCTION__, "Invalidated AudioClient - Releasing");