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 <cstring>
#include <memory>
#include <optional>
#include <string>
@ -115,15 +116,30 @@ HRESULT get_string_property_value(
REFPROPERTYKEY key,
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;
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

View File

@ -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<DWORD> positions;
if (WAVE_FORMAT_EXTENSIBLE == mix_format->wFormatTag)
positions = reinterpret_cast<WAVEFORMATEXTENSIBLE const *>(mix_format.get())->dwChannelMask;
populate_wave_format(
format,
input ? device->info.m_sources : device->info.m_sinks,
rate);
rate,
positions);
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
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<voice_info>(*this, format);
voice_info_ptr info = std::make_unique<voice_info>(*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))