mirror of
				https://github.com/alsa-project/alsa-lib.git
				synced 2025-11-03 09:01:52 -05:00 
			
		
		
		
	Added multithread aware status for plugins
This commit is contained in:
		
							parent
							
								
									3196ef28ae
								
							
						
					
					
						commit
						a02e742609
					
				
					 7 changed files with 197 additions and 21 deletions
				
			
		| 
						 | 
				
			
			@ -1,13 +1,13 @@
 | 
			
		|||
 | 
			
		||||
EXTRA_LTLIBRARIES = libpcm.la
 | 
			
		||||
 | 
			
		||||
libpcm_la_SOURCES = mask.c interval.c \
 | 
			
		||||
libpcm_la_SOURCES = atomic.c mask.c interval.c \
 | 
			
		||||
		    pcm.c pcm_m4.c pcm_hw.c pcm_plugin.c pcm_copy.c pcm_linear.c \
 | 
			
		||||
		    pcm_route.c pcm_mulaw.c pcm_alaw.c pcm_adpcm.c \
 | 
			
		||||
		    pcm_rate.c pcm_plug.c pcm_misc.c pcm_mmap.c pcm_multi.c \
 | 
			
		||||
	            pcm_shm.c pcm_file.c pcm_share.c pcm_null.c \
 | 
			
		||||
		    pcm_params.c
 | 
			
		||||
noinst_HEADERS = pcm_local.h pcm_plugin.h mask.h mask_inline.h \
 | 
			
		||||
noinst_HEADERS = atomic.h pcm_local.h pcm_plugin.h mask.h mask_inline.h \
 | 
			
		||||
	         interval.h interval_inline.h plugin_ops.h
 | 
			
		||||
 | 
			
		||||
all: libpcm.la
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										43
									
								
								src/pcm/atomic.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								src/pcm/atomic.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,43 @@
 | 
			
		|||
/*
 | 
			
		||||
 *  Atomic read/write
 | 
			
		||||
 *  Copyright (c) 2001 by Abramo Bagnara <abramo@alsa-project.org>
 | 
			
		||||
 *
 | 
			
		||||
 *   This library is free software; you can redistribute it and/or modify
 | 
			
		||||
 *   it under the terms of the GNU Library General Public License as
 | 
			
		||||
 *   published by the Free Software Foundation; either version 2 of
 | 
			
		||||
 *   the License, or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 *   This program is distributed in the hope that it will be useful,
 | 
			
		||||
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 *   GNU Library General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 *   You should have received a copy of the GNU Library General Public
 | 
			
		||||
 *   License along with this library; if not, write to the Free Software
 | 
			
		||||
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
  
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <time.h>
 | 
			
		||||
#include <sched.h>
 | 
			
		||||
#include "atomic.h"
 | 
			
		||||
 | 
			
		||||
void snd_atomic_read_wait(snd_atomic_read_t *t)
 | 
			
		||||
{
 | 
			
		||||
	volatile const snd_atomic_write_t *w = t->write;
 | 
			
		||||
	unsigned int loops = 0;
 | 
			
		||||
	struct timespec ts;
 | 
			
		||||
	while (w->begin != w->end) {
 | 
			
		||||
		if (loops < MAX_SPIN_COUNT) {
 | 
			
		||||
			sched_yield();
 | 
			
		||||
			loops++;
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
		loops = 0;
 | 
			
		||||
		ts.tv_sec = 0;
 | 
			
		||||
		ts.tv_nsec = SPIN_SLEEP_DURATION;
 | 
			
		||||
		nanosleep(&ts, NULL);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										85
									
								
								src/pcm/atomic.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								src/pcm/atomic.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,85 @@
 | 
			
		|||
/*
 | 
			
		||||
 *  Atomic read/write
 | 
			
		||||
 *  Copyright (c) 2001 by Abramo Bagnara <abramo@alsa-project.org>
 | 
			
		||||
 *
 | 
			
		||||
 *   This library is free software; you can redistribute it and/or modify
 | 
			
		||||
 *   it under the terms of the GNU Library General Public License as
 | 
			
		||||
 *   published by the Free Software Foundation; either version 2 of
 | 
			
		||||
 *   the License, or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 *   This program is distributed in the hope that it will be useful,
 | 
			
		||||
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 *   GNU Library General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 *   You should have received a copy of the GNU Library General Public
 | 
			
		||||
 *   License along with this library; if not, write to the Free Software
 | 
			
		||||
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <asm/system.h>
 | 
			
		||||
 | 
			
		||||
/* Max number of times we must spin on a spinlock calling sched_yield().
 | 
			
		||||
   After MAX_SPIN_COUNT iterations, we put the calling thread to sleep. */
 | 
			
		||||
 | 
			
		||||
#ifndef MAX_SPIN_COUNT
 | 
			
		||||
#define MAX_SPIN_COUNT 50
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* Duration of sleep (in nanoseconds) when we can't acquire a spinlock
 | 
			
		||||
   after MAX_SPIN_COUNT iterations of sched_yield().
 | 
			
		||||
   This MUST BE > 2ms.
 | 
			
		||||
   (Otherwise the kernel does busy-waiting for realtime threads,
 | 
			
		||||
    giving other threads no chance to run.) */
 | 
			
		||||
 | 
			
		||||
#ifndef SPIN_SLEEP_DURATION
 | 
			
		||||
#define SPIN_SLEEP_DURATION 2000001
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
	unsigned int begin, end;
 | 
			
		||||
} snd_atomic_write_t;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
	volatile const snd_atomic_write_t *write;
 | 
			
		||||
	unsigned int end;
 | 
			
		||||
} snd_atomic_read_t;
 | 
			
		||||
 | 
			
		||||
void snd_atomic_read_wait(snd_atomic_read_t *t);
 | 
			
		||||
 | 
			
		||||
static inline void snd_atomic_write_init(snd_atomic_write_t *w)
 | 
			
		||||
{
 | 
			
		||||
	w->begin = 0;
 | 
			
		||||
	w->end = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void snd_atomic_write_begin(snd_atomic_write_t *w)
 | 
			
		||||
{
 | 
			
		||||
	w->begin++;
 | 
			
		||||
	wmb();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void snd_atomic_write_end(snd_atomic_write_t *w)
 | 
			
		||||
{
 | 
			
		||||
	wmb();
 | 
			
		||||
	w->end++;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void snd_atomic_read_init(snd_atomic_read_t *r, snd_atomic_write_t *w)
 | 
			
		||||
{
 | 
			
		||||
	r->write = w;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void snd_atomic_read_begin(snd_atomic_read_t *r)
 | 
			
		||||
{
 | 
			
		||||
	r->end = r->write->end;
 | 
			
		||||
	rmb();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int snd_atomic_read_ok(snd_atomic_read_t *r)
 | 
			
		||||
{
 | 
			
		||||
	rmb();
 | 
			
		||||
	return r->end == r->write->begin;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -214,7 +214,7 @@ static int snd_pcm_hw_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
 | 
			
		|||
	snd_pcm_hw_t *hw = pcm->private_data;
 | 
			
		||||
	int fd = hw->fd;
 | 
			
		||||
	if (ioctl(fd, SNDRV_PCM_IOCTL_DELAY, delayp) < 0) {
 | 
			
		||||
		SYSERR("SNDRV_PCM_IOCTL_DELAY failed");
 | 
			
		||||
		// SYSERR("SNDRV_PCM_IOCTL_DELAY failed");
 | 
			
		||||
		return -errno;
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,6 +24,7 @@
 | 
			
		|||
#include <stdlib.h>
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
#include <sys/uio.h>
 | 
			
		||||
#include <asm/system.h>
 | 
			
		||||
 | 
			
		||||
#define _snd_pcm_access_mask _snd_mask
 | 
			
		||||
#define _snd_pcm_format_mask _snd_mask
 | 
			
		||||
| 
						 | 
				
			
			@ -486,3 +487,4 @@ int snd_pcm_hw_strategy_simple_choices(snd_pcm_hw_strategy_t *strategy, int orde
 | 
			
		|||
#define SND_PCM_ACCBIT_MMAP ((1 << (unsigned long) SND_PCM_ACCESS_MMAP_INTERLEAVED) | \
 | 
			
		||||
			     (1 << (unsigned long) SND_PCM_ACCESS_MMAP_NONINTERLEAVED) | \
 | 
			
		||||
			     (1 << (unsigned long) SND_PCM_ACCESS_MMAP_COMPLEX))
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -70,18 +70,6 @@ int snd_pcm_plugin_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info)
 | 
			
		|||
	return snd_pcm_channel_info_shm(pcm, info, plugin->shmid);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int snd_pcm_plugin_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
 | 
			
		||||
{
 | 
			
		||||
	snd_pcm_plugin_t *plugin = pcm->private_data;
 | 
			
		||||
	int err = snd_pcm_status(plugin->slave, status);
 | 
			
		||||
	if (err < 0)
 | 
			
		||||
		return err;
 | 
			
		||||
	status->avail = snd_pcm_mmap_avail(pcm);
 | 
			
		||||
	if (plugin->client_frames)
 | 
			
		||||
		status->avail_max = plugin->client_frames(pcm, status->avail_max);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
snd_pcm_state_t snd_pcm_plugin_state(snd_pcm_t *pcm)
 | 
			
		||||
{
 | 
			
		||||
	snd_pcm_plugin_t *plugin = pcm->private_data;
 | 
			
		||||
| 
						 | 
				
			
			@ -104,11 +92,16 @@ int snd_pcm_plugin_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
 | 
			
		|||
int snd_pcm_plugin_prepare(snd_pcm_t *pcm)
 | 
			
		||||
{
 | 
			
		||||
	snd_pcm_plugin_t *plugin = pcm->private_data;
 | 
			
		||||
	int err = snd_pcm_prepare(plugin->slave);
 | 
			
		||||
	if (err < 0)
 | 
			
		||||
	int err;
 | 
			
		||||
	snd_atomic_write_begin(&plugin->watom);
 | 
			
		||||
	err = snd_pcm_prepare(plugin->slave);
 | 
			
		||||
	if (err < 0) {
 | 
			
		||||
		snd_atomic_write_end(&plugin->watom);
 | 
			
		||||
		return err;
 | 
			
		||||
	}
 | 
			
		||||
	plugin->hw_ptr = 0;
 | 
			
		||||
	plugin->appl_ptr = 0;
 | 
			
		||||
	snd_atomic_write_end(&plugin->watom);
 | 
			
		||||
	if (plugin->init) {
 | 
			
		||||
		err = plugin->init(pcm);
 | 
			
		||||
		if (err < 0)
 | 
			
		||||
| 
						 | 
				
			
			@ -120,11 +113,16 @@ int snd_pcm_plugin_prepare(snd_pcm_t *pcm)
 | 
			
		|||
int snd_pcm_plugin_reset(snd_pcm_t *pcm)
 | 
			
		||||
{
 | 
			
		||||
	snd_pcm_plugin_t *plugin = pcm->private_data;
 | 
			
		||||
	int err = snd_pcm_reset(plugin->slave);
 | 
			
		||||
	if (err < 0)
 | 
			
		||||
	int err;
 | 
			
		||||
	snd_atomic_write_begin(&plugin->watom);
 | 
			
		||||
	err = snd_pcm_reset(plugin->slave);
 | 
			
		||||
	if (err < 0) {
 | 
			
		||||
		snd_atomic_write_end(&plugin->watom);
 | 
			
		||||
		return err;
 | 
			
		||||
	}
 | 
			
		||||
	plugin->hw_ptr = 0;
 | 
			
		||||
	plugin->appl_ptr = 0;
 | 
			
		||||
	snd_atomic_write_end(&plugin->watom);
 | 
			
		||||
	if (plugin->init) {
 | 
			
		||||
		err = plugin->init(pcm);
 | 
			
		||||
		if (err < 0)
 | 
			
		||||
| 
						 | 
				
			
			@ -172,19 +170,24 @@ snd_pcm_sframes_t snd_pcm_plugin_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames
 | 
			
		|||
		/* FIXME: rate plugin */
 | 
			
		||||
		if (plugin->slave_frames)
 | 
			
		||||
			frames = plugin->slave_frames(pcm, frames);
 | 
			
		||||
		snd_atomic_write_begin(&plugin->watom);
 | 
			
		||||
		err = snd_pcm_rewind(plugin->slave, frames);
 | 
			
		||||
		if (err < 0) {
 | 
			
		||||
			if (n <= 0)
 | 
			
		||||
			if (n <= 0) {
 | 
			
		||||
				snd_atomic_write_end(&plugin->watom);
 | 
			
		||||
				return err;
 | 
			
		||||
			}
 | 
			
		||||
			goto _end;
 | 
			
		||||
		}
 | 
			
		||||
		if (plugin->client_frames)
 | 
			
		||||
			err = plugin->client_frames(pcm, err);
 | 
			
		||||
		snd_pcm_mmap_hw_backward(pcm, err);
 | 
			
		||||
		n += err;
 | 
			
		||||
	}
 | 
			
		||||
	} else
 | 
			
		||||
		snd_atomic_write_begin(&plugin->watom);
 | 
			
		||||
 _end:
 | 
			
		||||
	snd_pcm_mmap_appl_backward(pcm, n);
 | 
			
		||||
	snd_atomic_write_end(&plugin->watom);
 | 
			
		||||
	return n;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -207,9 +210,11 @@ snd_pcm_uframes_t snd_pcm_plugin_write_areas(snd_pcm_t *pcm,
 | 
			
		|||
		frames = plugin->write(pcm, areas, offset, frames,
 | 
			
		||||
				       slave_areas, slave_offset, &slave_frames);
 | 
			
		||||
		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);
 | 
			
		||||
		snd_pcm_mmap_forward(slave, slave_frames);
 | 
			
		||||
		snd_atomic_write_end(&plugin->watom);
 | 
			
		||||
		offset += frames;
 | 
			
		||||
		size -= frames;
 | 
			
		||||
		if (slave_frames == slave_cont)
 | 
			
		||||
| 
						 | 
				
			
			@ -239,9 +244,11 @@ snd_pcm_uframes_t snd_pcm_plugin_read_areas(snd_pcm_t *pcm,
 | 
			
		|||
		frames = plugin->read(pcm, areas, offset, frames,
 | 
			
		||||
				      slave_areas, slave_offset, &slave_frames);
 | 
			
		||||
		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);
 | 
			
		||||
		snd_pcm_mmap_forward(slave, slave_frames);
 | 
			
		||||
		snd_atomic_write_end(&plugin->watom);
 | 
			
		||||
		offset += frames;
 | 
			
		||||
		size -= frames;
 | 
			
		||||
		if (slave_frames == slave_cont)
 | 
			
		||||
| 
						 | 
				
			
			@ -293,7 +300,9 @@ snd_pcm_sframes_t snd_pcm_plugin_mmap_forward(snd_pcm_t *pcm, snd_pcm_uframes_t
 | 
			
		|||
	snd_pcm_uframes_t xfer, offset;
 | 
			
		||||
	snd_pcm_uframes_t slave_offset, slave_size;
 | 
			
		||||
	if (pcm->stream == SND_PCM_STREAM_CAPTURE) {
 | 
			
		||||
		snd_atomic_write_begin(&plugin->watom);
 | 
			
		||||
		snd_pcm_mmap_appl_forward(pcm, size);
 | 
			
		||||
		snd_atomic_write_end(&plugin->watom);
 | 
			
		||||
		return size;
 | 
			
		||||
	}
 | 
			
		||||
	slave_size = snd_pcm_avail_update(slave);
 | 
			
		||||
| 
						 | 
				
			
			@ -315,9 +324,11 @@ snd_pcm_sframes_t snd_pcm_plugin_mmap_forward(snd_pcm_t *pcm, snd_pcm_uframes_t
 | 
			
		|||
			slave_frames = slave_cont;
 | 
			
		||||
		frames = plugin->write(pcm, areas, 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_forward(slave, slave_frames);
 | 
			
		||||
		snd_atomic_write_end(&plugin->watom);
 | 
			
		||||
		xfer += frames;
 | 
			
		||||
		if (frames == cont)
 | 
			
		||||
			offset = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -365,8 +376,10 @@ snd_pcm_sframes_t snd_pcm_plugin_avail_update(snd_pcm_t *pcm)
 | 
			
		|||
			slave_frames = slave_cont;
 | 
			
		||||
		frames = plugin->read(pcm, areas, offset, frames,
 | 
			
		||||
				      slave_areas, slave_offset, &slave_frames);
 | 
			
		||||
		snd_atomic_write_begin(&plugin->watom);
 | 
			
		||||
		snd_pcm_mmap_hw_forward(pcm, frames);
 | 
			
		||||
		snd_pcm_mmap_forward(slave, slave_frames);
 | 
			
		||||
		snd_atomic_write_end(&plugin->watom);
 | 
			
		||||
		xfer += frames;
 | 
			
		||||
		if (frames == cont)
 | 
			
		||||
			offset = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -411,6 +424,36 @@ int snd_pcm_plugin_poll_descriptor(snd_pcm_t *pcm)
 | 
			
		|||
	return _snd_pcm_poll_descriptor(plugin->slave);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int snd_pcm_plugin_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
 | 
			
		||||
{
 | 
			
		||||
	snd_pcm_plugin_t *plugin = pcm->private_data;
 | 
			
		||||
	snd_pcm_sframes_t err;
 | 
			
		||||
	snd_atomic_read_t ratom;
 | 
			
		||||
	snd_atomic_read_init(&ratom, &plugin->watom);
 | 
			
		||||
 _again:
 | 
			
		||||
	snd_atomic_read_begin(&ratom);
 | 
			
		||||
	err = snd_pcm_status(plugin->slave, status);
 | 
			
		||||
	if (err < 0) {
 | 
			
		||||
		snd_atomic_read_ok(&ratom);
 | 
			
		||||
		return err;
 | 
			
		||||
	}
 | 
			
		||||
	status->appl_ptr = plugin->appl_ptr;
 | 
			
		||||
	status->hw_ptr = plugin->hw_ptr;
 | 
			
		||||
	err = snd_pcm_plugin_avail_update(pcm);
 | 
			
		||||
	if (err < 0)
 | 
			
		||||
		status->avail = pcm->buffer_size;
 | 
			
		||||
	else
 | 
			
		||||
		status->avail = err;
 | 
			
		||||
	snd_pcm_plugin_delay(pcm, &status->delay);
 | 
			
		||||
	if (!snd_atomic_read_ok(&ratom)) {
 | 
			
		||||
		snd_atomic_read_wait(&ratom);
 | 
			
		||||
		goto _again;
 | 
			
		||||
	}
 | 
			
		||||
	if (plugin->client_frames)
 | 
			
		||||
		status->avail_max = plugin->client_frames(pcm, status->avail_max);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int snd_pcm_plugin_hw_refine_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
 | 
			
		||||
{
 | 
			
		||||
	snd_pcm_plugin_t *plugin = pcm->private_data;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,6 +19,8 @@
 | 
			
		|||
 *
 | 
			
		||||
 */
 | 
			
		||||
  
 | 
			
		||||
#include "atomic.h"
 | 
			
		||||
 | 
			
		||||
typedef snd_pcm_uframes_t (*snd_pcm_slave_xfer_areas_func_t)
 | 
			
		||||
     (snd_pcm_t *pcm, 
 | 
			
		||||
      const snd_pcm_channel_area_t *areas,
 | 
			
		||||
| 
						 | 
				
			
			@ -38,6 +40,7 @@ typedef struct {
 | 
			
		|||
	int (*init)(snd_pcm_t *pcm);
 | 
			
		||||
	int shmid;
 | 
			
		||||
	snd_pcm_uframes_t appl_ptr, hw_ptr;
 | 
			
		||||
	snd_atomic_write_t watom;
 | 
			
		||||
} snd_pcm_plugin_t;	
 | 
			
		||||
 | 
			
		||||
int snd_pcm_plugin_close(snd_pcm_t *pcm);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue