@@ -117,19 +117,24 @@ namespace {
117117
118118 using virtual_sink_waveformats_t = std::vector<WAVEFORMATEXTENSIBLE>;
119119
120+ // The list of virtual formats are sorted in preference order and the first valid format will be used.
121+ // All bits-per-sample options are listed because we try to match this to the default audio device.
120122 template <WORD channel_count>
121123 virtual_sink_waveformats_t create_virtual_sink_waveformats () {
122124 if constexpr (channel_count == 2 ) {
123125 auto channel_mask = waveformat_mask_stereo;
124- // only choose 24 or 16-bit formats to avoid clobbering existing Dolby/DTS spatial audio settings
126+ // The 32-bit formats are a lower priority for stereo because using one will disable Dolby/DTS
127+ // spatial audio mode if the user enabled it on the Steam speaker.
125128 return {
126129 create_waveformat (sample_format_e::s24in32, channel_count, channel_mask),
127130 create_waveformat (sample_format_e::s24, channel_count, channel_mask),
128131 create_waveformat (sample_format_e::s16, channel_count, channel_mask),
132+ create_waveformat (sample_format_e::f32 , channel_count, channel_mask),
133+ create_waveformat (sample_format_e::s32, channel_count, channel_mask),
129134 };
130135 } else if (channel_count == 6 ) {
131136 auto channel_mask1 = waveformat_mask_surround51_with_backspeakers;
132- auto channel_mask2 = waveformat_mask_surround51_with_sidespeakers;
137+ auto channel_mask2 = waveformat_mask_surround51_with_sidespeakers; // XXX will never be used, but is probably the better 5.1 layout
133138 return {
134139 create_waveformat (sample_format_e::f32 , channel_count, channel_mask1),
135140 create_waveformat (sample_format_e::f32 , channel_count, channel_mask2),
@@ -298,6 +303,10 @@ namespace platf::audio {
298303 auto waveformatext_pointer = reinterpret_cast <const WAVEFORMATEXTENSIBLE *>(mixer_waveformat.get ());
299304 capture_waveformat.dwChannelMask = waveformatext_pointer->dwChannelMask ;
300305 }
306+
307+ BOOST_LOG (info) << " Audio mixer format is " sv << mixer_waveformat->wBitsPerSample << " -bit, " sv
308+ << mixer_waveformat->nSamplesPerSec << " Hz, " sv
309+ << ((mixer_waveformat->nSamplesPerSec != 48000 ) ? " will be resampled to 48000 by Windows" sv : " no resampling needed" sv);
301310 }
302311
303312 status = audio_client->Initialize (
@@ -315,7 +324,7 @@ namespace platf::audio {
315324 return nullptr ;
316325 }
317326
318- BOOST_LOG (info) << " Audio capture format is " << logging::bracket (waveformat_to_pretty_string (capture_waveformat));
327+ BOOST_LOG (info) << " Audio capture format is " sv << logging::bracket (waveformat_to_pretty_string (capture_waveformat));
319328
320329 return audio_client;
321330 }
@@ -793,6 +802,26 @@ namespace platf::audio {
793802 }
794803 }
795804
805+ // When switching to a Steam virtual speaker device, try to retain the bit depth of the
806+ // default audio device. Switching from a 16-bit device to a 24-bit one has been known to
807+ // cause glitches for some users.
808+ int wanted_bits_per_sample = 32 ;
809+ auto current_default_dev = default_device (device_enum);
810+ if (current_default_dev) {
811+ audio::prop_t prop;
812+ prop_var_t current_device_format;
813+
814+ // clang-format off: easier to read this split over 2 lines
815+ if ( SUCCEEDED (current_default_dev->OpenPropertyStore (STGM_READ, &prop))
816+ && SUCCEEDED (prop->GetValue (PKEY_AudioEngine_DeviceFormat, ¤t_device_format.prop )) )
817+ {
818+ auto *format = (WAVEFORMATEXTENSIBLE *)current_device_format.prop .blob .pBlobData ;
819+ wanted_bits_per_sample = format->Samples .wValidBitsPerSample ;
820+ BOOST_LOG (info) << " Virtual audio device will use " sv << wanted_bits_per_sample << " -bit to match default device" sv;
821+ }
822+ // clang-format on
823+ }
824+
796825 auto &device_id = virtual_sink_info->first ;
797826 auto &waveformats = virtual_sink_info->second .get ().virtual_sink_waveformats ;
798827 for (const auto &waveformat : waveformats) {
@@ -802,6 +831,10 @@ namespace platf::audio {
802831 auto waveformat_copy = waveformat;
803832 auto waveformat_copy_pointer = reinterpret_cast <WAVEFORMATEX *>(&waveformat_copy);
804833
834+ if (wanted_bits_per_sample != waveformat.Samples .wValidBitsPerSample ) {
835+ continue ;
836+ }
837+
805838 WAVEFORMATEXTENSIBLE p {};
806839 if (SUCCEEDED (policy->SetDeviceFormat (device_id_copy.c_str (), waveformat_copy_pointer, (WAVEFORMATEX *) &p))) {
807840 BOOST_LOG (info) << " Changed virtual audio sink format to " << logging::bracket (waveformat_to_pretty_string (waveformat));
0 commit comments