From 7e4490974191a9e8222bf5cb9808740773ba5bc4 Mon Sep 17 00:00:00 2001 From: Carlos Rafael Giani Date: Mon, 13 Jun 2022 20:02:33 +0200 Subject: [PATCH] alsa: add lower rate bound for DSD playback This prevents errors when trying to play at a rate that's lower than DSD64 (the lowest rate available). --- spa/plugins/alsa/alsa-pcm.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/spa/plugins/alsa/alsa-pcm.c b/spa/plugins/alsa/alsa-pcm.c index 950311cd9..7ff4edb37 100644 --- a/spa/plugins/alsa/alsa-pcm.c +++ b/spa/plugins/alsa/alsa-pcm.c @@ -752,7 +752,7 @@ static bool uint32_array_contains(uint32_t *vals, uint32_t n_vals, uint32_t val) } static int add_rate(struct state *state, uint32_t scale, bool all, uint32_t index, uint32_t *next, - snd_pcm_hw_params_t *params, struct spa_pod_builder *b) + uint32_t min_allowed_rate, snd_pcm_hw_params_t *params, struct spa_pod_builder *b) { struct spa_pod_frame f[1]; int err, dir; @@ -763,6 +763,9 @@ static int add_rate(struct state *state, uint32_t scale, bool all, uint32_t inde CHECK(snd_pcm_hw_params_get_rate_min(params, &min, &dir), "get_rate_min"); CHECK(snd_pcm_hw_params_get_rate_max(params, &max, &dir), "get_rate_max"); + min_allowed_rate /= scale; + min = SPA_MAX(min_allowed_rate, min); + if (!state->multi_rate && state->card->format_ref > 0) rate = state->card->rate; else @@ -1017,7 +1020,7 @@ static int enum_pcm_formats(struct state *state, uint32_t index, uint32_t *next, choice->body.type = SPA_CHOICE_Enum; spa_pod_builder_pop(b, &f[1]); - if ((res = add_rate(state, 1, false, index & 0xffff, next, params, b)) != 1) + if ((res = add_rate(state, 1, false, index & 0xffff, next, 0, params, b)) != 1) return res; if ((res = add_channels(state, false, index & 0xffff, next, params, b)) != 1) @@ -1110,7 +1113,7 @@ static int enum_iec958_formats(struct state *state, uint32_t index, uint32_t *ne } spa_pod_builder_pop(b, &f[1]); - if ((res = add_rate(state, 1, true, index & 0xffff, next, params, b)) != 1) + if ((res = add_rate(state, 1, true, index & 0xffff, next, 0, params, b)) != 1) return res; (*next)++; @@ -1165,7 +1168,14 @@ static int enum_dsd_formats(struct state *state, uint32_t index, uint32_t *next, spa_pod_builder_prop(b, SPA_FORMAT_AUDIO_interleave, 0); spa_pod_builder_int(b, interleave); - if ((res = add_rate(state, SPA_ABS(interleave), true, index & 0xffff, next, params, b)) != 1) + /* Use a lower rate limit of 352800 (= 44100 * 64 / 8). This is because in + * PipeWire, DSD rates are given in bytes, not bits, so 352800 corresponds + * to the bit rate of DSD64. (The "64" in DSD64 means "64 times the rate + * of 44.1 kHz".) Some hardware may report rates lower than that, for example + * 176400. This would correspond to "DSD32" (which does not exist). Trying + * to use such a rate with DSD hardware does not work and may cause undefined + * behavior in said hardware. */ + if ((res = add_rate(state, SPA_ABS(interleave), true, index & 0xffff, next, 44100 * 64 / 8, params, b)) != 1) return res; if ((res = add_channels(state, true, index & 0xffff, next, params, b)) != 1)