From 97625ff9e060d395f75bb2e94e0084c489e37745 Mon Sep 17 00:00:00 2001 From: Vas Crabb Date: Fri, 30 May 2025 04:18:55 +1000 Subject: [PATCH] sound/wasapi_sound.cpp: Repeat the channel mask from the mix format back when initialising the audio client. --- src/osd/modules/sound/mmdevice_helpers.h | 32 ++++++++++++++++++------ src/osd/modules/sound/wasapi_sound.cpp | 22 +++++++++------- src/osd/modules/sound/xaudio2_sound.cpp | 12 ++++----- 3 files changed, 43 insertions(+), 23 deletions(-) diff --git a/src/osd/modules/sound/mmdevice_helpers.h b/src/osd/modules/sound/mmdevice_helpers.h index 17ebe4fd2ce..71aeac54ad7 100644 --- a/src/osd/modules/sound/mmdevice_helpers.h +++ b/src/osd/modules/sound/mmdevice_helpers.h @@ -9,6 +9,7 @@ #include "interface/audio.h" +#include #include #include #include @@ -115,15 +116,30 @@ HRESULT get_string_property_value( REFPROPERTYKEY key, std::optional &value); -inline void populate_wave_format(WAVEFORMATEX &format, DWORD channels, DWORD rate) +inline void populate_wave_format( + WAVEFORMATEXTENSIBLE &format, + DWORD channels, + DWORD rate, + std::optional positions) { - format.wFormatTag = WAVE_FORMAT_PCM; - format.nChannels = channels; - format.nSamplesPerSec = rate; - format.nAvgBytesPerSec = 2 * channels * rate; - format.nBlockAlign = 2 * channels; - format.wBitsPerSample = 16; - format.cbSize = 0; + std::memset(&format, 0, sizeof(format)); + + format.Format.wFormatTag = WAVE_FORMAT_PCM; + format.Format.nChannels = channels; + format.Format.nSamplesPerSec = rate; + format.Format.nAvgBytesPerSec = 2 * channels * rate; + format.Format.nBlockAlign = 2 * channels; + format.Format.wBitsPerSample = 16; + format.Format.cbSize = 0; + + if (positions || (2 < channels)) + { + format.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; + format.Format.cbSize = sizeof(format) - sizeof(format.Format); + format.Samples.wValidBitsPerSample = 16; + format.dwChannelMask = positions ? *positions : 0; + format.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + } } } // namespace osd diff --git a/src/osd/modules/sound/wasapi_sound.cpp b/src/osd/modules/sound/wasapi_sound.cpp index 8fa60bfda34..f5a34a44068 100644 --- a/src/osd/modules/sound/wasapi_sound.cpp +++ b/src/osd/modules/sound/wasapi_sound.cpp @@ -191,7 +191,7 @@ private: device_info_vector_iterator &device, audio_client_ptr &client, co_task_wave_format_ptr &mix_format, - WAVEFORMATEX &format); + WAVEFORMATEXTENSIBLE &format); void cleanup_task(); @@ -749,13 +749,13 @@ uint32_t sound_wasapi::stream_sink_open(uint32_t node, std::string name, uint32_ device_info_vector_iterator device; audio_client_ptr client; co_task_wave_format_ptr mix; - WAVEFORMATEX format; + WAVEFORMATEXTENSIBLE format; if (!activate_audio_client(node, name, rate, false, device, client, mix, format)) return 0; // need sample rate conversion if the sample rates don't match DWORD stream_flags = AUDCLNT_STREAMFLAGS_EVENTCALLBACK; - if (format.nSamplesPerSec != mix->nSamplesPerSec) + if (format.Format.nSamplesPerSec != mix->nSamplesPerSec) stream_flags |= AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY; // initialise the audio client interface @@ -764,7 +764,7 @@ uint32_t sound_wasapi::stream_sink_open(uint32_t node, std::string name, uint32_ stream_flags, lround(m_audio_latency * 1e4F), // 100 ns units 0, - &format, + &format.Format, nullptr); if (FAILED(result)) { @@ -879,7 +879,7 @@ uint32_t sound_wasapi::stream_source_open(uint32_t node, std::string name, uint3 device_info_vector_iterator device; audio_client_ptr client; co_task_wave_format_ptr mix; - WAVEFORMATEX format; + WAVEFORMATEXTENSIBLE format; if (!activate_audio_client(node, name, rate, true, device, client, mix, format)) return 0; @@ -887,7 +887,7 @@ uint32_t sound_wasapi::stream_source_open(uint32_t node, std::string name, uint3 DWORD stream_flags = AUDCLNT_STREAMFLAGS_EVENTCALLBACK; if (device->info.m_sinks) stream_flags |= AUDCLNT_STREAMFLAGS_LOOPBACK; - if (format.nSamplesPerSec != mix->nSamplesPerSec) + if (format.Format.nSamplesPerSec != mix->nSamplesPerSec) stream_flags |= AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY; // initialise the audio client interface @@ -896,7 +896,7 @@ uint32_t sound_wasapi::stream_source_open(uint32_t node, std::string name, uint3 stream_flags, 10 * 10'000, // 10 ms in units of 100 ns 0, - &format, + &format.Format, nullptr); if (FAILED(result)) { @@ -1519,7 +1519,7 @@ bool sound_wasapi::activate_audio_client( device_info_vector_iterator &device, audio_client_ptr &client, co_task_wave_format_ptr &mix_format, - WAVEFORMATEX &format) + WAVEFORMATEXTENSIBLE &format) { HRESULT result; @@ -1581,10 +1581,14 @@ bool sound_wasapi::activate_audio_client( } // set up desired format + std::optional positions; + if (WAVE_FORMAT_EXTENSIBLE == mix_format->wFormatTag) + positions = reinterpret_cast(mix_format.get())->dwChannelMask; populate_wave_format( format, input ? device->info.m_sources : device->info.m_sinks, - rate); + rate, + positions); return true; } diff --git a/src/osd/modules/sound/xaudio2_sound.cpp b/src/osd/modules/sound/xaudio2_sound.cpp index 389a4785a32..3b3ec004709 100644 --- a/src/osd/modules/sound/xaudio2_sound.cpp +++ b/src/osd/modules/sound/xaudio2_sound.cpp @@ -712,8 +712,8 @@ uint32_t sound_xaudio2::stream_sink_open(uint32_t node, std::string name, uint32 } // set up desired input format - WAVEFORMATEX format; - populate_wave_format(format, (*device)->info.m_sinks, rate); + WAVEFORMATEXTENSIBLE format; + populate_wave_format(format, (*device)->info.m_sinks, rate, std::nullopt); // set up destinations XAUDIO2_SEND_DESCRIPTOR destination; @@ -724,7 +724,7 @@ uint32_t sound_xaudio2::stream_sink_open(uint32_t node, std::string name, uint32 sends.pSends = &destination; // create the voice info object - voice_info_ptr info = std::make_unique(*this, format); + voice_info_ptr info = std::make_unique(*this, format.Format); info->info.m_node = node; info->info.m_volumes.resize((*device)->info.m_sinks, 0.0F); @@ -732,7 +732,7 @@ uint32_t sound_xaudio2::stream_sink_open(uint32_t node, std::string name, uint32 IXAudio2SourceVoice *source_voice_raw = nullptr; result = (*device)->engine->CreateSourceVoice( &source_voice_raw, - &format, + &format.Format, XAUDIO2_VOICE_NOPITCH, 1.0F, info.get(), @@ -755,8 +755,8 @@ uint32_t sound_xaudio2::stream_sink_open(uint32_t node, std::string name, uint32 // set the channel mapping result = info->voice->SetOutputMatrix( nullptr, - format.nChannels, - format.nChannels, + format.Format.nChannels, + format.Format.nChannels, info->volume_matrix.get(), XAUDIO2_COMMIT_NOW); if (FAILED(result))