[alsa-devel] [RFC PATCH 1/2] ASoC: pcm: update FE/BE trigger order based on the command

Sridharan, Ranjani ranjani.sridharan at intel.com
Fri Oct 4 23:37:07 CEST 2019


On Fri, Oct 4, 2019 at 2:34 PM Pierre-Louis Bossart <
pierre-louis.bossart at linux.intel.com> wrote:

> On 10/4/19 8:41 AM, Ranjani Sridharan wrote:
> > Currently, the trigger orders SND_SOC_DPCM_TRIGGER_PRE/POST
> > determine the order in which FE DAI and BE DAI are triggered.
> > In the case of SND_SOC_DPCM_TRIGGER_PRE, the FE DAI is
> > triggered before the BE DAI and in the case of
> > SND_SOC_DPCM_TRIGGER_POST, the BE DAI is triggered before
> > the FE DAI. And this order remains the same irrespective of the
> > trigger command.
> >
> > In the case of the SOF driver, during playback, the FW
> > expects the BE DAI to be triggered before the FE DAI during
> > the START trigger. The BE DAI trigger handles the starting of
> > Link DMA and so it must be started before the FE DAI is started
> > to prevent xruns during pause/release. This can be addressed
> > by setting the trigger order for the FE dai link to
> > SND_SOC_DPCM_TRIGGER_POST. But during the STOP trigger,
> > the FW expects the FE DAI to be triggered before the BE DAI.
> > Retaining the same order during the START and STOP commands,
> > results in FW error as the DAI component in the FW is still
> > active.
> >
> > The issue can be fixed by mirroring the trigger order of
> > FE and BE DAI's during the START and STOP trigger. So, with the
> > trigger order set to SND_SOC_DPCM_TRIGGER_PRE, the FE DAI will be
> > trigger first during SNDRV_PCM_TRIGGER_START/STOP/RESUME
> > and the BE DAI will be triggered first during the
> > STOP/SUSPEND/PAUSE commands. Conversely, with the trigger order
> > set to SND_SOC_DPCM_TRIGGER_POST, the BE DAI will be triggered
> > first during the SNDRV_PCM_TRIGGER_START/STOP/RESUME commands
> > and the FE DAI will be triggered first during the
> > SNDRV_PCM_TRIGGER_STOP/SUSPEND/PAUSE commands.
> >
> > Github Issue: https://github.com/thesofproject/linux/issues/1160
> > Signed-off-by: Ranjani Sridharan <ranjani.sridharan at linux.intel.com>
> > ---
> >   sound/soc/soc-pcm.c | 99 ++++++++++++++++++++++++++++++++-------------
> >   1 file changed, 72 insertions(+), 27 deletions(-)
> >
> > diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
> > index 66910500e3b6..8e5097eead27 100644
> > --- a/sound/soc/soc-pcm.c
> > +++ b/sound/soc/soc-pcm.c
> > @@ -2340,42 +2340,85 @@ int dpcm_be_dai_trigger(struct
> snd_soc_pcm_runtime *fe, int stream,
> >   }
> >   EXPORT_SYMBOL_GPL(dpcm_be_dai_trigger);
> >
> > +static int dpcm_dai_trigger_fe_first(struct snd_pcm_substream
> *substream,
> > +                                  int cmd, bool fe_first)
>
> the function name is odd with the fe_first repeat
>
> maybe 'dpcm_dai_trigger_fe_be' ?
>
Sure, will change in v2.

>
> > +{
> > +     struct snd_soc_pcm_runtime *fe = substream->private_data;
> > +     int ret;
> > +
> > +     /* call trigger on the frontend before the backend. */
> > +     if (fe_first) {
> > +             dev_dbg(fe->dev, "ASoC: pre trigger FE %s cmd %d\n",
> > +                     fe->dai_link->name, cmd);
> > +
> > +             ret = soc_pcm_trigger(substream, cmd);
> > +             if (ret < 0)
> > +                     return ret;
> > +
> > +             ret = dpcm_be_dai_trigger(fe, substream->stream, cmd);
> > +             return ret;
> > +     }
> > +
> > +     /* call trigger on the frontend after the backend. */
> > +     ret = dpcm_be_dai_trigger(fe, substream->stream, cmd);
> > +     if (ret < 0)
> > +             return ret;
> > +
> > +     dev_dbg(fe->dev, "ASoC: post trigger FE %s cmd %d\n",
> > +             fe->dai_link->name, cmd);
> > +
> > +     ret = soc_pcm_trigger(substream, cmd);
> > +
> > +     return ret;
> > +}
> > +
> >   static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream,
> int cmd)
> >   {
> >       struct snd_soc_pcm_runtime *fe = substream->private_data;
> > -     int stream = substream->stream, ret;
> > +     int stream = substream->stream;
> > +     int ret = 0;
> >       enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
> >
> >       fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
> >
> >       switch (trigger) {
> >       case SND_SOC_DPCM_TRIGGER_PRE:
> > -             /* call trigger on the frontend before the backend. */
> > -
> > -             dev_dbg(fe->dev, "ASoC: pre trigger FE %s cmd %d\n",
> > -                             fe->dai_link->name, cmd);
> > -
> > -             ret = soc_pcm_trigger(substream, cmd);
> > -             if (ret < 0) {
> > -                     dev_err(fe->dev,"ASoC: trigger FE failed %d\n",
> ret);
> > -                     goto out;
> > +             switch (cmd) {
> > +             case SNDRV_PCM_TRIGGER_START:
> > +             case SNDRV_PCM_TRIGGER_RESUME:
> > +             case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
> > +                     ret = dpcm_dai_trigger_fe_first(substream, cmd,
> true);
> > +                     break;
> > +             case SNDRV_PCM_TRIGGER_STOP:
> > +             case SNDRV_PCM_TRIGGER_SUSPEND:
> > +                     ret = dpcm_dai_trigger_fe_first(substream, cmd,
> false);
> > +                     break;
> > +             case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
> > +                     ret = dpcm_dai_trigger_fe_first(substream, cmd,
> false);
> > +                     break;
>
> can we group these 3 cases together? The last two are identical.
>
Ahh yes, I originally intended to set the state here as well but changed my
mind later on . Will fix in v2.


More information about the Alsa-devel mailing list