Merge pull request #1129 from jmarshallnz/remove_smb_auth_details_in_add_source
[vuplus_xbmc] / xbmc / cores / AudioEngine / Sinks / AESinkWASAPI.cpp
1 /*
2  *      Copyright (C) 2010-2012 Team XBMC
3  *      http://www.xbmc.org
4  *
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)
8  *  any later version.
9  *
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.
14  *
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
19  *
20  */
21
22 #include "AESinkWASAPI.h"
23 #include <Audioclient.h>
24 #include <avrt.h>
25 #include <initguid.h>
26 #include <Mmreg.h>
27 #include <stdint.h>
28
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"
37 #include <Mmreg.h>
38 #include <mmdeviceapi.h>
39
40 #pragma comment(lib, "Avrt.lib")
41
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);
46
47 static const unsigned int WASAPISampleRateCount = 10;
48 static const unsigned int WASAPISampleRates[] = {384000, 192000, 176400, 96000, 88200, 48000, 44100, 32000, 22050, 11025};
49
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};
59
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};
68
69 static enum AEChannel layoutsByChCount[9][9] = {
70     {AE_CH_NULL},
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}};
79
80 struct sampleFormat
81 {
82   GUID subFormat;
83   unsigned int bitsPerSample;
84   unsigned int validBitsPerSample;
85   AEDataFormat subFormatType;
86 };
87
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} };
93
94 struct winEndpointsToAEDeviceType
95 {
96   std::string winEndpointType;
97   AEDeviceType aeDeviceType;
98 };
99
100 static const winEndpointsToAEDeviceType winEndpoints[EndpointFormFactor_enum_count] =
101 {
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},
113 };
114
115 AEDeviceInfoList DeviceInfoList;
116
117 #define EXIT_ON_FAILURE(hr, reason, ...) if(FAILED(hr)) {CLog::Log(LOGERROR, reason " - %s", __VA_ARGS__, WASAPIErrToStr(hr)); goto failed;}
118
119 #define ERRTOSTR(err) case err: return #err
120
121 DEFINE_PROPERTYKEY(PKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 14);
122
123 CAESinkWASAPI::CAESinkWASAPI() :
124   m_pAudioClient(NULL),
125   m_pRenderClient(NULL),
126   m_needDataEvent(0),
127   m_pDevice(NULL),
128   m_initialized(false),
129   m_running(false),
130   m_encodedFormat(AE_FMT_INVALID),
131   m_encodedChannels(0),
132   m_encodedSampleRate(0),
133   m_uiBufferLen(0),
134   m_avgTimeWaiting(50),
135   m_isDirty(false)
136 {
137   m_channelLayout.Reset();
138 }
139
140 CAESinkWASAPI::~CAESinkWASAPI()
141 {
142
143 }
144
145 bool CAESinkWASAPI::Initialize(AEAudioFormat &format, std::string &device)
146 {
147   if (m_initialized)
148     return false;
149
150   CLog::Log(LOGDEBUG, __FUNCTION__": Initializing WASAPI Sink Rev. 1.0.5");
151
152   m_device = device;
153
154   /* Save requested format */
155   /* Clear returned format */
156   sinkReqFormat = format.m_dataFormat;
157   sinkRetFormat = AE_FMT_INVALID;
158
159   IMMDeviceEnumerator* pEnumerator = NULL;
160   IMMDeviceCollection* pEnumDevices = NULL;
161
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)
164
165   //Get our device.
166   //First try to find the named device.
167   UINT uiCount = 0;
168
169   hr = pEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &pEnumDevices);
170   EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of audio endpoint enumeration failed.")
171
172   hr = pEnumDevices->GetCount(&uiCount);
173   EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of audio endpoint count failed.")
174
175   for (UINT i = 0; i < uiCount; i++)
176   {
177     IPropertyStore *pProperty = NULL;
178     PROPVARIANT varName;
179
180     hr = pEnumDevices->Item(i, &m_pDevice);
181     EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of WASAPI endpoint failed.")
182
183     hr = m_pDevice->OpenPropertyStore(STGM_READ, &pProperty);
184     EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of WASAPI endpoint properties failed.")
185
186     hr = pProperty->GetValue(PKEY_AudioEndpoint_GUID, &varName);
187     if (FAILED(hr))
188     {
189       CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint GUID failed.");
190       SAFE_RELEASE(pProperty);
191       goto failed;
192     }
193
194     std::wstring strRawDevName(varName.pwszVal);
195     std::string strDevName = std::string(strRawDevName.begin(), strRawDevName.end());
196     //g_charsetConverter.ucs2CharsetToStringCharset(strRawDevName, strDevName.c_str());
197
198     if (device == strDevName)
199       i = uiCount;
200     else
201       SAFE_RELEASE(m_pDevice);
202
203     PropVariantClear(&varName);
204     SAFE_RELEASE(pProperty);
205   }
206
207   SAFE_RELEASE(pEnumDevices);
208
209   if (!m_pDevice)
210   {
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.")
214
215     IPropertyStore *pProperty = NULL;
216     PROPVARIANT varName;
217
218     hr = m_pDevice->OpenPropertyStore(STGM_READ, &pProperty);
219     EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of WASAPI endpoint properties failed.")
220
221     hr = pProperty->GetValue(PKEY_AudioEndpoint_GUID, &varName);
222
223     std::wstring strRawDevName(varName.pwszVal);
224     std::string strDevName = std::string(strRawDevName.begin(), strRawDevName.end());
225
226     PropVariantClear(&varName);
227     SAFE_RELEASE(pProperty);
228   }
229
230   //We are done with the enumerator.
231   SAFE_RELEASE(pEnumerator);
232
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.")
235
236   if (!InitializeExclusive(format))
237   {
238     CLog::Log(LOGINFO, __FUNCTION__": Could not Initialize Exclusive with that format");
239     goto failed;
240   }
241
242   /* get the buffer size and calculate the frames for AE */
243   m_pAudioClient->GetBufferSize(&m_uiBufferLen);
244
245   format.m_frames       = m_uiBufferLen;
246   format.m_frameSamples = format.m_frames * format.m_channelLayout.Count();
247   m_format              = format;
248   sinkRetFormat         = format.m_dataFormat;
249
250   CLog::Log(LOGDEBUG, __FUNCTION__": Buffer Size     = %d Bytes", m_uiBufferLen * format.m_frameSize);
251
252   hr = m_pAudioClient->GetService(IID_IAudioRenderClient, (void**)&m_pRenderClient);
253   EXIT_ON_FAILURE(hr, __FUNCTION__": Could not initialize the WASAPI render client interface.")
254
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.");
258
259   m_initialized = true;
260   m_isDirty     = false;
261
262   return true;
263
264 failed:
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);
272
273   return false;
274 }
275
276 void CAESinkWASAPI::Deinitialize()
277 {
278   if (!m_initialized)
279     return;
280
281
282   if (m_running)
283     m_pAudioClient->Stop();
284   m_running = false;
285
286
287   SAFE_RELEASE(m_pRenderClient);
288   SAFE_RELEASE(m_pAudioClient);
289   SAFE_RELEASE(m_pDevice);
290   CloseHandle(m_needDataEvent);
291
292   m_initialized = false;
293 }
294
295 bool CAESinkWASAPI::IsCompatible(const AEAudioFormat format, const std::string device)
296 {
297   if (!m_initialized || m_isDirty)
298     return false;
299
300   u_int notCompatible         = 0;
301   const u_int numTests        = 5;
302   std::string strDiffBecause ("");
303   static const char* compatibleParams[numTests] = {":Devices",
304                                                    ":Channels",
305                                                    ":Sample Rates",
306                                                    ":Data Formats",
307                                                    ":Passthrough Formats"};
308
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));
316
317   if (!notCompatible)
318   {
319     CLog::Log(LOGDEBUG, __FUNCTION__": Formats compatible - reusing existing sink");
320     return true;
321   }
322
323   for (int i = 0; i < numTests ; i++)
324   {
325     strDiffBecause += (notCompatible & 0x01) ? (std::string) compatibleParams[i] : "";
326     notCompatible    = notCompatible >> 1;
327   }
328
329   CLog::Log(LOGDEBUG, __FUNCTION__": Formats Incompatible due to different %s", strDiffBecause.c_str());
330   return false;
331 }
332
333 double CAESinkWASAPI::GetDelay()
334 {
335   return GetCacheTime();
336 }
337
338 double CAESinkWASAPI::GetCacheTime()
339 {
340   if (!m_initialized)
341     return 0.0;
342
343   unsigned int numPaddingFrames;
344   HRESULT hr = m_pAudioClient->GetCurrentPadding(&numPaddingFrames);
345   if (FAILED(hr))
346   {
347     CLog::Log(LOGERROR, __FUNCTION__": GetCurrentPadding Failed : %s", WASAPIErrToStr(hr));
348     return 0.0;
349   }
350   return (double)numPaddingFrames / (double)m_format.m_sampleRate;
351 }
352
353 double CAESinkWASAPI::GetCacheTotal()
354 {
355   if (!m_initialized)
356     return 0.0;
357
358   REFERENCE_TIME hnsLatency;
359   HRESULT hr = m_pAudioClient->GetStreamLatency(&hnsLatency);
360
361   /** returns buffer duration in seconds */
362   return hnsLatency / 10.0;
363 }
364
365 unsigned int CAESinkWASAPI::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio)
366 {
367   if (!m_initialized)
368     return 0;
369
370   HRESULT hr;
371   BYTE *buf;
372   DWORD flags = 0;
373
374 #ifndef _DEBUG
375   LARGE_INTEGER timerStart;
376   LARGE_INTEGER timerStop;
377   LARGE_INTEGER timerFreq;
378 #endif
379
380   unsigned int NumFramesRequested = frames;
381
382   if (!m_running) //first time called, pre-fill buffer then start audio client
383   {
384     hr = m_pRenderClient->GetBuffer(NumFramesRequested, &buf);
385     if (FAILED(hr))
386     {
387       #ifdef _DEBUG
388       CLog::Log(LOGERROR, __FUNCTION__": GetBuffer failed due to %s", WASAPIErrToStr(hr));
389       #endif
390       m_isDirty = true; //flag new device or re-init needed
391       return INT_MAX;
392     }
393     memcpy(buf, data, NumFramesRequested * m_format.m_frameSize); //fill buffer
394     hr = m_pRenderClient->ReleaseBuffer(NumFramesRequested, flags); //pass back to audio driver
395     if (FAILED(hr))
396     {
397       #ifdef _DEBUG
398       CLog::Log(LOGDEBUG, __FUNCTION__": ReleaseBuffer failed due to %s.", WASAPIErrToStr(hr));
399       #endif
400       m_isDirty = true; //flag new device or re-init needed
401       return INT_MAX;
402     }
403     hr = m_pAudioClient->Start(); //start the audio driver running
404     if FAILED(hr)
405       CLog::Log(LOGERROR, __FUNCTION__": AudioClient Start Failed");
406     m_running = true; //signal that we're processing frames
407     return NumFramesRequested;
408   }
409
410 #ifndef _DEBUG
411   /* Get clock time for latency checks */
412   QueryPerformanceFrequency(&timerFreq);
413   QueryPerformanceCounter(&timerStart);
414 #endif
415
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)
419   {
420     // Event handle timed out - stop audio device
421     m_pAudioClient->Stop();
422     CLog::Log(LOGERROR, __FUNCTION__": Endpoint Buffer timed out");
423     m_running = false;
424     m_pAudioClient->Stop(); //stop processing - we're done
425     m_isDirty = true; //flag new device or re-init needed
426     return INT_MAX;
427   }
428
429 #ifndef _DEBUG
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;
434
435   if (m_avgTimeWaiting < 3.0)
436   {
437     CLog::Log(LOGDEBUG, __FUNCTION__": Possible AQ Loss: Avg. Time Waiting for Audio Driver callback : %dmsec", (int)m_avgTimeWaiting);
438   }
439 #endif
440
441   hr = m_pRenderClient->GetBuffer(NumFramesRequested, &buf);
442   if (FAILED(hr))
443   {
444     #ifdef _DEBUG
445       CLog::Log(LOGERROR, __FUNCTION__": GetBuffer failed due to %s", WASAPIErrToStr(hr));
446     #endif
447     return 0;
448   }
449   memcpy(buf, data, NumFramesRequested * m_format.m_frameSize); //fill buffer
450   hr = m_pRenderClient->ReleaseBuffer(NumFramesRequested, flags); //pass back to audio driver
451   if (FAILED(hr))
452   {
453     #ifdef _DEBUG
454     CLog::Log(LOGDEBUG, __FUNCTION__": ReleaseBuffer failed due to %s.", WASAPIErrToStr(hr));
455     #endif
456     return 0;
457   }
458
459   return NumFramesRequested;
460 }
461
462 void CAESinkWASAPI::EnumerateDevicesEx(AEDeviceInfoList &deviceInfoList)
463 {
464   IMMDeviceEnumerator* pEnumerator = NULL;
465   IMMDeviceCollection* pEnumDevices = NULL;
466   CAEDeviceInfo        deviceInfo;
467   CAEChannelInfo       deviceChannels;
468
469   WAVEFORMATEXTENSIBLE wfxex = {0};
470   WAVEFORMATEX*        pwfxex = NULL;
471   HRESULT              hr;
472
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)
475
476   UINT uiCount = 0;
477
478   hr = pEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &pEnumDevices);
479   EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of audio endpoint enumeration failed.")
480
481   hr = pEnumDevices->GetCount(&uiCount);
482   EXIT_ON_FAILURE(hr, __FUNCTION__": Retrieval of audio endpoint count failed.")
483
484   for (UINT i = 0; i < uiCount; i++)
485   {
486     IMMDevice *pDevice = NULL;
487     IPropertyStore *pProperty = NULL;
488     PROPVARIANT varName;
489     PropVariantInit(&varName);
490
491     deviceInfo.m_channels.Reset();
492     deviceInfo.m_dataFormats.clear();
493     deviceInfo.m_sampleRates.clear();
494
495     hr = pEnumDevices->Item(i, &pDevice);
496     if (FAILED(hr))
497     {
498       CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint failed.");
499       goto failed;
500     }
501
502     hr = pDevice->OpenPropertyStore(STGM_READ, &pProperty);
503     if (FAILED(hr))
504     {
505       CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint properties failed.");
506       SAFE_RELEASE(pDevice);
507       goto failed;
508     }
509
510     hr = pProperty->GetValue(PKEY_Device_FriendlyName, &varName);
511     if (FAILED(hr))
512     {
513       CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint device name failed.");
514       SAFE_RELEASE(pDevice);
515       SAFE_RELEASE(pProperty);
516       goto failed;
517     }
518
519     std::wstring strRawFriendlyName(varName.pwszVal);
520     std::string strFriendlyName = std::string(strRawFriendlyName.begin(), strRawFriendlyName.end());
521
522     PropVariantClear(&varName);
523
524     hr = pProperty->GetValue(PKEY_AudioEndpoint_GUID, &varName);
525     if(FAILED(hr))
526     {
527       CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint GUID failed.");
528       SAFE_RELEASE(pDevice);
529       SAFE_RELEASE(pProperty);
530       goto failed;
531     }
532
533     std::wstring strRawDevName(varName.pwszVal);
534     std::string strDevName = std::string(strRawDevName.begin(), strRawDevName.end());
535
536     PropVariantClear(&varName);
537
538     hr = pProperty->GetValue(PKEY_AudioEndpoint_FormFactor, &varName);
539     if (FAILED(hr))
540     {
541       CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint form factor failed.");
542       SAFE_RELEASE(pDevice);
543       SAFE_RELEASE(pProperty);
544       goto failed;
545     }
546     std::string strWinDevType = winEndpoints[(EndpointFormFactor)varName.uiVal].winEndpointType;
547     AEDeviceType aeDeviceType = winEndpoints[(EndpointFormFactor)varName.uiVal].aeDeviceType;
548
549     PropVariantClear(&varName);
550
551     hr = pProperty->GetValue(PKEY_AudioEndpoint_PhysicalSpeakers, &varName);
552     if (FAILED(hr))
553     {
554       CLog::Log(LOGERROR, __FUNCTION__": Retrieval of WASAPI endpoint speaker layout failed.");
555       SAFE_RELEASE(pDevice);
556       SAFE_RELEASE(pProperty);
557       goto failed;
558     }
559     unsigned int uiChannelMask = std::max(varName.uintVal, (unsigned int) AE_CH_FL | AE_CH_FR);
560
561     deviceChannels.Reset();
562
563     for (unsigned int c = 0; c < WASAPI_SPEAKER_COUNT; c++)
564     {
565       if (uiChannelMask & WASAPIChannelOrder[c])
566         deviceChannels += AEChannelNames[c];
567     }
568
569     PropVariantClear(&varName);
570
571     IAudioClient *pClient;
572     hr = pDevice->Activate(IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&pClient);
573     if (SUCCEEDED(hr))
574     {
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);
587       if (SUCCEEDED(hr))
588         deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_DTSHD));
589
590       /* Test format Dolby TrueHD */
591       wfxex.SubFormat                   = KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_MLP;
592       hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
593       if (SUCCEEDED(hr))
594         deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_TRUEHD));
595
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);
602       if (SUCCEEDED(hr))
603         deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_EAC3));
604
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);
612       if (SUCCEEDED(hr))
613         deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_DTS));
614
615       /* Test format Dolby AC3 */
616       wfxex.SubFormat                   = KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL;
617       hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
618       if (SUCCEEDED(hr))
619         deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_AC3));
620
621       /* Test format AAC */
622       wfxex.SubFormat                   = KSDATAFORMAT_SUBTYPE_IEC61937_AAC;
623       hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
624       if (SUCCEEDED(hr))
625         deviceInfo.m_dataFormats.push_back(AEDataFormat(AE_FMT_AAC));
626
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;
632
633       for (int p = AE_FMT_FLOAT; p > AE_FMT_INVALID; p--)
634       {
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)
641         {
642           wfxex.Samples.wValidBitsPerSample = 24;
643         }
644         else
645         {
646           wfxex.Samples.wValidBitsPerSample = wfxex.Format.wBitsPerSample;
647         }
648
649         hr = pClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
650         if (SUCCEEDED(hr))
651           deviceInfo.m_dataFormats.push_back((AEDataFormat) p);
652       }
653
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;
664
665       for (int j = 0; j < WASAPISampleRateCount; j++)
666       {
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);
670         if (SUCCEEDED(hr))
671           deviceInfo.m_sampleRates.push_back(WASAPISampleRates[j]);
672       }
673
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;
685
686       //bool mpcmFlagged                  = false;
687
688       for (int k = AE_CH_LAYOUT_MAX; k > 0; k--)
689       {
690         DWORD mask = 0;
691         for (int c = 0; c < WASAPI_SPEAKER_COUNT; c++)
692         {
693           if (uiChannelMask & WASAPIChannelOrder[c])
694             mask |= WASAPIChannelOrder[c];
695         }
696
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);
702         if (SUCCEEDED(hr))
703         {
704           deviceChannels                = layoutsByChCount[k];
705           if (k > AE_CH_LAYOUT_2_1) // && !mpcmFlagged)
706           {
707             deviceInfo.m_dataFormats.push_back(AE_FMT_LPCM);
708             //mpcmFlagged = true;
709           }
710           break;
711         }
712       }
713       pClient->Release();
714     }
715     else
716     {
717       CLog::Log(LOGDEBUG, __FUNCTION__": Failed to activate device for passthrough capability testing.");
718     }
719
720     SAFE_RELEASE(pDevice);
721     SAFE_RELEASE(pProperty);
722
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;
728
729     /* Now logged by AESinkFactory on startup */
730     //CLog::Log(LOGDEBUG,"Audio Device %d:    %s", i, ((std::string)deviceInfo).c_str());
731
732     deviceInfoList.push_back(deviceInfo);
733   }
734   return;
735
736 failed:
737
738   if (FAILED(hr))
739     CLog::Log(LOGERROR, __FUNCTION__": Failed to enumerate WASAPI endpoint devices (%s).", WASAPIErrToStr(hr));
740
741   SAFE_RELEASE(pEnumDevices);
742   SAFE_RELEASE(pEnumerator);
743 }
744
745 //Private utility functions////////////////////////////////////////////////////
746
747 void CAESinkWASAPI::BuildWaveFormatExtensible(AEAudioFormat &format, WAVEFORMATEXTENSIBLE &wfxex)
748 {
749   wfxex.Format.wFormatTag        = WAVE_FORMAT_EXTENSIBLE;
750   wfxex.Format.cbSize            = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
751
752
753   if (!AE_IS_RAW(format.m_dataFormat)) // PCM data
754   {
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;
760   }
761   else //Raw bitstream
762   {
763     wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
764     if (format.m_dataFormat == AE_FMT_AC3 || format.m_dataFormat == AE_FMT_DTS)
765     {
766       wfxex.dwChannelMask          = bool (format.m_channelLayout.Count() == 2) ? KSAUDIO_SPEAKER_STEREO : KSAUDIO_SPEAKER_5POINT1;
767
768       if (format.m_dataFormat == AE_FMT_AC3)
769       {
770         wfxex.SubFormat            = KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL;
771         //wfxex.Format.wFormatTag    = WAVE_FORMAT_DOLBY_AC3_SPDIF;
772       }
773       else
774       {
775         wfxex.SubFormat            = KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL; //KSDATAFORMAT_SUBTYPE_IEC61937_DTS;
776         //wfxex.Format.wFormatTag    = WAVE_FORMAT_DTS;
777       }
778
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;
783     }
784     else if (format.m_dataFormat == AE_FMT_EAC3 || format.m_dataFormat == AE_FMT_TRUEHD || format.m_dataFormat == AE_FMT_DTSHD)
785     {
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;
792
793       switch (format.m_dataFormat)
794       {
795         case AE_FMT_EAC3:
796           wfxex.SubFormat             = KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL_PLUS;
797           wfxex.Format.nChannels      = 2; // One IEC 60958 Line.
798           wfxex.dwChannelMask         = KSAUDIO_SPEAKER_5POINT1;
799           break;
800         case AE_FMT_TRUEHD:
801           wfxex.SubFormat             = KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_MLP;
802           wfxex.Format.nChannels      = 8; // Four IEC 60958 Lines.
803           wfxex.dwChannelMask         = KSAUDIO_SPEAKER_7POINT1_SURROUND;
804           break;
805         case AE_FMT_DTSHD:
806           wfxex.SubFormat             = KSDATAFORMAT_SUBTYPE_IEC61937_DTS_HD;
807           wfxex.Format.nChannels      = 8; // Four IEC 60958 Lines.
808           wfxex.dwChannelMask         = KSAUDIO_SPEAKER_7POINT1_SURROUND;
809           break;
810       }
811
812       if (format.m_channelLayout.Count() == 8)
813         wfxex.dwChannelMask         = KSAUDIO_SPEAKER_7POINT1_SURROUND;
814       else
815         wfxex.dwChannelMask         = KSAUDIO_SPEAKER_5POINT1;
816     }
817   }
818
819   if (wfxex.Format.wBitsPerSample == 32 && wfxex.SubFormat != KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)
820     wfxex.Samples.wValidBitsPerSample = 24;
821   else
822     wfxex.Samples.wValidBitsPerSample = wfxex.Format.wBitsPerSample;
823
824   wfxex.Format.nBlockAlign          = wfxex.Format.nChannels * (wfxex.Format.wBitsPerSample >> 3);
825   wfxex.Format.nAvgBytesPerSec      = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
826 }
827
828 void CAESinkWASAPI::BuildWaveFormatExtensibleIEC61397(AEAudioFormat &format, WAVEFORMATEXTENSIBLE_IEC61937 &wfxex)
829 {
830   //Fill the common structure.
831   BuildWaveFormatExtensible(format, wfxex.FormatExt);
832   /*
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 */
839 }
840
841 bool CAESinkWASAPI::InitializeExclusive(AEAudioFormat &format)
842 {
843   WAVEFORMATEXTENSIBLE_IEC61937 wfxex_iec61937;
844   WAVEFORMATEXTENSIBLE &wfxex = wfxex_iec61937.FormatExt;
845
846   if (format.m_dataFormat <= AE_FMT_FLOAT) //DDDamian was AE_FMT_DTS
847     BuildWaveFormatExtensible(format, wfxex);
848   else
849     BuildWaveFormatExtensibleIEC61397(format, wfxex_iec61937);
850
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)
857   {
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;
868   }
869
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);
882
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");
897   else
898     CLog::Log(LOGDEBUG, "  SubFormat       : NO SUBFORMAT SPECIFIED");
899
900   HRESULT hr = m_pAudioClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
901
902   if (SUCCEEDED(hr))
903   {
904     CLog::Log(LOGDEBUG, __FUNCTION__": Format is Supported - will attempt to Initialize");
905     goto initialize;
906   }
907   else if (hr != AUDCLNT_E_UNSUPPORTED_FORMAT) //It failed for a reason unrelated to an unsupported format.
908   {
909     CLog::Log(LOGERROR, __FUNCTION__": IsFormatSupported failed (%s)", WASAPIErrToStr(hr));
910     return false;
911   }
912   else if (AE_IS_RAW(format.m_dataFormat)) //No sense in trying other formats for passthrough.
913     return false;
914
915   CLog::Log(LOGERROR, __FUNCTION__": IsFormatSupported failed (%s) - trying to find a compatible format", WASAPIErrToStr(hr));
916
917   int closestMatch;
918
919   //The requested format is not supported by the device.  Find something that works.
920   //Try other formats
921   for (int j = 0; j < sizeof(testFormats)/sizeof(sampleFormat); j++)
922   {
923     closestMatch = -1;
924
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);
930
931     for (int i = 0 ; i < WASAPISampleRateCount; i++)
932     {
933       wfxex.Format.nSamplesPerSec    = WASAPISampleRates[i];
934       wfxex.Format.nAvgBytesPerSec   = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
935
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);
941
942       hr = m_pAudioClient->IsFormatSupported(AUDCLNT_SHAREMODE_EXCLUSIVE, &wfxex.Format, NULL);
943
944       if (SUCCEEDED(hr))
945       {
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))
948           goto initialize;
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))
951           closestMatch = i;
952       }
953       else if (hr != AUDCLNT_E_UNSUPPORTED_FORMAT)
954           CLog::Log(LOGERROR, __FUNCTION__": IsFormatSupported failed (%s)", WASAPIErrToStr(hr));
955     }
956
957     if (closestMatch >= 0)
958     {
959       wfxex.Format.nSamplesPerSec    = WASAPISampleRates[closestMatch];
960       wfxex.Format.nAvgBytesPerSec   = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
961       goto initialize;
962     }
963   }
964
965   CLog::Log(LOGERROR, __FUNCTION__": Unable to locate a supported output format for the device.  Check the speaker settings in the control panel.");
966
967   //We couldn't find anything supported.  This should never happen unless the user set the wrong
968   //speaker setting in the control panel.
969   return false;
970
971 initialize:
972
973   AEChannelsFromSpeakerMask(wfxex.dwChannelMask);
974
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;
982
983   if (!AE_IS_RAW(format.m_dataFormat))
984   {
985     if (wfxex.Format.wBitsPerSample == 32)
986     {
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;
991       else
992         format.m_dataFormat = AE_FMT_S24NE4;
993     }
994     else
995     {
996       format.m_dataFormat = AE_FMT_S16NE;
997     }
998   }
999
1000   format.m_sampleRate    = wfxex.Format.nSamplesPerSec; //PCM: Sample rate.  RAW: Link speed
1001
1002   format.m_frameSize     = (wfxex.Format.wBitsPerSample >> 3) * wfxex.Format.nChannels;
1003
1004   REFERENCE_TIME audioSinkBufferDurationMsec, hnsLatency;
1005
1006   /* Get m_audioSinkBufferSizeMsec from advancedsettings.xml */
1007   audioSinkBufferDurationMsec = (REFERENCE_TIME)g_advancedSettings.m_audioSinkBufferDurationMsec * 10000;
1008
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
1012
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);
1028
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");
1043   else
1044     CLog::Log(LOGDEBUG, "  SubFormat       : NO SUBFORMAT SPECIFIED");
1045
1046   if (AE_IS_RAW(format.m_dataFormat))
1047     format.m_dataFormat = AE_FMT_S16NE;
1048
1049   hr = m_pAudioClient->Initialize(AUDCLNT_SHAREMODE_EXCLUSIVE, AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_NOPERSIST,
1050                                     audioSinkBufferDurationMsec, audioSinkBufferDurationMsec, &wfxex.Format, NULL);
1051
1052   if (hr == AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED)
1053   {
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);
1057     if (FAILED(hr))
1058     {
1059       CLog::Log(LOGERROR, __FUNCTION__": GetBufferSize Failed : %s", WASAPIErrToStr(hr));
1060       return false;
1061     }
1062
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);
1066
1067     // Release the previous allocations.
1068     SAFE_RELEASE(m_pAudioClient);
1069
1070     // Create a new audio client.
1071     hr = m_pDevice->Activate(IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&m_pAudioClient);
1072     if (FAILED(hr))
1073     {
1074       CLog::Log(LOGERROR, __FUNCTION__": Device Activation Failed : %s", WASAPIErrToStr(hr));
1075       return false;
1076     }
1077
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);
1081   }
1082   if (FAILED(hr))
1083   {
1084     CLog::Log(LOGERROR, __FUNCTION__": Unable to initialize WASAPI in exclusive mode %d - (%s).", HRESULT(hr), WASAPIErrToStr(hr));
1085     return false;
1086   }
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!!!");
1090   return true;
1091 }
1092
1093 void CAESinkWASAPI::AEChannelsFromSpeakerMask(DWORD speakers)
1094 {
1095   m_channelLayout.Reset();
1096
1097   for (int i = 0; i < WASAPI_SPEAKER_COUNT; i++)
1098   {
1099     if (speakers & WASAPIChannelOrder[i])
1100       m_channelLayout += AEChannelNames[i];
1101   }
1102 }
1103
1104 DWORD CAESinkWASAPI::SpeakerMaskFromAEChannels(const CAEChannelInfo &channels)
1105 {
1106   DWORD mask = 0;
1107
1108   for (unsigned int i = 0; i < channels.Count(); i++)
1109   {
1110     for (unsigned int j = 0; j < WASAPI_SPEAKER_COUNT; j++)
1111       if (channels[i] == AEChannelNames[j])
1112         mask |= WASAPIChannelOrder[j];
1113   }
1114   return mask;
1115 }
1116
1117 const char *CAESinkWASAPI::WASAPIErrToStr(HRESULT err)
1118 {
1119   switch(err)
1120   {
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);
1149     default: break;
1150   }
1151   return NULL;
1152 }