@@ -117,19 +117,24 @@ namespace {
117
117
118
118
using virtual_sink_waveformats_t = std::vector<WAVEFORMATEXTENSIBLE>;
119
119
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.
120
122
template <WORD channel_count>
121
123
virtual_sink_waveformats_t create_virtual_sink_waveformats () {
122
124
if constexpr (channel_count == 2 ) {
123
125
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.
125
128
return {
126
129
create_waveformat (sample_format_e::s24in32, channel_count, channel_mask),
127
130
create_waveformat (sample_format_e::s24, channel_count, channel_mask),
128
131
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),
129
134
};
130
135
} else if (channel_count == 6 ) {
131
136
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
133
138
return {
134
139
create_waveformat (sample_format_e::f32, channel_count, channel_mask1),
135
140
create_waveformat (sample_format_e::f32, channel_count, channel_mask2),
@@ -298,6 +303,10 @@ namespace platf::audio {
298
303
auto waveformatext_pointer = reinterpret_cast <const WAVEFORMATEXTENSIBLE *>(mixer_waveformat.get ());
299
304
capture_waveformat.dwChannelMask = waveformatext_pointer->dwChannelMask ;
300
305
}
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);
301
310
}
302
311
303
312
status = audio_client->Initialize (
@@ -315,7 +324,7 @@ namespace platf::audio {
315
324
return nullptr ;
316
325
}
317
326
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));
319
328
320
329
return audio_client;
321
330
}
@@ -793,6 +802,26 @@ namespace platf::audio {
793
802
}
794
803
}
795
804
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
+
796
825
auto &device_id = virtual_sink_info->first ;
797
826
auto &waveformats = virtual_sink_info->second .get ().virtual_sink_waveformats ;
798
827
for (const auto &waveformat : waveformats) {
@@ -802,6 +831,10 @@ namespace platf::audio {
802
831
auto waveformat_copy = waveformat;
803
832
auto waveformat_copy_pointer = reinterpret_cast <WAVEFORMATEX *>(&waveformat_copy);
804
833
834
+ if (wanted_bits_per_sample != waveformat.Samples .wValidBitsPerSample ) {
835
+ continue ;
836
+ }
837
+
805
838
WAVEFORMATEXTENSIBLE p {};
806
839
if (SUCCEEDED (policy->SetDeviceFormat (device_id_copy.c_str (), waveformat_copy_pointer, (WAVEFORMATEX *) &p))) {
807
840
BOOST_LOG (info) << " Changed virtual audio sink format to " << logging::bracket (waveformat_to_pretty_string (waveformat));
0 commit comments