[alsa-devel] [PATCH - extplug refinement from hw_params 1/1] pcm: extplug: Update slave PCM if extplug slave params were changed

Takashi Iwai tiwai at suse.de
Fri Dec 7 12:03:31 CET 2018


On Thu, 06 Dec 2018 15:31:43 +0100,
<twischer at de.adit-jv.com> wrote:
> 
> From: Timo Wischer <twischer at de.adit-jv.com>
> 
> from extplug hw_params() callback function.
> 
> This feature is for example required in the following use case:
> - A filter plugin supports only 1-8 channels. Therefore it calls
> snd_pcm_extplug_set_slave_param_minmax(SND_PCM_EXTPLUG_HW_CHANNELS, 1,
> 8) to provide the salve PCM parameters limited to 1-8 channels to the
> user application

Which condition is supposed for this constraint (1-8 channels)?  If
this is about the input to the extplug itself, it should be set via
snd_pcm_extplug_set_param_minmax() instead.

The snd_pcm_extplug_set_slave_param_minmax() is used to restrict the
output from extplug (i.e. the condition to be passed to the slave).
This is needed only when the slave PCM can't have the proper input
constraints.  So usually this sets to a single condition or alike.


Takashi

> - The user application requests 2 channels. But in this case the slave
> PCM will be configured with 1 channel because it is the first valid
> configuration
> - To update the salve PCM
> snd_pcm_extplug_set_slave_param_minmax(SND_PCM_EXTPLUG_HW_CHANNELS, 2,
> 2) could be called from the extplug hw_params() callback function
> 
> Without this patch the call to snd_pcm_extplug_set_slave_param_minmax()
> would not have any effect. With this patch the slave device will also be
> configured with 2 channels and no down mixing has to be done by the
> extplug.
> 
> This new feature can also be used for some specific dependencies. For
> example a down mixing extplug supports only 2to1 and 4to2 channel down
> mixing. Therefore the salve PCM has to be opened with 2 channels if the
> user application requests 4 channels.
> 
> Signed-off-by: Timo Wischer <twischer at de.adit-jv.com>
> 
> diff --git a/src/pcm/pcm_extplug.c b/src/pcm/pcm_extplug.c
> index 1f887c5..44afadb 100644
> --- a/src/pcm/pcm_extplug.c
> +++ b/src/pcm/pcm_extplug.c
> @@ -26,6 +26,7 @@
>   *
>   */
>    
> +#include <stdbool.h>
>  #include "pcm_local.h"
>  #include "pcm_plugin.h"
>  #include "pcm_extplug.h"
> @@ -43,6 +44,7 @@ typedef struct snd_pcm_extplug_priv {
>  	snd_pcm_extplug_t *data;
>  	struct snd_ext_parm params[SND_PCM_EXTPLUG_HW_PARAMS];
>  	struct snd_ext_parm sparams[SND_PCM_EXTPLUG_HW_PARAMS];
> +	bool sparams_changed;
>  } extplug_priv_t;
>  
>  static const int hw_params_type[SND_PCM_EXTPLUG_HW_PARAMS] = {
> @@ -60,18 +62,49 @@ static const unsigned int excl_parbits[SND_PCM_EXTPLUG_HW_PARAMS] = {
>  					 SND_PCM_HW_PARBIT_FRAME_BITS),
>  };
>  
> +static bool snd_ext_parm_equal(const struct snd_ext_parm * const a,
> +			      const struct snd_ext_parm * const b)
> +{
> +	if (a != b || a->active != b->active || a->num_list != b->num_list)
> +		return false;
> +
> +	if (a->num_list > 0) {
> +		for (unsigned int i = 0; i++; i < a->num_list) {
> +			if (a->list[i] != b->list[i])
> +				return false;
> +		}
> +	} else {
> +		if (a->min != b->min || a->max != b->max)
> +			return false;
> +	}
> +
> +	return true;
> +}
> +
> +static int snd_ext_parm_set(struct snd_ext_parm *parm, unsigned int min,
> +			    unsigned int max, unsigned int num_list,
> +			    unsigned int *list)
> +{
> +	const struct snd_ext_parm new_parm = {
> +		.min = min,
> +		.max = max,
> +		.num_list = num_list,
> +		.list = list,
> +		.active = 1,
> +	};
> +	const int changed = snd_ext_parm_equal(parm, &new_parm) ? 0 : 1;
> +
> +	free(parm->list);
> +	*parm = new_parm;
> +	return changed;
> +}
> +
>  /*
>   * set min/max values for the given parameter
>   */
>  int snd_ext_parm_set_minmax(struct snd_ext_parm *parm, unsigned int min, unsigned int max)
>  {
> -	parm->num_list = 0;
> -	free(parm->list);
> -	parm->list = NULL;
> -	parm->min = min;
> -	parm->max = max;
> -	parm->active = 1;
> -	return 0;
> +	return snd_ext_parm_set(parm, min, max, 0, NULL);
>  }
>  
>  /*
> @@ -92,11 +125,7 @@ int snd_ext_parm_set_list(struct snd_ext_parm *parm, unsigned int num_list, cons
>  	memcpy(new_list, list, sizeof(*new_list) * num_list);
>  	qsort(new_list, num_list, sizeof(*new_list), val_compar);
>  
> -	free(parm->list);
> -	parm->num_list = num_list;
> -	parm->list = new_list;
> -	parm->active = 1;
> -	return 0;
> +	return snd_ext_parm_set(parm, 0, 0, num_list, new_list);
>  }
>  
>  void snd_ext_parm_clear(struct snd_ext_parm *parm)
> @@ -291,29 +320,37 @@ static int snd_pcm_extplug_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params
>   */
>  static int snd_pcm_extplug_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
>  {
> -
>  	extplug_priv_t *ext = pcm->private_data;
>  	snd_pcm_t *slave = ext->plug.gen.slave;
> -	int err = snd_pcm_hw_params_slave(pcm, params,
> -					  snd_pcm_extplug_hw_refine_cchange,
> -					  snd_pcm_extplug_hw_refine_sprepare,
> -					  snd_pcm_extplug_hw_refine_schange,
> -					  snd_pcm_generic_hw_params);
> -	if (err < 0)
> -		return err;
> -	ext->data->slave_format = slave->format;
> -	ext->data->slave_subformat = slave->subformat;
> -	ext->data->slave_channels = slave->channels;
> -	ext->data->rate = slave->rate;
> -	INTERNAL(snd_pcm_hw_params_get_format)(params, &ext->data->format);
> -	INTERNAL(snd_pcm_hw_params_get_subformat)(params, &ext->data->subformat);
> -	INTERNAL(snd_pcm_hw_params_get_channels)(params, &ext->data->channels);
> -
> -	if (ext->data->callback->hw_params) {
> -		err = ext->data->callback->hw_params(ext->data, params);
> +
> +	do {
> +		ext->sparams_changed = false;
> +
> +		int err = snd_pcm_hw_params_slave(pcm, params,
> +						  snd_pcm_extplug_hw_refine_cchange,
> +						  snd_pcm_extplug_hw_refine_sprepare,
> +						  snd_pcm_extplug_hw_refine_schange,
> +						  snd_pcm_generic_hw_params);
>  		if (err < 0)
>  			return err;
> -	}
> +		ext->data->slave_format = slave->format;
> +		ext->data->slave_subformat = slave->subformat;
> +		ext->data->slave_channels = slave->channels;
> +		ext->data->rate = slave->rate;
> +		INTERNAL(snd_pcm_hw_params_get_format)(
> +				params, &ext->data->format);
> +		INTERNAL(snd_pcm_hw_params_get_subformat)(
> +				params, &ext->data->subformat);
> +		INTERNAL(snd_pcm_hw_params_get_channels)(
> +				params, &ext->data->channels);
> +
> +		if (ext->data->callback->hw_params) {
> +			err = ext->data->callback->hw_params(ext->data, params);
> +			if (err < 0)
> +				return err;
> +		}
> +	} while (ext->sparams_changed);
> +
>  	return 0;
>  }
>  
> @@ -411,6 +448,7 @@ static void clear_ext_params(extplug_priv_t *ext)
>  	int i;
>  	for (i = 0; i < SND_PCM_EXTPLUG_HW_PARAMS; i++) {
>  		snd_ext_parm_clear(&ext->params[i]);
> +		ext->sparams_changed |= ext->sparams[i].active;
>  		snd_ext_parm_clear(&ext->sparams[i]);
>  	}
>  }
> @@ -637,7 +675,9 @@ parameters are sample format and channels.
>  To define the constraints of the slave PCM configuration, use
>  either #snd_pcm_extplug_set_slave_param_minmax() and
>  #snd_pcm_extplug_set_slave_param_list().  The arguments are as same
> -as former functions.
> +as former functions. Both functions can also be called from the hw_params
> +callback. This can be used to further limit the configuration of the slave
> +device depending on the configuration of the user device.
>  
>  To clear the parameter constraints, call #snd_pcm_extplug_params_reset()
>  function. 
> @@ -768,11 +808,17 @@ void snd_pcm_extplug_params_reset(snd_pcm_extplug_t *extplug)
>  int snd_pcm_extplug_set_slave_param_list(snd_pcm_extplug_t *extplug, int type, unsigned int num_list, const unsigned int *list)
>  {
>  	extplug_priv_t *ext = extplug->pcm->private_data;
> +	int changed = 0;
> +
>  	if (type < 0 || type >= SND_PCM_EXTPLUG_HW_PARAMS) {
>  		SNDERR("EXTPLUG: invalid parameter type %d", type);
>  		return -EINVAL;
>  	}
> -	return snd_ext_parm_set_list(&ext->sparams[type], num_list, list);
> +	changed = snd_ext_parm_set_list(&ext->sparams[type], num_list, list);
> +	if (changed > 0)
> +		ext->sparams_changed = true;
> +
> +	return changed;
>  }
>  
>  /**
> @@ -790,6 +836,8 @@ int snd_pcm_extplug_set_slave_param_list(snd_pcm_extplug_t *extplug, int type, u
>  int snd_pcm_extplug_set_slave_param_minmax(snd_pcm_extplug_t *extplug, int type, unsigned int min, unsigned int max)
>  {
>  	extplug_priv_t *ext = extplug->pcm->private_data;
> +	int changed = 0;
> +
>  	if (type < 0 || type >= SND_PCM_EXTPLUG_HW_PARAMS) {
>  		SNDERR("EXTPLUG: invalid parameter type %d", type);
>  		return -EINVAL;
> @@ -798,7 +846,11 @@ int snd_pcm_extplug_set_slave_param_minmax(snd_pcm_extplug_t *extplug, int type,
>  		SNDERR("EXTPLUG: invalid parameter type %d", type);
>  		return -EINVAL;
>  	}
> -	return snd_ext_parm_set_minmax(&ext->sparams[type], min, max);
> +	changed = snd_ext_parm_set_minmax(&ext->sparams[type], min, max);
> +	if (changed > 0)
> +		ext->sparams_changed = true;
> +
> +	return changed;
>  }
>  
>  /**
> -- 
> 2.7.4
> 


More information about the Alsa-devel mailing list