[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:52:30 CET 2018
On Fri, 07 Dec 2018 12:45:38 +0100,
Timo Wischer wrote:
>
> On 12/7/18 12:03, Takashi Iwai wrote:
> > 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.
>
>
> When using snd_pcm_extplug_set_param_minmax() it will ignore the
> capabilities of the slave device. For example the salve device
> supports only 2 channels but the extplug supports 1-8 channels and
> uses snd_pcm_extplug_set_param_minmax(CHANNELS, 1, 8).
> So the user application can open the device with 8 channels and the
> extplug has to down mix to 2 channels. But I do not want to support
> down mixing in my extplug. I only want to limit the capabilities of
> the slave device with the limitations of my extplug and forward this
> to the user application.
Well, if you just need some additional constraints that is specific to
the explug, keep the constraints linked to slave, but apply the
additional refine on top of it. That should make things much easier,
I suppose.
Takashi
>
> PS: currently I am investigating in an issue of this patch in case of
> MMAP access where snd_pcm_hw_params() fails with EBUSY because
> snd_pcm_mmap() is called twice. Therefore please do not merge this
> version of the patch.
>
> But anyway I am interested whether you are fine with this approach,
> now or I have to find another approach.
>
> Best regards
>
> Timo
>
> >
> >
> > 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