Пример #1
0
/* called in pcm lock */
snd_pcm_sframes_t snd_pcm_read_mmap(snd_pcm_t *pcm, snd_pcm_uframes_t offset,
				    snd_pcm_uframes_t size)
{
	snd_pcm_uframes_t xfer = 0;
	snd_pcm_sframes_t err = 0;
	if (! size)
		return 0;
	while (xfer < size) {
		snd_pcm_uframes_t frames = size - xfer;
		snd_pcm_uframes_t cont = pcm->buffer_size - offset;
		if (cont < frames)
			frames = cont;
		switch (pcm->access) {
		case SND_PCM_ACCESS_MMAP_INTERLEAVED:
		{
			const snd_pcm_channel_area_t *a = snd_pcm_mmap_areas(pcm);
			char *buf = snd_pcm_channel_area_addr(a, offset);
			snd_pcm_unlock(pcm); /* to avoid deadlock */
			err = _snd_pcm_readi(pcm, buf, frames);
			snd_pcm_lock(pcm);
			if (err >= 0)
				frames = err;
			break;
		}
		case SND_PCM_ACCESS_MMAP_NONINTERLEAVED:
		{
			snd_pcm_uframes_t channels = pcm->channels;
			unsigned int c;
			void *bufs[channels];
			const snd_pcm_channel_area_t *areas = snd_pcm_mmap_areas(pcm);
			for (c = 0; c < channels; ++c) {
				const snd_pcm_channel_area_t *a = &areas[c];
				bufs[c] = snd_pcm_channel_area_addr(a, offset);
			}
			snd_pcm_unlock(pcm); /* to avoid deadlock */
			err = _snd_pcm_readn(pcm->fast_op_arg, bufs, frames);
			snd_pcm_lock(pcm);
			if (err >= 0)
				frames = err;
			break;
		}
		default:
			SNDMSG("invalid access type %d", pcm->access);
			return -EINVAL;
		}
		if (err < 0)
			break;
		xfer += frames;
		offset = (offset + frames) % pcm->buffer_size;
	}
	if (xfer > 0)
		return xfer;
	return err;
}
Пример #2
0
/*
 *  synchronize shm ring buffer with hardware
 */
static void snd_pcm_dshare_sync_area(snd_pcm_t *pcm)
{
	snd_pcm_direct_t *dshare = pcm->private_data;
	snd_pcm_uframes_t slave_hw_ptr, slave_appl_ptr, slave_size;
	snd_pcm_uframes_t appl_ptr, size;
	const snd_pcm_channel_area_t *src_areas, *dst_areas;
	
	/* calculate the size to transfer */
	size = dshare->appl_ptr - dshare->last_appl_ptr;
	if (! size)
		return;
	slave_hw_ptr = dshare->slave_hw_ptr;
	/* don't write on the last active period - this area may be cleared
	 * by the driver during write operation...
	 */
	slave_hw_ptr -= slave_hw_ptr % dshare->slave_period_size;
	slave_hw_ptr += dshare->slave_buffer_size;
	if (dshare->slave_hw_ptr > dshare->slave_boundary)
		slave_hw_ptr -= dshare->slave_boundary;
	if (slave_hw_ptr < dshare->slave_appl_ptr)
		slave_size = slave_hw_ptr + (dshare->slave_boundary - dshare->slave_appl_ptr);
	else
		slave_size = slave_hw_ptr - dshare->slave_appl_ptr;
	if (slave_size < size)
		size = slave_size;
	if (! size)
		return;

	/* add sample areas here */
	src_areas = snd_pcm_mmap_areas(pcm);
	dst_areas = snd_pcm_mmap_areas(dshare->spcm);
	appl_ptr = dshare->last_appl_ptr % pcm->buffer_size;
	dshare->last_appl_ptr += size;
	dshare->last_appl_ptr %= pcm->boundary;
	slave_appl_ptr = dshare->slave_appl_ptr % dshare->slave_buffer_size;
	dshare->slave_appl_ptr += size;
	dshare->slave_appl_ptr %= dshare->slave_boundary;
	for (;;) {
		snd_pcm_uframes_t transfer = size;
		if (appl_ptr + transfer > pcm->buffer_size)
			transfer = pcm->buffer_size - appl_ptr;
		if (slave_appl_ptr + transfer > dshare->slave_buffer_size)
			transfer = dshare->slave_buffer_size - slave_appl_ptr;
		share_areas(dshare, src_areas, dst_areas, appl_ptr, slave_appl_ptr, transfer);
		size -= transfer;
		if (! size)
			break;
		slave_appl_ptr += transfer;
		slave_appl_ptr %= dshare->slave_buffer_size;
		appl_ptr += transfer;
		appl_ptr %= pcm->buffer_size;
	}
}
Пример #3
0
/*
 *  synchronize shm ring buffer with hardware
 */
static void snd_pcm_dmix_sync_area(snd_pcm_t *pcm)
{
	snd_pcm_direct_t *dmix = pcm->private_data;
	snd_pcm_uframes_t appl_ptr, slave_appl_ptr, slave_bsize;
	snd_pcm_uframes_t size, slave_hw_ptr;
	const snd_pcm_channel_area_t *src_areas, *dst_areas;
	
	/* calculate the size to transfer */
	size = dmix->appl_ptr - dmix->last_appl_ptr;
	if (! size)
		return;
	slave_bsize = dmix->shmptr->s.buffer_size;
	slave_hw_ptr = dmix->slave_hw_ptr;
	/* don't write on the last active period - this area may be cleared
	 * by the driver during mix operation...
	 */
	slave_hw_ptr -= slave_hw_ptr % dmix->shmptr->s.period_size;
	slave_hw_ptr += slave_bsize;
	if (dmix->slave_hw_ptr > dmix->slave_appl_ptr)
		slave_hw_ptr -= dmix->shmptr->s.boundary;
	if (dmix->slave_appl_ptr + size >= slave_hw_ptr)
		size = slave_hw_ptr - dmix->slave_appl_ptr;
	if (! size)
		return;
	/* add sample areas here */
	src_areas = snd_pcm_mmap_areas(pcm);
	dst_areas = snd_pcm_mmap_areas(dmix->spcm);
	appl_ptr = dmix->last_appl_ptr % pcm->buffer_size;
	dmix->last_appl_ptr += size;
	dmix->last_appl_ptr %= pcm->boundary;
	slave_appl_ptr = dmix->slave_appl_ptr % slave_bsize;
	dmix->slave_appl_ptr += size;
	dmix->slave_appl_ptr %= dmix->shmptr->s.boundary;
	dmix_down_sem(dmix);
	for (;;) {
		snd_pcm_uframes_t transfer = size;
		if (appl_ptr + transfer > pcm->buffer_size)
			transfer = pcm->buffer_size - appl_ptr;
		if (slave_appl_ptr + transfer > slave_bsize)
			transfer = slave_bsize - slave_appl_ptr;
		mix_areas(dmix, src_areas, dst_areas, appl_ptr, slave_appl_ptr, transfer);
		size -= transfer;
		if (! size)
			break;
		slave_appl_ptr += transfer;
		slave_appl_ptr %= slave_bsize;
		appl_ptr += transfer;
		appl_ptr %= pcm->buffer_size;
	}
	dmix_up_sem(dmix);
}
Пример #4
0
/*
 *  synchronize shm ring buffer with hardware
 */
static void snd_pcm_dsnoop_sync_area(snd_pcm_t *pcm, snd_pcm_uframes_t slave_hw_ptr, snd_pcm_uframes_t size)
{
	snd_pcm_direct_t *dsnoop = pcm->private_data;
	snd_pcm_uframes_t hw_ptr = dsnoop->hw_ptr;
	snd_pcm_uframes_t transfer;
	const snd_pcm_channel_area_t *src_areas, *dst_areas;
	
	/* add sample areas here */
	dst_areas = snd_pcm_mmap_areas(pcm);
	src_areas = snd_pcm_mmap_areas(dsnoop->spcm);
	hw_ptr %= pcm->buffer_size;
	slave_hw_ptr %= dsnoop->slave_buffer_size;
	while (size > 0) {
		transfer = hw_ptr + size > pcm->buffer_size ? pcm->buffer_size - hw_ptr : size;
		transfer = slave_hw_ptr + transfer > dsnoop->slave_buffer_size ?
			dsnoop->slave_buffer_size - slave_hw_ptr : transfer;
		size -= transfer;
		snoop_areas(dsnoop, src_areas, dst_areas, slave_hw_ptr, hw_ptr, transfer);
		slave_hw_ptr += transfer;
	 	slave_hw_ptr %= dsnoop->slave_buffer_size;
		hw_ptr += transfer;
		hw_ptr %= pcm->buffer_size;
	}
}
Пример #5
0
static void do_silence(snd_pcm_t *pcm)
{
	snd_pcm_direct_t *dshare = pcm->private_data;
	const snd_pcm_channel_area_t *dst_areas;
	unsigned int chn, dchn, channels;
	snd_pcm_format_t format;

	dst_areas = snd_pcm_mmap_areas(dshare->spcm);
	channels = dshare->channels;
	format = dshare->shmptr->s.format;
	for (chn = 0; chn < channels; chn++) {
		dchn = dshare->bindings ? dshare->bindings[chn] : chn;
		snd_pcm_area_silence(&dst_areas[dchn], 0, dshare->shmptr->s.buffer_size, format);
	}
}
Пример #6
0
/*
 *  synchronize shm ring buffer with hardware
 */
static void snd_pcm_dmix_sync_area(snd_pcm_t *pcm)
{
	snd_pcm_direct_t *dmix = pcm->private_data;
	snd_pcm_uframes_t slave_hw_ptr, slave_appl_ptr, slave_size;
	snd_pcm_uframes_t appl_ptr, size, transfer;
	const snd_pcm_channel_area_t *src_areas, *dst_areas;
	
	/* calculate the size to transfer */
	/* check the available size in the local buffer
	 * last_appl_ptr keeps the last updated position
	 */
	size = dmix->appl_ptr - dmix->last_appl_ptr;
	if (! size)
		return;
	if (size >= pcm->boundary / 2)
		size = pcm->boundary - size;

	/* the slave_app_ptr can be far behind the slave_hw_ptr */
	/* reduce mixing and errors here - just skip not catched writes */
	if (dmix->slave_hw_ptr <= dmix->slave_appl_ptr)
		slave_size = dmix->slave_appl_ptr - dmix->slave_hw_ptr;
	else
		slave_size = dmix->slave_appl_ptr + (dmix->slave_boundary - dmix->slave_hw_ptr);
	if (slave_size > dmix->slave_buffer_size) {
		transfer = dmix->slave_buffer_size - slave_size;
		if (transfer > size)
			transfer = size;
		dmix->last_appl_ptr += transfer;
		dmix->last_appl_ptr %= pcm->boundary;
		dmix->slave_appl_ptr += transfer;
		dmix->slave_appl_ptr %= dmix->slave_boundary;
		size = dmix->appl_ptr - dmix->last_appl_ptr;
		if (! size)
			return;
		if (size >= pcm->boundary / 2)
			size = pcm->boundary - size;
	}

	/* check the available size in the slave PCM buffer */
	slave_hw_ptr = dmix->slave_hw_ptr;
	/* don't write on the last active period - this area may be cleared
	 * by the driver during mix operation...
	 */
	slave_hw_ptr -= slave_hw_ptr % dmix->slave_period_size;
	slave_hw_ptr += dmix->slave_buffer_size;
	if (slave_hw_ptr >= dmix->slave_boundary)
		slave_hw_ptr -= dmix->slave_boundary;
	if (slave_hw_ptr < dmix->slave_appl_ptr)
		slave_size = slave_hw_ptr + (dmix->slave_boundary - dmix->slave_appl_ptr);
	else
		slave_size = slave_hw_ptr - dmix->slave_appl_ptr;
	if (slave_size < size)
		size = slave_size;
	if (! size)
		return;

	/* add sample areas here */
	src_areas = snd_pcm_mmap_areas(pcm);
	dst_areas = snd_pcm_mmap_areas(dmix->spcm);
	appl_ptr = dmix->last_appl_ptr % pcm->buffer_size;
	dmix->last_appl_ptr += size;
	dmix->last_appl_ptr %= pcm->boundary;
	slave_appl_ptr = dmix->slave_appl_ptr % dmix->slave_buffer_size;
	dmix->slave_appl_ptr += size;
	dmix->slave_appl_ptr %= dmix->slave_boundary;
	dmix_down_sem(dmix);
	for (;;) {
		transfer = size;
		if (appl_ptr + transfer > pcm->buffer_size)
			transfer = pcm->buffer_size - appl_ptr;
		if (slave_appl_ptr + transfer > dmix->slave_buffer_size)
			transfer = dmix->slave_buffer_size - slave_appl_ptr;
		mix_areas(dmix, src_areas, dst_areas, appl_ptr, slave_appl_ptr, transfer);
		size -= transfer;
		if (! size)
			break;
		slave_appl_ptr += transfer;
		slave_appl_ptr %= dmix->slave_buffer_size;
		appl_ptr += transfer;
		appl_ptr %= pcm->buffer_size;
	}
	dmix_up_sem(dmix);
}