At some point the comment was probably true, but recent versions of pulseaudio have no trouble with any reasonable selection of sample formats.
There are some exceptions:
* at present DSD is not (yet) supported in pulseaudio
* pulseaudio supports U8, but not S8, vis-versa for mpd
* pulseaudio supports both packed and unpacked variants of
S24 for both endian, but mpd apparently doesn't support
non-packed 24bit samples, which is a little odd since the
ALSA output plugin assumes it does and so seems to always
fall back to packed for 24bit formats!?! (bug?)
I originally started this patch from the multi-format support
code in the ALSA plugin, and as such it still contains the
logic for fall-back formats, but whereas the ALSA plugin
attempts to open a stream, this isn't necessary in this case
since there's a pulse API for testing the validity of a
sample_spec.
---
src/output/plugins/PulseOutputPlugin.cxx | 120 +++++++++++++++++++++++++++++--
1 file changed, 116 insertions(+), 4 deletions(-)
diff --git a/src/output/plugins/PulseOutputPlugin.cxx
b/src/output/plugins/PulseOutputPlugin.cxx
index 0d79af7..b6c7128 100644
--- a/src/output/plugins/PulseOutputPlugin.cxx
+++ b/src/output/plugins/PulseOutputPlugin.cxx
@@ -544,6 +544,94 @@ pulse_output_setup_stream(PulseOutput *po, const
pa_sample_spec *ss,
return true;
}
+static pa_sample_format_t
+get_bitformat(SampleFormat sample_format)
+{
+ /* Pulse supports U8 and S24LE/BE formats but mpd
+ currently does not. Pulse does not support S8. */
+ switch (sample_format) {
+ case SampleFormat::UNDEFINED:
+ case SampleFormat::DSD:
+ case SampleFormat::S8:
+ return PA_SAMPLE_INVALID;
+
+ case SampleFormat::S16:
+ return PA_SAMPLE_S16NE;
+
+ case SampleFormat::S24_P32:
+ return PA_SAMPLE_S24_32NE;
+
+ case SampleFormat::S32:
+ return PA_SAMPLE_S32NE;
+
+ case SampleFormat::FLOAT:
+ return PA_SAMPLE_FLOAT32NE;
+ }
+
+ assert(false);
+ gcc_unreachable();
+}
+
+static pa_sample_format_t
+byteswap_bitformat(pa_sample_format_t fmt)
+{
+ switch(fmt) {
+ case PA_SAMPLE_S16LE: return PA_SAMPLE_S16BE;
+ case PA_SAMPLE_S24LE: return PA_SAMPLE_S24BE;
+ case PA_SAMPLE_S32LE: return PA_SAMPLE_S32BE;
+ case PA_SAMPLE_S16BE: return PA_SAMPLE_S16LE;
+ case PA_SAMPLE_S24BE: return PA_SAMPLE_S24LE;
+
+ case PA_SAMPLE_S24_32BE:
+ return PA_SAMPLE_S24_32LE;
+
+ case PA_SAMPLE_S24_32LE:
+ return PA_SAMPLE_S24_32BE;
+
+ case PA_SAMPLE_S32BE: return PA_SAMPLE_S32LE;
+
+ case PA_SAMPLE_FLOAT32BE:
+ return PA_SAMPLE_FLOAT32LE;
+
+ case PA_SAMPLE_FLOAT32LE:
+ return PA_SAMPLE_FLOAT32BE;
+
+ default: return PA_SAMPLE_INVALID;
+ }
+}
+
+/**
+ * Attempts to configure the specified sample format, and tries the
+ * reversed host byte order if was not supported.
+ */
+static pa_sample_format_t
+pulse_get_valid_format(uint32_t sample_rate, SampleFormat sample_format,
+ uint8_t channels)
+{
+ pa_sample_spec test_spec;
+ int ret;
+
+ test_spec.rate = sample_rate;
+ test_spec.channels = channels;
+ test_spec.format = get_bitformat(sample_format);
+ if (test_spec.format == PA_SAMPLE_INVALID)
+ return test_spec.format;
+
+ ret = pa_sample_spec_valid(&test_spec);
+ if (ret != 0)
+ return test_spec.format;
+
+ test_spec.format = byteswap_bitformat(test_spec.format);
+ if (test_spec.format == PA_SAMPLE_INVALID)
+ return test_spec.format;
+
+ ret = pa_sample_spec_valid(&test_spec);
+ if (ret != 0)
+ return test_spec.format;
+ else
+ return PA_SAMPLE_INVALID;
+}
+
static bool
pulse_output_open(AudioOutput *ao, AudioFormat &audio_format,
Error &error)
@@ -579,11 +667,35 @@ pulse_output_open(AudioOutput *ao, AudioFormat
&audio_format,
return false;
}
- /* MPD doesn't support the other pulseaudio sample formats, so
- we just force MPD to send us everything as 16 bit */
- audio_format.format = SampleFormat::S16;
- ss.format = PA_SAMPLE_S16NE;
+ /* pulseaudio can validate a sample_spec before opening the stream */
+ ss.format = pulse_get_valid_format(audio_format.sample_rate,
+ audio_format.format, audio_format.channels);
+
+ /* if unsupported, try other formats */
+
+ if (ss.format == PA_SAMPLE_INVALID) {
+ static const SampleFormat probe_formats[] = {
+ SampleFormat::S24_P32,
+ SampleFormat::S32,
+ SampleFormat::S16,
+ SampleFormat::UNDEFINED,
+ };
+
+ for (unsigned i = 0;
+ ss.format == PA_SAMPLE_INVALID && probe_formats[i] !=
SampleFormat::UNDEFINED;
+ ++i) {
+ const SampleFormat mpd_format = probe_formats[i];
+ if (mpd_format == audio_format.format)
+ continue;
+
+ ss.format = pulse_get_valid_format(audio_format.sample_rate,
+ mpd_format, audio_format.channels);
+ if (ss.format != PA_SAMPLE_INVALID)
+ audio_format.format = mpd_format;
+ }
+ }
+ /* Set other params for pulse stream */
ss.rate = audio_format.sample_rate;
ss.channels = audio_format.channels;
--
2.1.2
signature.asc
Description: This is a digitally signed message part
_______________________________________________ mpd-devel mailing list [email protected] http://mailman.blarg.de/listinfo/mpd-devel
