mirror of
				https://github.com/alsa-project/alsa-lib.git
				synced 2025-11-03 09:01:52 -05:00 
			
		
		
		
	Cleaned the mmap_commit implementations in plugins.
Added undo callbacks for snd_pcm_plugin based plugins. - helpers when mmap_commit proceed only a partial transfer Fixes to avail_update implementation in pcm_hw.c.
This commit is contained in:
		
							parent
							
								
									9b0eebbcb7
								
							
						
					
					
						commit
						e128bf856e
					
				
					 22 changed files with 260 additions and 120 deletions
				
			
		| 
						 | 
				
			
			@ -5122,7 +5122,7 @@ int snd_pcm_mmap_begin(snd_pcm_t *pcm,
 | 
			
		|||
	f = *frames;
 | 
			
		||||
	avail = snd_pcm_mmap_avail(pcm);
 | 
			
		||||
	if (avail > pcm->buffer_size)
 | 
			
		||||
		return -EPIPE;
 | 
			
		||||
		avail = pcm->buffer_size;
 | 
			
		||||
	if (f > avail)
 | 
			
		||||
		f = avail;
 | 
			
		||||
	if (f > cont)
 | 
			
		||||
| 
						 | 
				
			
			@ -5187,26 +5187,10 @@ snd_pcm_sframes_t snd_pcm_mmap_commit(snd_pcm_t *pcm,
 | 
			
		|||
				      snd_pcm_uframes_t offset,
 | 
			
		||||
				      snd_pcm_uframes_t frames)
 | 
			
		||||
{
 | 
			
		||||
	int res;
 | 
			
		||||
	snd_pcm_uframes_t appl_ptr;
 | 
			
		||||
 | 
			
		||||
	assert(pcm);
 | 
			
		||||
	assert(offset == *pcm->appl_ptr % pcm->buffer_size);
 | 
			
		||||
	assert(frames <= snd_pcm_mmap_avail(pcm));
 | 
			
		||||
	appl_ptr = *pcm->appl_ptr;
 | 
			
		||||
	res = pcm->fast_ops->mmap_commit(pcm->fast_op_arg, offset, frames);
 | 
			
		||||
	if (res < 0) {
 | 
			
		||||
		snd_pcm_sframes_t diff;
 | 
			
		||||
 | 
			
		||||
		if (appl_ptr == *pcm->appl_ptr)
 | 
			
		||||
			return res;
 | 
			
		||||
		diff = *pcm->appl_ptr - appl_ptr;
 | 
			
		||||
		if (diff < 0)
 | 
			
		||||
			diff += pcm->boundary;
 | 
			
		||||
		assert(diff >= 0 && (snd_pcm_uframes_t)diff < pcm->boundary);
 | 
			
		||||
		return diff;
 | 
			
		||||
	}
 | 
			
		||||
	return frames;
 | 
			
		||||
	return pcm->fast_ops->mmap_commit(pcm->fast_op_arg, offset, frames);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifndef DOC_HIDDEN
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -553,6 +553,7 @@ int snd_pcm_adpcm_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sfor
 | 
			
		|||
		return -ENOMEM;
 | 
			
		||||
	}
 | 
			
		||||
	adpcm->sformat = sformat;
 | 
			
		||||
	snd_pcm_plugin_init(&adpcm->plug);
 | 
			
		||||
	adpcm->plug.read = snd_pcm_adpcm_read_areas;
 | 
			
		||||
	adpcm->plug.write = snd_pcm_adpcm_write_areas;
 | 
			
		||||
	adpcm->plug.init = snd_pcm_adpcm_init;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -424,9 +424,12 @@ int snd_pcm_alaw_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sform
 | 
			
		|||
	if (!alaw) {
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	}
 | 
			
		||||
	snd_pcm_plugin_init(&alaw->plug);
 | 
			
		||||
	alaw->sformat = sformat;
 | 
			
		||||
	alaw->plug.read = snd_pcm_alaw_read_areas;
 | 
			
		||||
	alaw->plug.write = snd_pcm_alaw_write_areas;
 | 
			
		||||
	alaw->plug.undo_read = snd_pcm_plugin_undo_read_generic;
 | 
			
		||||
	alaw->plug.undo_write = snd_pcm_plugin_undo_write_generic;
 | 
			
		||||
	alaw->plug.slave = slave;
 | 
			
		||||
	alaw->plug.close_slave = close_slave;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -188,8 +188,11 @@ int snd_pcm_copy_open(snd_pcm_t **pcmp, const char *name, snd_pcm_t *slave, int
 | 
			
		|||
	if (!copy) {
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	}
 | 
			
		||||
	snd_pcm_plugin_init(©->plug);
 | 
			
		||||
	copy->plug.read = snd_pcm_copy_read_areas;
 | 
			
		||||
	copy->plug.write = snd_pcm_copy_write_areas;
 | 
			
		||||
	copy->plug.undo_read = snd_pcm_plugin_undo_read_generic;
 | 
			
		||||
	copy->plug.undo_write = snd_pcm_plugin_undo_write_generic;
 | 
			
		||||
	copy->plug.slave = slave;
 | 
			
		||||
	copy->plug.close_slave = close_slave;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -86,7 +86,8 @@ static void snd_pcm_file_write_bytes(snd_pcm_t *pcm, size_t bytes)
 | 
			
		|||
 | 
			
		||||
static void snd_pcm_file_add_frames(snd_pcm_t *pcm, 
 | 
			
		||||
				    const snd_pcm_channel_area_t *areas,
 | 
			
		||||
				    snd_pcm_uframes_t offset, snd_pcm_uframes_t frames)
 | 
			
		||||
				    snd_pcm_uframes_t offset,
 | 
			
		||||
				    snd_pcm_uframes_t frames)
 | 
			
		||||
{
 | 
			
		||||
	snd_pcm_file_t *file = pcm->private_data;
 | 
			
		||||
	while (frames > 0) {
 | 
			
		||||
| 
						 | 
				
			
			@ -290,19 +291,22 @@ static snd_pcm_sframes_t snd_pcm_file_readn(snd_pcm_t *pcm, void **bufs, snd_pcm
 | 
			
		|||
	return n;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int snd_pcm_file_mmap_commit(snd_pcm_t *pcm,
 | 
			
		||||
				    snd_pcm_uframes_t offset,
 | 
			
		||||
				    snd_pcm_uframes_t size)
 | 
			
		||||
static snd_pcm_sframes_t snd_pcm_file_mmap_commit(snd_pcm_t *pcm,
 | 
			
		||||
					          snd_pcm_uframes_t offset,
 | 
			
		||||
						  snd_pcm_uframes_t size)
 | 
			
		||||
{
 | 
			
		||||
	snd_pcm_file_t *file = pcm->private_data;
 | 
			
		||||
	snd_pcm_uframes_t ofs;
 | 
			
		||||
	snd_pcm_uframes_t siz = size;
 | 
			
		||||
	const snd_pcm_channel_area_t *areas;
 | 
			
		||||
	snd_pcm_sframes_t result;
 | 
			
		||||
 | 
			
		||||
	snd_pcm_mmap_begin(file->slave, &areas, &ofs, &siz);
 | 
			
		||||
	assert(ofs == offset && siz == size);
 | 
			
		||||
	snd_pcm_mmap_commit(file->slave, ofs, siz);
 | 
			
		||||
	snd_pcm_file_add_frames(pcm, areas, ofs, siz);
 | 
			
		||||
	return 0;
 | 
			
		||||
	result = snd_pcm_mmap_commit(file->slave, ofs, siz);
 | 
			
		||||
	if (result > 0)
 | 
			
		||||
		snd_pcm_file_add_frames(pcm, areas, ofs, result);
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static snd_pcm_sframes_t snd_pcm_file_avail_update(snd_pcm_t *pcm)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -194,9 +194,9 @@ static snd_pcm_sframes_t snd_pcm_hooks_readn(snd_pcm_t *pcm, void **bufs, snd_pc
 | 
			
		|||
	return snd_pcm_readn(h->slave, bufs, size);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int snd_pcm_hooks_mmap_commit(snd_pcm_t *pcm,
 | 
			
		||||
				     snd_pcm_uframes_t offset,
 | 
			
		||||
				     snd_pcm_uframes_t size)
 | 
			
		||||
static snd_pcm_sframes_t snd_pcm_hooks_mmap_commit(snd_pcm_t *pcm,
 | 
			
		||||
						   snd_pcm_uframes_t offset,
 | 
			
		||||
						   snd_pcm_uframes_t size)
 | 
			
		||||
{
 | 
			
		||||
	snd_pcm_hooks_t *h = pcm->private_data;
 | 
			
		||||
	return snd_pcm_mmap_commit(h->slave, offset, size);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -74,6 +74,8 @@ typedef struct {
 | 
			
		|||
#define UPDATE_SHADOW_PTR(hw) \
 | 
			
		||||
	do { if (hw->shadow_appl_ptr && !hw->avail_update_flag) \
 | 
			
		||||
	       hw->appl_ptr = hw->mmap_control->appl_ptr; } while (0)
 | 
			
		||||
#define FAST_PCM_STATE(hw) \
 | 
			
		||||
	((enum sndrv_pcm_state) (hw)->mmap_status->state)
 | 
			
		||||
 | 
			
		||||
#endif /* DOC_HIDDEN */
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -593,29 +595,31 @@ static int snd_pcm_hw_close(snd_pcm_t *pcm)
 | 
			
		|||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int snd_pcm_hw_mmap_commit(snd_pcm_t *pcm,
 | 
			
		||||
				  snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
 | 
			
		||||
				  snd_pcm_uframes_t size)
 | 
			
		||||
static snd_pcm_sframes_t snd_pcm_hw_mmap_commit(snd_pcm_t *pcm,
 | 
			
		||||
						snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
 | 
			
		||||
						snd_pcm_uframes_t size)
 | 
			
		||||
{
 | 
			
		||||
	snd_pcm_hw_t *hw = pcm->private_data;
 | 
			
		||||
 | 
			
		||||
	if (hw->mmap_shm) {
 | 
			
		||||
		if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
 | 
			
		||||
		    	snd_pcm_sframes_t res;
 | 
			
		||||
		    	snd_pcm_sframes_t result = 0, res;
 | 
			
		||||
 | 
			
		||||
			do {
 | 
			
		||||
				res = snd_pcm_write_mmap(pcm, size);
 | 
			
		||||
				if (res < 0)
 | 
			
		||||
					return res;
 | 
			
		||||
					return result > 0 ? result : res;
 | 
			
		||||
				size -= res;
 | 
			
		||||
				result += res;
 | 
			
		||||
			} while (size > 0);
 | 
			
		||||
			return 0;
 | 
			
		||||
			return result;
 | 
			
		||||
		} else {
 | 
			
		||||
			snd_pcm_hw_t *hw = pcm->private_data;
 | 
			
		||||
			assert(hw->shadow_appl_ptr);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	snd_pcm_mmap_appl_forward(pcm, size);
 | 
			
		||||
	return 0;
 | 
			
		||||
	return size;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static snd_pcm_sframes_t snd_pcm_hw_avail_update(snd_pcm_t *pcm)
 | 
			
		||||
| 
						 | 
				
			
			@ -638,14 +642,21 @@ static snd_pcm_sframes_t snd_pcm_hw_avail_update(snd_pcm_t *pcm)
 | 
			
		|||
			return err;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if (avail >= pcm->stop_threshold) {
 | 
			
		||||
		/* SNDRV_PCM_IOCTL_XRUN ioctl has been implemented since PCM kernel API 2.0.1 */
 | 
			
		||||
		if (SNDRV_PROTOCOL_VERSION(2, 0, 1) <= hw->version) {
 | 
			
		||||
			if (ioctl(hw->fd, SND_PCM_IOCTL_XRUN) < 0)
 | 
			
		||||
				return -errno;
 | 
			
		||||
	switch (FAST_PCM_STATE(hw)) {
 | 
			
		||||
	case SNDRV_PCM_STATE_RUNNING:
 | 
			
		||||
		if (avail >= pcm->stop_threshold) {
 | 
			
		||||
			/* SNDRV_PCM_IOCTL_XRUN ioctl has been implemented since PCM kernel API 2.0.1 */
 | 
			
		||||
			if (SNDRV_PROTOCOL_VERSION(2, 0, 1) <= hw->version) {
 | 
			
		||||
				if (ioctl(hw->fd, SND_PCM_IOCTL_XRUN) < 0)
 | 
			
		||||
					return -errno;
 | 
			
		||||
			}
 | 
			
		||||
			/* everything is ok, state == SND_PCM_STATE_XRUN at the moment */
 | 
			
		||||
			return -EPIPE;
 | 
			
		||||
		}
 | 
			
		||||
		/* everything is ok, state == SND_PCM_STATE_XRUN at the moment */
 | 
			
		||||
	case SNDRV_PCM_STATE_XRUN:
 | 
			
		||||
		return -EPIPE;
 | 
			
		||||
	default:
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
	return avail;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1135,9 +1135,12 @@ int snd_pcm_ladspa_open(snd_pcm_t **pcmp, const char *name,
 | 
			
		|||
	ladspa = calloc(1, sizeof(snd_pcm_ladspa_t));
 | 
			
		||||
	if (!ladspa)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	snd_pcm_plugin_init(&ladspa->plug);
 | 
			
		||||
	ladspa->plug.init = snd_pcm_ladspa_init;
 | 
			
		||||
	ladspa->plug.read = snd_pcm_ladspa_read_areas;
 | 
			
		||||
	ladspa->plug.write = snd_pcm_ladspa_write_areas;
 | 
			
		||||
	ladspa->plug.undo_read = snd_pcm_plugin_undo_read_generic;
 | 
			
		||||
	ladspa->plug.undo_write = snd_pcm_plugin_undo_write_generic;
 | 
			
		||||
	ladspa->plug.slave = slave;
 | 
			
		||||
	ladspa->plug.close_slave = close_slave;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -389,9 +389,12 @@ int snd_pcm_lfloat_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sfo
 | 
			
		|||
	if (!lfloat) {
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	}
 | 
			
		||||
	snd_pcm_plugin_init(&lfloat->plug);
 | 
			
		||||
	lfloat->sformat = sformat;
 | 
			
		||||
	lfloat->plug.read = snd_pcm_lfloat_read_areas;
 | 
			
		||||
	lfloat->plug.write = snd_pcm_lfloat_write_areas;
 | 
			
		||||
	lfloat->plug.undo_read = snd_pcm_plugin_undo_read_generic;
 | 
			
		||||
	lfloat->plug.undo_write = snd_pcm_plugin_undo_write_generic;
 | 
			
		||||
	lfloat->plug.slave = slave;
 | 
			
		||||
	lfloat->plug.close_slave = close_slave;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -328,9 +328,12 @@ int snd_pcm_linear_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sfo
 | 
			
		|||
	if (!linear) {
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	}
 | 
			
		||||
	snd_pcm_plugin_init(&linear->plug);
 | 
			
		||||
	linear->sformat = sformat;
 | 
			
		||||
	linear->plug.read = snd_pcm_linear_read_areas;
 | 
			
		||||
	linear->plug.write = snd_pcm_linear_write_areas;
 | 
			
		||||
	linear->plug.undo_read = snd_pcm_plugin_undo_read_generic;
 | 
			
		||||
	linear->plug.undo_write = snd_pcm_plugin_undo_write_generic;
 | 
			
		||||
	linear->plug.slave = slave;
 | 
			
		||||
	linear->plug.close_slave = close_slave;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -141,7 +141,7 @@ typedef struct {
 | 
			
		|||
	snd_pcm_sframes_t (*readi)(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size);
 | 
			
		||||
	snd_pcm_sframes_t (*readn)(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size);
 | 
			
		||||
	snd_pcm_sframes_t (*avail_update)(snd_pcm_t *pcm);
 | 
			
		||||
	int (*mmap_commit)(snd_pcm_t *pcm, snd_pcm_uframes_t offset, snd_pcm_uframes_t size);
 | 
			
		||||
	snd_pcm_sframes_t (*mmap_commit)(snd_pcm_t *pcm, snd_pcm_uframes_t offset, snd_pcm_uframes_t size);
 | 
			
		||||
} snd_pcm_fast_ops_t;
 | 
			
		||||
 | 
			
		||||
struct _snd_pcm {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -396,9 +396,9 @@ static int snd_pcm_meter_resume(snd_pcm_t *pcm)
 | 
			
		|||
	return snd_pcm_resume(meter->slave);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int snd_pcm_meter_mmap_commit(snd_pcm_t *pcm,
 | 
			
		||||
				     snd_pcm_uframes_t offset,
 | 
			
		||||
				     snd_pcm_uframes_t size)
 | 
			
		||||
static snd_pcm_sframes_t snd_pcm_meter_mmap_commit(snd_pcm_t *pcm,
 | 
			
		||||
						   snd_pcm_uframes_t offset,
 | 
			
		||||
						   snd_pcm_uframes_t size)
 | 
			
		||||
{
 | 
			
		||||
	snd_pcm_meter_t *meter = pcm->private_data;
 | 
			
		||||
	snd_pcm_uframes_t old_rptr = *pcm->appl_ptr;
 | 
			
		||||
| 
						 | 
				
			
			@ -406,10 +406,10 @@ static int snd_pcm_meter_mmap_commit(snd_pcm_t *pcm,
 | 
			
		|||
	if (result <= 0)
 | 
			
		||||
		return result;
 | 
			
		||||
	if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
 | 
			
		||||
		snd_pcm_meter_add_frames(pcm, snd_pcm_mmap_areas(pcm), old_rptr, size);
 | 
			
		||||
		snd_pcm_meter_add_frames(pcm, snd_pcm_mmap_areas(pcm), old_rptr, result);
 | 
			
		||||
		meter->rptr = *pcm->appl_ptr;
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static snd_pcm_sframes_t snd_pcm_meter_avail_update(snd_pcm_t *pcm)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -86,24 +86,25 @@ static snd_pcm_sframes_t snd_pcm_mmap_write_areas(snd_pcm_t *pcm,
 | 
			
		|||
						  snd_pcm_uframes_t size)
 | 
			
		||||
{
 | 
			
		||||
	snd_pcm_uframes_t xfer = 0;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	assert(snd_pcm_mmap_playback_avail(pcm) >= size);
 | 
			
		||||
	while (size > 0) {
 | 
			
		||||
		const snd_pcm_channel_area_t *pcm_areas;
 | 
			
		||||
		snd_pcm_uframes_t pcm_offset;
 | 
			
		||||
		snd_pcm_uframes_t frames = size;
 | 
			
		||||
		snd_pcm_sframes_t result;
 | 
			
		||||
 | 
			
		||||
		snd_pcm_mmap_begin(pcm, &pcm_areas, &pcm_offset, &frames);
 | 
			
		||||
		snd_pcm_areas_copy(pcm_areas, pcm_offset,
 | 
			
		||||
				   areas, offset, 
 | 
			
		||||
				   pcm->channels, 
 | 
			
		||||
				   frames, pcm->format);
 | 
			
		||||
		err = snd_pcm_mmap_commit(pcm, pcm_offset, frames);
 | 
			
		||||
		if (err < 0)
 | 
			
		||||
			return xfer > 0 ? xfer : err;
 | 
			
		||||
		offset += frames;
 | 
			
		||||
		xfer += frames;
 | 
			
		||||
		size -= frames;
 | 
			
		||||
		result = snd_pcm_mmap_commit(pcm, pcm_offset, frames);
 | 
			
		||||
		if (result < 0)
 | 
			
		||||
			return xfer > 0 ? xfer : result;
 | 
			
		||||
		offset += result;
 | 
			
		||||
		xfer += result;
 | 
			
		||||
		size -= result;
 | 
			
		||||
	}
 | 
			
		||||
	return xfer;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -114,24 +115,25 @@ static snd_pcm_sframes_t snd_pcm_mmap_read_areas(snd_pcm_t *pcm,
 | 
			
		|||
						 snd_pcm_uframes_t size)
 | 
			
		||||
{
 | 
			
		||||
	snd_pcm_uframes_t xfer = 0;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	assert(snd_pcm_mmap_capture_avail(pcm) >= size);
 | 
			
		||||
	while (size > 0) {
 | 
			
		||||
		const snd_pcm_channel_area_t *pcm_areas;
 | 
			
		||||
		snd_pcm_uframes_t pcm_offset;
 | 
			
		||||
		snd_pcm_uframes_t frames = size;
 | 
			
		||||
		snd_pcm_sframes_t result;
 | 
			
		||||
		
 | 
			
		||||
		snd_pcm_mmap_begin(pcm, &pcm_areas, &pcm_offset, &frames);
 | 
			
		||||
		snd_pcm_areas_copy(areas, offset,
 | 
			
		||||
				   pcm_areas, pcm_offset,
 | 
			
		||||
				   pcm->channels, 
 | 
			
		||||
				   frames, pcm->format);
 | 
			
		||||
		err = snd_pcm_mmap_commit(pcm, pcm_offset, frames);
 | 
			
		||||
		if (err < 0)
 | 
			
		||||
			return xfer > 0 ? xfer : err;
 | 
			
		||||
		offset += frames;
 | 
			
		||||
		xfer += frames;
 | 
			
		||||
		size -= frames;
 | 
			
		||||
		result = snd_pcm_mmap_commit(pcm, pcm_offset, frames);
 | 
			
		||||
		if (result < 0)
 | 
			
		||||
			return xfer > 0 ? xfer : result;
 | 
			
		||||
		offset += result;
 | 
			
		||||
		xfer += result;
 | 
			
		||||
		size -= result;
 | 
			
		||||
	}
 | 
			
		||||
	return xfer;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -439,9 +439,12 @@ int snd_pcm_mulaw_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sfor
 | 
			
		|||
	if (!mulaw) {
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	}
 | 
			
		||||
	snd_pcm_plugin_init(&mulaw->plug);
 | 
			
		||||
	mulaw->sformat = sformat;
 | 
			
		||||
	mulaw->plug.read = snd_pcm_mulaw_read_areas;
 | 
			
		||||
	mulaw->plug.write = snd_pcm_mulaw_write_areas;
 | 
			
		||||
	mulaw->plug.undo_read = snd_pcm_plugin_undo_read_generic;
 | 
			
		||||
	mulaw->plug.undo_write = snd_pcm_plugin_undo_write_generic;
 | 
			
		||||
	mulaw->plug.slave = slave;
 | 
			
		||||
	mulaw->plug.close_slave = close_slave;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -496,8 +496,14 @@ static snd_pcm_sframes_t snd_pcm_multi_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t
 | 
			
		|||
	for (i = 0; i < multi->slaves_count; ++i) {
 | 
			
		||||
		snd_pcm_t *slave_i = multi->slaves[i].pcm;
 | 
			
		||||
		snd_pcm_uframes_t f = pos[i] - frames;
 | 
			
		||||
		if (f > 0)
 | 
			
		||||
			snd_pcm_mmap_commit(slave_i, snd_pcm_mmap_offset(slave_i), f);
 | 
			
		||||
		snd_pcm_sframes_t result;
 | 
			
		||||
		if (f > 0) {
 | 
			
		||||
			result = snd_pcm_mmap_commit(slave_i, snd_pcm_mmap_offset(slave_i), f);
 | 
			
		||||
			if (result < 0)
 | 
			
		||||
				return result;
 | 
			
		||||
			if ((snd_pcm_uframes_t)result != f)
 | 
			
		||||
				return -EIO;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return frames;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -517,20 +523,22 @@ static int snd_pcm_multi_resume(snd_pcm_t *pcm)
 | 
			
		|||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int snd_pcm_multi_mmap_commit(snd_pcm_t *pcm,
 | 
			
		||||
				     snd_pcm_uframes_t offset,
 | 
			
		||||
				     snd_pcm_uframes_t size)
 | 
			
		||||
static snd_pcm_sframes_t snd_pcm_multi_mmap_commit(snd_pcm_t *pcm,
 | 
			
		||||
						   snd_pcm_uframes_t offset,
 | 
			
		||||
						   snd_pcm_uframes_t size)
 | 
			
		||||
{
 | 
			
		||||
	snd_pcm_multi_t *multi = pcm->private_data;
 | 
			
		||||
	snd_pcm_t *slave;
 | 
			
		||||
	unsigned int i;
 | 
			
		||||
	int err;
 | 
			
		||||
	snd_pcm_sframes_t result;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < multi->slaves_count; ++i) {
 | 
			
		||||
		slave = multi->slaves[i].pcm;
 | 
			
		||||
		err = snd_pcm_mmap_commit(slave, offset, size);
 | 
			
		||||
		if (err < 0)
 | 
			
		||||
			return err;
 | 
			
		||||
		result = snd_pcm_mmap_commit(slave, offset, size);
 | 
			
		||||
		if (result < 0)
 | 
			
		||||
			return result;
 | 
			
		||||
		if ((snd_pcm_uframes_t)result != size)
 | 
			
		||||
			return -EIO;
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -230,17 +230,16 @@ static snd_pcm_sframes_t snd_pcm_null_readn(snd_pcm_t *pcm, void **bufs ATTRIBUT
 | 
			
		|||
	return snd_pcm_read_areas(pcm, NULL, 0, size, snd_pcm_null_xfer_areas);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int snd_pcm_null_mmap_commit(snd_pcm_t *pcm,
 | 
			
		||||
				    snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
 | 
			
		||||
				    snd_pcm_uframes_t size)
 | 
			
		||||
static snd_pcm_sframes_t snd_pcm_null_mmap_commit(snd_pcm_t *pcm,
 | 
			
		||||
						  snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
 | 
			
		||||
						  snd_pcm_uframes_t size)
 | 
			
		||||
{
 | 
			
		||||
	snd_pcm_sframes_t res;
 | 
			
		||||
	
 | 
			
		||||
	res = snd_pcm_null_fwd(pcm, size);
 | 
			
		||||
	if (res < 0)
 | 
			
		||||
		return res;
 | 
			
		||||
	assert((snd_pcm_uframes_t)res == size);
 | 
			
		||||
	return 0;
 | 
			
		||||
	return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static snd_pcm_sframes_t snd_pcm_null_avail_update(snd_pcm_t *pcm)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -89,6 +89,53 @@ pcm.rate44100Hz {
 | 
			
		|||
 | 
			
		||||
#ifndef DOC_HIDDEN
 | 
			
		||||
 | 
			
		||||
static snd_pcm_sframes_t
 | 
			
		||||
snd_pcm_plugin_undo_read(snd_pcm_t *pcm ATTRIBUTE_UNUSED,
 | 
			
		||||
			 const snd_pcm_channel_area_t *res_areas ATTRIBUTE_UNUSED,
 | 
			
		||||
			 snd_pcm_uframes_t res_offset ATTRIBUTE_UNUSED,
 | 
			
		||||
			 snd_pcm_uframes_t res_size ATTRIBUTE_UNUSED,
 | 
			
		||||
			 snd_pcm_uframes_t slave_undo_size ATTRIBUTE_UNUSED)
 | 
			
		||||
{
 | 
			
		||||
	return -EIO;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static snd_pcm_sframes_t
 | 
			
		||||
snd_pcm_plugin_undo_write(snd_pcm_t *pcm ATTRIBUTE_UNUSED,
 | 
			
		||||
			  const snd_pcm_channel_area_t *res_areas ATTRIBUTE_UNUSED,
 | 
			
		||||
			  snd_pcm_uframes_t res_offset ATTRIBUTE_UNUSED,
 | 
			
		||||
			  snd_pcm_uframes_t res_size ATTRIBUTE_UNUSED,
 | 
			
		||||
			  snd_pcm_uframes_t slave_undo_size ATTRIBUTE_UNUSED)
 | 
			
		||||
{
 | 
			
		||||
	return -EIO;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
snd_pcm_sframes_t
 | 
			
		||||
snd_pcm_plugin_undo_read_generic(snd_pcm_t *pcm ATTRIBUTE_UNUSED,
 | 
			
		||||
				 const snd_pcm_channel_area_t *res_areas ATTRIBUTE_UNUSED,
 | 
			
		||||
				 snd_pcm_uframes_t res_offset ATTRIBUTE_UNUSED,
 | 
			
		||||
				 snd_pcm_uframes_t res_size ATTRIBUTE_UNUSED,
 | 
			
		||||
				 snd_pcm_uframes_t slave_undo_size)
 | 
			
		||||
{
 | 
			
		||||
	return slave_undo_size;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
snd_pcm_sframes_t
 | 
			
		||||
snd_pcm_plugin_undo_write_generic(snd_pcm_t *pcm ATTRIBUTE_UNUSED,
 | 
			
		||||
				  const snd_pcm_channel_area_t *res_areas ATTRIBUTE_UNUSED,
 | 
			
		||||
				  snd_pcm_uframes_t res_offset ATTRIBUTE_UNUSED,
 | 
			
		||||
				  snd_pcm_uframes_t res_size ATTRIBUTE_UNUSED,
 | 
			
		||||
				  snd_pcm_uframes_t slave_undo_size)
 | 
			
		||||
{
 | 
			
		||||
	return slave_undo_size;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void snd_pcm_plugin_init(snd_pcm_plugin_t *plugin)
 | 
			
		||||
{
 | 
			
		||||
	memset(plugin, 0, sizeof(snd_pcm_plugin_t));
 | 
			
		||||
	plugin->undo_read = snd_pcm_plugin_undo_read;
 | 
			
		||||
	plugin->undo_write = snd_pcm_plugin_undo_write;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int snd_pcm_plugin_close(snd_pcm_t *pcm)
 | 
			
		||||
{
 | 
			
		||||
	snd_pcm_plugin_t *plugin = pcm->private_data;
 | 
			
		||||
| 
						 | 
				
			
			@ -270,7 +317,7 @@ static snd_pcm_sframes_t snd_pcm_plugin_write_areas(snd_pcm_t *pcm,
 | 
			
		|||
	snd_pcm_plugin_t *plugin = pcm->private_data;
 | 
			
		||||
	snd_pcm_t *slave = plugin->slave;
 | 
			
		||||
	snd_pcm_uframes_t xfer = 0;
 | 
			
		||||
	snd_pcm_sframes_t err;
 | 
			
		||||
	snd_pcm_sframes_t result;
 | 
			
		||||
 | 
			
		||||
	while (size > 0) {
 | 
			
		||||
		snd_pcm_uframes_t frames = size;
 | 
			
		||||
| 
						 | 
				
			
			@ -283,13 +330,13 @@ static snd_pcm_sframes_t snd_pcm_plugin_write_areas(snd_pcm_t *pcm,
 | 
			
		|||
		assert(slave_frames <= snd_pcm_mmap_playback_avail(slave));
 | 
			
		||||
		snd_atomic_write_begin(&plugin->watom);
 | 
			
		||||
		snd_pcm_mmap_appl_forward(pcm, frames);
 | 
			
		||||
		err = snd_pcm_mmap_commit(slave, slave_offset, slave_frames);
 | 
			
		||||
		result = snd_pcm_mmap_commit(slave, slave_offset, slave_frames);
 | 
			
		||||
		snd_atomic_write_end(&plugin->watom);
 | 
			
		||||
		if (err < 0)
 | 
			
		||||
			return xfer > 0 ? xfer : err;
 | 
			
		||||
		offset += frames;
 | 
			
		||||
		xfer += frames;
 | 
			
		||||
		size -= frames;
 | 
			
		||||
		if (result < 0)
 | 
			
		||||
			return xfer > 0 ? xfer : result;
 | 
			
		||||
		offset += result;
 | 
			
		||||
		xfer += result;
 | 
			
		||||
		size -= result;
 | 
			
		||||
	}
 | 
			
		||||
	return xfer;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -302,7 +349,7 @@ static snd_pcm_sframes_t snd_pcm_plugin_read_areas(snd_pcm_t *pcm,
 | 
			
		|||
	snd_pcm_plugin_t *plugin = pcm->private_data;
 | 
			
		||||
	snd_pcm_t *slave = plugin->slave;
 | 
			
		||||
	snd_pcm_uframes_t xfer = 0;
 | 
			
		||||
	snd_pcm_sframes_t err;
 | 
			
		||||
	snd_pcm_sframes_t result;
 | 
			
		||||
	
 | 
			
		||||
	while (size > 0) {
 | 
			
		||||
		snd_pcm_uframes_t frames = size;
 | 
			
		||||
| 
						 | 
				
			
			@ -315,13 +362,13 @@ static snd_pcm_sframes_t snd_pcm_plugin_read_areas(snd_pcm_t *pcm,
 | 
			
		|||
		assert(slave_frames <= snd_pcm_mmap_capture_avail(slave));
 | 
			
		||||
		snd_atomic_write_begin(&plugin->watom);
 | 
			
		||||
		snd_pcm_mmap_appl_forward(pcm, frames);
 | 
			
		||||
		err = snd_pcm_mmap_commit(slave, slave_offset, slave_frames);
 | 
			
		||||
		result = snd_pcm_mmap_commit(slave, slave_offset, slave_frames);
 | 
			
		||||
		snd_atomic_write_end(&plugin->watom);
 | 
			
		||||
		if (err < 0)
 | 
			
		||||
			return xfer > 0 ? xfer : err;
 | 
			
		||||
		offset += frames;
 | 
			
		||||
		xfer += frames;
 | 
			
		||||
		size -= frames;
 | 
			
		||||
		if (result < 0)
 | 
			
		||||
			return xfer > 0 ? xfer : result;
 | 
			
		||||
		offset += result;
 | 
			
		||||
		xfer += result;
 | 
			
		||||
		size -= result;
 | 
			
		||||
	}
 | 
			
		||||
	return xfer;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -359,15 +406,16 @@ snd_pcm_sframes_t snd_pcm_plugin_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_ufra
 | 
			
		|||
				  snd_pcm_plugin_read_areas);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int snd_pcm_plugin_mmap_commit(snd_pcm_t *pcm,
 | 
			
		||||
			       snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
 | 
			
		||||
			       snd_pcm_uframes_t size)
 | 
			
		||||
snd_pcm_sframes_t snd_pcm_plugin_mmap_commit(snd_pcm_t *pcm,
 | 
			
		||||
					     snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
 | 
			
		||||
					     snd_pcm_uframes_t size)
 | 
			
		||||
{
 | 
			
		||||
	snd_pcm_plugin_t *plugin = pcm->private_data;
 | 
			
		||||
	snd_pcm_t *slave = plugin->slave;
 | 
			
		||||
	const snd_pcm_channel_area_t *areas;
 | 
			
		||||
	snd_pcm_uframes_t appl_offset;
 | 
			
		||||
	snd_pcm_sframes_t slave_size;
 | 
			
		||||
	snd_pcm_sframes_t xfer;
 | 
			
		||||
 | 
			
		||||
	if (pcm->stream == SND_PCM_STREAM_CAPTURE) {
 | 
			
		||||
		snd_atomic_write_begin(&plugin->watom);
 | 
			
		||||
| 
						 | 
				
			
			@ -378,35 +426,49 @@ int snd_pcm_plugin_mmap_commit(snd_pcm_t *pcm,
 | 
			
		|||
	slave_size = snd_pcm_avail_update(slave);
 | 
			
		||||
	if (slave_size < 0)
 | 
			
		||||
		return slave_size;
 | 
			
		||||
	if ((snd_pcm_uframes_t)slave_size < size)
 | 
			
		||||
		return -EIO;
 | 
			
		||||
	areas = snd_pcm_mmap_areas(pcm);
 | 
			
		||||
	appl_offset = snd_pcm_mmap_offset(pcm);
 | 
			
		||||
	xfer = 0;
 | 
			
		||||
	while (size > 0 && slave_size > 0) {
 | 
			
		||||
		snd_pcm_uframes_t frames = size;
 | 
			
		||||
		snd_pcm_uframes_t cont = pcm->buffer_size - appl_offset;
 | 
			
		||||
		const snd_pcm_channel_area_t *slave_areas;
 | 
			
		||||
		snd_pcm_uframes_t slave_offset;
 | 
			
		||||
		snd_pcm_uframes_t slave_frames = ULONG_MAX;
 | 
			
		||||
		snd_pcm_sframes_t result;
 | 
			
		||||
		int err;
 | 
			
		||||
 | 
			
		||||
		snd_pcm_mmap_begin(slave, &slave_areas, &slave_offset, &slave_frames);
 | 
			
		||||
		err = snd_pcm_mmap_begin(slave, &slave_areas, &slave_offset, &slave_frames);
 | 
			
		||||
		if (err < 0)
 | 
			
		||||
			return xfer > 0 ? xfer : err;
 | 
			
		||||
		if (frames > cont)
 | 
			
		||||
			frames = cont;
 | 
			
		||||
		frames = plugin->write(pcm, areas, appl_offset, frames,
 | 
			
		||||
				       slave_areas, slave_offset, &slave_frames);
 | 
			
		||||
		snd_atomic_write_begin(&plugin->watom);
 | 
			
		||||
		snd_pcm_mmap_appl_forward(pcm, frames);
 | 
			
		||||
		snd_pcm_mmap_commit(slave, slave_offset, slave_frames);
 | 
			
		||||
		result = snd_pcm_mmap_commit(slave, slave_offset, slave_frames);
 | 
			
		||||
		snd_atomic_write_end(&plugin->watom);
 | 
			
		||||
		if (result > 0 && (snd_pcm_uframes_t)result != slave_frames) {
 | 
			
		||||
			snd_pcm_sframes_t res;
 | 
			
		||||
			
 | 
			
		||||
			res = plugin->undo_write(pcm, slave_areas, slave_offset + result, slave_frames, slave_frames - result);
 | 
			
		||||
			if (res < 0)
 | 
			
		||||
				return xfer > 0 ? xfer : res;
 | 
			
		||||
			frames -= res;
 | 
			
		||||
		}
 | 
			
		||||
		if (result <= 0)
 | 
			
		||||
			return xfer > 0 ? xfer : result;
 | 
			
		||||
		if (frames == cont)
 | 
			
		||||
			appl_offset = 0;
 | 
			
		||||
		else
 | 
			
		||||
			appl_offset += frames;
 | 
			
		||||
			appl_offset += result;
 | 
			
		||||
		size -= frames;
 | 
			
		||||
		slave_size -= slave_frames;
 | 
			
		||||
		slave_size -= frames;
 | 
			
		||||
		xfer += frames;
 | 
			
		||||
	}
 | 
			
		||||
	assert(size == 0);
 | 
			
		||||
	return 0;
 | 
			
		||||
	return xfer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
snd_pcm_sframes_t snd_pcm_plugin_avail_update(snd_pcm_t *pcm)
 | 
			
		||||
| 
						 | 
				
			
			@ -434,32 +496,48 @@ snd_pcm_sframes_t snd_pcm_plugin_avail_update(snd_pcm_t *pcm)
 | 
			
		|||
		const snd_pcm_channel_area_t *areas;
 | 
			
		||||
		snd_pcm_uframes_t xfer, hw_offset, size;
 | 
			
		||||
		
 | 
			
		||||
		xfer = snd_pcm_mmap_capture_avail(pcm);
 | 
			
		||||
		size = pcm->buffer_size - xfer;
 | 
			
		||||
		size = snd_pcm_mmap_capture_avail(pcm);
 | 
			
		||||
		size = pcm->buffer_size - size;
 | 
			
		||||
		areas = snd_pcm_mmap_areas(pcm);
 | 
			
		||||
		hw_offset = snd_pcm_mmap_hw_offset(pcm);
 | 
			
		||||
		xfer = 0;
 | 
			
		||||
		while (size > 0 && slave_size > 0) {
 | 
			
		||||
		snd_pcm_uframes_t frames = size;
 | 
			
		||||
			snd_pcm_uframes_t frames = size;
 | 
			
		||||
			snd_pcm_uframes_t cont = pcm->buffer_size - hw_offset;
 | 
			
		||||
			const snd_pcm_channel_area_t *slave_areas;
 | 
			
		||||
			snd_pcm_uframes_t slave_offset;
 | 
			
		||||
			snd_pcm_uframes_t slave_frames = ULONG_MAX;
 | 
			
		||||
			snd_pcm_mmap_begin(slave, &slave_areas, &slave_offset, &slave_frames);
 | 
			
		||||
			snd_pcm_sframes_t result;
 | 
			
		||||
			int err;
 | 
			
		||||
 | 
			
		||||
			err = snd_pcm_mmap_begin(slave, &slave_areas, &slave_offset, &slave_frames);
 | 
			
		||||
			if (err < 0)
 | 
			
		||||
				return xfer > 0 ? xfer : err;
 | 
			
		||||
			if (frames > cont)
 | 
			
		||||
				frames = cont;
 | 
			
		||||
			frames = plugin->read(pcm, areas, hw_offset, frames,
 | 
			
		||||
					      slave_areas, slave_offset, &slave_frames);
 | 
			
		||||
			snd_atomic_write_begin(&plugin->watom);
 | 
			
		||||
			snd_pcm_mmap_hw_forward(pcm, frames);
 | 
			
		||||
			snd_pcm_mmap_commit(slave, slave_offset, slave_frames);
 | 
			
		||||
			result = snd_pcm_mmap_commit(slave, slave_offset, slave_frames);
 | 
			
		||||
			snd_atomic_write_end(&plugin->watom);
 | 
			
		||||
			xfer += frames;
 | 
			
		||||
			if (result > 0 && (snd_pcm_uframes_t)result != slave_frames) {
 | 
			
		||||
				snd_pcm_sframes_t res;
 | 
			
		||||
				
 | 
			
		||||
				res = plugin->undo_read(slave, areas, hw_offset, frames, slave_frames - result);
 | 
			
		||||
				if (res < 0)
 | 
			
		||||
					return xfer > 0 ? xfer : res;
 | 
			
		||||
				frames -= res;
 | 
			
		||||
			}
 | 
			
		||||
			if (result <= 0)
 | 
			
		||||
				return xfer > 0 ? xfer : result;
 | 
			
		||||
			if (frames == cont)
 | 
			
		||||
				hw_offset = 0;
 | 
			
		||||
			else
 | 
			
		||||
				hw_offset += frames;
 | 
			
		||||
			size -= frames;
 | 
			
		||||
			slave_size -= slave_frames;
 | 
			
		||||
			xfer += frames;
 | 
			
		||||
		}
 | 
			
		||||
		return xfer;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -30,11 +30,20 @@ typedef snd_pcm_uframes_t (*snd_pcm_slave_xfer_areas_func_t)
 | 
			
		|||
      snd_pcm_uframes_t slave_offset, 
 | 
			
		||||
      snd_pcm_uframes_t *slave_sizep);
 | 
			
		||||
 | 
			
		||||
typedef snd_pcm_sframes_t (*snd_pcm_slave_xfer_areas_undo_func_t)
 | 
			
		||||
     (snd_pcm_t *pcm,
 | 
			
		||||
      const snd_pcm_channel_area_t *res_areas,	/* result areas */
 | 
			
		||||
      snd_pcm_uframes_t res_offset,		/* offset of result areas */
 | 
			
		||||
      snd_pcm_uframes_t res_size,		/* size of result areas */
 | 
			
		||||
      snd_pcm_uframes_t slave_undo_size);
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
	snd_pcm_t *slave;
 | 
			
		||||
	int close_slave;
 | 
			
		||||
	snd_pcm_slave_xfer_areas_func_t read;
 | 
			
		||||
	snd_pcm_slave_xfer_areas_func_t write;
 | 
			
		||||
	snd_pcm_slave_xfer_areas_undo_func_t undo_read;
 | 
			
		||||
	snd_pcm_slave_xfer_areas_undo_func_t undo_write;
 | 
			
		||||
	snd_pcm_sframes_t (*client_frames)(snd_pcm_t *pcm, snd_pcm_sframes_t frames);
 | 
			
		||||
	snd_pcm_sframes_t (*slave_frames)(snd_pcm_t *pcm, snd_pcm_sframes_t frames);
 | 
			
		||||
	int (*init)(snd_pcm_t *pcm);
 | 
			
		||||
| 
						 | 
				
			
			@ -43,6 +52,7 @@ typedef struct {
 | 
			
		|||
	snd_atomic_write_t watom;
 | 
			
		||||
} snd_pcm_plugin_t;	
 | 
			
		||||
 | 
			
		||||
void snd_pcm_plugin_init(snd_pcm_plugin_t *plugin);
 | 
			
		||||
int snd_pcm_plugin_close(snd_pcm_t *pcm);
 | 
			
		||||
int snd_pcm_plugin_card(snd_pcm_t *pcm);
 | 
			
		||||
int snd_pcm_plugin_nonblock(snd_pcm_t *pcm, int nonblock);
 | 
			
		||||
| 
						 | 
				
			
			@ -65,7 +75,7 @@ snd_pcm_sframes_t snd_pcm_plugin_writei(snd_pcm_t *pcm, const void *buffer, snd_
 | 
			
		|||
snd_pcm_sframes_t snd_pcm_plugin_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size);
 | 
			
		||||
snd_pcm_sframes_t snd_pcm_plugin_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size);
 | 
			
		||||
snd_pcm_sframes_t snd_pcm_plugin_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size);
 | 
			
		||||
int snd_pcm_plugin_mmap_commit(snd_pcm_t *pcm, snd_pcm_uframes_t offset, snd_pcm_uframes_t size);
 | 
			
		||||
snd_pcm_sframes_t snd_pcm_plugin_mmap_commit(snd_pcm_t *pcm, snd_pcm_uframes_t offset, snd_pcm_uframes_t size);
 | 
			
		||||
snd_pcm_sframes_t snd_pcm_plugin_avail_update(snd_pcm_t *pcm);
 | 
			
		||||
int snd_pcm_plugin_mmap_status(snd_pcm_t *pcm);
 | 
			
		||||
int snd_pcm_plugin_mmap_control(snd_pcm_t *pcm);
 | 
			
		||||
| 
						 | 
				
			
			@ -79,6 +89,20 @@ int snd_pcm_plugin_hw_refine_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params);
 | 
			
		|||
 | 
			
		||||
extern snd_pcm_fast_ops_t snd_pcm_plugin_fast_ops;
 | 
			
		||||
 | 
			
		||||
snd_pcm_sframes_t snd_pcm_plugin_undo_read_generic
 | 
			
		||||
     (snd_pcm_t *pcm,
 | 
			
		||||
      const snd_pcm_channel_area_t *res_areas,	/* result areas */
 | 
			
		||||
      snd_pcm_uframes_t res_offset,		/* offset of result areas */
 | 
			
		||||
      snd_pcm_uframes_t res_size,		/* size of result areas */
 | 
			
		||||
      snd_pcm_uframes_t slave_undo_size);
 | 
			
		||||
 | 
			
		||||
snd_pcm_sframes_t snd_pcm_plugin_undo_write_generic
 | 
			
		||||
     (snd_pcm_t *pcm,
 | 
			
		||||
      const snd_pcm_channel_area_t *res_areas,	/* result areas */
 | 
			
		||||
      snd_pcm_uframes_t res_offset,		/* offset of result areas */
 | 
			
		||||
      snd_pcm_uframes_t res_size,		/* size of result areas */
 | 
			
		||||
      snd_pcm_uframes_t slave_undo_size);
 | 
			
		||||
 | 
			
		||||
int snd_pcm_linear_get_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format);
 | 
			
		||||
int snd_pcm_linear_put_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format);
 | 
			
		||||
int snd_pcm_linear_convert_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -534,6 +534,7 @@ int snd_pcm_rate_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sform
 | 
			
		|||
	if (!rate) {
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	}
 | 
			
		||||
	snd_pcm_plugin_init(&rate->plug);
 | 
			
		||||
	rate->srate = srate;
 | 
			
		||||
	rate->sformat = sformat;
 | 
			
		||||
	rate->plug.read = snd_pcm_rate_read_areas;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -781,10 +781,13 @@ int snd_pcm_route_open(snd_pcm_t **pcmp, const char *name,
 | 
			
		|||
	if (!route) {
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	}
 | 
			
		||||
	snd_pcm_plugin_init(&route->plug);
 | 
			
		||||
	route->sformat = sformat;
 | 
			
		||||
	route->schannels = schannels;
 | 
			
		||||
	route->plug.read = snd_pcm_route_read_areas;
 | 
			
		||||
	route->plug.write = snd_pcm_route_write_areas;
 | 
			
		||||
	route->plug.undo_read = snd_pcm_plugin_undo_read_generic;
 | 
			
		||||
	route->plug.undo_write = snd_pcm_plugin_undo_write_generic;
 | 
			
		||||
	route->plug.slave = slave;
 | 
			
		||||
	route->plug.close_slave = close_slave;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -770,9 +770,9 @@ static snd_pcm_sframes_t snd_pcm_share_avail_update(snd_pcm_t *pcm)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
/* Call it with mutex held */
 | 
			
		||||
static int _snd_pcm_share_mmap_commit(snd_pcm_t *pcm,
 | 
			
		||||
				      snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
 | 
			
		||||
				      snd_pcm_uframes_t size)
 | 
			
		||||
static snd_pcm_sframes_t _snd_pcm_share_mmap_commit(snd_pcm_t *pcm,
 | 
			
		||||
						    snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
 | 
			
		||||
						    snd_pcm_uframes_t size)
 | 
			
		||||
{
 | 
			
		||||
	snd_pcm_share_t *share = pcm->private_data;
 | 
			
		||||
	snd_pcm_share_slave_t *slave = share->slave;
 | 
			
		||||
| 
						 | 
				
			
			@ -803,12 +803,12 @@ static int _snd_pcm_share_mmap_commit(snd_pcm_t *pcm,
 | 
			
		|||
		}
 | 
			
		||||
		_snd_pcm_share_update(pcm);
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
	return size;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int snd_pcm_share_mmap_commit(snd_pcm_t *pcm,
 | 
			
		||||
				     snd_pcm_uframes_t offset,
 | 
			
		||||
				     snd_pcm_uframes_t size)
 | 
			
		||||
static snd_pcm_sframes_t snd_pcm_share_mmap_commit(snd_pcm_t *pcm,
 | 
			
		||||
						   snd_pcm_uframes_t offset,
 | 
			
		||||
						   snd_pcm_uframes_t size)
 | 
			
		||||
{
 | 
			
		||||
	snd_pcm_share_t *share = pcm->private_data;
 | 
			
		||||
	snd_pcm_share_slave_t *slave = share->slave;
 | 
			
		||||
| 
						 | 
				
			
			@ -909,8 +909,15 @@ static int snd_pcm_share_start(snd_pcm_t *pcm)
 | 
			
		|||
			xfer += frames;
 | 
			
		||||
		}
 | 
			
		||||
		snd_pcm_mmap_appl_forward(pcm, hw_avail);
 | 
			
		||||
		if (slave->running_count == 0)
 | 
			
		||||
			snd_pcm_mmap_commit(spcm, snd_pcm_mmap_offset(spcm), hw_avail);
 | 
			
		||||
		if (slave->running_count == 0) {
 | 
			
		||||
			snd_pcm_sframes_t res;
 | 
			
		||||
			res = snd_pcm_mmap_commit(spcm, snd_pcm_mmap_offset(spcm), hw_avail);
 | 
			
		||||
			if (res < 0) {
 | 
			
		||||
				err = res;
 | 
			
		||||
				goto _end;
 | 
			
		||||
			}
 | 
			
		||||
			assert((snd_pcm_uframes_t)res == hw_avail);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if (slave->running_count == 0) {
 | 
			
		||||
		err = snd_pcm_start(spcm);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -93,7 +93,7 @@ int receive_fd(int sock, void *data, size_t len, int *fd)
 | 
			
		|||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static int snd_pcm_shm_action(snd_pcm_t *pcm)
 | 
			
		||||
static long snd_pcm_shm_action(snd_pcm_t *pcm)
 | 
			
		||||
{
 | 
			
		||||
	snd_pcm_shm_t *shm = pcm->private_data;
 | 
			
		||||
	int err;
 | 
			
		||||
| 
						 | 
				
			
			@ -112,7 +112,7 @@ static int snd_pcm_shm_action(snd_pcm_t *pcm)
 | 
			
		|||
	return ctrl->result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int snd_pcm_shm_action_fd(snd_pcm_t *pcm, int *fd)
 | 
			
		||||
static long snd_pcm_shm_action_fd(snd_pcm_t *pcm, int *fd)
 | 
			
		||||
{
 | 
			
		||||
	snd_pcm_shm_t *shm = pcm->private_data;
 | 
			
		||||
	int err;
 | 
			
		||||
| 
						 | 
				
			
			@ -457,9 +457,9 @@ static int snd_pcm_shm_resume(snd_pcm_t *pcm)
 | 
			
		|||
	return snd_pcm_shm_action(pcm);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int snd_pcm_shm_mmap_commit(snd_pcm_t *pcm,
 | 
			
		||||
				   snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
 | 
			
		||||
				   snd_pcm_uframes_t size)
 | 
			
		||||
static snd_pcm_sframes_t snd_pcm_shm_mmap_commit(snd_pcm_t *pcm,
 | 
			
		||||
						 snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
 | 
			
		||||
						 snd_pcm_uframes_t size)
 | 
			
		||||
{
 | 
			
		||||
	snd_pcm_shm_t *shm = pcm->private_data;
 | 
			
		||||
	volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue