aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--xbmc/cores/AudioEngine/CMakeLists.txt3
-rw-r--r--xbmc/cores/AudioEngine/Sinks/AESinkXAudio.cpp146
-rw-r--r--xbmc/cores/AudioEngine/Sinks/AESinkXAudio.h4
-rw-r--r--xbmc/cores/AudioEngine/Sinks/windows/AESinkFactoryWin.h7
-rw-r--r--xbmc/cores/AudioEngine/Sinks/windows/AESinkFactoryWin10.cpp98
-rw-r--r--xbmc/cores/AudioEngine/Sinks/windows/AESinkFactoryWin32.cpp1
-rw-r--r--xbmc/cores/AudioEngine/Sinks/windows/AESinkFactoryWinRT.cpp124
-rw-r--r--xbmc/platform/win10/AsyncHelpers.h4
8 files changed, 252 insertions, 135 deletions
diff --git a/xbmc/cores/AudioEngine/CMakeLists.txt b/xbmc/cores/AudioEngine/CMakeLists.txt
index 4a2531753e..d3a5acc973 100644
--- a/xbmc/cores/AudioEngine/CMakeLists.txt
+++ b/xbmc/cores/AudioEngine/CMakeLists.txt
@@ -106,7 +106,8 @@ endif()
if(CORE_SYSTEM_NAME MATCHES windows)
list(APPEND SOURCES Sinks/AESinkWASAPI.cpp
Sinks/AESinkXAudio.cpp
- Sinks/windows/AESinkFactoryWin.cpp)
+ Sinks/windows/AESinkFactoryWin.cpp
+ Sinks/windows/AESinkFactoryWinRT.cpp)
list(APPEND HEADERS Sinks/AESinkWASAPI.h
Sinks/AESinkXAudio.h
Sinks/windows/AESinkFactoryWin.h)
diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkXAudio.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkXAudio.cpp
index 1c6e3a2f36..792c8ffc6a 100644
--- a/xbmc/cores/AudioEngine/Sinks/AESinkXAudio.cpp
+++ b/xbmc/cores/AudioEngine/Sinks/AESinkXAudio.cpp
@@ -13,27 +13,62 @@
#include "cores/AudioEngine/Sinks/windows/AESinkFactoryWin.h"
#include "cores/AudioEngine/Utils/AEDeviceInfo.h"
#include "cores/AudioEngine/Utils/AEUtil.h"
+#include "utils/SystemInfo.h"
#include "utils/log.h"
-#ifdef TARGET_WINDOWS_STORE
-#include "platform/win10/AsyncHelpers.h"
-#endif
#include "platform/win32/CharsetConverter.h"
#include <algorithm>
#include <stdint.h>
#include <ksmedia.h>
-#include <mfapi.h>
-#include <mmdeviceapi.h>
-#include <mmreg.h>
-#include <wrl/implements.h>
using namespace Microsoft::WRL;
namespace
{
constexpr int XAUDIO_BUFFERS_IN_QUEUE = 2;
+
+HRESULT KXAudio2Create(IXAudio2** ppXAudio2,
+ UINT32 Flags X2DEFAULT(0),
+ XAUDIO2_PROCESSOR XAudio2Processor X2DEFAULT(XAUDIO2_DEFAULT_PROCESSOR))
+{
+ typedef HRESULT(__stdcall * XAudio2CreateInfoFunc)(_Outptr_ IXAudio2**, UINT32,
+ XAUDIO2_PROCESSOR);
+ static HMODULE dll = NULL;
+ static XAudio2CreateInfoFunc XAudio2CreateFn = nullptr;
+
+ if (dll == NULL)
+ {
+ dll = LoadLibraryEx(L"xaudio2_9redist.dll", NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
+
+ if (dll == NULL)
+ {
+ dll = LoadLibraryEx(L"xaudio2_9.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
+
+ if (dll == NULL)
+ {
+ // Windows 8 compatibility
+ dll = LoadLibraryEx(L"xaudio2_8.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
+
+ if (dll == NULL)
+ return HRESULT_FROM_WIN32(GetLastError());
+ }
+ }
+
+ XAudio2CreateFn = (XAudio2CreateInfoFunc)(void*)GetProcAddress(dll, "XAudio2Create");
+ if (!XAudio2CreateFn)
+ {
+ return HRESULT_FROM_WIN32(GetLastError());
+ }
+ }
+
+ if (XAudio2CreateFn)
+ return (*XAudio2CreateFn)(ppXAudio2, Flags, XAudio2Processor);
+ else
+ return E_FAIL;
+}
+
} // namespace
extern const char* WASAPIErrToStr(HRESULT err);
@@ -50,10 +85,10 @@ inline void SafeDestroyVoice(TVoice **ppVoice)
CAESinkXAudio::CAESinkXAudio()
{
- HRESULT hr = XAudio2Create(m_xAudio2.ReleaseAndGetAddressOf(), 0);
+ HRESULT hr = KXAudio2Create(m_xAudio2.ReleaseAndGetAddressOf(), 0);
if (FAILED(hr))
{
- CLog::LogF(LOGERROR, "XAudio initialization failed.");
+ CLog::LogF(LOGERROR, "XAudio initialization failed, error {:X}.", hr);
}
#ifdef _DEBUG
else
@@ -89,6 +124,13 @@ void CAESinkXAudio::Register()
std::unique_ptr<IAESink> CAESinkXAudio::Create(std::string& device, AEAudioFormat& desiredFormat)
{
auto sink = std::make_unique<CAESinkXAudio>();
+
+ if (!sink->m_xAudio2)
+ {
+ CLog::LogF(LOGERROR, "XAudio2 not loaded.");
+ return {};
+ }
+
if (sink->Initialize(desiredFormat, device))
return sink;
@@ -283,7 +325,13 @@ void CAESinkXAudio::EnumerateDevicesEx(AEDeviceInfoList &deviceInfoList, bool fo
IXAudio2SourceVoice* mSourceVoice = nullptr;
Microsoft::WRL::ComPtr<IXAudio2> xaudio2;
- hr = XAudio2Create(xaudio2.ReleaseAndGetAddressOf(), eflags);
+ // ForegroundOnlyMedia/BackgroundCapableMedia replaced in Windows 10 by Movie/Media
+ const AUDIO_STREAM_CATEGORY streamCategory{
+ CSysInfo::IsWindowsVersionAtLeast(CSysInfo::WindowsVersionWin10)
+ ? AudioCategory_Media
+ : AudioCategory_ForegroundOnlyMedia};
+
+ hr = KXAudio2Create(xaudio2.ReleaseAndGetAddressOf(), eflags);
if (FAILED(hr))
{
CLog::LogF(LOGERROR, "failed to activate XAudio for capability testing ({})",
@@ -291,7 +339,7 @@ void CAESinkXAudio::EnumerateDevicesEx(AEDeviceInfoList &deviceInfoList, bool fo
return;
}
- for(RendererDetail& details : CAESinkFactoryWin::GetRendererDetails())
+ for (RendererDetail& details : CAESinkFactoryWin::GetRendererDetailsWinRT())
{
deviceInfo.m_channels.Reset();
deviceInfo.m_dataFormats.clear();
@@ -304,7 +352,7 @@ void CAESinkXAudio::EnumerateDevicesEx(AEDeviceInfoList &deviceInfoList, bool fo
deviceChannels += AEChannelNames[c];
}
- const std::wstring deviceId = KODI::PLATFORM::WINDOWS::ToW(details.strDevicePath);
+ const std::wstring deviceId = KODI::PLATFORM::WINDOWS::ToW(details.strDeviceId);
/* Test format for PCM format iteration */
wfxex.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
@@ -314,9 +362,15 @@ void CAESinkXAudio::EnumerateDevicesEx(AEDeviceInfoList &deviceInfoList, bool fo
wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
- xaudio2->CreateMasteringVoice(&mMasterVoice, wfxex.Format.nChannels,
- wfxex.Format.nSamplesPerSec, 0, deviceId.c_str(), nullptr,
- AudioCategory_Media);
+ hr = xaudio2->CreateMasteringVoice(&mMasterVoice, wfxex.Format.nChannels,
+ wfxex.Format.nSamplesPerSec, 0, deviceId.c_str(), nullptr,
+ streamCategory);
+
+ if (FAILED(hr))
+ {
+ CLog::LogF(LOGERROR, "failed to create mastering voice (:X)", hr);
+ return;
+ }
for (int p = AE_FMT_FLOAT; p > AE_FMT_INVALID; p--)
{
@@ -359,25 +413,31 @@ void CAESinkXAudio::EnumerateDevicesEx(AEDeviceInfoList &deviceInfoList, bool fo
for (int j = 0; j < WASAPISampleRateCount; j++)
{
+ if (WASAPISampleRates[j] < XAUDIO2_MIN_SAMPLE_RATE ||
+ WASAPISampleRates[j] > XAUDIO2_MAX_SAMPLE_RATE)
+ continue;
+
SafeDestroyVoice(&mSourceVoice);
SafeDestroyVoice(&mMasterVoice);
wfxex.Format.nSamplesPerSec = WASAPISampleRates[j];
wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
- xaudio2->CreateMasteringVoice(&mMasterVoice, wfxex.Format.nChannels,
- wfxex.Format.nSamplesPerSec, 0, deviceId.c_str(), nullptr,
- AudioCategory_Media);
- hr = xaudio2->CreateSourceVoice(&mSourceVoice, &wfxex.Format);
+ if (SUCCEEDED(xaudio2->CreateMasteringVoice(&mMasterVoice, wfxex.Format.nChannels,
+ wfxex.Format.nSamplesPerSec, 0, deviceId.c_str(),
+ nullptr, streamCategory)))
+ {
+ hr = xaudio2->CreateSourceVoice(&mSourceVoice, &wfxex.Format);
- if (SUCCEEDED(hr))
- deviceInfo.m_sampleRates.push_back(WASAPISampleRates[j]);
+ if (SUCCEEDED(hr))
+ deviceInfo.m_sampleRates.push_back(WASAPISampleRates[j]);
+ }
}
SafeDestroyVoice(&mSourceVoice);
SafeDestroyVoice(&mMasterVoice);
- deviceInfo.m_deviceName = details.strDevicePath;
+ deviceInfo.m_deviceName = details.strDeviceId;
deviceInfo.m_displayName = details.strWinDevType.append(details.strDescription);
deviceInfo.m_displayNameExtra = std::string("XAudio: ").append(details.strDescription);
deviceInfo.m_deviceType = details.eDeviceType;
@@ -442,11 +502,18 @@ bool CAESinkXAudio::InitializeInternal(std::string deviceId, AEAudioFormat &form
HRESULT hr;
IXAudio2MasteringVoice* pMasterVoice = nullptr;
+ const wchar_t* pDevice = device.c_str();
+ // ForegroundOnlyMedia/BackgroundCapableMedia replaced in Windows 10 by Movie/Media
+ const AUDIO_STREAM_CATEGORY streamCategory{
+ CSysInfo::IsWindowsVersionAtLeast(CSysInfo::WindowsVersionWin10)
+ ? AudioCategory_Media
+ : AudioCategory_ForegroundOnlyMedia};
if (!bdefault)
{
- hr = m_xAudio2->CreateMasteringVoice(&pMasterVoice, wfxex.Format.nChannels, wfxex.Format.nSamplesPerSec,
- 0, device.c_str(), nullptr, AudioCategory_Media);
+ hr = m_xAudio2->CreateMasteringVoice(&pMasterVoice, wfxex.Format.nChannels,
+ wfxex.Format.nSamplesPerSec, 0, pDevice, nullptr,
+ streamCategory);
}
if (!pMasterVoice)
@@ -458,11 +525,12 @@ bool CAESinkXAudio::InitializeInternal(std::string deviceId, AEAudioFormat &form
"Trying the default device...",
KODI::PLATFORM::WINDOWS::FromW(device));
}
-
// smartphone issue: providing device ID (even default ID) causes E_NOINTERFACE result
// workaround: device = nullptr will initialize default audio endpoint
- hr = m_xAudio2->CreateMasteringVoice(&pMasterVoice, wfxex.Format.nChannels, wfxex.Format.nSamplesPerSec,
- 0, 0, nullptr, AudioCategory_Media);
+ pDevice = nullptr;
+ hr = m_xAudio2->CreateMasteringVoice(&pMasterVoice, wfxex.Format.nChannels,
+ wfxex.Format.nSamplesPerSec, 0, pDevice, nullptr,
+ streamCategory);
if (FAILED(hr) || !pMasterVoice)
{
CLog::LogF(LOGINFO, "Could not retrieve the default XAudio audio endpoint ({}).",
@@ -525,11 +593,19 @@ bool CAESinkXAudio::InitializeInternal(std::string deviceId, AEAudioFormat &form
for (int i = 0 ; i < WASAPISampleRateCount; i++)
{
+ if (WASAPISampleRates[j] < XAUDIO2_MIN_SAMPLE_RATE ||
+ WASAPISampleRates[j] > XAUDIO2_MAX_SAMPLE_RATE)
+ continue;
+
+ SafeDestroyVoice(&m_sourceVoice);
+ SafeDestroyVoice(&m_masterVoice);
+
wfxex.Format.nSamplesPerSec = WASAPISampleRates[i];
wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
- hr = m_xAudio2->CreateMasteringVoice(&m_masterVoice, wfxex.Format.nChannels, wfxex.Format.nSamplesPerSec,
- 0, device.c_str(), nullptr, AudioCategory_Media);
+ hr = m_xAudio2->CreateMasteringVoice(&m_masterVoice, wfxex.Format.nChannels,
+ wfxex.Format.nSamplesPerSec, 0, pDevice, nullptr,
+ streamCategory);
if (SUCCEEDED(hr))
{
hr = m_xAudio2->CreateSourceVoice(&m_sourceVoice, &wfxex.Format, 0, XAUDIO2_DEFAULT_FREQ_RATIO, &m_voiceCallback);
@@ -550,9 +626,19 @@ bool CAESinkXAudio::InitializeInternal(std::string deviceId, AEAudioFormat &form
if (closestMatch >= 0)
{
+ // Closest match may be different from the last successful sample rate tested
+ SafeDestroyVoice(&m_sourceVoice);
+ SafeDestroyVoice(&m_masterVoice);
+
wfxex.Format.nSamplesPerSec = WASAPISampleRates[closestMatch];
wfxex.Format.nAvgBytesPerSec = wfxex.Format.nSamplesPerSec * wfxex.Format.nBlockAlign;
- goto initialize;
+
+ if (SUCCEEDED(m_xAudio2->CreateMasteringVoice(&m_masterVoice, wfxex.Format.nChannels,
+ wfxex.Format.nSamplesPerSec, 0, pDevice,
+ nullptr, streamCategory)) &&
+ SUCCEEDED(m_xAudio2->CreateSourceVoice(&m_sourceVoice, &wfxex.Format, 0,
+ XAUDIO2_DEFAULT_FREQ_RATIO, &m_voiceCallback)))
+ goto initialize;
}
}
}
diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkXAudio.h b/xbmc/cores/AudioEngine/Sinks/AESinkXAudio.h
index f398ca9b0e..1335714d09 100644
--- a/xbmc/cores/AudioEngine/Sinks/AESinkXAudio.h
+++ b/xbmc/cores/AudioEngine/Sinks/AESinkXAudio.h
@@ -13,14 +13,10 @@
#include <stdint.h>
-#include <mmdeviceapi.h>
-#include <ppltasks.h>
-#include <wrl/implements.h>
#include <x3daudio.h>
#include <xapofx.h>
#include <xaudio2.h>
#include <xaudio2fx.h>
-#pragma comment(lib,"xaudio2.lib")
class CAESinkXAudio : public IAESink
{
diff --git a/xbmc/cores/AudioEngine/Sinks/windows/AESinkFactoryWin.h b/xbmc/cores/AudioEngine/Sinks/windows/AESinkFactoryWin.h
index d308673b91..68a8bd4a5c 100644
--- a/xbmc/cores/AudioEngine/Sinks/windows/AESinkFactoryWin.h
+++ b/xbmc/cores/AudioEngine/Sinks/windows/AESinkFactoryWin.h
@@ -175,7 +175,6 @@ static const sampleFormat testFormats[] = { {KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 32
struct RendererDetail
{
- std::string strDevicePath;
std::string strDeviceId;
std::string strDescription;
std::string strWinDevType;
@@ -198,10 +197,14 @@ class CAESinkFactoryWin
{
public:
/*
- Gets list of audio renderers available on platform
+ Gets list of available audio renderers - using MMDevice
*/
static std::vector<RendererDetail> GetRendererDetails();
/*
+ Gets list of available audio renderers - using WinRT
+ */
+ static std::vector<RendererDetail> GetRendererDetailsWinRT();
+ /*
Gets default device id
*/
static std::string GetDefaultDeviceId();
diff --git a/xbmc/cores/AudioEngine/Sinks/windows/AESinkFactoryWin10.cpp b/xbmc/cores/AudioEngine/Sinks/windows/AESinkFactoryWin10.cpp
index 2492f02279..ea3eccf56f 100644
--- a/xbmc/cores/AudioEngine/Sinks/windows/AESinkFactoryWin10.cpp
+++ b/xbmc/cores/AudioEngine/Sinks/windows/AESinkFactoryWin10.cpp
@@ -6,117 +6,21 @@
* See LICENSES/README.md for more information.
*/
#include "AESinkFactoryWin.h"
-#include "utils/log.h"
-#include "platform/win10/AsyncHelpers.h"
#include "platform/win32/CharsetConverter.h"
#include <mmdeviceapi.h>
#include <mmreg.h>
#include <winrt/Windows.Devices.Enumeration.h>
-#include <winrt/Windows.Media.Devices.Core.h>
#include <winrt/Windows.Media.Devices.h>
using namespace winrt::Windows::Devices::Enumeration;
using namespace winrt::Windows::Media::Devices;
-using namespace winrt::Windows::Media::Devices::Core;
using namespace Microsoft::WRL;
-static winrt::hstring PKEY_Device_FriendlyName = L"System.ItemNameDisplay";
-static winrt::hstring PKEY_AudioEndpoint_FormFactor = L"{1da5d803-d492-4edd-8c23-e0c0ffee7f0e} 0";
-static winrt::hstring PKEY_AudioEndpoint_ControlPanelPageProvider = L"{1da5d803-d492-4edd-8c23-e0c0ffee7f0e} 1";
-static winrt::hstring PKEY_AudioEndpoint_Association = L"{1da5d803-d492-4edd-8c23-e0c0ffee7f0e} 2";
-static winrt::hstring PKEY_AudioEndpoint_PhysicalSpeakers = L"{1da5d803-d492-4edd-8c23-e0c0ffee7f0e} 3";
-static winrt::hstring PKEY_AudioEndpoint_GUID = L"{1da5d803-d492-4edd-8c23-e0c0ffee7f0e} 4";
-static winrt::hstring PKEY_AudioEndpoint_Disable_SysFx = L"{1da5d803-d492-4edd-8c23-e0c0ffee7f0e} 5";
-static winrt::hstring PKEY_AudioEndpoint_FullRangeSpeakers = L"{1da5d803-d492-4edd-8c23-e0c0ffee7f0e} 6";
-static winrt::hstring PKEY_AudioEndpoint_Supports_EventDriven_Mode = L"{1da5d803-d492-4edd-8c23-e0c0ffee7f0e} 7";
-static winrt::hstring PKEY_AudioEndpoint_JackSubType = L"{1da5d803-d492-4edd-8c23-e0c0ffee7f0e} 8";
-static winrt::hstring PKEY_AudioEndpoint_Default_VolumeInDb = L"{1da5d803-d492-4edd-8c23-e0c0ffee7f0e} 9";
-static winrt::hstring PKEY_AudioEngine_DeviceFormat = L"{f19f064d-082c-4e27-bc73-6882a1bb8e4c} 0";
-static winrt::hstring PKEY_Device_EnumeratorName = L"{a45c254e-df1c-4efd-8020-67d146a850e0} 24";
-
std::vector<RendererDetail> CAESinkFactoryWin::GetRendererDetails()
{
- std::vector<RendererDetail> list;
- try
- {
- // Get the string identifier of the audio renderer
- auto defaultId = MediaDevice::GetDefaultAudioRenderId(AudioDeviceRole::Default);
- auto audioSelector = MediaDevice::GetAudioRenderSelector();
-
- // Add custom properties to the query
- DeviceInformationCollection devInfocollection = Wait(DeviceInformation::FindAllAsync(audioSelector,
- {
- PKEY_AudioEndpoint_FormFactor,
- PKEY_AudioEndpoint_GUID,
- PKEY_AudioEndpoint_PhysicalSpeakers,
- PKEY_AudioEngine_DeviceFormat,
- PKEY_Device_EnumeratorName
- }));
- if (devInfocollection == nullptr || devInfocollection.Size() == 0)
- goto failed;
-
- for (unsigned int i = 0; i < devInfocollection.Size(); i++)
- {
- RendererDetail details;
-
- DeviceInformation devInfo = devInfocollection.GetAt(i);
- if (devInfo.Properties().Size() == 0)
- goto failed;
-
- winrt::IInspectable propObj = nullptr;
-
- propObj = devInfo.Properties().Lookup(PKEY_AudioEndpoint_FormFactor);
- if (!propObj)
- goto failed;
-
- details.strWinDevType = winEndpoints[propObj.as<winrt::IPropertyValue>().GetUInt32()].winEndpointType;
- details.eDeviceType = winEndpoints[propObj.as<winrt::IPropertyValue>().GetUInt32()].aeDeviceType;
-
- unsigned long ulChannelMask = 0;
- unsigned int nChannels = 0;
-
- propObj = devInfo.Properties().Lookup(PKEY_AudioEngine_DeviceFormat);
- if (propObj)
- {
- winrt::com_array<uint8_t> com_arr;
- propObj.as<winrt::IPropertyValue>().GetUInt8Array(com_arr);
-
- WAVEFORMATEXTENSIBLE* smpwfxex = (WAVEFORMATEXTENSIBLE*)com_arr.data();
- nChannels = std::max(std::min(smpwfxex->Format.nChannels, (WORD)8), (WORD)2);
- ulChannelMask = smpwfxex->dwChannelMask;
- }
- else
- {
- // suppose stereo
- nChannels = 2;
- ulChannelMask = 3;
- }
-
- propObj = devInfo.Properties().Lookup(PKEY_AudioEndpoint_PhysicalSpeakers);
- details.uiChannelMask = propObj ? propObj.as<winrt::IPropertyValue>().GetUInt32() : ulChannelMask;
- details.nChannels = nChannels;
-
- details.strDescription = KODI::PLATFORM::WINDOWS::FromW(devInfo.Name().c_str());
- details.strDeviceId = KODI::PLATFORM::WINDOWS::FromW(devInfo.Id().c_str());
-
- // on Windows UWP device Id is same as Path
- details.strDevicePath = details.strDeviceId;
-
- details.bDefault = (devInfo.Id() == defaultId);
-
- list.push_back(details);
- }
- return list;
- }
- catch (...)
- {
- }
-
-failed:
- CLog::Log(LOGERROR, __FUNCTION__": Failed to enumerate audio renderer devices.");
- return list;
+ return GetRendererDetailsWinRT();
}
class CAudioInterfaceActivator : public winrt::implements<CAudioInterfaceActivator, IActivateAudioInterfaceCompletionHandler>
diff --git a/xbmc/cores/AudioEngine/Sinks/windows/AESinkFactoryWin32.cpp b/xbmc/cores/AudioEngine/Sinks/windows/AESinkFactoryWin32.cpp
index e7d81282ae..d5869c5e2e 100644
--- a/xbmc/cores/AudioEngine/Sinks/windows/AESinkFactoryWin32.cpp
+++ b/xbmc/cores/AudioEngine/Sinks/windows/AESinkFactoryWin32.cpp
@@ -147,7 +147,6 @@ std::vector<RendererDetail> CAESinkFactoryWin::GetRendererDetails()
if (wstrDDID.compare(pwszID) == 0)
details.bDefault = true;
- details.strDevicePath = KODI::PLATFORM::WINDOWS::FromW(pwszID);
CoTaskMemFree(pwszID);
}
diff --git a/xbmc/cores/AudioEngine/Sinks/windows/AESinkFactoryWinRT.cpp b/xbmc/cores/AudioEngine/Sinks/windows/AESinkFactoryWinRT.cpp
new file mode 100644
index 0000000000..d69c64f69a
--- /dev/null
+++ b/xbmc/cores/AudioEngine/Sinks/windows/AESinkFactoryWinRT.cpp
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2024 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "AESinkFactoryWin.h"
+#include "utils/log.h"
+
+#include "platform/win10/AsyncHelpers.h"
+#include "platform/win32/CharsetConverter.h"
+
+#include <winrt/windows.devices.enumeration.h>
+#include <winrt/windows.foundation.collections.h>
+#include <winrt/windows.foundation.h>
+#include <winrt/windows.media.devices.core.h>
+#include <winrt/windows.media.devices.h>
+
+namespace winrt
+{
+using namespace Windows::Foundation;
+}
+
+using namespace winrt::Windows::Devices::Enumeration;
+using namespace winrt::Windows::Media::Devices;
+using namespace winrt::Windows::Media::Devices::Core;
+
+// clang-format off
+static winrt::hstring PKEY_Device_FriendlyName = L"System.ItemNameDisplay";
+static winrt::hstring PKEY_AudioEndpoint_FormFactor = L"{1da5d803-d492-4edd-8c23-e0c0ffee7f0e} 0";
+static winrt::hstring PKEY_AudioEndpoint_ControlPanelPageProvider = L"{1da5d803-d492-4edd-8c23-e0c0ffee7f0e} 1";
+static winrt::hstring PKEY_AudioEndpoint_Association = L"{1da5d803-d492-4edd-8c23-e0c0ffee7f0e} 2";
+static winrt::hstring PKEY_AudioEndpoint_PhysicalSpeakers = L"{1da5d803-d492-4edd-8c23-e0c0ffee7f0e} 3";
+static winrt::hstring PKEY_AudioEndpoint_GUID = L"{1da5d803-d492-4edd-8c23-e0c0ffee7f0e} 4";
+static winrt::hstring PKEY_AudioEndpoint_Disable_SysFx = L"{1da5d803-d492-4edd-8c23-e0c0ffee7f0e} 5";
+static winrt::hstring PKEY_AudioEndpoint_FullRangeSpeakers = L"{1da5d803-d492-4edd-8c23-e0c0ffee7f0e} 6";
+static winrt::hstring PKEY_AudioEndpoint_Supports_EventDriven_Mode = L"{1da5d803-d492-4edd-8c23-e0c0ffee7f0e} 7";
+static winrt::hstring PKEY_AudioEndpoint_JackSubType = L"{1da5d803-d492-4edd-8c23-e0c0ffee7f0e} 8";
+static winrt::hstring PKEY_AudioEndpoint_Default_VolumeInDb = L"{1da5d803-d492-4edd-8c23-e0c0ffee7f0e} 9";
+static winrt::hstring PKEY_AudioEngine_DeviceFormat = L"{f19f064d-082c-4e27-bc73-6882a1bb8e4c} 0";
+static winrt::hstring PKEY_Device_EnumeratorName = L"{a45c254e-df1c-4efd-8020-67d146a850e0} 24";
+// clang-format on
+
+std::vector<RendererDetail> CAESinkFactoryWin::GetRendererDetailsWinRT()
+{
+ std::vector<RendererDetail> list;
+ try
+ {
+ // Get the string identifier of the audio renderer
+ auto defaultId = MediaDevice::GetDefaultAudioRenderId(AudioDeviceRole::Default);
+ auto audioSelector = MediaDevice::GetAudioRenderSelector();
+
+ // Add custom properties to the query
+ DeviceInformationCollection devInfoCollection = Wait(DeviceInformation::FindAllAsync(
+ audioSelector, {PKEY_AudioEndpoint_FormFactor, PKEY_AudioEndpoint_GUID,
+ PKEY_AudioEndpoint_PhysicalSpeakers, PKEY_AudioEngine_DeviceFormat,
+ PKEY_Device_EnumeratorName}));
+
+ if (devInfoCollection == nullptr || devInfoCollection.Size() == 0)
+ goto failed;
+
+ for (const DeviceInformation& devInfo : devInfoCollection)
+ {
+ RendererDetail details;
+
+ if (devInfo.Properties().Size() == 0)
+ goto failed;
+
+ winrt::IInspectable propObj = nullptr;
+
+ propObj = devInfo.Properties().Lookup(PKEY_AudioEndpoint_FormFactor);
+ if (!propObj)
+ goto failed;
+
+ const uint32_t indexFF{propObj.as<winrt::IPropertyValue>().GetUInt32()};
+ details.strWinDevType = winEndpoints[indexFF].winEndpointType;
+ details.eDeviceType = winEndpoints[indexFF].aeDeviceType;
+
+ DWORD ulChannelMask = 0;
+ unsigned int nChannels = 0;
+
+ propObj = devInfo.Properties().Lookup(PKEY_AudioEngine_DeviceFormat);
+ if (propObj)
+ {
+ winrt::com_array<uint8_t> com_arr;
+ propObj.as<winrt::IPropertyValue>().GetUInt8Array(com_arr);
+
+ WAVEFORMATEXTENSIBLE* smpwfxex = (WAVEFORMATEXTENSIBLE*)com_arr.data();
+ nChannels = std::max(std::min(smpwfxex->Format.nChannels, (WORD)8), (WORD)2);
+ ulChannelMask = smpwfxex->dwChannelMask;
+ }
+ else
+ {
+ // suppose stereo
+ nChannels = 2;
+ ulChannelMask = 3;
+ }
+
+ propObj = devInfo.Properties().Lookup(PKEY_AudioEndpoint_PhysicalSpeakers);
+
+ details.uiChannelMask = propObj ? propObj.as<winrt::IPropertyValue>().GetUInt32()
+ : static_cast<unsigned int>(ulChannelMask);
+
+ details.nChannels = nChannels;
+
+ details.strDescription = KODI::PLATFORM::WINDOWS::FromW(devInfo.Name().c_str());
+ details.strDeviceId = KODI::PLATFORM::WINDOWS::FromW(devInfo.Id().c_str());
+
+ details.bDefault = (devInfo.Id() == defaultId);
+
+ list.push_back(details);
+ }
+ return list;
+ }
+ catch (...)
+ {
+ }
+
+failed:
+ CLog::LogF(LOGERROR, "Failed to enumerate audio renderer devices.");
+ return list;
+}
diff --git a/xbmc/platform/win10/AsyncHelpers.h b/xbmc/platform/win10/AsyncHelpers.h
index dd2a290b9f..7ad9320dd5 100644
--- a/xbmc/platform/win10/AsyncHelpers.h
+++ b/xbmc/platform/win10/AsyncHelpers.h
@@ -12,6 +12,10 @@
#include <ppltasks.h>
#include <sdkddkver.h>
+#ifndef TARGET_WINDOWS_STORE
+#include <winrt/windows.foundation.h>
+#endif
+
namespace winrt
{
using namespace Windows::Foundation;