From 13057b74c84c0916557cfc0b999aa4ff837ede7e Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Fri, 23 Feb 2024 21:50:01 +0100 Subject: [PATCH] pcm: clarify and fix default sbits (msbits) value for all formats As described in the kernel patch (link bellow), the significant (resolution) bits should be related to the usable sample bits not the physical sample bits. Link: https://lore.kernel.org/linux-sound/20240222173649.1447549-1-perex@perex.cz/ Link: https://github.com/larsimmisch/pyalsaaudio/pull/146 Signed-off-by: Jaroslav Kysela --- src/pcm/pcm.c | 7 ++++++- src/pcm/pcm_hw.c | 22 +++++++++++++++++++--- src/pcm/pcm_params.c | 6 ++++++ 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c index ab3bbda7..bd1fecbf 100644 --- a/src/pcm/pcm.c +++ b/src/pcm/pcm.c @@ -215,7 +215,8 @@ range, thus you may get the significant bits for linear samples via #snd_pcm_hw_params_get_sbits() function. The example: ICE1712 chips support 32-bit sample processing, but low byte is ignored (playback) or zero (capture). The function snd_pcm_hw_params_get_sbits() -returns 24 in this case. +returns 24 in this case. The significant bits are related to the usable +sample bits (width) not the physical sample space. \section alsa_transfers ALSA transfers @@ -3905,6 +3906,10 @@ int snd_pcm_hw_params_get_rate_numden(const snd_pcm_hw_params_t *params, * \param params Configuration space * \return signification bits in sample otherwise a negative error code if the info is not available * + * Significant bits are related to usable sample bits (width) not the + * physical sample bits (width). For non-linear formats, this value may have + * a special meaning which may be defined in future. + * * This function should only be called when the configuration space * contains a single configuration. Call #snd_pcm_hw_params to choose * a single configuration from the configuration space. diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c index bd3ecfc9..f3fbcb6e 100644 --- a/src/pcm/pcm_hw.c +++ b/src/pcm/pcm_hw.c @@ -379,12 +379,28 @@ static int snd_pcm_hw_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) return 0; } -static inline int hw_params_call(snd_pcm_hw_t *pcm_hw, snd_pcm_hw_params_t *params) +#define hw_param_mask(params,var) \ + &((params)->masks[(var) - SND_PCM_HW_PARAM_FIRST_MASK]) + +static int hw_params_call(snd_pcm_hw_t *pcm_hw, snd_pcm_hw_params_t *params) { + int err; + /* check for new hw_params structure; it's available from 2.0.2 version of PCM API */ if (SNDRV_PROTOCOL_VERSION(2, 0, 2) <= pcm_hw->version) - return ioctl(pcm_hw->fd, SNDRV_PCM_IOCTL_HW_PARAMS, params); - return use_old_hw_params_ioctl(pcm_hw->fd, SND_PCM_IOCTL_HW_PARAMS_OLD, params); + err = ioctl(pcm_hw->fd, SNDRV_PCM_IOCTL_HW_PARAMS, params); + else + err = use_old_hw_params_ioctl(pcm_hw->fd, SND_PCM_IOCTL_HW_PARAMS_OLD, params); + if (err >= 0 && pcm_hw->version < SNDRV_PROTOCOL_VERSION(2, 0, 17) && params->msbits > 0) { + snd_mask_t *m = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + if (snd_mask_single(m)) { + snd_pcm_format_t format = snd_mask_min(m); + int width = snd_pcm_format_width(format); + if (width > 0 && params->msbits > (unsigned int)width) + params->msbits = width; + } + } + return err; } static int snd_pcm_hw_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) diff --git a/src/pcm/pcm_params.c b/src/pcm/pcm_params.c index c2f78634..05bfe3b2 100644 --- a/src/pcm/pcm_params.c +++ b/src/pcm/pcm_params.c @@ -2075,6 +2075,7 @@ int snd_pcm_hw_refine_soft(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t { unsigned int k; snd_interval_t *i; + snd_mask_t *m; unsigned int rstamps[RULES]; unsigned int vstamps[SND_PCM_HW_PARAM_LAST_INTERVAL + 1]; unsigned int stamp = 2; @@ -2159,6 +2160,11 @@ int snd_pcm_hw_refine_soft(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t i = hw_param_interval(params, SND_PCM_HW_PARAM_SAMPLE_BITS); if (snd_interval_single(i)) params->msbits = snd_interval_value(i); + m = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT); + if (snd_mask_single(m)) { + snd_pcm_format_t format = snd_mask_min(m); + params->msbits = snd_pcm_format_width(format); + } } if (!params->rate_den) { -- 2.47.1