2 * Copyright (C) 2010-2012 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, write to
17 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18 * http://www.gnu.org/copyleft/gpl.html
22 #include "AESinkWASAPI.h"
23 #include <Audioclient.h>
29 #include "../Utils/AEUtil.h"
30 #include "settings/GUISettings.h"
31 #include "settings/AdvancedSettings.h"
32 #include "utils/StdString.h"
33 #include "utils/log.h"
34 #include "threads/SingleLock.h"
35 #include "utils/CharsetConverter.h"
36 #include "../Utils/AEDeviceInfo.h"
38 #include <mmdeviceapi.h>
40 #pragma comment(lib, "Avrt.lib")
42 const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator);
43 const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator);
44 const IID IID_IAudioClient = __uuidof(IAudioClient);
45 const IID IID_IAudioRenderClient = __uuidof(IAudioRenderClient);
47 static const unsigned int WASAPISampleRateCount = 10;
48 static const unsigned int WASAPISampleRates[] = {384000, 192000, 176400, 96000, 88200, 48000, 44100, 32000, 22050, 11025};
50 #define WASAPI_SPEAKER_COUNT 21
51 static const unsigned int WASAPIChannelOrder[] = {AE_CH_RAW,
52 SPEAKER_FRONT_LEFT, SPEAKER_FRONT_RIGHT, SPEAKER_FRONT_CENTER,
53 SPEAKER_LOW_FREQUENCY, SPEAKER_BACK_LEFT, SPEAKER_BACK_RIGHT,
54 SPEAKER_FRONT_LEFT_OF_CENTER, SPEAKER_FRONT_RIGHT_OF_CENTER,
55 SPEAKER_BACK_CENTER, SPEAKER_SIDE_LEFT, SPEAKER_SIDE_RIGHT,
56 SPEAKER_TOP_FRONT_LEFT, SPEAKER_TOP_FRONT_RIGHT, SPEAKER_TOP_FRONT_CENTER,
57 SPEAKER_TOP_CENTER, SPEAKER_TOP_BACK_LEFT, SPEAKER_TOP_BACK_RIGHT,
58 SPEAKER_TOP_BACK_CENTER, SPEAKER_RESERVED, SPEAKER_RESERVED};
60 static const enum AEChannel AEChannelNames[] = {AE_CH_RAW,
61 AE_CH_FL, AE_CH_FR, AE_CH_FC,
62 AE_CH_LFE, AE_CH_BL, AE_CH_BR,
63 AE_CH_FLOC, AE_CH_FROC,
64 AE_CH_BC, AE_CH_SL, AE_CH_SR,
65 AE_CH_TFL, AE_CH_TFR, AE_CH_TFC ,
66 AE_CH_TC , AE_CH_TBL, AE_CH_TBR,
67 AE_CH_TBC, AE_CH_BLOC, AE_CH_BROC};
69 static enum AEChannel layoutsByChCount[9][9] = {
71 {AE_CH_FC, AE_CH_NULL},
72 {AE_CH_FL, AE_CH_FR, AE_CH_NULL},
73 {AE_CH_FL, AE_CH_FR, AE_CH_FC, AE_CH_NULL},
74 {AE_CH_FL, AE_CH_FR, AE_CH_BL, AE_CH_BR, AE_CH_NULL},
75 {AE_CH_FL, AE_CH_FR, AE_CH_FC, AE_CH_BL, AE_CH_BR, AE_CH_NULL},
76 {AE_CH_FL, AE_CH_FR, AE_CH_FC, AE_CH_BL, AE_CH_BR, AE_CH_LFE, AE_CH_NULL},
77 {AE_CH_FL, AE_CH_FR, AE_CH_FC, AE_CH_BL, AE_CH_BR, AE_CH_BC, AE_CH_LFE, AE_CH_NULL},
78 {AE_CH_FL, AE_CH_FR, AE_CH_FC, AE_CH_BL, AE_CH_BR, AE_CH_SL, AE_CH_SR, AE_CH_LFE, AE_CH_NULL}};
83 unsigned int bitsPerSample;
84 unsigned int validBitsPerSample;
85 AEDataFormat subFormatType;
88 //Sample formats go from float -> 32 bit int -> 24 bit int (packed in 32) -> 16 bit int
89 static const sampleFormat testFormats[] = { {KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 32, 32, AE_FMT_FLOAT},
90 {KSDATAFORMAT_SUBTYPE_PCM, 32, 32, AE_FMT_S32NE},
91 {KSDATAFORMAT_SUBTYPE_PCM, 32, 24, AE_FMT_S24NE4},
92 {KSDATAFORMAT_SUBTYPE_PCM, 16, 16, AE_FMT_S16NE} };
94 struct winEndpointsToAEDeviceType
96 std::string winEndpointType;
97 AEDeviceType aeDeviceType;
100 static const winEndpointsToAEDeviceType winEndpoints[EndpointFormFactor_enum_count] =
102 {"Network Device - ", AE_DEVTYPE_PCM},
103 {"Speakers - ", AE_DEVTYPE_PCM},
104 {"LineLevel - ", AE_DEVTYPE_PCM},
105 {"Headphones - ", AE_DEVTYPE_PCM},
106 {"Microphone - ", AE_DEVTYPE_PCM},
107 {"Headset - ", AE_DEVTYPE_PCM},
108 {"Handset - ", AE_DEVTYPE_PCM},
109 {"Digital Passthrough - ", AE_DEVTYPE_IEC958},
110 {"SPDIF - ", AE_DEVTYPE_IEC958},
111 {"HDMI - ", AE_DEVTYPE_HDMI},
112 {"Unknown - ", AE_DEVTYPE_PCM},
115 AEDeviceInfoList DeviceInfoList;
117 #define EXIT_ON_FAILURE(hr, reason, ...) if(FAILED(hr)) {CLog::Log(LOGERROR, reason " - %s", __VA_ARGS__, WASAPIErrToStr(hr)); goto failed;}
119 #define ERRTOSTR(err) case err: return #err
121 DEFINE_PROPERTYKEY(PKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 14);
123 CAESinkWASAPI::CAESinkWASAPI() :
124 m_pAudioClient(NULL),
125 m_pRenderClient(NULL),
128 m_initialized(false),
130 m_encodedFormat(AE_FMT_INVALID),
131 m_encodedChannels(0),
132 m_encodedSampleRate(0),
134 m_avgTimeWaiting(50),
137 m_channelLayout.Reset();
140 CAESinkWASAPI::~CAESinkWASAPI()
145 bool CAESinkWASAPI::Initialize(AEAudioFormat &format, std::string &device)
150 CLog::Log(LOGDEBUG, __FUNCTION__": Initializing WASAPI Sink Rev. 1.0.5");
154 /* Save requested format */
155 /* Clear returned format */
156 sinkReqFormat = format.m_dataFormat;
157 sinkRetFormat = AE_FMT_INVALID;
159 IMMDeviceEnumerator* pEnumerator = NULL;
160 IMMDeviceCollection* pEnumDevices = NULL;
162 HRESULT hr = CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void**)&pEnumerator);
163 EXIT_ON_FAILURE(hr, __FUNCTION__": Could not allocate WASAPI device enumerator. CoCreateInstance error code: %li", hr)
166 //First try to find the named device.
169 hr = pEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &pEnumDevices);
170 EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of audio endpoint enumeration failed.")
172 hr = pEnumDevices->GetCount(&uiCount);
173 EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of audio endpoint count failed.")
175 for (UINT i = 0; i < uiCount; i++)
177 IPropertyStore *pProperty = NULL;
180 hr = pEnumDevices->Item(i, &m_pDevice);
181 EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of WASAPI endpoint failed.")
183 hr = m_pDevice->OpenPropertyStore(STGM_READ, &pProperty);
184 EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of WASAPI endpoint properties failed.")
186 hr = pProperty->GetValue(PKEY_AudioEndpoint_GUID, &varName);
189 CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint GUID failed.");
190 SAFE_RELEASE(pProperty);
194 std::wstring strRawDevName(varName.pwszVal);
195 std::string strDevName = std::string(strRawDevName.begin(), strRawDevName.end());
196 //g_charsetConverter.ucs2CharsetToStringCharset(strRawDevName, strDevName.c_str());
198 if (device == strDevName)
201 SAFE_RELEASE(m_pDevice);
203 PropVariantClear(&varName);
204 SAFE_RELEASE(pProperty);
207 SAFE_RELEASE(pEnumDevices);
211 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());
212 hr = pEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &m_pDevice);
213 EXIT_ON_FAILURE(hr, __FUNCTION__": Could not retrieve the default WASAPI audio endpoint.")
215 IPropertyStore *pProperty = NULL;
218 hr = m_pDevice->OpenPropertyStore(STGM_READ, &pProperty);
219 EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of WASAPI endpoint properties failed.")
221 hr = pProperty->GetValue(PKEY_AudioEndpoint_GUID, &varName);
223 std::wstring strRawDevName(varName.pwszVal);
224 std::string strDevName = std::string(strRawDevName.begin(), strRawDevName.end());
226 PropVariantClear(&varName);
227 SAFE_RELEASE(pProperty);
230 //We are done with the enumerator.
231 SAFE_RELEASE(pEnumerator);
233 hr = m_pDevice->Activate(IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&m_pAudioClient);
234 EXIT_ON_FAILURE(hr, __FUNCTION__": Activating the WASAPI endpoint device failed.")
236 if (!InitializeExclusive(format))
238 CLog::Log(LOGINFO, __FUNCTION__": Could not Initialize Exclusive with that format");
242 /* get the buffer size and calculate the frames for AE */
243 m_pAudioClient->GetBufferSize(&m_uiBufferLen);
245 format.m_frames = m_uiBufferLen;
246 format.m_frameSamples = format.m_frames * format.m_channelLayout.Count();
248 sinkRetFormat = format.m_dataFormat;
250 CLog::Log(LOGDEBUG, __FUNCTION__": Buffer Size = %d Bytes", m_uiBufferLen * format.m_frameSize);
252 hr = m_pAudioClient->GetService(IID_IAudioRenderClient, (void**)&m_pRenderClient);
253 EXIT_ON_FAILURE(hr, __FUNCTION__": Could not initialize the WASAPI render client interface.")
255 m_needDataEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
256 hr = m_pAudioClient->SetEventHandle(m_needDataEvent);
257 EXIT_ON_FAILURE(hr, __FUNCTION__": Could not set the WASAPI event handler.");
259 m_initialized = true;
265 CLog::Log(LOGERROR, __FUNCTION__": WASAPI initialization failed.");
266 SAFE_RELEASE(pEnumDevices);
267 SAFE_RELEASE(pEnumerator);
268 SAFE_RELEASE(m_pRenderClient);
269 SAFE_RELEASE(m_pAudioClient);
270 SAFE_RELEASE(m_pDevice);
271 CloseHandle(m_needDataEvent);
276 void CAESinkWASAPI::Deinitialize()
283 m_pAudioClient->Stop();
287 SAFE_RELEASE(m_pRenderClient);
288 SAFE_RELEASE(m_pAudioClient);
289 SAFE_RELEASE(m_pDevice);
290 CloseHandle(m_needDataEvent);
292 m_initialized = false;
295 bool CAESinkWASAPI::IsCompatible(const AEAudioFormat format, const std::string device)
297 if (!m_initialized || m_isDirty)
300 u_int notCompatible = 0;
301 const u_int numTests = 5;
302 std::string strDiffBecause ("");
303 static const char* compatibleParams[numTests] = {":Devices",
307 ":Passthrough Formats"};
309 notCompatible = (notCompatible +!((AE_IS_RAW(format.m_dataFormat) == AE_IS_RAW(m_encodedFormat)) ||
310 (!AE_IS_RAW(format.m_dataFormat) == !AE_IS_RAW(m_encodedFormat)))) << 1;
311 notCompatible = (notCompatible +!((sinkReqFormat == format.m_dataFormat) &&
312 (sinkRetFormat == m_format.m_dataFormat))) << 1;
313 notCompatible = (notCompatible + !(format.m_sampleRate == m_format.m_sampleRate)) << 1;
314 notCompatible = (notCompatible + !(format.m_channelLayout.Count() == m_format.m_channelLayout.Count())) << 1;
315 notCompatible = (notCompatible + !(m_device == device));
319 CLog::Log(LOGDEBUG, __FUNCTION__": Formats compatible - reusing existing sink");
323 for (int i = 0; i < numTests ; i++)
325 strDiffBecause += (notCompatible & 0x01) ? (std::string) compatibleParams[i] : "";
326 notCompatible = notCompatible >> 1;
329 CLog::Log(LOGDEBUG, __FUNCTION__": Formats Incompatible due to different %s", strDiffBecause.c_str());
333 double CAESinkWASAPI::GetDelay()
339 hr = m_pAudioClient->GetBufferSize(&m_uiBufferLen);
343 CLog::Log(LOGERROR, __FUNCTION__": GetBufferSize Failed : %s", WASAPIErrToStr(hr));
347 return (double)m_uiBufferLen / (double)m_format.m_sampleRate;
350 double CAESinkWASAPI::GetCacheTime()
355 REFERENCE_TIME hnsLatency;
356 HRESULT hr = m_pAudioClient->GetStreamLatency(&hnsLatency);
358 /** returns buffer duration in seconds */
359 return hnsLatency / 10.0;
362 double CAESinkWASAPI::GetCacheTotal()
367 REFERENCE_TIME hnsLatency;
368 HRESULT hr = m_pAudioClient->GetStreamLatency(&hnsLatency);
370 /** returns buffer duration in seconds */
371 return hnsLatency / 10.0;
374 unsigned int CAESinkWASAPI::AddPackets(uint8_t *data, unsigned int frames)
384 LARGE_INTEGER timerStart;
385 LARGE_INTEGER timerStop;
386 LARGE_INTEGER timerFreq;
389 unsigned int NumFramesRequested = frames;
391 if (!m_running) //first time called, pre-fill buffer then start audio client
393 hr = m_pRenderClient->GetBuffer(NumFramesRequested, &buf);
397 CLog::Log(LOGERROR, __FUNCTION__": GetBuffer failed due to %s", WASAPIErrToStr(hr));
399 m_isDirty = true; //flag new device or re-init needed
402 memcpy(buf, data, NumFramesRequested * m_format.m_frameSize); //fill buffer
403 hr = m_pRenderClient->ReleaseBuffer(NumFramesRequested, flags); //pass back to audio driver
407 CLog::Log(LOGDEBUG, __FUNCTION__": ReleaseBuffer failed due to %s.", WASAPIErrToStr(hr));
409 m_isDirty = true; //flag new device or re-init needed
412 hr = m_pAudioClient->Start(); //start the audio driver running
414 CLog::Log(LOGERROR, __FUNCTION__": AudioClient Start Failed");
415 m_running = true; //signal that we're processing frames
416 return NumFramesRequested;
420 /* Get clock time for latency checks */
421 QueryPerformanceFrequency(&timerFreq);
422 QueryPerformanceCounter(&timerStart);
425 /* Wait for Audio Driver to tell us it's got a buffer available */
426 DWORD eventAudioCallback = WaitForSingleObject(m_needDataEvent, 1100);
427 if (eventAudioCallback != WAIT_OBJECT_0)
429 // Event handle timed out - stop audio device
430 m_pAudioClient->Stop();
431 CLog::Log(LOGERROR, __FUNCTION__": Endpoint Buffer timed out");
433 m_pAudioClient->Stop(); //stop processing - we're done
434 m_isDirty = true; //flag new device or re-init needed
439 QueryPerformanceCounter(&timerStop);
440 LONGLONG timerDiff = timerStop.QuadPart - timerStart.QuadPart;
441 double timerElapsed = (double) timerDiff * 1000.0 / (double) timerFreq.QuadPart;
442 m_avgTimeWaiting += (timerElapsed - m_avgTimeWaiting) * 0.5;
444 if (m_avgTimeWaiting < 3.0)
446 CLog::Log(LOGDEBUG, __FUNCTION__": Possible AQ Loss: Avg. Time Waiting for Audio Driver callback : %dmsec", (int)m_avgTimeWaiting);
450 hr = m_pRenderClient->GetBuffer(NumFramesRequested, &buf);
454 CLog::Log(LOGERROR, __FUNCTION__": GetBuffer failed due to %s", WASAPIErrToStr(hr));
458 memcpy(buf, data, NumFramesRequested * m_format.m_frameSize); //fill buffer
459 hr = m_pRenderClient->ReleaseBuffer(NumFramesRequested, flags); //pass back to audio driver
463 CLog::Log(LOGDEBUG, __FUNCTION__": ReleaseBuffer failed due to %s.", WASAPIErrToStr(hr));
468 return NumFramesRequested;
471 void CAESinkWASAPI::EnumerateDevicesEx(AEDeviceInfoList &deviceInfoList)
473 IMMDeviceEnumerator* pEnumerator = NULL;
474 IMMDeviceCollection* pEnumDevices = NULL;
475 CAEDeviceInfo deviceInfo;
476 CAEChannelInfo deviceChannels;
478 WAVEFORMATEXTENSIBLE wfxex = {0};
479 WAVEFORMATEX* pwfxex = NULL;
482 hr = CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void**)&pEnumerator);
483 EXIT_ON_FAILURE(hr, __FUNCTION__": Could not allocate WASAPI device enumerator. CoCreateInstance error code: %li", hr)
487 hr = pEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &pEnumDevices);
488 EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of audio endpoint enumeration failed.")
490 hr = pEnumDevices->GetCount(&uiCount);
491 EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of audio endpoint count failed.")
493 for (UINT i = 0; i < uiCount; i++)
495 IMMDevice *pDevice = NULL;
496 IPropertyStore *pProperty = NULL;
498 PropVariantInit(&varName);
500 deviceInfo.m_channels.Reset();
501 deviceInfo.m_dataFormats.clear();
502 deviceInfo.m_sampleRates.clear();
504 hr = pEnumDevices->Item(i, &pDevice);
507 CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint failed.");
511 hr = pDevice->OpenPropertyStore(STGM_READ, &pProperty);
514 CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint properties failed.");
515 SAFE_RELEASE(pDevice);
519 hr = pProperty->GetValue(PKEY_Device_FriendlyName, &varName);
522 CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint device name failed.");
523 SAFE_RELEASE(pDevice);
524 SAFE_RELEASE(pProperty);
528 std::wstring strRawFriendlyName(varName.pwszVal);
529 std::string strFriendlyName = std::string(strRawFriendlyName.begin(), strRawFriendlyName.end());
531 PropVariantClear(&varName);
533 hr = pProperty->GetValue(PKEY_AudioEndpoint_GUID, &varName);
536 CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint GUID failed.");
537 SAFE_RELEASE(pDevice);
538 SAFE_RELEASE(pProperty);
542 std::wstring strRawDevName(varName.pwszVal);
543 std::string strDevName = std::string(strRawDevName.begin(), strRawDevName.end());
545 PropVariantClear(&varName);
547 hr = pProperty->GetValue(PKEY_AudioEndpoint_FormFactor, &varName);
550 CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint form factor failed.");
551 SAFE_RELEASE(pDevice);
552 SAFE_RELEASE(pProperty);
555 std::string strWinDevType = winEndpoints[(EndpointFormFactor)varName.uiVal].winEndpointType;
556 AEDeviceType aeDeviceType = winEndpoints[(EndpointFormFactor)varName.uiVal].aeDeviceType;
558 PropVariantClear(&varName);
560 hr = pProperty->GetValue(PKEY_AudioEndpoint_PhysicalSpeakers, &varName);
563 CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint speaker layout failed.");
564 SAFE_RELEASE(pDevice);
565 SAFE_RELEASE(pProperty);
568 unsigned int uiChannelMask = std::max(varName.uintVal, (unsigned int) AE_CH_FL | AE_CH_FR);
570 deviceChannels.Reset();
572 for (unsigned int c = 0; c < WASAPI_SPEAKER_COUNT; c++)
574 if (uiChannelMask & WASAPIChannelOrder[c])
575 deviceChannels += AEChannelNames[c];
578 PropVariantClear(&varName);
580 IAudioClient *pClient;
581 hr = pDevice->Activate(IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&pClient);
584 /* Test format DTS-HD */
585 wfxex.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
586 wfxex.Format.nSamplesPerSec = 192000;
587 wfxex.dwChannelMask = KSAUDIO_SPEAKER_7POINT1_SURROUND;
588 wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
589 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DTS_HD;
590 wfxex.Format.wBitsPerSample = 16;
591 wfxex.Samples.wValidBitsPerSample = 16;
592 wfxex.Format.nChannels = 8;
593 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
594 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
595 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
597 deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_DTSHD));
599 /* Test format Dolby TrueHD */
600 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_MLP;
601 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
603 deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_TRUEHD));
605 /* Test format Dolby EAC3 */
606 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL_PLUS;
607 wfxex.Format.nChannels = 2;
608 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
609 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
610 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
612 deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_EAC3));
614 /* Test format DTS */
615 wfxex.Format.nSamplesPerSec = 48000;
616 wfxex.dwChannelMask = KSAUDIO_SPEAKER_5POINT1;
617 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DTS;
618 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
619 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
620 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
622 deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_DTS));
624 /* Test format Dolby AC3 */
625 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL;
626 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
628 deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_AC3));
630 /* Test format AAC */
631 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_AAC;
632 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
634 deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_AAC));
636 /* Test format for PCM format iteration */
637 wfxex.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
638 wfxex.dwChannelMask = AE_CH_FL | AE_CH_FR;
639 wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
640 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
642 for (int p = AE_FMT_FLOAT; p > AE_FMT_INVALID; p--)
644 if (p < AE_FMT_FLOAT)
645 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
646 wfxex.Format.wBitsPerSample = CAEUtil::DataFormatToBits((AEDataFormat) p);
647 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
648 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
649 if (p <= AE_FMT_S24NE4 && p >= AE_FMT_S24BE4)
651 wfxex.Samples.wValidBitsPerSample = 24;
655 wfxex.Samples.wValidBitsPerSample = wfxex.Format.wBitsPerSample;
658 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
660 deviceInfo.m_dataFormats.push_back((AEDataFormat) p);
663 /* Test format for sample rate iteration */
664 wfxex.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
665 wfxex.dwChannelMask = AE_CH_FL | AE_CH_FR;
666 wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
667 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
668 wfxex.Format.wBitsPerSample = 16;
669 wfxex.Samples.wValidBitsPerSample = 16;
670 wfxex.Format.nChannels = 2;
671 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
672 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
674 for (int j = 0; j < WASAPISampleRateCount; j++)
676 wfxex.Format.nSamplesPerSec = WASAPISampleRates[j];
677 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
678 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
680 deviceInfo.m_sampleRates.push_back(WASAPISampleRates[j]);
683 /* Test format for channels iteration */
684 wfxex.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
685 wfxex.dwChannelMask = AE_CH_FL | AE_CH_FR;
686 wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
687 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
688 wfxex.Format.nSamplesPerSec = 48000;
689 wfxex.Format.wBitsPerSample = 16;
690 wfxex.Samples.wValidBitsPerSample = 16;
691 wfxex.Format.nChannels = 2;
692 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
693 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
695 //bool mpcmFlagged = false;
697 for (int k = AE_CH_LAYOUT_MAX; k > 0; k--)
700 for (int c = 0; c < WASAPI_SPEAKER_COUNT; c++)
702 if (uiChannelMask & WASAPIChannelOrder[c])
703 mask |= WASAPIChannelOrder[c];
706 wfxex.dwChannelMask = mask;
707 wfxex.Format.nChannels = k;
708 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
709 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
710 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
713 deviceChannels = layoutsByChCount[k];
714 if (k > AE_CH_LAYOUT_2_1) // && !mpcmFlagged)
716 deviceInfo.m_dataFormats.push_back(AE_FMT_LPCM);
717 //mpcmFlagged = true;
726 CLog::Log(LOGDEBUG, __FUNCTION__": Failed to activate device for passthrough capability testing.");
729 SAFE_RELEASE(pDevice);
730 SAFE_RELEASE(pProperty);
732 deviceInfo.m_deviceName = strDevName;
733 deviceInfo.m_displayName = strWinDevType.append(strFriendlyName);
734 deviceInfo.m_displayNameExtra = std::string("WASAPI: ").append(strFriendlyName);
735 deviceInfo.m_deviceType = aeDeviceType;
736 deviceInfo.m_channels = deviceChannels;
738 /* Now logged by AESinkFactory on startup */
739 //CLog::Log(LOGDEBUG,"Audio Device %d: %s", i, ((std::string)deviceInfo).c_str());
741 deviceInfoList.push_back(deviceInfo);
748 CLog::Log(LOGERROR, __FUNCTION__": Failed to enumerate WASAPI endpoint devices (%s).", WASAPIErrToStr(hr));
750 SAFE_RELEASE(pEnumDevices);
751 SAFE_RELEASE(pEnumerator);
754 //Private utility functions////////////////////////////////////////////////////
756 void CAESinkWASAPI::BuildWaveFormatExtensible(AEAudioFormat &format, WAVEFORMATEXTENSIBLE &wfxex)
758 wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
759 wfxex.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
762 if (!AE_IS_RAW(format.m_dataFormat)) // PCM data
764 wfxex.dwChannelMask = SpeakerMaskFromAEChannels(format.m_channelLayout);
765 wfxex.Format.nChannels = (WORD)format.m_channelLayout.Count();
766 wfxex.Format.nSamplesPerSec = format.m_sampleRate;
767 wfxex.Format.wBitsPerSample = format.m_dataFormat <= AE_FMT_S16NE ? 16 : 32;
768 wfxex.SubFormat = format.m_dataFormat <= AE_FMT_FLOAT ? KSDATAFORMAT_SUBTYPE_PCM : KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
772 wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
773 if (format.m_dataFormat == AE_FMT_AC3 || format.m_dataFormat == AE_FMT_DTS)
775 wfxex.dwChannelMask = bool (format.m_channelLayout.Count() == 2) ? KSAUDIO_SPEAKER_STEREO : KSAUDIO_SPEAKER_5POINT1;
777 if (format.m_dataFormat == AE_FMT_AC3)
779 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL;
780 //wfxex.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;
784 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL; //KSDATAFORMAT_SUBTYPE_IEC61937_DTS;
785 //wfxex.Format.wFormatTag = WAVE_FORMAT_DTS;
788 wfxex.Format.wBitsPerSample = 16;
789 wfxex.Samples.wValidBitsPerSample = 16;
790 wfxex.Format.nChannels = (WORD)format.m_channelLayout.Count();
791 wfxex.Format.nSamplesPerSec = format.m_sampleRate;
793 else if (format.m_dataFormat == AE_FMT_EAC3 || format.m_dataFormat == AE_FMT_TRUEHD || format.m_dataFormat == AE_FMT_DTSHD)
795 //IEC 61937 transmissions.
796 //Currently these formats only run over HDMI.
797 wfxex.Format.nSamplesPerSec = 192000L; // Link runs at 192 KHz.
798 wfxex.Format.wBitsPerSample = 16; // Always at 16 bits over IEC 60958.
799 wfxex.Samples.wValidBitsPerSample = 16;
800 wfxex.dwChannelMask = KSAUDIO_SPEAKER_7POINT1_SURROUND;
802 switch (format.m_dataFormat)
805 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL_PLUS;
806 wfxex.Format.nChannels = 2; // One IEC 60958 Line.
807 wfxex.dwChannelMask = KSAUDIO_SPEAKER_5POINT1;
810 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_MLP;
811 wfxex.Format.nChannels = 8; // Four IEC 60958 Lines.
812 wfxex.dwChannelMask = KSAUDIO_SPEAKER_7POINT1_SURROUND;
815 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DTS_HD;
816 wfxex.Format.nChannels = 8; // Four IEC 60958 Lines.
817 wfxex.dwChannelMask = KSAUDIO_SPEAKER_7POINT1_SURROUND;
821 if (format.m_channelLayout.Count() == 8)
822 wfxex.dwChannelMask = KSAUDIO_SPEAKER_7POINT1_SURROUND;
824 wfxex.dwChannelMask = KSAUDIO_SPEAKER_5POINT1;
828 if (wfxex.Format.wBitsPerSample == 32 && wfxex.SubFormat != KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)
829 wfxex.Samples.wValidBitsPerSample = 24;
831 wfxex.Samples.wValidBitsPerSample = wfxex.Format.wBitsPerSample;
833 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
834 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
837 void CAESinkWASAPI::BuildWaveFormatExtensibleIEC61397(AEAudioFormat &format, WAVEFORMATEXTENSIBLE_IEC61937 &wfxex)
839 //Fill the common structure.
840 BuildWaveFormatExtensible(format, wfxex.FormatExt);
842 wfxex.FormatExt.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE_IEC61937)-sizeof(WAVEFORMATEX);
843 wfxex.dwEncodedChannelCount = format.m_channelLayout.Count();
844 wfxex.dwEncodedSamplesPerSec = bool(format.m_dataFormat == AE_FMT_TRUEHD ||
845 format.m_dataFormat == AE_FMT_DTSHD ||
846 format.m_dataFormat == AE_FMT_EAC3) ? 96000L : 48000L;
847 wfxex.dwAverageBytesPerSec = 0; //Ignored */
850 bool CAESinkWASAPI::InitializeExclusive(AEAudioFormat &format)
852 WAVEFORMATEXTENSIBLE_IEC61937 wfxex_iec61937;
853 WAVEFORMATEXTENSIBLE &wfxex = wfxex_iec61937.FormatExt;
855 if (format.m_dataFormat <= AE_FMT_FLOAT) //DDDamian was AE_FMT_DTS
856 BuildWaveFormatExtensible(format, wfxex);
858 BuildWaveFormatExtensibleIEC61397(format, wfxex_iec61937);
860 //test for incomplete or startup format and provide default
861 if (format.m_sampleRate == 0 ||
862 format.m_channelLayout == NULL ||
863 format.m_dataFormat <= AE_FMT_INVALID ||
864 format.m_dataFormat >= AE_FMT_MAX ||
865 format.m_channelLayout.Count() == 0)
867 wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
868 wfxex.Format.nChannels = 2;
869 wfxex.Format.nSamplesPerSec = 44100L;
870 wfxex.Format.wBitsPerSample = 16;
871 wfxex.Format.nBlockAlign = 4;
872 wfxex.Samples.wValidBitsPerSample = 16;
873 wfxex.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
874 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nBlockAlign * wfxex.Format.nSamplesPerSec;
875 wfxex.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
876 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
879 CLog::Log(LOGDEBUG, __FUNCTION__": Checking IsFormatSupported with the following parameters:");
880 CLog::Log(LOGDEBUG, " Sample Rate : %d", wfxex.Format.nSamplesPerSec);
881 CLog::Log(LOGDEBUG, " Sample Format : %s", CAEUtil::DataFormatToStr(format.m_dataFormat));
882 CLog::Log(LOGDEBUG, " Bits Per Sample : %d", wfxex.Format.wBitsPerSample);
883 CLog::Log(LOGDEBUG, " Valid Bits/Samp : %d", wfxex.Samples.wValidBitsPerSample);
884 CLog::Log(LOGDEBUG, " Channel Count : %d", wfxex.Format.nChannels);
885 CLog::Log(LOGDEBUG, " Block Align : %d", wfxex.Format.nBlockAlign);
886 CLog::Log(LOGDEBUG, " Avg. Bytes Sec : %d", wfxex.Format.nAvgBytesPerSec);
887 CLog::Log(LOGDEBUG, " Samples/Block : %d", wfxex.Samples.wSamplesPerBlock);
888 CLog::Log(LOGDEBUG, " Format cBSize : %d", wfxex.Format.cbSize);
889 CLog::Log(LOGDEBUG, " Channel Layout : %s", ((std::string)format.m_channelLayout).c_str());
890 CLog::Log(LOGDEBUG, " Channel Mask : %d", wfxex.dwChannelMask);
892 if (wfxex.SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)
893 CLog::Log(LOGDEBUG, " SubFormat : KSDATAFORMAT_SUBTYPE_IEEE_FLOAT");
894 else if (wfxex.SubFormat == KSDATAFORMAT_SUBTYPE_PCM)
895 CLog::Log(LOGDEBUG, " SubFormat : KSDATAFORMAT_SUBTYPE_PCM");
896 else if (wfxex.SubFormat == KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL)
897 CLog::Log(LOGDEBUG, " SubFormat : KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL");
898 else if (wfxex.SubFormat == KSDATAFORMAT_SUBTYPE_IEC61937_DTS)
899 CLog::Log(LOGDEBUG, " SubFormat : KSDATAFORMAT_SUBTYPE_IEC61937_DTS");
900 else if (wfxex.SubFormat == KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL_PLUS)
901 CLog::Log(LOGDEBUG, " SubFormat : KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL_PLUS");
902 else if (wfxex.SubFormat == KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_MLP)
903 CLog::Log(LOGDEBUG, " SubFormat : KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_MLP");
904 else if (wfxex.SubFormat == KSDATAFORMAT_SUBTYPE_IEC61937_DTS_HD)
905 CLog::Log(LOGDEBUG, " SubFormat : KSDATAFORMAT_SUBTYPE_IEC61937_DTS_HD");
907 CLog::Log(LOGDEBUG, " SubFormat : NO SUBFORMAT SPECIFIED");
909 HRESULT hr = m_pAudioClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
913 CLog::Log(LOGDEBUG, __FUNCTION__": Format is Supported - will attempt to Initialize");
916 else if (hr != AUDCLNT_E_UNSUPPORTED_FORMAT) //It failed for a reason unrelated to an unsupported format.
918 CLog::Log(LOGERROR, __FUNCTION__": IsFormatSupported failed (%s)", WASAPIErrToStr(hr));
921 else if (AE_IS_RAW(format.m_dataFormat)) //No sense in trying other formats for passthrough.
924 CLog::Log(LOGERROR, __FUNCTION__": IsFormatSupported failed (%s) - trying to find a compatible format", WASAPIErrToStr(hr));
928 //The requested format is not supported by the device. Find something that works.
930 for (int j = 0; j < sizeof(testFormats)/sizeof(sampleFormat); j++)
934 wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
935 wfxex.SubFormat = testFormats[j].subFormat;
936 wfxex.Format.wBitsPerSample = testFormats[j].bitsPerSample;
937 wfxex.Samples.wValidBitsPerSample = testFormats[j].validBitsPerSample;
938 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
940 for (int i = 0 ; i < WASAPISampleRateCount; i++)
942 wfxex.Format.nSamplesPerSec = WASAPISampleRates[i];
943 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
945 /* Uncomment to trace format match iteration loop via log */
946 CLog::Log(LOGDEBUG, "WASAPI: Trying Sample Format : %s", CAEUtil::DataFormatToStr(testFormats[j].subFormatType));
947 CLog::Log(LOGDEBUG, "WASAPI: Trying Sample Rate : %d", wfxex.Format.nSamplesPerSec);
948 CLog::Log(LOGDEBUG, "WASAPI: Trying Bits/Sample : %d", wfxex.Format.wBitsPerSample);
949 CLog::Log(LOGDEBUG, "WASAPI: Trying Valid Bits/Sample: %d", wfxex.Samples.wValidBitsPerSample);
951 hr = m_pAudioClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
955 //If the current sample rate matches the source then stop looking and use it.
956 if ((WASAPISampleRates[i] == format.m_sampleRate) && (testFormats[j].subFormatType <= format.m_dataFormat))
958 //If this rate is closer to the source then the previous one, save it.
959 else if (closestMatch < 0 || abs((int)WASAPISampleRates[i] - (int)format.m_sampleRate) < abs((int)WASAPISampleRates[closestMatch] - (int)format.m_sampleRate))
962 else if (hr != AUDCLNT_E_UNSUPPORTED_FORMAT)
963 CLog::Log(LOGERROR, __FUNCTION__": IsFormatSupported failed (%s)", WASAPIErrToStr(hr));
966 if (closestMatch >= 0)
968 wfxex.Format.nSamplesPerSec = WASAPISampleRates[closestMatch];
969 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
974 CLog::Log(LOGERROR, __FUNCTION__": Unable to locate a supported output format for the device. Check the speaker settings in the control panel.");
976 //We couldn't find anything supported. This should never happen unless the user set the wrong
977 //speaker setting in the control panel.
982 AEChannelsFromSpeakerMask(wfxex.dwChannelMask);
984 //When the stream is raw, the values in the format structure are set to the link
985 //parameters, so store the encoded stream values here for the IsCompatible function.
986 m_encodedFormat = format.m_dataFormat;
987 m_encodedChannels = wfxex.Format.nChannels;
988 m_encodedSampleRate = format.m_encodedRate;// bool(format.m_dataFormat == AE_FMT_TRUEHD || format.m_dataFormat == AE_FMT_DTSHD) ? 96000L : 48000L;
989 wfxex_iec61937.dwEncodedChannelCount = wfxex.Format.nChannels;
990 wfxex_iec61937.dwEncodedSamplesPerSec = m_encodedSampleRate;
992 if (!AE_IS_RAW(format.m_dataFormat))
994 if (wfxex.Format.wBitsPerSample == 32)
996 if (wfxex.SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)
997 format.m_dataFormat = AE_FMT_FLOAT;
998 else if (wfxex.Samples.wValidBitsPerSample == 32)
999 format.m_dataFormat = AE_FMT_S32NE;
1001 format.m_dataFormat = AE_FMT_S24NE4;
1005 format.m_dataFormat = AE_FMT_S16NE;
1009 format.m_sampleRate = wfxex.Format.nSamplesPerSec; //PCM: Sample rate. RAW: Link speed
1011 format.m_frameSize = (wfxex.Format.wBitsPerSample >> 3) * wfxex.Format.nChannels;
1013 REFERENCE_TIME audioSinkBufferDurationMsec, hnsLatency;
1015 /* Get m_audioSinkBufferSizeMsec from advancedsettings.xml */
1016 audioSinkBufferDurationMsec = (REFERENCE_TIME)g_advancedSettings.m_audioSinkBufferDurationMsec * 10000;
1018 //use user's advancedsetting value for buffer size as long as it's over minimum set above
1019 audioSinkBufferDurationMsec = (REFERENCE_TIME)std::max(audioSinkBufferDurationMsec, (REFERENCE_TIME)500000);
1020 audioSinkBufferDurationMsec = (REFERENCE_TIME)((audioSinkBufferDurationMsec / format.m_frameSize) * format.m_frameSize); //even number of frames
1022 CLog::Log(LOGDEBUG, __FUNCTION__": Initializing WASAPI exclusive mode with the following parameters:");
1023 CLog::Log(LOGDEBUG, " Sample Rate : %d", wfxex.Format.nSamplesPerSec);
1024 CLog::Log(LOGDEBUG, " Sample Format : %s", CAEUtil::DataFormatToStr(format.m_dataFormat));
1025 CLog::Log(LOGDEBUG, " Bits Per Sample : %d", wfxex.Format.wBitsPerSample);
1026 CLog::Log(LOGDEBUG, " Valid Bits/Samp : %d", wfxex.Samples.wValidBitsPerSample);
1027 CLog::Log(LOGDEBUG, " Channel Count : %d", wfxex.Format.nChannels);
1028 CLog::Log(LOGDEBUG, " Block Align : %d", wfxex.Format.nBlockAlign);
1029 CLog::Log(LOGDEBUG, " Avg. Bytes Sec : %d", wfxex.Format.nAvgBytesPerSec);
1030 CLog::Log(LOGDEBUG, " Samples/Block : %d", wfxex.Samples.wSamplesPerBlock);
1031 CLog::Log(LOGDEBUG, " Format cBSize : %d", wfxex.Format.cbSize);
1032 CLog::Log(LOGDEBUG, " Channel Layout : %s", ((std::string)format.m_channelLayout).c_str());
1033 CLog::Log(LOGDEBUG, " Enc. Channels : %d", wfxex_iec61937.dwEncodedChannelCount);
1034 CLog::Log(LOGDEBUG, " Enc. Samples/Sec: %d", wfxex_iec61937.dwEncodedSamplesPerSec);
1035 CLog::Log(LOGDEBUG, " Channel Mask : %d", wfxex.dwChannelMask);
1036 CLog::Log(LOGDEBUG, " Periodicty : %d", audioSinkBufferDurationMsec);
1038 if (wfxex.SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)
1039 CLog::Log(LOGDEBUG, " SubFormat : KSDATAFORMAT_SUBTYPE_IEEE_FLOAT");
1040 else if (wfxex.SubFormat == KSDATAFORMAT_SUBTYPE_PCM)
1041 CLog::Log(LOGDEBUG, " SubFormat : KSDATAFORMAT_SUBTYPE_PCM");
1042 else if (wfxex.SubFormat == KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL)
1043 CLog::Log(LOGDEBUG, " SubFormat : KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL");
1044 else if (wfxex.SubFormat == KSDATAFORMAT_SUBTYPE_IEC61937_DTS)
1045 CLog::Log(LOGDEBUG, " SubFormat : KSDATAFORMAT_SUBTYPE_IEC61937_DTS");
1046 else if (wfxex.SubFormat == KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL_PLUS)
1047 CLog::Log(LOGDEBUG, " SubFormat : KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL_PLUS");
1048 else if (wfxex.SubFormat == KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_MLP)
1049 CLog::Log(LOGDEBUG, " SubFormat : KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_MLP");
1050 else if (wfxex.SubFormat == KSDATAFORMAT_SUBTYPE_IEC61937_DTS_HD)
1051 CLog::Log(LOGDEBUG, " SubFormat : KSDATAFORMAT_SUBTYPE_IEC61937_DTS_HD");
1053 CLog::Log(LOGDEBUG, " SubFormat : NO SUBFORMAT SPECIFIED");
1055 if (AE_IS_RAW(format.m_dataFormat))
1056 format.m_dataFormat = AE_FMT_S16NE;
1058 hr = m_pAudioClient->Initialize(AUDCLNT_SHAREMODE_EXCLUSIVE, AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_NOPERSIST,
1059 audioSinkBufferDurationMsec, audioSinkBufferDurationMsec, &wfxex.Format, NULL);
1061 if (hr == AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED)
1063 CLog::Log(LOGDEBUG, __FUNCTION__": Re-aligning WASAPI sink buffer due to %s.", WASAPIErrToStr(hr));
1064 // Get the next aligned frame.
1065 hr = m_pAudioClient->GetBufferSize(&m_uiBufferLen);
1068 CLog::Log(LOGERROR, __FUNCTION__": GetBufferSize Failed : %s", WASAPIErrToStr(hr));
1072 audioSinkBufferDurationMsec = (REFERENCE_TIME) ((10000.0 * 1000 / wfxex.Format.nSamplesPerSec * m_uiBufferLen) + 0.5);
1073 CLog::Log(LOGDEBUG, __FUNCTION__": Number of Frames in Buffer : %d", m_uiBufferLen);
1074 CLog::Log(LOGDEBUG, __FUNCTION__": Requested Duration of Buffer : %d", audioSinkBufferDurationMsec);
1076 // Release the previous allocations.
1077 SAFE_RELEASE(m_pAudioClient);
1079 // Create a new audio client.
1080 hr = m_pDevice->Activate(IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&m_pAudioClient);
1083 CLog::Log(LOGERROR, __FUNCTION__": Device Activation Failed : %s", WASAPIErrToStr(hr));
1087 // Open the stream and associate it with an audio session.
1088 hr = m_pAudioClient->Initialize(AUDCLNT_SHAREMODE_EXCLUSIVE, AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_NOPERSIST,
1089 audioSinkBufferDurationMsec, audioSinkBufferDurationMsec, &wfxex.Format, NULL);
1093 CLog::Log(LOGERROR, __FUNCTION__": Unable to initialize WASAPI in exclusive mode %d - (%s).", HRESULT(hr), WASAPIErrToStr(hr));
1096 hr = m_pAudioClient->GetStreamLatency(&hnsLatency);
1097 CLog::Log(LOGDEBUG, __FUNCTION__": Requested Duration of Buffer : %fmsec", hnsLatency / 10000.0);
1098 CLog::Log(LOGNOTICE, __FUNCTION__": WASAPI Exclusive Mode Sink Initialized Successfully!!!");
1102 void CAESinkWASAPI::AEChannelsFromSpeakerMask(DWORD speakers)
1104 m_channelLayout.Reset();
1106 for (int i = 0; i < WASAPI_SPEAKER_COUNT; i++)
1108 if (speakers & WASAPIChannelOrder[i])
1109 m_channelLayout += AEChannelNames[i];
1113 DWORD CAESinkWASAPI::SpeakerMaskFromAEChannels(const CAEChannelInfo &channels)
1117 for (unsigned int i = 0; i < channels.Count(); i++)
1119 for (unsigned int j = 0; j < WASAPI_SPEAKER_COUNT; j++)
1120 if (channels[i] == AEChannelNames[j])
1121 mask |= WASAPIChannelOrder[j];
1126 const char *CAESinkWASAPI::WASAPIErrToStr(HRESULT err)
1130 ERRTOSTR(AUDCLNT_E_NOT_INITIALIZED);
1131 ERRTOSTR(AUDCLNT_E_ALREADY_INITIALIZED);
1132 ERRTOSTR(AUDCLNT_E_WRONG_ENDPOINT_TYPE);
1133 ERRTOSTR(AUDCLNT_E_DEVICE_INVALIDATED);
1134 ERRTOSTR(AUDCLNT_E_NOT_STOPPED);
1135 ERRTOSTR(AUDCLNT_E_BUFFER_TOO_LARGE);
1136 ERRTOSTR(AUDCLNT_E_OUT_OF_ORDER);
1137 ERRTOSTR(AUDCLNT_E_UNSUPPORTED_FORMAT);
1138 ERRTOSTR(AUDCLNT_E_INVALID_SIZE);
1139 ERRTOSTR(AUDCLNT_E_DEVICE_IN_USE);
1140 ERRTOSTR(AUDCLNT_E_BUFFER_OPERATION_PENDING);
1141 ERRTOSTR(AUDCLNT_E_THREAD_NOT_REGISTERED);
1142 ERRTOSTR(AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED);
1143 ERRTOSTR(AUDCLNT_E_ENDPOINT_CREATE_FAILED);
1144 ERRTOSTR(AUDCLNT_E_SERVICE_NOT_RUNNING);
1145 ERRTOSTR(AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED);
1146 ERRTOSTR(AUDCLNT_E_EXCLUSIVE_MODE_ONLY);
1147 ERRTOSTR(AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL);
1148 ERRTOSTR(AUDCLNT_E_EVENTHANDLE_NOT_SET);
1149 ERRTOSTR(AUDCLNT_E_INCORRECT_BUFFER_SIZE);
1150 ERRTOSTR(AUDCLNT_E_BUFFER_SIZE_ERROR);
1151 ERRTOSTR(AUDCLNT_E_CPUUSAGE_EXCEEDED);
1152 ERRTOSTR(AUDCLNT_E_BUFFER_ERROR);
1153 ERRTOSTR(AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED);
1154 ERRTOSTR(AUDCLNT_E_INVALID_DEVICE_PERIOD);
1155 ERRTOSTR(E_POINTER);
1156 ERRTOSTR(E_INVALIDARG);
1157 ERRTOSTR(E_OUTOFMEMORY);