static int snd_pcm_dshare_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) { snd_pcm_direct_t *dshare = pcm->private_data; int err; switch (dshare->state) { case SNDRV_PCM_STATE_DRAINING: case SNDRV_PCM_STATE_RUNNING: err = snd_pcm_dshare_sync_ptr(pcm); if (err < 0) return err; /* fallthru */ 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: return -EPIPE; case SNDRV_PCM_STATE_DISCONNECTED: return -ENODEV; default: return -EBADFD; } }
/* locked version */ static int __snd_pcm_dshare_drain(snd_pcm_t *pcm) { snd_pcm_direct_t *dshare = pcm->private_data; snd_pcm_uframes_t stop_threshold; int err; switch (snd_pcm_state(dshare->spcm)) { case SND_PCM_STATE_SUSPENDED: return -ESTRPIPE; default: break; } if (dshare->state == SND_PCM_STATE_OPEN) return -EBADFD; if (pcm->mode & SND_PCM_NONBLOCK) return -EAGAIN; if (dshare->state == SND_PCM_STATE_PREPARED) { if (snd_pcm_mmap_playback_hw_avail(pcm) > 0) snd_pcm_dshare_start(pcm); else { snd_pcm_dshare_drop(pcm); return 0; } } if (dshare->state == SND_PCM_STATE_XRUN) { snd_pcm_dshare_drop(pcm); return 0; } stop_threshold = pcm->stop_threshold; if (pcm->stop_threshold > pcm->buffer_size) pcm->stop_threshold = pcm->buffer_size; dshare->state = SND_PCM_STATE_DRAINING; do { err = snd_pcm_dshare_sync_ptr(pcm); if (err < 0) { snd_pcm_dshare_drop(pcm); break; } if (dshare->state == SND_PCM_STATE_DRAINING) { snd_pcm_dshare_sync_area(pcm); snd_pcm_wait_nocheck(pcm, -1); snd_pcm_direct_clear_timer_queue(dshare); /* force poll to wait */ switch (snd_pcm_state(dshare->spcm)) { case SND_PCM_STATE_SUSPENDED: return -ESTRPIPE; default: break; } } } while (dshare->state == SND_PCM_STATE_DRAINING); pcm->stop_threshold = stop_threshold; return 0; }
static int snd_pcm_dshare_hwsync(snd_pcm_t *pcm) { snd_pcm_direct_t *dshare = pcm->private_data; switch(dshare->state) { case SNDRV_PCM_STATE_DRAINING: case SNDRV_PCM_STATE_RUNNING: return snd_pcm_dshare_sync_ptr(pcm); case SNDRV_PCM_STATE_PREPARED: case SNDRV_PCM_STATE_SUSPENDED: return 0; case SNDRV_PCM_STATE_XRUN: return -EPIPE; case SNDRV_PCM_STATE_DISCONNECTED: return -ENODEV; default: return -EBADFD; } }
static int snd_pcm_dshare_status(snd_pcm_t *pcm, snd_pcm_status_t * status) { snd_pcm_direct_t *dshare = pcm->private_data; switch (dshare->state) { case SNDRV_PCM_STATE_DRAINING: case SNDRV_PCM_STATE_RUNNING: snd_pcm_dshare_sync_ptr(pcm); break; default: break; } memset(status, 0, sizeof(*status)); status->state = snd_pcm_state(dshare->spcm); status->trigger_tstamp = dshare->trigger_tstamp; status->tstamp = snd_pcm_hw_fast_tstamp(dshare->spcm); status->avail = snd_pcm_mmap_playback_avail(pcm); status->avail_max = status->avail > dshare->avail_max ? status->avail : dshare->avail_max; dshare->avail_max = 0; return 0; }