sound/wasapi_sound.cpp: Repeat the channel mask from the mix format back when initialising the audio client.

This commit is contained in:
Vas Crabb 2025-05-30 04:18:55 +10:00
parent d1bac658e4
commit 97625ff9e0
3 changed files with 43 additions and 23 deletions

View File

@ -9,6 +9,7 @@
#include "interface/audio.h" #include "interface/audio.h"
#include <cstring>
#include <memory> #include <memory>
#include <optional> #include <optional>
#include <string> #include <string>
@ -115,15 +116,30 @@ HRESULT get_string_property_value(
REFPROPERTYKEY key, REFPROPERTYKEY key,
std::optional<std::string> &value); std::optional<std::string> &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<DWORD> positions)
{ {
format.wFormatTag = WAVE_FORMAT_PCM; std::memset(&format, 0, sizeof(format));
format.nChannels = channels;
format.nSamplesPerSec = rate; format.Format.wFormatTag = WAVE_FORMAT_PCM;
format.nAvgBytesPerSec = 2 * channels * rate; format.Format.nChannels = channels;
format.nBlockAlign = 2 * channels; format.Format.nSamplesPerSec = rate;
format.wBitsPerSample = 16; format.Format.nAvgBytesPerSec = 2 * channels * rate;
format.cbSize = 0; 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 } // namespace osd

View File

@ -191,7 +191,7 @@ private:
device_info_vector_iterator &device, device_info_vector_iterator &device,
audio_client_ptr &client, audio_client_ptr &client,
co_task_wave_format_ptr &mix_format, co_task_wave_format_ptr &mix_format,
WAVEFORMATEX &format); WAVEFORMATEXTENSIBLE &format);
void cleanup_task(); 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; device_info_vector_iterator device;
audio_client_ptr client; audio_client_ptr client;
co_task_wave_format_ptr mix; co_task_wave_format_ptr mix;
WAVEFORMATEX format; WAVEFORMATEXTENSIBLE format;
if (!activate_audio_client(node, name, rate, false, device, client, mix, format)) if (!activate_audio_client(node, name, rate, false, device, client, mix, format))
return 0; return 0;
// need sample rate conversion if the sample rates don't match // need sample rate conversion if the sample rates don't match
DWORD stream_flags = AUDCLNT_STREAMFLAGS_EVENTCALLBACK; 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; stream_flags |= AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY;
// initialise the audio client interface // 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, stream_flags,
lround(m_audio_latency * 1e4F), // 100 ns units lround(m_audio_latency * 1e4F), // 100 ns units
0, 0,
&format, &format.Format,
nullptr); nullptr);
if (FAILED(result)) 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; device_info_vector_iterator device;
audio_client_ptr client; audio_client_ptr client;
co_task_wave_format_ptr mix; co_task_wave_format_ptr mix;
WAVEFORMATEX format; WAVEFORMATEXTENSIBLE format;
if (!activate_audio_client(node, name, rate, true, device, client, mix, format)) if (!activate_audio_client(node, name, rate, true, device, client, mix, format))
return 0; 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; DWORD stream_flags = AUDCLNT_STREAMFLAGS_EVENTCALLBACK;
if (device->info.m_sinks) if (device->info.m_sinks)
stream_flags |= AUDCLNT_STREAMFLAGS_LOOPBACK; 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; stream_flags |= AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY;
// initialise the audio client interface // 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, stream_flags,
10 * 10'000, // 10 ms in units of 100 ns 10 * 10'000, // 10 ms in units of 100 ns
0, 0,
&format, &format.Format,
nullptr); nullptr);
if (FAILED(result)) if (FAILED(result))
{ {
@ -1519,7 +1519,7 @@ bool sound_wasapi::activate_audio_client(
device_info_vector_iterator &device, device_info_vector_iterator &device,
audio_client_ptr &client, audio_client_ptr &client,
co_task_wave_format_ptr &mix_format, co_task_wave_format_ptr &mix_format,
WAVEFORMATEX &format) WAVEFORMATEXTENSIBLE &format)
{ {
HRESULT result; HRESULT result;
@ -1581,10 +1581,14 @@ bool sound_wasapi::activate_audio_client(
} }
// set up desired format // set up desired format
std::optional<DWORD> positions;
if (WAVE_FORMAT_EXTENSIBLE == mix_format->wFormatTag)
positions = reinterpret_cast<WAVEFORMATEXTENSIBLE const *>(mix_format.get())->dwChannelMask;
populate_wave_format( populate_wave_format(
format, format,
input ? device->info.m_sources : device->info.m_sinks, input ? device->info.m_sources : device->info.m_sinks,
rate); rate,
positions);
return true; return true;
} }

View File

@ -712,8 +712,8 @@ uint32_t sound_xaudio2::stream_sink_open(uint32_t node, std::string name, uint32
} }
// set up desired input format // set up desired input format
WAVEFORMATEX format; WAVEFORMATEXTENSIBLE format;
populate_wave_format(format, (*device)->info.m_sinks, rate); populate_wave_format(format, (*device)->info.m_sinks, rate, std::nullopt);
// set up destinations // set up destinations
XAUDIO2_SEND_DESCRIPTOR destination; 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; sends.pSends = &destination;
// create the voice info object // create the voice info object
voice_info_ptr info = std::make_unique<voice_info>(*this, format); voice_info_ptr info = std::make_unique<voice_info>(*this, format.Format);
info->info.m_node = node; info->info.m_node = node;
info->info.m_volumes.resize((*device)->info.m_sinks, 0.0F); 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; IXAudio2SourceVoice *source_voice_raw = nullptr;
result = (*device)->engine->CreateSourceVoice( result = (*device)->engine->CreateSourceVoice(
&source_voice_raw, &source_voice_raw,
&format, &format.Format,
XAUDIO2_VOICE_NOPITCH, XAUDIO2_VOICE_NOPITCH,
1.0F, 1.0F,
info.get(), info.get(),
@ -755,8 +755,8 @@ uint32_t sound_xaudio2::stream_sink_open(uint32_t node, std::string name, uint32
// set the channel mapping // set the channel mapping
result = info->voice->SetOutputMatrix( result = info->voice->SetOutputMatrix(
nullptr, nullptr,
format.nChannels, format.Format.nChannels,
format.nChannels, format.Format.nChannels,
info->volume_matrix.get(), info->volume_matrix.get(),
XAUDIO2_COMMIT_NOW); XAUDIO2_COMMIT_NOW);
if (FAILED(result)) if (FAILED(result))