ASoC: soc-pcm: improve BE state transitions

Merge series from Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>:

With additional tests with the introduction of a 'deep-buffer' PCM
device mixed with the regular low-latency path, we came up with two
improvements in the BE state machine and transitions. The short
explanation is that the BE cannot directly use the trigger commands
provided by the FE, and a translation is needed to deal with paused
states.
This commit is contained in:
Mark Brown 2022-04-20 14:22:08 +01:00
commit 2ad1e059cb
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0
2 changed files with 37 additions and 3 deletions

View File

@ -103,6 +103,8 @@ struct snd_soc_dpcm_runtime {
int trigger_pending; /* trigger cmd + 1 if pending, 0 if not */
int be_start; /* refcount protected by BE stream pcm lock */
int be_pause; /* refcount protected by BE stream pcm lock */
bool fe_pause; /* used to track STOP after PAUSE */
};
#define for_each_dpcm_fe(be, stream, _dpcm) \

View File

@ -2090,6 +2090,7 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
int cmd)
{
struct snd_soc_pcm_runtime *be;
bool pause_stop_transition;
struct snd_soc_dpcm *dpcm;
unsigned long flags;
int ret = 0;
@ -2121,6 +2122,13 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
if (be->dpcm[stream].be_start != 1)
goto next;
if (be->dpcm[stream].state == SND_SOC_DPCM_STATE_PAUSED)
ret = soc_pcm_trigger(be_substream,
SNDRV_PCM_TRIGGER_PAUSE_RELEASE);
else
ret = soc_pcm_trigger(be_substream,
SNDRV_PCM_TRIGGER_START);
ret = soc_pcm_trigger(be_substream, cmd);
if (ret) {
be->dpcm[stream].be_start--;
@ -2148,10 +2156,12 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
if (!be->dpcm[stream].be_start &&
(be->dpcm[stream].state != SND_SOC_DPCM_STATE_START) &&
(be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
(be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
goto next;
fe->dpcm[stream].fe_pause = false;
be->dpcm[stream].be_pause--;
be->dpcm[stream].be_start++;
if (be->dpcm[stream].be_start != 1)
goto next;
@ -2175,14 +2185,33 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
if (be->dpcm[stream].be_start != 0)
goto next;
ret = soc_pcm_trigger(be_substream, cmd);
pause_stop_transition = false;
if (fe->dpcm[stream].fe_pause) {
pause_stop_transition = true;
fe->dpcm[stream].fe_pause = false;
be->dpcm[stream].be_pause--;
}
if (be->dpcm[stream].be_pause != 0)
ret = soc_pcm_trigger(be_substream, SNDRV_PCM_TRIGGER_PAUSE_PUSH);
else
ret = soc_pcm_trigger(be_substream, SNDRV_PCM_TRIGGER_STOP);
if (ret) {
if (be->dpcm[stream].state == SND_SOC_DPCM_STATE_START)
be->dpcm[stream].be_start++;
if (pause_stop_transition) {
fe->dpcm[stream].fe_pause = true;
be->dpcm[stream].be_pause++;
}
goto next;
}
be->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
if (be->dpcm[stream].be_pause != 0)
be->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
else
be->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
@ -2204,6 +2233,9 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
goto next;
fe->dpcm[stream].fe_pause = true;
be->dpcm[stream].be_pause++;
be->dpcm[stream].be_start--;
if (be->dpcm[stream].be_start != 0)
goto next;