mirror of
				https://github.com/alsa-project/alsa-lib.git
				synced 2025-10-29 05:40:25 -04: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; | 	f = *frames; | ||||||
| 	avail = snd_pcm_mmap_avail(pcm); | 	avail = snd_pcm_mmap_avail(pcm); | ||||||
| 	if (avail > pcm->buffer_size) | 	if (avail > pcm->buffer_size) | ||||||
| 		return -EPIPE; | 		avail = pcm->buffer_size; | ||||||
| 	if (f > avail) | 	if (f > avail) | ||||||
| 		f = avail; | 		f = avail; | ||||||
| 	if (f > cont) | 	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 offset, | ||||||
| 				      snd_pcm_uframes_t frames) | 				      snd_pcm_uframes_t frames) | ||||||
| { | { | ||||||
| 	int res; |  | ||||||
| 	snd_pcm_uframes_t appl_ptr; |  | ||||||
| 
 |  | ||||||
| 	assert(pcm); | 	assert(pcm); | ||||||
| 	assert(offset == *pcm->appl_ptr % pcm->buffer_size); | 	assert(offset == *pcm->appl_ptr % pcm->buffer_size); | ||||||
| 	assert(frames <= snd_pcm_mmap_avail(pcm)); | 	assert(frames <= snd_pcm_mmap_avail(pcm)); | ||||||
| 	appl_ptr = *pcm->appl_ptr; | 	return pcm->fast_ops->mmap_commit(pcm->fast_op_arg, offset, frames); | ||||||
| 	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; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #ifndef DOC_HIDDEN | #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; | 		return -ENOMEM; | ||||||
| 	} | 	} | ||||||
| 	adpcm->sformat = sformat; | 	adpcm->sformat = sformat; | ||||||
|  | 	snd_pcm_plugin_init(&adpcm->plug); | ||||||
| 	adpcm->plug.read = snd_pcm_adpcm_read_areas; | 	adpcm->plug.read = snd_pcm_adpcm_read_areas; | ||||||
| 	adpcm->plug.write = snd_pcm_adpcm_write_areas; | 	adpcm->plug.write = snd_pcm_adpcm_write_areas; | ||||||
| 	adpcm->plug.init = snd_pcm_adpcm_init; | 	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) { | 	if (!alaw) { | ||||||
| 		return -ENOMEM; | 		return -ENOMEM; | ||||||
| 	} | 	} | ||||||
|  | 	snd_pcm_plugin_init(&alaw->plug); | ||||||
| 	alaw->sformat = sformat; | 	alaw->sformat = sformat; | ||||||
| 	alaw->plug.read = snd_pcm_alaw_read_areas; | 	alaw->plug.read = snd_pcm_alaw_read_areas; | ||||||
| 	alaw->plug.write = snd_pcm_alaw_write_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.slave = slave; | ||||||
| 	alaw->plug.close_slave = close_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) { | 	if (!copy) { | ||||||
| 		return -ENOMEM; | 		return -ENOMEM; | ||||||
| 	} | 	} | ||||||
|  | 	snd_pcm_plugin_init(©->plug); | ||||||
| 	copy->plug.read = snd_pcm_copy_read_areas; | 	copy->plug.read = snd_pcm_copy_read_areas; | ||||||
| 	copy->plug.write = snd_pcm_copy_write_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.slave = slave; | ||||||
| 	copy->plug.close_slave = close_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,  | static void snd_pcm_file_add_frames(snd_pcm_t *pcm,  | ||||||
| 				    const snd_pcm_channel_area_t *areas, | 				    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; | 	snd_pcm_file_t *file = pcm->private_data; | ||||||
| 	while (frames > 0) { | 	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; | 	return n; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int snd_pcm_file_mmap_commit(snd_pcm_t *pcm, | static snd_pcm_sframes_t snd_pcm_file_mmap_commit(snd_pcm_t *pcm, | ||||||
| 				    snd_pcm_uframes_t offset, | 					          snd_pcm_uframes_t offset, | ||||||
| 				    snd_pcm_uframes_t size) | 						  snd_pcm_uframes_t size) | ||||||
| { | { | ||||||
| 	snd_pcm_file_t *file = pcm->private_data; | 	snd_pcm_file_t *file = pcm->private_data; | ||||||
| 	snd_pcm_uframes_t ofs; | 	snd_pcm_uframes_t ofs; | ||||||
| 	snd_pcm_uframes_t siz = size; | 	snd_pcm_uframes_t siz = size; | ||||||
| 	const snd_pcm_channel_area_t *areas; | 	const snd_pcm_channel_area_t *areas; | ||||||
|  | 	snd_pcm_sframes_t result; | ||||||
|  | 
 | ||||||
| 	snd_pcm_mmap_begin(file->slave, &areas, &ofs, &siz); | 	snd_pcm_mmap_begin(file->slave, &areas, &ofs, &siz); | ||||||
| 	assert(ofs == offset && siz == size); | 	assert(ofs == offset && siz == size); | ||||||
| 	snd_pcm_mmap_commit(file->slave, ofs, siz); | 	result = snd_pcm_mmap_commit(file->slave, ofs, siz); | ||||||
| 	snd_pcm_file_add_frames(pcm, areas, ofs, siz); | 	if (result > 0) | ||||||
| 	return 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) | 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); | 	return snd_pcm_readn(h->slave, bufs, size); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int snd_pcm_hooks_mmap_commit(snd_pcm_t *pcm, | static snd_pcm_sframes_t snd_pcm_hooks_mmap_commit(snd_pcm_t *pcm, | ||||||
| 				     snd_pcm_uframes_t offset, | 						   snd_pcm_uframes_t offset, | ||||||
| 				     snd_pcm_uframes_t size) | 						   snd_pcm_uframes_t size) | ||||||
| { | { | ||||||
| 	snd_pcm_hooks_t *h = pcm->private_data; | 	snd_pcm_hooks_t *h = pcm->private_data; | ||||||
| 	return snd_pcm_mmap_commit(h->slave, offset, size); | 	return snd_pcm_mmap_commit(h->slave, offset, size); | ||||||
|  |  | ||||||
|  | @ -74,6 +74,8 @@ typedef struct { | ||||||
| #define UPDATE_SHADOW_PTR(hw) \ | #define UPDATE_SHADOW_PTR(hw) \ | ||||||
| 	do { if (hw->shadow_appl_ptr && !hw->avail_update_flag) \ | 	do { if (hw->shadow_appl_ptr && !hw->avail_update_flag) \ | ||||||
| 	       hw->appl_ptr = hw->mmap_control->appl_ptr; } while (0) | 	       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 */ | #endif /* DOC_HIDDEN */ | ||||||
| 
 | 
 | ||||||
|  | @ -593,29 +595,31 @@ static int snd_pcm_hw_close(snd_pcm_t *pcm) | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int snd_pcm_hw_mmap_commit(snd_pcm_t *pcm, | 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 offset ATTRIBUTE_UNUSED, | ||||||
| 				  snd_pcm_uframes_t size) | 						snd_pcm_uframes_t size) | ||||||
| { | { | ||||||
| 	snd_pcm_hw_t *hw = pcm->private_data; | 	snd_pcm_hw_t *hw = pcm->private_data; | ||||||
|  | 
 | ||||||
| 	if (hw->mmap_shm) { | 	if (hw->mmap_shm) { | ||||||
| 		if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { | 		if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { | ||||||
| 		    	snd_pcm_sframes_t res; | 		    	snd_pcm_sframes_t result = 0, res; | ||||||
| 
 | 
 | ||||||
| 			do { | 			do { | ||||||
| 				res = snd_pcm_write_mmap(pcm, size); | 				res = snd_pcm_write_mmap(pcm, size); | ||||||
| 				if (res < 0) | 				if (res < 0) | ||||||
| 					return res; | 					return result > 0 ? result : res; | ||||||
| 				size -= res; | 				size -= res; | ||||||
|  | 				result += res; | ||||||
| 			} while (size > 0); | 			} while (size > 0); | ||||||
| 			return 0; | 			return result; | ||||||
| 		} else { | 		} else { | ||||||
| 			snd_pcm_hw_t *hw = pcm->private_data; | 			snd_pcm_hw_t *hw = pcm->private_data; | ||||||
| 			assert(hw->shadow_appl_ptr); | 			assert(hw->shadow_appl_ptr); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	snd_pcm_mmap_appl_forward(pcm, size); | 	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) | 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; | 			return err; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	if (avail >= pcm->stop_threshold) { | 	switch (FAST_PCM_STATE(hw)) { | ||||||
| 		/* SNDRV_PCM_IOCTL_XRUN ioctl has been implemented since PCM kernel API 2.0.1 */ | 	case SNDRV_PCM_STATE_RUNNING: | ||||||
| 		if (SNDRV_PROTOCOL_VERSION(2, 0, 1) <= hw->version) { | 		if (avail >= pcm->stop_threshold) { | ||||||
| 			if (ioctl(hw->fd, SND_PCM_IOCTL_XRUN) < 0) | 			/* SNDRV_PCM_IOCTL_XRUN ioctl has been implemented since PCM kernel API 2.0.1 */ | ||||||
| 				return -errno; | 			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; | 		return -EPIPE; | ||||||
|  | 	default: | ||||||
|  | 		break; | ||||||
| 	} | 	} | ||||||
| 	return avail; | 	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)); | 	ladspa = calloc(1, sizeof(snd_pcm_ladspa_t)); | ||||||
| 	if (!ladspa) | 	if (!ladspa) | ||||||
| 		return -ENOMEM; | 		return -ENOMEM; | ||||||
|  | 	snd_pcm_plugin_init(&ladspa->plug); | ||||||
| 	ladspa->plug.init = snd_pcm_ladspa_init; | 	ladspa->plug.init = snd_pcm_ladspa_init; | ||||||
| 	ladspa->plug.read = snd_pcm_ladspa_read_areas; | 	ladspa->plug.read = snd_pcm_ladspa_read_areas; | ||||||
| 	ladspa->plug.write = snd_pcm_ladspa_write_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.slave = slave; | ||||||
| 	ladspa->plug.close_slave = close_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) { | 	if (!lfloat) { | ||||||
| 		return -ENOMEM; | 		return -ENOMEM; | ||||||
| 	} | 	} | ||||||
|  | 	snd_pcm_plugin_init(&lfloat->plug); | ||||||
| 	lfloat->sformat = sformat; | 	lfloat->sformat = sformat; | ||||||
| 	lfloat->plug.read = snd_pcm_lfloat_read_areas; | 	lfloat->plug.read = snd_pcm_lfloat_read_areas; | ||||||
| 	lfloat->plug.write = snd_pcm_lfloat_write_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.slave = slave; | ||||||
| 	lfloat->plug.close_slave = close_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) { | 	if (!linear) { | ||||||
| 		return -ENOMEM; | 		return -ENOMEM; | ||||||
| 	} | 	} | ||||||
|  | 	snd_pcm_plugin_init(&linear->plug); | ||||||
| 	linear->sformat = sformat; | 	linear->sformat = sformat; | ||||||
| 	linear->plug.read = snd_pcm_linear_read_areas; | 	linear->plug.read = snd_pcm_linear_read_areas; | ||||||
| 	linear->plug.write = snd_pcm_linear_write_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.slave = slave; | ||||||
| 	linear->plug.close_slave = close_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 (*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 (*readn)(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size); | ||||||
| 	snd_pcm_sframes_t (*avail_update)(snd_pcm_t *pcm); | 	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; | } snd_pcm_fast_ops_t; | ||||||
| 
 | 
 | ||||||
| struct _snd_pcm { | struct _snd_pcm { | ||||||
|  |  | ||||||
|  | @ -396,9 +396,9 @@ static int snd_pcm_meter_resume(snd_pcm_t *pcm) | ||||||
| 	return snd_pcm_resume(meter->slave); | 	return snd_pcm_resume(meter->slave); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int snd_pcm_meter_mmap_commit(snd_pcm_t *pcm, | static snd_pcm_sframes_t snd_pcm_meter_mmap_commit(snd_pcm_t *pcm, | ||||||
| 				     snd_pcm_uframes_t offset, | 						   snd_pcm_uframes_t offset, | ||||||
| 				     snd_pcm_uframes_t size) | 						   snd_pcm_uframes_t size) | ||||||
| { | { | ||||||
| 	snd_pcm_meter_t *meter = pcm->private_data; | 	snd_pcm_meter_t *meter = pcm->private_data; | ||||||
| 	snd_pcm_uframes_t old_rptr = *pcm->appl_ptr; | 	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) | 	if (result <= 0) | ||||||
| 		return result; | 		return result; | ||||||
| 	if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { | 	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; | 		meter->rptr = *pcm->appl_ptr; | ||||||
| 	} | 	} | ||||||
| 	return 0; | 	return result; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static snd_pcm_sframes_t snd_pcm_meter_avail_update(snd_pcm_t *pcm) | 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 size) | ||||||
| { | { | ||||||
| 	snd_pcm_uframes_t xfer = 0; | 	snd_pcm_uframes_t xfer = 0; | ||||||
| 	int err; |  | ||||||
| 
 | 
 | ||||||
| 	assert(snd_pcm_mmap_playback_avail(pcm) >= size); | 	assert(snd_pcm_mmap_playback_avail(pcm) >= size); | ||||||
| 	while (size > 0) { | 	while (size > 0) { | ||||||
| 		const snd_pcm_channel_area_t *pcm_areas; | 		const snd_pcm_channel_area_t *pcm_areas; | ||||||
| 		snd_pcm_uframes_t pcm_offset; | 		snd_pcm_uframes_t pcm_offset; | ||||||
| 		snd_pcm_uframes_t frames = size; | 		snd_pcm_uframes_t frames = size; | ||||||
|  | 		snd_pcm_sframes_t result; | ||||||
|  | 
 | ||||||
| 		snd_pcm_mmap_begin(pcm, &pcm_areas, &pcm_offset, &frames); | 		snd_pcm_mmap_begin(pcm, &pcm_areas, &pcm_offset, &frames); | ||||||
| 		snd_pcm_areas_copy(pcm_areas, pcm_offset, | 		snd_pcm_areas_copy(pcm_areas, pcm_offset, | ||||||
| 				   areas, offset,  | 				   areas, offset,  | ||||||
| 				   pcm->channels,  | 				   pcm->channels,  | ||||||
| 				   frames, pcm->format); | 				   frames, pcm->format); | ||||||
| 		err = snd_pcm_mmap_commit(pcm, pcm_offset, frames); | 		result = snd_pcm_mmap_commit(pcm, pcm_offset, frames); | ||||||
| 		if (err < 0) | 		if (result < 0) | ||||||
| 			return xfer > 0 ? xfer : err; | 			return xfer > 0 ? xfer : result; | ||||||
| 		offset += frames; | 		offset += result; | ||||||
| 		xfer += frames; | 		xfer += result; | ||||||
| 		size -= frames; | 		size -= result; | ||||||
| 	} | 	} | ||||||
| 	return xfer; | 	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 size) | ||||||
| { | { | ||||||
| 	snd_pcm_uframes_t xfer = 0; | 	snd_pcm_uframes_t xfer = 0; | ||||||
| 	int err; |  | ||||||
| 
 | 
 | ||||||
| 	assert(snd_pcm_mmap_capture_avail(pcm) >= size); | 	assert(snd_pcm_mmap_capture_avail(pcm) >= size); | ||||||
| 	while (size > 0) { | 	while (size > 0) { | ||||||
| 		const snd_pcm_channel_area_t *pcm_areas; | 		const snd_pcm_channel_area_t *pcm_areas; | ||||||
| 		snd_pcm_uframes_t pcm_offset; | 		snd_pcm_uframes_t pcm_offset; | ||||||
| 		snd_pcm_uframes_t frames = size; | 		snd_pcm_uframes_t frames = size; | ||||||
|  | 		snd_pcm_sframes_t result; | ||||||
|  | 		 | ||||||
| 		snd_pcm_mmap_begin(pcm, &pcm_areas, &pcm_offset, &frames); | 		snd_pcm_mmap_begin(pcm, &pcm_areas, &pcm_offset, &frames); | ||||||
| 		snd_pcm_areas_copy(areas, offset, | 		snd_pcm_areas_copy(areas, offset, | ||||||
| 				   pcm_areas, pcm_offset, | 				   pcm_areas, pcm_offset, | ||||||
| 				   pcm->channels,  | 				   pcm->channels,  | ||||||
| 				   frames, pcm->format); | 				   frames, pcm->format); | ||||||
| 		err = snd_pcm_mmap_commit(pcm, pcm_offset, frames); | 		result = snd_pcm_mmap_commit(pcm, pcm_offset, frames); | ||||||
| 		if (err < 0) | 		if (result < 0) | ||||||
| 			return xfer > 0 ? xfer : err; | 			return xfer > 0 ? xfer : result; | ||||||
| 		offset += frames; | 		offset += result; | ||||||
| 		xfer += frames; | 		xfer += result; | ||||||
| 		size -= frames; | 		size -= result; | ||||||
| 	} | 	} | ||||||
| 	return xfer; | 	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) { | 	if (!mulaw) { | ||||||
| 		return -ENOMEM; | 		return -ENOMEM; | ||||||
| 	} | 	} | ||||||
|  | 	snd_pcm_plugin_init(&mulaw->plug); | ||||||
| 	mulaw->sformat = sformat; | 	mulaw->sformat = sformat; | ||||||
| 	mulaw->plug.read = snd_pcm_mulaw_read_areas; | 	mulaw->plug.read = snd_pcm_mulaw_read_areas; | ||||||
| 	mulaw->plug.write = snd_pcm_mulaw_write_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.slave = slave; | ||||||
| 	mulaw->plug.close_slave = close_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) { | 	for (i = 0; i < multi->slaves_count; ++i) { | ||||||
| 		snd_pcm_t *slave_i = multi->slaves[i].pcm; | 		snd_pcm_t *slave_i = multi->slaves[i].pcm; | ||||||
| 		snd_pcm_uframes_t f = pos[i] - frames; | 		snd_pcm_uframes_t f = pos[i] - frames; | ||||||
| 		if (f > 0) | 		snd_pcm_sframes_t result; | ||||||
| 			snd_pcm_mmap_commit(slave_i, snd_pcm_mmap_offset(slave_i), f); | 		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; | 	return frames; | ||||||
| } | } | ||||||
|  | @ -517,20 +523,22 @@ static int snd_pcm_multi_resume(snd_pcm_t *pcm) | ||||||
| 	return err; | 	return err; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int snd_pcm_multi_mmap_commit(snd_pcm_t *pcm, | static snd_pcm_sframes_t snd_pcm_multi_mmap_commit(snd_pcm_t *pcm, | ||||||
| 				     snd_pcm_uframes_t offset, | 						   snd_pcm_uframes_t offset, | ||||||
| 				     snd_pcm_uframes_t size) | 						   snd_pcm_uframes_t size) | ||||||
| { | { | ||||||
| 	snd_pcm_multi_t *multi = pcm->private_data; | 	snd_pcm_multi_t *multi = pcm->private_data; | ||||||
| 	snd_pcm_t *slave; | 	snd_pcm_t *slave; | ||||||
| 	unsigned int i; | 	unsigned int i; | ||||||
| 	int err; | 	snd_pcm_sframes_t result; | ||||||
| 
 | 
 | ||||||
| 	for (i = 0; i < multi->slaves_count; ++i) { | 	for (i = 0; i < multi->slaves_count; ++i) { | ||||||
| 		slave = multi->slaves[i].pcm; | 		slave = multi->slaves[i].pcm; | ||||||
| 		err = snd_pcm_mmap_commit(slave, offset, size); | 		result = snd_pcm_mmap_commit(slave, offset, size); | ||||||
| 		if (err < 0) | 		if (result < 0) | ||||||
| 			return err; | 			return result; | ||||||
|  | 		if ((snd_pcm_uframes_t)result != size) | ||||||
|  | 			return -EIO; | ||||||
| 	} | 	} | ||||||
| 	return 0; | 	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); | 	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, | 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 offset ATTRIBUTE_UNUSED, | ||||||
| 				    snd_pcm_uframes_t size) | 						  snd_pcm_uframes_t size) | ||||||
| { | { | ||||||
| 	snd_pcm_sframes_t res; | 	snd_pcm_sframes_t res; | ||||||
| 	 | 	 | ||||||
| 	res = snd_pcm_null_fwd(pcm, size); | 	res = snd_pcm_null_fwd(pcm, size); | ||||||
| 	if (res < 0) | 	if (res < 0) | ||||||
| 		return res; | 		return res; | ||||||
| 	assert((snd_pcm_uframes_t)res == size); | 	return res; | ||||||
| 	return 0; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static snd_pcm_sframes_t snd_pcm_null_avail_update(snd_pcm_t *pcm) | static snd_pcm_sframes_t snd_pcm_null_avail_update(snd_pcm_t *pcm) | ||||||
|  |  | ||||||
|  | @ -89,6 +89,53 @@ pcm.rate44100Hz { | ||||||
| 
 | 
 | ||||||
| #ifndef DOC_HIDDEN | #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) | int snd_pcm_plugin_close(snd_pcm_t *pcm) | ||||||
| { | { | ||||||
| 	snd_pcm_plugin_t *plugin = pcm->private_data; | 	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_plugin_t *plugin = pcm->private_data; | ||||||
| 	snd_pcm_t *slave = plugin->slave; | 	snd_pcm_t *slave = plugin->slave; | ||||||
| 	snd_pcm_uframes_t xfer = 0; | 	snd_pcm_uframes_t xfer = 0; | ||||||
| 	snd_pcm_sframes_t err; | 	snd_pcm_sframes_t result; | ||||||
| 
 | 
 | ||||||
| 	while (size > 0) { | 	while (size > 0) { | ||||||
| 		snd_pcm_uframes_t frames = size; | 		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)); | 		assert(slave_frames <= snd_pcm_mmap_playback_avail(slave)); | ||||||
| 		snd_atomic_write_begin(&plugin->watom); | 		snd_atomic_write_begin(&plugin->watom); | ||||||
| 		snd_pcm_mmap_appl_forward(pcm, frames); | 		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); | 		snd_atomic_write_end(&plugin->watom); | ||||||
| 		if (err < 0) | 		if (result < 0) | ||||||
| 			return xfer > 0 ? xfer : err; | 			return xfer > 0 ? xfer : result; | ||||||
| 		offset += frames; | 		offset += result; | ||||||
| 		xfer += frames; | 		xfer += result; | ||||||
| 		size -= frames; | 		size -= result; | ||||||
| 	} | 	} | ||||||
| 	return xfer; | 	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_plugin_t *plugin = pcm->private_data; | ||||||
| 	snd_pcm_t *slave = plugin->slave; | 	snd_pcm_t *slave = plugin->slave; | ||||||
| 	snd_pcm_uframes_t xfer = 0; | 	snd_pcm_uframes_t xfer = 0; | ||||||
| 	snd_pcm_sframes_t err; | 	snd_pcm_sframes_t result; | ||||||
| 	 | 	 | ||||||
| 	while (size > 0) { | 	while (size > 0) { | ||||||
| 		snd_pcm_uframes_t frames = size; | 		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)); | 		assert(slave_frames <= snd_pcm_mmap_capture_avail(slave)); | ||||||
| 		snd_atomic_write_begin(&plugin->watom); | 		snd_atomic_write_begin(&plugin->watom); | ||||||
| 		snd_pcm_mmap_appl_forward(pcm, frames); | 		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); | 		snd_atomic_write_end(&plugin->watom); | ||||||
| 		if (err < 0) | 		if (result < 0) | ||||||
| 			return xfer > 0 ? xfer : err; | 			return xfer > 0 ? xfer : result; | ||||||
| 		offset += frames; | 		offset += result; | ||||||
| 		xfer += frames; | 		xfer += result; | ||||||
| 		size -= frames; | 		size -= result; | ||||||
| 	} | 	} | ||||||
| 	return xfer; | 	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); | 				  snd_pcm_plugin_read_areas); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int snd_pcm_plugin_mmap_commit(snd_pcm_t *pcm, | snd_pcm_sframes_t snd_pcm_plugin_mmap_commit(snd_pcm_t *pcm, | ||||||
| 			       snd_pcm_uframes_t offset ATTRIBUTE_UNUSED, | 					     snd_pcm_uframes_t offset ATTRIBUTE_UNUSED, | ||||||
| 			       snd_pcm_uframes_t size) | 					     snd_pcm_uframes_t size) | ||||||
| { | { | ||||||
| 	snd_pcm_plugin_t *plugin = pcm->private_data; | 	snd_pcm_plugin_t *plugin = pcm->private_data; | ||||||
| 	snd_pcm_t *slave = plugin->slave; | 	snd_pcm_t *slave = plugin->slave; | ||||||
| 	const snd_pcm_channel_area_t *areas; | 	const snd_pcm_channel_area_t *areas; | ||||||
| 	snd_pcm_uframes_t appl_offset; | 	snd_pcm_uframes_t appl_offset; | ||||||
| 	snd_pcm_sframes_t slave_size; | 	snd_pcm_sframes_t slave_size; | ||||||
|  | 	snd_pcm_sframes_t xfer; | ||||||
| 
 | 
 | ||||||
| 	if (pcm->stream == SND_PCM_STREAM_CAPTURE) { | 	if (pcm->stream == SND_PCM_STREAM_CAPTURE) { | ||||||
| 		snd_atomic_write_begin(&plugin->watom); | 		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); | 	slave_size = snd_pcm_avail_update(slave); | ||||||
| 	if (slave_size < 0) | 	if (slave_size < 0) | ||||||
| 		return slave_size; | 		return slave_size; | ||||||
| 	if ((snd_pcm_uframes_t)slave_size < size) |  | ||||||
| 		return -EIO; |  | ||||||
| 	areas = snd_pcm_mmap_areas(pcm); | 	areas = snd_pcm_mmap_areas(pcm); | ||||||
| 	appl_offset = snd_pcm_mmap_offset(pcm); | 	appl_offset = snd_pcm_mmap_offset(pcm); | ||||||
|  | 	xfer = 0; | ||||||
| 	while (size > 0 && slave_size > 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 - appl_offset; | 		snd_pcm_uframes_t cont = pcm->buffer_size - appl_offset; | ||||||
| 		const snd_pcm_channel_area_t *slave_areas; | 		const snd_pcm_channel_area_t *slave_areas; | ||||||
| 		snd_pcm_uframes_t slave_offset; | 		snd_pcm_uframes_t slave_offset; | ||||||
| 		snd_pcm_uframes_t slave_frames = ULONG_MAX; | 		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) | 		if (frames > cont) | ||||||
| 			frames = cont; | 			frames = cont; | ||||||
| 		frames = plugin->write(pcm, areas, appl_offset, frames, | 		frames = plugin->write(pcm, areas, appl_offset, frames, | ||||||
| 				       slave_areas, slave_offset, &slave_frames); | 				       slave_areas, slave_offset, &slave_frames); | ||||||
| 		snd_atomic_write_begin(&plugin->watom); | 		snd_atomic_write_begin(&plugin->watom); | ||||||
| 		snd_pcm_mmap_appl_forward(pcm, frames); | 		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); | 		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) | 		if (frames == cont) | ||||||
| 			appl_offset = 0; | 			appl_offset = 0; | ||||||
| 		else | 		else | ||||||
| 			appl_offset += frames; | 			appl_offset += result; | ||||||
| 		size -= frames; | 		size -= frames; | ||||||
| 		slave_size -= slave_frames; | 		slave_size -= frames; | ||||||
|  | 		xfer += frames; | ||||||
| 	} | 	} | ||||||
| 	assert(size == 0); | 	assert(size == 0); | ||||||
| 	return 0; | 	return xfer; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| snd_pcm_sframes_t snd_pcm_plugin_avail_update(snd_pcm_t *pcm) | 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; | 		const snd_pcm_channel_area_t *areas; | ||||||
| 		snd_pcm_uframes_t xfer, hw_offset, size; | 		snd_pcm_uframes_t xfer, hw_offset, size; | ||||||
| 		 | 		 | ||||||
| 		xfer = snd_pcm_mmap_capture_avail(pcm); | 		size = snd_pcm_mmap_capture_avail(pcm); | ||||||
| 		size = pcm->buffer_size - xfer; | 		size = pcm->buffer_size - size; | ||||||
| 		areas = snd_pcm_mmap_areas(pcm); | 		areas = snd_pcm_mmap_areas(pcm); | ||||||
| 		hw_offset = snd_pcm_mmap_hw_offset(pcm); | 		hw_offset = snd_pcm_mmap_hw_offset(pcm); | ||||||
|  | 		xfer = 0; | ||||||
| 		while (size > 0 && slave_size > 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; | 			snd_pcm_uframes_t cont = pcm->buffer_size - hw_offset; | ||||||
| 			const snd_pcm_channel_area_t *slave_areas; | 			const snd_pcm_channel_area_t *slave_areas; | ||||||
| 			snd_pcm_uframes_t slave_offset; | 			snd_pcm_uframes_t slave_offset; | ||||||
| 			snd_pcm_uframes_t slave_frames = ULONG_MAX; | 			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) | 			if (frames > cont) | ||||||
| 				frames = cont; | 				frames = cont; | ||||||
| 			frames = plugin->read(pcm, areas, hw_offset, frames, | 			frames = plugin->read(pcm, areas, hw_offset, frames, | ||||||
| 					      slave_areas, slave_offset, &slave_frames); | 					      slave_areas, slave_offset, &slave_frames); | ||||||
| 			snd_atomic_write_begin(&plugin->watom); | 			snd_atomic_write_begin(&plugin->watom); | ||||||
| 			snd_pcm_mmap_hw_forward(pcm, frames); | 			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); | 			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) | 			if (frames == cont) | ||||||
| 				hw_offset = 0; | 				hw_offset = 0; | ||||||
| 			else | 			else | ||||||
| 				hw_offset += frames; | 				hw_offset += frames; | ||||||
| 			size -= frames; | 			size -= frames; | ||||||
| 			slave_size -= slave_frames; | 			slave_size -= slave_frames; | ||||||
|  | 			xfer += frames; | ||||||
| 		} | 		} | ||||||
| 		return xfer; | 		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_offset,  | ||||||
|       snd_pcm_uframes_t *slave_sizep); |       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 { | typedef struct { | ||||||
| 	snd_pcm_t *slave; | 	snd_pcm_t *slave; | ||||||
| 	int close_slave; | 	int close_slave; | ||||||
| 	snd_pcm_slave_xfer_areas_func_t read; | 	snd_pcm_slave_xfer_areas_func_t read; | ||||||
| 	snd_pcm_slave_xfer_areas_func_t write; | 	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 (*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); | 	snd_pcm_sframes_t (*slave_frames)(snd_pcm_t *pcm, snd_pcm_sframes_t frames); | ||||||
| 	int (*init)(snd_pcm_t *pcm); | 	int (*init)(snd_pcm_t *pcm); | ||||||
|  | @ -43,6 +52,7 @@ typedef struct { | ||||||
| 	snd_atomic_write_t watom; | 	snd_atomic_write_t watom; | ||||||
| } snd_pcm_plugin_t;	 | } 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_close(snd_pcm_t *pcm); | ||||||
| int snd_pcm_plugin_card(snd_pcm_t *pcm); | int snd_pcm_plugin_card(snd_pcm_t *pcm); | ||||||
| int snd_pcm_plugin_nonblock(snd_pcm_t *pcm, int nonblock); | 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_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_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); | 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); | 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_status(snd_pcm_t *pcm); | ||||||
| int snd_pcm_plugin_mmap_control(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; | 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_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_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); | 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) { | 	if (!rate) { | ||||||
| 		return -ENOMEM; | 		return -ENOMEM; | ||||||
| 	} | 	} | ||||||
|  | 	snd_pcm_plugin_init(&rate->plug); | ||||||
| 	rate->srate = srate; | 	rate->srate = srate; | ||||||
| 	rate->sformat = sformat; | 	rate->sformat = sformat; | ||||||
| 	rate->plug.read = snd_pcm_rate_read_areas; | 	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) { | 	if (!route) { | ||||||
| 		return -ENOMEM; | 		return -ENOMEM; | ||||||
| 	} | 	} | ||||||
|  | 	snd_pcm_plugin_init(&route->plug); | ||||||
| 	route->sformat = sformat; | 	route->sformat = sformat; | ||||||
| 	route->schannels = schannels; | 	route->schannels = schannels; | ||||||
| 	route->plug.read = snd_pcm_route_read_areas; | 	route->plug.read = snd_pcm_route_read_areas; | ||||||
| 	route->plug.write = snd_pcm_route_write_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.slave = slave; | ||||||
| 	route->plug.close_slave = close_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 */ | /* Call it with mutex held */ | ||||||
| static int _snd_pcm_share_mmap_commit(snd_pcm_t *pcm, | 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 offset ATTRIBUTE_UNUSED, | ||||||
| 				      snd_pcm_uframes_t size) | 						    snd_pcm_uframes_t size) | ||||||
| { | { | ||||||
| 	snd_pcm_share_t *share = pcm->private_data; | 	snd_pcm_share_t *share = pcm->private_data; | ||||||
| 	snd_pcm_share_slave_t *slave = share->slave; | 	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); | 		_snd_pcm_share_update(pcm); | ||||||
| 	} | 	} | ||||||
| 	return 0; | 	return size; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int snd_pcm_share_mmap_commit(snd_pcm_t *pcm, | static snd_pcm_sframes_t snd_pcm_share_mmap_commit(snd_pcm_t *pcm, | ||||||
| 				     snd_pcm_uframes_t offset, | 						   snd_pcm_uframes_t offset, | ||||||
| 				     snd_pcm_uframes_t size) | 						   snd_pcm_uframes_t size) | ||||||
| { | { | ||||||
| 	snd_pcm_share_t *share = pcm->private_data; | 	snd_pcm_share_t *share = pcm->private_data; | ||||||
| 	snd_pcm_share_slave_t *slave = share->slave; | 	snd_pcm_share_slave_t *slave = share->slave; | ||||||
|  | @ -909,8 +909,15 @@ static int snd_pcm_share_start(snd_pcm_t *pcm) | ||||||
| 			xfer += frames; | 			xfer += frames; | ||||||
| 		} | 		} | ||||||
| 		snd_pcm_mmap_appl_forward(pcm, hw_avail); | 		snd_pcm_mmap_appl_forward(pcm, hw_avail); | ||||||
| 		if (slave->running_count == 0) | 		if (slave->running_count == 0) { | ||||||
| 			snd_pcm_mmap_commit(spcm, snd_pcm_mmap_offset(spcm), hw_avail); | 			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) { | 	if (slave->running_count == 0) { | ||||||
| 		err = snd_pcm_start(spcm); | 		err = snd_pcm_start(spcm); | ||||||
|  |  | ||||||
|  | @ -93,7 +93,7 @@ int receive_fd(int sock, void *data, size_t len, int *fd) | ||||||
| } | } | ||||||
| #endif | #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; | 	snd_pcm_shm_t *shm = pcm->private_data; | ||||||
| 	int err; | 	int err; | ||||||
|  | @ -112,7 +112,7 @@ static int snd_pcm_shm_action(snd_pcm_t *pcm) | ||||||
| 	return ctrl->result; | 	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; | 	snd_pcm_shm_t *shm = pcm->private_data; | ||||||
| 	int err; | 	int err; | ||||||
|  | @ -457,9 +457,9 @@ static int snd_pcm_shm_resume(snd_pcm_t *pcm) | ||||||
| 	return snd_pcm_shm_action(pcm); | 	return snd_pcm_shm_action(pcm); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int snd_pcm_shm_mmap_commit(snd_pcm_t *pcm, | 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 offset ATTRIBUTE_UNUSED, | ||||||
| 				   snd_pcm_uframes_t size) | 						 snd_pcm_uframes_t size) | ||||||
| { | { | ||||||
| 	snd_pcm_shm_t *shm = pcm->private_data; | 	snd_pcm_shm_t *shm = pcm->private_data; | ||||||
| 	volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl; | 	volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Jaroslav Kysela
						Jaroslav Kysela