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),
197 m_hnsRequestedDuration(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::EndsWith(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 bool CAESinkWASAPI::IsCompatible(const AEAudioFormat format, const std::string &device)
380 if (!m_initialized || m_isDirty)
383 u_int notCompatible = 0;
384 const u_int numTests = 5;
385 std::string strDiffBecause ("");
386 static const char* compatibleParams[numTests] = {":Devices",
390 ":Passthrough Formats"};
392 notCompatible = (notCompatible +!((AE_IS_RAW(format.m_dataFormat) == AE_IS_RAW(m_encodedFormat)) ||
393 (!AE_IS_RAW(format.m_dataFormat) == !AE_IS_RAW(m_encodedFormat)))) << 1;
394 notCompatible = (notCompatible +!((sinkReqFormat == format.m_dataFormat) &&
395 (sinkRetFormat == m_format.m_dataFormat))) << 1;
396 notCompatible = (notCompatible + !(format.m_sampleRate == m_format.m_sampleRate)) << 1;
397 notCompatible = (notCompatible + !(format.m_channelLayout.Count() == m_format.m_channelLayout.Count())) << 1;
398 notCompatible = (notCompatible + !(m_device == device));
402 CLog::Log(LOGDEBUG, __FUNCTION__": Formats compatible - reusing existing sink");
406 for (int i = 0; i < numTests ; i++)
408 strDiffBecause += (notCompatible & 0x01) ? (std::string) compatibleParams[i] : "";
409 notCompatible = notCompatible >> 1;
412 CLog::Log(LOGDEBUG, __FUNCTION__": Formats Incompatible due to different %s", strDiffBecause.c_str());
416 double CAESinkWASAPI::GetDelay()
421 return m_sinkLatency;
424 double CAESinkWASAPI::GetCacheTime()
426 /* This function deviates from the defined usage due to the event-driven */
427 /* mode of WASAPI utilizing twin buffers which are written to in single */
428 /* buffer chunks. Therefore the buffers are either 100% full or 50% full */
429 /* At 50% issues arise with water levels in the stream and player. For */
430 /* this reason the cache is shown as 100% full at all times, and control */
431 /* of the buffer filling is assumed in AddPackets() and by the WASAPI */
432 /* implementation of the WaitforSingleObject event indicating one of the */
433 /* buffers is ready for filling via AddPackets */
437 return m_sinkLatency;
440 double CAESinkWASAPI::GetCacheTotal()
445 return m_sinkLatency;
448 unsigned int CAESinkWASAPI::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio, bool blocking)
458 LARGE_INTEGER timerStart;
459 LARGE_INTEGER timerStop;
460 LARGE_INTEGER timerFreq;
463 unsigned int NumFramesRequested = m_format.m_frames;
464 unsigned int FramesToCopy = std::min(m_format.m_frames - m_bufferPtr, frames);
465 if (m_bufferPtr != 0 || frames != m_format.m_frames)
467 memcpy(m_pBuffer+m_bufferPtr*m_format.m_frameSize, data, FramesToCopy*m_format.m_frameSize);
468 m_bufferPtr += FramesToCopy;
469 if (frames != m_format.m_frames)
473 if (!m_running) //first time called, pre-fill buffer then start audio client
475 hr = m_pAudioClient->Reset();
478 CLog::Log(LOGERROR, __FUNCTION__ " AudioClient reset failed due to %s", WASAPIErrToStr(hr));
481 hr = m_pRenderClient->GetBuffer(NumFramesRequested, &buf);
485 CLog::Log(LOGERROR, __FUNCTION__": GetBuffer failed due to %s", WASAPIErrToStr(hr));
487 m_isDirty = true; //flag new device or re-init needed
491 /* Inject one buffer of silence if sink has just opened */
492 /* to avoid losing start of stream or GUI sound */
493 if (g_advancedSettings.m_streamSilence)
494 memcpy(buf, data, NumFramesRequested * m_format.m_frameSize); //fill buffer with audio
496 memset(buf, 0, NumFramesRequested * m_format.m_frameSize); //fill buffer with silence
498 hr = m_pRenderClient->ReleaseBuffer(NumFramesRequested, flags); //pass back to audio driver
502 CLog::Log(LOGDEBUG, __FUNCTION__": ReleaseBuffer failed due to %s.", WASAPIErrToStr(hr));
504 m_isDirty = true; //flag new device or re-init needed
507 hr = m_pAudioClient->Start(); //start the audio driver running
509 CLog::Log(LOGERROR, __FUNCTION__": AudioClient Start Failed");
510 m_running = true; //signal that we're processing frames
511 return g_advancedSettings.m_streamSilence ? NumFramesRequested : 0U;
515 /* Get clock time for latency checks */
516 QueryPerformanceFrequency(&timerFreq);
517 QueryPerformanceCounter(&timerStart);
520 /* Wait for Audio Driver to tell us it's got a buffer available */
521 DWORD eventAudioCallback;
523 eventAudioCallback = WaitForSingleObject(m_needDataEvent, 0);
525 eventAudioCallback = WaitForSingleObject(m_needDataEvent, 1100);
529 if(eventAudioCallback != WAIT_OBJECT_0)
534 if(eventAudioCallback != WAIT_OBJECT_0 || !&buf)
536 /* Event handle timed out - flag sink as dirty for re-initializing */
537 CLog::Log(LOGERROR, __FUNCTION__": Endpoint Buffer timed out");
538 if (g_advancedSettings.m_streamSilence)
540 m_isDirty = true; //flag new device or re-init needed
553 QueryPerformanceCounter(&timerStop);
554 LONGLONG timerDiff = timerStop.QuadPart - timerStart.QuadPart;
555 double timerElapsed = (double) timerDiff * 1000.0 / (double) timerFreq.QuadPart;
556 m_avgTimeWaiting += (timerElapsed - m_avgTimeWaiting) * 0.5;
558 if (m_avgTimeWaiting < 3.0)
560 CLog::Log(LOGDEBUG, __FUNCTION__": Possible AQ Loss: Avg. Time Waiting for Audio Driver callback : %dmsec", (int)m_avgTimeWaiting);
564 hr = m_pRenderClient->GetBuffer(NumFramesRequested, &buf);
568 CLog::Log(LOGERROR, __FUNCTION__": GetBuffer failed due to %s", WASAPIErrToStr(hr));
572 memcpy(buf, m_bufferPtr == 0 ? data : m_pBuffer, NumFramesRequested * m_format.m_frameSize); //fill buffer
574 hr = m_pRenderClient->ReleaseBuffer(NumFramesRequested, flags); //pass back to audio driver
578 CLog::Log(LOGDEBUG, __FUNCTION__": ReleaseBuffer failed due to %s.", WASAPIErrToStr(hr));
583 if (FramesToCopy != frames)
585 m_bufferPtr = frames-FramesToCopy;
586 memcpy(m_pBuffer, data+FramesToCopy*m_format.m_frameSize, m_bufferPtr*m_format.m_frameSize);
592 bool CAESinkWASAPI::SoftSuspend()
594 /* Sink has been asked to suspend output - we release audio */
595 /* device as we are in exclusive mode and thus allow external */
596 /* audio sources to play. This requires us to reinitialize */
604 bool CAESinkWASAPI::SoftResume()
606 /* Sink asked to resume output. To release audio device in */
607 /* exclusive mode we release the device context and therefore */
608 /* must reinitialize. Return false to force re-init by engine */
613 void CAESinkWASAPI::EnumerateDevicesEx(AEDeviceInfoList &deviceInfoList, bool force)
615 IMMDeviceEnumerator* pEnumerator = NULL;
616 IMMDeviceCollection* pEnumDevices = NULL;
617 CAEDeviceInfo deviceInfo;
618 CAEChannelInfo deviceChannels;
620 WAVEFORMATEXTENSIBLE wfxex = {0};
623 // add default device entry
624 deviceInfo.m_deviceName = std::string("default");
625 deviceInfo.m_displayName = std::string("default");
627 /* Store the device info */
628 deviceInfoList.push_back(deviceInfo);
630 hr = CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void**)&pEnumerator);
631 EXIT_ON_FAILURE(hr, __FUNCTION__": Could not allocate WASAPI device enumerator. CoCreateInstance error code: %li", hr)
635 hr = pEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &pEnumDevices);
636 EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of audio endpoint enumeration failed.")
638 hr = pEnumDevices->GetCount(&uiCount);
639 EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of audio endpoint count failed.")
641 for (UINT i = 0; i < uiCount; i++)
643 IMMDevice *pDevice = NULL;
644 IPropertyStore *pProperty = NULL;
646 PropVariantInit(&varName);
648 deviceInfo.m_channels.Reset();
649 deviceInfo.m_dataFormats.clear();
650 deviceInfo.m_sampleRates.clear();
652 hr = pEnumDevices->Item(i, &pDevice);
655 CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint failed.");
659 hr = pDevice->OpenPropertyStore(STGM_READ, &pProperty);
662 CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint properties failed.");
663 SAFE_RELEASE(pDevice);
667 hr = pProperty->GetValue(PKEY_Device_FriendlyName, &varName);
670 CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint device name failed.");
671 SAFE_RELEASE(pDevice);
672 SAFE_RELEASE(pProperty);
676 std::string strFriendlyName = localWideToUtf(varName.pwszVal);
677 PropVariantClear(&varName);
679 hr = pProperty->GetValue(PKEY_AudioEndpoint_GUID, &varName);
682 CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint GUID failed.");
683 SAFE_RELEASE(pDevice);
684 SAFE_RELEASE(pProperty);
688 std::string strDevName = localWideToUtf(varName.pwszVal);
689 PropVariantClear(&varName);
691 hr = pProperty->GetValue(PKEY_AudioEndpoint_FormFactor, &varName);
694 CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint form factor failed.");
695 SAFE_RELEASE(pDevice);
696 SAFE_RELEASE(pProperty);
699 std::string strWinDevType = winEndpoints[(EndpointFormFactor)varName.uiVal].winEndpointType;
700 AEDeviceType aeDeviceType = winEndpoints[(EndpointFormFactor)varName.uiVal].aeDeviceType;
702 PropVariantClear(&varName);
704 hr = pProperty->GetValue(PKEY_AudioEndpoint_PhysicalSpeakers, &varName);
707 CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint speaker layout failed.");
708 SAFE_RELEASE(pDevice);
709 SAFE_RELEASE(pProperty);
712 unsigned int uiChannelMask = std::max(varName.uintVal, (unsigned int) KSAUDIO_SPEAKER_STEREO);
714 deviceChannels.Reset();
716 for (unsigned int c = 0; c < WASAPI_SPEAKER_COUNT; c++)
718 if (uiChannelMask & WASAPIChannelOrder[c])
719 deviceChannels += AEChannelNames[c];
722 PropVariantClear(&varName);
724 IAudioClient *pClient;
725 hr = pDevice->Activate(IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&pClient);
728 /* Test format DTS-HD */
729 wfxex.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
730 wfxex.Format.nSamplesPerSec = 192000;
731 wfxex.dwChannelMask = KSAUDIO_SPEAKER_7POINT1_SURROUND;
732 wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
733 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DTS_HD;
734 wfxex.Format.wBitsPerSample = 16;
735 wfxex.Samples.wValidBitsPerSample = 16;
736 wfxex.Format.nChannels = 8;
737 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
738 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
739 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
741 deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_DTSHD));
743 /* Test format Dolby TrueHD */
744 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_MLP;
745 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
747 deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_TRUEHD));
749 /* Test format Dolby EAC3 */
750 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL_PLUS;
751 wfxex.Format.nChannels = 2;
752 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
753 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
754 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
756 deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_EAC3));
758 /* Test format DTS */
759 wfxex.Format.nSamplesPerSec = 48000;
760 wfxex.dwChannelMask = KSAUDIO_SPEAKER_5POINT1;
761 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DTS;
762 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
763 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
764 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
766 deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_DTS));
768 /* Test format Dolby AC3 */
769 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL;
770 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
772 deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_AC3));
774 /* Test format AAC */
775 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_AAC;
776 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
778 deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_AAC));
780 /* Test format for PCM format iteration */
781 wfxex.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
782 wfxex.dwChannelMask = KSAUDIO_SPEAKER_STEREO;
783 wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
784 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
786 for (int p = AE_FMT_FLOAT; p > AE_FMT_INVALID; p--)
788 if (p < AE_FMT_FLOAT)
789 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
790 wfxex.Format.wBitsPerSample = CAEUtil::DataFormatToBits((AEDataFormat) p);
791 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
792 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
793 if (p <= AE_FMT_S24NE4 && p >= AE_FMT_S24BE4)
795 wfxex.Samples.wValidBitsPerSample = 24;
799 wfxex.Samples.wValidBitsPerSample = wfxex.Format.wBitsPerSample;
802 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
804 deviceInfo.m_dataFormats.push_back((AEDataFormat) p);
807 /* Test format for sample rate iteration */
808 wfxex.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
809 wfxex.dwChannelMask = KSAUDIO_SPEAKER_STEREO;
810 wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
811 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
812 wfxex.Format.wBitsPerSample = 16;
813 wfxex.Samples.wValidBitsPerSample = 16;
814 wfxex.Format.nChannels = 2;
815 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
816 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
818 for (int j = 0; j < WASAPISampleRateCount; j++)
820 wfxex.Format.nSamplesPerSec = WASAPISampleRates[j];
821 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
822 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
824 deviceInfo.m_sampleRates.push_back(WASAPISampleRates[j]);
827 /* Test format for channels iteration */
828 wfxex.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
829 wfxex.dwChannelMask = KSAUDIO_SPEAKER_STEREO;
830 wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
831 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
832 wfxex.Format.nSamplesPerSec = 48000;
833 wfxex.Format.wBitsPerSample = 16;
834 wfxex.Samples.wValidBitsPerSample = 16;
835 wfxex.Format.nChannels = 2;
836 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
837 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
839 bool hasLpcm = false;
841 // Try with KSAUDIO_SPEAKER_DIRECTOUT
842 for (unsigned int k = WASAPI_SPEAKER_COUNT; k > 0; k--)
844 wfxex.dwChannelMask = KSAUDIO_SPEAKER_DIRECTOUT;
845 wfxex.Format.nChannels = k;
846 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
847 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
848 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
851 if (k > 3) // Add only multichannel LPCM
853 deviceInfo.m_dataFormats.push_back(AE_FMT_LPCM);
860 /* Try with reported channel mask */
861 for (unsigned int k = WASAPI_SPEAKER_COUNT; k > 0; k--)
863 wfxex.dwChannelMask = uiChannelMask;
864 wfxex.Format.nChannels = k;
865 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
866 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
867 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
870 if ( !hasLpcm && k > 3) // Add only multichannel LPCM
872 deviceInfo.m_dataFormats.push_back(AE_FMT_LPCM);
879 /* Try with specific speakers configurations */
880 for (unsigned int i = 0; i < ARRAYSIZE(layoutsList); i++)
882 unsigned int nmbOfCh;
883 wfxex.dwChannelMask = ChLayoutToChMask(layoutsList[i], &nmbOfCh);
884 wfxex.Format.nChannels = nmbOfCh;
885 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
886 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
887 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
890 if ( deviceChannels.Count() < nmbOfCh)
891 deviceChannels = layoutsList[i];
892 if ( !hasLpcm && nmbOfCh > 3) // Add only multichannel LPCM
894 deviceInfo.m_dataFormats.push_back(AE_FMT_LPCM);
903 CLog::Log(LOGDEBUG, __FUNCTION__": Failed to activate device for passthrough capability testing.");
906 SAFE_RELEASE(pDevice);
907 SAFE_RELEASE(pProperty);
909 deviceInfo.m_deviceName = strDevName;
910 deviceInfo.m_displayName = strWinDevType.append(strFriendlyName);
911 deviceInfo.m_displayNameExtra = std::string("WASAPI: ").append(strFriendlyName);
912 deviceInfo.m_deviceType = aeDeviceType;
913 deviceInfo.m_channels = deviceChannels;
915 /* Store the device info */
916 deviceInfoList.push_back(deviceInfo);
923 CLog::Log(LOGERROR, __FUNCTION__": Failed to enumerate WASAPI endpoint devices (%s).", WASAPIErrToStr(hr));
925 SAFE_RELEASE(pEnumDevices);
926 SAFE_RELEASE(pEnumerator);
929 //Private utility functions////////////////////////////////////////////////////
931 void CAESinkWASAPI::BuildWaveFormatExtensible(AEAudioFormat &format, WAVEFORMATEXTENSIBLE &wfxex)
933 wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
934 wfxex.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
937 if (!AE_IS_RAW(format.m_dataFormat)) // PCM data
939 wfxex.dwChannelMask = SpeakerMaskFromAEChannels(format.m_channelLayout);
940 wfxex.Format.nChannels = (WORD)format.m_channelLayout.Count();
941 wfxex.Format.nSamplesPerSec = format.m_sampleRate;
942 wfxex.Format.wBitsPerSample = CAEUtil::DataFormatToBits((AEDataFormat) format.m_dataFormat);
943 wfxex.SubFormat = format.m_dataFormat <= AE_FMT_FLOAT ? KSDATAFORMAT_SUBTYPE_PCM : KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
947 wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
948 if (format.m_dataFormat == AE_FMT_AC3 || format.m_dataFormat == AE_FMT_DTS)
950 wfxex.dwChannelMask = bool (format.m_channelLayout.Count() == 2) ? KSAUDIO_SPEAKER_STEREO : KSAUDIO_SPEAKER_5POINT1;
951 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL;
952 wfxex.Format.wBitsPerSample = 16;
953 wfxex.Samples.wValidBitsPerSample = 16;
954 wfxex.Format.nChannels = (WORD)format.m_channelLayout.Count();
955 wfxex.Format.nSamplesPerSec = format.m_sampleRate;
957 else if (format.m_dataFormat == AE_FMT_EAC3 || format.m_dataFormat == AE_FMT_TRUEHD || format.m_dataFormat == AE_FMT_DTSHD)
959 /* IEC 61937 transmissions over HDMI */
960 wfxex.Format.nSamplesPerSec = 192000L;
961 wfxex.Format.wBitsPerSample = 16;
962 wfxex.Samples.wValidBitsPerSample = 16;
963 wfxex.dwChannelMask = KSAUDIO_SPEAKER_7POINT1_SURROUND;
965 switch (format.m_dataFormat)
968 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL_PLUS;
969 wfxex.Format.nChannels = 2; // One IEC 60958 Line.
970 wfxex.dwChannelMask = KSAUDIO_SPEAKER_5POINT1;
973 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_MLP;
974 wfxex.Format.nChannels = 8; // Four IEC 60958 Lines.
975 wfxex.dwChannelMask = KSAUDIO_SPEAKER_7POINT1_SURROUND;
978 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DTS_HD;
979 wfxex.Format.nChannels = 8; // Four IEC 60958 Lines.
980 wfxex.dwChannelMask = KSAUDIO_SPEAKER_7POINT1_SURROUND;
984 if (format.m_channelLayout.Count() == 8)
985 wfxex.dwChannelMask = KSAUDIO_SPEAKER_7POINT1_SURROUND;
987 wfxex.dwChannelMask = KSAUDIO_SPEAKER_5POINT1;
991 if (wfxex.Format.wBitsPerSample == 32 && wfxex.SubFormat != KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)
992 wfxex.Samples.wValidBitsPerSample = 24;
994 wfxex.Samples.wValidBitsPerSample = wfxex.Format.wBitsPerSample;
996 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
997 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
1000 void CAESinkWASAPI::BuildWaveFormatExtensibleIEC61397(AEAudioFormat &format, WAVEFORMATEXTENSIBLE_IEC61937 &wfxex)
1002 /* Fill the common structure */
1003 BuildWaveFormatExtensible(format, wfxex.FormatExt);
1005 /* Code below kept for future use - preferred for later Windows versions */
1006 /* but can cause problems on older Windows versions and drivers */
1008 wfxex.FormatExt.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE_IEC61937)-sizeof(WAVEFORMATEX);
1009 wfxex.dwEncodedChannelCount = format.m_channelLayout.Count();
1010 wfxex.dwEncodedSamplesPerSec = bool(format.m_dataFormat == AE_FMT_TRUEHD ||
1011 format.m_dataFormat == AE_FMT_DTSHD ||
1012 format.m_dataFormat == AE_FMT_EAC3) ? 96000L : 48000L;
1013 wfxex.dwAverageBytesPerSec = 0; //Ignored */
1016 bool CAESinkWASAPI::InitializeExclusive(AEAudioFormat &format)
1018 WAVEFORMATEXTENSIBLE_IEC61937 wfxex_iec61937;
1019 WAVEFORMATEXTENSIBLE &wfxex = wfxex_iec61937.FormatExt;
1021 if (format.m_dataFormat <= AE_FMT_FLOAT)
1022 BuildWaveFormatExtensible(format, wfxex);
1024 BuildWaveFormatExtensibleIEC61397(format, wfxex_iec61937);
1026 /* Test for incomplete format and provide defaults */
1027 if (format.m_sampleRate == 0 ||
1028 format.m_channelLayout == NULL ||
1029 format.m_dataFormat <= AE_FMT_INVALID ||
1030 format.m_dataFormat >= AE_FMT_MAX ||
1031 format.m_channelLayout.Count() == 0)
1033 wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
1034 wfxex.Format.nChannels = 2;
1035 wfxex.Format.nSamplesPerSec = 44100L;
1036 wfxex.Format.wBitsPerSample = 16;
1037 wfxex.Format.nBlockAlign = 4;
1038 wfxex.Samples.wValidBitsPerSample = 16;
1039 wfxex.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
1040 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nBlockAlign * wfxex.Format.nSamplesPerSec;
1041 wfxex.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
1042 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1045 HRESULT hr = m_pAudioClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
1049 CLog::Log(LOGINFO, __FUNCTION__": Format is Supported - will attempt to Initialize");
1052 else if (hr != AUDCLNT_E_UNSUPPORTED_FORMAT) //It failed for a reason unrelated to an unsupported format.
1054 CLog::Log(LOGERROR, __FUNCTION__": IsFormatSupported failed (%s)", WASAPIErrToStr(hr));
1057 else if (AE_IS_RAW(format.m_dataFormat)) //No sense in trying other formats for passthrough.
1060 CLog::Log(LOGERROR, __FUNCTION__": IsFormatSupported failed (%s) - trying to find a compatible format", WASAPIErrToStr(hr));
1064 /* The requested format is not supported by the device. Find something that works */
1065 for (int j = 0; j < sizeof(testFormats)/sizeof(sampleFormat); j++)
1069 wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
1070 wfxex.SubFormat = testFormats[j].subFormat;
1071 wfxex.Format.wBitsPerSample = testFormats[j].bitsPerSample;
1072 wfxex.Samples.wValidBitsPerSample = testFormats[j].validBitsPerSample;
1073 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
1075 for (int i = 0 ; i < WASAPISampleRateCount; i++)
1077 wfxex.Format.nSamplesPerSec = WASAPISampleRates[i];
1078 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
1080 /* Trace format match iteration loop via log */
1082 CLog::Log(LOGDEBUG, "WASAPI: Trying Format: %s, %d, %d, %d", CAEUtil::DataFormatToStr(testFormats[j].subFormatType),
1083 wfxex.Format.nSamplesPerSec,
1084 wfxex.Format.wBitsPerSample,
1085 wfxex.Samples.wValidBitsPerSample);
1088 hr = m_pAudioClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
1092 /* If the current sample rate matches the source then stop looking and use it */
1093 if ((WASAPISampleRates[i] == format.m_sampleRate) && (testFormats[j].subFormatType <= format.m_dataFormat))
1095 /* If this rate is closer to the source then the previous one, save it */
1096 else if (closestMatch < 0 || abs((int)WASAPISampleRates[i] - (int)format.m_sampleRate) < abs((int)WASAPISampleRates[closestMatch] - (int)format.m_sampleRate))
1099 else if (hr != AUDCLNT_E_UNSUPPORTED_FORMAT)
1100 CLog::Log(LOGERROR, __FUNCTION__": IsFormatSupported failed (%s)", WASAPIErrToStr(hr));
1103 if (closestMatch >= 0)
1105 wfxex.Format.nSamplesPerSec = WASAPISampleRates[closestMatch];
1106 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
1111 CLog::Log(LOGERROR, __FUNCTION__": Unable to locate a supported output format for the device. Check the speaker settings in the control panel.");
1113 /* We couldn't find anything supported. This should never happen */
1114 /* unless the user set the wrong speaker setting in the control panel */
1119 AEChannelsFromSpeakerMask(wfxex.dwChannelMask);
1121 /* When the stream is raw, the values in the format structure are set to the link */
1122 /* parameters, so store the encoded stream values here for the IsCompatible function */
1123 m_encodedFormat = format.m_dataFormat;
1124 m_encodedChannels = wfxex.Format.nChannels;
1125 m_encodedSampleRate = format.m_encodedRate;
1126 wfxex_iec61937.dwEncodedChannelCount = wfxex.Format.nChannels;
1127 wfxex_iec61937.dwEncodedSamplesPerSec = m_encodedSampleRate;
1129 /* Set up returned sink format for engine */
1130 if (!AE_IS_RAW(format.m_dataFormat))
1132 if (wfxex.Format.wBitsPerSample == 32)
1134 if (wfxex.SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)
1135 format.m_dataFormat = AE_FMT_FLOAT;
1136 else if (wfxex.Samples.wValidBitsPerSample == 32)
1137 format.m_dataFormat = AE_FMT_S32NE;
1139 format.m_dataFormat = AE_FMT_S24NE4;
1141 else if (wfxex.Format.wBitsPerSample == 24)
1142 format.m_dataFormat = AE_FMT_S24NE3;
1144 format.m_dataFormat = AE_FMT_S16NE;
1147 format.m_sampleRate = wfxex.Format.nSamplesPerSec; //PCM: Sample rate. RAW: Link speed
1148 format.m_frameSize = (wfxex.Format.wBitsPerSample >> 3) * wfxex.Format.nChannels;
1150 REFERENCE_TIME audioSinkBufferDurationMsec, hnsLatency;
1152 /* Get m_audioSinkBufferSizeMsec from advancedsettings.xml */
1153 audioSinkBufferDurationMsec = (REFERENCE_TIME)g_advancedSettings.m_audioSinkBufferDurationMsec * 10000;
1155 /* Use advancedsetting value for buffer size as long as it's over minimum set above */
1156 audioSinkBufferDurationMsec = (REFERENCE_TIME)std::max(audioSinkBufferDurationMsec, (REFERENCE_TIME)500000);
1157 audioSinkBufferDurationMsec = (REFERENCE_TIME)((audioSinkBufferDurationMsec / format.m_frameSize) * format.m_frameSize); //even number of frames
1159 if (AE_IS_RAW(format.m_dataFormat))
1160 format.m_dataFormat = AE_FMT_S16NE;
1162 hr = m_pAudioClient->Initialize(AUDCLNT_SHAREMODE_EXCLUSIVE, AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_NOPERSIST,
1163 audioSinkBufferDurationMsec, audioSinkBufferDurationMsec, &wfxex.Format, NULL);
1165 m_hnsRequestedDuration = audioSinkBufferDurationMsec;
1167 if (hr == AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED)
1169 /* WASAPI requires aligned buffer */
1170 /* Get the next aligned frame */
1171 hr = m_pAudioClient->GetBufferSize(&m_uiBufferLen);
1174 CLog::Log(LOGERROR, __FUNCTION__": GetBufferSize Failed : %s", WASAPIErrToStr(hr));
1178 audioSinkBufferDurationMsec = (REFERENCE_TIME) ((10000.0 * 1000 / wfxex.Format.nSamplesPerSec * m_uiBufferLen) + 0.5);
1180 /* Release the previous allocations */
1181 SAFE_RELEASE(m_pAudioClient);
1183 /* Create a new audio client */
1184 hr = m_pDevice->Activate(IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&m_pAudioClient);
1187 CLog::Log(LOGERROR, __FUNCTION__": Device Activation Failed : %s", WASAPIErrToStr(hr));
1191 /* Open the stream and associate it with an audio session */
1192 hr = m_pAudioClient->Initialize(AUDCLNT_SHAREMODE_EXCLUSIVE, AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_NOPERSIST,
1193 audioSinkBufferDurationMsec, audioSinkBufferDurationMsec, &wfxex.Format, NULL);
1197 CLog::Log(LOGERROR, __FUNCTION__": Failed to initialize WASAPI in exclusive mode %d - (%s).", HRESULT(hr), WASAPIErrToStr(hr));
1198 CLog::Log(LOGDEBUG, " Sample Rate : %d", wfxex.Format.nSamplesPerSec);
1199 CLog::Log(LOGDEBUG, " Sample Format : %s", CAEUtil::DataFormatToStr(format.m_dataFormat));
1200 CLog::Log(LOGDEBUG, " Bits Per Sample : %d", wfxex.Format.wBitsPerSample);
1201 CLog::Log(LOGDEBUG, " Valid Bits/Samp : %d", wfxex.Samples.wValidBitsPerSample);
1202 CLog::Log(LOGDEBUG, " Channel Count : %d", wfxex.Format.nChannels);
1203 CLog::Log(LOGDEBUG, " Block Align : %d", wfxex.Format.nBlockAlign);
1204 CLog::Log(LOGDEBUG, " Avg. Bytes Sec : %d", wfxex.Format.nAvgBytesPerSec);
1205 CLog::Log(LOGDEBUG, " Samples/Block : %d", wfxex.Samples.wSamplesPerBlock);
1206 CLog::Log(LOGDEBUG, " Format cBSize : %d", wfxex.Format.cbSize);
1207 CLog::Log(LOGDEBUG, " Channel Layout : %s", ((std::string)format.m_channelLayout).c_str());
1208 CLog::Log(LOGDEBUG, " Enc. Channels : %d", wfxex_iec61937.dwEncodedChannelCount);
1209 CLog::Log(LOGDEBUG, " Enc. Samples/Sec: %d", wfxex_iec61937.dwEncodedSamplesPerSec);
1210 CLog::Log(LOGDEBUG, " Channel Mask : %d", wfxex.dwChannelMask);
1211 CLog::Log(LOGDEBUG, " Periodicty : %d", audioSinkBufferDurationMsec);
1215 /* Latency of WASAPI buffers in event-driven mode is equal to the returned value */
1216 /* of GetStreamLatency converted from 100ns intervals to seconds then multiplied */
1217 /* by two as there are two equally-sized buffers and playback starts when the */
1218 /* second buffer is filled. Multiplying the returned 100ns intervals by 0.0000002 */
1219 /* is handles both the unit conversion and twin buffers. */
1220 hr = m_pAudioClient->GetStreamLatency(&hnsLatency);
1223 CLog::Log(LOGERROR, __FUNCTION__": GetStreamLatency Failed : %s", WASAPIErrToStr(hr));
1227 m_sinkLatency = hnsLatency * 0.0000002;
1229 CLog::Log(LOGINFO, __FUNCTION__": WASAPI Exclusive Mode Sink Initialized using: %s, %d, %d",
1230 CAEUtil::DataFormatToStr(format.m_dataFormat),
1231 wfxex.Format.nSamplesPerSec,
1232 wfxex.Format.nChannels);
1236 void CAESinkWASAPI::AEChannelsFromSpeakerMask(DWORD speakers)
1238 m_channelLayout.Reset();
1240 for (int i = 0; i < WASAPI_SPEAKER_COUNT; i++)
1242 if (speakers & WASAPIChannelOrder[i])
1243 m_channelLayout += AEChannelNames[i];
1247 DWORD CAESinkWASAPI::SpeakerMaskFromAEChannels(const CAEChannelInfo &channels)
1251 for (unsigned int i = 0; i < channels.Count(); i++)
1253 for (unsigned int j = 0; j < WASAPI_SPEAKER_COUNT; j++)
1254 if (channels[i] == AEChannelNames[j])
1255 mask |= WASAPIChannelOrder[j];
1260 const char *CAESinkWASAPI::WASAPIErrToStr(HRESULT err)
1264 ERRTOSTR(AUDCLNT_E_NOT_INITIALIZED);
1265 ERRTOSTR(AUDCLNT_E_ALREADY_INITIALIZED);
1266 ERRTOSTR(AUDCLNT_E_WRONG_ENDPOINT_TYPE);
1267 ERRTOSTR(AUDCLNT_E_DEVICE_INVALIDATED);
1268 ERRTOSTR(AUDCLNT_E_NOT_STOPPED);
1269 ERRTOSTR(AUDCLNT_E_BUFFER_TOO_LARGE);
1270 ERRTOSTR(AUDCLNT_E_OUT_OF_ORDER);
1271 ERRTOSTR(AUDCLNT_E_UNSUPPORTED_FORMAT);
1272 ERRTOSTR(AUDCLNT_E_INVALID_SIZE);
1273 ERRTOSTR(AUDCLNT_E_DEVICE_IN_USE);
1274 ERRTOSTR(AUDCLNT_E_BUFFER_OPERATION_PENDING);
1275 ERRTOSTR(AUDCLNT_E_THREAD_NOT_REGISTERED);
1276 ERRTOSTR(AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED);
1277 ERRTOSTR(AUDCLNT_E_ENDPOINT_CREATE_FAILED);
1278 ERRTOSTR(AUDCLNT_E_SERVICE_NOT_RUNNING);
1279 ERRTOSTR(AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED);
1280 ERRTOSTR(AUDCLNT_E_EXCLUSIVE_MODE_ONLY);
1281 ERRTOSTR(AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL);
1282 ERRTOSTR(AUDCLNT_E_EVENTHANDLE_NOT_SET);
1283 ERRTOSTR(AUDCLNT_E_INCORRECT_BUFFER_SIZE);
1284 ERRTOSTR(AUDCLNT_E_BUFFER_SIZE_ERROR);
1285 ERRTOSTR(AUDCLNT_E_CPUUSAGE_EXCEEDED);
1286 ERRTOSTR(AUDCLNT_E_BUFFER_ERROR);
1287 ERRTOSTR(AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED);
1288 ERRTOSTR(AUDCLNT_E_INVALID_DEVICE_PERIOD);
1289 ERRTOSTR(E_POINTER);
1290 ERRTOSTR(E_INVALIDARG);
1291 ERRTOSTR(E_OUTOFMEMORY);
1297 void CAESinkWASAPI::Drain()
1302 Sleep( (DWORD)(m_hnsRequestedDuration / 10000));
1308 m_pAudioClient->Stop(); //stop the audio output
1309 m_pAudioClient->Reset(); //flush buffer and reset audio clock stream position
1313 CLog::Log(LOGDEBUG, __FUNCTION__, "Invalidated AudioClient - Releasing");