[XAudio2] share Xbox audio device enumeration with desktop and Windows 8.1 compatibility
[xbmc.git] / xbmc / cores / AudioEngine / Sinks / windows / AESinkFactoryWinRT.cpp
blobd69c64f69ae8e0ac5c592f78040aa2974447df30
1 /*
2 * Copyright (C) 2024 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
9 #include "AESinkFactoryWin.h"
10 #include "utils/log.h"
12 #include "platform/win10/AsyncHelpers.h"
13 #include "platform/win32/CharsetConverter.h"
15 #include <winrt/windows.devices.enumeration.h>
16 #include <winrt/windows.foundation.collections.h>
17 #include <winrt/windows.foundation.h>
18 #include <winrt/windows.media.devices.core.h>
19 #include <winrt/windows.media.devices.h>
21 namespace winrt
23 using namespace Windows::Foundation;
26 using namespace winrt::Windows::Devices::Enumeration;
27 using namespace winrt::Windows::Media::Devices;
28 using namespace winrt::Windows::Media::Devices::Core;
30 // clang-format off
31 static winrt::hstring PKEY_Device_FriendlyName = L"System.ItemNameDisplay";
32 static winrt::hstring PKEY_AudioEndpoint_FormFactor = L"{1da5d803-d492-4edd-8c23-e0c0ffee7f0e} 0";
33 static winrt::hstring PKEY_AudioEndpoint_ControlPanelPageProvider = L"{1da5d803-d492-4edd-8c23-e0c0ffee7f0e} 1";
34 static winrt::hstring PKEY_AudioEndpoint_Association = L"{1da5d803-d492-4edd-8c23-e0c0ffee7f0e} 2";
35 static winrt::hstring PKEY_AudioEndpoint_PhysicalSpeakers = L"{1da5d803-d492-4edd-8c23-e0c0ffee7f0e} 3";
36 static winrt::hstring PKEY_AudioEndpoint_GUID = L"{1da5d803-d492-4edd-8c23-e0c0ffee7f0e} 4";
37 static winrt::hstring PKEY_AudioEndpoint_Disable_SysFx = L"{1da5d803-d492-4edd-8c23-e0c0ffee7f0e} 5";
38 static winrt::hstring PKEY_AudioEndpoint_FullRangeSpeakers = L"{1da5d803-d492-4edd-8c23-e0c0ffee7f0e} 6";
39 static winrt::hstring PKEY_AudioEndpoint_Supports_EventDriven_Mode = L"{1da5d803-d492-4edd-8c23-e0c0ffee7f0e} 7";
40 static winrt::hstring PKEY_AudioEndpoint_JackSubType = L"{1da5d803-d492-4edd-8c23-e0c0ffee7f0e} 8";
41 static winrt::hstring PKEY_AudioEndpoint_Default_VolumeInDb = L"{1da5d803-d492-4edd-8c23-e0c0ffee7f0e} 9";
42 static winrt::hstring PKEY_AudioEngine_DeviceFormat = L"{f19f064d-082c-4e27-bc73-6882a1bb8e4c} 0";
43 static winrt::hstring PKEY_Device_EnumeratorName = L"{a45c254e-df1c-4efd-8020-67d146a850e0} 24";
44 // clang-format on
46 std::vector<RendererDetail> CAESinkFactoryWin::GetRendererDetailsWinRT()
48 std::vector<RendererDetail> list;
49 try
51 // Get the string identifier of the audio renderer
52 auto defaultId = MediaDevice::GetDefaultAudioRenderId(AudioDeviceRole::Default);
53 auto audioSelector = MediaDevice::GetAudioRenderSelector();
55 // Add custom properties to the query
56 DeviceInformationCollection devInfoCollection = Wait(DeviceInformation::FindAllAsync(
57 audioSelector, {PKEY_AudioEndpoint_FormFactor, PKEY_AudioEndpoint_GUID,
58 PKEY_AudioEndpoint_PhysicalSpeakers, PKEY_AudioEngine_DeviceFormat,
59 PKEY_Device_EnumeratorName}));
61 if (devInfoCollection == nullptr || devInfoCollection.Size() == 0)
62 goto failed;
64 for (const DeviceInformation& devInfo : devInfoCollection)
66 RendererDetail details;
68 if (devInfo.Properties().Size() == 0)
69 goto failed;
71 winrt::IInspectable propObj = nullptr;
73 propObj = devInfo.Properties().Lookup(PKEY_AudioEndpoint_FormFactor);
74 if (!propObj)
75 goto failed;
77 const uint32_t indexFF{propObj.as<winrt::IPropertyValue>().GetUInt32()};
78 details.strWinDevType = winEndpoints[indexFF].winEndpointType;
79 details.eDeviceType = winEndpoints[indexFF].aeDeviceType;
81 DWORD ulChannelMask = 0;
82 unsigned int nChannels = 0;
84 propObj = devInfo.Properties().Lookup(PKEY_AudioEngine_DeviceFormat);
85 if (propObj)
87 winrt::com_array<uint8_t> com_arr;
88 propObj.as<winrt::IPropertyValue>().GetUInt8Array(com_arr);
90 WAVEFORMATEXTENSIBLE* smpwfxex = (WAVEFORMATEXTENSIBLE*)com_arr.data();
91 nChannels = std::max(std::min(smpwfxex->Format.nChannels, (WORD)8), (WORD)2);
92 ulChannelMask = smpwfxex->dwChannelMask;
94 else
96 // suppose stereo
97 nChannels = 2;
98 ulChannelMask = 3;
101 propObj = devInfo.Properties().Lookup(PKEY_AudioEndpoint_PhysicalSpeakers);
103 details.uiChannelMask = propObj ? propObj.as<winrt::IPropertyValue>().GetUInt32()
104 : static_cast<unsigned int>(ulChannelMask);
106 details.nChannels = nChannels;
108 details.strDescription = KODI::PLATFORM::WINDOWS::FromW(devInfo.Name().c_str());
109 details.strDeviceId = KODI::PLATFORM::WINDOWS::FromW(devInfo.Id().c_str());
111 details.bDefault = (devInfo.Id() == defaultId);
113 list.push_back(details);
115 return list;
117 catch (...)
121 failed:
122 CLog::LogF(LOGERROR, "Failed to enumerate audio renderer devices.");
123 return list;