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>
27 #include "cores/AudioEngine/Utils/AEUtil.h"
28 #include "settings/AdvancedSettings.h"
29 #include "utils/StdString.h"
30 #include "utils/log.h"
31 #include "threads/SingleLock.h"
32 #include "threads/SystemClock.h"
33 #include "utils/CharsetConverter.h"
34 #include "cores/AudioEngine/Utils/AEDeviceInfo.h"
36 #include "utils/StringUtils.h"
38 #pragma comment(lib, "Avrt.lib")
40 const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator);
41 const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator);
42 const IID IID_IAudioClient = __uuidof(IAudioClient);
43 const IID IID_IAudioRenderClient = __uuidof(IAudioRenderClient);
45 static const unsigned int WASAPISampleRateCount = 10;
46 static const unsigned int WASAPISampleRates[] = {384000, 192000, 176400, 96000, 88200, 48000, 44100, 32000, 22050, 11025};
48 #define WASAPI_SPEAKER_COUNT 21
49 static const unsigned int WASAPIChannelOrder[] = {AE_CH_RAW,
50 SPEAKER_FRONT_LEFT, SPEAKER_FRONT_RIGHT, SPEAKER_FRONT_CENTER,
51 SPEAKER_LOW_FREQUENCY, SPEAKER_BACK_LEFT, SPEAKER_BACK_RIGHT,
52 SPEAKER_FRONT_LEFT_OF_CENTER, SPEAKER_FRONT_RIGHT_OF_CENTER,
53 SPEAKER_BACK_CENTER, SPEAKER_SIDE_LEFT, SPEAKER_SIDE_RIGHT,
54 SPEAKER_TOP_FRONT_LEFT, SPEAKER_TOP_FRONT_RIGHT, SPEAKER_TOP_FRONT_CENTER,
55 SPEAKER_TOP_CENTER, SPEAKER_TOP_BACK_LEFT, SPEAKER_TOP_BACK_RIGHT,
56 SPEAKER_TOP_BACK_CENTER, SPEAKER_RESERVED, SPEAKER_RESERVED};
58 static const enum AEChannel AEChannelNames[] = {AE_CH_RAW,
59 AE_CH_FL, AE_CH_FR, AE_CH_FC,
60 AE_CH_LFE, AE_CH_BL, AE_CH_BR,
61 AE_CH_FLOC, AE_CH_FROC,
62 AE_CH_BC, AE_CH_SL, AE_CH_SR,
63 AE_CH_TFL, AE_CH_TFR, AE_CH_TFC ,
64 AE_CH_TC , AE_CH_TBL, AE_CH_TBR,
65 AE_CH_TBC, AE_CH_BLOC, AE_CH_BROC};
67 static const enum AEChannel layoutsList[][16] =
69 /* Most common configurations */
70 {AE_CH_FC, AE_CH_NULL}, // Mono
71 {AE_CH_FL, AE_CH_FR, AE_CH_NULL}, // Stereo
72 {AE_CH_FL, AE_CH_FR, AE_CH_BL, AE_CH_BR, AE_CH_NULL}, // Quad
73 {AE_CH_FL, AE_CH_FR, AE_CH_FC, AE_CH_BC, AE_CH_NULL}, // Surround
74 {AE_CH_FL, AE_CH_FR, AE_CH_FC, AE_CH_LFE, AE_CH_SL, AE_CH_SR, AE_CH_NULL}, // Standard 5.1
75 {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
76 /* Less common configurations */
77 {AE_CH_FL, AE_CH_FR, AE_CH_LFE, AE_CH_NULL}, // 2.1
78 {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)
79 {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)
80 /* Exotic configurations */
81 {AE_CH_FL, AE_CH_FR, AE_CH_FC, AE_CH_NULL}, // 3 front speakers
82 {AE_CH_FL, AE_CH_FR, AE_CH_FC, AE_CH_LFE, AE_CH_NULL}, // 3 front speakers + LFE
83 {AE_CH_FL, AE_CH_FR, AE_CH_BL, AE_CH_BR, AE_CH_LFE, AE_CH_NULL}, // Quad + LFE
84 {AE_CH_FL, AE_CH_FR, AE_CH_FC, AE_CH_BC, AE_CH_LFE, AE_CH_NULL}, // Surround + LFE
85 {AE_CH_FL, AE_CH_FR, AE_CH_FC, AE_CH_SL, AE_CH_SR, AE_CH_NULL}, // Standard 5.1 w/o LFE
86 {AE_CH_FL, AE_CH_FR, AE_CH_FC, AE_CH_BL, AE_CH_BR, AE_CH_NULL}, // 5.1 wide w/o LFE
87 {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
88 {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
89 {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
90 {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
91 {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
92 {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
93 {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
94 {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
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_TFL, AE_CH_TFR, AE_CH_NULL}, // Standard 7.1 + 2 front top
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_TFC, AE_CH_NULL}, // Standard 7.1 + 3 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_TBL, AE_CH_TBR, AE_CH_NULL}, // Standard 7.1 + 2 front top + 2 back 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_TFC, AE_CH_TBL, AE_CH_TBR, AE_CH_NULL}, // Standard 7.1 + 3 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_TBC, AE_CH_NULL}, // Standard 7.1 + 3 front top + 3 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_TC, AE_CH_NULL} // Standard 7.1 + 3 front top + 3 back top + Top Center
106 unsigned int bitsPerSample;
107 unsigned int validBitsPerSample;
108 AEDataFormat subFormatType;
111 /* Sample formats go from float -> 32 bit int -> 24 bit int (packed in 32) -> -> 24 bit int -> 16 bit int */
112 static const sampleFormat testFormats[] = { {KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 32, 32, AE_FMT_FLOAT},
113 {KSDATAFORMAT_SUBTYPE_PCM, 32, 32, AE_FMT_S32NE},
114 {KSDATAFORMAT_SUBTYPE_PCM, 32, 24, AE_FMT_S24NE4},
115 {KSDATAFORMAT_SUBTYPE_PCM, 24, 24, AE_FMT_S24NE3},
116 {KSDATAFORMAT_SUBTYPE_PCM, 16, 16, AE_FMT_S16NE} };
118 struct winEndpointsToAEDeviceType
120 std::string winEndpointType;
121 AEDeviceType aeDeviceType;
124 static const winEndpointsToAEDeviceType winEndpoints[EndpointFormFactor_enum_count] =
126 {"Network Device - ", AE_DEVTYPE_PCM},
127 {"Speakers - ", AE_DEVTYPE_PCM},
128 {"LineLevel - ", AE_DEVTYPE_PCM},
129 {"Headphones - ", AE_DEVTYPE_PCM},
130 {"Microphone - ", AE_DEVTYPE_PCM},
131 {"Headset - ", AE_DEVTYPE_PCM},
132 {"Handset - ", AE_DEVTYPE_PCM},
133 {"Digital Passthrough - ", AE_DEVTYPE_IEC958},
134 {"SPDIF - ", AE_DEVTYPE_IEC958},
135 {"HDMI - ", AE_DEVTYPE_HDMI},
136 {"Unknown - ", AE_DEVTYPE_PCM},
139 AEDeviceInfoList DeviceInfoList;
141 #define EXIT_ON_FAILURE(hr, reason, ...) if(FAILED(hr)) {CLog::Log(LOGERROR, reason " - %s", __VA_ARGS__, WASAPIErrToStr(hr)); goto failed;}
143 #define ERRTOSTR(err) case err: return #err
145 DEFINE_PROPERTYKEY(PKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 14);
147 DWORD ChLayoutToChMask(const enum AEChannel * layout, unsigned int * numberOfChannels = NULL)
149 if (numberOfChannels)
150 *numberOfChannels = 0;
156 for (i = 0; layout[i] != AE_CH_NULL; i++)
157 mask |= WASAPIChannelOrder[layout[i]];
159 if (numberOfChannels)
160 *numberOfChannels = i;
165 CStdStringA localWideToUtf(LPCWSTR wstr)
169 int bufSize = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);
170 CStdStringA strA ("", bufSize);
171 if ( bufSize == 0 || WideCharToMultiByte(CP_UTF8, 0, wstr, -1, strA.GetBuf(bufSize), bufSize, NULL, NULL) != bufSize )
177 CAESinkWASAPI::CAESinkWASAPI() :
180 m_pAudioClient(NULL),
181 m_pRenderClient(NULL),
182 m_encodedFormat(AE_FMT_INVALID),
183 m_encodedChannels(0),
184 m_encodedSampleRate(0),
185 sinkReqFormat(AE_FMT_INVALID),
186 sinkRetFormat(AE_FMT_INVALID),
188 m_initialized(false),
189 m_isSuspended(false),
192 m_avgTimeWaiting(50),
194 m_lastWriteToBuffer(0),
198 m_channelLayout.Reset();
201 CAESinkWASAPI::~CAESinkWASAPI()
206 bool CAESinkWASAPI::Initialize(AEAudioFormat &format, std::string &device)
212 bool bdefault = false;
214 /* Save requested format */
215 /* Clear returned format */
216 sinkReqFormat = format.m_dataFormat;
217 sinkRetFormat = AE_FMT_INVALID;
219 IMMDeviceEnumerator* pEnumerator = NULL;
220 IMMDeviceCollection* pEnumDevices = NULL;
222 HRESULT hr = CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void**)&pEnumerator);
223 EXIT_ON_FAILURE(hr, __FUNCTION__": Could not allocate WASAPI device enumerator. CoCreateInstance error code: %li", hr)
225 /* Get our device. First try to find the named device. */
228 hr = pEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &pEnumDevices);
229 EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of audio endpoint enumeration failed.")
231 hr = pEnumDevices->GetCount(&uiCount);
232 EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of audio endpoint count failed.")
234 if(StringUtils::EndsWithNoCase(device, std::string("default")))
239 for (UINT i = 0; i < uiCount; i++)
241 IPropertyStore *pProperty = NULL;
244 hr = pEnumDevices->Item(i, &m_pDevice);
245 EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of WASAPI endpoint failed.")
247 hr = m_pDevice->OpenPropertyStore(STGM_READ, &pProperty);
248 EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of WASAPI endpoint properties failed.")
250 hr = pProperty->GetValue(PKEY_AudioEndpoint_GUID, &varName);
253 CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint GUID failed.");
254 SAFE_RELEASE(pProperty);
258 std::string strDevName = localWideToUtf(varName.pwszVal);
260 if (device == strDevName)
263 SAFE_RELEASE(m_pDevice);
265 PropVariantClear(&varName);
266 SAFE_RELEASE(pProperty);
269 SAFE_RELEASE(pEnumDevices);
274 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());
275 hr = pEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &m_pDevice);
276 EXIT_ON_FAILURE(hr, __FUNCTION__": Could not retrieve the default WASAPI audio endpoint.")
278 IPropertyStore *pProperty = NULL;
281 hr = m_pDevice->OpenPropertyStore(STGM_READ, &pProperty);
282 EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of WASAPI endpoint properties failed.")
284 hr = pProperty->GetValue(PKEY_AudioEndpoint_GUID, &varName);
286 device = localWideToUtf(varName.pwszVal);
287 PropVariantClear(&varName);
288 SAFE_RELEASE(pProperty);
291 SAFE_RELEASE(pEnumerator);
293 hr = m_pDevice->Activate(IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&m_pAudioClient);
294 EXIT_ON_FAILURE(hr, __FUNCTION__": Activating the WASAPI endpoint device failed.")
296 if (!InitializeExclusive(format))
298 CLog::Log(LOGINFO, __FUNCTION__": Could not Initialize Exclusive with that format");
302 /* get the buffer size and calculate the frames for AE */
303 m_pAudioClient->GetBufferSize(&m_uiBufferLen);
305 format.m_frames = m_uiBufferLen;
306 format.m_frameSamples = format.m_frames * format.m_channelLayout.Count();
308 sinkRetFormat = format.m_dataFormat;
310 hr = m_pAudioClient->GetService(IID_IAudioRenderClient, (void**)&m_pRenderClient);
311 EXIT_ON_FAILURE(hr, __FUNCTION__": Could not initialize the WASAPI render client interface.")
313 m_needDataEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
314 hr = m_pAudioClient->SetEventHandle(m_needDataEvent);
315 EXIT_ON_FAILURE(hr, __FUNCTION__": Could not set the WASAPI event handler.");
317 m_initialized = true;
320 // allow feeding less samples than buffer size
321 // if the device is opened exclusive and event driven, provided samples must match buffersize
322 // ActiveAE tries to align provided samples with buffer size but cannot guarantee (e.g. transcoding)
323 // this can be avoided by dropping the event mode which has not much benefit; SoftAE polls anyway
325 m_pBuffer = new uint8_t[format.m_frames * format.m_frameSize];
331 CLog::Log(LOGERROR, __FUNCTION__": WASAPI initialization failed.");
332 SAFE_RELEASE(pEnumDevices);
333 SAFE_RELEASE(pEnumerator);
334 SAFE_RELEASE(m_pRenderClient);
335 SAFE_RELEASE(m_pAudioClient);
336 SAFE_RELEASE(m_pDevice);
339 CloseHandle(m_needDataEvent);
346 void CAESinkWASAPI::Deinitialize()
348 if (!m_initialized && !m_isDirty)
355 m_pAudioClient->Stop(); //stop the audio output
356 m_pAudioClient->Reset(); //flush buffer and reset audio clock stream position
360 CLog::Log(LOGDEBUG, __FUNCTION__, "Invalidated AudioClient - Releasing");
365 CloseHandle(m_needDataEvent);
367 SAFE_RELEASE(m_pRenderClient);
368 SAFE_RELEASE(m_pAudioClient);
369 SAFE_RELEASE(m_pDevice);
371 m_initialized = false;
377 double CAESinkWASAPI::GetDelay()
382 double time_played = 0.0;
385 unsigned int now = XbmcThreads::SystemClockMillis();
386 time_played = (double)(now-m_lastWriteToBuffer) / 1000;
389 double delay = m_sinkLatency - time_played + (double)m_bufferPtr / (double)m_format.m_sampleRate;
397 double CAESinkWASAPI::GetCacheTotal()
402 return m_sinkLatency;
405 unsigned int CAESinkWASAPI::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio, bool blocking)
415 LARGE_INTEGER timerStart;
416 LARGE_INTEGER timerStop;
417 LARGE_INTEGER timerFreq;
420 unsigned int NumFramesRequested = m_format.m_frames;
421 unsigned int FramesToCopy = std::min(m_format.m_frames - m_bufferPtr, frames);
422 if (m_bufferPtr != 0 || frames != m_format.m_frames)
424 memcpy(m_pBuffer+m_bufferPtr*m_format.m_frameSize, data, FramesToCopy*m_format.m_frameSize);
425 m_bufferPtr += FramesToCopy;
426 if (m_bufferPtr != m_format.m_frames)
430 if (!m_running) //first time called, pre-fill buffer then start audio client
432 hr = m_pAudioClient->Reset();
435 CLog::Log(LOGERROR, __FUNCTION__ " AudioClient reset failed due to %s", WASAPIErrToStr(hr));
438 hr = m_pRenderClient->GetBuffer(NumFramesRequested, &buf);
442 CLog::Log(LOGERROR, __FUNCTION__": GetBuffer failed due to %s", WASAPIErrToStr(hr));
444 m_isDirty = true; //flag new device or re-init needed
448 memset(buf, 0, NumFramesRequested * m_format.m_frameSize); //fill buffer with silence
450 hr = m_pRenderClient->ReleaseBuffer(NumFramesRequested, flags); //pass back to audio driver
454 CLog::Log(LOGDEBUG, __FUNCTION__": ReleaseBuffer failed due to %s.", WASAPIErrToStr(hr));
456 m_isDirty = true; //flag new device or re-init needed
459 hr = m_pAudioClient->Start(); //start the audio driver running
461 CLog::Log(LOGERROR, __FUNCTION__": AudioClient Start Failed");
462 m_running = true; //signal that we're processing frames
467 /* Get clock time for latency checks */
468 QueryPerformanceFrequency(&timerFreq);
469 QueryPerformanceCounter(&timerStart);
472 /* Wait for Audio Driver to tell us it's got a buffer available */
473 DWORD eventAudioCallback;
475 eventAudioCallback = WaitForSingleObject(m_needDataEvent, 0);
477 eventAudioCallback = WaitForSingleObject(m_needDataEvent, 1100);
481 if(eventAudioCallback != WAIT_OBJECT_0)
486 if(eventAudioCallback != WAIT_OBJECT_0 || !&buf)
488 CLog::Log(LOGERROR, __FUNCTION__": Endpoint Buffer timed out");
498 QueryPerformanceCounter(&timerStop);
499 LONGLONG timerDiff = timerStop.QuadPart - timerStart.QuadPart;
500 double timerElapsed = (double) timerDiff * 1000.0 / (double) timerFreq.QuadPart;
501 m_avgTimeWaiting += (timerElapsed - m_avgTimeWaiting) * 0.5;
503 if (m_avgTimeWaiting < 3.0)
505 CLog::Log(LOGDEBUG, __FUNCTION__": Possible AQ Loss: Avg. Time Waiting for Audio Driver callback : %dmsec", (int)m_avgTimeWaiting);
509 hr = m_pRenderClient->GetBuffer(NumFramesRequested, &buf);
513 CLog::Log(LOGERROR, __FUNCTION__": GetBuffer failed due to %s", WASAPIErrToStr(hr));
517 memcpy(buf, m_bufferPtr == 0 ? data : m_pBuffer, NumFramesRequested * m_format.m_frameSize); //fill buffer
519 hr = m_pRenderClient->ReleaseBuffer(NumFramesRequested, flags); //pass back to audio driver
523 CLog::Log(LOGDEBUG, __FUNCTION__": ReleaseBuffer failed due to %s.", WASAPIErrToStr(hr));
527 m_lastWriteToBuffer = XbmcThreads::SystemClockMillis();
529 if (FramesToCopy != frames)
531 m_bufferPtr = frames-FramesToCopy;
532 memcpy(m_pBuffer, data+FramesToCopy*m_format.m_frameSize, m_bufferPtr*m_format.m_frameSize);
538 void CAESinkWASAPI::EnumerateDevicesEx(AEDeviceInfoList &deviceInfoList, bool force)
540 IMMDeviceEnumerator* pEnumerator = NULL;
541 IMMDeviceCollection* pEnumDevices = NULL;
542 IMMDevice* pDefaultDevice = NULL;
543 CAEDeviceInfo deviceInfo;
544 CAEChannelInfo deviceChannels;
545 LPWSTR pwszID = NULL;
546 std::wstring wstrDDID;
548 WAVEFORMATEXTENSIBLE wfxex = {0};
551 hr = CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void**)&pEnumerator);
552 EXIT_ON_FAILURE(hr, __FUNCTION__": Could not allocate WASAPI device enumerator. CoCreateInstance error code: %li", hr)
556 // get the default audio endpoint
557 if(pEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &pDefaultDevice) == S_OK)
559 if(pDefaultDevice->GetId(&pwszID) == S_OK)
562 CoTaskMemFree(pwszID);
564 SAFE_RELEASE(pDefaultDevice);
567 // enumerate over all audio endpoints
568 hr = pEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &pEnumDevices);
569 EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of audio endpoint enumeration failed.")
571 hr = pEnumDevices->GetCount(&uiCount);
572 EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of audio endpoint count failed.")
574 for (UINT i = 0; i < uiCount; i++)
576 IMMDevice *pDevice = NULL;
577 IPropertyStore *pProperty = NULL;
579 PropVariantInit(&varName);
581 deviceInfo.m_channels.Reset();
582 deviceInfo.m_dataFormats.clear();
583 deviceInfo.m_sampleRates.clear();
585 hr = pEnumDevices->Item(i, &pDevice);
588 CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint failed.");
592 hr = pDevice->OpenPropertyStore(STGM_READ, &pProperty);
595 CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint properties failed.");
596 SAFE_RELEASE(pDevice);
600 hr = pProperty->GetValue(PKEY_Device_FriendlyName, &varName);
603 CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint device name failed.");
604 SAFE_RELEASE(pDevice);
605 SAFE_RELEASE(pProperty);
609 std::string strFriendlyName = localWideToUtf(varName.pwszVal);
610 PropVariantClear(&varName);
612 hr = pProperty->GetValue(PKEY_AudioEndpoint_GUID, &varName);
615 CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint GUID failed.");
616 SAFE_RELEASE(pDevice);
617 SAFE_RELEASE(pProperty);
621 std::string strDevName = localWideToUtf(varName.pwszVal);
622 PropVariantClear(&varName);
624 hr = pProperty->GetValue(PKEY_AudioEndpoint_FormFactor, &varName);
627 CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint form factor failed.");
628 SAFE_RELEASE(pDevice);
629 SAFE_RELEASE(pProperty);
632 std::string strWinDevType = winEndpoints[(EndpointFormFactor)varName.uiVal].winEndpointType;
633 AEDeviceType aeDeviceType = winEndpoints[(EndpointFormFactor)varName.uiVal].aeDeviceType;
635 PropVariantClear(&varName);
637 hr = pProperty->GetValue(PKEY_AudioEndpoint_PhysicalSpeakers, &varName);
640 CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint speaker layout failed.");
641 SAFE_RELEASE(pDevice);
642 SAFE_RELEASE(pProperty);
645 unsigned int uiChannelMask = std::max(varName.uintVal, (unsigned int) KSAUDIO_SPEAKER_STEREO);
647 deviceChannels.Reset();
649 for (unsigned int c = 0; c < WASAPI_SPEAKER_COUNT; c++)
651 if (uiChannelMask & WASAPIChannelOrder[c])
652 deviceChannels += AEChannelNames[c];
655 PropVariantClear(&varName);
657 IAudioClient *pClient;
658 hr = pDevice->Activate(IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&pClient);
661 /* Test format DTS-HD */
662 wfxex.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
663 wfxex.Format.nSamplesPerSec = 192000;
664 wfxex.dwChannelMask = KSAUDIO_SPEAKER_7POINT1_SURROUND;
665 wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
666 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DTS_HD;
667 wfxex.Format.wBitsPerSample = 16;
668 wfxex.Samples.wValidBitsPerSample = 16;
669 wfxex.Format.nChannels = 8;
670 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
671 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
672 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
674 deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_DTSHD));
676 /* Test format Dolby TrueHD */
677 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_MLP;
678 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
680 deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_TRUEHD));
682 /* Test format Dolby EAC3 */
683 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL_PLUS;
684 wfxex.Format.nChannels = 2;
685 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
686 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
687 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
689 deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_EAC3));
691 /* Test format DTS */
692 wfxex.Format.nSamplesPerSec = 48000;
693 wfxex.dwChannelMask = KSAUDIO_SPEAKER_5POINT1;
694 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DTS;
695 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
696 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
697 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
699 deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_DTS));
701 /* Test format Dolby AC3 */
702 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL;
703 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
705 deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_AC3));
707 /* Test format AAC */
708 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_AAC;
709 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
711 deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_AAC));
713 /* Test format for PCM format iteration */
714 wfxex.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
715 wfxex.dwChannelMask = KSAUDIO_SPEAKER_STEREO;
716 wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
717 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
719 for (int p = AE_FMT_FLOAT; p > AE_FMT_INVALID; p--)
721 if (p < AE_FMT_FLOAT)
722 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
723 wfxex.Format.wBitsPerSample = CAEUtil::DataFormatToBits((AEDataFormat) p);
724 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
725 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
726 if (p <= AE_FMT_S24NE4 && p >= AE_FMT_S24BE4)
728 wfxex.Samples.wValidBitsPerSample = 24;
732 wfxex.Samples.wValidBitsPerSample = wfxex.Format.wBitsPerSample;
735 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
737 deviceInfo.m_dataFormats.push_back((AEDataFormat) p);
740 /* Test format for sample rate iteration */
741 wfxex.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
742 wfxex.dwChannelMask = KSAUDIO_SPEAKER_STEREO;
743 wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
744 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
745 wfxex.Format.wBitsPerSample = 16;
746 wfxex.Samples.wValidBitsPerSample = 16;
747 wfxex.Format.nChannels = 2;
748 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
749 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
751 for (int j = 0; j < WASAPISampleRateCount; j++)
753 wfxex.Format.nSamplesPerSec = WASAPISampleRates[j];
754 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
755 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
757 deviceInfo.m_sampleRates.push_back(WASAPISampleRates[j]);
760 /* Test format for channels iteration */
761 wfxex.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
762 wfxex.dwChannelMask = KSAUDIO_SPEAKER_STEREO;
763 wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
764 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
765 wfxex.Format.nSamplesPerSec = 48000;
766 wfxex.Format.wBitsPerSample = 16;
767 wfxex.Samples.wValidBitsPerSample = 16;
768 wfxex.Format.nChannels = 2;
769 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
770 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
772 bool hasLpcm = false;
774 // Try with KSAUDIO_SPEAKER_DIRECTOUT
775 for (unsigned int k = WASAPI_SPEAKER_COUNT; k > 0; k--)
777 wfxex.dwChannelMask = KSAUDIO_SPEAKER_DIRECTOUT;
778 wfxex.Format.nChannels = k;
779 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
780 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
781 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
784 if (k > 3) // Add only multichannel LPCM
786 deviceInfo.m_dataFormats.push_back(AE_FMT_LPCM);
793 /* Try with reported channel mask */
794 for (unsigned int k = WASAPI_SPEAKER_COUNT; k > 0; k--)
796 wfxex.dwChannelMask = uiChannelMask;
797 wfxex.Format.nChannels = k;
798 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
799 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
800 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
803 if ( !hasLpcm && k > 3) // Add only multichannel LPCM
805 deviceInfo.m_dataFormats.push_back(AE_FMT_LPCM);
812 /* Try with specific speakers configurations */
813 for (unsigned int i = 0; i < ARRAYSIZE(layoutsList); i++)
815 unsigned int nmbOfCh;
816 wfxex.dwChannelMask = ChLayoutToChMask(layoutsList[i], &nmbOfCh);
817 wfxex.Format.nChannels = nmbOfCh;
818 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
819 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
820 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
823 if ( deviceChannels.Count() < nmbOfCh)
824 deviceChannels = layoutsList[i];
825 if ( !hasLpcm && nmbOfCh > 3) // Add only multichannel LPCM
827 deviceInfo.m_dataFormats.push_back(AE_FMT_LPCM);
836 CLog::Log(LOGDEBUG, __FUNCTION__": Failed to activate device for passthrough capability testing.");
839 deviceInfo.m_deviceName = strDevName;
840 deviceInfo.m_displayName = strWinDevType.append(strFriendlyName);
841 deviceInfo.m_displayNameExtra = std::string("WASAPI: ").append(strFriendlyName);
842 deviceInfo.m_deviceType = aeDeviceType;
843 deviceInfo.m_channels = deviceChannels;
845 /* Store the device info */
846 deviceInfoList.push_back(deviceInfo);
848 if(pDevice->GetId(&pwszID) == S_OK)
850 if(wstrDDID.compare(pwszID) == 0)
852 deviceInfo.m_deviceName = std::string("default");
853 deviceInfo.m_displayName = std::string("default");
854 deviceInfo.m_displayNameExtra = std::string("");
855 deviceInfoList.push_back(deviceInfo);
857 CoTaskMemFree(pwszID);
860 SAFE_RELEASE(pDevice);
861 SAFE_RELEASE(pProperty);
868 CLog::Log(LOGERROR, __FUNCTION__": Failed to enumerate WASAPI endpoint devices (%s).", WASAPIErrToStr(hr));
870 SAFE_RELEASE(pEnumDevices);
871 SAFE_RELEASE(pEnumerator);
874 //Private utility functions////////////////////////////////////////////////////
876 void CAESinkWASAPI::BuildWaveFormatExtensible(AEAudioFormat &format, WAVEFORMATEXTENSIBLE &wfxex)
878 wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
879 wfxex.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
882 if (!AE_IS_RAW(format.m_dataFormat)) // PCM data
884 wfxex.dwChannelMask = SpeakerMaskFromAEChannels(format.m_channelLayout);
885 wfxex.Format.nChannels = (WORD)format.m_channelLayout.Count();
886 wfxex.Format.nSamplesPerSec = format.m_sampleRate;
887 wfxex.Format.wBitsPerSample = CAEUtil::DataFormatToBits((AEDataFormat) format.m_dataFormat);
888 wfxex.SubFormat = format.m_dataFormat <= AE_FMT_FLOAT ? KSDATAFORMAT_SUBTYPE_PCM : KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
892 wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
893 if (format.m_dataFormat == AE_FMT_AC3 || format.m_dataFormat == AE_FMT_DTS)
895 wfxex.dwChannelMask = bool (format.m_channelLayout.Count() == 2) ? KSAUDIO_SPEAKER_STEREO : KSAUDIO_SPEAKER_5POINT1;
896 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL;
897 wfxex.Format.wBitsPerSample = 16;
898 wfxex.Samples.wValidBitsPerSample = 16;
899 wfxex.Format.nChannels = (WORD)format.m_channelLayout.Count();
900 wfxex.Format.nSamplesPerSec = format.m_sampleRate;
902 else if (format.m_dataFormat == AE_FMT_EAC3 || format.m_dataFormat == AE_FMT_TRUEHD || format.m_dataFormat == AE_FMT_DTSHD)
904 /* IEC 61937 transmissions over HDMI */
905 wfxex.Format.nSamplesPerSec = 192000L;
906 wfxex.Format.wBitsPerSample = 16;
907 wfxex.Samples.wValidBitsPerSample = 16;
908 wfxex.dwChannelMask = KSAUDIO_SPEAKER_7POINT1_SURROUND;
910 switch (format.m_dataFormat)
913 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL_PLUS;
914 wfxex.Format.nChannels = 2; // One IEC 60958 Line.
915 wfxex.dwChannelMask = KSAUDIO_SPEAKER_5POINT1;
918 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_MLP;
919 wfxex.Format.nChannels = 8; // Four IEC 60958 Lines.
920 wfxex.dwChannelMask = KSAUDIO_SPEAKER_7POINT1_SURROUND;
923 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DTS_HD;
924 wfxex.Format.nChannels = 8; // Four IEC 60958 Lines.
925 wfxex.dwChannelMask = KSAUDIO_SPEAKER_7POINT1_SURROUND;
929 if (format.m_channelLayout.Count() == 8)
930 wfxex.dwChannelMask = KSAUDIO_SPEAKER_7POINT1_SURROUND;
932 wfxex.dwChannelMask = KSAUDIO_SPEAKER_5POINT1;
936 if (wfxex.Format.wBitsPerSample == 32 && wfxex.SubFormat != KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)
937 wfxex.Samples.wValidBitsPerSample = 24;
939 wfxex.Samples.wValidBitsPerSample = wfxex.Format.wBitsPerSample;
941 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
942 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
945 void CAESinkWASAPI::BuildWaveFormatExtensibleIEC61397(AEAudioFormat &format, WAVEFORMATEXTENSIBLE_IEC61937 &wfxex)
947 /* Fill the common structure */
948 BuildWaveFormatExtensible(format, wfxex.FormatExt);
950 /* Code below kept for future use - preferred for later Windows versions */
951 /* but can cause problems on older Windows versions and drivers */
953 wfxex.FormatExt.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE_IEC61937)-sizeof(WAVEFORMATEX);
954 wfxex.dwEncodedChannelCount = format.m_channelLayout.Count();
955 wfxex.dwEncodedSamplesPerSec = bool(format.m_dataFormat == AE_FMT_TRUEHD ||
956 format.m_dataFormat == AE_FMT_DTSHD ||
957 format.m_dataFormat == AE_FMT_EAC3) ? 96000L : 48000L;
958 wfxex.dwAverageBytesPerSec = 0; //Ignored */
961 bool CAESinkWASAPI::InitializeExclusive(AEAudioFormat &format)
963 WAVEFORMATEXTENSIBLE_IEC61937 wfxex_iec61937;
964 WAVEFORMATEXTENSIBLE &wfxex = wfxex_iec61937.FormatExt;
966 if (format.m_dataFormat <= AE_FMT_FLOAT)
967 BuildWaveFormatExtensible(format, wfxex);
969 BuildWaveFormatExtensibleIEC61397(format, wfxex_iec61937);
971 /* Test for incomplete format and provide defaults */
972 if (format.m_sampleRate == 0 ||
973 format.m_channelLayout == NULL ||
974 format.m_dataFormat <= AE_FMT_INVALID ||
975 format.m_dataFormat >= AE_FMT_MAX ||
976 format.m_channelLayout.Count() == 0)
978 wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
979 wfxex.Format.nChannels = 2;
980 wfxex.Format.nSamplesPerSec = 44100L;
981 wfxex.Format.wBitsPerSample = 16;
982 wfxex.Format.nBlockAlign = 4;
983 wfxex.Samples.wValidBitsPerSample = 16;
984 wfxex.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
985 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nBlockAlign * wfxex.Format.nSamplesPerSec;
986 wfxex.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
987 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
990 HRESULT hr = m_pAudioClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
994 CLog::Log(LOGINFO, __FUNCTION__": Format is Supported - will attempt to Initialize");
997 else if (hr != AUDCLNT_E_UNSUPPORTED_FORMAT) //It failed for a reason unrelated to an unsupported format.
999 CLog::Log(LOGERROR, __FUNCTION__": IsFormatSupported failed (%s)", WASAPIErrToStr(hr));
1002 else if (AE_IS_RAW(format.m_dataFormat)) //No sense in trying other formats for passthrough.
1005 CLog::Log(LOGERROR, __FUNCTION__": IsFormatSupported failed (%s) - trying to find a compatible format", WASAPIErrToStr(hr));
1008 unsigned int requestedChannels = wfxex.Format.nChannels;
1009 unsigned int noOfCh;
1011 /* The requested format is not supported by the device. Find something that works */
1012 for (int layout = -1; layout <= (int)ARRAYSIZE(layoutsList); layout++)
1014 // if requested layout is not suppported, try standard layouts with at least
1015 // the number of channels as requested
1016 // as the last resort try stereo
1017 if (layout == ARRAYSIZE(layoutsList))
1019 wfxex.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
1020 wfxex.Format.nChannels = 2;
1022 else if (layout >= 0)
1024 wfxex.dwChannelMask = ChLayoutToChMask(layoutsList[layout], &noOfCh);
1025 wfxex.Format.nChannels = noOfCh;
1026 if (noOfCh < requestedChannels)
1030 for (int j = 0; j < sizeof(testFormats)/sizeof(sampleFormat); j++)
1034 wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
1035 wfxex.SubFormat = testFormats[j].subFormat;
1036 wfxex.Format.wBitsPerSample = testFormats[j].bitsPerSample;
1037 wfxex.Samples.wValidBitsPerSample = testFormats[j].validBitsPerSample;
1038 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
1040 for (int i = 0 ; i < WASAPISampleRateCount; i++)
1042 wfxex.Format.nSamplesPerSec = WASAPISampleRates[i];
1043 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
1045 /* Trace format match iteration loop via log */
1047 CLog::Log(LOGDEBUG, "WASAPI: Trying Format: %s, %d, %d, %d", CAEUtil::DataFormatToStr(testFormats[j].subFormatType),
1048 wfxex.Format.nSamplesPerSec,
1049 wfxex.Format.wBitsPerSample,
1050 wfxex.Samples.wValidBitsPerSample);
1053 hr = m_pAudioClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
1057 /* If the current sample rate matches the source then stop looking and use it */
1058 if ((WASAPISampleRates[i] == format.m_sampleRate) && (testFormats[j].subFormatType <= format.m_dataFormat))
1060 /* If this rate is closer to the source then the previous one, save it */
1061 else if (closestMatch < 0 || abs((int)WASAPISampleRates[i] - (int)format.m_sampleRate) < abs((int)WASAPISampleRates[closestMatch] - (int)format.m_sampleRate))
1064 else if (hr != AUDCLNT_E_UNSUPPORTED_FORMAT)
1065 CLog::Log(LOGERROR, __FUNCTION__": IsFormatSupported failed (%s)", WASAPIErrToStr(hr));
1068 if (closestMatch >= 0)
1070 wfxex.Format.nSamplesPerSec = WASAPISampleRates[closestMatch];
1071 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
1077 CLog::Log(LOGERROR, __FUNCTION__": Unable to locate a supported output format for the device. Check the speaker settings in the control panel.");
1079 /* We couldn't find anything supported. This should never happen */
1080 /* unless the user set the wrong speaker setting in the control panel */
1085 AEChannelsFromSpeakerMask(wfxex.dwChannelMask);
1086 format.m_channelLayout = m_channelLayout;
1088 /* When the stream is raw, the values in the format structure are set to the link */
1089 /* parameters, so store the encoded stream values here for the IsCompatible function */
1090 m_encodedFormat = format.m_dataFormat;
1091 m_encodedChannels = wfxex.Format.nChannels;
1092 m_encodedSampleRate = format.m_encodedRate;
1093 wfxex_iec61937.dwEncodedChannelCount = wfxex.Format.nChannels;
1094 wfxex_iec61937.dwEncodedSamplesPerSec = m_encodedSampleRate;
1096 /* Set up returned sink format for engine */
1097 if (!AE_IS_RAW(format.m_dataFormat))
1099 if (wfxex.Format.wBitsPerSample == 32)
1101 if (wfxex.SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)
1102 format.m_dataFormat = AE_FMT_FLOAT;
1103 else if (wfxex.Samples.wValidBitsPerSample == 32)
1104 format.m_dataFormat = AE_FMT_S32NE;
1106 format.m_dataFormat = AE_FMT_S24NE4;
1108 else if (wfxex.Format.wBitsPerSample == 24)
1109 format.m_dataFormat = AE_FMT_S24NE3;
1111 format.m_dataFormat = AE_FMT_S16NE;
1114 format.m_sampleRate = wfxex.Format.nSamplesPerSec; //PCM: Sample rate. RAW: Link speed
1115 format.m_frameSize = (wfxex.Format.wBitsPerSample >> 3) * wfxex.Format.nChannels;
1117 REFERENCE_TIME audioSinkBufferDurationMsec, hnsLatency;
1119 audioSinkBufferDurationMsec = (REFERENCE_TIME)500000;
1120 audioSinkBufferDurationMsec = (REFERENCE_TIME)((audioSinkBufferDurationMsec / format.m_frameSize) * format.m_frameSize); //even number of frames
1122 if (AE_IS_RAW(format.m_dataFormat))
1123 format.m_dataFormat = AE_FMT_S16NE;
1125 hr = m_pAudioClient->Initialize(AUDCLNT_SHAREMODE_EXCLUSIVE, AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_NOPERSIST,
1126 audioSinkBufferDurationMsec, audioSinkBufferDurationMsec, &wfxex.Format, NULL);
1128 if (hr == AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED)
1130 /* WASAPI requires aligned buffer */
1131 /* Get the next aligned frame */
1132 hr = m_pAudioClient->GetBufferSize(&m_uiBufferLen);
1135 CLog::Log(LOGERROR, __FUNCTION__": GetBufferSize Failed : %s", WASAPIErrToStr(hr));
1139 audioSinkBufferDurationMsec = (REFERENCE_TIME) ((10000.0 * 1000 / wfxex.Format.nSamplesPerSec * m_uiBufferLen) + 0.5);
1141 /* Release the previous allocations */
1142 SAFE_RELEASE(m_pAudioClient);
1144 /* Create a new audio client */
1145 hr = m_pDevice->Activate(IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&m_pAudioClient);
1148 CLog::Log(LOGERROR, __FUNCTION__": Device Activation Failed : %s", WASAPIErrToStr(hr));
1152 /* Open the stream and associate it with an audio session */
1153 hr = m_pAudioClient->Initialize(AUDCLNT_SHAREMODE_EXCLUSIVE, AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_NOPERSIST,
1154 audioSinkBufferDurationMsec, audioSinkBufferDurationMsec, &wfxex.Format, NULL);
1158 CLog::Log(LOGERROR, __FUNCTION__": Failed to initialize WASAPI in exclusive mode %d - (%s).", HRESULT(hr), WASAPIErrToStr(hr));
1159 CLog::Log(LOGDEBUG, " Sample Rate : %d", wfxex.Format.nSamplesPerSec);
1160 CLog::Log(LOGDEBUG, " Sample Format : %s", CAEUtil::DataFormatToStr(format.m_dataFormat));
1161 CLog::Log(LOGDEBUG, " Bits Per Sample : %d", wfxex.Format.wBitsPerSample);
1162 CLog::Log(LOGDEBUG, " Valid Bits/Samp : %d", wfxex.Samples.wValidBitsPerSample);
1163 CLog::Log(LOGDEBUG, " Channel Count : %d", wfxex.Format.nChannels);
1164 CLog::Log(LOGDEBUG, " Block Align : %d", wfxex.Format.nBlockAlign);
1165 CLog::Log(LOGDEBUG, " Avg. Bytes Sec : %d", wfxex.Format.nAvgBytesPerSec);
1166 CLog::Log(LOGDEBUG, " Samples/Block : %d", wfxex.Samples.wSamplesPerBlock);
1167 CLog::Log(LOGDEBUG, " Format cBSize : %d", wfxex.Format.cbSize);
1168 CLog::Log(LOGDEBUG, " Channel Layout : %s", ((std::string)format.m_channelLayout).c_str());
1169 CLog::Log(LOGDEBUG, " Enc. Channels : %d", wfxex_iec61937.dwEncodedChannelCount);
1170 CLog::Log(LOGDEBUG, " Enc. Samples/Sec: %d", wfxex_iec61937.dwEncodedSamplesPerSec);
1171 CLog::Log(LOGDEBUG, " Channel Mask : %d", wfxex.dwChannelMask);
1172 CLog::Log(LOGDEBUG, " Periodicty : %d", audioSinkBufferDurationMsec);
1176 /* Latency of WASAPI buffers in event-driven mode is equal to the returned value */
1177 /* of GetStreamLatency converted from 100ns intervals to seconds then multiplied */
1178 /* by two as there are two equally-sized buffers and playback starts when the */
1179 /* second buffer is filled. Multiplying the returned 100ns intervals by 0.0000002 */
1180 /* is handles both the unit conversion and twin buffers. */
1181 hr = m_pAudioClient->GetStreamLatency(&hnsLatency);
1184 CLog::Log(LOGERROR, __FUNCTION__": GetStreamLatency Failed : %s", WASAPIErrToStr(hr));
1188 m_sinkLatency = hnsLatency * 0.0000002;
1190 CLog::Log(LOGINFO, __FUNCTION__": WASAPI Exclusive Mode Sink Initialized using: %s, %d, %d",
1191 CAEUtil::DataFormatToStr(format.m_dataFormat),
1192 wfxex.Format.nSamplesPerSec,
1193 wfxex.Format.nChannels);
1197 void CAESinkWASAPI::AEChannelsFromSpeakerMask(DWORD speakers)
1199 m_channelLayout.Reset();
1201 for (int i = 0; i < WASAPI_SPEAKER_COUNT; i++)
1203 if (speakers & WASAPIChannelOrder[i])
1204 m_channelLayout += AEChannelNames[i];
1208 DWORD CAESinkWASAPI::SpeakerMaskFromAEChannels(const CAEChannelInfo &channels)
1212 for (unsigned int i = 0; i < channels.Count(); i++)
1214 for (unsigned int j = 0; j < WASAPI_SPEAKER_COUNT; j++)
1215 if (channels[i] == AEChannelNames[j])
1216 mask |= WASAPIChannelOrder[j];
1221 const char *CAESinkWASAPI::WASAPIErrToStr(HRESULT err)
1225 ERRTOSTR(AUDCLNT_E_NOT_INITIALIZED);
1226 ERRTOSTR(AUDCLNT_E_ALREADY_INITIALIZED);
1227 ERRTOSTR(AUDCLNT_E_WRONG_ENDPOINT_TYPE);
1228 ERRTOSTR(AUDCLNT_E_DEVICE_INVALIDATED);
1229 ERRTOSTR(AUDCLNT_E_NOT_STOPPED);
1230 ERRTOSTR(AUDCLNT_E_BUFFER_TOO_LARGE);
1231 ERRTOSTR(AUDCLNT_E_OUT_OF_ORDER);
1232 ERRTOSTR(AUDCLNT_E_UNSUPPORTED_FORMAT);
1233 ERRTOSTR(AUDCLNT_E_INVALID_SIZE);
1234 ERRTOSTR(AUDCLNT_E_DEVICE_IN_USE);
1235 ERRTOSTR(AUDCLNT_E_BUFFER_OPERATION_PENDING);
1236 ERRTOSTR(AUDCLNT_E_THREAD_NOT_REGISTERED);
1237 ERRTOSTR(AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED);
1238 ERRTOSTR(AUDCLNT_E_ENDPOINT_CREATE_FAILED);
1239 ERRTOSTR(AUDCLNT_E_SERVICE_NOT_RUNNING);
1240 ERRTOSTR(AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED);
1241 ERRTOSTR(AUDCLNT_E_EXCLUSIVE_MODE_ONLY);
1242 ERRTOSTR(AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL);
1243 ERRTOSTR(AUDCLNT_E_EVENTHANDLE_NOT_SET);
1244 ERRTOSTR(AUDCLNT_E_INCORRECT_BUFFER_SIZE);
1245 ERRTOSTR(AUDCLNT_E_BUFFER_SIZE_ERROR);
1246 ERRTOSTR(AUDCLNT_E_CPUUSAGE_EXCEEDED);
1247 ERRTOSTR(AUDCLNT_E_BUFFER_ERROR);
1248 ERRTOSTR(AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED);
1249 ERRTOSTR(AUDCLNT_E_INVALID_DEVICE_PERIOD);
1250 ERRTOSTR(E_POINTER);
1251 ERRTOSTR(E_INVALIDARG);
1252 ERRTOSTR(E_OUTOFMEMORY);
1258 void CAESinkWASAPI::Drain()
1263 Sleep( (DWORD)(GetDelay()*500) );
1269 m_pAudioClient->Stop(); //stop the audio output
1270 m_pAudioClient->Reset(); //flush buffer and reset audio clock stream position
1274 CLog::Log(LOGDEBUG, __FUNCTION__, "Invalidated AudioClient - Releasing");