Reinitialize capture if the default audio device changes

We already reinitialized if the default device was removed, but we didn't in the case a new default device was set without removing the old one.
This commit is contained in:
Cameron Gutman
2023-05-07 14:31:45 -05:00
parent ccdc882c13
commit bc392093a3

View File

@@ -262,6 +262,78 @@ namespace platf::audio {
return device;
}
class audio_notification_t: public ::IMMNotificationClient {
public:
audio_notification_t() {}
// IUnknown implementation (unused by IMMDeviceEnumerator)
ULONG STDMETHODCALLTYPE
AddRef() {
return 1;
}
ULONG STDMETHODCALLTYPE
Release() {
return 1;
}
HRESULT STDMETHODCALLTYPE
QueryInterface(REFIID riid, VOID **ppvInterface) {
if (IID_IUnknown == riid) {
AddRef();
*ppvInterface = (IUnknown *) this;
return S_OK;
}
else if (__uuidof(IMMNotificationClient) == riid) {
AddRef();
*ppvInterface = (IMMNotificationClient *) this;
return S_OK;
}
else {
*ppvInterface = NULL;
return E_NOINTERFACE;
}
}
// IMMNotificationClient
HRESULT STDMETHODCALLTYPE
OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR pwstrDeviceId) {
if (flow == eRender) {
default_render_device_changed_flag.store(true);
}
return S_OK;
}
HRESULT STDMETHODCALLTYPE
OnDeviceAdded(LPCWSTR pwstrDeviceId) { return S_OK; }
HRESULT STDMETHODCALLTYPE
OnDeviceRemoved(LPCWSTR pwstrDeviceId) { return S_OK; }
HRESULT STDMETHODCALLTYPE
OnDeviceStateChanged(
LPCWSTR pwstrDeviceId,
DWORD dwNewState) { return S_OK; }
HRESULT STDMETHODCALLTYPE
OnPropertyValueChanged(
LPCWSTR pwstrDeviceId,
const PROPERTYKEY key) { return S_OK; }
/**
* @brief Checks if the default rendering device changed and resets the change flag
*
* @return true if the device changed since last call
*/
bool
check_default_render_device_changed() {
return default_render_device_changed_flag.exchange(false);
}
private:
std::atomic_bool default_render_device_changed_flag;
};
class mic_wasapi_t: public mic_t {
public:
capture_e
@@ -310,6 +382,13 @@ namespace platf::audio {
return -1;
}
status = device_enum->RegisterEndpointNotificationCallback(&endpt_notification);
if (FAILED(status)) {
BOOST_LOG(error) << "Couldn't register endpoint notification [0x"sv << util::hex(status).to_string_view() << ']';
return -1;
}
auto device = default_device(device_enum);
if (!device) {
return -1;
@@ -377,6 +456,10 @@ namespace platf::audio {
}
~mic_wasapi_t() override {
if (device_enum) {
device_enum->UnregisterEndpointNotificationCallback(&endpt_notification);
}
if (audio_client) {
audio_client->Stop();
}
@@ -398,6 +481,12 @@ namespace platf::audio {
std::uint32_t audio_sample_size;
} block_aligned;
// Check if the default audio device has changed
if (endpt_notification.check_default_render_device_changed()) {
// Reinitialize to pick up the new default device
return capture_e::reinit;
}
status = WaitForSingleObjectEx(audio_event.get(), default_latency_ms, FALSE);
switch (status) {
case WAIT_OBJECT_0:
@@ -465,6 +554,7 @@ namespace platf::audio {
audio_client_t audio_client;
audio_capture_t audio_capture;
audio_notification_t endpt_notification;
REFERENCE_TIME default_latency_ms;
util::buffer_t<std::int16_t> sample_buf;