[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 14:21:47 CET 2018
On Fri, 07 Dec 2018 12:52:30 +0100,
Takashi Iwai wrote:
>
> 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.
But actually I'd like to see exactly what's failing before going
further. Could you give a simple test case? You can write a dummy
extplug plugin that just shows the behavior, for example.
thanks,
Takashi
>
>
> 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