pcm handle split

This commit is contained in:
Abramo Bagnara 2000-06-21 14:59:20 +00:00
parent 0535d28240
commit 60fa939c21
5 changed files with 694 additions and 974 deletions

View file

@ -5,12 +5,7 @@
* * * *
****************************************************************************/ ****************************************************************************/
#define SND_PCM_OPEN_PLAYBACK 0x0001 #define SND_PCM_NONBLOCK 0x0001
#define SND_PCM_OPEN_CAPTURE 0x0002
#define SND_PCM_OPEN_DUPLEX 0x0003
#define SND_PCM_NONBLOCK_PLAYBACK 0x1000
#define SND_PCM_NONBLOCK_CAPTURE 0x2000
#define SND_PCM_NONBLOCK 0x3000
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -18,137 +13,152 @@ extern "C" {
typedef unsigned int bitset_t; typedef unsigned int bitset_t;
static inline size_t bitset_size(int nbits) static inline size_t bitset_size(size_t nbits)
{ {
return (nbits + sizeof(bitset_t) * 8 - 1) / (sizeof(bitset_t) * 8); return (nbits + sizeof(bitset_t) * 8 - 1) / (sizeof(bitset_t) * 8);
} }
static inline bitset_t *bitset_alloc(int nbits) static inline bitset_t *bitset_alloc(size_t nbits)
{ {
return (bitset_t*) calloc(bitset_size(nbits), sizeof(bitset_t)); return (bitset_t*) calloc(bitset_size(nbits), sizeof(bitset_t));
} }
static inline void bitset_set(bitset_t *bitmap, unsigned int pos) static inline void bitset_set(bitset_t *bitmap, unsigned int pos)
{ {
int bits = sizeof(*bitmap) * 8; size_t bits = sizeof(*bitmap) * 8;
bitmap[pos / bits] |= 1 << (pos % bits); bitmap[pos / bits] |= 1U << (pos % bits);
} }
static inline void bitset_reset(bitset_t *bitmap, unsigned int pos) static inline void bitset_reset(bitset_t *bitmap, unsigned int pos)
{ {
int bits = sizeof(*bitmap) * 8; size_t bits = sizeof(*bitmap) * 8;
bitmap[pos / bits] &= ~(1 << (pos % bits)); bitmap[pos / bits] &= ~(1U << (pos % bits));
} }
static inline int bitset_get(bitset_t *bitmap, unsigned int pos) static inline int bitset_get(bitset_t *bitmap, unsigned int pos)
{ {
int bits = sizeof(*bitmap) * 8; size_t bits = sizeof(*bitmap) * 8;
return !!(bitmap[pos / bits] & (1 << (pos % bits))); return !!(bitmap[pos / bits] & (1U << (pos % bits)));
} }
static inline void bitset_copy(bitset_t *dst, bitset_t *src, unsigned int nbits) static inline void bitset_copy(bitset_t *dst, bitset_t *src, size_t nbits)
{ {
memcpy(dst, src, bitset_size(nbits) * sizeof(bitset_t)); memcpy(dst, src, bitset_size(nbits) * sizeof(bitset_t));
} }
static inline void bitset_and(bitset_t *dst, bitset_t *bs, unsigned int nbits) static inline void bitset_and(bitset_t *dst, bitset_t *bs, size_t nbits)
{ {
bitset_t *end = dst + bitset_size(nbits); bitset_t *end = dst + bitset_size(nbits);
while (dst < end) while (dst < end)
*dst++ &= *bs++; *dst++ &= *bs++;
} }
static inline void bitset_or(bitset_t *dst, bitset_t *bs, unsigned int nbits) static inline void bitset_or(bitset_t *dst, bitset_t *bs, size_t nbits)
{ {
bitset_t *end = dst + bitset_size(nbits); bitset_t *end = dst + bitset_size(nbits);
while (dst < end) while (dst < end)
*dst++ |= *bs++; *dst++ |= *bs++;
} }
static inline void bitset_zero(bitset_t *dst, unsigned int nbits) static inline void bitset_zero(bitset_t *dst, size_t nbits)
{ {
bitset_t *end = dst + bitset_size(nbits); bitset_t *end = dst + bitset_size(nbits);
while (dst < end) while (dst < end)
*dst++ = 0; *dst++ = 0;
} }
static inline void bitset_one(bitset_t *dst, unsigned int nbits) static inline void bitset_one(bitset_t *dst, size_t nbits)
{ {
bitset_t *end = dst + bitset_size(nbits); bitset_t *end = dst + bitset_size(nbits);
while (dst < end) while (dst < end)
*dst++ = ~(bitset_t)0; *dst++ = ~(bitset_t)0;
} }
static inline size_t hweight32(bitset_t v)
{
v = (v & 0x55555555) + ((v >> 1) & 0x55555555);
v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
v = (v & 0x0F0F0F0F) + ((v >> 4) & 0x0F0F0F0F);
v = (v & 0x00FF00FF) + ((v >> 8) & 0x00FF00FF);
return (v & 0x0000FFFF) + ((v >> 16) & 0x0000FFFF);
}
/* Count bits set */
static inline size_t bitset_count(bitset_t *bitset, size_t nbits)
{
bitset_t *end = bitset + bitset_size(nbits) - 1;
size_t bits = sizeof(*bitset) * 8;
size_t count = 0;
while (bitset < end)
count += hweight32(*bitset++);
count += hweight32(*bitset & ((1U << (nbits % bits)) - 1));
return count;
}
typedef struct snd_pcm snd_pcm_t; typedef struct snd_pcm snd_pcm_t;
typedef struct snd_pcm_loopback snd_pcm_loopback_t; typedef struct snd_pcm_loopback snd_pcm_loopback_t;
typedef enum { SND_PCM_TYPE_HW, SND_PCM_TYPE_PLUG, SND_PCM_TYPE_MULTI } snd_pcm_type_t; typedef enum { SND_PCM_TYPE_HW, SND_PCM_TYPE_PLUG, SND_PCM_TYPE_MULTI } snd_pcm_type_t;
int snd_pcm_open(snd_pcm_t **handle, int card, int device, int mode); int snd_pcm_hw_open_subdevice(snd_pcm_t **handle, int card, int device, int subdevice, int stream, int mode);
int snd_pcm_open_subdevice(snd_pcm_t **handle, int card, int device, int subdevice, int mode); int snd_pcm_hw_open(snd_pcm_t **handle, int card, int device, int stream, int mode);
snd_pcm_type_t snd_pcm_type(snd_pcm_t *handle); snd_pcm_type_t snd_pcm_type(snd_pcm_t *handle);
int snd_pcm_close(snd_pcm_t *handle); int snd_pcm_close(snd_pcm_t *handle);
int snd_pcm_stream_close(snd_pcm_t *handle, int stream); int snd_pcm_file_descriptor(snd_pcm_t *handle);
int snd_pcm_file_descriptor(snd_pcm_t *handle, int stream); int snd_pcm_nonblock(snd_pcm_t *handle, int nonblock);
int snd_pcm_stream_nonblock(snd_pcm_t *handle, int stream, int nonblock);
int snd_pcm_info(snd_pcm_t *handle, snd_pcm_info_t *info); int snd_pcm_info(snd_pcm_t *handle, snd_pcm_info_t *info);
int snd_pcm_stream_info(snd_pcm_t *handle, snd_pcm_stream_info_t *info); int snd_pcm_params(snd_pcm_t *handle, snd_pcm_params_t *params);
int snd_pcm_stream_params(snd_pcm_t *handle, snd_pcm_stream_params_t *params); int snd_pcm_setup(snd_pcm_t *handle, snd_pcm_setup_t *setup);
int snd_pcm_stream_setup(snd_pcm_t *handle, snd_pcm_stream_setup_t *setup); int snd_pcm_channel_setup(snd_pcm_t *handle, snd_pcm_channel_setup_t *setup);
int snd_pcm_channel_setup(snd_pcm_t *handle, int stream, snd_pcm_channel_setup_t *setup); int snd_pcm_status(snd_pcm_t *handle, snd_pcm_status_t *status);
int snd_pcm_stream_status(snd_pcm_t *handle, snd_pcm_stream_status_t *status); int snd_pcm_prepare(snd_pcm_t *handle);
int snd_pcm_playback_prepare(snd_pcm_t *handle); int snd_pcm_go(snd_pcm_t *handle);
int snd_pcm_capture_prepare(snd_pcm_t *handle);
int snd_pcm_stream_prepare(snd_pcm_t *handle, int stream);
int snd_pcm_playback_go(snd_pcm_t *handle);
int snd_pcm_capture_go(snd_pcm_t *handle);
int snd_pcm_stream_go(snd_pcm_t *handle, int stream);
int snd_pcm_sync_go(snd_pcm_t *handle, snd_pcm_sync_t *sync); int snd_pcm_sync_go(snd_pcm_t *handle, snd_pcm_sync_t *sync);
int snd_pcm_playback_drain(snd_pcm_t *handle); int snd_pcm_drain(snd_pcm_t *handle);
int snd_pcm_stream_drain(snd_pcm_t *handle, int stream); int snd_pcm_flush(snd_pcm_t *handle);
int snd_pcm_playback_flush(snd_pcm_t *handle); int snd_pcm_pause(snd_pcm_t *handle, int enable);
int snd_pcm_capture_flush(snd_pcm_t *handle); int snd_pcm_state(snd_pcm_t *handle);
int snd_pcm_stream_flush(snd_pcm_t *handle, int stream); ssize_t snd_pcm_frame_io(snd_pcm_t *handle, int update);
int snd_pcm_playback_pause(snd_pcm_t *handle, int enable); ssize_t snd_pcm_frame_data(snd_pcm_t *handle, off_t offset);
int snd_pcm_stream_pause(snd_pcm_t *handle, int stream, int enable);
int snd_pcm_stream_state(snd_pcm_t *handle, int stream);
int snd_pcm_mmap_stream_state(snd_pcm_t *handle, int stream);
ssize_t snd_pcm_stream_frame_io(snd_pcm_t *handle, int stream, int update);
ssize_t snd_pcm_mmap_stream_frame_io(snd_pcm_t *handle, int stream);
ssize_t snd_pcm_stream_frame_data(snd_pcm_t *handle, int stream, off_t offset);
ssize_t snd_pcm_mmap_stream_frame_data(snd_pcm_t *handle, int stream, off_t offset);
ssize_t snd_pcm_write(snd_pcm_t *handle, const void *buffer, size_t size); ssize_t snd_pcm_write(snd_pcm_t *handle, const void *buffer, size_t size);
ssize_t snd_pcm_read(snd_pcm_t *handle, void *buffer, size_t size); ssize_t snd_pcm_read(snd_pcm_t *handle, void *buffer, size_t size);
ssize_t snd_pcm_writev(snd_pcm_t *pcm, const struct iovec *vector, unsigned long count); ssize_t snd_pcm_writev(snd_pcm_t *handle, const struct iovec *vector, unsigned long count);
ssize_t snd_pcm_readv(snd_pcm_t *pcm, const struct iovec *vector, unsigned long count); ssize_t snd_pcm_readv(snd_pcm_t *handle, const struct iovec *vector, unsigned long count);
int snd_pcm_dump_setup(snd_pcm_t *handle, FILE *fp);
int snd_pcm_channels_mask(snd_pcm_t *handle, bitset_t *client_vmask);
/* mmap */
int snd_pcm_mmap(snd_pcm_t *handle, snd_pcm_mmap_status_t **status, snd_pcm_mmap_control_t **control, void **buffer);
int snd_pcm_munmap(snd_pcm_t *handle);
int snd_pcm_mmap_state(snd_pcm_t *handle);
ssize_t snd_pcm_mmap_frame_io(snd_pcm_t *handle);
ssize_t snd_pcm_mmap_frame_data(snd_pcm_t *handle, off_t offset);
int snd_pcm_mmap_status(snd_pcm_t *handle, snd_pcm_mmap_status_t **status);
int snd_pcm_mmap_control(snd_pcm_t *handle, snd_pcm_mmap_control_t **control);
int snd_pcm_mmap_data(snd_pcm_t *handle, void **buffer);
int snd_pcm_munmap_status(snd_pcm_t *handle);
int snd_pcm_munmap_control(snd_pcm_t *handle);
int snd_pcm_munmap_data(snd_pcm_t *handle);
int snd_pcm_mmap_ready(snd_pcm_t *handle);
ssize_t snd_pcm_mmap_write(snd_pcm_t *handle, const void *buffer, size_t size);
ssize_t snd_pcm_mmap_read(snd_pcm_t *handle, void *buffer, size_t size);
ssize_t snd_pcm_mmap_writev(snd_pcm_t *handle, const struct iovec *vector, unsigned long count);
ssize_t snd_pcm_mmap_readv(snd_pcm_t *handle, const struct iovec *vector, unsigned long count);
int snd_pcm_mmap_frames_avail(snd_pcm_t *handle, ssize_t *frames);
ssize_t snd_pcm_mmap_frames_xfer(snd_pcm_t *handle, size_t frames);
ssize_t snd_pcm_mmap_frames_offset(snd_pcm_t *handle);
ssize_t snd_pcm_mmap_write_areas(snd_pcm_t *handle, snd_pcm_channel_area_t *channels, size_t frames);
ssize_t snd_pcm_mmap_write_frames(snd_pcm_t *handle, const void *buffer, size_t frames);
ssize_t snd_pcm_mmap_read_areas(snd_pcm_t *handle, snd_pcm_channel_area_t *channels, size_t frames);
ssize_t snd_pcm_mmap_read_frames(snd_pcm_t *handle, const void *buffer, size_t frames);
int snd_pcm_mmap_get_areas(snd_pcm_t *handle, snd_pcm_channel_area_t *areas);
const char *snd_pcm_get_format_name(int format); const char *snd_pcm_get_format_name(int format);
const char *snd_pcm_get_format_description(int format); const char *snd_pcm_get_format_description(int format);
int snd_pcm_get_format_value(const char* name); int snd_pcm_get_format_value(const char* name);
int snd_pcm_dump_setup(snd_pcm_t *pcm, int stream, FILE *fp);
int snd_pcm_mmap(snd_pcm_t *handle, int stream, snd_pcm_mmap_status_t **status, snd_pcm_mmap_control_t **control, void **buffer);
int snd_pcm_munmap(snd_pcm_t *handle, int stream);
int snd_pcm_mmap_status(snd_pcm_t *handle, int stream, snd_pcm_mmap_status_t **status);
int snd_pcm_mmap_control(snd_pcm_t *handle, int stream, snd_pcm_mmap_control_t **control);
int snd_pcm_mmap_data(snd_pcm_t *handle, int stream, void **buffer);
int snd_pcm_munmap_status(snd_pcm_t *handle, int stream);
int snd_pcm_munmap_control(snd_pcm_t *handle, int stream);
int snd_pcm_munmap_data(snd_pcm_t *handle, int stream);
int snd_pcm_channels_mask(snd_pcm_t *pcm, int stream, bitset_t *client_vmask);
int snd_pcm_mmap_ready(snd_pcm_t *pcm, int stream);
ssize_t snd_pcm_mmap_write(snd_pcm_t *handle, const void *buffer, size_t size);
ssize_t snd_pcm_mmap_read(snd_pcm_t *handle, void *buffer, size_t size);
ssize_t snd_pcm_mmap_writev(snd_pcm_t *pcm, const struct iovec *vector, unsigned long count);
ssize_t snd_pcm_mmap_readv(snd_pcm_t *pcm, const struct iovec *vector, unsigned long count);
int snd_pcm_mmap_frames_avail(snd_pcm_t *pcm, int stream, ssize_t *frames);
ssize_t snd_pcm_mmap_frames_xfer(snd_pcm_t *pcm, int stream, size_t frames);
ssize_t snd_pcm_mmap_frames_offset(snd_pcm_t *pcm, int stream);
ssize_t snd_pcm_mmap_write_areas(snd_pcm_t *pcm, snd_pcm_channel_area_t *channels, size_t frames);
ssize_t snd_pcm_mmap_write_frames(snd_pcm_t *pcm, const void *buffer, size_t frames);
ssize_t snd_pcm_mmap_read_areas(snd_pcm_t *pcm, snd_pcm_channel_area_t *channels, size_t frames);
ssize_t snd_pcm_mmap_read_frames(snd_pcm_t *pcm, const void *buffer, size_t frames);
int snd_pcm_mmap_get_areas(snd_pcm_t *pcm, int stream, snd_pcm_channel_area_t *areas);
int snd_pcm_area_silence(const snd_pcm_channel_area_t *dst_channel, size_t dst_offset, int snd_pcm_area_silence(const snd_pcm_channel_area_t *dst_channel, size_t dst_offset,
size_t samples, int format); size_t samples, int format);
@ -161,10 +171,10 @@ int snd_pcm_areas_copy(const snd_pcm_channel_area_t *src_channels, size_t src_of
const snd_pcm_channel_area_t *dst_channels, size_t dst_offset, const snd_pcm_channel_area_t *dst_channels, size_t dst_offset,
size_t vcount, size_t frames, int format); size_t vcount, size_t frames, int format);
ssize_t snd_pcm_bytes_to_frames(snd_pcm_t *pcm, int stream, ssize_t bytes); ssize_t snd_pcm_bytes_to_frames(snd_pcm_t *pcm, ssize_t bytes);
ssize_t snd_pcm_frames_to_bytes(snd_pcm_t *pcm, int stream, ssize_t frames); ssize_t snd_pcm_frames_to_bytes(snd_pcm_t *pcm, ssize_t frames);
ssize_t snd_pcm_bytes_to_samples(snd_pcm_t *pcm, int stream, ssize_t bytes); ssize_t snd_pcm_bytes_to_samples(snd_pcm_t *pcm, ssize_t bytes);
ssize_t snd_pcm_samples_to_bytes(snd_pcm_t *pcm, int stream, ssize_t samples); ssize_t snd_pcm_samples_to_bytes(snd_pcm_t *pcm, ssize_t samples);
/* misc */ /* misc */
@ -197,7 +207,7 @@ extern "C" {
#endif #endif
typedef struct snd_stru_pcm_plugin snd_pcm_plugin_t; typedef struct snd_stru_pcm_plugin snd_pcm_plugin_t;
#define snd_pcm_plugin_handle_t snd_pcm_t #define snd_pcm_plug_t struct snd_pcm_plug
typedef enum { typedef enum {
INIT = 0, INIT = 0,
@ -208,7 +218,6 @@ typedef enum {
} snd_pcm_plugin_action_t; } snd_pcm_plugin_action_t;
typedef struct snd_stru_pcm_plugin_channel { typedef struct snd_stru_pcm_plugin_channel {
void *aptr; /* pointer to the allocated area */
snd_pcm_channel_area_t area; snd_pcm_channel_area_t area;
unsigned int enabled:1; /* channel need to be processed */ unsigned int enabled:1; /* channel need to be processed */
unsigned int wanted:1; /* channel is wanted */ unsigned int wanted:1; /* channel is wanted */
@ -247,54 +256,47 @@ struct snd_stru_pcm_plugin {
unsigned long *value); unsigned long *value);
snd_pcm_plugin_t *prev; snd_pcm_plugin_t *prev;
snd_pcm_plugin_t *next; snd_pcm_plugin_t *next;
snd_pcm_plugin_handle_t *handle; snd_pcm_plug_t *plug;
void *private_data; void *private_data;
void (*private_free)(snd_pcm_plugin_t *plugin, void *private_data); void (*private_free)(snd_pcm_plugin_t *plugin, void *private_data);
snd_pcm_plugin_channel_t *src_channels; char *buf;
snd_pcm_plugin_channel_t *dst_channels; size_t buf_frames;
snd_pcm_plugin_channel_t *buf_channels;
bitset_t *src_vmask; bitset_t *src_vmask;
bitset_t *dst_vmask; bitset_t *dst_vmask;
char extra_data[0]; char extra_data[0];
}; };
int snd_pcm_plug_connect(snd_pcm_t **handle, snd_pcm_t *slave, int mode, int close_slave); int snd_pcm_plug_create(snd_pcm_t **handle, snd_pcm_t *slave, int close_slave);
int snd_pcm_plug_open_subdevice(snd_pcm_t **handle, int card, int device, int subdevice, int mode); int snd_pcm_plug_open_subdevice(snd_pcm_t **handle, int card, int device, int subdevice, int stream, int mode);
int snd_pcm_plug_open(snd_pcm_t **handle, int card, int device, int mode); int snd_pcm_plug_open(snd_pcm_t **handle, int card, int device, int stream, int mode);
int snd_pcm_plugin_free(snd_pcm_plugin_t *plugin); int snd_pcm_plugin_free(snd_pcm_plugin_t *plugin);
int snd_pcm_plug_clear(snd_pcm_t *handle, int stream);
int snd_pcm_plugin_insert(snd_pcm_plugin_t *plugin); int snd_pcm_plugin_insert(snd_pcm_plugin_t *plugin);
int snd_pcm_plugin_append(snd_pcm_plugin_t *plugin); int snd_pcm_plugin_append(snd_pcm_plugin_t *plugin);
#if 0 int snd_pcm_plug_alloc(snd_pcm_plug_t *plug, size_t frames);
int snd_pcm_plugin_remove_to(snd_pcm_plugin_t *plugin); int snd_pcm_plug_clear(snd_pcm_plug_t *plug);
int snd_pcm_plug_remove_first(snd_pcm_t *handle, int stream); snd_pcm_plugin_t *snd_pcm_plug_first(snd_pcm_plug_t *plug);
#endif snd_pcm_plugin_t *snd_pcm_plug_last(snd_pcm_plug_t *plug);
snd_pcm_plugin_t *snd_pcm_plug_first(snd_pcm_t *handle, int stream); int snd_pcm_plug_direct(snd_pcm_plug_t *plug);
snd_pcm_plugin_t *snd_pcm_plug_last(snd_pcm_t *handle, int stream); ssize_t snd_pcm_plug_client_size(snd_pcm_plug_t *plug, size_t drv_frames);
int snd_pcm_plug_direct(snd_pcm_t *pcm, int stream); ssize_t snd_pcm_plug_slave_size(snd_pcm_plug_t *plug, size_t clt_frames);
ssize_t snd_pcm_plug_client_size(snd_pcm_t *handle, int stream, size_t drv_frames);
ssize_t snd_pcm_plug_slave_size(snd_pcm_t *handle, int stream, size_t clt_frames);
/* /*
* Plug-In constructors * Plug-In constructors
*/ */
int snd_pcm_plugin_build(snd_pcm_plugin_handle_t *handle, int snd_pcm_plugin_build(snd_pcm_plug_t *plug,
int stream,
const char *name, const char *name,
snd_pcm_format_t *src_format, snd_pcm_format_t *src_format,
snd_pcm_format_t *dst_format, snd_pcm_format_t *dst_format,
size_t extra, size_t extra,
snd_pcm_plugin_t **ret); snd_pcm_plugin_t **ret);
/* basic I/O */ /* basic I/O */
int snd_pcm_plugin_build_io(snd_pcm_plugin_handle_t *handle, int snd_pcm_plugin_build_io(snd_pcm_plug_t *plug,
int stream,
snd_pcm_t *slave,
snd_pcm_format_t *format, snd_pcm_format_t *format,
snd_pcm_plugin_t **r_plugin); snd_pcm_plugin_t **r_plugin);
int snd_pcm_plugin_build_mmap(snd_pcm_plugin_handle_t *handle, int snd_pcm_plugin_build_mmap(snd_pcm_plug_t *plug,
int stream,
snd_pcm_t *slave,
snd_pcm_format_t *format, snd_pcm_format_t *format,
snd_pcm_plugin_t **r_plugin); snd_pcm_plugin_t **r_plugin);
@ -310,44 +312,36 @@ typedef int route_ttable_entry_t;
#endif #endif
/* conversion plugins */ /* conversion plugins */
int snd_pcm_plugin_build_interleave(snd_pcm_plugin_handle_t *handle, int snd_pcm_plugin_build_interleave(snd_pcm_plug_t *plug,
int stream,
snd_pcm_format_t *src_format, snd_pcm_format_t *src_format,
snd_pcm_format_t *dst_format, snd_pcm_format_t *dst_format,
snd_pcm_plugin_t **r_plugin); snd_pcm_plugin_t **r_plugin);
int snd_pcm_plugin_build_linear(snd_pcm_plugin_handle_t *handle, int snd_pcm_plugin_build_linear(snd_pcm_plug_t *plug,
int stream,
snd_pcm_format_t *src_format, snd_pcm_format_t *src_format,
snd_pcm_format_t *dst_format, snd_pcm_format_t *dst_format,
snd_pcm_plugin_t **r_plugin); snd_pcm_plugin_t **r_plugin);
int snd_pcm_plugin_build_mulaw(snd_pcm_plugin_handle_t *handle, int snd_pcm_plugin_build_mulaw(snd_pcm_plug_t *plug,
int stream,
snd_pcm_format_t *src_format, snd_pcm_format_t *src_format,
snd_pcm_format_t *dst_format, snd_pcm_format_t *dst_format,
snd_pcm_plugin_t **r_plugin); snd_pcm_plugin_t **r_plugin);
int snd_pcm_plugin_build_alaw(snd_pcm_plugin_handle_t *handle, int snd_pcm_plugin_build_alaw(snd_pcm_plug_t *plug,
int stream,
snd_pcm_format_t *src_format, snd_pcm_format_t *src_format,
snd_pcm_format_t *dst_format, snd_pcm_format_t *dst_format,
snd_pcm_plugin_t **r_plugin); snd_pcm_plugin_t **r_plugin);
int snd_pcm_plugin_build_adpcm(snd_pcm_plugin_handle_t *handle, int snd_pcm_plugin_build_adpcm(snd_pcm_plug_t *plug,
int stream,
snd_pcm_format_t *src_format, snd_pcm_format_t *src_format,
snd_pcm_format_t *dst_format, snd_pcm_format_t *dst_format,
snd_pcm_plugin_t **r_plugin); snd_pcm_plugin_t **r_plugin);
int snd_pcm_plugin_build_rate(snd_pcm_plugin_handle_t *handle, int snd_pcm_plugin_build_rate(snd_pcm_plug_t *plug,
int stream,
snd_pcm_format_t *src_format, snd_pcm_format_t *src_format,
snd_pcm_format_t *dst_format, snd_pcm_format_t *dst_format,
snd_pcm_plugin_t **r_plugin); snd_pcm_plugin_t **r_plugin);
int snd_pcm_plugin_build_route(snd_pcm_plugin_handle_t *handle, int snd_pcm_plugin_build_route(snd_pcm_plug_t *plug,
int stream,
snd_pcm_format_t *src_format, snd_pcm_format_t *src_format,
snd_pcm_format_t *dst_format, snd_pcm_format_t *dst_format,
route_ttable_entry_t *ttable, route_ttable_entry_t *ttable,
snd_pcm_plugin_t **r_plugin); snd_pcm_plugin_t **r_plugin);
int snd_pcm_plugin_build_copy(snd_pcm_plugin_handle_t *handle, int snd_pcm_plugin_build_copy(snd_pcm_plug_t *plug,
int stream,
snd_pcm_format_t *src_format, snd_pcm_format_t *src_format,
snd_pcm_format_t *dst_format, snd_pcm_format_t *dst_format,
snd_pcm_plugin_t **r_plugin); snd_pcm_plugin_t **r_plugin);

View file

@ -27,372 +27,219 @@
#include <sys/uio.h> #include <sys/uio.h>
#include "pcm_local.h" #include "pcm_local.h"
int snd_pcm_abstract_open(snd_pcm_t **handle, int mode,
snd_pcm_type_t type, size_t extra)
{
snd_pcm_t *pcm;
assert(handle);
*handle = NULL;
pcm = (snd_pcm_t *) calloc(1, sizeof(snd_pcm_t) + extra);
if (pcm == NULL)
return -ENOMEM;
if (mode & SND_PCM_OPEN_PLAYBACK) {
snd_pcm_stream_t *str = &pcm->stream[SND_PCM_STREAM_PLAYBACK];
str->open = 1;
str->mode = (mode & SND_PCM_NONBLOCK_PLAYBACK) ? SND_PCM_NONBLOCK : 0;
}
if (mode & SND_PCM_OPEN_CAPTURE) {
snd_pcm_stream_t *str = &pcm->stream[SND_PCM_STREAM_CAPTURE];
str->open = 1;
str->mode = (mode & SND_PCM_NONBLOCK_CAPTURE) ? SND_PCM_NONBLOCK : 0;
}
pcm->type = type;
pcm->mode = mode & SND_PCM_OPEN_DUPLEX;
*handle = pcm;
return 0;
}
snd_pcm_type_t snd_pcm_type(snd_pcm_t *handle) snd_pcm_type_t snd_pcm_type(snd_pcm_t *handle)
{ {
assert(handle);
return handle->type; return handle->type;
} }
int snd_pcm_stream_close(snd_pcm_t *pcm, int stream) snd_pcm_type_t snd_pcm(snd_pcm_t *handle)
{
assert(handle);
return handle->stream;
}
int snd_pcm_close(snd_pcm_t *handle)
{ {
int ret = 0; int ret = 0;
int err; int err;
snd_pcm_stream_t *str; assert(handle);
assert(pcm); if (handle->mmap_status) {
assert(stream >= 0 && stream <= 1); if ((err = snd_pcm_munmap_status(handle)) < 0)
str = &pcm->stream[stream];
assert(str->open);
if (str->mmap_status) {
if ((err = snd_pcm_munmap_status(pcm, stream)) < 0)
ret = err; ret = err;
} }
if (str->mmap_control) { if (handle->mmap_control) {
if ((err = snd_pcm_munmap_control(pcm, stream)) < 0) if ((err = snd_pcm_munmap_control(handle)) < 0)
ret = err; ret = err;
} }
if (str->mmap_data) { if (handle->mmap_data) {
if ((err = snd_pcm_munmap_data(pcm, stream)) < 0) if ((err = snd_pcm_munmap_data(handle)) < 0)
ret = err; ret = err;
} }
if ((err = pcm->ops->stream_close(pcm, stream)) < 0) if ((err = handle->ops->close(handle->op_arg)) < 0)
ret = err; ret = err;
str->open = 0; handle->valid_setup = 0;
str->valid_setup = 0; free(handle);
return ret; return ret;
} }
int snd_pcm_close(snd_pcm_t *pcm) int snd_pcm_nonblock(snd_pcm_t *handle, int nonblock)
{
int err, ret = 0;
int stream;
assert(pcm);
for (stream = 0; stream < 2; ++stream) {
if (pcm->stream[stream].open) {
if ((err = snd_pcm_stream_close(pcm, stream)) < 0)
ret = err;
}
}
free(pcm);
return ret;
}
int snd_pcm_stream_nonblock(snd_pcm_t *pcm, int stream, int nonblock)
{ {
int err; int err;
snd_pcm_stream_t *str; assert(handle);
assert(pcm); if ((err = handle->ops->nonblock(handle->op_arg, nonblock)) < 0)
assert(stream >= 0 && stream <= 1);
str = &pcm->stream[stream];
assert(pcm->stream[stream].open);
if ((err = pcm->ops->stream_nonblock(pcm, stream, nonblock)) < 0)
return err; return err;
if (nonblock) if (nonblock)
str->mode |= SND_PCM_NONBLOCK; handle->mode |= SND_PCM_NONBLOCK;
else else
str->mode &= ~SND_PCM_NONBLOCK; handle->mode &= ~SND_PCM_NONBLOCK;
return 0; return 0;
} }
int snd_pcm_info(snd_pcm_t *pcm, snd_pcm_info_t *info) int snd_pcm_info(snd_pcm_t *handle, snd_pcm_info_t *info)
{ {
int stream; assert(handle && info);
assert(pcm && info); /* Here we pass private and not op_arg.
for (stream = 0; stream < 2; ++stream) { FIXME: find a better solution */
if (pcm->stream[stream].open) return handle->ops->info(handle->private, info);
return pcm->ops->info(pcm, stream, info);
}
assert(0);
} }
int snd_pcm_stream_info(snd_pcm_t *pcm, snd_pcm_stream_info_t *info) int snd_pcm_setup(snd_pcm_t *handle, snd_pcm_setup_t *setup)
{
assert(pcm && info);
assert(info->stream >= 0 && info->stream <= 1);
assert(pcm->stream[info->stream].open);
return pcm->ops->stream_info(pcm, info);
}
int snd_pcm_stream_params(snd_pcm_t *pcm, snd_pcm_stream_params_t *params)
{ {
int err; int err;
snd_pcm_stream_setup_t setup; assert(handle && setup);
snd_pcm_stream_t *str; if (handle->valid_setup) {
assert(pcm && params); *setup = handle->setup;
assert(params->stream >= 0 && params->stream <= 1);
str = &pcm->stream[params->stream];
assert(str->open);
assert(!str->mmap_data);
if ((err = pcm->ops->stream_params(pcm, params)) < 0)
return err;
str->valid_setup = 0;
setup.stream = params->stream;
return snd_pcm_stream_setup(pcm, &setup);
}
int snd_pcm_stream_setup(snd_pcm_t *pcm, snd_pcm_stream_setup_t *setup)
{
int err;
snd_pcm_stream_t *str;
assert(pcm && setup);
assert(setup->stream >= 0 && setup->stream <= 1);
str = &pcm->stream[setup->stream];
assert(str->open);
if (str->valid_setup) {
*setup = str->setup;
return 0; return 0;
} }
str->setup.stream = setup->stream; /* Here we pass private and not op_arg.
if ((err = pcm->ops->stream_setup(pcm, &str->setup)) < 0) FIXME: find a better solution */
if ((err = handle->ops->setup(handle->private, &handle->setup)) < 0)
return err; return err;
*setup = str->setup; *setup = handle->setup;
str->bits_per_sample = snd_pcm_format_physical_width(setup->format.format); handle->bits_per_sample = snd_pcm_format_physical_width(setup->format.format);
str->bits_per_frame = str->bits_per_sample * setup->format.channels; handle->bits_per_frame = handle->bits_per_sample * setup->format.channels;
str->valid_setup = 1; handle->valid_setup = 1;
return 0; return 0;
} }
const snd_pcm_stream_setup_t* snd_pcm_stream_cached_setup(snd_pcm_t *pcm, int stream) int snd_pcm_channel_setup(snd_pcm_t *handle, snd_pcm_channel_setup_t *setup)
{ {
snd_pcm_stream_t *str; assert(handle && setup);
assert(pcm); assert(handle->valid_setup);
assert(stream >= 0 && stream <= 1); return handle->ops->channel_setup(handle->op_arg, setup);
str = &pcm->stream[stream];
assert(str->valid_setup);
return &str->setup;
} }
int snd_pcm_channel_setup(snd_pcm_t *pcm, int stream, snd_pcm_channel_setup_t *setup) int snd_pcm_params(snd_pcm_t *handle, snd_pcm_params_t *params)
{ {
snd_pcm_stream_t *str; int err;
assert(pcm && setup); snd_pcm_setup_t setup;
assert(stream >= 0 && stream <= 1); assert(handle && params);
str = &pcm->stream[stream]; assert(!handle->mmap_data);
assert(str->valid_setup); /* Here we pass private and not op_arg.
return pcm->ops->channel_setup(pcm, stream, setup); FIXME: find a better solution */
if ((err = handle->ops->params(handle->private, params)) < 0)
return err;
handle->valid_setup = 0;
return snd_pcm_setup(handle, &setup);
} }
int snd_pcm_stream_status(snd_pcm_t *pcm, snd_pcm_stream_status_t *status) int snd_pcm_status(snd_pcm_t *handle, snd_pcm_status_t *status)
{ {
assert(pcm && status); assert(handle && status);
assert(status->stream >= 0 && status->stream <= 1); return handle->ops->status(handle->op_arg, status);
assert(pcm->stream[status->stream].open);
return pcm->ops->stream_status(pcm, status);
} }
int snd_pcm_stream_state(snd_pcm_t *pcm, int stream) int snd_pcm_state(snd_pcm_t *handle)
{ {
snd_pcm_stream_t *str; assert(handle);
assert(pcm); if (handle->mmap_status)
assert(stream >= 0 && stream <= 1); return handle->mmap_status->state;
str = &pcm->stream[stream]; return handle->ops->state(handle->op_arg);
assert(str->open);
if (str->mmap_status)
return str->mmap_status->state;
return pcm->ops->stream_state(pcm, stream);
} }
int snd_pcm_stream_frame_io(snd_pcm_t *pcm, int stream, int update) int snd_pcm_frame_io(snd_pcm_t *handle, int update)
{ {
snd_pcm_stream_t *str; assert(handle);
assert(pcm); assert(handle->valid_setup);
assert(stream >= 0 && stream <= 1); if (handle->mmap_status && !update)
str = &pcm->stream[stream]; return handle->mmap_status->frame_io;
assert(str->valid_setup); return handle->ops->frame_io(handle->op_arg, update);
if (str->mmap_status && !update)
return str->mmap_status->frame_io;
return pcm->ops->stream_frame_io(pcm, stream, update);
} }
int snd_pcm_stream_prepare(snd_pcm_t *pcm, int stream) int snd_pcm_prepare(snd_pcm_t *handle)
{ {
assert(pcm); assert(handle);
assert(stream >= 0 && stream <= 1); return handle->ops->prepare(handle->op_arg);
assert(pcm->stream[stream].open);
return pcm->ops->stream_prepare(pcm, stream);
} }
int snd_pcm_playback_prepare(snd_pcm_t *pcm) int snd_pcm_go(snd_pcm_t *handle)
{ {
return snd_pcm_stream_prepare(pcm, SND_PCM_STREAM_PLAYBACK); assert(handle);
return handle->ops->go(handle->op_arg);
} }
int snd_pcm_capture_prepare(snd_pcm_t *pcm) int snd_pcm_sync_go(snd_pcm_t *handle, snd_pcm_sync_t *sync)
{ {
return snd_pcm_stream_prepare(pcm, SND_PCM_STREAM_CAPTURE); assert(handle);
return handle->ops->sync_go(handle->op_arg, sync);
} }
int snd_pcm_stream_go(snd_pcm_t *pcm, int stream) int snd_pcm_drain(snd_pcm_t *handle)
{ {
snd_pcm_stream_t *str; assert(handle);
assert(pcm); return handle->ops->drain(handle->op_arg);
assert(stream >= 0 && stream <= 1);
str = &pcm->stream[stream];
assert(str->valid_setup);
return pcm->ops->stream_go(pcm, stream);
} }
int snd_pcm_playback_go(snd_pcm_t *pcm) int snd_pcm_flush(snd_pcm_t *handle)
{ {
return snd_pcm_stream_go(pcm, SND_PCM_STREAM_PLAYBACK); assert(handle);
return handle->ops->flush(handle->op_arg);
} }
int snd_pcm_capture_go(snd_pcm_t *pcm) int snd_pcm_pause(snd_pcm_t *handle, int enable)
{ {
return snd_pcm_stream_go(pcm, SND_PCM_STREAM_CAPTURE); assert(handle);
return handle->ops->pause(handle->op_arg, enable);
} }
int snd_pcm_sync_go(snd_pcm_t *pcm, snd_pcm_sync_t *sync)
{
int stream;
assert(pcm && sync);
for (stream = 0; stream < 2; ++stream) {
if (pcm->stream[stream].open)
return pcm->ops->sync_go(pcm, stream, sync);
}
assert(0);
}
int snd_pcm_stream_drain(snd_pcm_t *pcm, int stream) ssize_t snd_pcm_frame_data(snd_pcm_t *handle, off_t offset)
{ {
assert(pcm); assert(handle);
assert(stream >= 0 && stream <= 1); assert(handle->valid_setup);
assert(pcm->stream[stream].open); if (handle->mmap_control) {
assert(stream == SND_PCM_STREAM_PLAYBACK);
return pcm->ops->stream_drain(pcm, stream);
}
int snd_pcm_playback_drain(snd_pcm_t *pcm)
{
return snd_pcm_stream_drain(pcm, SND_PCM_STREAM_PLAYBACK);
}
int snd_pcm_stream_flush(snd_pcm_t *pcm, int stream)
{
assert(pcm);
assert(stream >= 0 && stream <= 1);
assert(pcm->stream[stream].open);
return pcm->ops->stream_flush(pcm, stream);
}
int snd_pcm_playback_flush(snd_pcm_t *pcm)
{
return snd_pcm_stream_flush(pcm, SND_PCM_STREAM_PLAYBACK);
}
int snd_pcm_capture_flush(snd_pcm_t *pcm)
{
return snd_pcm_stream_flush(pcm, SND_PCM_STREAM_CAPTURE);
}
int snd_pcm_stream_pause(snd_pcm_t *pcm, int stream, int enable)
{
assert(pcm);
assert(stream >= 0 && stream <= 1);
assert(pcm->stream[stream].open);
assert(stream == SND_PCM_STREAM_PLAYBACK);
return pcm->ops->stream_pause(pcm, stream, enable);
}
int snd_pcm_playback_pause(snd_pcm_t *pcm, int enable)
{
return snd_pcm_stream_pause(pcm, SND_PCM_STREAM_PLAYBACK, enable);
}
ssize_t snd_pcm_stream_frame_data(snd_pcm_t *pcm, int stream, off_t offset)
{
snd_pcm_stream_t *str;
assert(pcm);
assert(stream >= 0 && stream <= 1);
str = &pcm->stream[stream];
assert(str->valid_setup);
if (str->mmap_control) {
if (offset == 0) if (offset == 0)
return str->mmap_control->frame_data; return handle->mmap_control->frame_data;
if (str->mmap_status)
return snd_pcm_mmap_stream_frame_data(pcm, stream, offset);
} }
return pcm->ops->stream_frame_data(pcm, stream, offset); return handle->ops->frame_data(handle->op_arg, offset);
} }
ssize_t snd_pcm_write(snd_pcm_t *pcm, const void *buffer, size_t size) ssize_t snd_pcm_write(snd_pcm_t *handle, const void *buffer, size_t size)
{ {
snd_pcm_stream_t *str; assert(handle);
assert(pcm);
str = &pcm->stream[SND_PCM_STREAM_PLAYBACK];
assert(str->valid_setup);
assert(size == 0 || buffer); assert(size == 0 || buffer);
assert(size % str->setup.frames_align == 0); assert(handle->valid_setup);
return pcm->ops->write(pcm, buffer, size); assert(size % handle->setup.frames_align == 0);
return handle->ops->write(handle->op_arg, buffer, size);
} }
ssize_t snd_pcm_writev(snd_pcm_t *pcm, const struct iovec *vector, unsigned long count) ssize_t snd_pcm_writev(snd_pcm_t *handle, const struct iovec *vector, unsigned long count)
{ {
assert(pcm); assert(handle);
assert(pcm->stream[SND_PCM_STREAM_PLAYBACK].valid_setup);
assert(count == 0 || vector); assert(count == 0 || vector);
return pcm->ops->writev(pcm, vector, count); assert(handle->valid_setup);
return handle->ops->writev(handle->op_arg, vector, count);
} }
ssize_t snd_pcm_read(snd_pcm_t *pcm, void *buffer, size_t size) ssize_t snd_pcm_read(snd_pcm_t *handle, void *buffer, size_t size)
{ {
snd_pcm_stream_t *str; assert(handle);
assert(pcm);
str = &pcm->stream[SND_PCM_STREAM_CAPTURE];
assert(str->valid_setup);
assert(size == 0 || buffer); assert(size == 0 || buffer);
assert(size % str->setup.frames_align == 0); assert(handle->valid_setup);
return pcm->ops->read(pcm, buffer, size); assert(size % handle->setup.frames_align == 0);
return handle->ops->read(handle->op_arg, buffer, size);
} }
ssize_t snd_pcm_readv(snd_pcm_t *pcm, const struct iovec *vector, unsigned long count) ssize_t snd_pcm_readv(snd_pcm_t *handle, const struct iovec *vector, unsigned long count)
{ {
assert(pcm); assert(handle);
assert(pcm->stream[SND_PCM_STREAM_CAPTURE].valid_setup);
assert(count == 0 || vector); assert(count == 0 || vector);
return pcm->ops->readv(pcm, vector, count); assert(handle->valid_setup);
return handle->ops->readv(handle->op_arg, vector, count);
} }
int snd_pcm_file_descriptor(snd_pcm_t* pcm, int stream) int snd_pcm_file_descriptor(snd_pcm_t *handle)
{ {
assert(pcm); assert(handle);
assert(stream >= 0 && stream <= 1); return handle->ops->file_descriptor(handle->op_arg);
assert(pcm->stream[stream].open);
return pcm->ops->file_descriptor(pcm, stream);
} }
int snd_pcm_channels_mask(snd_pcm_t *pcm, int stream, bitset_t *client_vmask) int snd_pcm_channels_mask(snd_pcm_t *handle, bitset_t *client_vmask)
{ {
assert(pcm); assert(handle);
assert(stream >= 0 && stream <= 1); assert(handle->valid_setup);
assert(pcm->stream[stream].valid_setup); return handle->ops->channels_mask(handle->op_arg, client_vmask);
return pcm->ops->channels_mask(pcm, stream, client_vmask);
} }
typedef struct { typedef struct {
@ -475,16 +322,13 @@ static assoc_t xruns[] = { XRUN(FLUSH), XRUN(DRAIN), END };
static assoc_t fills[] = { FILL(NONE), FILL(SILENCE_WHOLE), FILL(SILENCE), END }; static assoc_t fills[] = { FILL(NONE), FILL(SILENCE_WHOLE), FILL(SILENCE), END };
static assoc_t onoff[] = { {0, "OFF", NULL}, {1, "ON", NULL}, {-1, "ON", NULL}, END }; static assoc_t onoff[] = { {0, "OFF", NULL}, {1, "ON", NULL}, {-1, "ON", NULL}, END };
int snd_pcm_dump_setup(snd_pcm_t *pcm, int stream, FILE *fp) int snd_pcm_dump_setup(snd_pcm_t *handle, FILE *fp)
{ {
snd_pcm_stream_t *str; snd_pcm_setup_t *setup;
snd_pcm_stream_setup_t *setup; assert(handle);
assert(pcm); assert(handle->valid_setup);
assert(stream >= 0 && stream <= 1); setup = &handle->setup;
str = &pcm->stream[stream]; fprintf(fp, "stream: %s\n", assoc(handle->stream, streams));
assert(str->valid_setup);
setup = &str->setup;
fprintf(fp, "stream: %s\n", assoc(setup->stream, streams));
fprintf(fp, "mode: %s\n", assoc(setup->mode, modes)); fprintf(fp, "mode: %s\n", assoc(setup->mode, modes));
fprintf(fp, "format: %s\n", assoc(setup->format.format, fmts)); fprintf(fp, "format: %s\n", assoc(setup->format.format, fmts));
fprintf(fp, "channels: %d\n", setup->format.channels); fprintf(fp, "channels: %d\n", setup->format.channels);
@ -532,42 +376,31 @@ int snd_pcm_get_format_value(const char* name)
return -1; return -1;
} }
ssize_t snd_pcm_bytes_to_frames(snd_pcm_t *pcm, int stream, int bytes) ssize_t snd_pcm_bytes_to_frames(snd_pcm_t *handle, int bytes)
{ {
snd_pcm_stream_t *str; assert(handle);
assert(pcm); assert(handle->valid_setup);
assert(stream >= 0 && stream <= 1); return bytes * 8 / handle->bits_per_frame;
str = &pcm->stream[stream];
assert(str->valid_setup);
return bytes * 8 / str->bits_per_frame;
} }
ssize_t snd_pcm_frames_to_bytes(snd_pcm_t *pcm, int stream, int frames) ssize_t snd_pcm_frames_to_bytes(snd_pcm_t *handle, int frames)
{ {
snd_pcm_stream_t *str; assert(handle);
assert(pcm); assert(handle->valid_setup);
assert(stream >= 0 && stream <= 1); return frames * handle->bits_per_frame / 8;
str = &pcm->stream[stream];
assert(str->valid_setup);
return frames * str->bits_per_frame / 8;
} }
ssize_t snd_pcm_bytes_to_samples(snd_pcm_t *pcm, int stream, int bytes) ssize_t snd_pcm_bytes_to_samples(snd_pcm_t *handle, int bytes)
{ {
snd_pcm_stream_t *str; assert(handle);
assert(pcm); assert(handle->valid_setup);
assert(stream >= 0 && stream <= 1); return bytes * 8 / handle->bits_per_sample;
str = &pcm->stream[stream];
assert(str->valid_setup);
return bytes * 8 / str->bits_per_sample;
} }
ssize_t snd_pcm_samples_to_bytes(snd_pcm_t *pcm, int stream, int samples) ssize_t snd_pcm_samples_to_bytes(snd_pcm_t *handle, int samples)
{ {
snd_pcm_stream_t *str; assert(handle);
assert(pcm); assert(handle->valid_setup);
assert(stream >= 0 && stream <= 1); return samples * handle->bits_per_sample / 8;
str = &pcm->stream[stream];
assert(str->valid_setup);
return samples * str->bits_per_sample / 8;
} }

View file

@ -30,35 +30,30 @@
#include "pcm_local.h" #include "pcm_local.h"
typedef struct { typedef struct {
snd_pcm_t *handle;
int fd; int fd;
} snd_pcm_hw_stream_t;
typedef struct snd_pcm_hw {
int card;
int device;
int ver;
snd_pcm_hw_stream_t stream[2];
} snd_pcm_hw_t; } snd_pcm_hw_t;
#define SND_FILE_PCM_PLAYBACK "/dev/snd/pcmC%iD%ip" #define SND_FILE_PCM_STREAM_PLAYBACK "/dev/snd/pcmC%iD%ip"
#define SND_FILE_PCM_CAPTURE "/dev/snd/pcmC%iD%ic" #define SND_FILE_PCM_STREAM_CAPTURE "/dev/snd/pcmC%iD%ic"
#define SND_PCM_VERSION_MAX SND_PROTOCOL_VERSION(2, 0, 0) #define SND_PCM_VERSION_MAX SND_PROTOCOL_VERSION(2, 0, 0)
static int snd_pcm_hw_stream_close(snd_pcm_t *pcm, int stream) static int snd_pcm_hw_close(void *private)
{ {
snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private; snd_pcm_hw_t *hw = (snd_pcm_hw_t*) private;
int fd = hw->stream[stream].fd; int fd = hw->fd;
free(private);
if (fd >= 0) if (fd >= 0)
if (close(fd)) if (close(fd))
return -errno; return -errno;
return 0; return 0;
} }
static int snd_pcm_hw_stream_nonblock(snd_pcm_t *pcm, int stream, int nonblock) static int snd_pcm_hw_nonblock(void *private, int nonblock)
{ {
long flags; long flags;
snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private; snd_pcm_hw_t *hw = (snd_pcm_hw_t*) private;
int fd = hw->stream[stream].fd; int fd = hw->fd;
if ((flags = fcntl(fd, F_GETFL)) < 0) if ((flags = fcntl(fd, F_GETFL)) < 0)
return -errno; return -errno;
@ -71,151 +66,144 @@ static int snd_pcm_hw_stream_nonblock(snd_pcm_t *pcm, int stream, int nonblock)
return 0; return 0;
} }
static int snd_pcm_hw_info(snd_pcm_t *pcm, int stream, snd_pcm_info_t * info) static int snd_pcm_hw_info(void *private, snd_pcm_info_t * info)
{ {
snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private; snd_pcm_hw_t *hw = (snd_pcm_hw_t*) private;
int fd = hw->stream[stream].fd; int fd = hw->fd;
if (ioctl(fd, SND_PCM_IOCTL_INFO, info) < 0) if (ioctl(fd, SND_PCM_IOCTL_INFO, info) < 0)
return -errno; return -errno;
return 0; return 0;
} }
static int snd_pcm_hw_stream_info(snd_pcm_t *pcm, snd_pcm_stream_info_t * info) static int snd_pcm_hw_params(void *private, snd_pcm_params_t * params)
{ {
snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private; snd_pcm_hw_t *hw = (snd_pcm_hw_t*) private;
int fd = hw->stream[info->stream].fd; int fd = hw->fd;
if (ioctl(fd, SND_PCM_IOCTL_STREAM_INFO, info) < 0) if (ioctl(fd, SND_PCM_IOCTL_PARAMS, params) < 0)
return -errno; return -errno;
return 0; return 0;
} }
static int snd_pcm_hw_stream_params(snd_pcm_t *pcm, snd_pcm_stream_params_t * params) static int snd_pcm_hw_setup(void *private, snd_pcm_setup_t * setup)
{ {
snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private; snd_pcm_hw_t *hw = (snd_pcm_hw_t*) private;
int fd = hw->stream[params->stream].fd; int fd = hw->fd;
if (ioctl(fd, SND_PCM_IOCTL_STREAM_PARAMS, params) < 0) if (ioctl(fd, SND_PCM_IOCTL_SETUP, setup) < 0)
return -errno; return -errno;
return 0; return 0;
} }
static int snd_pcm_hw_stream_setup(snd_pcm_t *pcm, snd_pcm_stream_setup_t * setup) static int snd_pcm_hw_channel_setup(void *private, snd_pcm_channel_setup_t * setup)
{ {
snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private; snd_pcm_hw_t *hw = (snd_pcm_hw_t*) private;
int fd = hw->stream[setup->stream].fd; int fd = hw->fd;
if (ioctl(fd, SND_PCM_IOCTL_STREAM_SETUP, setup) < 0)
return -errno;
return 0;
}
static int snd_pcm_hw_channel_setup(snd_pcm_t *pcm, int stream, snd_pcm_channel_setup_t * setup)
{
snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private;
int fd = hw->stream[stream].fd;
if (ioctl(fd, SND_PCM_IOCTL_CHANNEL_SETUP, setup) < 0) if (ioctl(fd, SND_PCM_IOCTL_CHANNEL_SETUP, setup) < 0)
return -errno; return -errno;
return 0; return 0;
} }
static int snd_pcm_hw_stream_status(snd_pcm_t *pcm, snd_pcm_stream_status_t * status) static int snd_pcm_hw_status(void *private, snd_pcm_status_t * status)
{ {
snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private; snd_pcm_hw_t *hw = (snd_pcm_hw_t*) private;
int fd = hw->stream[status->stream].fd; int fd = hw->fd;
if (ioctl(fd, SND_PCM_IOCTL_STREAM_STATUS, status) < 0) if (ioctl(fd, SND_PCM_IOCTL_STATUS, status) < 0)
return -errno; return -errno;
return 0; return 0;
} }
static ssize_t snd_pcm_hw_stream_state(snd_pcm_t *pcm, int stream) static ssize_t snd_pcm_hw_state(void *private)
{ {
snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private; snd_pcm_hw_t *hw = (snd_pcm_hw_t*) private;
int fd = hw->stream[stream].fd; int fd = hw->fd;
snd_pcm_stream_status_t status; snd_pcm_status_t status;
status.stream = stream; if (ioctl(fd, SND_PCM_IOCTL_STATUS, status) < 0)
if (ioctl(fd, SND_PCM_IOCTL_STREAM_STATUS, status) < 0)
return -errno; return -errno;
return status.state; return status.state;
} }
static ssize_t snd_pcm_hw_stream_frame_io(snd_pcm_t *pcm, int stream, int update UNUSED) static ssize_t snd_pcm_hw_frame_io(void *private, int update UNUSED)
{ {
snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private; snd_pcm_hw_t *hw = (snd_pcm_hw_t*) private;
int fd = hw->stream[stream].fd; int fd = hw->fd;
ssize_t pos = ioctl(fd, SND_PCM_IOCTL_STREAM_FRAME_IO); ssize_t pos = ioctl(fd, SND_PCM_IOCTL_FRAME_IO);
if (pos < 0) if (pos < 0)
return -errno; return -errno;
return pos; return pos;
} }
static int snd_pcm_hw_stream_prepare(snd_pcm_t *pcm, int stream) static int snd_pcm_hw_prepare(void *private)
{ {
snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private; snd_pcm_hw_t *hw = (snd_pcm_hw_t*) private;
int fd = hw->stream[stream].fd; int fd = hw->fd;
if (ioctl(fd, SND_PCM_IOCTL_STREAM_PREPARE) < 0) if (ioctl(fd, SND_PCM_IOCTL_PREPARE) < 0)
return -errno; return -errno;
return 0; return 0;
} }
static int snd_pcm_hw_stream_go(snd_pcm_t *pcm, int stream) static int snd_pcm_hw_go(void *private)
{ {
snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private; snd_pcm_hw_t *hw = (snd_pcm_hw_t*) private;
int fd = hw->stream[stream].fd; int fd = hw->fd;
if (ioctl(fd, SND_PCM_IOCTL_STREAM_GO) < 0) if (ioctl(fd, SND_PCM_IOCTL_GO) < 0)
return -errno; return -errno;
return 0; return 0;
} }
static int snd_pcm_hw_sync_go(snd_pcm_t *pcm, int stream, snd_pcm_sync_t *sync) static int snd_pcm_hw_sync_go(void *private, snd_pcm_sync_t *sync)
{ {
snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private; snd_pcm_hw_t *hw = (snd_pcm_hw_t*) private;
int fd = hw->stream[stream].fd; int fd = hw->fd;
if (ioctl(fd, SND_PCM_IOCTL_SYNC_GO, sync) < 0) if (ioctl(fd, SND_PCM_IOCTL_SYNC_GO, sync) < 0)
return -errno; return -errno;
return 0; return 0;
} }
static int snd_pcm_hw_stream_drain(snd_pcm_t *pcm, int stream) static int snd_pcm_hw_drain(void *private)
{ {
snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private; snd_pcm_hw_t *hw = (snd_pcm_hw_t*) private;
int fd = hw->stream[stream].fd; int fd = hw->fd;
if (ioctl(fd, SND_PCM_IOCTL_STREAM_DRAIN) < 0) if (ioctl(fd, SND_PCM_IOCTL_DRAIN) < 0)
return -errno; return -errno;
return 0; return 0;
} }
static int snd_pcm_hw_stream_flush(snd_pcm_t *pcm, int stream) static int snd_pcm_hw_flush(void *private)
{ {
snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private; snd_pcm_hw_t *hw = (snd_pcm_hw_t*) private;
int fd = hw->stream[stream].fd; int fd = hw->fd;
if (ioctl(fd, SND_PCM_IOCTL_STREAM_FLUSH) < 0) if (ioctl(fd, SND_PCM_IOCTL_FLUSH) < 0)
return -errno; return -errno;
return 0; return 0;
} }
static int snd_pcm_hw_stream_pause(snd_pcm_t *pcm, int stream, int enable) static int snd_pcm_hw_pause(void *private, int enable)
{ {
snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private; snd_pcm_hw_t *hw = (snd_pcm_hw_t*) private;
int fd = hw->stream[stream].fd; int fd = hw->fd;
if (ioctl(fd, SND_PCM_IOCTL_STREAM_PAUSE, &enable) < 0) if (ioctl(fd, SND_PCM_IOCTL_PAUSE, &enable) < 0)
return -errno; return -errno;
return 0; return 0;
} }
static ssize_t snd_pcm_hw_stream_frame_data(snd_pcm_t *pcm, int stream, off_t offset) static ssize_t snd_pcm_hw_frame_data(void *private, off_t offset)
{ {
ssize_t result; ssize_t result;
snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private; snd_pcm_hw_t *hw = (snd_pcm_hw_t*) private;
int fd = hw->stream[stream].fd; snd_pcm_t *handle = hw->handle;
result = ioctl(fd, SND_PCM_IOCTL_STREAM_FRAME_DATA, offset); int fd = hw->fd;
if (handle->mmap_status && handle->mmap_control)
return snd_pcm_mmap_frame_data(handle, offset);
result = ioctl(fd, SND_PCM_IOCTL_FRAME_DATA, offset);
if (result < 0) if (result < 0)
return -errno; return -errno;
return result; return result;
} }
static ssize_t snd_pcm_hw_write(snd_pcm_t *pcm, const void *buffer, size_t size) static ssize_t snd_pcm_hw_write(void *private, const void *buffer, size_t size)
{ {
ssize_t result; ssize_t result;
snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private; snd_pcm_hw_t *hw = (snd_pcm_hw_t*) private;
int fd = hw->stream[SND_PCM_STREAM_PLAYBACK].fd; int fd = hw->fd;
snd_xfer_t xfer; snd_xfer_t xfer;
xfer.buf = (char*) buffer; xfer.buf = (char*) buffer;
xfer.count = size; xfer.count = size;
@ -225,11 +213,11 @@ static ssize_t snd_pcm_hw_write(snd_pcm_t *pcm, const void *buffer, size_t size)
return result; return result;
} }
static ssize_t snd_pcm_hw_writev(snd_pcm_t *pcm, const struct iovec *vector, unsigned long count) static ssize_t snd_pcm_hw_writev(void *private, const struct iovec *vector, unsigned long count)
{ {
ssize_t result; ssize_t result;
snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private; snd_pcm_hw_t *hw = (snd_pcm_hw_t*) private;
int fd = hw->stream[SND_PCM_STREAM_PLAYBACK].fd; int fd = hw->fd;
snd_xferv_t xferv; snd_xferv_t xferv;
xferv.vector = vector; xferv.vector = vector;
xferv.count = count; xferv.count = count;
@ -239,11 +227,11 @@ static ssize_t snd_pcm_hw_writev(snd_pcm_t *pcm, const struct iovec *vector, uns
return result; return result;
} }
static ssize_t snd_pcm_hw_read(snd_pcm_t *pcm, void *buffer, size_t size) static ssize_t snd_pcm_hw_read(void *private, void *buffer, size_t size)
{ {
ssize_t result; ssize_t result;
snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private; snd_pcm_hw_t *hw = (snd_pcm_hw_t*) private;
int fd = hw->stream[SND_PCM_STREAM_CAPTURE].fd; int fd = hw->fd;
snd_xfer_t xfer; snd_xfer_t xfer;
xfer.buf = buffer; xfer.buf = buffer;
xfer.count = size; xfer.count = size;
@ -253,11 +241,11 @@ static ssize_t snd_pcm_hw_read(snd_pcm_t *pcm, void *buffer, size_t size)
return result; return result;
} }
ssize_t snd_pcm_hw_readv(snd_pcm_t *pcm, const struct iovec *vector, unsigned long count) ssize_t snd_pcm_hw_readv(void *private, const struct iovec *vector, unsigned long count)
{ {
ssize_t result; ssize_t result;
snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private; snd_pcm_hw_t *hw = (snd_pcm_hw_t*) private;
int fd = hw->stream[SND_PCM_STREAM_CAPTURE].fd; int fd = hw->fd;
snd_xferv_t xferv; snd_xferv_t xferv;
xferv.vector = vector; xferv.vector = vector;
xferv.count = count; xferv.count = count;
@ -267,95 +255,94 @@ ssize_t snd_pcm_hw_readv(snd_pcm_t *pcm, const struct iovec *vector, unsigned lo
return result; return result;
} }
static int snd_pcm_hw_mmap_status(snd_pcm_t *pcm, int stream, snd_pcm_mmap_status_t **status) static int snd_pcm_hw_mmap_status(void *private, snd_pcm_mmap_status_t **status)
{ {
void *ptr; void *ptr;
snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private; snd_pcm_hw_t *hw = (snd_pcm_hw_t*) private;
ptr = mmap(NULL, sizeof(snd_pcm_mmap_control_t), PROT_READ, MAP_FILE|MAP_SHARED, ptr = mmap(NULL, sizeof(snd_pcm_mmap_control_t), PROT_READ, MAP_FILE|MAP_SHARED,
hw->stream[stream].fd, SND_PCM_MMAP_OFFSET_STATUS); hw->fd, SND_PCM_MMAP_OFFSET_STATUS);
if (ptr == MAP_FAILED || ptr == NULL) if (ptr == MAP_FAILED || ptr == NULL)
return -errno; return -errno;
*status = ptr; *status = ptr;
return 0; return 0;
} }
static int snd_pcm_hw_mmap_control(snd_pcm_t *pcm, int stream, snd_pcm_mmap_control_t **control) static int snd_pcm_hw_mmap_control(void *private, snd_pcm_mmap_control_t **control)
{ {
void *ptr; void *ptr;
snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private; snd_pcm_hw_t *hw = (snd_pcm_hw_t*) private;
ptr = mmap(NULL, sizeof(snd_pcm_mmap_control_t), PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, ptr = mmap(NULL, sizeof(snd_pcm_mmap_control_t), PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED,
hw->stream[stream].fd, SND_PCM_MMAP_OFFSET_CONTROL); hw->fd, SND_PCM_MMAP_OFFSET_CONTROL);
if (ptr == MAP_FAILED || ptr == NULL) if (ptr == MAP_FAILED || ptr == NULL)
return -errno; return -errno;
*control = ptr; *control = ptr;
return 0; return 0;
} }
static int snd_pcm_hw_mmap_data(snd_pcm_t *pcm, int stream, void **buffer, size_t bsize) static int snd_pcm_hw_mmap_data(void *private, void **buffer, size_t bsize)
{ {
int prot; int prot;
void *daddr; void *daddr;
snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private; snd_pcm_hw_t *hw = (snd_pcm_hw_t*) private;
prot = stream == SND_PCM_STREAM_PLAYBACK ? PROT_WRITE : PROT_READ; prot = hw->handle->stream == SND_PCM_STREAM_PLAYBACK ? PROT_WRITE : PROT_READ;
daddr = mmap(NULL, bsize, prot, MAP_FILE|MAP_SHARED, daddr = mmap(NULL, bsize, prot, MAP_FILE|MAP_SHARED,
hw->stream[stream].fd, SND_PCM_MMAP_OFFSET_DATA); hw->fd, SND_PCM_MMAP_OFFSET_DATA);
if (daddr == MAP_FAILED || daddr == NULL) if (daddr == MAP_FAILED || daddr == NULL)
return -errno; return -errno;
*buffer = daddr; *buffer = daddr;
return 0; return 0;
} }
static int snd_pcm_hw_munmap_status(snd_pcm_t *pcm UNUSED, int stream UNUSED, snd_pcm_mmap_status_t *status) static int snd_pcm_hw_munmap_status(void *private UNUSED, snd_pcm_mmap_status_t *status)
{ {
if (munmap(status, sizeof(*status)) < 0) if (munmap(status, sizeof(*status)) < 0)
return -errno; return -errno;
return 0; return 0;
} }
static int snd_pcm_hw_munmap_control(snd_pcm_t *pcm UNUSED, int stream UNUSED, snd_pcm_mmap_control_t *control) static int snd_pcm_hw_munmap_control(void *private UNUSED, snd_pcm_mmap_control_t *control)
{ {
if (munmap(control, sizeof(*control)) < 0) if (munmap(control, sizeof(*control)) < 0)
return -errno; return -errno;
return 0; return 0;
} }
static int snd_pcm_hw_munmap_data(snd_pcm_t *pcm UNUSED, int stream UNUSED, void *buffer, size_t bsize) static int snd_pcm_hw_munmap_data(void *private UNUSED, void *buffer, size_t bsize)
{ {
if (munmap(buffer, bsize) < 0) if (munmap(buffer, bsize) < 0)
return -errno; return -errno;
return 0; return 0;
} }
static int snd_pcm_hw_file_descriptor(snd_pcm_t *pcm, int stream) static int snd_pcm_hw_file_descriptor(void *private)
{ {
snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private; snd_pcm_hw_t *hw = (snd_pcm_hw_t*) private;
return hw->stream[stream].fd; return hw->fd;
} }
static int snd_pcm_hw_channels_mask(snd_pcm_t *pcm UNUSED, int stream UNUSED, static int snd_pcm_hw_channels_mask(void *private UNUSED,
bitset_t *client_vmask UNUSED) bitset_t *client_vmask UNUSED)
{ {
return 0; return 0;
} }
struct snd_pcm_ops snd_pcm_hw_ops = { struct snd_pcm_ops snd_pcm_hw_ops = {
stream_close: snd_pcm_hw_stream_close, close: snd_pcm_hw_close,
stream_nonblock: snd_pcm_hw_stream_nonblock, nonblock: snd_pcm_hw_nonblock,
info: snd_pcm_hw_info, info: snd_pcm_hw_info,
stream_info: snd_pcm_hw_stream_info, params: snd_pcm_hw_params,
stream_params: snd_pcm_hw_stream_params, setup: snd_pcm_hw_setup,
stream_setup: snd_pcm_hw_stream_setup,
channel_setup: snd_pcm_hw_channel_setup, channel_setup: snd_pcm_hw_channel_setup,
stream_status: snd_pcm_hw_stream_status, status: snd_pcm_hw_status,
stream_frame_io: snd_pcm_hw_stream_frame_io, frame_io: snd_pcm_hw_frame_io,
stream_state: snd_pcm_hw_stream_state, state: snd_pcm_hw_state,
stream_prepare: snd_pcm_hw_stream_prepare, prepare: snd_pcm_hw_prepare,
stream_go: snd_pcm_hw_stream_go, go: snd_pcm_hw_go,
sync_go: snd_pcm_hw_sync_go, sync_go: snd_pcm_hw_sync_go,
stream_drain: snd_pcm_hw_stream_drain, drain: snd_pcm_hw_drain,
stream_flush: snd_pcm_hw_stream_flush, flush: snd_pcm_hw_flush,
stream_pause: snd_pcm_hw_stream_pause, pause: snd_pcm_hw_pause,
stream_frame_data: snd_pcm_hw_stream_frame_data, frame_data: snd_pcm_hw_frame_data,
write: snd_pcm_hw_write, write: snd_pcm_hw_write,
writev: snd_pcm_hw_writev, writev: snd_pcm_hw_writev,
read: snd_pcm_hw_read, read: snd_pcm_hw_read,
@ -370,122 +357,99 @@ struct snd_pcm_ops snd_pcm_hw_ops = {
channels_mask: snd_pcm_hw_channels_mask, channels_mask: snd_pcm_hw_channels_mask,
}; };
static int snd_pcm_hw_open_stream(int card, int device, int stream, int subdevice, int fmode, snd_ctl_t *ctl, int *ver) int snd_pcm_hw_open_subdevice(snd_pcm_t **handlep, int card, int device, int subdevice, int stream, int mode)
{ {
char filename[32]; char filename[32];
char *filefmt; char *filefmt;
int err, fd; int ver;
int ret = 0, fd = -1;
int attempt = 0; int attempt = 0;
snd_pcm_stream_info_t info; snd_pcm_info_t info;
int fmode;
snd_ctl_t *ctl;
snd_pcm_t *handle;
snd_pcm_hw_t *hw;
*handlep = 0;
if ((ret = snd_ctl_open(&ctl, card)) < 0)
return ret;
switch (stream) { switch (stream) {
case SND_PCM_STREAM_PLAYBACK: case SND_PCM_STREAM_PLAYBACK:
filefmt = SND_FILE_PCM_PLAYBACK; filefmt = SND_FILE_PCM_STREAM_PLAYBACK;
break; break;
case SND_PCM_STREAM_CAPTURE: case SND_PCM_STREAM_CAPTURE:
filefmt = SND_FILE_PCM_CAPTURE; filefmt = SND_FILE_PCM_STREAM_CAPTURE;
break; break;
default: default:
assert(0); assert(0);
} }
if ((err = snd_ctl_pcm_stream_prefer_subdevice(ctl, device, stream, subdevice)) < 0) if ((ret = snd_ctl_pcm_prefer_subdevice(ctl, subdevice)) < 0)
return err; goto __end;
sprintf(filename, filefmt, card, device); sprintf(filename, filefmt, card, device);
__again: __again:
if (attempt++ > 3) { if (attempt++ > 3) {
snd_ctl_close(ctl); ret = -EBUSY;
return -EBUSY; goto __end;
} }
fmode = O_RDWR;
if (mode & SND_PCM_NONBLOCK)
fmode |= O_NONBLOCK;
if ((fd = open(filename, fmode)) < 0) { if ((fd = open(filename, fmode)) < 0) {
err = -errno; ret = -errno;
return err; goto __end;
} }
if (ioctl(fd, SND_PCM_IOCTL_PVERSION, ver) < 0) { if (ioctl(fd, SND_PCM_IOCTL_PVERSION, &ver) < 0) {
err = -errno; ret = -errno;
close(fd); goto __end;
return err;
} }
if (SND_PROTOCOL_INCOMPATIBLE(*ver, SND_PCM_VERSION_MAX)) { if (SND_PROTOCOL_INCOMPATIBLE(ver, SND_PCM_VERSION_MAX)) {
close(fd); ret = -SND_ERROR_INCOMPATIBLE_VERSION;
return -SND_ERROR_INCOMPATIBLE_VERSION; goto __end;
} }
if (subdevice >= 0) { if (subdevice >= 0) {
memset(&info, 0, sizeof(info)); memset(&info, 0, sizeof(info));
if (ioctl(fd, SND_PCM_IOCTL_STREAM_INFO, &info) < 0) { if (ioctl(fd, SND_PCM_IOCTL_INFO, &info) < 0) {
err = -errno; ret = -errno;
close(fd); goto __end;
return err;
} }
if (info.subdevice != subdevice) { if (info.subdevice != subdevice) {
close(fd); close(fd);
goto __again; goto __again;
} }
} }
return fd; handle = calloc(1, sizeof(snd_pcm_t));
} if (!handle) {
ret = -ENOMEM;
int snd_pcm_open_subdevice(snd_pcm_t **handle, int card, int device, int subdevice, int mode) goto __end;
{ }
int fmode, ver, err; hw = calloc(1, sizeof(snd_pcm_hw_t));
snd_pcm_t *pcm; if (!handle) {
snd_pcm_hw_t *hw; free(handle);
snd_ctl_t *ctl; ret = -ENOMEM;
int pfd = -1, cfd = -1; goto __end;
}
assert(handle); hw->handle = handle;
*handle = NULL; hw->fd = fd;
handle->type = SND_PCM_TYPE_HW;
handle->stream = stream;
handle->ops = &snd_pcm_hw_ops;
handle->op_arg = hw;
handle->mode = mode;
handle->private = hw;
*handlep = handle;
assert(card >= 0 && card < SND_CARDS); __end:
if ((err = snd_ctl_open(&ctl, card)) < 0) if (ret < 0 && fd >= 0)
return err; close(fd);
if (mode & SND_PCM_OPEN_PLAYBACK) {
fmode = O_RDWR;
if (mode & SND_PCM_NONBLOCK_PLAYBACK)
fmode |= O_NONBLOCK;
pfd = snd_pcm_hw_open_stream(card, device, SND_PCM_STREAM_PLAYBACK,
subdevice, fmode, ctl, &ver);
if (pfd < 0) {
snd_ctl_close(ctl);
return pfd;
}
}
if (mode & SND_PCM_OPEN_CAPTURE) {
fmode = O_RDWR;
if (mode & SND_PCM_NONBLOCK_CAPTURE)
fmode |= O_NONBLOCK;
cfd = snd_pcm_hw_open_stream(card, device, SND_PCM_STREAM_CAPTURE,
subdevice, fmode, ctl, &ver);
if (cfd < 0) {
if (pfd >= 0)
close(pfd);
snd_ctl_close(ctl);
return cfd;
}
}
snd_ctl_close(ctl); snd_ctl_close(ctl);
assert(pfd >= 0 || cfd >= 0); return ret;
err = snd_pcm_abstract_open(handle, mode, SND_PCM_TYPE_HW, sizeof(snd_pcm_hw_t));
if (err < 0) {
if (pfd >= 0)
close(pfd);
if (cfd >= 0)
close(cfd);
return err;
}
pcm = *handle;
pcm->ops = &snd_pcm_hw_ops;
hw = (snd_pcm_hw_t*) &pcm->private;
hw->card = card;
hw->device = device;
hw->ver = ver;
hw->stream[SND_PCM_STREAM_PLAYBACK].fd = pfd;
hw->stream[SND_PCM_STREAM_CAPTURE].fd = cfd;
return 0;
} }
int snd_pcm_open(snd_pcm_t **handle, int card, int device, int mode) int snd_pcm_hw_open(snd_pcm_t **handlep, int card, int device, int stream, int mode)
{ {
return snd_pcm_open_subdevice(handle, card, device, -1, mode); return snd_pcm_hw_open_subdevice(handlep, card, device, -1, stream, mode);
} }

View file

@ -21,58 +21,44 @@
#include <assert.h> #include <assert.h>
#include "asoundlib.h" #include "asoundlib.h"
struct snd_pcm_ops { struct snd_pcm_ops {
int (*stream_close)(snd_pcm_t *pcm, int stream); int (*close)(void *private);
int (*stream_nonblock)(snd_pcm_t *pcm, int stream, int nonblock); int (*nonblock)(void *private, int nonblock);
int (*info)(snd_pcm_t *pcm, int stream, snd_pcm_info_t *info); int (*info)(void *private, snd_pcm_info_t *info);
int (*stream_info)(snd_pcm_t *pcm, snd_pcm_stream_info_t *info); int (*params)(void *private, snd_pcm_params_t *params);
int (*stream_params)(snd_pcm_t *pcm, snd_pcm_stream_params_t *params); int (*setup)(void *private, snd_pcm_setup_t *setup);
int (*stream_setup)(snd_pcm_t *pcm, snd_pcm_stream_setup_t *setup); int (*channel_setup)(void *private, snd_pcm_channel_setup_t *setup);
int (*channel_setup)(snd_pcm_t *pcm, int stream, snd_pcm_channel_setup_t *setup); int (*status)(void *private, snd_pcm_status_t *status);
int (*stream_status)(snd_pcm_t *pcm, snd_pcm_stream_status_t *status); int (*prepare)(void *private);
int (*stream_prepare)(snd_pcm_t *pcm, int stream); int (*go)(void *private);
int (*stream_go)(snd_pcm_t *pcm, int stream); int (*sync_go)(void *private, snd_pcm_sync_t *sync);
int (*sync_go)(snd_pcm_t *pcm, int stream, snd_pcm_sync_t *sync); int (*drain)(void *private);
int (*stream_drain)(snd_pcm_t *pcm, int stream); int (*flush)(void *private);
int (*stream_flush)(snd_pcm_t *pcm, int stream); int (*pause)(void *private, int enable);
int (*stream_pause)(snd_pcm_t *pcm, int stream, int enable); int (*state)(void *private);
int (*stream_state)(snd_pcm_t *pcm, int stream); ssize_t (*frame_io)(void *private, int update);
ssize_t (*stream_frame_io)(snd_pcm_t *pcm, int stream, int update); ssize_t (*frame_data)(void *private, off_t offset);
ssize_t (*stream_frame_data)(snd_pcm_t *pcm, int stream, off_t offset); ssize_t (*write)(void *private, const void *buffer, size_t size);
ssize_t (*write)(snd_pcm_t *pcm, const void *buffer, size_t size); ssize_t (*writev)(void *private, const struct iovec *vector, unsigned long count);
ssize_t (*writev)(snd_pcm_t *pcm, const struct iovec *vector, unsigned long count); ssize_t (*read)(void *private, void *buffer, size_t size);
ssize_t (*read)(snd_pcm_t *pcm, void *buffer, size_t size); ssize_t (*readv)(void *private, const struct iovec *vector, unsigned long count);
ssize_t (*readv)(snd_pcm_t *pcm, const struct iovec *vector, unsigned long count); int (*mmap_status)(void *private, snd_pcm_mmap_status_t **status);
int (*mmap_status)(snd_pcm_t *pcm, int stream, snd_pcm_mmap_status_t **status); int (*mmap_control)(void *private, snd_pcm_mmap_control_t **control);
int (*mmap_control)(snd_pcm_t *pcm, int stream, snd_pcm_mmap_control_t **control); int (*mmap_data)(void *private, void **buffer, size_t bsize);
int (*mmap_data)(snd_pcm_t *pcm, int stream, void **buffer, size_t bsize); int (*munmap_status)(void *private, snd_pcm_mmap_status_t *status);
int (*munmap_status)(snd_pcm_t *pcm, int stream, snd_pcm_mmap_status_t *status); int (*munmap_control)(void *private, snd_pcm_mmap_control_t *control);
int (*munmap_control)(snd_pcm_t *pcm, int stream, snd_pcm_mmap_control_t *control); int (*munmap_data)(void *private, void *buffer, size_t bsize);
int (*munmap_data)(snd_pcm_t *pcm, int stream, void *buffer, size_t bsize); int (*file_descriptor)(void *private);
int (*file_descriptor)(snd_pcm_t* pcm, int stream); int (*channels_mask)(void *private, bitset_t *client_vmask);
int (*channels_mask)(snd_pcm_t *pcm, int stream, bitset_t *client_vmask);
}; };
typedef struct { struct snd_pcm {
snd_pcm_plugin_t *first; snd_pcm_type_t type;
snd_pcm_plugin_t *last; int stream;
void *alloc_ptr[2];
size_t alloc_size[2];
int alloc_lock[2];
} snd_pcm_plug_stream_t;
typedef struct {
int close_slave;
snd_pcm_t *slave;
snd_pcm_plug_stream_t stream[2];
} snd_pcm_plug_t;
typedef struct {
int open;
int mode; int mode;
int valid_setup; int valid_setup;
snd_pcm_stream_setup_t setup; snd_pcm_setup_t setup;
snd_pcm_channel_area_t *channels; snd_pcm_channel_area_t *channels;
size_t bits_per_sample; size_t bits_per_sample;
size_t bits_per_frame; size_t bits_per_frame;
@ -81,46 +67,48 @@ typedef struct {
char *mmap_data; char *mmap_data;
size_t mmap_data_size; size_t mmap_data_size;
enum { _INTERLEAVED, _NONINTERLEAVED, _COMPLEX } mmap_type; enum { _INTERLEAVED, _NONINTERLEAVED, _COMPLEX } mmap_type;
} snd_pcm_stream_t;
struct snd_pcm {
snd_pcm_type_t type;
int mode;
struct snd_pcm_ops *ops; struct snd_pcm_ops *ops;
snd_pcm_stream_t stream[2]; void *op_arg;
int private[0]; void *private;
}; };
int snd_pcm_abstract_open(snd_pcm_t **handle, int mode, snd_pcm_type_t type, size_t extra); #undef snd_pcm_plug_t
typedef struct snd_pcm_plug {
int close_slave;
snd_pcm_t *handle;
snd_pcm_t *slave;
snd_pcm_plugin_t *first;
snd_pcm_plugin_t *last;
size_t frames_alloc;
} snd_pcm_plug_t;
unsigned int snd_pcm_plug_formats(unsigned int formats); unsigned int snd_pcm_plug_formats(unsigned int formats);
int snd_pcm_plug_slave_params(snd_pcm_stream_params_t *params, int snd_pcm_plug_slave_params(snd_pcm_params_t *params,
snd_pcm_stream_info_t *slave_info, snd_pcm_info_t *slave_info,
snd_pcm_stream_params_t *slave_params); snd_pcm_params_t *slave_params);
int snd_pcm_plug_format(snd_pcm_plugin_handle_t *pcm, int snd_pcm_plug_format(snd_pcm_plug_t *plug,
snd_pcm_stream_params_t *params, snd_pcm_params_t *params,
snd_pcm_stream_params_t *slave_params); snd_pcm_params_t *slave_params);
ssize_t snd_pcm_plug_write_transfer(snd_pcm_plugin_handle_t *handle, snd_pcm_plugin_channel_t *src_channels, size_t size); ssize_t snd_pcm_plug_write_transfer(snd_pcm_plug_t *plug, snd_pcm_plugin_channel_t *src_channels, size_t size);
ssize_t snd_pcm_plug_read_transfer(snd_pcm_plugin_handle_t *handle, snd_pcm_plugin_channel_t *dst_channels_final, size_t size); ssize_t snd_pcm_plug_read_transfer(snd_pcm_plug_t *plug, snd_pcm_plugin_channel_t *dst_channels_final, size_t size);
ssize_t snd_pcm_plug_client_channels_iovec(snd_pcm_plugin_handle_t *handle, int stream, ssize_t snd_pcm_plug_client_channels_iovec(snd_pcm_plug_t *plug,
const struct iovec *vector, unsigned long count, const struct iovec *vector, unsigned long count,
snd_pcm_plugin_channel_t **channels);
ssize_t snd_pcm_plug_client_channels_buf(snd_pcm_plug_t *plug,
char *buf, size_t count,
snd_pcm_plugin_channel_t **channels); snd_pcm_plugin_channel_t **channels);
ssize_t snd_pcm_plug_client_channels_buf(snd_pcm_plugin_handle_t *handle, int stream,
char *buf, size_t count,
snd_pcm_plugin_channel_t **channels);
int snd_pcm_plug_playback_channels_mask(snd_pcm_plugin_handle_t *handle, int snd_pcm_plug_playback_channels_mask(snd_pcm_plug_t *plug,
bitset_t *client_vmask); bitset_t *client_vmask);
int snd_pcm_plug_capture_channels_mask(snd_pcm_plugin_handle_t *handle, int snd_pcm_plug_capture_channels_mask(snd_pcm_plug_t *plug,
bitset_t *client_vmask); bitset_t *client_vmask);
int snd_pcm_plugin_client_channels(snd_pcm_plugin_t *plugin, int snd_pcm_plugin_client_channels(snd_pcm_plugin_t *plugin,
size_t frames, size_t frames,
snd_pcm_plugin_channel_t **channels); snd_pcm_plugin_channel_t **channels);
void *snd_pcm_plug_buf_alloc(snd_pcm_t *pcm, int stream, size_t size); void *snd_pcm_plug_buf_alloc(snd_pcm_plug_t *plug, size_t size);
void snd_pcm_plug_buf_unlock(snd_pcm_t *pcm, int stream, void *ptr); void snd_pcm_plug_buf_unlock(snd_pcm_plug_t *pcm, void *ptr);
#define ROUTE_PLUGIN_RESOLUTION 16 #define ROUTE_PLUGIN_RESOLUTION 16
@ -133,7 +121,7 @@ int conv_index(int src_format, int dst_format);
#define pdprintf( args... ) { ; } #define pdprintf( args... ) { ; }
#endif #endif
static inline size_t snd_pcm_mmap_playback_frames_avail(snd_pcm_stream_t *str) static inline size_t snd_pcm_mmap_playback_frames_avail(snd_pcm_t *str)
{ {
ssize_t frames_avail; ssize_t frames_avail;
frames_avail = str->mmap_status->frame_io + str->setup.buffer_size - str->mmap_control->frame_data; frames_avail = str->mmap_status->frame_io + str->setup.buffer_size - str->mmap_control->frame_data;
@ -142,7 +130,7 @@ static inline size_t snd_pcm_mmap_playback_frames_avail(snd_pcm_stream_t *str)
return frames_avail; return frames_avail;
} }
static inline size_t snd_pcm_mmap_capture_frames_avail(snd_pcm_stream_t *str) static inline size_t snd_pcm_mmap_capture_frames_avail(snd_pcm_t *str)
{ {
ssize_t frames_avail; ssize_t frames_avail;
frames_avail = str->mmap_status->frame_io - str->mmap_control->frame_data; frames_avail = str->mmap_status->frame_io - str->mmap_control->frame_data;
@ -151,3 +139,4 @@ static inline size_t snd_pcm_mmap_capture_frames_avail(snd_pcm_stream_t *str)
return frames_avail; return frames_avail;
} }
#define snd_pcm_plug_stream(plug) ((plug)->handle->stream)

View file

@ -25,145 +25,119 @@
#include <sys/uio.h> #include <sys/uio.h>
#include "pcm_local.h" #include "pcm_local.h"
int snd_pcm_frames_avail(snd_pcm_t *pcm, int stream, ssize_t *frames) int snd_pcm_frames_avail(snd_pcm_t *handle, ssize_t *frames)
{ {
snd_pcm_stream_t *str; assert(handle);
assert(pcm); assert(handle->mmap_status && handle->mmap_control);
assert(stream >= 0 && stream <= 1); if (handle->stream == SND_PCM_STREAM_PLAYBACK)
str = &pcm->stream[stream]; *frames = snd_pcm_mmap_playback_frames_avail(handle);
assert(str->mmap_status && str->mmap_control);
if (stream == SND_PCM_STREAM_PLAYBACK)
*frames = snd_pcm_mmap_playback_frames_avail(str);
else else
*frames = snd_pcm_mmap_capture_frames_avail(str); *frames = snd_pcm_mmap_capture_frames_avail(handle);
return 0; return 0;
} }
static int snd_pcm_mmap_playback_ready(snd_pcm_t *pcm) static int snd_pcm_mmap_playback_ready(snd_pcm_t *handle)
{ {
snd_pcm_stream_t *str; if (handle->mmap_status->state == SND_PCM_STATE_XRUN)
str = &pcm->stream[SND_PCM_STREAM_PLAYBACK];
if (str->mmap_status->state == SND_PCM_STATE_XRUN)
return -EPIPE; return -EPIPE;
return snd_pcm_mmap_playback_frames_avail(str) >= str->setup.frames_min; return snd_pcm_mmap_playback_frames_avail(handle) >= handle->setup.frames_min;
} }
static int snd_pcm_mmap_capture_ready(snd_pcm_t *pcm) static int snd_pcm_mmap_capture_ready(snd_pcm_t *handle)
{ {
snd_pcm_stream_t *str;
int ret = 0; int ret = 0;
str = &pcm->stream[SND_PCM_STREAM_CAPTURE]; if (handle->mmap_status->state == SND_PCM_STATE_XRUN) {
if (str->mmap_status->state == SND_PCM_STATE_XRUN) {
ret = -EPIPE; ret = -EPIPE;
if (str->setup.xrun_mode == SND_PCM_XRUN_DRAIN) if (handle->setup.xrun_mode == SND_PCM_XRUN_DRAIN)
return -EPIPE; return -EPIPE;
} }
if (snd_pcm_mmap_capture_frames_avail(str) >= str->setup.frames_min) if (snd_pcm_mmap_capture_frames_avail(handle) >= handle->setup.frames_min)
return 1; return 1;
return ret; return ret;
} }
int snd_pcm_mmap_ready(snd_pcm_t *pcm, int stream) int snd_pcm_mmap_ready(snd_pcm_t *handle)
{ {
snd_pcm_stream_t *str; assert(handle);
assert(pcm); assert(handle->mmap_status && handle->mmap_control);
assert(stream >= 0 && stream <= 1); assert(handle->mmap_status->state >= SND_PCM_STATE_PREPARED);
str = &pcm->stream[stream]; if (handle->stream == SND_PCM_STREAM_PLAYBACK) {
assert(str->mmap_status && str->mmap_control); return snd_pcm_mmap_playback_ready(handle);
assert(str->mmap_status->state >= SND_PCM_STATE_PREPARED);
if (stream == SND_PCM_STREAM_PLAYBACK) {
return snd_pcm_mmap_playback_ready(pcm);
} else { } else {
return snd_pcm_mmap_capture_ready(pcm); return snd_pcm_mmap_capture_ready(handle);
} }
} }
static size_t snd_pcm_mmap_playback_frames_xfer(snd_pcm_t *pcm, size_t frames) static size_t snd_pcm_mmap_playback_frames_xfer(snd_pcm_t *handle, size_t frames)
{ {
snd_pcm_stream_t *str = &pcm->stream[SND_PCM_STREAM_PLAYBACK]; snd_pcm_mmap_control_t *control = handle->mmap_control;
snd_pcm_mmap_control_t *control = str->mmap_control;
size_t frames_cont; size_t frames_cont;
size_t frames_avail = snd_pcm_mmap_playback_frames_avail(str); size_t frames_avail = snd_pcm_mmap_playback_frames_avail(handle);
if (frames_avail < frames) if (frames_avail < frames)
frames = frames_avail; frames = frames_avail;
frames_cont = str->setup.buffer_size - control->frame_data % str->setup.buffer_size; frames_cont = handle->setup.buffer_size - control->frame_data % handle->setup.buffer_size;
if (frames_cont < frames) if (frames_cont < frames)
frames = frames_cont; frames = frames_cont;
return frames; return frames;
} }
static size_t snd_pcm_mmap_capture_frames_xfer(snd_pcm_t *pcm, size_t frames) static size_t snd_pcm_mmap_capture_frames_xfer(snd_pcm_t *handle, size_t frames)
{ {
snd_pcm_stream_t *str = &pcm->stream[SND_PCM_STREAM_CAPTURE]; snd_pcm_mmap_control_t *control = handle->mmap_control;
snd_pcm_mmap_control_t *control = str->mmap_control;
size_t frames_cont; size_t frames_cont;
size_t frames_avail = snd_pcm_mmap_capture_frames_avail(str); size_t frames_avail = snd_pcm_mmap_capture_frames_avail(handle);
if (frames_avail < frames) if (frames_avail < frames)
frames = frames_avail; frames = frames_avail;
frames_cont = str->setup.buffer_size - control->frame_data % str->setup.buffer_size; frames_cont = handle->setup.buffer_size - control->frame_data % handle->setup.buffer_size;
if (frames_cont < frames) if (frames_cont < frames)
frames = frames_cont; frames = frames_cont;
return frames; return frames;
} }
ssize_t snd_pcm_mmap_frames_xfer(snd_pcm_t *pcm, int stream, size_t frames) ssize_t snd_pcm_mmap_frames_xfer(snd_pcm_t *handle, size_t frames)
{ {
snd_pcm_stream_t *str; assert(handle);
assert(pcm); assert(handle->mmap_status && handle->mmap_control);
assert(stream >= 0 && stream <= 1); if (handle->stream == SND_PCM_STREAM_PLAYBACK)
str = &pcm->stream[stream]; return snd_pcm_mmap_playback_frames_xfer(handle, frames);
assert(str->mmap_status && str->mmap_control);
if (stream == SND_PCM_STREAM_PLAYBACK)
return snd_pcm_mmap_playback_frames_xfer(pcm, frames);
else else
return snd_pcm_mmap_capture_frames_xfer(pcm, frames); return snd_pcm_mmap_capture_frames_xfer(handle, frames);
} }
ssize_t snd_pcm_mmap_frames_offset(snd_pcm_t *pcm, int stream) ssize_t snd_pcm_mmap_frames_offset(snd_pcm_t *handle)
{ {
snd_pcm_stream_t *str; assert(handle);
assert(pcm); assert(handle->mmap_control);
assert(stream >= 0 && stream <= 1); return handle->mmap_control->frame_data % handle->setup.buffer_size;
str = &pcm->stream[stream];
assert(str->mmap_control);
return str->mmap_control->frame_data % str->setup.buffer_size;
} }
int snd_pcm_mmap_stream_state(snd_pcm_t *pcm, int stream) int snd_pcm_mmap_state(snd_pcm_t *handle)
{ {
snd_pcm_stream_t *str; assert(handle);
assert(pcm); assert(handle->mmap_status);
assert(stream >= 0 && stream <= 1); return handle->mmap_status->state;
str = &pcm->stream[stream];
assert(str->mmap_status);
return str->mmap_status->state;
} }
int snd_pcm_mmap_stream_frame_io(snd_pcm_t *pcm, int stream) int snd_pcm_mmap_frame_io(snd_pcm_t *handle)
{ {
snd_pcm_stream_t *str; assert(handle);
assert(pcm); assert(handle->mmap_status);
assert(stream >= 0 && stream <= 1); return handle->mmap_status->frame_io;
str = &pcm->stream[stream];
assert(str->mmap_status);
return str->mmap_status->frame_io;
} }
ssize_t snd_pcm_mmap_stream_frame_data(snd_pcm_t *pcm, int stream, off_t offset) ssize_t snd_pcm_mmap_frame_data(snd_pcm_t *handle, off_t offset)
{ {
snd_pcm_stream_t *str;
ssize_t frame_data; ssize_t frame_data;
assert(pcm); assert(handle);
assert(stream >= 0 && stream <= 1); assert(handle->mmap_status && handle->mmap_control);
str = &pcm->stream[stream]; assert(offset == 0 || handle->type == SND_PCM_TYPE_HW);
assert(str->mmap_status && str->mmap_control); frame_data = handle->mmap_control->frame_data;
frame_data = str->mmap_control->frame_data;
if (offset == 0) if (offset == 0)
return frame_data; return frame_data;
switch (str->mmap_status->state) { switch (handle->mmap_status->state) {
case SND_PCM_STATE_RUNNING: case SND_PCM_STATE_RUNNING:
if (str->setup.mode == SND_PCM_MODE_FRAME) if (handle->setup.mode == SND_PCM_MODE_FRAME)
snd_pcm_stream_frame_io(pcm, stream, 1); snd_pcm_frame_io(handle, 1);
break; break;
case SND_PCM_STATE_PREPARED: case SND_PCM_STATE_PREPARED:
break; break;
@ -171,85 +145,83 @@ ssize_t snd_pcm_mmap_stream_frame_data(snd_pcm_t *pcm, int stream, off_t offset)
return -EBADFD; return -EBADFD;
} }
if (offset < 0) { if (offset < 0) {
if (offset < -(ssize_t)str->setup.buffer_size) if (offset < -(ssize_t)handle->setup.buffer_size)
offset = -(ssize_t)str->setup.buffer_size; offset = -(ssize_t)handle->setup.buffer_size;
else else
offset -= offset % str->setup.frames_align; offset -= offset % handle->setup.frames_align;
frame_data += offset; frame_data += offset;
if (frame_data < 0) if (frame_data < 0)
frame_data += str->setup.frame_boundary; frame_data += handle->setup.frame_boundary;
} else { } else {
size_t frames_avail; size_t frames_avail;
if (stream == SND_PCM_STREAM_PLAYBACK) if (handle->stream == SND_PCM_STREAM_PLAYBACK)
frames_avail = snd_pcm_mmap_playback_frames_avail(str); frames_avail = snd_pcm_mmap_playback_frames_avail(handle);
else else
frames_avail = snd_pcm_mmap_capture_frames_avail(str); frames_avail = snd_pcm_mmap_capture_frames_avail(handle);
if ((size_t)offset > frames_avail) if ((size_t)offset > frames_avail)
offset = frames_avail; offset = frames_avail;
offset -= offset % str->setup.frames_align; offset -= offset % handle->setup.frames_align;
frame_data += offset; frame_data += offset;
if ((size_t)frame_data >= str->setup.frame_boundary) if ((size_t)frame_data >= handle->setup.frame_boundary)
frame_data -= str->setup.frame_boundary; frame_data -= handle->setup.frame_boundary;
} }
str->mmap_control->frame_data = frame_data; handle->mmap_control->frame_data = frame_data;
return frame_data; return frame_data;
} }
ssize_t snd_pcm_mmap_write_areas(snd_pcm_t *pcm, snd_pcm_channel_area_t *channels, size_t frames) ssize_t snd_pcm_mmap_write_areas(snd_pcm_t *handle, snd_pcm_channel_area_t *channels, size_t frames)
{ {
snd_pcm_stream_t *str;
snd_pcm_mmap_status_t *status; snd_pcm_mmap_status_t *status;
size_t offset = 0; size_t offset = 0;
size_t result = 0; size_t result = 0;
int err; int err;
str = &pcm->stream[SND_PCM_STREAM_PLAYBACK]; assert(handle->mmap_data && handle->mmap_status && handle->mmap_control);
assert(str->mmap_data && str->mmap_status && str->mmap_control); status = handle->mmap_status;
status = str->mmap_status;
assert(status->state >= SND_PCM_STATE_PREPARED); assert(status->state >= SND_PCM_STATE_PREPARED);
if (str->setup.mode == SND_PCM_MODE_FRAGMENT) { if (handle->setup.mode == SND_PCM_MODE_FRAGMENT) {
assert(frames % str->setup.frag_size == 0); assert(frames % handle->setup.frag_size == 0);
} else { } else {
if (status->state == SND_PCM_STATE_RUNNING && if (status->state == SND_PCM_STATE_RUNNING &&
str->mode & SND_PCM_NONBLOCK) handle->mode & SND_PCM_NONBLOCK)
snd_pcm_stream_frame_io(pcm, SND_PCM_STREAM_PLAYBACK, 1); snd_pcm_frame_io(handle, 1);
} }
while (frames > 0) { while (frames > 0) {
ssize_t mmap_offset; ssize_t mmap_offset;
size_t frames1; size_t frames1;
int ready = snd_pcm_mmap_playback_ready(pcm); int ready = snd_pcm_mmap_playback_ready(handle);
if (ready < 0) if (ready < 0)
return ready; return ready;
if (!ready) { if (!ready) {
struct pollfd pfd; struct pollfd pfd;
if (status->state != SND_PCM_STATE_RUNNING) if (status->state != SND_PCM_STATE_RUNNING)
return result > 0 ? result : -EPIPE; return result > 0 ? result : -EPIPE;
if (str->mode & SND_PCM_NONBLOCK) if (handle->mode & SND_PCM_NONBLOCK)
return result > 0 ? result : -EAGAIN; return result > 0 ? result : -EAGAIN;
pfd.fd = snd_pcm_file_descriptor(pcm, SND_PCM_STREAM_PLAYBACK); pfd.fd = snd_pcm_file_descriptor(handle);
pfd.events = POLLOUT | POLLERR; pfd.events = POLLOUT | POLLERR;
ready = poll(&pfd, 1, 10000); ready = poll(&pfd, 1, 10000);
if (ready < 0) if (ready < 0)
return result > 0 ? result : ready; return result > 0 ? result : ready;
if (ready && pfd.revents & POLLERR) if (ready && pfd.revents & POLLERR)
return result > 0 ? result : -EPIPE; return result > 0 ? result : -EPIPE;
assert(snd_pcm_mmap_playback_ready(pcm)); assert(snd_pcm_mmap_playback_ready(handle));
} }
frames1 = snd_pcm_mmap_playback_frames_xfer(pcm, frames); frames1 = snd_pcm_mmap_playback_frames_xfer(handle, frames);
assert(frames1 > 0); assert(frames1 > 0);
mmap_offset = snd_pcm_mmap_frames_offset(pcm, SND_PCM_STREAM_PLAYBACK); mmap_offset = snd_pcm_mmap_frames_offset(handle);
snd_pcm_areas_copy(channels, offset, str->channels, mmap_offset, str->setup.format.channels, frames1, str->setup.format.format); snd_pcm_areas_copy(channels, offset, handle->channels, mmap_offset, handle->setup.format.channels, frames1, handle->setup.format.format);
if (status->state == SND_PCM_STATE_XRUN) if (status->state == SND_PCM_STATE_XRUN)
return result > 0 ? result : -EPIPE; return result > 0 ? result : -EPIPE;
snd_pcm_stream_frame_data(pcm, SND_PCM_STREAM_PLAYBACK, frames1); snd_pcm_frame_data(handle, frames1);
frames -= frames1; frames -= frames1;
offset += frames1; offset += frames1;
result += frames1; result += frames1;
if (status->state == SND_PCM_STATE_PREPARED && if (status->state == SND_PCM_STATE_PREPARED &&
(str->setup.start_mode == SND_PCM_START_DATA || (handle->setup.start_mode == SND_PCM_START_DATA ||
(str->setup.start_mode == SND_PCM_START_FULL && (handle->setup.start_mode == SND_PCM_START_FULL &&
!snd_pcm_mmap_playback_ready(pcm)))) { !snd_pcm_mmap_playback_ready(handle)))) {
err = snd_pcm_stream_go(pcm, SND_PCM_STREAM_PLAYBACK); err = snd_pcm_go(handle);
if (err < 0) if (err < 0)
return result > 0 ? result : err; return result > 0 ? result : err;
} }
@ -257,44 +229,40 @@ ssize_t snd_pcm_mmap_write_areas(snd_pcm_t *pcm, snd_pcm_channel_area_t *channel
return result; return result;
} }
ssize_t snd_pcm_mmap_write(snd_pcm_t *pcm, const void *buffer, size_t frames) ssize_t snd_pcm_mmap_write(snd_pcm_t *handle, const void *buffer, size_t frames)
{ {
snd_pcm_stream_t *str;
unsigned int nchannels; unsigned int nchannels;
assert(pcm); assert(handle);
str = &pcm->stream[SND_PCM_STREAM_PLAYBACK]; assert(handle->mmap_data && handle->mmap_status && handle->mmap_control);
assert(str->mmap_data && str->mmap_status && str->mmap_control);
assert(frames == 0 || buffer); assert(frames == 0 || buffer);
nchannels = str->setup.format.channels; nchannels = handle->setup.format.channels;
assert(str->setup.format.interleave || nchannels == 1); assert(handle->setup.format.interleave || nchannels == 1);
{ {
snd_pcm_channel_area_t channels[nchannels]; snd_pcm_channel_area_t channels[nchannels];
unsigned int channel; unsigned int channel;
for (channel = 0; channel < nchannels; ++channel) { for (channel = 0; channel < nchannels; ++channel) {
channels[channel].addr = (char*)buffer; channels[channel].addr = (char*)buffer;
channels[channel].first = str->bits_per_sample * channel; channels[channel].first = handle->bits_per_sample * channel;
channels[channel].step = str->bits_per_frame; channels[channel].step = handle->bits_per_frame;
} }
return snd_pcm_mmap_write_areas(pcm, channels, frames); return snd_pcm_mmap_write_areas(handle, channels, frames);
} }
} }
ssize_t snd_pcm_mmap_writev(snd_pcm_t *pcm, const struct iovec *vector, unsigned long vcount) ssize_t snd_pcm_mmap_writev(snd_pcm_t *handle, const struct iovec *vector, unsigned long vcount)
{ {
snd_pcm_stream_t *str;
size_t result = 0; size_t result = 0;
unsigned int nchannels; unsigned int nchannels;
assert(pcm); assert(handle);
str = &pcm->stream[SND_PCM_STREAM_PLAYBACK]; assert(handle->mmap_data && handle->mmap_status && handle->mmap_control);
assert(str->mmap_data && str->mmap_status && str->mmap_control);
assert(vcount == 0 || vector); assert(vcount == 0 || vector);
nchannels = str->setup.format.channels; nchannels = handle->setup.format.channels;
if (str->setup.format.interleave) { if (handle->setup.format.interleave) {
unsigned int b; unsigned int b;
for (b = 0; b < vcount; b++) { for (b = 0; b < vcount; b++) {
ssize_t ret; ssize_t ret;
size_t frames = vector[b].iov_len; size_t frames = vector[b].iov_len;
ret = snd_pcm_mmap_write(pcm, vector[b].iov_base, frames); ret = snd_pcm_mmap_write(handle, vector[b].iov_base, frames);
if (ret < 0) { if (ret < 0) {
if (result <= 0) if (result <= 0)
return ret; return ret;
@ -316,9 +284,9 @@ ssize_t snd_pcm_mmap_writev(snd_pcm_t *pcm, const struct iovec *vector, unsigned
assert(vector[v].iov_len == frames); assert(vector[v].iov_len == frames);
channels[v].addr = vector[v].iov_base; channels[v].addr = vector[v].iov_base;
channels[v].first = 0; channels[v].first = 0;
channels[v].step = str->bits_per_sample; channels[v].step = handle->bits_per_sample;
} }
ret = snd_pcm_mmap_write_areas(pcm, channels, frames); ret = snd_pcm_mmap_write_areas(handle, channels, frames);
if (ret < 0) { if (ret < 0) {
if (result <= 0) if (result <= 0)
return ret; return ret;
@ -333,60 +301,58 @@ ssize_t snd_pcm_mmap_writev(snd_pcm_t *pcm, const struct iovec *vector, unsigned
return result; return result;
} }
ssize_t snd_pcm_mmap_read_areas(snd_pcm_t *pcm, snd_pcm_channel_area_t *channels, size_t frames) ssize_t snd_pcm_mmap_read_areas(snd_pcm_t *handle, snd_pcm_channel_area_t *channels, size_t frames)
{ {
snd_pcm_stream_t *str;
snd_pcm_mmap_status_t *status; snd_pcm_mmap_status_t *status;
size_t offset = 0; size_t offset = 0;
size_t result = 0; size_t result = 0;
int err; int err;
str = &pcm->stream[SND_PCM_STREAM_CAPTURE]; assert(handle->mmap_data && handle->mmap_status && handle->mmap_control);
assert(str->mmap_data && str->mmap_status && str->mmap_control); status = handle->mmap_status;
status = str->mmap_status;
assert(status->state >= SND_PCM_STATE_PREPARED); assert(status->state >= SND_PCM_STATE_PREPARED);
if (str->setup.mode == SND_PCM_MODE_FRAGMENT) { if (handle->setup.mode == SND_PCM_MODE_FRAGMENT) {
assert(frames % str->setup.frag_size == 0); assert(frames % handle->setup.frag_size == 0);
} else { } else {
if (status->state == SND_PCM_STATE_RUNNING && if (status->state == SND_PCM_STATE_RUNNING &&
str->mode & SND_PCM_NONBLOCK) handle->mode & SND_PCM_NONBLOCK)
snd_pcm_stream_frame_io(pcm, SND_PCM_STREAM_CAPTURE, 1); snd_pcm_frame_io(handle, 1);
} }
if (status->state == SND_PCM_STATE_PREPARED && if (status->state == SND_PCM_STATE_PREPARED &&
str->setup.start_mode == SND_PCM_START_DATA) { handle->setup.start_mode == SND_PCM_START_DATA) {
err = snd_pcm_stream_go(pcm, SND_PCM_STREAM_CAPTURE); err = snd_pcm_go(handle);
if (err < 0) if (err < 0)
return err; return err;
} }
while (frames > 0) { while (frames > 0) {
ssize_t mmap_offset; ssize_t mmap_offset;
size_t frames1; size_t frames1;
int ready = snd_pcm_mmap_capture_ready(pcm); int ready = snd_pcm_mmap_capture_ready(handle);
if (ready < 0) if (ready < 0)
return ready; return ready;
if (!ready) { if (!ready) {
struct pollfd pfd; struct pollfd pfd;
if (status->state != SND_PCM_STATE_RUNNING) if (status->state != SND_PCM_STATE_RUNNING)
return result > 0 ? result : -EPIPE; return result > 0 ? result : -EPIPE;
if (str->mode & SND_PCM_NONBLOCK) if (handle->mode & SND_PCM_NONBLOCK)
return result > 0 ? result : -EAGAIN; return result > 0 ? result : -EAGAIN;
pfd.fd = snd_pcm_file_descriptor(pcm, SND_PCM_STREAM_CAPTURE); pfd.fd = snd_pcm_file_descriptor(handle);
pfd.events = POLLIN | POLLERR; pfd.events = POLLIN | POLLERR;
ready = poll(&pfd, 1, 10000); ready = poll(&pfd, 1, 10000);
if (ready < 0) if (ready < 0)
return result > 0 ? result : ready; return result > 0 ? result : ready;
if (ready && pfd.revents & POLLERR) if (ready && pfd.revents & POLLERR)
return result > 0 ? result : -EPIPE; return result > 0 ? result : -EPIPE;
assert(snd_pcm_mmap_capture_ready(pcm)); assert(snd_pcm_mmap_capture_ready(handle));
} }
frames1 = snd_pcm_mmap_capture_frames_xfer(pcm, frames); frames1 = snd_pcm_mmap_capture_frames_xfer(handle, frames);
assert(frames1 > 0); assert(frames1 > 0);
mmap_offset = snd_pcm_mmap_frames_offset(pcm, SND_PCM_STREAM_CAPTURE); mmap_offset = snd_pcm_mmap_frames_offset(handle);
snd_pcm_areas_copy(str->channels, mmap_offset, channels, offset, str->setup.format.channels, frames1, str->setup.format.format); snd_pcm_areas_copy(handle->channels, mmap_offset, channels, offset, handle->setup.format.channels, frames1, handle->setup.format.format);
if (status->state == SND_PCM_STATE_XRUN && if (status->state == SND_PCM_STATE_XRUN &&
str->setup.xrun_mode == SND_PCM_XRUN_DRAIN) handle->setup.xrun_mode == SND_PCM_XRUN_DRAIN)
return result > 0 ? result : -EPIPE; return result > 0 ? result : -EPIPE;
snd_pcm_stream_frame_data(pcm, SND_PCM_STREAM_CAPTURE, frames1); snd_pcm_frame_data(handle, frames1);
frames -= frames1; frames -= frames1;
offset += frames1; offset += frames1;
result += frames1; result += frames1;
@ -394,44 +360,40 @@ ssize_t snd_pcm_mmap_read_areas(snd_pcm_t *pcm, snd_pcm_channel_area_t *channels
return result; return result;
} }
ssize_t snd_pcm_mmap_read(snd_pcm_t *pcm, void *buffer, size_t frames) ssize_t snd_pcm_mmap_read(snd_pcm_t *handle, void *buffer, size_t frames)
{ {
snd_pcm_stream_t *str;
unsigned int nchannels; unsigned int nchannels;
assert(pcm); assert(handle);
str = &pcm->stream[SND_PCM_STREAM_CAPTURE]; assert(handle->mmap_data && handle->mmap_status && handle->mmap_control);
assert(str->mmap_data && str->mmap_status && str->mmap_control);
assert(frames == 0 || buffer); assert(frames == 0 || buffer);
nchannels = str->setup.format.channels; nchannels = handle->setup.format.channels;
assert(str->setup.format.interleave || nchannels == 1); assert(handle->setup.format.interleave || nchannels == 1);
{ {
snd_pcm_channel_area_t channels[nchannels]; snd_pcm_channel_area_t channels[nchannels];
unsigned int channel; unsigned int channel;
for (channel = 0; channel < nchannels; ++channel) { for (channel = 0; channel < nchannels; ++channel) {
channels[channel].addr = (char*)buffer; channels[channel].addr = (char*)buffer;
channels[channel].first = str->bits_per_sample * channel; channels[channel].first = handle->bits_per_sample * channel;
channels[channel].step = str->bits_per_frame; channels[channel].step = handle->bits_per_frame;
} }
return snd_pcm_mmap_read_areas(pcm, channels, frames); return snd_pcm_mmap_read_areas(handle, channels, frames);
} }
} }
ssize_t snd_pcm_mmap_readv(snd_pcm_t *pcm, const struct iovec *vector, unsigned long vcount) ssize_t snd_pcm_mmap_readv(snd_pcm_t *handle, const struct iovec *vector, unsigned long vcount)
{ {
snd_pcm_stream_t *str;
size_t result = 0; size_t result = 0;
unsigned int nchannels; unsigned int nchannels;
assert(pcm); assert(handle);
str = &pcm->stream[SND_PCM_STREAM_CAPTURE]; assert(handle->mmap_data && handle->mmap_status && handle->mmap_control);
assert(str->mmap_data && str->mmap_status && str->mmap_control);
assert(vcount == 0 || vector); assert(vcount == 0 || vector);
nchannels = str->setup.format.channels; nchannels = handle->setup.format.channels;
if (str->setup.format.interleave) { if (handle->setup.format.interleave) {
unsigned int b; unsigned int b;
for (b = 0; b < vcount; b++) { for (b = 0; b < vcount; b++) {
ssize_t ret; ssize_t ret;
size_t frames = vector[b].iov_len; size_t frames = vector[b].iov_len;
ret = snd_pcm_mmap_read(pcm, vector[b].iov_base, frames); ret = snd_pcm_mmap_read(handle, vector[b].iov_base, frames);
if (ret < 0) { if (ret < 0) {
if (result <= 0) if (result <= 0)
return ret; return ret;
@ -453,9 +415,9 @@ ssize_t snd_pcm_mmap_readv(snd_pcm_t *pcm, const struct iovec *vector, unsigned
assert(vector[v].iov_len == frames); assert(vector[v].iov_len == frames);
channels[v].addr = vector[v].iov_base; channels[v].addr = vector[v].iov_base;
channels[v].first = 0; channels[v].first = 0;
channels[v].step = str->bits_per_sample; channels[v].step = handle->bits_per_sample;
} }
ret = snd_pcm_mmap_read_areas(pcm, channels, frames); ret = snd_pcm_mmap_read_areas(handle, channels, frames);
if (ret < 0) { if (ret < 0) {
if (result <= 0) if (result <= 0)
return ret; return ret;
@ -470,64 +432,55 @@ ssize_t snd_pcm_mmap_readv(snd_pcm_t *pcm, const struct iovec *vector, unsigned
return result; return result;
} }
int snd_pcm_mmap_status(snd_pcm_t *pcm, int stream, snd_pcm_mmap_status_t **status) int snd_pcm_mmap_status(snd_pcm_t *handle, snd_pcm_mmap_status_t **status)
{ {
snd_pcm_stream_t *str;
int err; int err;
assert(pcm); assert(handle);
assert(stream >= 0 && stream <= 1); assert(handle->valid_setup);
str = &pcm->stream[stream]; if (handle->mmap_status) {
assert(str->valid_setup);
if (str->mmap_status) {
if (status) if (status)
*status = str->mmap_status; *status = handle->mmap_status;
return 0; return 0;
} }
if ((err = pcm->ops->mmap_status(pcm, stream, &str->mmap_status)) < 0) if ((err = handle->ops->mmap_status(handle->op_arg, &handle->mmap_status)) < 0)
return err; return err;
if (status) if (status)
*status = str->mmap_status; *status = handle->mmap_status;
return 0; return 0;
} }
int snd_pcm_mmap_control(snd_pcm_t *pcm, int stream, snd_pcm_mmap_control_t **control) int snd_pcm_mmap_control(snd_pcm_t *handle, snd_pcm_mmap_control_t **control)
{ {
snd_pcm_stream_t *str;
int err; int err;
assert(pcm); assert(handle);
assert(stream >= 0 && stream <= 1); assert(handle->valid_setup);
str = &pcm->stream[stream]; if (handle->mmap_control) {
assert(str->valid_setup);
if (str->mmap_control) {
if (control) if (control)
*control = str->mmap_control; *control = handle->mmap_control;
return 0; return 0;
} }
if ((err = pcm->ops->mmap_control(pcm, stream, &str->mmap_control)) < 0) if ((err = handle->ops->mmap_control(handle->op_arg, &handle->mmap_control)) < 0)
return err; return err;
if (control) if (control)
*control = str->mmap_control; *control = handle->mmap_control;
return 0; return 0;
} }
int snd_pcm_mmap_get_areas(snd_pcm_t *pcm, int stream, snd_pcm_channel_area_t *areas) int snd_pcm_mmap_get_areas(snd_pcm_t *handle, snd_pcm_channel_area_t *areas)
{ {
snd_pcm_stream_t *str;
snd_pcm_channel_setup_t s; snd_pcm_channel_setup_t s;
snd_pcm_channel_area_t *a, *ap; snd_pcm_channel_area_t *a, *ap;
unsigned int channel; unsigned int channel;
int interleaved = 1, noninterleaved = 1; int interleaved = 1, noninterleaved = 1;
int err; int err;
assert(pcm); assert(handle);
assert(stream >= 0 && stream <= 1); assert(handle->mmap_data);
str = &pcm->stream[stream]; a = calloc(handle->setup.format.channels, sizeof(*areas));
assert(str->mmap_data); for (channel = 0, ap = a; channel < handle->setup.format.channels; ++channel, ++ap) {
a = calloc(str->setup.format.channels, sizeof(*areas));
for (channel = 0, ap = a; channel < str->setup.format.channels; ++channel, ++ap) {
s.channel = channel; s.channel = channel;
err = snd_pcm_channel_setup(pcm, stream, &s); err = snd_pcm_channel_setup(handle, &s);
if (err < 0) { if (err < 0) {
free(a); free(a);
return err; return err;
@ -535,131 +488,118 @@ int snd_pcm_mmap_get_areas(snd_pcm_t *pcm, int stream, snd_pcm_channel_area_t *a
if (areas) if (areas)
areas[channel] = s.area; areas[channel] = s.area;
*ap = s.area; *ap = s.area;
if (ap->step != str->bits_per_sample || ap->first != 0) if (ap->step != handle->bits_per_sample || ap->first != 0)
noninterleaved = 0; noninterleaved = 0;
if (ap->addr != a[0].addr || if (ap->addr != a[0].addr ||
ap->step != str->bits_per_frame || ap->step != handle->bits_per_frame ||
ap->first != channel * str->bits_per_sample) ap->first != channel * handle->bits_per_sample)
interleaved = 0; interleaved = 0;
} }
if (noninterleaved) if (noninterleaved)
str->mmap_type = _NONINTERLEAVED; handle->mmap_type = _NONINTERLEAVED;
else if (interleaved) else if (interleaved)
str->mmap_type = _INTERLEAVED; handle->mmap_type = _INTERLEAVED;
else else
str->mmap_type = _COMPLEX; handle->mmap_type = _COMPLEX;
str->channels = a; handle->channels = a;
return 0; return 0;
} }
int snd_pcm_mmap_data(snd_pcm_t *pcm, int stream, void **data) int snd_pcm_mmap_data(snd_pcm_t *handle, void **data)
{ {
snd_pcm_stream_t *str; snd_pcm_info_t info;
snd_pcm_stream_info_t info;
size_t bsize; size_t bsize;
int err; int err;
assert(pcm); assert(handle);
assert(stream >= 0 && stream <= 1); assert(handle->valid_setup);
str = &pcm->stream[stream]; if (handle->mmap_data) {
assert(str->valid_setup);
if (str->mmap_data) {
if (data) if (data)
*data = str->mmap_data; *data = handle->mmap_data;
return 0; return 0;
} }
info.stream = stream; err = snd_pcm_info(handle, &info);
err = snd_pcm_stream_info(pcm, &info);
if (err < 0) if (err < 0)
return err; return err;
bsize = info.mmap_size; bsize = info.mmap_size;
if (!(info.flags & SND_PCM_STREAM_INFO_MMAP)) if (!(info.flags & SND_PCM_INFO_MMAP))
return -ENXIO; return -ENXIO;
if ((err = pcm->ops->mmap_data(pcm, stream, (void**)&str->mmap_data, bsize)) < 0) if ((err = handle->ops->mmap_data(handle->op_arg, (void**)&handle->mmap_data, bsize)) < 0)
return err; return err;
if (data) if (data)
*data = str->mmap_data; *data = handle->mmap_data;
str->mmap_data_size = bsize; handle->mmap_data_size = bsize;
err = snd_pcm_mmap_get_areas(pcm, stream, NULL); err = snd_pcm_mmap_get_areas(handle, NULL);
if (err < 0) if (err < 0)
return err; return err;
return 0; return 0;
} }
int snd_pcm_mmap(snd_pcm_t *pcm, int stream, snd_pcm_mmap_status_t **status, snd_pcm_mmap_control_t **control, void **data) int snd_pcm_mmap(snd_pcm_t *handle, snd_pcm_mmap_status_t **status, snd_pcm_mmap_control_t **control, void **data)
{ {
int err; int err;
err = snd_pcm_mmap_status(pcm, stream, status); err = snd_pcm_mmap_status(handle, status);
if (err < 0) if (err < 0)
return err; return err;
err = snd_pcm_mmap_control(pcm, stream, control); err = snd_pcm_mmap_control(handle, control);
if (err < 0) { if (err < 0) {
snd_pcm_munmap_status(pcm, stream); snd_pcm_munmap_status(handle);
return err; return err;
} }
err = snd_pcm_mmap_data(pcm, stream, data); err = snd_pcm_mmap_data(handle, data);
if (err < 0) { if (err < 0) {
snd_pcm_munmap_status(pcm, stream); snd_pcm_munmap_status(handle);
snd_pcm_munmap_control(pcm, stream); snd_pcm_munmap_control(handle);
return err; return err;
} }
return 0; return 0;
} }
int snd_pcm_munmap_status(snd_pcm_t *pcm, int stream) int snd_pcm_munmap_status(snd_pcm_t *handle)
{ {
int err; int err;
snd_pcm_stream_t *str; assert(handle);
assert(pcm); assert(handle->mmap_status);
assert(stream >= 0 && stream <= 1); if ((err = handle->ops->munmap_status(handle->op_arg, handle->mmap_status)) < 0)
str = &pcm->stream[stream];
assert(str->mmap_status);
if ((err = pcm->ops->munmap_status(pcm, stream, str->mmap_status)) < 0)
return err; return err;
str->mmap_status = 0; handle->mmap_status = 0;
return 0; return 0;
} }
int snd_pcm_munmap_control(snd_pcm_t *pcm, int stream) int snd_pcm_munmap_control(snd_pcm_t *handle)
{ {
int err; int err;
snd_pcm_stream_t *str; assert(handle);
assert(pcm); assert(handle->mmap_control);
assert(stream >= 0 && stream <= 1); if ((err = handle->ops->munmap_control(handle->op_arg, handle->mmap_control)) < 0)
str = &pcm->stream[stream];
assert(str->mmap_control);
if ((err = pcm->ops->munmap_control(pcm, stream, str->mmap_control)) < 0)
return err; return err;
str->mmap_control = 0; handle->mmap_control = 0;
return 0; return 0;
} }
int snd_pcm_munmap_data(snd_pcm_t *pcm, int stream) int snd_pcm_munmap_data(snd_pcm_t *handle)
{ {
int err; int err;
snd_pcm_stream_t *str; assert(handle);
assert(pcm); assert(handle->mmap_data);
assert(stream >= 0 && stream <= 1); if ((err = handle->ops->munmap_data(handle->op_arg, handle->mmap_data, handle->mmap_data_size)) < 0)
str = &pcm->stream[stream];
assert(str->mmap_data);
if ((err = pcm->ops->munmap_data(pcm, stream, str->mmap_data, str->mmap_data_size)) < 0)
return err; return err;
free(str->channels); free(handle->channels);
str->channels = 0; handle->channels = 0;
str->mmap_data = 0; handle->mmap_data = 0;
str->mmap_data_size = 0; handle->mmap_data_size = 0;
return 0; return 0;
} }
int snd_pcm_munmap(snd_pcm_t *pcm, int stream) int snd_pcm_munmap(snd_pcm_t *handle)
{ {
int err; int err;
err = snd_pcm_munmap_status(pcm, stream); err = snd_pcm_munmap_status(handle);
if (err < 0) if (err < 0)
return err; return err;
err = snd_pcm_munmap_control(pcm, stream); err = snd_pcm_munmap_control(handle);
if (err < 0) if (err < 0)
return err; return err;
return snd_pcm_munmap_data(pcm, stream); return snd_pcm_munmap_data(handle);
} }