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()
335 return GetCacheTime();
338 double CAESinkWASAPI::GetCacheTime()
343 unsigned int numPaddingFrames;
344 HRESULT hr = m_pAudioClient->GetCurrentPadding(&numPaddingFrames);
347 CLog::Log(LOGERROR, __FUNCTION__": GetCurrentPadding Failed : %s", WASAPIErrToStr(hr));
350 return (double)numPaddingFrames / (double)m_format.m_sampleRate;
353 double CAESinkWASAPI::GetCacheTotal()
358 REFERENCE_TIME hnsLatency;
359 HRESULT hr = m_pAudioClient->GetStreamLatency(&hnsLatency);
361 /** returns buffer duration in seconds */
362 return hnsLatency / 10.0;
365 unsigned int CAESinkWASAPI::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio)
375 LARGE_INTEGER timerStart;
376 LARGE_INTEGER timerStop;
377 LARGE_INTEGER timerFreq;
380 unsigned int NumFramesRequested = frames;
382 if (!m_running) //first time called, pre-fill buffer then start audio client
384 hr = m_pRenderClient->GetBuffer(NumFramesRequested, &buf);
388 CLog::Log(LOGERROR, __FUNCTION__": GetBuffer failed due to %s", WASAPIErrToStr(hr));
390 m_isDirty = true; //flag new device or re-init needed
393 memcpy(buf, data, NumFramesRequested * m_format.m_frameSize); //fill buffer
394 hr = m_pRenderClient->ReleaseBuffer(NumFramesRequested, flags); //pass back to audio driver
398 CLog::Log(LOGDEBUG, __FUNCTION__": ReleaseBuffer failed due to %s.", WASAPIErrToStr(hr));
400 m_isDirty = true; //flag new device or re-init needed
403 hr = m_pAudioClient->Start(); //start the audio driver running
405 CLog::Log(LOGERROR, __FUNCTION__": AudioClient Start Failed");
406 m_running = true; //signal that we're processing frames
407 return NumFramesRequested;
411 /* Get clock time for latency checks */
412 QueryPerformanceFrequency(&timerFreq);
413 QueryPerformanceCounter(&timerStart);
416 /* Wait for Audio Driver to tell us it's got a buffer available */
417 DWORD eventAudioCallback = WaitForSingleObject(m_needDataEvent, 1100);
418 if (eventAudioCallback != WAIT_OBJECT_0)
420 // Event handle timed out - stop audio device
421 m_pAudioClient->Stop();
422 CLog::Log(LOGERROR, __FUNCTION__": Endpoint Buffer timed out");
424 m_pAudioClient->Stop(); //stop processing - we're done
425 m_isDirty = true; //flag new device or re-init needed
430 QueryPerformanceCounter(&timerStop);
431 LONGLONG timerDiff = timerStop.QuadPart - timerStart.QuadPart;
432 double timerElapsed = (double) timerDiff * 1000.0 / (double) timerFreq.QuadPart;
433 m_avgTimeWaiting += (timerElapsed - m_avgTimeWaiting) * 0.5;
435 if (m_avgTimeWaiting < 3.0)
437 CLog::Log(LOGDEBUG, __FUNCTION__": Possible AQ Loss: Avg. Time Waiting for Audio Driver callback : %dmsec", (int)m_avgTimeWaiting);
441 hr = m_pRenderClient->GetBuffer(NumFramesRequested, &buf);
445 CLog::Log(LOGERROR, __FUNCTION__": GetBuffer failed due to %s", WASAPIErrToStr(hr));
449 memcpy(buf, data, NumFramesRequested * m_format.m_frameSize); //fill buffer
450 hr = m_pRenderClient->ReleaseBuffer(NumFramesRequested, flags); //pass back to audio driver
454 CLog::Log(LOGDEBUG, __FUNCTION__": ReleaseBuffer failed due to %s.", WASAPIErrToStr(hr));
459 return NumFramesRequested;
462 void CAESinkWASAPI::EnumerateDevicesEx(AEDeviceInfoList &deviceInfoList)
464 IMMDeviceEnumerator* pEnumerator = NULL;
465 IMMDeviceCollection* pEnumDevices = NULL;
466 CAEDeviceInfo deviceInfo;
467 CAEChannelInfo deviceChannels;
469 WAVEFORMATEXTENSIBLE wfxex = {0};
470 WAVEFORMATEX* pwfxex = NULL;
473 hr = CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void**)&pEnumerator);
474 EXIT_ON_FAILURE(hr, __FUNCTION__": Could not allocate WASAPI device enumerator. CoCreateInstance error code: %li", hr)
478 hr = pEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &pEnumDevices);
479 EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of audio endpoint enumeration failed.")
481 hr = pEnumDevices->GetCount(&uiCount);
482 EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of audio endpoint count failed.")
484 for (UINT i = 0; i < uiCount; i++)
486 IMMDevice *pDevice = NULL;
487 IPropertyStore *pProperty = NULL;
489 PropVariantInit(&varName);
491 deviceInfo.m_channels.Reset();
492 deviceInfo.m_dataFormats.clear();
493 deviceInfo.m_sampleRates.clear();
495 hr = pEnumDevices->Item(i, &pDevice);
498 CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint failed.");
502 hr = pDevice->OpenPropertyStore(STGM_READ, &pProperty);
505 CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint properties failed.");
506 SAFE_RELEASE(pDevice);
510 hr = pProperty->GetValue(PKEY_Device_FriendlyName, &varName);
513 CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint device name failed.");
514 SAFE_RELEASE(pDevice);
515 SAFE_RELEASE(pProperty);
519 std::wstring strRawFriendlyName(varName.pwszVal);
520 std::string strFriendlyName = std::string(strRawFriendlyName.begin(), strRawFriendlyName.end());
522 PropVariantClear(&varName);
524 hr = pProperty->GetValue(PKEY_AudioEndpoint_GUID, &varName);
527 CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint GUID failed.");
528 SAFE_RELEASE(pDevice);
529 SAFE_RELEASE(pProperty);
533 std::wstring strRawDevName(varName.pwszVal);
534 std::string strDevName = std::string(strRawDevName.begin(), strRawDevName.end());
536 PropVariantClear(&varName);
538 hr = pProperty->GetValue(PKEY_AudioEndpoint_FormFactor, &varName);
541 CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint form factor failed.");
542 SAFE_RELEASE(pDevice);
543 SAFE_RELEASE(pProperty);
546 std::string strWinDevType = winEndpoints[(EndpointFormFactor)varName.uiVal].winEndpointType;
547 AEDeviceType aeDeviceType = winEndpoints[(EndpointFormFactor)varName.uiVal].aeDeviceType;
549 PropVariantClear(&varName);
551 hr = pProperty->GetValue(PKEY_AudioEndpoint_PhysicalSpeakers, &varName);
554 CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint speaker layout failed.");
555 SAFE_RELEASE(pDevice);
556 SAFE_RELEASE(pProperty);
559 unsigned int uiChannelMask = std::max(varName.uintVal, (unsigned int) AE_CH_FL | AE_CH_FR);
561 deviceChannels.Reset();
563 for (unsigned int c = 0; c < WASAPI_SPEAKER_COUNT; c++)
565 if (uiChannelMask & WASAPIChannelOrder[c])
566 deviceChannels += AEChannelNames[c];
569 PropVariantClear(&varName);
571 IAudioClient *pClient;
572 hr = pDevice->Activate(IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&pClient);
575 /* Test format DTS-HD */
576 wfxex.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
577 wfxex.Format.nSamplesPerSec = 192000;
578 wfxex.dwChannelMask = KSAUDIO_SPEAKER_7POINT1_SURROUND;
579 wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
580 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DTS_HD;
581 wfxex.Format.wBitsPerSample = 16;
582 wfxex.Samples.wValidBitsPerSample = 16;
583 wfxex.Format.nChannels = 8;
584 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
585 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
586 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
588 deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_DTSHD));
590 /* Test format Dolby TrueHD */
591 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_MLP;
592 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
594 deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_TRUEHD));
596 /* Test format Dolby EAC3 */
597 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL_PLUS;
598 wfxex.Format.nChannels = 2;
599 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
600 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
601 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
603 deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_EAC3));
605 /* Test format DTS */
606 wfxex.Format.nSamplesPerSec = 48000;
607 wfxex.dwChannelMask = KSAUDIO_SPEAKER_5POINT1;
608 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DTS;
609 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
610 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
611 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
613 deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_DTS));
615 /* Test format Dolby AC3 */
616 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL;
617 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
619 deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_AC3));
621 /* Test format AAC */
622 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_AAC;
623 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
625 deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_AAC));
627 /* Test format for PCM format iteration */
628 wfxex.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
629 wfxex.dwChannelMask = AE_CH_FL | AE_CH_FR;
630 wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
631 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
633 for (int p = AE_FMT_FLOAT; p > AE_FMT_INVALID; p--)
635 if (p < AE_FMT_FLOAT)
636 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
637 wfxex.Format.wBitsPerSample = CAEUtil::DataFormatToBits((AEDataFormat) p);
638 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
639 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
640 if (p <= AE_FMT_S24NE4 && p >= AE_FMT_S24BE4)
642 wfxex.Samples.wValidBitsPerSample = 24;
646 wfxex.Samples.wValidBitsPerSample = wfxex.Format.wBitsPerSample;
649 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
651 deviceInfo.m_dataFormats.push_back((AEDataFormat) p);
654 /* Test format for sample rate iteration */
655 wfxex.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
656 wfxex.dwChannelMask = AE_CH_FL | AE_CH_FR;
657 wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
658 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
659 wfxex.Format.wBitsPerSample = 16;
660 wfxex.Samples.wValidBitsPerSample = 16;
661 wfxex.Format.nChannels = 2;
662 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
663 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
665 for (int j = 0; j < WASAPISampleRateCount; j++)
667 wfxex.Format.nSamplesPerSec = WASAPISampleRates[j];
668 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
669 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
671 deviceInfo.m_sampleRates.push_back(WASAPISampleRates[j]);
674 /* Test format for channels iteration */
675 wfxex.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
676 wfxex.dwChannelMask = AE_CH_FL | AE_CH_FR;
677 wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
678 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
679 wfxex.Format.nSamplesPerSec = 48000;
680 wfxex.Format.wBitsPerSample = 16;
681 wfxex.Samples.wValidBitsPerSample = 16;
682 wfxex.Format.nChannels = 2;
683 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
684 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
686 //bool mpcmFlagged = false;
688 for (int k = AE_CH_LAYOUT_MAX; k > 0; k--)
691 for (int c = 0; c < WASAPI_SPEAKER_COUNT; c++)
693 if (uiChannelMask & WASAPIChannelOrder[c])
694 mask |= WASAPIChannelOrder[c];
697 wfxex.dwChannelMask = mask;
698 wfxex.Format.nChannels = k;
699 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
700 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
701 hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
704 deviceChannels = layoutsByChCount[k];
705 if (k > AE_CH_LAYOUT_2_1) // && !mpcmFlagged)
707 deviceInfo.m_dataFormats.push_back(AE_FMT_LPCM);
708 //mpcmFlagged = true;
717 CLog::Log(LOGDEBUG, __FUNCTION__": Failed to activate device for passthrough capability testing.");
720 SAFE_RELEASE(pDevice);
721 SAFE_RELEASE(pProperty);
723 deviceInfo.m_deviceName = strDevName;
724 deviceInfo.m_displayName = strWinDevType.append(strFriendlyName);
725 deviceInfo.m_displayNameExtra = std::string("WASAPI: ").append(strFriendlyName);
726 deviceInfo.m_deviceType = aeDeviceType;
727 deviceInfo.m_channels = deviceChannels;
729 /* Now logged by AESinkFactory on startup */
730 //CLog::Log(LOGDEBUG,"Audio Device %d: %s", i, ((std::string)deviceInfo).c_str());
732 deviceInfoList.push_back(deviceInfo);
739 CLog::Log(LOGERROR, __FUNCTION__": Failed to enumerate WASAPI endpoint devices (%s).", WASAPIErrToStr(hr));
741 SAFE_RELEASE(pEnumDevices);
742 SAFE_RELEASE(pEnumerator);
745 //Private utility functions////////////////////////////////////////////////////
747 void CAESinkWASAPI::BuildWaveFormatExtensible(AEAudioFormat &format, WAVEFORMATEXTENSIBLE &wfxex)
749 wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
750 wfxex.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
753 if (!AE_IS_RAW(format.m_dataFormat)) // PCM data
755 wfxex.dwChannelMask = SpeakerMaskFromAEChannels(format.m_channelLayout);
756 wfxex.Format.nChannels = (WORD)format.m_channelLayout.Count();
757 wfxex.Format.nSamplesPerSec = format.m_sampleRate;
758 wfxex.Format.wBitsPerSample = format.m_dataFormat <= AE_FMT_S16NE ? 16 : 32;
759 wfxex.SubFormat = format.m_dataFormat <= AE_FMT_FLOAT ? KSDATAFORMAT_SUBTYPE_PCM : KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
763 wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
764 if (format.m_dataFormat == AE_FMT_AC3 || format.m_dataFormat == AE_FMT_DTS)
766 wfxex.dwChannelMask = bool (format.m_channelLayout.Count() == 2) ? KSAUDIO_SPEAKER_STEREO : KSAUDIO_SPEAKER_5POINT1;
768 if (format.m_dataFormat == AE_FMT_AC3)
770 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL;
771 //wfxex.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;
775 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL; //KSDATAFORMAT_SUBTYPE_IEC61937_DTS;
776 //wfxex.Format.wFormatTag = WAVE_FORMAT_DTS;
779 wfxex.Format.wBitsPerSample = 16;
780 wfxex.Samples.wValidBitsPerSample = 16;
781 wfxex.Format.nChannels = (WORD)format.m_channelLayout.Count();
782 wfxex.Format.nSamplesPerSec = format.m_sampleRate;
784 else if (format.m_dataFormat == AE_FMT_EAC3 || format.m_dataFormat == AE_FMT_TRUEHD || format.m_dataFormat == AE_FMT_DTSHD)
786 //IEC 61937 transmissions.
787 //Currently these formats only run over HDMI.
788 wfxex.Format.nSamplesPerSec = 192000L; // Link runs at 192 KHz.
789 wfxex.Format.wBitsPerSample = 16; // Always at 16 bits over IEC 60958.
790 wfxex.Samples.wValidBitsPerSample = 16;
791 wfxex.dwChannelMask = KSAUDIO_SPEAKER_7POINT1_SURROUND;
793 switch (format.m_dataFormat)
796 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL_PLUS;
797 wfxex.Format.nChannels = 2; // One IEC 60958 Line.
798 wfxex.dwChannelMask = KSAUDIO_SPEAKER_5POINT1;
801 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_MLP;
802 wfxex.Format.nChannels = 8; // Four IEC 60958 Lines.
803 wfxex.dwChannelMask = KSAUDIO_SPEAKER_7POINT1_SURROUND;
806 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEC61937_DTS_HD;
807 wfxex.Format.nChannels = 8; // Four IEC 60958 Lines.
808 wfxex.dwChannelMask = KSAUDIO_SPEAKER_7POINT1_SURROUND;
812 if (format.m_channelLayout.Count() == 8)
813 wfxex.dwChannelMask = KSAUDIO_SPEAKER_7POINT1_SURROUND;
815 wfxex.dwChannelMask = KSAUDIO_SPEAKER_5POINT1;
819 if (wfxex.Format.wBitsPerSample == 32 && wfxex.SubFormat != KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)
820 wfxex.Samples.wValidBitsPerSample = 24;
822 wfxex.Samples.wValidBitsPerSample = wfxex.Format.wBitsPerSample;
824 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
825 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
828 void CAESinkWASAPI::BuildWaveFormatExtensibleIEC61397(AEAudioFormat &format, WAVEFORMATEXTENSIBLE_IEC61937 &wfxex)
830 //Fill the common structure.
831 BuildWaveFormatExtensible(format, wfxex.FormatExt);
833 wfxex.FormatExt.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE_IEC61937)-sizeof(WAVEFORMATEX);
834 wfxex.dwEncodedChannelCount = format.m_channelLayout.Count();
835 wfxex.dwEncodedSamplesPerSec = bool(format.m_dataFormat == AE_FMT_TRUEHD ||
836 format.m_dataFormat == AE_FMT_DTSHD ||
837 format.m_dataFormat == AE_FMT_EAC3) ? 96000L : 48000L;
838 wfxex.dwAverageBytesPerSec = 0; //Ignored */
841 bool CAESinkWASAPI::InitializeExclusive(AEAudioFormat &format)
843 WAVEFORMATEXTENSIBLE_IEC61937 wfxex_iec61937;
844 WAVEFORMATEXTENSIBLE &wfxex = wfxex_iec61937.FormatExt;
846 if (format.m_dataFormat <= AE_FMT_FLOAT) //DDDamian was AE_FMT_DTS
847 BuildWaveFormatExtensible(format, wfxex);
849 BuildWaveFormatExtensibleIEC61397(format, wfxex_iec61937);
851 //test for incomplete or startup format and provide default
852 if (format.m_sampleRate == 0 ||
853 format.m_channelLayout == NULL ||
854 format.m_dataFormat <= AE_FMT_INVALID ||
855 format.m_dataFormat >= AE_FMT_MAX ||
856 format.m_channelLayout.Count() == 0)
858 wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
859 wfxex.Format.nChannels = 2;
860 wfxex.Format.nSamplesPerSec = 44100L;
861 wfxex.Format.wBitsPerSample = 16;
862 wfxex.Format.nBlockAlign = 4;
863 wfxex.Samples.wValidBitsPerSample = 16;
864 wfxex.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
865 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nBlockAlign * wfxex.Format.nSamplesPerSec;
866 wfxex.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
867 wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
870 CLog::Log(LOGDEBUG, __FUNCTION__": Checking IsFormatSupported with the following parameters:");
871 CLog::Log(LOGDEBUG, " Sample Rate : %d", wfxex.Format.nSamplesPerSec);
872 CLog::Log(LOGDEBUG, " Sample Format : %s", CAEUtil::DataFormatToStr(format.m_dataFormat));
873 CLog::Log(LOGDEBUG, " Bits Per Sample : %d", wfxex.Format.wBitsPerSample);
874 CLog::Log(LOGDEBUG, " Valid Bits/Samp : %d", wfxex.Samples.wValidBitsPerSample);
875 CLog::Log(LOGDEBUG, " Channel Count : %d", wfxex.Format.nChannels);
876 CLog::Log(LOGDEBUG, " Block Align : %d", wfxex.Format.nBlockAlign);
877 CLog::Log(LOGDEBUG, " Avg. Bytes Sec : %d", wfxex.Format.nAvgBytesPerSec);
878 CLog::Log(LOGDEBUG, " Samples/Block : %d", wfxex.Samples.wSamplesPerBlock);
879 CLog::Log(LOGDEBUG, " Format cBSize : %d", wfxex.Format.cbSize);
880 CLog::Log(LOGDEBUG, " Channel Layout : %s", ((std::string)format.m_channelLayout).c_str());
881 CLog::Log(LOGDEBUG, " Channel Mask : %d", wfxex.dwChannelMask);
883 if (wfxex.SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)
884 CLog::Log(LOGDEBUG, " SubFormat : KSDATAFORMAT_SUBTYPE_IEEE_FLOAT");
885 else if (wfxex.SubFormat == KSDATAFORMAT_SUBTYPE_PCM)
886 CLog::Log(LOGDEBUG, " SubFormat : KSDATAFORMAT_SUBTYPE_PCM");
887 else if (wfxex.SubFormat == KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL)
888 CLog::Log(LOGDEBUG, " SubFormat : KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL");
889 else if (wfxex.SubFormat == KSDATAFORMAT_SUBTYPE_IEC61937_DTS)
890 CLog::Log(LOGDEBUG, " SubFormat : KSDATAFORMAT_SUBTYPE_IEC61937_DTS");
891 else if (wfxex.SubFormat == KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL_PLUS)
892 CLog::Log(LOGDEBUG, " SubFormat : KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL_PLUS");
893 else if (wfxex.SubFormat == KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_MLP)
894 CLog::Log(LOGDEBUG, " SubFormat : KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_MLP");
895 else if (wfxex.SubFormat == KSDATAFORMAT_SUBTYPE_IEC61937_DTS_HD)
896 CLog::Log(LOGDEBUG, " SubFormat : KSDATAFORMAT_SUBTYPE_IEC61937_DTS_HD");
898 CLog::Log(LOGDEBUG, " SubFormat : NO SUBFORMAT SPECIFIED");
900 HRESULT hr = m_pAudioClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
904 CLog::Log(LOGDEBUG, __FUNCTION__": Format is Supported - will attempt to Initialize");
907 else if (hr != AUDCLNT_E_UNSUPPORTED_FORMAT) //It failed for a reason unrelated to an unsupported format.
909 CLog::Log(LOGERROR, __FUNCTION__": IsFormatSupported failed (%s)", WASAPIErrToStr(hr));
912 else if (AE_IS_RAW(format.m_dataFormat)) //No sense in trying other formats for passthrough.
915 CLog::Log(LOGERROR, __FUNCTION__": IsFormatSupported failed (%s) - trying to find a compatible format", WASAPIErrToStr(hr));
919 //The requested format is not supported by the device. Find something that works.
921 for (int j = 0; j < sizeof(testFormats)/sizeof(sampleFormat); j++)
925 wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
926 wfxex.SubFormat = testFormats[j].subFormat;
927 wfxex.Format.wBitsPerSample = testFormats[j].bitsPerSample;
928 wfxex.Samples.wValidBitsPerSample = testFormats[j].validBitsPerSample;
929 wfxex.Format.nBlockAlign = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
931 for (int i = 0 ; i < WASAPISampleRateCount; i++)
933 wfxex.Format.nSamplesPerSec = WASAPISampleRates[i];
934 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
936 /* Uncomment to trace format match iteration loop via log */
937 CLog::Log(LOGDEBUG, "WASAPI: Trying Sample Format : %s", CAEUtil::DataFormatToStr(testFormats[j].subFormatType));
938 CLog::Log(LOGDEBUG, "WASAPI: Trying Sample Rate : %d", wfxex.Format.nSamplesPerSec);
939 CLog::Log(LOGDEBUG, "WASAPI: Trying Bits/Sample : %d", wfxex.Format.wBitsPerSample);
940 CLog::Log(LOGDEBUG, "WASAPI: Trying Valid Bits/Sample: %d", wfxex.Samples.wValidBitsPerSample);
942 hr = m_pAudioClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
946 //If the current sample rate matches the source then stop looking and use it.
947 if ((WASAPISampleRates[i] == format.m_sampleRate) && (testFormats[j].subFormatType <= format.m_dataFormat))
949 //If this rate is closer to the source then the previous one, save it.
950 else if (closestMatch < 0 || abs((int)WASAPISampleRates[i] - (int)format.m_sampleRate) < abs((int)WASAPISampleRates[closestMatch] - (int)format.m_sampleRate))
953 else if (hr != AUDCLNT_E_UNSUPPORTED_FORMAT)
954 CLog::Log(LOGERROR, __FUNCTION__": IsFormatSupported failed (%s)", WASAPIErrToStr(hr));
957 if (closestMatch >= 0)
959 wfxex.Format.nSamplesPerSec = WASAPISampleRates[closestMatch];
960 wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
965 CLog::Log(LOGERROR, __FUNCTION__": Unable to locate a supported output format for the device. Check the speaker settings in the control panel.");
967 //We couldn't find anything supported. This should never happen unless the user set the wrong
968 //speaker setting in the control panel.
973 AEChannelsFromSpeakerMask(wfxex.dwChannelMask);
975 //When the stream is raw, the values in the format structure are set to the link
976 //parameters, so store the encoded stream values here for the IsCompatible function.
977 m_encodedFormat = format.m_dataFormat;
978 m_encodedChannels = wfxex.Format.nChannels;
979 m_encodedSampleRate = format.m_encodedRate;// bool(format.m_dataFormat == AE_FMT_TRUEHD || format.m_dataFormat == AE_FMT_DTSHD) ? 96000L : 48000L;
980 wfxex_iec61937.dwEncodedChannelCount = wfxex.Format.nChannels;
981 wfxex_iec61937.dwEncodedSamplesPerSec = m_encodedSampleRate;
983 if (!AE_IS_RAW(format.m_dataFormat))
985 if (wfxex.Format.wBitsPerSample == 32)
987 if (wfxex.SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)
988 format.m_dataFormat = AE_FMT_FLOAT;
989 else if (wfxex.Samples.wValidBitsPerSample == 32)
990 format.m_dataFormat = AE_FMT_S32NE;
992 format.m_dataFormat = AE_FMT_S24NE4;
996 format.m_dataFormat = AE_FMT_S16NE;
1000 format.m_sampleRate = wfxex.Format.nSamplesPerSec; //PCM: Sample rate. RAW: Link speed
1002 format.m_frameSize = (wfxex.Format.wBitsPerSample >> 3) * wfxex.Format.nChannels;
1004 REFERENCE_TIME audioSinkBufferDurationMsec, hnsLatency;
1006 /* Get m_audioSinkBufferSizeMsec from advancedsettings.xml */
1007 audioSinkBufferDurationMsec = (REFERENCE_TIME)g_advancedSettings.m_audioSinkBufferDurationMsec * 10000;
1009 //use user's advancedsetting value for buffer size as long as it's over minimum set above
1010 audioSinkBufferDurationMsec = (REFERENCE_TIME)std::max(audioSinkBufferDurationMsec, (REFERENCE_TIME)500000);
1011 audioSinkBufferDurationMsec = (REFERENCE_TIME)((audioSinkBufferDurationMsec / format.m_frameSize) * format.m_frameSize); //even number of frames
1013 CLog::Log(LOGDEBUG, __FUNCTION__": Initializing WASAPI exclusive mode with the following parameters:");
1014 CLog::Log(LOGDEBUG, " Sample Rate : %d", wfxex.Format.nSamplesPerSec);
1015 CLog::Log(LOGDEBUG, " Sample Format : %s", CAEUtil::DataFormatToStr(format.m_dataFormat));
1016 CLog::Log(LOGDEBUG, " Bits Per Sample : %d", wfxex.Format.wBitsPerSample);
1017 CLog::Log(LOGDEBUG, " Valid Bits/Samp : %d", wfxex.Samples.wValidBitsPerSample);
1018 CLog::Log(LOGDEBUG, " Channel Count : %d", wfxex.Format.nChannels);
1019 CLog::Log(LOGDEBUG, " Block Align : %d", wfxex.Format.nBlockAlign);
1020 CLog::Log(LOGDEBUG, " Avg. Bytes Sec : %d", wfxex.Format.nAvgBytesPerSec);
1021 CLog::Log(LOGDEBUG, " Samples/Block : %d", wfxex.Samples.wSamplesPerBlock);
1022 CLog::Log(LOGDEBUG, " Format cBSize : %d", wfxex.Format.cbSize);
1023 CLog::Log(LOGDEBUG, " Channel Layout : %s", ((std::string)format.m_channelLayout).c_str());
1024 CLog::Log(LOGDEBUG, " Enc. Channels : %d", wfxex_iec61937.dwEncodedChannelCount);
1025 CLog::Log(LOGDEBUG, " Enc. Samples/Sec: %d", wfxex_iec61937.dwEncodedSamplesPerSec);
1026 CLog::Log(LOGDEBUG, " Channel Mask : %d", wfxex.dwChannelMask);
1027 CLog::Log(LOGDEBUG, " Periodicty : %d", audioSinkBufferDurationMsec);
1029 if (wfxex.SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)
1030 CLog::Log(LOGDEBUG, " SubFormat : KSDATAFORMAT_SUBTYPE_IEEE_FLOAT");
1031 else if (wfxex.SubFormat == KSDATAFORMAT_SUBTYPE_PCM)
1032 CLog::Log(LOGDEBUG, " SubFormat : KSDATAFORMAT_SUBTYPE_PCM");
1033 else if (wfxex.SubFormat == KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL)
1034 CLog::Log(LOGDEBUG, " SubFormat : KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL");
1035 else if (wfxex.SubFormat == KSDATAFORMAT_SUBTYPE_IEC61937_DTS)
1036 CLog::Log(LOGDEBUG, " SubFormat : KSDATAFORMAT_SUBTYPE_IEC61937_DTS");
1037 else if (wfxex.SubFormat == KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL_PLUS)
1038 CLog::Log(LOGDEBUG, " SubFormat : KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL_PLUS");
1039 else if (wfxex.SubFormat == KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_MLP)
1040 CLog::Log(LOGDEBUG, " SubFormat : KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_MLP");
1041 else if (wfxex.SubFormat == KSDATAFORMAT_SUBTYPE_IEC61937_DTS_HD)
1042 CLog::Log(LOGDEBUG, " SubFormat : KSDATAFORMAT_SUBTYPE_IEC61937_DTS_HD");
1044 CLog::Log(LOGDEBUG, " SubFormat : NO SUBFORMAT SPECIFIED");
1046 if (AE_IS_RAW(format.m_dataFormat))
1047 format.m_dataFormat = AE_FMT_S16NE;
1049 hr = m_pAudioClient->Initialize(AUDCLNT_SHAREMODE_EXCLUSIVE, AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_NOPERSIST,
1050 audioSinkBufferDurationMsec, audioSinkBufferDurationMsec, &wfxex.Format, NULL);
1052 if (hr == AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED)
1054 CLog::Log(LOGDEBUG, __FUNCTION__": Re-aligning WASAPI sink buffer due to %s.", WASAPIErrToStr(hr));
1055 // Get the next aligned frame.
1056 hr = m_pAudioClient->GetBufferSize(&m_uiBufferLen);
1059 CLog::Log(LOGERROR, __FUNCTION__": GetBufferSize Failed : %s", WASAPIErrToStr(hr));
1063 audioSinkBufferDurationMsec = (REFERENCE_TIME) ((10000.0 * 1000 / wfxex.Format.nSamplesPerSec * m_uiBufferLen) + 0.5);
1064 CLog::Log(LOGDEBUG, __FUNCTION__": Number of Frames in Buffer : %d", m_uiBufferLen);
1065 CLog::Log(LOGDEBUG, __FUNCTION__": Requested Duration of Buffer : %d", audioSinkBufferDurationMsec);
1067 // Release the previous allocations.
1068 SAFE_RELEASE(m_pAudioClient);
1070 // Create a new audio client.
1071 hr = m_pDevice->Activate(IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&m_pAudioClient);
1074 CLog::Log(LOGERROR, __FUNCTION__": Device Activation Failed : %s", WASAPIErrToStr(hr));
1078 // Open the stream and associate it with an audio session.
1079 hr = m_pAudioClient->Initialize(AUDCLNT_SHAREMODE_EXCLUSIVE, AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_NOPERSIST,
1080 audioSinkBufferDurationMsec, audioSinkBufferDurationMsec, &wfxex.Format, NULL);
1084 CLog::Log(LOGERROR, __FUNCTION__": Unable to initialize WASAPI in exclusive mode %d - (%s).", HRESULT(hr), WASAPIErrToStr(hr));
1087 hr = m_pAudioClient->GetStreamLatency(&hnsLatency);
1088 CLog::Log(LOGDEBUG, __FUNCTION__": Requested Duration of Buffer : %fmsec", hnsLatency / 10000.0);
1089 CLog::Log(LOGNOTICE, __FUNCTION__": WASAPI Exclusive Mode Sink Initialized Successfully!!!");
1093 void CAESinkWASAPI::AEChannelsFromSpeakerMask(DWORD speakers)
1095 m_channelLayout.Reset();
1097 for (int i = 0; i < WASAPI_SPEAKER_COUNT; i++)
1099 if (speakers & WASAPIChannelOrder[i])
1100 m_channelLayout += AEChannelNames[i];
1104 DWORD CAESinkWASAPI::SpeakerMaskFromAEChannels(const CAEChannelInfo &channels)
1108 for (unsigned int i = 0; i < channels.Count(); i++)
1110 for (unsigned int j = 0; j < WASAPI_SPEAKER_COUNT; j++)
1111 if (channels[i] == AEChannelNames[j])
1112 mask |= WASAPIChannelOrder[j];
1117 const char *CAESinkWASAPI::WASAPIErrToStr(HRESULT err)
1121 ERRTOSTR(AUDCLNT_E_NOT_INITIALIZED);
1122 ERRTOSTR(AUDCLNT_E_ALREADY_INITIALIZED);
1123 ERRTOSTR(AUDCLNT_E_WRONG_ENDPOINT_TYPE);
1124 ERRTOSTR(AUDCLNT_E_DEVICE_INVALIDATED);
1125 ERRTOSTR(AUDCLNT_E_NOT_STOPPED);
1126 ERRTOSTR(AUDCLNT_E_BUFFER_TOO_LARGE);
1127 ERRTOSTR(AUDCLNT_E_OUT_OF_ORDER);
1128 ERRTOSTR(AUDCLNT_E_UNSUPPORTED_FORMAT);
1129 ERRTOSTR(AUDCLNT_E_INVALID_SIZE);
1130 ERRTOSTR(AUDCLNT_E_DEVICE_IN_USE);
1131 ERRTOSTR(AUDCLNT_E_BUFFER_OPERATION_PENDING);
1132 ERRTOSTR(AUDCLNT_E_THREAD_NOT_REGISTERED);
1133 ERRTOSTR(AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED);
1134 ERRTOSTR(AUDCLNT_E_ENDPOINT_CREATE_FAILED);
1135 ERRTOSTR(AUDCLNT_E_SERVICE_NOT_RUNNING);
1136 ERRTOSTR(AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED);
1137 ERRTOSTR(AUDCLNT_E_EXCLUSIVE_MODE_ONLY);
1138 ERRTOSTR(AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL);
1139 ERRTOSTR(AUDCLNT_E_EVENTHANDLE_NOT_SET);
1140 ERRTOSTR(AUDCLNT_E_INCORRECT_BUFFER_SIZE);
1141 ERRTOSTR(AUDCLNT_E_BUFFER_SIZE_ERROR);
1142 ERRTOSTR(AUDCLNT_E_CPUUSAGE_EXCEEDED);
1143 ERRTOSTR(AUDCLNT_E_BUFFER_ERROR);
1144 ERRTOSTR(AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED);
1145 ERRTOSTR(AUDCLNT_E_INVALID_DEVICE_PERIOD);
1146 ERRTOSTR(E_POINTER);
1147 ERRTOSTR(E_INVALIDARG);
1148 ERRTOSTR(E_OUTOFMEMORY);