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 double time_played = 0.0;
424 unsigned int now = XbmcThreads::SystemClockMillis();
425 time_played = (double)(now-m_lastWriteToBuffer) / 1000;
428 double delay = m_sinkLatency - time_played + (double)m_bufferPtr / (double)m_format.m_sampleRate;
436 double CAESinkWASAPI::GetCacheTime()
438 /* This function deviates from the defined usage due to the event-driven */
439 /* mode of WASAPI utilizing twin buffers which are written to in single */
440 /* buffer chunks. Therefore the buffers are either 100% full or 50% full */
441 /* At 50% issues arise with water levels in the stream and player. For */
442 /* this reason the cache is shown as 100% full at all times, and control */
443 /* of the buffer filling is assumed in AddPackets() and by the WASAPI */
444 /* implementation of the WaitforSingleObject event indicating one of the */
445 /* buffers is ready for filling via AddPackets */
449 return m_sinkLatency;
452 double CAESinkWASAPI::GetCacheTotal()
457 return m_sinkLatency;
460 unsigned int CAESinkWASAPI::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio, bool blocking)
470 LARGE_INTEGER timerStart;
471 LARGE_INTEGER timerStop;
472 LARGE_INTEGER timerFreq;
475 unsigned int NumFramesRequested = m_format.m_frames;
476 unsigned int FramesToCopy = std::min(m_format.m_frames - m_bufferPtr, frames);
477 if (m_bufferPtr != 0 || frames != m_format.m_frames)
479 memcpy(m_pBuffer+m_bufferPtr*m_format.m_frameSize, data, FramesToCopy*m_format.m_frameSize);
480 m_bufferPtr += FramesToCopy;
481 if (m_bufferPtr != m_format.m_frames)
485 if (!m_running) //first time called, pre-fill buffer then start audio client
487 hr = m_pAudioClient->Reset();
490 CLog::Log(LOGERROR, __FUNCTION__ " AudioClient reset failed due to %s", WASAPIErrToStr(hr));
493 hr = m_pRenderClient->GetBuffer(NumFramesRequested, &buf);
497 CLog::Log(LOGERROR, __FUNCTION__": GetBuffer failed due to %s", WASAPIErrToStr(hr));
499 m_isDirty = true; //flag new device or re-init needed
503 /* Inject one buffer of silence if sink has just opened */
504 /* to avoid losing start of stream or GUI sound */
505 if (g_advancedSettings.m_streamSilence)
506 memcpy(buf, data, NumFramesRequested * m_format.m_frameSize); //fill buffer with audio
508 memset(buf, 0, NumFramesRequested * m_format.m_frameSize); //fill buffer with silence
510 hr = m_pRenderClient->ReleaseBuffer(NumFramesRequested, flags); //pass back to audio driver
514 CLog::Log(LOGDEBUG, __FUNCTION__": ReleaseBuffer failed due to %s.", WASAPIErrToStr(hr));
516 m_isDirty = true; //flag new device or re-init needed
519 hr = m_pAudioClient->Start(); //start the audio driver running
521 CLog::Log(LOGERROR, __FUNCTION__": AudioClient Start Failed");
522 m_running = true; //signal that we're processing frames
523 return g_advancedSettings.m_streamSilence ? NumFramesRequested : 0U;
527 /* Get clock time for latency checks */
528 QueryPerformanceFrequency(&timerFreq);
529 QueryPerformanceCounter(&timerStart);
532 /* Wait for Audio Driver to tell us it's got a buffer available */
533 DWORD eventAudioCallback;
535 eventAudioCallback = WaitForSingleObject(m_needDataEvent, 0);
537 eventAudioCallback = WaitForSingleObject(m_needDataEvent, 1100);
541 if(eventAudioCallback != WAIT_OBJECT_0)
546 if(eventAudioCallback != WAIT_OBJECT_0 || !&buf)
548 /* Event handle timed out - flag sink as dirty for re-initializing */
549 CLog::Log(LOGERROR, __FUNCTION__": Endpoint Buffer timed out");
550 if (g_advancedSettings.m_streamSilence)
552 m_isDirty = true; //flag new device or re-init needed
565 QueryPerformanceCounter(&timerStop);
566 LONGLONG timerDiff = timerStop.QuadPart - timerStart.QuadPart;
567 double timerElapsed = (double) timerDiff * 1000.0 / (double) timerFreq.QuadPart;
568 m_avgTimeWaiting += (timerElapsed - m_avgTimeWaiting) * 0.5;
570 if (m_avgTimeWaiting < 3.0)
572 CLog::Log(LOGDEBUG, __FUNCTION__": Possible AQ Loss: Avg. Time Waiting for Audio Driver callback : %dmsec", (int)m_avgTimeWaiting);
576 hr = m_pRenderClient->GetBuffer(NumFramesRequested, &buf);
580 CLog::Log(LOGERROR, __FUNCTION__": GetBuffer failed due to %s", WASAPIErrToStr(hr));
584 memcpy(buf, m_bufferPtr == 0 ? data : m_pBuffer, NumFramesRequested * m_format.m_frameSize); //fill buffer
586 hr = m_pRenderClient->ReleaseBuffer(NumFramesRequested, flags); //pass back to audio driver
590 CLog::Log(LOGDEBUG, __FUNCTION__": ReleaseBuffer failed due to %s.", WASAPIErrToStr(hr));
594 m_lastWriteToBuffer = XbmcThreads::SystemClockMillis();
596 if (FramesToCopy != frames)
598 m_bufferPtr = frames-FramesToCopy;
599 memcpy(m_pBuffer, data+FramesToCopy*m_format.m_frameSize, m_bufferPtr*m_format.m_frameSize);
605 bool CAESinkWASAPI::SoftSuspend()
607 /* Sink has been asked to suspend output - we release audio */
608 /* device as we are in exclusive mode and thus allow external */
609 /* audio sources to play. This requires us to reinitialize */
617 bool CAESinkWASAPI::SoftResume()
619 /* Sink asked to resume output. To release audio device in */
620 /* exclusive mode we release the device context and therefore */
621 /* must reinitialize. Return false to force re-init by engine */
626 void CAESinkWASAPI::EnumerateDevicesEx(AEDeviceInfoList &deviceInfoList, bool force)
628 IMMDeviceEnumerator* pEnumerator = NULL;
629 IMMDeviceCollection* pEnumDevices = NULL;
630 IMMDevice* pDefaultDevice = NULL;
631 CAEDeviceInfo deviceInfo;
632 CAEChannelInfo deviceChannels;
633 LPWSTR pwszID = NULL;
634 std::wstring wstrDDID;
636 WAVEFORMATEXTENSIBLE wfxex = {0};
639 hr = CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void**)&pEnumerator);
640 EXIT_ON_FAILURE(hr, __FUNCTION__": Could not allocate WASAPI device enumerator. CoCreateInstance error code: %li", hr)
644 // get the default audio endpoint
645 if(pEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &pDefaultDevice) == S_OK)
647 if(pDefaultDevice->GetId(&pwszID) == S_OK)
650 CoTaskMemFree(pwszID);
652 SAFE_RELEASE(pDefaultDevice);
655 // enumerate over all audio endpoints
656 hr = pEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &pEnumDevices);
657 EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of audio endpoint enumeration failed.")
659 hr = pEnumDevices->GetCount(&uiCount);
660 EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of audio endpoint count failed.")
662 for (UINT i = 0; i < uiCount; i++)
664 IMMDevice *pDevice = NULL;
665 IPropertyStore *pProperty = NULL;
667 PropVariantInit(&varName);
669 deviceInfo.m_channels.Reset();
670 deviceInfo.m_dataFormats.clear();
671 deviceInfo.m_sampleRates.clear();
673 hr = pEnumDevices->Item(i, &pDevice);
676 CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint failed.");
680 hr = pDevice->OpenPropertyStore(STGM_READ, &pProperty);
683 CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint properties failed.");
684 SAFE_RELEASE(pDevice);
688 hr = pProperty->GetValue(PKEY_Device_FriendlyName, &varName);
691 CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint device name failed.");
692 SAFE_RELEASE(pDevice);
693 SAFE_RELEASE(pProperty);
697 std::string strFriendlyName = localWideToUtf(varName.pwszVal);
698 PropVariantClear(&varName);
700 hr = pProperty->GetValue(PKEY_AudioEndpoint_GUID, &varName);
703 CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint GUID failed.");
704 SAFE_RELEASE(pDevice);
705 SAFE_RELEASE(pProperty);
709 std::string strDevName = localWideToUtf(varName.pwszVal);
710 PropVariantClear(&varName);
712 hr = pProperty->GetValue(PKEY_AudioEndpoint_FormFactor, &varName);
715 CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint form factor failed.");
716 SAFE_RELEASE(pDevice);
717 SAFE_RELEASE(pProperty);
720 std::string strWinDevType = winEndpoints[(EndpointFormFactor)varName.uiVal].winEndpointType;
721 AEDeviceType aeDeviceType = winEndpoints[(EndpointFormFactor)varName.uiVal].aeDeviceType;
723 PropVariantClear(&varName);
725 hr = pProperty->GetValue(PKEY_AudioEndpoint_PhysicalSpeakers, &varName);
728 CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint speaker layout failed.");
729 SAFE_RELEASE(pDevice);
730 SAFE_RELEASE(pProperty);
733 unsigned int uiChannelMask = std::max(varName.uintVal, (unsigned int) KSAUDIO_SPEAKER_STEREO);
735 deviceChannels.Reset();
737 for (unsigned int c = 0; c < WASAPI_SPEAKER_COUNT; c++)
739 if (uiChannelMask & WASAPIChannelOrder[c])
740 deviceChannels += AEChannelNames[c];
743 PropVariantClear(&varName);
745 IAudioClient *pClient;
746 hr = pDevice->Activate(IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&pClient);
749 /* Test format DTS-HD */
750 wfxex.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
751 wfxex.Format.nSamplesPerSec = 192000;
752 wfxex.dwChannelMask = KSAUDIO_SPEAKER_7POINT1_SURROUND;
753 wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
754 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DTS_HD;
755 wfxex.Format.wBitsPerSample = 16;
756 wfxex.Samples.wValidBitsPerSample = 16;
757 wfxex.Format.nChannels = 8;
758 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
759 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
760 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
762 deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_DTSHD));
764 /* Test format Dolby TrueHD */
765 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_MLP;
766 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
768 deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_TRUEHD));
770 /* Test format Dolby EAC3 */
771 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL_PLUS;
772 wfxex.Format.nChannels = 2;
773 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
774 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
775 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
777 deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_EAC3));
779 /* Test format DTS */
780 wfxex.Format.nSamplesPerSec = 48000;
781 wfxex.dwChannelMask = KSAUDIO_SPEAKER_5POINT1;
782 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DTS;
783 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
784 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
785 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
787 deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_DTS));
789 /* Test format Dolby AC3 */
790 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL;
791 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
793 deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_AC3));
795 /* Test format AAC */
796 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_AAC;
797 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
799 deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_AAC));
801 /* Test format for PCM format iteration */
802 wfxex.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
803 wfxex.dwChannelMask = KSAUDIO_SPEAKER_STEREO;
804 wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
805 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
807 for (int p = AE_FMT_FLOAT; p > AE_FMT_INVALID; p--)
809 if (p < AE_FMT_FLOAT)
810 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
811 wfxex.Format.wBitsPerSample = CAEUtil::DataFormatToBits((AEDataFormat) p);
812 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
813 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
814 if (p <= AE_FMT_S24NE4 && p >= AE_FMT_S24BE4)
816 wfxex.Samples.wValidBitsPerSample = 24;
820 wfxex.Samples.wValidBitsPerSample = wfxex.Format.wBitsPerSample;
823 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
825 deviceInfo.m_dataFormats.push_back((AEDataFormat) p);
828 /* Test format for sample rate iteration */
829 wfxex.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
830 wfxex.dwChannelMask = KSAUDIO_SPEAKER_STEREO;
831 wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
832 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
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 for (int j = 0; j < WASAPISampleRateCount; j++)
841 wfxex.Format.nSamplesPerSec = WASAPISampleRates[j];
842 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
843 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
845 deviceInfo.m_sampleRates.push_back(WASAPISampleRates[j]);
848 /* Test format for channels iteration */
849 wfxex.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
850 wfxex.dwChannelMask = KSAUDIO_SPEAKER_STEREO;
851 wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
852 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
853 wfxex.Format.nSamplesPerSec = 48000;
854 wfxex.Format.wBitsPerSample = 16;
855 wfxex.Samples.wValidBitsPerSample = 16;
856 wfxex.Format.nChannels = 2;
857 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
858 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
860 bool hasLpcm = false;
862 // Try with KSAUDIO_SPEAKER_DIRECTOUT
863 for (unsigned int k = WASAPI_SPEAKER_COUNT; k > 0; k--)
865 wfxex.dwChannelMask = KSAUDIO_SPEAKER_DIRECTOUT;
866 wfxex.Format.nChannels = k;
867 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
868 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
869 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
872 if (k > 3) // Add only multichannel LPCM
874 deviceInfo.m_dataFormats.push_back(AE_FMT_LPCM);
881 /* Try with reported channel mask */
882 for (unsigned int k = WASAPI_SPEAKER_COUNT; k > 0; k--)
884 wfxex.dwChannelMask = uiChannelMask;
885 wfxex.Format.nChannels = k;
886 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
887 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
888 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
891 if ( !hasLpcm && k > 3) // Add only multichannel LPCM
893 deviceInfo.m_dataFormats.push_back(AE_FMT_LPCM);
900 /* Try with specific speakers configurations */
901 for (unsigned int i = 0; i < ARRAYSIZE(layoutsList); i++)
903 unsigned int nmbOfCh;
904 wfxex.dwChannelMask = ChLayoutToChMask(layoutsList[i], &nmbOfCh);
905 wfxex.Format.nChannels = nmbOfCh;
906 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
907 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
908 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
911 if ( deviceChannels.Count() < nmbOfCh)
912 deviceChannels = layoutsList[i];
913 if ( !hasLpcm && nmbOfCh > 3) // Add only multichannel LPCM
915 deviceInfo.m_dataFormats.push_back(AE_FMT_LPCM);
924 CLog::Log(LOGDEBUG, __FUNCTION__": Failed to activate device for passthrough capability testing.");
927 deviceInfo.m_deviceName = strDevName;
928 deviceInfo.m_displayName = strWinDevType.append(strFriendlyName);
929 deviceInfo.m_displayNameExtra = std::string("WASAPI: ").append(strFriendlyName);
930 deviceInfo.m_deviceType = aeDeviceType;
931 deviceInfo.m_channels = deviceChannels;
933 /* Store the device info */
934 deviceInfoList.push_back(deviceInfo);
936 if(pDevice->GetId(&pwszID) == S_OK)
938 if(wstrDDID.compare(pwszID) == 0)
940 deviceInfo.m_deviceName = std::string("default");
941 deviceInfo.m_displayName = std::string("default");
942 deviceInfo.m_displayNameExtra = std::string("");
943 deviceInfoList.push_back(deviceInfo);
945 CoTaskMemFree(pwszID);
948 SAFE_RELEASE(pDevice);
949 SAFE_RELEASE(pProperty);
956 CLog::Log(LOGERROR, __FUNCTION__": Failed to enumerate WASAPI endpoint devices (%s).", WASAPIErrToStr(hr));
958 SAFE_RELEASE(pEnumDevices);
959 SAFE_RELEASE(pEnumerator);
962 //Private utility functions////////////////////////////////////////////////////
964 void CAESinkWASAPI::BuildWaveFormatExtensible(AEAudioFormat &format, WAVEFORMATEXTENSIBLE &wfxex)
966 wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
967 wfxex.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
970 if (!AE_IS_RAW(format.m_dataFormat)) // PCM data
972 wfxex.dwChannelMask = SpeakerMaskFromAEChannels(format.m_channelLayout);
973 wfxex.Format.nChannels = (WORD)format.m_channelLayout.Count();
974 wfxex.Format.nSamplesPerSec = format.m_sampleRate;
975 wfxex.Format.wBitsPerSample = CAEUtil::DataFormatToBits((AEDataFormat) format.m_dataFormat);
976 wfxex.SubFormat = format.m_dataFormat <= AE_FMT_FLOAT ? KSDATAFORMAT_SUBTYPE_PCM : KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
980 wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
981 if (format.m_dataFormat == AE_FMT_AC3 || format.m_dataFormat == AE_FMT_DTS)
983 wfxex.dwChannelMask = bool (format.m_channelLayout.Count() == 2) ? KSAUDIO_SPEAKER_STEREO : KSAUDIO_SPEAKER_5POINT1;
984 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL;
985 wfxex.Format.wBitsPerSample = 16;
986 wfxex.Samples.wValidBitsPerSample = 16;
987 wfxex.Format.nChannels = (WORD)format.m_channelLayout.Count();
988 wfxex.Format.nSamplesPerSec = format.m_sampleRate;
990 else if (format.m_dataFormat == AE_FMT_EAC3 || format.m_dataFormat == AE_FMT_TRUEHD || format.m_dataFormat == AE_FMT_DTSHD)
992 /* IEC 61937 transmissions over HDMI */
993 wfxex.Format.nSamplesPerSec = 192000L;
994 wfxex.Format.wBitsPerSample = 16;
995 wfxex.Samples.wValidBitsPerSample = 16;
996 wfxex.dwChannelMask = KSAUDIO_SPEAKER_7POINT1_SURROUND;
998 switch (format.m_dataFormat)
1001 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL_PLUS;
1002 wfxex.Format.nChannels = 2; // One IEC 60958 Line.
1003 wfxex.dwChannelMask = KSAUDIO_SPEAKER_5POINT1;
1006 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_MLP;
1007 wfxex.Format.nChannels = 8; // Four IEC 60958 Lines.
1008 wfxex.dwChannelMask = KSAUDIO_SPEAKER_7POINT1_SURROUND;
1011 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DTS_HD;
1012 wfxex.Format.nChannels = 8; // Four IEC 60958 Lines.
1013 wfxex.dwChannelMask = KSAUDIO_SPEAKER_7POINT1_SURROUND;
1017 if (format.m_channelLayout.Count() == 8)
1018 wfxex.dwChannelMask = KSAUDIO_SPEAKER_7POINT1_SURROUND;
1020 wfxex.dwChannelMask = KSAUDIO_SPEAKER_5POINT1;
1024 if (wfxex.Format.wBitsPerSample == 32 && wfxex.SubFormat != KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)
1025 wfxex.Samples.wValidBitsPerSample = 24;
1027 wfxex.Samples.wValidBitsPerSample = wfxex.Format.wBitsPerSample;
1029 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
1030 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
1033 void CAESinkWASAPI::BuildWaveFormatExtensibleIEC61397(AEAudioFormat &format, WAVEFORMATEXTENSIBLE_IEC61937 &wfxex)
1035 /* Fill the common structure */
1036 BuildWaveFormatExtensible(format, wfxex.FormatExt);
1038 /* Code below kept for future use - preferred for later Windows versions */
1039 /* but can cause problems on older Windows versions and drivers */
1041 wfxex.FormatExt.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE_IEC61937)-sizeof(WAVEFORMATEX);
1042 wfxex.dwEncodedChannelCount = format.m_channelLayout.Count();
1043 wfxex.dwEncodedSamplesPerSec = bool(format.m_dataFormat == AE_FMT_TRUEHD ||
1044 format.m_dataFormat == AE_FMT_DTSHD ||
1045 format.m_dataFormat == AE_FMT_EAC3) ? 96000L : 48000L;
1046 wfxex.dwAverageBytesPerSec = 0; //Ignored */
1049 bool CAESinkWASAPI::InitializeExclusive(AEAudioFormat &format)
1051 WAVEFORMATEXTENSIBLE_IEC61937 wfxex_iec61937;
1052 WAVEFORMATEXTENSIBLE &wfxex = wfxex_iec61937.FormatExt;
1054 if (format.m_dataFormat <= AE_FMT_FLOAT)
1055 BuildWaveFormatExtensible(format, wfxex);
1057 BuildWaveFormatExtensibleIEC61397(format, wfxex_iec61937);
1059 /* Test for incomplete format and provide defaults */
1060 if (format.m_sampleRate == 0 ||
1061 format.m_channelLayout == NULL ||
1062 format.m_dataFormat <= AE_FMT_INVALID ||
1063 format.m_dataFormat >= AE_FMT_MAX ||
1064 format.m_channelLayout.Count() == 0)
1066 wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
1067 wfxex.Format.nChannels = 2;
1068 wfxex.Format.nSamplesPerSec = 44100L;
1069 wfxex.Format.wBitsPerSample = 16;
1070 wfxex.Format.nBlockAlign = 4;
1071 wfxex.Samples.wValidBitsPerSample = 16;
1072 wfxex.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
1073 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nBlockAlign * wfxex.Format.nSamplesPerSec;
1074 wfxex.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
1075 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
1078 HRESULT hr = m_pAudioClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
1082 CLog::Log(LOGINFO, __FUNCTION__": Format is Supported - will attempt to Initialize");
1085 else if (hr != AUDCLNT_E_UNSUPPORTED_FORMAT) //It failed for a reason unrelated to an unsupported format.
1087 CLog::Log(LOGERROR, __FUNCTION__": IsFormatSupported failed (%s)", WASAPIErrToStr(hr));
1090 else if (AE_IS_RAW(format.m_dataFormat)) //No sense in trying other formats for passthrough.
1093 CLog::Log(LOGERROR, __FUNCTION__": IsFormatSupported failed (%s) - trying to find a compatible format", WASAPIErrToStr(hr));
1097 /* The requested format is not supported by the device. Find something that works */
1098 for (int j = 0; j < sizeof(testFormats)/sizeof(sampleFormat); j++)
1102 wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
1103 wfxex.SubFormat = testFormats[j].subFormat;
1104 wfxex.Format.wBitsPerSample = testFormats[j].bitsPerSample;
1105 wfxex.Samples.wValidBitsPerSample = testFormats[j].validBitsPerSample;
1106 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
1108 for (int i = 0 ; i < WASAPISampleRateCount; i++)
1110 wfxex.Format.nSamplesPerSec = WASAPISampleRates[i];
1111 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
1113 /* Trace format match iteration loop via log */
1115 CLog::Log(LOGDEBUG, "WASAPI: Trying Format: %s, %d, %d, %d", CAEUtil::DataFormatToStr(testFormats[j].subFormatType),
1116 wfxex.Format.nSamplesPerSec,
1117 wfxex.Format.wBitsPerSample,
1118 wfxex.Samples.wValidBitsPerSample);
1121 hr = m_pAudioClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
1125 /* If the current sample rate matches the source then stop looking and use it */
1126 if ((WASAPISampleRates[i] == format.m_sampleRate) && (testFormats[j].subFormatType <= format.m_dataFormat))
1128 /* If this rate is closer to the source then the previous one, save it */
1129 else if (closestMatch < 0 || abs((int)WASAPISampleRates[i] - (int)format.m_sampleRate) < abs((int)WASAPISampleRates[closestMatch] - (int)format.m_sampleRate))
1132 else if (hr != AUDCLNT_E_UNSUPPORTED_FORMAT)
1133 CLog::Log(LOGERROR, __FUNCTION__": IsFormatSupported failed (%s)", WASAPIErrToStr(hr));
1136 if (closestMatch >= 0)
1138 wfxex.Format.nSamplesPerSec = WASAPISampleRates[closestMatch];
1139 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
1144 CLog::Log(LOGERROR, __FUNCTION__": Unable to locate a supported output format for the device. Check the speaker settings in the control panel.");
1146 /* We couldn't find anything supported. This should never happen */
1147 /* unless the user set the wrong speaker setting in the control panel */
1152 AEChannelsFromSpeakerMask(wfxex.dwChannelMask);
1154 /* When the stream is raw, the values in the format structure are set to the link */
1155 /* parameters, so store the encoded stream values here for the IsCompatible function */
1156 m_encodedFormat = format.m_dataFormat;
1157 m_encodedChannels = wfxex.Format.nChannels;
1158 m_encodedSampleRate = format.m_encodedRate;
1159 wfxex_iec61937.dwEncodedChannelCount = wfxex.Format.nChannels;
1160 wfxex_iec61937.dwEncodedSamplesPerSec = m_encodedSampleRate;
1162 /* Set up returned sink format for engine */
1163 if (!AE_IS_RAW(format.m_dataFormat))
1165 if (wfxex.Format.wBitsPerSample == 32)
1167 if (wfxex.SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)
1168 format.m_dataFormat = AE_FMT_FLOAT;
1169 else if (wfxex.Samples.wValidBitsPerSample == 32)
1170 format.m_dataFormat = AE_FMT_S32NE;
1172 format.m_dataFormat = AE_FMT_S24NE4;
1174 else if (wfxex.Format.wBitsPerSample == 24)
1175 format.m_dataFormat = AE_FMT_S24NE3;
1177 format.m_dataFormat = AE_FMT_S16NE;
1180 format.m_sampleRate = wfxex.Format.nSamplesPerSec; //PCM: Sample rate. RAW: Link speed
1181 format.m_frameSize = (wfxex.Format.wBitsPerSample >> 3) * wfxex.Format.nChannels;
1183 REFERENCE_TIME audioSinkBufferDurationMsec, hnsLatency;
1185 /* Get m_audioSinkBufferSizeMsec from advancedsettings.xml */
1186 audioSinkBufferDurationMsec = (REFERENCE_TIME)g_advancedSettings.m_audioSinkBufferDurationMsec * 10000;
1188 /* Use advancedsetting value for buffer size as long as it's over minimum set above */
1189 audioSinkBufferDurationMsec = (REFERENCE_TIME)std::max(audioSinkBufferDurationMsec, (REFERENCE_TIME)500000);
1190 audioSinkBufferDurationMsec = (REFERENCE_TIME)((audioSinkBufferDurationMsec / format.m_frameSize) * format.m_frameSize); //even number of frames
1192 if (AE_IS_RAW(format.m_dataFormat))
1193 format.m_dataFormat = AE_FMT_S16NE;
1195 hr = m_pAudioClient->Initialize(AUDCLNT_SHAREMODE_EXCLUSIVE, AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_NOPERSIST,
1196 audioSinkBufferDurationMsec, audioSinkBufferDurationMsec, &wfxex.Format, NULL);
1198 m_hnsRequestedDuration = audioSinkBufferDurationMsec;
1200 if (hr == AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED)
1202 /* WASAPI requires aligned buffer */
1203 /* Get the next aligned frame */
1204 hr = m_pAudioClient->GetBufferSize(&m_uiBufferLen);
1207 CLog::Log(LOGERROR, __FUNCTION__": GetBufferSize Failed : %s", WASAPIErrToStr(hr));
1211 audioSinkBufferDurationMsec = (REFERENCE_TIME) ((10000.0 * 1000 / wfxex.Format.nSamplesPerSec * m_uiBufferLen) + 0.5);
1213 /* Release the previous allocations */
1214 SAFE_RELEASE(m_pAudioClient);
1216 /* Create a new audio client */
1217 hr = m_pDevice->Activate(IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&m_pAudioClient);
1220 CLog::Log(LOGERROR, __FUNCTION__": Device Activation Failed : %s", WASAPIErrToStr(hr));
1224 /* Open the stream and associate it with an audio session */
1225 hr = m_pAudioClient->Initialize(AUDCLNT_SHAREMODE_EXCLUSIVE, AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_NOPERSIST,
1226 audioSinkBufferDurationMsec, audioSinkBufferDurationMsec, &wfxex.Format, NULL);
1230 CLog::Log(LOGERROR, __FUNCTION__": Failed to initialize WASAPI in exclusive mode %d - (%s).", HRESULT(hr), WASAPIErrToStr(hr));
1231 CLog::Log(LOGDEBUG, " Sample Rate : %d", wfxex.Format.nSamplesPerSec);
1232 CLog::Log(LOGDEBUG, " Sample Format : %s", CAEUtil::DataFormatToStr(format.m_dataFormat));
1233 CLog::Log(LOGDEBUG, " Bits Per Sample : %d", wfxex.Format.wBitsPerSample);
1234 CLog::Log(LOGDEBUG, " Valid Bits/Samp : %d", wfxex.Samples.wValidBitsPerSample);
1235 CLog::Log(LOGDEBUG, " Channel Count : %d", wfxex.Format.nChannels);
1236 CLog::Log(LOGDEBUG, " Block Align : %d", wfxex.Format.nBlockAlign);
1237 CLog::Log(LOGDEBUG, " Avg. Bytes Sec : %d", wfxex.Format.nAvgBytesPerSec);
1238 CLog::Log(LOGDEBUG, " Samples/Block : %d", wfxex.Samples.wSamplesPerBlock);
1239 CLog::Log(LOGDEBUG, " Format cBSize : %d", wfxex.Format.cbSize);
1240 CLog::Log(LOGDEBUG, " Channel Layout : %s", ((std::string)format.m_channelLayout).c_str());
1241 CLog::Log(LOGDEBUG, " Enc. Channels : %d", wfxex_iec61937.dwEncodedChannelCount);
1242 CLog::Log(LOGDEBUG, " Enc. Samples/Sec: %d", wfxex_iec61937.dwEncodedSamplesPerSec);
1243 CLog::Log(LOGDEBUG, " Channel Mask : %d", wfxex.dwChannelMask);
1244 CLog::Log(LOGDEBUG, " Periodicty : %d", audioSinkBufferDurationMsec);
1248 /* Latency of WASAPI buffers in event-driven mode is equal to the returned value */
1249 /* of GetStreamLatency converted from 100ns intervals to seconds then multiplied */
1250 /* by two as there are two equally-sized buffers and playback starts when the */
1251 /* second buffer is filled. Multiplying the returned 100ns intervals by 0.0000002 */
1252 /* is handles both the unit conversion and twin buffers. */
1253 hr = m_pAudioClient->GetStreamLatency(&hnsLatency);
1256 CLog::Log(LOGERROR, __FUNCTION__": GetStreamLatency Failed : %s", WASAPIErrToStr(hr));
1260 m_sinkLatency = hnsLatency * 0.0000002;
1262 CLog::Log(LOGINFO, __FUNCTION__": WASAPI Exclusive Mode Sink Initialized using: %s, %d, %d",
1263 CAEUtil::DataFormatToStr(format.m_dataFormat),
1264 wfxex.Format.nSamplesPerSec,
1265 wfxex.Format.nChannels);
1269 void CAESinkWASAPI::AEChannelsFromSpeakerMask(DWORD speakers)
1271 m_channelLayout.Reset();
1273 for (int i = 0; i < WASAPI_SPEAKER_COUNT; i++)
1275 if (speakers & WASAPIChannelOrder[i])
1276 m_channelLayout += AEChannelNames[i];
1280 DWORD CAESinkWASAPI::SpeakerMaskFromAEChannels(const CAEChannelInfo &channels)
1284 for (unsigned int i = 0; i < channels.Count(); i++)
1286 for (unsigned int j = 0; j < WASAPI_SPEAKER_COUNT; j++)
1287 if (channels[i] == AEChannelNames[j])
1288 mask |= WASAPIChannelOrder[j];
1293 const char *CAESinkWASAPI::WASAPIErrToStr(HRESULT err)
1297 ERRTOSTR(AUDCLNT_E_NOT_INITIALIZED);
1298 ERRTOSTR(AUDCLNT_E_ALREADY_INITIALIZED);
1299 ERRTOSTR(AUDCLNT_E_WRONG_ENDPOINT_TYPE);
1300 ERRTOSTR(AUDCLNT_E_DEVICE_INVALIDATED);
1301 ERRTOSTR(AUDCLNT_E_NOT_STOPPED);
1302 ERRTOSTR(AUDCLNT_E_BUFFER_TOO_LARGE);
1303 ERRTOSTR(AUDCLNT_E_OUT_OF_ORDER);
1304 ERRTOSTR(AUDCLNT_E_UNSUPPORTED_FORMAT);
1305 ERRTOSTR(AUDCLNT_E_INVALID_SIZE);
1306 ERRTOSTR(AUDCLNT_E_DEVICE_IN_USE);
1307 ERRTOSTR(AUDCLNT_E_BUFFER_OPERATION_PENDING);
1308 ERRTOSTR(AUDCLNT_E_THREAD_NOT_REGISTERED);
1309 ERRTOSTR(AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED);
1310 ERRTOSTR(AUDCLNT_E_ENDPOINT_CREATE_FAILED);
1311 ERRTOSTR(AUDCLNT_E_SERVICE_NOT_RUNNING);
1312 ERRTOSTR(AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED);
1313 ERRTOSTR(AUDCLNT_E_EXCLUSIVE_MODE_ONLY);
1314 ERRTOSTR(AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL);
1315 ERRTOSTR(AUDCLNT_E_EVENTHANDLE_NOT_SET);
1316 ERRTOSTR(AUDCLNT_E_INCORRECT_BUFFER_SIZE);
1317 ERRTOSTR(AUDCLNT_E_BUFFER_SIZE_ERROR);
1318 ERRTOSTR(AUDCLNT_E_CPUUSAGE_EXCEEDED);
1319 ERRTOSTR(AUDCLNT_E_BUFFER_ERROR);
1320 ERRTOSTR(AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED);
1321 ERRTOSTR(AUDCLNT_E_INVALID_DEVICE_PERIOD);
1322 ERRTOSTR(E_POINTER);
1323 ERRTOSTR(E_INVALIDARG);
1324 ERRTOSTR(E_OUTOFMEMORY);
1330 void CAESinkWASAPI::Drain()
1335 Sleep( (DWORD)(m_hnsRequestedDuration / 10000));
1341 m_pAudioClient->Stop(); //stop the audio output
1342 m_pAudioClient->Reset(); //flush buffer and reset audio clock stream position
1346 CLog::Log(LOGDEBUG, __FUNCTION__, "Invalidated AudioClient - Releasing");