26 using super = audio_system;
28 audio_system_win32() : super(), _notification_client(std::make_unique<audio_system_win32_notification_client>(
this))
30 hi_hresult_check(CoInitializeEx(NULL, COINIT_MULTITHREADED));
32 hi_hresult_check(CoCreateInstance(
33 __uuidof(MMDeviceEnumerator),
36 __uuidof(IMMDeviceEnumerator),
37 reinterpret_cast<LPVOID *
>(&_device_enumerator)));
38 hi_assert(_device_enumerator);
40 _device_enumerator->RegisterEndpointNotificationCallback(_notification_client.
get());
48 if (_device_enumerator) {
49 _device_enumerator->UnregisterEndpointNotificationCallback(_notification_client.
get());
50 _device_enumerator->Release();
54 [[nodiscard]] generator<audio_device&>
devices() noexcept
override
56 for (hilet& device : _devices) {
62 class audio_system_win32_notification_client :
public IMMNotificationClient {
64 virtual ~audio_system_win32_notification_client() =
default;
66 audio_system_win32_notification_client(
audio_system_win32 *system) : IMMNotificationClient(), _system(system) {}
68 STDMETHOD(OnDefaultDeviceChanged)(EDataFlow flow, ERole role, LPCWSTR device_id)
override
70 loop::main().wfree_post_function([
this]() {
71 _system->update_device_list();
77 STDMETHOD(OnDeviceAdded)(LPCWSTR device_id)
override
79 loop::main().wfree_post_function([
this]() {
80 _system->update_device_list();
86 STDMETHOD(OnDeviceRemoved)(LPCWSTR device_id)
override
95 hi_assert_not_null(device_id);
96 loop::main().wfree_post_function([
this]() {
97 _system->update_device_list();
103 STDMETHOD(OnDeviceStateChanged)(LPCWSTR device_id, DWORD state)
override
105 loop::main().wfree_post_function([
this]() {
106 _system->update_device_list();
107 _system->_notifier();
112 STDMETHOD(OnPropertyValueChanged)(LPCWSTR device_id, PROPERTYKEY
const key)
override
114 loop::main().wfree_post_function([
this]() {
115 _system->update_device_list();
116 _system->_notifier();
121 STDMETHOD(QueryInterface)(REFIID iid,
void **object)
override
126 STDMETHOD_(ULONG, AddRef)()
override
131 STDMETHOD_(ULONG, Release)()
override
137 audio_system_win32 *_system;
149 std::vector<std::shared_ptr<audio_device>> _devices;
151 IMMDeviceEnumerator *_device_enumerator;
152 std::unique_ptr<audio_system_win32_notification_client> _notification_client;
156 void update_device_list() noexcept
158 hi_axiom(loop::main().on_thread());
159 hi_log_info(
"Updating audio device list:");
161 IMMDeviceCollection *device_collection;
162 if (FAILED(_device_enumerator->EnumAudioEndpoints(
163 eAll, DEVICE_STATE_ACTIVE | DEVICE_STATE_DISABLED | DEVICE_STATE_UNPLUGGED, &device_collection))) {
167 hi_assert(device_collection);
169 UINT number_of_devices;
170 if (FAILED(device_collection->GetCount(&number_of_devices))) {
172 device_collection->Release();
176 auto old_devices = _devices;
178 for (UINT i = 0; i < number_of_devices; i++) {
179 IMMDevice *win32_device;
180 if (FAILED(device_collection->Item(i, &win32_device))) {
182 device_collection->Release();
185 hi_assert(win32_device);
187 auto win32_device_id = std::string{};
190 }
catch (std::exception
const& e) {
191 hi_log_error(
"EnumAudioEndpoints()->Item({})->get_device_id failed: {}", i, e.
what());
192 device_collection->Release();
193 win32_device->Release();
197 auto it =
std::find_if(old_devices.begin(), old_devices.end(), [&win32_device_id](
auto& item) {
198 return item->id() == win32_device_id;
201 if (it != old_devices.end()) {
203 win32_device->Release();
205 old_devices.erase(it);
208 _devices.back()->update_state();
223 device_collection->Release();
226 friend class audio_system_win32_notification_client;