From 66989a4690f21fa140c9b1ec7ef09e17a76405ef Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sun, 7 May 2023 14:34:34 -0500 Subject: [PATCH] Set the default back to the virtual sink if it's changed Fixes #976 --- src/platform/windows/audio.cpp | 79 ++++++++++++++++++++++++---------- 1 file changed, 56 insertions(+), 23 deletions(-) diff --git a/src/platform/windows/audio.cpp b/src/platform/windows/audio.cpp index 80a76af9..aa27c246 100644 --- a/src/platform/windows/audio.cpp +++ b/src/platform/windows/audio.cpp @@ -483,6 +483,11 @@ namespace platf::audio { // Check if the default audio device has changed if (endpt_notification.check_default_render_device_changed()) { + // Invoke the audio_control_t's callback if it wants one + if (default_endpt_changed_cb) { + (*default_endpt_changed_cb)(); + } + // Reinitialize to pick up the new default device return capture_e::reinit; } @@ -555,6 +560,8 @@ namespace platf::audio { audio_capture_t audio_capture; audio_notification_t endpt_notification; + std::optional> default_endpt_changed_cb; + REFERENCE_TIME default_latency_ms; util::buffer_t sample_buf; @@ -667,6 +674,34 @@ namespace platf::audio { return sink; } + /** + * @brief Gets information encoded in the raw sink name + * + * @param sink The raw sink name + * + * @return A pair of type and the real sink name + */ + std::pair + get_sink_info(const std::string &sink) { + std::string_view sv { sink.c_str(), sink.size() }; + + // sink format: + // [virtual-(format name)]device_id + auto prefix = "virtual-"sv; + if (sv.find(prefix) == 0) { + sv = sv.substr(prefix.size(), sv.size() - prefix.size()); + + for (auto &format : formats) { + auto &name = format.name; + if (sv.find(name) == 0) { + return std::make_pair(format.type, sv.substr(name.size(), sv.size() - name.size())); + } + } + } + + return std::make_pair(format_t::none, sv); + } + std::unique_ptr microphone(const std::uint8_t *mapping, int channels, std::uint32_t sample_rate, std::uint32_t frame_size) override { auto mic = std::make_unique(); @@ -675,6 +710,15 @@ namespace platf::audio { return nullptr; } + // If this is a virtual sink, set a callback that will change the sink back if it's changed + auto sink_info = get_sink_info(assigned_sink); + if (sink_info.first != format_t::none) { + mic->default_endpt_changed_cb = [this] { + BOOST_LOG(info) << "Resetting sink to ["sv << assigned_sink << "] after default changed"; + set_sink(assigned_sink); + }; + } + return mic; } @@ -688,30 +732,12 @@ namespace platf::audio { */ std::optional set_format(const std::string &sink) { - std::string_view sv { sink.c_str(), sink.size() }; - - format_t::type_e type = format_t::none; - // sink format: - // [virtual-(format name)]device_id - auto prefix = "virtual-"sv; - if (sv.find(prefix) == 0) { - sv = sv.substr(prefix.size(), sv.size() - prefix.size()); - - for (auto &format : formats) { - auto &name = format.name; - if (sv.find(name) == 0) { - type = format.type; - sv = sv.substr(name.size(), sv.size() - name.size()); - - break; - } - } - } + auto sink_info = get_sink_info(sink); // If the sink isn't a device name, we'll assume it's a device ID - auto wstring_device_id = find_device_id_by_name(sink).value_or(converter.from_bytes(sv.data())); + auto wstring_device_id = find_device_id_by_name(sink).value_or(converter.from_bytes(sink_info.second.data())); - if (type == format_t::none) { + if (sink_info.first == format_t::none) { // wstring_device_id does not contain virtual-(format name) // It's a simple deviceId, just pass it back return std::make_optional(std::move(wstring_device_id)); @@ -725,14 +751,14 @@ namespace platf::audio { return std::nullopt; } - set_wave_format(wave_format, formats[(int) type - 1]); + set_wave_format(wave_format, formats[(int) sink_info.first - 1]); WAVEFORMATEXTENSIBLE p {}; status = policy->SetDeviceFormat(wstring_device_id.c_str(), wave_format.get(), (WAVEFORMATEX *) &p); // Surround 5.1 might contain side-{left, right} instead of speaker in the back // Try again with different speaker mask. - if (status == 0x88890008 && type == format_t::surr51) { + if (status == 0x88890008 && sink_info.first == format_t::surr51) { set_wave_format(wave_format, surround_51_side_speakers); status = policy->SetDeviceFormat(wstring_device_id.c_str(), wave_format.get(), (WAVEFORMATEX *) &p); } @@ -768,6 +794,12 @@ namespace platf::audio { } } + // Remember the assigned sink name, so we have it for later if we need to set it + // back after another application changes it + if (!failure) { + assigned_sink = sink; + } + return failure; } @@ -867,6 +899,7 @@ namespace platf::audio { ~audio_control_t() override {} policy_t policy; + std::string assigned_sink; }; } // namespace platf::audio