pcm: direct: Fix for sync issue on xrun recover

If using very short periods, DSHARE/DSNOOP/DMIX may report underruns while in
status 'prepared'. This prohibits correct recovery. Now slave xrun conditions
for DSHARE/DSNOOP/DMIX are being handled properly.

Signed-off-by: Andreas Pape <apape@de.adit-jv.com>
Signed-off-by: Joshua Frkuska <joshua_frkuska@mentor.com>
Signed-off-by: Mounesh Sutar <mounesh_sutar@mentor.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Andreas Pape 2017-01-10 12:03:36 +05:30 committed by Takashi Iwai
parent 3f0dc404f1
commit 1a9bd0f044
5 changed files with 162 additions and 16 deletions

View file

@ -434,15 +434,21 @@ static int snd_pcm_dmix_sync_ptr0(snd_pcm_t *pcm, snd_pcm_uframes_t slave_hw_ptr
static int snd_pcm_dmix_sync_ptr(snd_pcm_t *pcm)
{
snd_pcm_direct_t *dmix = pcm->private_data;
int err;
switch (snd_pcm_state(dmix->spcm)) {
case SND_PCM_STATE_DISCONNECTED:
dmix->state = SND_PCM_STATE_DISCONNECTED;
return -ENODEV;
case SND_PCM_STATE_XRUN:
if ((err = snd_pcm_direct_slave_recover(dmix)) < 0)
return err;
break;
default:
break;
}
if (snd_pcm_direct_client_chk_xrun(dmix, pcm))
return -EPIPE;
if (dmix->slowptr)
snd_pcm_hwsync(dmix->spcm);
@ -828,12 +834,16 @@ static snd_pcm_sframes_t snd_pcm_dmix_mmap_commit(snd_pcm_t *pcm,
switch (snd_pcm_state(dmix->spcm)) {
case SND_PCM_STATE_XRUN:
return -EPIPE;
if ((err = snd_pcm_direct_slave_recover(dmix)) < 0)
return err;
break;
case SND_PCM_STATE_SUSPENDED:
return -ESTRPIPE;
default:
break;
}
if (snd_pcm_direct_client_chk_xrun(dmix, pcm))
return -EPIPE;
if (! size)
return 0;
snd_pcm_mmap_appl_forward(pcm, size);
@ -841,8 +851,10 @@ static snd_pcm_sframes_t snd_pcm_dmix_mmap_commit(snd_pcm_t *pcm,
if ((err = snd_pcm_dmix_start_timer(pcm, dmix)) < 0)
return err;
} else if (dmix->state == SND_PCM_STATE_RUNNING ||
dmix->state == SND_PCM_STATE_DRAINING)
snd_pcm_dmix_sync_ptr(pcm);
dmix->state == SND_PCM_STATE_DRAINING) {
if ((err = snd_pcm_dmix_sync_ptr(pcm)) < 0)
return err;
}
if (dmix->state == SND_PCM_STATE_RUNNING ||
dmix->state == SND_PCM_STATE_DRAINING) {
/* ok, we commit the changes after the validation of area */
@ -858,10 +870,13 @@ static snd_pcm_sframes_t snd_pcm_dmix_mmap_commit(snd_pcm_t *pcm,
static snd_pcm_sframes_t snd_pcm_dmix_avail_update(snd_pcm_t *pcm)
{
snd_pcm_direct_t *dmix = pcm->private_data;
int err;
if (dmix->state == SND_PCM_STATE_RUNNING ||
dmix->state == SND_PCM_STATE_DRAINING)
snd_pcm_dmix_sync_ptr(pcm);
dmix->state == SND_PCM_STATE_DRAINING) {
if ((err = snd_pcm_dmix_sync_ptr(pcm)) < 0)
return err;
}
return snd_pcm_mmap_playback_avail(pcm);
}