mirror of
				https://github.com/alsa-project/alsa-lib.git
				synced 2025-11-03 09:01:52 -05:00 
			
		
		
		
	- added snd_pcm_mmap_begin_avail function; it is optimized for use after
snd_pcm_avail_update() call - fixed broken hw_ptr management inside snd_pcm_plugin code
This commit is contained in:
		
							parent
							
								
									b63e44aab0
								
							
						
					
					
						commit
						b7b11c3558
					
				
					 4 changed files with 187 additions and 69 deletions
				
			
		| 
						 | 
				
			
			@ -4845,7 +4845,7 @@ int snd_pcm_mmap_begin(snd_pcm_t *pcm,
 | 
			
		|||
		       snd_pcm_uframes_t *frames)
 | 
			
		||||
{
 | 
			
		||||
	snd_pcm_uframes_t cont;
 | 
			
		||||
	snd_pcm_uframes_t avail;
 | 
			
		||||
	snd_pcm_sframes_t avail;
 | 
			
		||||
	snd_pcm_uframes_t f;
 | 
			
		||||
	assert(pcm && areas && offset && frames);
 | 
			
		||||
	if (pcm->stopped_areas &&
 | 
			
		||||
| 
						 | 
				
			
			@ -4855,7 +4855,43 @@ int snd_pcm_mmap_begin(snd_pcm_t *pcm,
 | 
			
		|||
		*areas = pcm->running_areas;
 | 
			
		||||
	*offset = *pcm->appl_ptr % pcm->buffer_size;
 | 
			
		||||
	cont = pcm->buffer_size - *offset;
 | 
			
		||||
	avail = snd_pcm_mmap_avail(pcm);
 | 
			
		||||
	avail = snd_pcm_avail_update(pcm);
 | 
			
		||||
	if (avail < 0)
 | 
			
		||||
		return avail;
 | 
			
		||||
	f = *frames;
 | 
			
		||||
	if (f > (snd_pcm_uframes_t)avail)
 | 
			
		||||
		f = avail;
 | 
			
		||||
	if (f > cont)
 | 
			
		||||
		f = cont;
 | 
			
		||||
	*frames = f;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * \brief Application request to access a portion of direct (mmap) area
 | 
			
		||||
 * \param pcm PCM handle 
 | 
			
		||||
 * \param areas Returned mmap channel areas
 | 
			
		||||
 * \param offset Returned mmap area offset in area steps (== frames)
 | 
			
		||||
 * \param size mmap area portion size in frames (wanted on entry, contiguous available on exit)
 | 
			
		||||
 * \param avail available frames (result from snd_pcm_avail_update())
 | 
			
		||||
 * \return 0 on success otherwise a negative error code
 | 
			
		||||
 */
 | 
			
		||||
int snd_pcm_mmap_begin_avail(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 avail)
 | 
			
		||||
{
 | 
			
		||||
	snd_pcm_uframes_t cont;
 | 
			
		||||
	snd_pcm_uframes_t f;
 | 
			
		||||
	assert(pcm && areas && offset && frames && avail <= pcm->buffer_size);
 | 
			
		||||
	if (pcm->stopped_areas &&
 | 
			
		||||
	    snd_pcm_state(pcm) != SND_PCM_STATE_RUNNING) 
 | 
			
		||||
		*areas = pcm->stopped_areas;
 | 
			
		||||
	else
 | 
			
		||||
		*areas = pcm->running_areas;
 | 
			
		||||
	*offset = *pcm->appl_ptr % pcm->buffer_size;
 | 
			
		||||
	cont = pcm->buffer_size - *offset;
 | 
			
		||||
	f = *frames;
 | 
			
		||||
	if (f > avail)
 | 
			
		||||
		f = avail;
 | 
			
		||||
| 
						 | 
				
			
			@ -4879,7 +4915,7 @@ int snd_pcm_mmap_begin(snd_pcm_t *pcm,
 | 
			
		|||
 * count that snd_pcm_mmap_begin() returned. Each call to snd_pcm_mmap_begin()
 | 
			
		||||
 * must be followed by a call to snd_pcm_mmap_commit().
 | 
			
		||||
 *
 | 
			
		||||
 * Example:
 | 
			
		||||
 * Example #1:
 | 
			
		||||
\code
 | 
			
		||||
  double phase = 0;
 | 
			
		||||
  const snd_pcm_area_t *areas;
 | 
			
		||||
| 
						 | 
				
			
			@ -4894,6 +4930,27 @@ int snd_pcm_mmap_begin(snd_pcm_t *pcm,
 | 
			
		|||
  err = snd_pcm_mmap_commit(pcm_handle, offset, frames);
 | 
			
		||||
  if (err < 0)
 | 
			
		||||
    error(err);
 | 
			
		||||
\endcode
 | 
			
		||||
 *
 | 
			
		||||
 * Example #2 (determine available frame count at beginning):
 | 
			
		||||
\code
 | 
			
		||||
  double phase = 0;
 | 
			
		||||
  const snd_pcm_area_t *areas;
 | 
			
		||||
  snd_pcm_sframes_t avail;
 | 
			
		||||
  snd_pcm_uframes_t offset, frames;
 | 
			
		||||
 | 
			
		||||
  avail = snd_pcm_avail_update(pcm);
 | 
			
		||||
  if (avail < 0)
 | 
			
		||||
    error(avail);
 | 
			
		||||
  frames = frame_buffer_size > avail ? avail : frame_buffer_size;
 | 
			
		||||
  err = snd_pcm_mmap_begin_avail(pcm_handle, &areas, &offset, &frames, avail);
 | 
			
		||||
  if (err < 0)
 | 
			
		||||
    error(err);
 | 
			
		||||
  // this function fills the areas from offset with count of frames
 | 
			
		||||
  generate_sine(areas, offset, frames, &phase);
 | 
			
		||||
  err = snd_pcm_mmap_commit(pcm_handle, offset, frames);
 | 
			
		||||
  if (err < 0)
 | 
			
		||||
    error(err);
 | 
			
		||||
\endcode
 | 
			
		||||
 *
 | 
			
		||||
 * Look to the \ref example_test_pcm "Sine-wave generator" example
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -218,7 +218,6 @@ 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);
 | 
			
		||||
		snd_pcm_mmap_hw_forward(pcm, frames);
 | 
			
		||||
		err = snd_pcm_mmap_commit(slave, slave_offset, slave_frames);
 | 
			
		||||
		snd_atomic_write_end(&plugin->watom);
 | 
			
		||||
		if (err < 0)
 | 
			
		||||
| 
						 | 
				
			
			@ -251,7 +250,6 @@ 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);
 | 
			
		||||
		snd_pcm_mmap_hw_forward(pcm, frames);
 | 
			
		||||
		err = snd_pcm_mmap_commit(slave, slave_offset, slave_frames);
 | 
			
		||||
		snd_atomic_write_end(&plugin->watom);
 | 
			
		||||
		if (err < 0)
 | 
			
		||||
| 
						 | 
				
			
			@ -303,8 +301,9 @@ int snd_pcm_plugin_mmap_commit(snd_pcm_t *pcm,
 | 
			
		|||
	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 xfer, hw_offset;
 | 
			
		||||
	snd_pcm_uframes_t appl_offset;
 | 
			
		||||
	snd_pcm_sframes_t slave_size;
 | 
			
		||||
 | 
			
		||||
	if (pcm->stream == SND_PCM_STREAM_CAPTURE) {
 | 
			
		||||
		snd_atomic_write_begin(&plugin->watom);
 | 
			
		||||
		snd_pcm_mmap_appl_forward(pcm, size);
 | 
			
		||||
| 
						 | 
				
			
			@ -314,32 +313,30 @@ 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 (slave_size == 0)
 | 
			
		||||
	if ((snd_pcm_uframes_t)slave_size < size)
 | 
			
		||||
		return -EIO;
 | 
			
		||||
	areas = snd_pcm_mmap_areas(pcm);
 | 
			
		||||
	hw_offset = snd_pcm_mmap_hw_offset(pcm);
 | 
			
		||||
	xfer = 0;
 | 
			
		||||
	appl_offset = snd_pcm_mmap_offset(pcm);
 | 
			
		||||
	while (size > 0 && slave_size > 0) {
 | 
			
		||||
		snd_pcm_uframes_t frames = size;
 | 
			
		||||
		snd_pcm_uframes_t cont = pcm->buffer_size - hw_offset;
 | 
			
		||||
		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_mmap_begin(slave, &slave_areas, &slave_offset, &slave_frames);
 | 
			
		||||
		if (frames > cont)
 | 
			
		||||
			frames = cont;
 | 
			
		||||
		frames = plugin->write(pcm, areas, hw_offset, frames,
 | 
			
		||||
		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_hw_forward(pcm, frames);
 | 
			
		||||
		snd_pcm_mmap_commit(slave, slave_offset, slave_frames);
 | 
			
		||||
		snd_atomic_write_end(&plugin->watom);
 | 
			
		||||
		xfer += frames;
 | 
			
		||||
		if (frames == cont)
 | 
			
		||||
			hw_offset = 0;
 | 
			
		||||
			appl_offset = 0;
 | 
			
		||||
		else
 | 
			
		||||
			hw_offset += frames;
 | 
			
		||||
			appl_offset += frames;
 | 
			
		||||
		size -= frames;
 | 
			
		||||
		slave_size -= slave_frames;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -351,46 +348,56 @@ snd_pcm_sframes_t snd_pcm_plugin_avail_update(snd_pcm_t *pcm)
 | 
			
		|||
{
 | 
			
		||||
	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 xfer, hw_offset, size;
 | 
			
		||||
	snd_pcm_sframes_t slave_size;
 | 
			
		||||
 | 
			
		||||
	slave_size = snd_pcm_avail_update(slave);
 | 
			
		||||
	if (slave_size <= 0)
 | 
			
		||||
	if (pcm->stream == SND_PCM_STREAM_CAPTURE &&
 | 
			
		||||
	    pcm->access != SND_PCM_ACCESS_RW_INTERLEAVED &&
 | 
			
		||||
	    pcm->access != SND_PCM_ACCESS_RW_NONINTERLEAVED)
 | 
			
		||||
		goto _capture;
 | 
			
		||||
	if (plugin->client_frames) {
 | 
			
		||||
		plugin->hw_ptr = plugin->client_frames(slave, *slave->hw_ptr);
 | 
			
		||||
		if (slave_size <= 0)
 | 
			
		||||
			return slave_size;
 | 
			
		||||
		return plugin->client_frames(pcm, slave_size);
 | 
			
		||||
	} else {
 | 
			
		||||
		plugin->hw_ptr = *slave->hw_ptr;
 | 
			
		||||
		return slave_size;
 | 
			
		||||
	if (pcm->stream == SND_PCM_STREAM_PLAYBACK ||
 | 
			
		||||
	    pcm->access == SND_PCM_ACCESS_RW_INTERLEAVED ||
 | 
			
		||||
	    pcm->access == SND_PCM_ACCESS_RW_NONINTERLEAVED)
 | 
			
		||||
		return (plugin->client_frames ?
 | 
			
		||||
			plugin->client_frames(pcm, slave_size) : 
 | 
			
		||||
			slave_size);
 | 
			
		||||
	xfer = snd_pcm_mmap_capture_avail(pcm);
 | 
			
		||||
	size = pcm->buffer_size - xfer;
 | 
			
		||||
	areas = snd_pcm_mmap_areas(pcm);
 | 
			
		||||
	hw_offset = snd_pcm_mmap_hw_offset(pcm);
 | 
			
		||||
	while (size && slave_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);
 | 
			
		||||
		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);
 | 
			
		||||
		snd_atomic_write_end(&plugin->watom);
 | 
			
		||||
		xfer += frames;
 | 
			
		||||
		if (frames == cont)
 | 
			
		||||
			hw_offset = 0;
 | 
			
		||||
		else
 | 
			
		||||
			hw_offset += frames;
 | 
			
		||||
		size -= frames;
 | 
			
		||||
		slave_size -= slave_frames;
 | 
			
		||||
	}
 | 
			
		||||
	return xfer;
 | 
			
		||||
 _capture:
 | 
			
		||||
 	{
 | 
			
		||||
		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;
 | 
			
		||||
		areas = snd_pcm_mmap_areas(pcm);
 | 
			
		||||
		hw_offset = snd_pcm_mmap_hw_offset(pcm);
 | 
			
		||||
		while (size > 0 && slave_size > 0) {
 | 
			
		||||
		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);
 | 
			
		||||
			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);
 | 
			
		||||
			snd_atomic_write_end(&plugin->watom);
 | 
			
		||||
			xfer += frames;
 | 
			
		||||
			if (frames == cont)
 | 
			
		||||
				hw_offset = 0;
 | 
			
		||||
			else
 | 
			
		||||
				hw_offset += frames;
 | 
			
		||||
			size -= frames;
 | 
			
		||||
			slave_size -= slave_frames;
 | 
			
		||||
		}
 | 
			
		||||
		return xfer;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int snd_pcm_plugin_mmap(snd_pcm_t *pcm)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue