output/pipewire: DSD support

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1297
This commit is contained in:
Max Kellermann 2021-10-20 09:54:05 +02:00
parent 78257408b4
commit 32851d1bc7
3 changed files with 40 additions and 2 deletions

1
NEWS
View File

@ -3,6 +3,7 @@ ver 0.23.2 (not yet released)
- nfs: fix playback bug - nfs: fix playback bug
* output * output
- pipewire: send artist and title to PipeWire - pipewire: send artist and title to PipeWire
- pipewire: DSD support
* neighbor * neighbor
- mention failed plugin name in error message - mention failed plugin name in error message
* fix crash with libfmt versions older than 7 * fix crash with libfmt versions older than 7

View File

@ -1094,6 +1094,8 @@ Connect to a `PipeWire <https://pipewire.org/>`_ server. Requires
* - **remote NAME** * - **remote NAME**
- The name of the remote to connect to. The default is - The name of the remote to connect to. The default is
``pipewire-0``. ``pipewire-0``.
* - **dsd yes|no**
- Enable DSD playback. This requires PipeWire 0.38.
.. _pulse_plugin: .. _pulse_plugin:

View File

@ -31,6 +31,7 @@
#include "util/WritableBuffer.hxx" #include "util/WritableBuffer.hxx"
#include "Log.hxx" #include "Log.hxx"
#include "tag/Format.hxx" #include "tag/Format.hxx"
#include "config.h" // for ENABLE_DSD
#ifdef __GNUC__ #ifdef __GNUC__
#pragma GCC diagnostic push #pragma GCC diagnostic push
@ -91,6 +92,10 @@ class PipeWireOutput final : AudioOutput {
*/ */
SampleFormat sample_format; SampleFormat sample_format;
#if defined(ENABLE_DSD) && defined(SPA_AUDIO_DSD_FLAG_NONE)
const bool enable_dsd;
#endif
bool disconnected; bool disconnected;
/** /**
@ -262,6 +267,9 @@ PipeWireOutput::PipeWireOutput(const ConfigBlock &block)
name(block.GetBlockValue("name", "pipewire")), name(block.GetBlockValue("name", "pipewire")),
remote(block.GetBlockValue("remote", nullptr)), remote(block.GetBlockValue("remote", nullptr)),
target(block.GetBlockValue("target", 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 (target != nullptr) {
if (StringIsEmpty(target)) if (StringIsEmpty(target))
@ -477,6 +485,13 @@ PipeWireOutput::Open(AudioFormat &audio_format)
if (stream == nullptr) if (stream == nullptr)
throw MakeErrno("pw_stream_new_simple() failed"); 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); auto raw = ToPipeWireAudioFormat(audio_format);
frame_size = audio_format.GetFrameSize(); frame_size = audio_format.GetFrameSize();
@ -494,8 +509,28 @@ PipeWireOutput::Open(AudioFormat &audio_format)
pod_builder = {}; pod_builder = {};
pod_builder.data = buffer; pod_builder.data = buffer;
pod_builder.size = sizeof(buffer); pod_builder.size = sizeof(buffer);
#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, params[0] = spa_format_audio_raw_build(&pod_builder,
SPA_PARAM_EnumFormat, &raw); SPA_PARAM_EnumFormat,
&raw);
int error = int error =
pw_stream_connect(stream, pw_stream_connect(stream,