From 5e325ea18b096a721188738d2d49104e43cad11b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 29 Mar 2005 14:06:00 +0000 Subject: [PATCH] Delayed start for dmix Introducing a private state for the delayed start of PCM stream. This problem occurs when the rate plugin doesn't feed the data properly before triggering START. This results in weird problems, e.g. an inifinte loop of artsd eating 100% CPU time. To solve this problem, the state is marked as "pending" when no data appears at the trigger, and the stream is started later at the mmap commit. --- src/pcm/pcm_dmix.c | 56 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 42 insertions(+), 14 deletions(-) diff --git a/src/pcm/pcm_dmix.c b/src/pcm/pcm_dmix.c index a913c335..efdfeaa4 100644 --- a/src/pcm/pcm_dmix.c +++ b/src/pcm/pcm_dmix.c @@ -49,6 +49,9 @@ const char *_snd_module_pcm_dmix = ""; #endif +/* start is pending - this state happens when rate plugin does a delayed commit */ +#define STATE_RUN_PENDING 1024 + /* * */ @@ -300,8 +303,15 @@ static int snd_pcm_dmix_status(snd_pcm_t *pcm, snd_pcm_status_t * status) break; } memset(status, 0, sizeof(*status)); - state = snd_pcm_state(dmix->spcm); - status->state = state == SNDRV_PCM_STATE_RUNNING ? dmix->state : state; + if (dmix->state == STATE_RUN_PENDING) + status->state = SNDRV_PCM_STATE_RUNNING; + else { + state = snd_pcm_state(dmix->spcm); + if (state == SNDRV_PCM_STATE_RUNNING) + status->state = dmix->state; + else + status->state = state; + } status->trigger_tstamp = dmix->trigger_tstamp; status->tstamp = snd_pcm_hw_fast_tstamp(dmix->spcm); status->avail = snd_pcm_mmap_playback_avail(pcm); @@ -322,6 +332,8 @@ static snd_pcm_state_t snd_pcm_dmix_state(snd_pcm_t *pcm) default: break; } + if (dmix->state == STATE_RUN_PENDING) + return SNDRV_PCM_STATE_RUNNING; return dmix->state; } @@ -338,6 +350,7 @@ static int snd_pcm_dmix_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) return err; case SNDRV_PCM_STATE_PREPARED: case SNDRV_PCM_STATE_SUSPENDED: + case STATE_RUN_PENDING: *delayp = snd_pcm_mmap_playback_hw_avail(pcm); return 0; case SNDRV_PCM_STATE_XRUN: @@ -359,6 +372,7 @@ static int snd_pcm_dmix_hwsync(snd_pcm_t *pcm) return snd_pcm_dmix_sync_ptr(pcm); case SNDRV_PCM_STATE_PREPARED: case SNDRV_PCM_STATE_SUSPENDED: + case STATE_RUN_PENDING: return 0; case SNDRV_PCM_STATE_XRUN: return -EPIPE; @@ -399,18 +413,22 @@ static int snd_pcm_dmix_start(snd_pcm_t *pcm) if (dmix->state != SND_PCM_STATE_PREPARED) return -EBADFD; - err = snd_timer_start(dmix->timer); - if (err < 0) - return err; - dmix->state = SND_PCM_STATE_RUNNING; snd_pcm_hwsync(dmix->spcm); dmix->slave_appl_ptr = dmix->slave_hw_ptr = *dmix->spcm->hw.ptr; avail = snd_pcm_mmap_playback_hw_avail(pcm); - if (avail < 0) + if (avail == 0) + dmix->state = STATE_RUN_PENDING; + else if (avail < 0) return 0; - if (avail > (snd_pcm_sframes_t)pcm->buffer_size) - avail = pcm->buffer_size; - snd_pcm_dmix_sync_area(pcm, avail); + else { + if (avail > (snd_pcm_sframes_t)pcm->buffer_size) + avail = pcm->buffer_size; + err = snd_timer_start(dmix->timer); + if (err < 0) + return err; + dmix->state = SND_PCM_STATE_RUNNING; + snd_pcm_dmix_sync_area(pcm, avail); + } gettimeofday(&tv, 0); dmix->trigger_tstamp.tv_sec = tv.tv_sec; dmix->trigger_tstamp.tv_nsec = tv.tv_usec * 1000L; @@ -457,15 +475,19 @@ static int snd_pcm_dmix_pause(snd_pcm_t *pcm, int enable) { snd_pcm_direct_t *dmix = pcm->private_data; if (enable) { - if (dmix->state != SND_PCM_STATE_RUNNING) + if (dmix->state == SND_PCM_STATE_RUNNING) + snd_timer_stop(dmix->timer); + else if (dmix->state != STATE_RUN_PENDING) return -EBADFD; dmix->state = SND_PCM_STATE_PAUSED; - snd_timer_stop(dmix->timer); } else { if (dmix->state != SND_PCM_STATE_PAUSED) return -EBADFD; - dmix->state = SND_PCM_STATE_RUNNING; - snd_timer_start(dmix->timer); + if (snd_pcm_mmap_playback_hw_avail(pcm) > 0) { + dmix->state = SND_PCM_STATE_RUNNING; + snd_timer_start(dmix->timer); + } else + dmix->state = STATE_RUN_PENDING; } return 0; } @@ -553,6 +575,12 @@ static snd_pcm_sframes_t snd_pcm_dmix_mmap_commit(snd_pcm_t *pcm, break; } snd_pcm_mmap_appl_forward(pcm, size); + if (dmix->state == STATE_RUN_PENDING) { + err = snd_timer_start(dmix->timer); + if (err < 0) + return err; + dmix->state = SND_PCM_STATE_RUNNING; + } if (dmix->state == SND_PCM_STATE_RUNNING) { err = snd_pcm_dmix_sync_ptr(pcm); if (err < 0) -- 2.47.1