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) {