From 32851d1bc7d8a93445ceff13bb0335542a409841 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 20 Oct 2021 09:54:05 +0200 Subject: [PATCH] output/pipewire: DSD support Closes https://github.com/MusicPlayerDaemon/MPD/issues/1297 --- NEWS | 1 + doc/plugins.rst | 2 ++ src/output/plugins/PipeWireOutputPlugin.cxx | 39 +++++++++++++++++++-- 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index 3712f6fed..b4689cf39 100644 --- a/NEWS +++ b/NEWS @@ -3,6 +3,7 @@ ver 0.23.2 (not yet released) - nfs: fix playback bug * output - pipewire: send artist and title to PipeWire + - pipewire: DSD support * neighbor - mention failed plugin name in error message * fix crash with libfmt versions older than 7 diff --git a/doc/plugins.rst b/doc/plugins.rst index cb00877b2..18b176fd2 100644 --- a/doc/plugins.rst +++ b/doc/plugins.rst @@ -1094,6 +1094,8 @@ Connect to a `PipeWire `_ server. Requires * - **remote NAME** - The name of the remote to connect to. The default is ``pipewire-0``. + * - **dsd yes|no** + - Enable DSD playback. This requires PipeWire 0.38. .. _pulse_plugin: diff --git a/src/output/plugins/PipeWireOutputPlugin.cxx b/src/output/plugins/PipeWireOutputPlugin.cxx index 5f3ab5620..4d2717d1f 100644 --- a/src/output/plugins/PipeWireOutputPlugin.cxx +++ b/src/output/plugins/PipeWireOutputPlugin.cxx @@ -31,6 +31,7 @@ #include "util/WritableBuffer.hxx" #include "Log.hxx" #include "tag/Format.hxx" +#include "config.h" // for ENABLE_DSD #ifdef __GNUC__ #pragma GCC diagnostic push @@ -91,6 +92,10 @@ class PipeWireOutput final : AudioOutput { */ SampleFormat sample_format; +#if defined(ENABLE_DSD) && defined(SPA_AUDIO_DSD_FLAG_NONE) + const bool enable_dsd; +#endif + bool disconnected; /** @@ -262,6 +267,9 @@ PipeWireOutput::PipeWireOutput(const ConfigBlock &block) name(block.GetBlockValue("name", "pipewire")), remote(block.GetBlockValue("remote", nullptr)), target(block.GetBlockValue("target", nullptr)) +#if defined(ENABLE_DSD) && defined(SPA_AUDIO_DSD_FLAG_NONE) + , enable_dsd(block.GetBlockValue("dsd", false)) +#endif { if (target != nullptr) { if (StringIsEmpty(target)) @@ -477,6 +485,13 @@ PipeWireOutput::Open(AudioFormat &audio_format) if (stream == nullptr) throw MakeErrno("pw_stream_new_simple() failed"); +#if defined(ENABLE_DSD) && defined(SPA_AUDIO_DSD_FLAG_NONE) + /* this needs to be determined before ToPipeWireAudioFormat() + switches DSD to S16 */ + const bool use_dsd = enable_dsd && + audio_format.format == SampleFormat::DSD; +#endif + auto raw = ToPipeWireAudioFormat(audio_format); frame_size = audio_format.GetFrameSize(); @@ -494,8 +509,28 @@ PipeWireOutput::Open(AudioFormat &audio_format) pod_builder = {}; pod_builder.data = buffer; pod_builder.size = sizeof(buffer); - params[0] = spa_format_audio_raw_build(&pod_builder, - SPA_PARAM_EnumFormat, &raw); + +#if defined(ENABLE_DSD) && defined(SPA_AUDIO_DSD_FLAG_NONE) + struct spa_audio_info_dsd dsd; + if (use_dsd) { + dsd = {}; + + /* copy all relevant settings from the + ToPipeWireAudioFormat() return value */ + dsd.flags = raw.flags; + dsd.rate = raw.rate; + dsd.channels = raw.channels; + if ((dsd.flags & SPA_AUDIO_FLAG_UNPOSITIONED) == 0) + std::copy_n(raw.position, dsd.channels, dsd.position); + + params[0] = spa_format_audio_dsd_build(&pod_builder, + SPA_PARAM_EnumFormat, + &dsd); + } else +#endif + params[0] = spa_format_audio_raw_build(&pod_builder, + SPA_PARAM_EnumFormat, + &raw); int error = pw_stream_connect(stream,