Esempio n. 1
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;
}
Esempio n. 2
0
/*
 *  synchronize hardware pointer (hw_ptr) with ours
 */
static int snd_pcm_dshare_sync_ptr(snd_pcm_t *pcm)
{
	snd_pcm_direct_t *dshare = pcm->private_data;
	snd_pcm_uframes_t slave_hw_ptr, old_slave_hw_ptr, avail;
	snd_pcm_sframes_t diff;
	
	switch (snd_pcm_state(dshare->spcm)) {
	case SND_PCM_STATE_DISCONNECTED:
		dshare->state = SNDRV_PCM_STATE_DISCONNECTED;
		return -ENODEV;
	default:
		break;
	}
	if (dshare->slowptr)
		snd_pcm_hwsync(dshare->spcm);
	old_slave_hw_ptr = dshare->slave_hw_ptr;
	slave_hw_ptr = dshare->slave_hw_ptr = *dshare->spcm->hw.ptr;
	diff = slave_hw_ptr - old_slave_hw_ptr;
	if (diff == 0)		/* fast path */
		return 0;
	if (dshare->state != SND_PCM_STATE_RUNNING &&
	    dshare->state != SND_PCM_STATE_DRAINING)
		/* not really started yet - don't update hw_ptr */
		return 0;
	if (diff < 0) {
		slave_hw_ptr += dshare->slave_boundary;
		diff = slave_hw_ptr - old_slave_hw_ptr;
	}
	dshare->hw_ptr += diff;
	dshare->hw_ptr %= pcm->boundary;
	// printf("sync ptr diff = %li\n", diff);
	if (pcm->stop_threshold >= pcm->boundary)	/* don't care */
		return 0;
	avail = snd_pcm_mmap_playback_avail(pcm);
	if (avail > dshare->avail_max)
		dshare->avail_max = avail;
	if (avail >= pcm->stop_threshold) {
		struct timeval tv;
		snd_timer_stop(dshare->timer);
		gettimeofday(&tv, 0);
		dshare->trigger_tstamp.tv_sec = tv.tv_sec;
		dshare->trigger_tstamp.tv_nsec = tv.tv_usec * 1000L;
		if (dshare->state == SND_PCM_STATE_RUNNING) {
			dshare->state = SND_PCM_STATE_XRUN;
			return -EPIPE;
		}
		dshare->state = SND_PCM_STATE_SETUP;
		/* clear queue to remove pending poll events */
		snd_pcm_direct_clear_timer_queue(dshare);
	}
	return 0;
}
Esempio n. 3
0
/*
 *  synchronize hardware pointer (hw_ptr) with ours
 */
static int snd_pcm_dmix_sync_ptr(snd_pcm_t *pcm)
{
	snd_pcm_direct_t *dmix = pcm->private_data;
	snd_pcm_uframes_t slave_hw_ptr, old_slave_hw_ptr, avail;
	snd_pcm_sframes_t diff;
	
	switch (snd_pcm_state(dmix->spcm)) {
	case SND_PCM_STATE_DISCONNECTED:
		dmix->state = SND_PCM_STATE_DISCONNECTED;
		return -ENODEV;
	default:
		break;
	}
	if (dmix->slowptr)
		snd_pcm_hwsync(dmix->spcm);
	old_slave_hw_ptr = dmix->slave_hw_ptr;
	slave_hw_ptr = dmix->slave_hw_ptr = *dmix->spcm->hw.ptr;
	diff = slave_hw_ptr - old_slave_hw_ptr;
	if (diff == 0)		/* fast path */
		return 0;
	if (dmix->state != SND_PCM_STATE_RUNNING &&
	    dmix->state != SND_PCM_STATE_DRAINING)
		/* not really started yet - don't update hw_ptr */
		return 0;
	if (diff < 0) {
		slave_hw_ptr += dmix->slave_boundary;
		diff = slave_hw_ptr - old_slave_hw_ptr;
	}
	dmix->hw_ptr += diff;
	dmix->hw_ptr %= pcm->boundary;
	if (pcm->stop_threshold >= pcm->boundary)	/* don't care */
		return 0;
	avail = snd_pcm_mmap_playback_avail(pcm);
	if (avail > dmix->avail_max)
		dmix->avail_max = avail;
	if (avail >= pcm->stop_threshold) {
		snd_timer_stop(dmix->timer);
		gettimestamp(&dmix->trigger_tstamp, pcm->tstamp_type);
		if (dmix->state == SND_PCM_STATE_RUNNING) {
			dmix->state = SND_PCM_STATE_XRUN;
			return -EPIPE;
		}
		dmix->state = SND_PCM_STATE_SETUP;
		/* clear queue to remove pending poll events */
		snd_pcm_direct_clear_timer_queue(dmix);
	}
	return 0;
}
Esempio n. 4
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;
}
Esempio n. 5
0
/*
 *  synchronize hardware pointer (hw_ptr) with ours
 */
static int snd_pcm_dshare_sync_ptr0(snd_pcm_t *pcm, snd_pcm_uframes_t slave_hw_ptr)
{
	snd_pcm_direct_t *dshare = pcm->private_data;
	snd_pcm_uframes_t old_slave_hw_ptr, avail;
	snd_pcm_sframes_t diff;
	
	old_slave_hw_ptr = dshare->slave_hw_ptr;
	dshare->slave_hw_ptr = slave_hw_ptr;
	diff = slave_hw_ptr - old_slave_hw_ptr;
	if (diff == 0)		/* fast path */
		return 0;
	if (dshare->state != SND_PCM_STATE_RUNNING &&
	    dshare->state != SND_PCM_STATE_DRAINING)
		/* not really started yet - don't update hw_ptr */
		return 0;
	if (diff < 0) {
		slave_hw_ptr += dshare->slave_boundary;
		diff = slave_hw_ptr - old_slave_hw_ptr;
	}
	dshare->hw_ptr += diff;
	dshare->hw_ptr %= pcm->boundary;
	// printf("sync ptr diff = %li\n", diff);
	if (pcm->stop_threshold >= pcm->boundary)	/* don't care */
		return 0;
	avail = snd_pcm_mmap_playback_avail(pcm);
	if (avail > dshare->avail_max)
		dshare->avail_max = avail;
	if (avail >= pcm->stop_threshold) {
		snd_timer_stop(dshare->timer);
		do_silence(pcm);
		gettimestamp(&dshare->trigger_tstamp, pcm->tstamp_type);
		if (dshare->state == SND_PCM_STATE_RUNNING) {
			dshare->state = SND_PCM_STATE_XRUN;
			return -EPIPE;
		}
		dshare->state = SND_PCM_STATE_SETUP;
		/* clear queue to remove pending poll events */
		snd_pcm_direct_clear_timer_queue(dshare);
	}
	return 0;
}