Exemple #1
0
static void CheckXRUN(IDsDriverBufferImpl* This)
{
    snd_pcm_state_t state = snd_pcm_state(This->pcm);
    snd_pcm_sframes_t delay;
    int err;

    snd_pcm_hwsync(This->pcm);
    snd_pcm_delay(This->pcm, &delay);
    if ( state == SND_PCM_STATE_XRUN )
    {
        err = snd_pcm_prepare(This->pcm);
        CommitAll(This);
        snd_pcm_start(This->pcm);
        WARN("xrun occurred\n");
        if ( err < 0 )
            ERR("recovery from xrun failed, prepare failed: %s\n", snd_strerror(err));
    }
    else if ( state == SND_PCM_STATE_SUSPENDED )
    {
        int err = snd_pcm_resume(This->pcm);
        TRACE("recovery from suspension occurred\n");
        if (err < 0 && err != -EAGAIN){
            err = snd_pcm_prepare(This->pcm);
            if (err < 0)
                ERR("recovery from suspend failed, prepare failed: %s\n", snd_strerror(err));
        }
    } else if ( state != SND_PCM_STATE_RUNNING ) {
        FIXME("Unhandled state: %d\n", state);
    }
}
static int snd_pcm_ioctl_sync_ptr_compat(struct snd_pcm_substream *substream,
					 struct snd_pcm_sync_ptr32 __user *src)
{
	struct snd_pcm_runtime *runtime = substream->runtime;
	volatile struct snd_pcm_mmap_status *status;
	volatile struct snd_pcm_mmap_control *control;
	u32 sflags;
	struct snd_pcm_mmap_control scontrol;
	struct snd_pcm_mmap_status sstatus;
	snd_pcm_uframes_t boundary;
	int err;

	if (snd_BUG_ON(!runtime))
		return -EINVAL;

	if (get_user(sflags, &src->flags) ||
	    get_user(scontrol.appl_ptr, &src->c.control.appl_ptr) ||
	    get_user(scontrol.avail_min, &src->c.control.avail_min))
		return -EFAULT;
	if (sflags & SNDRV_PCM_SYNC_PTR_HWSYNC) {
		err = snd_pcm_hwsync(substream);
		if (err < 0)
			return err;
	}
	status = runtime->status;
	control = runtime->control;
	boundary = recalculate_boundary(runtime);
	if (! boundary)
		boundary = 0x7fffffff;
	snd_pcm_stream_lock_irq(substream);
	/* FIXME: we should consider the boundary for the sync from app */
	if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL))
		control->appl_ptr = scontrol.appl_ptr;
	else
		scontrol.appl_ptr = control->appl_ptr % boundary;
	if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
		control->avail_min = scontrol.avail_min;
	else
		scontrol.avail_min = control->avail_min;
	sstatus.state = status->state;
	sstatus.hw_ptr = status->hw_ptr % boundary;
	sstatus.tstamp = status->tstamp;
	sstatus.suspended_state = status->suspended_state;
	sstatus.audio_tstamp = status->audio_tstamp;
	snd_pcm_stream_unlock_irq(substream);
	if (put_user(sstatus.state, &src->s.status.state) ||
	    put_user(sstatus.hw_ptr, &src->s.status.hw_ptr) ||
	    compat_put_timespec(&sstatus.tstamp, &src->s.status.tstamp) ||
	    put_user(sstatus.suspended_state, &src->s.status.suspended_state) ||
	    compat_put_timespec(&sstatus.audio_tstamp,
		    &src->s.status.audio_tstamp) ||
	    put_user(scontrol.appl_ptr, &src->c.control.appl_ptr) ||
	    put_user(scontrol.avail_min, &src->c.control.avail_min))
		return -EFAULT;

	return 0;
}
static int snd_pcm_dmix_start_timer(snd_pcm_t *pcm, snd_pcm_direct_t *dmix)
{
	int err;

	snd_pcm_hwsync(dmix->spcm);
	reset_slave_ptr(pcm, dmix);
	err = snd_timer_start(dmix->timer);
	if (err < 0)
		return err;
	dmix->state = SND_PCM_STATE_RUNNING;
	return 0;
}
Exemple #4
0
static int snd_pcm_dshare_start_timer(snd_pcm_direct_t *dshare)
{
	int err;

	snd_pcm_hwsync(dshare->spcm);
	dshare->slave_appl_ptr = dshare->slave_hw_ptr = *dshare->spcm->hw.ptr;
	err = snd_timer_start(dshare->timer);
	if (err < 0)
		return err;
	dshare->state = SND_PCM_STATE_RUNNING;
	return 0;
}
Exemple #5
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;
}
Exemple #6
0
static void *peeper(void *data)
{
	int thread_no = (long)data;
	snd_pcm_sframes_t val;
	snd_pcm_status_t *stat;
	snd_htimestamp_t tstamp;
	int mode = running_mode, err;

	snd_pcm_status_alloca(&stat);

	while (running) {
		if (running_mode == MODE_RANDOM)
			mode = rand() % MODE_RANDOM;
		switch (mode) {
		case MODE_AVAIL_UPDATE:
			val = snd_pcm_avail_update(pcm);
			err = 0;
			break;
		case MODE_STATUS:
			err = snd_pcm_status(pcm, stat);
			val = snd_pcm_status_get_avail(stat);
			break;
		case MODE_HWSYNC:
			err = snd_pcm_hwsync(pcm);
			break;
		case MODE_TIMESTAMP:
			err = snd_pcm_htimestamp(pcm, (snd_pcm_uframes_t *)&val,
						 &tstamp);
			break;
		default:
			err = snd_pcm_delay(pcm, &val);
			break;
		}

		if (quiet)
			continue;
		if (running_mode == MODE_RANDOM) {
			fprintf(stderr, "%d%c%s", thread_no, mode_suffix[mode],
				err ? "!" : "");
		} else {
			if (show_value && mode != MODE_HWSYNC)
				fprintf(stderr, "\r%d     ", (int)val);
			else
				fprintf(stderr, "%d%s", thread_no,
					err ? "!" : "");
		}
	}
	return NULL;
}
/*
 *  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;
}
Exemple #8
0
static int snd_pcm_dsnoop_start(snd_pcm_t *pcm)
{
	snd_pcm_direct_t *dsnoop = pcm->private_data;
	int err;
	
	if (dsnoop->state != SND_PCM_STATE_PREPARED)
		return -EBADFD;
	snd_pcm_hwsync(dsnoop->spcm);
	snoop_timestamp(pcm);
	dsnoop->slave_appl_ptr = dsnoop->slave_hw_ptr;
	err = snd_timer_start(dsnoop->timer);
	if (err < 0)
		return err;
	dsnoop->state = SND_PCM_STATE_RUNNING;
	dsnoop->trigger_tstamp = dsnoop->update_tstamp;
	return 0;
}
Exemple #9
0
static int snd_pcm_dshare_sync_ptr(snd_pcm_t *pcm)
{
	snd_pcm_direct_t *dshare = pcm->private_data;

	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);

	return snd_pcm_dshare_sync_ptr0(pcm, *dshare->spcm->hw.ptr);
}
Exemple #10
0
/*
 *  synchronize hardware pointer (hw_ptr) with ours
 */
static int snd_pcm_dsnoop_sync_ptr(snd_pcm_t *pcm)
{
	snd_pcm_direct_t *dsnoop = pcm->private_data;
	snd_pcm_uframes_t slave_hw_ptr, old_slave_hw_ptr, avail;
	snd_pcm_sframes_t diff;
	
	switch (snd_pcm_state(dsnoop->spcm)) {
	case SND_PCM_STATE_DISCONNECTED:
		dsnoop->state = SNDRV_PCM_STATE_DISCONNECTED;
		return -ENODEV;
	default:
		break;
	}
	if (dsnoop->slowptr)
		snd_pcm_hwsync(dsnoop->spcm);
	old_slave_hw_ptr = dsnoop->slave_hw_ptr;
	snoop_timestamp(pcm);
	slave_hw_ptr = dsnoop->slave_hw_ptr;
	diff = slave_hw_ptr - old_slave_hw_ptr;
	if (diff == 0)		/* fast path */
		return 0;
	if (diff < 0) {
		slave_hw_ptr += dsnoop->slave_boundary;
		diff = slave_hw_ptr - old_slave_hw_ptr;
	}
	snd_pcm_dsnoop_sync_area(pcm, old_slave_hw_ptr, diff);
	dsnoop->hw_ptr += diff;
	dsnoop->hw_ptr %= pcm->boundary;
	// printf("sync ptr diff = %li\n", diff);
	if (pcm->stop_threshold >= pcm->boundary)	/* don't care */
		return 0;
	if ((avail = snd_pcm_mmap_capture_hw_avail(pcm)) >= pcm->stop_threshold) {
		gettimestamp(&dsnoop->trigger_tstamp, pcm->monotonic);
		dsnoop->state = SND_PCM_STATE_XRUN;
		dsnoop->avail_max = avail;
		return -EPIPE;
	}
	if (avail > dsnoop->avail_max)
		dsnoop->avail_max = avail;
	return 0;
}
Exemple #11
0
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);

	return snd_pcm_dmix_sync_ptr0(pcm, *dmix->spcm->hw.ptr);
}
int snd_pcm_generic_hwsync(snd_pcm_t *pcm)
{
    snd_pcm_generic_t *generic = pcm->private_data;
    return snd_pcm_hwsync(generic->slave);
}
Exemple #13
0
static
void
data_available_for_stream(pa_mainloop_api *a, pa_io_event *ioe, int fd, pa_io_event_flags_t events,
                          void *userdata)
{
    pa_stream          *s = userdata;
    snd_pcm_sframes_t   frame_count;
    size_t              frame_size = pa_frame_size(&s->ss);
    char                buf[16 * 1024];
    int                 paused = g_atomic_int_get(&s->paused);

    if (events & (PA_IO_EVENT_INPUT | PA_IO_EVENT_OUTPUT)) {

#if HAVE_SND_PCM_AVAIL
        frame_count = snd_pcm_avail(s->ph);
#else
        snd_pcm_hwsync(s->ph);
        frame_count = snd_pcm_avail_update(s->ph);
#endif

        if (frame_count < 0) {
            if (frame_count == -EBADFD) {
                // stream was closed
                return;
            }

            int cnt = 0, ret;
            do {
                cnt ++;
                ret = snd_pcm_recover(s->ph, frame_count, 1);
            } while (ret == -1 && errno == EINTR && cnt < 5);

#if HAVE_SND_PCM_AVAIL
            frame_count = snd_pcm_avail(s->ph);
#else
            snd_pcm_hwsync(s->ph);
            frame_count = snd_pcm_avail_update(s->ph);
#endif

            if (frame_count < 0) {
                trace_error("%s, can't recover after failed snd_pcm_avail (%d)\n", __func__,
                            (int)frame_count);
                return;
            }
        }
    } else {
        return;
    }

    if (events & PA_IO_EVENT_OUTPUT) {
        if (paused) {
            // client stream is corked. Pass silence to ALSA
            size_t bytecnt = MIN(sizeof(buf), frame_count * frame_size);
            memset(buf, 0, bytecnt);
            snd_pcm_writei(s->ph, buf, bytecnt / frame_size);
        } else {
            size_t writable_size = pa_stream_writable_size(s);

            if (s->write_cb && writable_size > 0)
                s->write_cb(s, writable_size, s->write_cb_userdata);

            size_t bytecnt = MIN(sizeof(buf), frame_count * frame_size);
            bytecnt = ringbuffer_read(s->rb, buf, bytecnt);

            if (bytecnt == 0) {
                // application is not ready yet, play silence
                bytecnt = MIN(sizeof(buf), frame_count * frame_size);
                memset(buf, 0, bytecnt);
            }
            snd_pcm_writei(s->ph, buf, bytecnt / frame_size);
        }
    }

    if (events & PA_IO_EVENT_INPUT) {
        if (paused) {
            // client stream is corked. Read data from ALSA and discard them
            size_t bytecnt = MIN(sizeof(buf), frame_count * frame_size);
            snd_pcm_readi(s->ph, buf, bytecnt / frame_size);
        } else {
            size_t bytecnt = ringbuffer_writable_size(s->rb);

            if (bytecnt == 0) {
                // ringbuffer is full because app doesn't read data fast enough.
                // Make some room
                ringbuffer_drop(s->rb, frame_count * frame_size);
                bytecnt = ringbuffer_writable_size(s->rb);
            }

            bytecnt = MIN(bytecnt, frame_count * frame_size);
            bytecnt = MIN(bytecnt, sizeof(buf));

            if (bytecnt > 0) {
                snd_pcm_readi(s->ph, buf, bytecnt / frame_size);
                ringbuffer_write(s->rb, buf, bytecnt);
            }

            size_t readable_size = pa_stream_readable_size(s);
            if (s->read_cb && readable_size > 0)
                s->read_cb(s, readable_size, s->read_cb_userdata);
        }
    }
}