29 audio_system_win32() : super(), _notification_client(std::make_unique<audio_system_win32_notification_client>(
this))
31 hi_hresult_check(CoInitializeEx(NULL, COINIT_MULTITHREADED));
33 hi_hresult_check(CoCreateInstance(
34 __uuidof(MMDeviceEnumerator),
37 __uuidof(IMMDeviceEnumerator),
38 reinterpret_cast<LPVOID *
>(&_device_enumerator)));
39 hi_assert(_device_enumerator);
41 _device_enumerator->RegisterEndpointNotificationCallback(_notification_client.
get());
49 if (_device_enumerator) {
50 _device_enumerator->UnregisterEndpointNotificationCallback(_notification_client.
get());
51 _device_enumerator->Release();
55 [[nodiscard]] generator<audio_device&>
devices() noexcept
override
57 for (
auto const& device : _devices) {
63 class audio_system_win32_notification_client :
public IMMNotificationClient {
65 virtual ~audio_system_win32_notification_client() =
default;
67 audio_system_win32_notification_client(
audio_system_win32 *system) : IMMNotificationClient(), _system(system) {}
69 STDMETHOD(OnDefaultDeviceChanged)(EDataFlow flow, ERole role, LPCWSTR device_id)
override
71 loop::main().wfree_post_function([
this]() {
72 _system->update_device_list();
78 STDMETHOD(OnDeviceAdded)(LPCWSTR device_id)
override
80 loop::main().wfree_post_function([
this]() {
81 _system->update_device_list();
87 STDMETHOD(OnDeviceRemoved)(LPCWSTR device_id)
override
96 hi_assert_not_null(device_id);
97 loop::main().wfree_post_function([
this]() {
98 _system->update_device_list();
104 STDMETHOD(OnDeviceStateChanged)(LPCWSTR device_id, DWORD state)
override
106 loop::main().wfree_post_function([
this]() {
107 _system->update_device_list();
108 _system->_notifier();
113 STDMETHOD(OnPropertyValueChanged)(LPCWSTR device_id, PROPERTYKEY
const key)
override
115 loop::main().wfree_post_function([
this]() {
116 _system->update_device_list();
117 _system->_notifier();
122 STDMETHOD(QueryInterface)(REFIID iid,
void **object)
override
127 STDMETHOD_(ULONG, AddRef)()
override
132 STDMETHOD_(ULONG, Release)()
override
138 audio_system_win32 *_system;
152 IMMDeviceEnumerator *_device_enumerator;
157 void update_device_list() noexcept
159 hi_axiom(loop::main().on_thread());
160 hi_log_info(
"Updating audio device list:");
162 IMMDeviceCollection *device_collection;
163 if (FAILED(_device_enumerator->EnumAudioEndpoints(
164 eAll, DEVICE_STATE_ACTIVE | DEVICE_STATE_DISABLED | DEVICE_STATE_UNPLUGGED, &device_collection))) {
168 hi_assert(device_collection);
170 UINT number_of_devices;
171 if (FAILED(device_collection->GetCount(&number_of_devices))) {
173 device_collection->Release();
177 auto old_devices = _devices;
179 for (UINT i = 0; i < number_of_devices; i++) {
180 IMMDevice *win32_device;
181 if (FAILED(device_collection->Item(i, &win32_device))) {
183 device_collection->Release();
186 hi_assert(win32_device);
192 hi_log_error(
"EnumAudioEndpoints()->Item({})->get_device_id failed: {}", i, e.
what());
193 device_collection->Release();
194 win32_device->Release();
198 auto it =
std::find_if(old_devices.begin(), old_devices.end(), [&win32_device_id](
auto& item) {
199 return item->id() == win32_device_id;
202 if (it != old_devices.end()) {
204 win32_device->Release();
206 old_devices.erase(it);
209 _devices.
back()->update_state();
213 std::allocate_shared<audio_device_win32>(locked_memory_allocator<audio_device_win32>{}, win32_device);
224 device_collection->Release();
227 friend class audio_system_win32_notification_client;