示例#1
0
static int snd_pcm_dmix_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
{
	snd_pcm_direct_t *dmix = pcm->private_data;
	int err;
	
	switch(dmix->state) {
	case SNDRV_PCM_STATE_DRAINING:
	case SNDRV_PCM_STATE_RUNNING:
		err = snd_pcm_dmix_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;
	}
}
示例#2
0
/* locked version */
static int __snd_pcm_dmix_drain(snd_pcm_t *pcm)
{
	snd_pcm_direct_t *dmix = pcm->private_data;
	snd_pcm_uframes_t stop_threshold;
	int err;

	switch (snd_pcm_state(dmix->spcm)) {
	case SND_PCM_STATE_SUSPENDED:
		return -ESTRPIPE;
	default:
		break;
	}

	if (dmix->state == SND_PCM_STATE_OPEN)
		return -EBADFD;
	if (pcm->mode & SND_PCM_NONBLOCK)
		return -EAGAIN;
	if (dmix->state == SND_PCM_STATE_PREPARED) {
		if (snd_pcm_mmap_playback_hw_avail(pcm) > 0)
			snd_pcm_dmix_start(pcm);
		else {
			snd_pcm_dmix_drop(pcm);
			return 0;
		}
	}

	if (dmix->state == SND_PCM_STATE_XRUN) {
		snd_pcm_dmix_drop(pcm);
		return 0;
	}

	stop_threshold = pcm->stop_threshold;
	if (pcm->stop_threshold > pcm->buffer_size)
		pcm->stop_threshold = pcm->buffer_size;
	dmix->state = SND_PCM_STATE_DRAINING;
	do {
		err = snd_pcm_dmix_sync_ptr(pcm);
		if (err < 0) {
			snd_pcm_dmix_drop(pcm);
			return err;
		}
		if (dmix->state == SND_PCM_STATE_DRAINING) {
			snd_pcm_dmix_sync_area(pcm);
			snd_pcm_wait_nocheck(pcm, -1);
			snd_pcm_direct_clear_timer_queue(dmix); /* force poll to wait */

			switch (snd_pcm_state(dmix->spcm)) {
			case SND_PCM_STATE_SUSPENDED:
				return -ESTRPIPE;
			default:
				break;
			}
		}
	} while (dmix->state == SND_PCM_STATE_DRAINING);
	pcm->stop_threshold = stop_threshold;
	return 0;
}
示例#3
0
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;

	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 */
		}
	} while (dshare->state == SND_PCM_STATE_DRAINING);
	pcm->stop_threshold = stop_threshold;
	return 0;
}
示例#4
0
static int snd_pcm_dmix_start(snd_pcm_t *pcm)
{
	snd_pcm_direct_t *dmix = pcm->private_data;
	snd_pcm_sframes_t avail;
	int err;
	
	if (dmix->state != SND_PCM_STATE_PREPARED)
		return -EBADFD;
	avail = snd_pcm_mmap_playback_hw_avail(pcm);
	if (avail == 0)
		dmix->state = STATE_RUN_PENDING;
	else if (avail < 0)
		return 0;
	else {
		if ((err = snd_pcm_dmix_start_timer(pcm, dmix)) < 0)
			return err;
		snd_pcm_dmix_sync_area(pcm);
	}
	gettimestamp(&dmix->trigger_tstamp, pcm->tstamp_type);
	return 0;
}
示例#5
0
static int snd_pcm_dshare_start(snd_pcm_t *pcm)
{
	snd_pcm_direct_t *dshare = pcm->private_data;
	snd_pcm_sframes_t avail;
	struct timeval tv;
	int err;
	
	if (dshare->state != SND_PCM_STATE_PREPARED)
		return -EBADFD;
	avail = snd_pcm_mmap_playback_hw_avail(pcm);
	if (avail == 0)
		dshare->state = STATE_RUN_PENDING;
	else if (avail < 0)
		return 0;
	else {
		if ((err = snd_pcm_dshare_start_timer(dshare)) < 0)
			return err;
		snd_pcm_dshare_sync_area(pcm);
	}
	gettimeofday(&tv, 0);
	dshare->trigger_tstamp.tv_sec = tv.tv_sec;
	dshare->trigger_tstamp.tv_nsec = tv.tv_usec * 1000L;
	return 0;
}