]> git.alsa-project.org Git - alsa-lib.git/commitdiff
pcm handle split
authorAbramo Bagnara <abramo@alsa-project.org>
Wed, 21 Jun 2000 14:59:20 +0000 (14:59 +0000)
committerAbramo Bagnara <abramo@alsa-project.org>
Wed, 21 Jun 2000 14:59:20 +0000 (14:59 +0000)
include/pcm.h
src/pcm/pcm.c
src/pcm/pcm_hw.c
src/pcm/pcm_local.h
src/pcm/pcm_mmap.c

index 689cdfd26c185a87055378763e2ea7de0fcb3d8f..0a4a0b360469a209d934a9a9a9a5bf8f50c4ed8b 100644 (file)
@@ -5,12 +5,7 @@
  *                                                                          *
  ****************************************************************************/
 
-#define SND_PCM_OPEN_PLAYBACK          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
+#define SND_PCM_NONBLOCK               0x0001
 
 #ifdef __cplusplus
 extern "C" {
@@ -18,137 +13,152 @@ extern "C" {
 
 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);
 }
 
-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));
 }
        
 static inline void bitset_set(bitset_t *bitmap, unsigned int pos)
 {
-       int bits = sizeof(*bitmap) * 8;
-       bitmap[pos / bits] |= 1 << (pos % bits);
+       size_t bits = sizeof(*bitmap) * 8;
+       bitmap[pos / bits] |= 1U << (pos % bits);
 }
 
 static inline void bitset_reset(bitset_t *bitmap, unsigned int pos)
 {
-       int bits = sizeof(*bitmap) * 8;
-       bitmap[pos / bits] &= ~(1 << (pos % bits));
+       size_t bits = sizeof(*bitmap) * 8;
+       bitmap[pos / bits] &= ~(1U << (pos % bits));
 }
 
 static inline int bitset_get(bitset_t *bitmap, unsigned int pos)
 {
-       int bits = sizeof(*bitmap) * 8;
-       return !!(bitmap[pos / bits] & (1 << (pos % bits)));
+       size_t bits = sizeof(*bitmap) * 8;
+       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));
 }
 
-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);
        while (dst < end)
                *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);
        while (dst < end)
                *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);
        while (dst < end)
                *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);
        while (dst < end)
                *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_loopback snd_pcm_loopback_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_open_subdevice(snd_pcm_t **handle, int card, int device, int subdevice, 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_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);
 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 stream);
-int snd_pcm_stream_nonblock(snd_pcm_t *handle, int stream, int nonblock);
+int snd_pcm_file_descriptor(snd_pcm_t *handle);
+int snd_pcm_nonblock(snd_pcm_t *handle, int nonblock);
 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_stream_params(snd_pcm_t *handle, snd_pcm_stream_params_t *params);
-int snd_pcm_stream_setup(snd_pcm_t *handle, snd_pcm_stream_setup_t *setup);
-int snd_pcm_channel_setup(snd_pcm_t *handle, int stream, snd_pcm_channel_setup_t *setup);
-int snd_pcm_stream_status(snd_pcm_t *handle, snd_pcm_stream_status_t *status);
-int snd_pcm_playback_prepare(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_params(snd_pcm_t *handle, snd_pcm_params_t *params);
+int snd_pcm_setup(snd_pcm_t *handle, snd_pcm_setup_t *setup);
+int snd_pcm_channel_setup(snd_pcm_t *handle, snd_pcm_channel_setup_t *setup);
+int snd_pcm_status(snd_pcm_t *handle, snd_pcm_status_t *status);
+int snd_pcm_prepare(snd_pcm_t *handle);
+int snd_pcm_go(snd_pcm_t *handle);
 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_stream_drain(snd_pcm_t *handle, int stream);
-int snd_pcm_playback_flush(snd_pcm_t *handle);
-int snd_pcm_capture_flush(snd_pcm_t *handle);
-int snd_pcm_stream_flush(snd_pcm_t *handle, int stream);
-int snd_pcm_playback_pause(snd_pcm_t *handle, int enable);
-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);
+int snd_pcm_drain(snd_pcm_t *handle);
+int snd_pcm_flush(snd_pcm_t *handle);
+int snd_pcm_pause(snd_pcm_t *handle, int enable);
+int snd_pcm_state(snd_pcm_t *handle);
+ssize_t snd_pcm_frame_io(snd_pcm_t *handle, int update);
+ssize_t snd_pcm_frame_data(snd_pcm_t *handle, off_t offset);
 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_writev(snd_pcm_t *pcm, 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_writev(snd_pcm_t *handle, 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_description(int format);
 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,
                         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,
                       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_frames_to_bytes(snd_pcm_t *pcm, int stream, ssize_t frames);
-ssize_t snd_pcm_bytes_to_samples(snd_pcm_t *pcm, int stream, ssize_t bytes);
-ssize_t snd_pcm_samples_to_bytes(snd_pcm_t *pcm, int stream, ssize_t samples);
+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, ssize_t frames);
+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, ssize_t samples);
 
 
 /* misc */
@@ -197,7 +207,7 @@ extern "C" {
 #endif
 
 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 {
        INIT = 0,
@@ -208,7 +218,6 @@ typedef enum {
 } snd_pcm_plugin_action_t;
 
 typedef struct snd_stru_pcm_plugin_channel {
-       void *aptr;                     /* pointer to the allocated area */
        snd_pcm_channel_area_t area;
        unsigned int enabled:1;         /* channel need to be processed */
        unsigned int wanted:1;          /* channel is wanted */
@@ -247,54 +256,47 @@ struct snd_stru_pcm_plugin {
                             unsigned long *value);
        snd_pcm_plugin_t *prev;
        snd_pcm_plugin_t *next;
-       snd_pcm_plugin_handle_t *handle;
+       snd_pcm_plug_t *plug;
        void *private_data;
        void (*private_free)(snd_pcm_plugin_t *plugin, void *private_data);
-       snd_pcm_plugin_channel_t *src_channels;
-       snd_pcm_plugin_channel_t *dst_channels;
+       char *buf;
+       size_t buf_frames;
+       snd_pcm_plugin_channel_t *buf_channels;
        bitset_t *src_vmask;
        bitset_t *dst_vmask;
        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_open_subdevice(snd_pcm_t **handle, int card, int device, int subdevice, int mode);
-int snd_pcm_plug_open(snd_pcm_t **handle, int card, int device, int mode);
+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 stream, 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_plug_clear(snd_pcm_t *handle, int stream);
 int snd_pcm_plugin_insert(snd_pcm_plugin_t *plugin);
 int snd_pcm_plugin_append(snd_pcm_plugin_t *plugin);
-#if 0
-int snd_pcm_plugin_remove_to(snd_pcm_plugin_t *plugin);
-int snd_pcm_plug_remove_first(snd_pcm_t *handle, int stream);
-#endif
-snd_pcm_plugin_t *snd_pcm_plug_first(snd_pcm_t *handle, int stream);
-snd_pcm_plugin_t *snd_pcm_plug_last(snd_pcm_t *handle, int stream);
-int snd_pcm_plug_direct(snd_pcm_t *pcm, int stream);
-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);
+int snd_pcm_plug_alloc(snd_pcm_plug_t *plug, size_t frames);
+int snd_pcm_plug_clear(snd_pcm_plug_t *plug);
+snd_pcm_plugin_t *snd_pcm_plug_first(snd_pcm_plug_t *plug);
+snd_pcm_plugin_t *snd_pcm_plug_last(snd_pcm_plug_t *plug);
+int snd_pcm_plug_direct(snd_pcm_plug_t *plug);
+ssize_t snd_pcm_plug_client_size(snd_pcm_plug_t *plug, size_t drv_frames);
+ssize_t snd_pcm_plug_slave_size(snd_pcm_plug_t *plug, size_t clt_frames);
 
 /*
  *  Plug-In constructors
  */
 
-int snd_pcm_plugin_build(snd_pcm_plugin_handle_t *handle,
-                        int stream,
+int snd_pcm_plugin_build(snd_pcm_plug_t *plug,
                         const char *name,
                         snd_pcm_format_t *src_format,
                         snd_pcm_format_t *dst_format,
                         size_t extra,
                         snd_pcm_plugin_t **ret);
 /* basic I/O */
-int snd_pcm_plugin_build_io(snd_pcm_plugin_handle_t *handle,
-                           int stream,
-                           snd_pcm_t *slave,
+int snd_pcm_plugin_build_io(snd_pcm_plug_t *plug,
                            snd_pcm_format_t *format,
                            snd_pcm_plugin_t **r_plugin);
-int snd_pcm_plugin_build_mmap(snd_pcm_plugin_handle_t *handle,
-                             int stream,
-                             snd_pcm_t *slave,
+int snd_pcm_plugin_build_mmap(snd_pcm_plug_t *plug,
                              snd_pcm_format_t *format,
                              snd_pcm_plugin_t **r_plugin);
 
@@ -310,44 +312,36 @@ typedef int route_ttable_entry_t;
 #endif
 
 /* conversion plugins */
-int snd_pcm_plugin_build_interleave(snd_pcm_plugin_handle_t *handle,
-                                   int stream,
+int snd_pcm_plugin_build_interleave(snd_pcm_plug_t *plug,
                                    snd_pcm_format_t *src_format,
                                    snd_pcm_format_t *dst_format,
                                    snd_pcm_plugin_t **r_plugin);
-int snd_pcm_plugin_build_linear(snd_pcm_plugin_handle_t *handle,
-                               int stream,
+int snd_pcm_plugin_build_linear(snd_pcm_plug_t *plug,
                                snd_pcm_format_t *src_format,
                                snd_pcm_format_t *dst_format,
                                snd_pcm_plugin_t **r_plugin);
-int snd_pcm_plugin_build_mulaw(snd_pcm_plugin_handle_t *handle,
-                              int stream,
+int snd_pcm_plugin_build_mulaw(snd_pcm_plug_t *plug,
                               snd_pcm_format_t *src_format,
                               snd_pcm_format_t *dst_format,
                               snd_pcm_plugin_t **r_plugin);
-int snd_pcm_plugin_build_alaw(snd_pcm_plugin_handle_t *handle,
-                             int stream,
+int snd_pcm_plugin_build_alaw(snd_pcm_plug_t *plug,
                              snd_pcm_format_t *src_format,
                              snd_pcm_format_t *dst_format,
                              snd_pcm_plugin_t **r_plugin);
-int snd_pcm_plugin_build_adpcm(snd_pcm_plugin_handle_t *handle,
-                              int stream,
+int snd_pcm_plugin_build_adpcm(snd_pcm_plug_t *plug,
                               snd_pcm_format_t *src_format,
                               snd_pcm_format_t *dst_format,
                               snd_pcm_plugin_t **r_plugin);
-int snd_pcm_plugin_build_rate(snd_pcm_plugin_handle_t *handle,
-                             int stream,
+int snd_pcm_plugin_build_rate(snd_pcm_plug_t *plug,
                              snd_pcm_format_t *src_format,
                              snd_pcm_format_t *dst_format,
                              snd_pcm_plugin_t **r_plugin);
-int snd_pcm_plugin_build_route(snd_pcm_plugin_handle_t *handle,
-                              int stream,
+int snd_pcm_plugin_build_route(snd_pcm_plug_t *plug,
                               snd_pcm_format_t *src_format,
                               snd_pcm_format_t *dst_format,
                               route_ttable_entry_t *ttable,
                               snd_pcm_plugin_t **r_plugin);
-int snd_pcm_plugin_build_copy(snd_pcm_plugin_handle_t *handle,
-                             int stream,
+int snd_pcm_plugin_build_copy(snd_pcm_plug_t *plug,
                              snd_pcm_format_t *src_format,
                              snd_pcm_format_t *dst_format,
                              snd_pcm_plugin_t **r_plugin);
index 882acf0b805e0f32304708e4c238784b922cee04..176450a5dad132a95072024979bdfbf9896b1cda 100644 (file)
 #include <sys/uio.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_type_t snd_pcm_type(snd_pcm_t *handle)
 {
-       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;
+       return handle->type;
 }
 
-snd_pcm_type_t snd_pcm_type(snd_pcm_t *handle)
+snd_pcm_type_t snd_pcm(snd_pcm_t *handle)
 {
-       return handle->type;
+       assert(handle);
+       return handle->stream;
 }
 
-int snd_pcm_stream_close(snd_pcm_t *pcm, int stream)
+int snd_pcm_close(snd_pcm_t *handle)
 {
        int ret = 0;
        int err;
-       snd_pcm_stream_t *str;
-       assert(pcm);
-       assert(stream >= 0 && stream <= 1);
-       str = &pcm->stream[stream];
-       assert(str->open);
-       if (str->mmap_status) {
-               if ((err = snd_pcm_munmap_status(pcm, stream)) < 0)
+       assert(handle);
+       if (handle->mmap_status) {
+               if ((err = snd_pcm_munmap_status(handle)) < 0)
                        ret = err;
        }
-       if (str->mmap_control) {
-               if ((err = snd_pcm_munmap_control(pcm, stream)) < 0)
+       if (handle->mmap_control) {
+               if ((err = snd_pcm_munmap_control(handle)) < 0)
                        ret = err;
        }
-       if (str->mmap_data) {
-               if ((err = snd_pcm_munmap_data(pcm, stream)) < 0)
+       if (handle->mmap_data) {
+               if ((err = snd_pcm_munmap_data(handle)) < 0)
                        ret = err;
        }
-       if ((err = pcm->ops->stream_close(pcm, stream)) < 0)
+       if ((err = handle->ops->close(handle->op_arg)) < 0)
                ret = err;
-       str->open = 0;
-       str->valid_setup = 0;
+       handle->valid_setup = 0;
+       free(handle);
        return ret;
 }      
 
-int snd_pcm_close(snd_pcm_t *pcm)
-{
-       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 snd_pcm_nonblock(snd_pcm_t *handle, int nonblock)
 {
        int err;
-       snd_pcm_stream_t *str;
-       assert(pcm);
-       assert(stream >= 0 && stream <= 1);
-       str = &pcm->stream[stream];
-       assert(pcm->stream[stream].open);
-       if ((err = pcm->ops->stream_nonblock(pcm, stream, nonblock)) < 0)
+       assert(handle);
+       if ((err = handle->ops->nonblock(handle->op_arg, nonblock)) < 0)
                return err;
        if (nonblock)
-               str->mode |= SND_PCM_NONBLOCK;
+               handle->mode |= SND_PCM_NONBLOCK;
        else
-               str->mode &= ~SND_PCM_NONBLOCK;
+               handle->mode &= ~SND_PCM_NONBLOCK;
        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(pcm && info);
-       for (stream = 0; stream < 2; ++stream) {
-               if (pcm->stream[stream].open)
-                       return pcm->ops->info(pcm, stream, info);
-       }
-       assert(0);
+       assert(handle && info);
+       /* Here we pass private and not op_arg.
+          FIXME: find a better solution */
+       return handle->ops->info(handle->private, info);
 }
 
-int snd_pcm_stream_info(snd_pcm_t *pcm, snd_pcm_stream_info_t *info)
-{
-       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 snd_pcm_setup(snd_pcm_t *handle, snd_pcm_setup_t *setup)
 {
        int err;
-       snd_pcm_stream_setup_t setup;
-       snd_pcm_stream_t *str;
-       assert(pcm && params);
-       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;
+       assert(handle && setup);
+       if (handle->valid_setup) {
+               *setup = handle->setup;
                return 0;
        }
-       str->setup.stream = setup->stream;
-       if ((err = pcm->ops->stream_setup(pcm, &str->setup)) < 0)
+       /* Here we pass private and not op_arg.
+          FIXME: find a better solution */
+       if ((err = handle->ops->setup(handle->private, &handle->setup)) < 0)
                return err;
-       *setup = str->setup;
-       str->bits_per_sample = snd_pcm_format_physical_width(setup->format.format);
-        str->bits_per_frame = str->bits_per_sample * setup->format.channels;
-       str->valid_setup = 1;
+       *setup = handle->setup;
+       handle->bits_per_sample = snd_pcm_format_physical_width(setup->format.format);
+        handle->bits_per_frame = handle->bits_per_sample * setup->format.channels;
+       handle->valid_setup = 1;
        return 0;
 }
 
-const snd_pcm_stream_setup_t* snd_pcm_stream_cached_setup(snd_pcm_t *pcm, int stream)
-{
-       snd_pcm_stream_t *str;
-       assert(pcm);
-       assert(stream >= 0 && stream <= 1);
-       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_channel_setup(snd_pcm_t *handle, snd_pcm_channel_setup_t *setup)
 {
-       snd_pcm_stream_t *str;
-       assert(pcm && setup);
-       assert(stream >= 0 && stream <= 1);
-       str = &pcm->stream[stream];
-       assert(str->valid_setup);
-       return pcm->ops->channel_setup(pcm, stream, setup);
+       assert(handle && setup);
+       assert(handle->valid_setup);
+       return handle->ops->channel_setup(handle->op_arg, setup);
 }
 
-int snd_pcm_stream_status(snd_pcm_t *pcm, snd_pcm_stream_status_t *status)
+int snd_pcm_params(snd_pcm_t *handle, snd_pcm_params_t *params)
 {
-       assert(pcm && status);
-       assert(status->stream >= 0 && status->stream <= 1);
-       assert(pcm->stream[status->stream].open);
-       return pcm->ops->stream_status(pcm, status);
-}
-
-int snd_pcm_stream_state(snd_pcm_t *pcm, int stream)
-{
-       snd_pcm_stream_t *str;
-       assert(pcm);
-       assert(stream >= 0 && stream <= 1);
-       str = &pcm->stream[stream];
-       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)
-{
-       snd_pcm_stream_t *str;
-       assert(pcm);
-       assert(stream >= 0 && stream <= 1);
-       str = &pcm->stream[stream];
-       assert(str->valid_setup);
-       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)
-{
-       assert(pcm);
-       assert(stream >= 0 && stream <= 1);
-       assert(pcm->stream[stream].open);
-       return pcm->ops->stream_prepare(pcm, stream);
-}
-
-int snd_pcm_playback_prepare(snd_pcm_t *pcm)
-{
-       return snd_pcm_stream_prepare(pcm, SND_PCM_STREAM_PLAYBACK);
-}
-
-int snd_pcm_capture_prepare(snd_pcm_t *pcm)
-{
-       return snd_pcm_stream_prepare(pcm, SND_PCM_STREAM_CAPTURE);
-}
-
-int snd_pcm_stream_go(snd_pcm_t *pcm, int stream)
-{
-       snd_pcm_stream_t *str;
-       assert(pcm);
-       assert(stream >= 0 && stream <= 1);
-       str = &pcm->stream[stream];
-       assert(str->valid_setup);
-       return pcm->ops->stream_go(pcm, stream);
+       int err;
+       snd_pcm_setup_t setup;
+       assert(handle && params);
+       assert(!handle->mmap_data);
+       /* Here we pass private and not op_arg.
+          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_playback_go(snd_pcm_t *pcm)
+int snd_pcm_status(snd_pcm_t *handle, snd_pcm_status_t *status)
 {
-       return snd_pcm_stream_go(pcm, SND_PCM_STREAM_PLAYBACK);
+       assert(handle && status);
+       return handle->ops->status(handle->op_arg, status);
 }
 
-int snd_pcm_capture_go(snd_pcm_t *pcm)
+int snd_pcm_state(snd_pcm_t *handle)
 {
-       return snd_pcm_stream_go(pcm, SND_PCM_STREAM_CAPTURE);
+       assert(handle);
+       if (handle->mmap_status)
+               return handle->mmap_status->state;
+       return handle->ops->state(handle->op_arg);
 }
 
-int snd_pcm_sync_go(snd_pcm_t *pcm, snd_pcm_sync_t *sync)
+int snd_pcm_frame_io(snd_pcm_t *handle, int update)
 {
-       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);
+       assert(handle);
+       assert(handle->valid_setup);
+       if (handle->mmap_status && !update)
+               return handle->mmap_status->frame_io;
+       return handle->ops->frame_io(handle->op_arg, update);
 }
 
-int snd_pcm_stream_drain(snd_pcm_t *pcm, int stream)
+int snd_pcm_prepare(snd_pcm_t *handle)
 {
-       assert(pcm);
-       assert(stream >= 0 && stream <= 1);
-       assert(pcm->stream[stream].open);
-       assert(stream == SND_PCM_STREAM_PLAYBACK);
-       return pcm->ops->stream_drain(pcm, stream);
+       assert(handle);
+       return handle->ops->prepare(handle->op_arg);
 }
 
-int snd_pcm_playback_drain(snd_pcm_t *pcm)
+int snd_pcm_go(snd_pcm_t *handle)
 {
-       return snd_pcm_stream_drain(pcm, SND_PCM_STREAM_PLAYBACK);
+       assert(handle);
+       return handle->ops->go(handle->op_arg);
 }
 
-int snd_pcm_stream_flush(snd_pcm_t *pcm, int stream)
+int snd_pcm_sync_go(snd_pcm_t *handle, snd_pcm_sync_t *sync)
 {
-       assert(pcm);
-       assert(stream >= 0 && stream <= 1);
-       assert(pcm->stream[stream].open);
-       return pcm->ops->stream_flush(pcm, stream);
+       assert(handle);
+       return handle->ops->sync_go(handle->op_arg, sync);
 }
 
-int snd_pcm_playback_flush(snd_pcm_t *pcm)
+int snd_pcm_drain(snd_pcm_t *handle)
 {
-       return snd_pcm_stream_flush(pcm, SND_PCM_STREAM_PLAYBACK);
+       assert(handle);
+       return handle->ops->drain(handle->op_arg);
 }
 
-int snd_pcm_capture_flush(snd_pcm_t *pcm)
+int snd_pcm_flush(snd_pcm_t *handle)
 {
-       return snd_pcm_stream_flush(pcm, SND_PCM_STREAM_CAPTURE);
+       assert(handle);
+       return handle->ops->flush(handle->op_arg);
 }
 
-int snd_pcm_stream_pause(snd_pcm_t *pcm, int stream, int enable)
+int snd_pcm_pause(snd_pcm_t *handle, 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);
+       assert(handle);
+       return handle->ops->pause(handle->op_arg, 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)
+ssize_t snd_pcm_frame_data(snd_pcm_t *handle, 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) {
+       assert(handle);
+       assert(handle->valid_setup);
+       if (handle->mmap_control) {
                if (offset == 0)
-                       return str->mmap_control->frame_data;
-               if (str->mmap_status)
-                       return snd_pcm_mmap_stream_frame_data(pcm, stream, offset);
+                       return handle->mmap_control->frame_data;
        }
-       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(pcm);
-       str = &pcm->stream[SND_PCM_STREAM_PLAYBACK];
-       assert(str->valid_setup);
+       assert(handle);
        assert(size == 0 || buffer);
-       assert(size % str->setup.frames_align == 0);
-       return pcm->ops->write(pcm, buffer, size);
+       assert(handle->valid_setup);
+       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(pcm->stream[SND_PCM_STREAM_PLAYBACK].valid_setup);
+       assert(handle);
        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(pcm);
-       str = &pcm->stream[SND_PCM_STREAM_CAPTURE];
-       assert(str->valid_setup);
+       assert(handle);
        assert(size == 0 || buffer);
-       assert(size % str->setup.frames_align == 0);
-       return pcm->ops->read(pcm, buffer, size);
+       assert(handle->valid_setup);
+       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(pcm->stream[SND_PCM_STREAM_CAPTURE].valid_setup);
+       assert(handle);
        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(stream >= 0 && stream <= 1);
-       assert(pcm->stream[stream].open);
-       return pcm->ops->file_descriptor(pcm, stream);
+       assert(handle);
+       return handle->ops->file_descriptor(handle->op_arg);
 }
 
-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(stream >= 0 && stream <= 1);
-       assert(pcm->stream[stream].valid_setup);
-       return pcm->ops->channels_mask(pcm, stream, client_vmask);
+       assert(handle);
+       assert(handle->valid_setup);
+       return handle->ops->channels_mask(handle->op_arg, client_vmask);
 }
 
 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 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_stream_setup_t *setup;
-       assert(pcm);
-       assert(stream >= 0 && stream <= 1);
-       str = &pcm->stream[stream];
-       assert(str->valid_setup);
-       setup = &str->setup;
-       fprintf(fp, "stream: %s\n", assoc(setup->stream, streams));
+       snd_pcm_setup_t *setup;
+       assert(handle);
+       assert(handle->valid_setup);
+       setup = &handle->setup;
+        fprintf(fp, "stream: %s\n", assoc(handle->stream, streams));
        fprintf(fp, "mode: %s\n", assoc(setup->mode, modes));
        fprintf(fp, "format: %s\n", assoc(setup->format.format, fmts));
        fprintf(fp, "channels: %d\n", setup->format.channels);
@@ -532,42 +376,31 @@ int snd_pcm_get_format_value(const char* name)
        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(pcm);
-       assert(stream >= 0 && stream <= 1);
-       str = &pcm->stream[stream];
-       assert(str->valid_setup);
-       return bytes * 8 / str->bits_per_frame;
+       assert(handle);
+       assert(handle->valid_setup);
+       return bytes * 8 / handle->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(pcm);
-       assert(stream >= 0 && stream <= 1);
-       str = &pcm->stream[stream];
-       assert(str->valid_setup);
-       return frames * str->bits_per_frame / 8;
+       assert(handle);
+       assert(handle->valid_setup);
+       return frames * handle->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(pcm);
-       assert(stream >= 0 && stream <= 1);
-       str = &pcm->stream[stream];
-       assert(str->valid_setup);
-       return bytes * 8 / str->bits_per_sample;
+       assert(handle);
+       assert(handle->valid_setup);
+       return bytes * 8 / handle->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(pcm);
-       assert(stream >= 0 && stream <= 1);
-       str = &pcm->stream[stream];
-       assert(str->valid_setup);
-       return samples * str->bits_per_sample / 8;
+       assert(handle);
+       assert(handle->valid_setup);
+       return samples * handle->bits_per_sample / 8;
 }
+
index 335f901bf9c3c72b5080df8e9a19e15d4739a36e..6ea34830b4818faf2d52f3082a638a816d7ae269 100644 (file)
 #include "pcm_local.h"
 
 typedef struct {
+       snd_pcm_t *handle;
        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;
 
-#define SND_FILE_PCM_PLAYBACK          "/dev/snd/pcmC%iD%ip"
-#define SND_FILE_PCM_CAPTURE           "/dev/snd/pcmC%iD%ic"
+#define SND_FILE_PCM_STREAM_PLAYBACK           "/dev/snd/pcmC%iD%ip"
+#define SND_FILE_PCM_STREAM_CAPTURE            "/dev/snd/pcmC%iD%ic"
 #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;
-       int fd = hw->stream[stream].fd;
+       snd_pcm_hw_t *hw = (snd_pcm_hw_t*) private;
+       int fd = hw->fd;
+       free(private);
        if (fd >= 0)
                if (close(fd))
                        return -errno;
        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;
-       snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private;
-       int fd = hw->stream[stream].fd;
+       snd_pcm_hw_t *hw = (snd_pcm_hw_t*) private;
+       int fd = hw->fd;
 
        if ((flags = fcntl(fd, F_GETFL)) < 0)
                return -errno;
@@ -71,151 +66,144 @@ static int snd_pcm_hw_stream_nonblock(snd_pcm_t *pcm, int stream, int nonblock)
        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;
-       int fd = hw->stream[stream].fd;
+       snd_pcm_hw_t *hw = (snd_pcm_hw_t*) private;
+       int fd = hw->fd;
        if (ioctl(fd, SND_PCM_IOCTL_INFO, info) < 0)
                return -errno;
        return 0;
 }
 
-static int snd_pcm_hw_stream_info(snd_pcm_t *pcm, snd_pcm_stream_info_t * info)
-{
-       snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private;
-       int fd = hw->stream[info->stream].fd;
-       if (ioctl(fd, SND_PCM_IOCTL_STREAM_INFO, info) < 0)
-               return -errno;
-       return 0;
-}
-
-static int snd_pcm_hw_stream_params(snd_pcm_t *pcm, snd_pcm_stream_params_t * params)
+static int snd_pcm_hw_params(void *private, snd_pcm_params_t * params)
 {
-       snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private;
-       int fd = hw->stream[params->stream].fd;
-       if (ioctl(fd, SND_PCM_IOCTL_STREAM_PARAMS, params) < 0)
+       snd_pcm_hw_t *hw = (snd_pcm_hw_t*) private;
+       int fd = hw->fd;
+       if (ioctl(fd, SND_PCM_IOCTL_PARAMS, params) < 0)
                return -errno;
        return 0;
 }
 
-static int snd_pcm_hw_stream_setup(snd_pcm_t *pcm, snd_pcm_stream_setup_t * setup)
+static int snd_pcm_hw_setup(void *private, snd_pcm_setup_t * setup)
 {
-       snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private;
-       int fd = hw->stream[setup->stream].fd;
-       if (ioctl(fd, SND_PCM_IOCTL_STREAM_SETUP, setup) < 0)
+       snd_pcm_hw_t *hw = (snd_pcm_hw_t*) private;
+       int fd = hw->fd;
+       if (ioctl(fd, SND_PCM_IOCTL_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)
+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;
-       int fd = hw->stream[stream].fd;
+       snd_pcm_hw_t *hw = (snd_pcm_hw_t*) private;
+       int fd = hw->fd;
        if (ioctl(fd, SND_PCM_IOCTL_CHANNEL_SETUP, setup) < 0)
                return -errno;
        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;
-       int fd = hw->stream[status->stream].fd;
-       if (ioctl(fd, SND_PCM_IOCTL_STREAM_STATUS, status) < 0)
+       snd_pcm_hw_t *hw = (snd_pcm_hw_t*) private;
+       int fd = hw->fd;
+       if (ioctl(fd, SND_PCM_IOCTL_STATUS, status) < 0)
                return -errno;
        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;
-       int fd = hw->stream[stream].fd;
-       snd_pcm_stream_status_t status;
-       status.stream = stream;
-       if (ioctl(fd, SND_PCM_IOCTL_STREAM_STATUS, status) < 0)
+       snd_pcm_hw_t *hw = (snd_pcm_hw_t*) private;
+       int fd = hw->fd;
+       snd_pcm_status_t status;
+       if (ioctl(fd, SND_PCM_IOCTL_STATUS, status) < 0)
                return -errno;
        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;
-       int fd = hw->stream[stream].fd;
-       ssize_t pos = ioctl(fd, SND_PCM_IOCTL_STREAM_FRAME_IO);
+       snd_pcm_hw_t *hw = (snd_pcm_hw_t*) private;
+       int fd = hw->fd;
+       ssize_t pos = ioctl(fd, SND_PCM_IOCTL_FRAME_IO);
        if (pos < 0)
                return -errno;
        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;
-       int fd = hw->stream[stream].fd;
-       if (ioctl(fd, SND_PCM_IOCTL_STREAM_PREPARE) < 0)
+       snd_pcm_hw_t *hw = (snd_pcm_hw_t*) private;
+       int fd = hw->fd;
+       if (ioctl(fd, SND_PCM_IOCTL_PREPARE) < 0)
                return -errno;
        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;
-       int fd = hw->stream[stream].fd;
-       if (ioctl(fd, SND_PCM_IOCTL_STREAM_GO) < 0)
+       snd_pcm_hw_t *hw = (snd_pcm_hw_t*) private;
+       int fd = hw->fd;
+       if (ioctl(fd, SND_PCM_IOCTL_GO) < 0)
                return -errno;
        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;
-       int fd = hw->stream[stream].fd;
+       snd_pcm_hw_t *hw = (snd_pcm_hw_t*) private;
+       int fd = hw->fd;
        if (ioctl(fd, SND_PCM_IOCTL_SYNC_GO, sync) < 0)
                return -errno;
        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;
-       int fd = hw->stream[stream].fd;
-       if (ioctl(fd, SND_PCM_IOCTL_STREAM_DRAIN) < 0)
+       snd_pcm_hw_t *hw = (snd_pcm_hw_t*) private;
+       int fd = hw->fd;
+       if (ioctl(fd, SND_PCM_IOCTL_DRAIN) < 0)
                return -errno;
        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;
-       int fd = hw->stream[stream].fd;
-       if (ioctl(fd, SND_PCM_IOCTL_STREAM_FLUSH) < 0)
+       snd_pcm_hw_t *hw = (snd_pcm_hw_t*) private;
+       int fd = hw->fd;
+       if (ioctl(fd, SND_PCM_IOCTL_FLUSH) < 0)
                return -errno;
        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;
-       int fd = hw->stream[stream].fd;
-       if (ioctl(fd, SND_PCM_IOCTL_STREAM_PAUSE, &enable) < 0)
+       snd_pcm_hw_t *hw = (snd_pcm_hw_t*) private;
+       int fd = hw->fd;
+       if (ioctl(fd, SND_PCM_IOCTL_PAUSE, &enable) < 0)
                return -errno;
        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;
-       snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private;
-       int fd = hw->stream[stream].fd;
-       result = ioctl(fd, SND_PCM_IOCTL_STREAM_FRAME_DATA, offset);
+       snd_pcm_hw_t *hw = (snd_pcm_hw_t*) private;
+       snd_pcm_t *handle = hw->handle;
+       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)
                return -errno;
        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;
-       snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private;
-       int fd = hw->stream[SND_PCM_STREAM_PLAYBACK].fd;
+       snd_pcm_hw_t *hw = (snd_pcm_hw_t*) private;
+       int fd = hw->fd;
        snd_xfer_t xfer;
        xfer.buf = (char*) buffer;
        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;
 }
 
-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;
-       snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private;
-       int fd = hw->stream[SND_PCM_STREAM_PLAYBACK].fd;
+       snd_pcm_hw_t *hw = (snd_pcm_hw_t*) private;
+       int fd = hw->fd;
        snd_xferv_t xferv;
        xferv.vector = vector;
        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;
 }
 
-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;
-       snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private;
-       int fd = hw->stream[SND_PCM_STREAM_CAPTURE].fd;
+       snd_pcm_hw_t *hw = (snd_pcm_hw_t*) private;
+       int fd = hw->fd;
        snd_xfer_t xfer;
        xfer.buf = buffer;
        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;
 }
 
-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;
-       snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private;
-       int fd = hw->stream[SND_PCM_STREAM_CAPTURE].fd;
+       snd_pcm_hw_t *hw = (snd_pcm_hw_t*) private;
+       int fd = hw->fd;
        snd_xferv_t xferv;
        xferv.vector = vector;
        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;
 }
 
-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;
-       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, 
-                  hw->stream[stream].fd, SND_PCM_MMAP_OFFSET_STATUS);
+                  hw->fd, SND_PCM_MMAP_OFFSET_STATUS);
        if (ptr == MAP_FAILED || ptr == NULL)
                return -errno;
        *status = ptr;
        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;
-       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, 
-                  hw->stream[stream].fd, SND_PCM_MMAP_OFFSET_CONTROL);
+                  hw->fd, SND_PCM_MMAP_OFFSET_CONTROL);
        if (ptr == MAP_FAILED || ptr == NULL)
                return -errno;
        *control = ptr;
        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;
        void *daddr;
-       snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private;
-       prot = stream == SND_PCM_STREAM_PLAYBACK ? PROT_WRITE : PROT_READ;
+       snd_pcm_hw_t *hw = (snd_pcm_hw_t*) private;
+       prot = hw->handle->stream == SND_PCM_STREAM_PLAYBACK ? PROT_WRITE : PROT_READ;
        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)
                return -errno;
        *buffer = daddr;
        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)
                return -errno;
        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)
                return -errno;
        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)
                return -errno;
        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;
-       return hw->stream[stream].fd;
+       snd_pcm_hw_t *hw = (snd_pcm_hw_t*) private;
+       return hw->fd;
 }
 
-static int snd_pcm_hw_channels_mask(snd_pcm_t *pcm UNUSED, int stream UNUSED,
-                                 bitset_t *client_vmask UNUSED)
+static int snd_pcm_hw_channels_mask(void *private UNUSED,
+                                   bitset_t *client_vmask UNUSED)
 {
        return 0;
 }
 
 struct snd_pcm_ops snd_pcm_hw_ops = {
-       stream_close: snd_pcm_hw_stream_close,
-       stream_nonblock: snd_pcm_hw_stream_nonblock,
+       close: snd_pcm_hw_close,
+       nonblock: snd_pcm_hw_nonblock,
        info: snd_pcm_hw_info,
-       stream_info: snd_pcm_hw_stream_info,
-       stream_params: snd_pcm_hw_stream_params,
-       stream_setup: snd_pcm_hw_stream_setup,
+       params: snd_pcm_hw_params,
+       setup: snd_pcm_hw_setup,
        channel_setup: snd_pcm_hw_channel_setup,
-       stream_status: snd_pcm_hw_stream_status,
-       stream_frame_io: snd_pcm_hw_stream_frame_io,
-       stream_state: snd_pcm_hw_stream_state,
-       stream_prepare: snd_pcm_hw_stream_prepare,
-       stream_go: snd_pcm_hw_stream_go,
+       status: snd_pcm_hw_status,
+       frame_io: snd_pcm_hw_frame_io,
+       state: snd_pcm_hw_state,
+       prepare: snd_pcm_hw_prepare,
+       go: snd_pcm_hw_go,
        sync_go: snd_pcm_hw_sync_go,
-       stream_drain: snd_pcm_hw_stream_drain,
-       stream_flush: snd_pcm_hw_stream_flush,
-       stream_pause: snd_pcm_hw_stream_pause,
-       stream_frame_data: snd_pcm_hw_stream_frame_data,
+       drain: snd_pcm_hw_drain,
+       flush: snd_pcm_hw_flush,
+       pause: snd_pcm_hw_pause,
+       frame_data: snd_pcm_hw_frame_data,
        write: snd_pcm_hw_write,
        writev: snd_pcm_hw_writev,
        read: snd_pcm_hw_read,
@@ -370,122 +357,99 @@ struct snd_pcm_ops snd_pcm_hw_ops = {
        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 *filefmt;
-       int err, fd;
+       int ver;
+       int ret = 0, fd = -1;
        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) {
        case SND_PCM_STREAM_PLAYBACK:
-               filefmt = SND_FILE_PCM_PLAYBACK;
+               filefmt = SND_FILE_PCM_STREAM_PLAYBACK;
                break;
        case SND_PCM_STREAM_CAPTURE:
-               filefmt = SND_FILE_PCM_CAPTURE;
+               filefmt = SND_FILE_PCM_STREAM_CAPTURE;
                break;
        default:
                assert(0);
        }
-       if ((err = snd_ctl_pcm_stream_prefer_subdevice(ctl, device, stream, subdevice)) < 0)
-               return err;
+       if ((ret = snd_ctl_pcm_prefer_subdevice(ctl, subdevice)) < 0)
+               goto __end;
        sprintf(filename, filefmt, card, device);
 
       __again:
        if (attempt++ > 3) {
-               snd_ctl_close(ctl);
-               return -EBUSY;
+               ret = -EBUSY;
+               goto __end;
        }
+       fmode = O_RDWR;
+       if (mode & SND_PCM_NONBLOCK)
+               fmode |= O_NONBLOCK;
        if ((fd = open(filename, fmode)) < 0) {
-               err = -errno;
-               return err;
+               ret = -errno;
+               goto __end;
        }
-       if (ioctl(fd, SND_PCM_IOCTL_PVERSION, ver) < 0) {
-               err = -errno;
-               close(fd);
-               return err;
+       if (ioctl(fd, SND_PCM_IOCTL_PVERSION, &ver) < 0) {
+               ret = -errno;
+               goto __end;
        }
-       if (SND_PROTOCOL_INCOMPATIBLE(*ver, SND_PCM_VERSION_MAX)) {
-               close(fd);
-               return -SND_ERROR_INCOMPATIBLE_VERSION;
+       if (SND_PROTOCOL_INCOMPATIBLE(ver, SND_PCM_VERSION_MAX)) {
+               ret = -SND_ERROR_INCOMPATIBLE_VERSION;
+               goto __end;
        }
        if (subdevice >= 0) {
                memset(&info, 0, sizeof(info));
-               if (ioctl(fd, SND_PCM_IOCTL_STREAM_INFO, &info) < 0) {
-                       err = -errno;
-                       close(fd);
-                       return err;
+               if (ioctl(fd, SND_PCM_IOCTL_INFO, &info) < 0) {
+                       ret = -errno;
+                       goto __end;
                }
                if (info.subdevice != subdevice) {
                        close(fd);
                        goto __again;
                }
        }
-       return fd;
-}
-
-int snd_pcm_open_subdevice(snd_pcm_t **handle, int card, int device, int subdevice, int mode)
-{
-       int fmode, ver, err;
-       snd_pcm_t *pcm;
-       snd_pcm_hw_t *hw;
-       snd_ctl_t *ctl;
-       int pfd = -1, cfd = -1;
-
-       assert(handle);
-       *handle = NULL;
-       
-       assert(card >= 0 && card < SND_CARDS);
-       if ((err = snd_ctl_open(&ctl, card)) < 0)
-               return err;
-       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;
-               }
+       handle = calloc(1, sizeof(snd_pcm_t));
+       if (!handle) {
+               ret = -ENOMEM;
+               goto __end;
        }
-       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;
-               }
+       hw = calloc(1, sizeof(snd_pcm_hw_t));
+       if (!handle) {
+               free(handle);
+               ret = -ENOMEM;
+               goto __end;
        }
+       hw->handle = handle;
+       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;
+       
+ __end:
+       if (ret < 0 && fd >= 0)
+               close(fd);
        snd_ctl_close(ctl);
-       assert(pfd >= 0 || cfd >= 0);
-
-       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;
+       return ret;
 }
 
-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);
 }
 
index 6c4e62cbe28611ac728059150760ac9f850787bc..9968927ec100c97c05a5aba9f81096a309b96c67 100644 (file)
 
 #include <assert.h>
 #include "asoundlib.h"
-  
+
 struct snd_pcm_ops {
-       int (*stream_close)(snd_pcm_t *pcm, int stream);
-       int (*stream_nonblock)(snd_pcm_t *pcm, int stream, int nonblock);
-       int (*info)(snd_pcm_t *pcm, int stream, snd_pcm_info_t *info);
-       int (*stream_info)(snd_pcm_t *pcm, snd_pcm_stream_info_t *info);
-       int (*stream_params)(snd_pcm_t *pcm, snd_pcm_stream_params_t *params);
-       int (*stream_setup)(snd_pcm_t *pcm, snd_pcm_stream_setup_t *setup);
-       int (*channel_setup)(snd_pcm_t *pcm, int stream, snd_pcm_channel_setup_t *setup);
-       int (*stream_status)(snd_pcm_t *pcm, snd_pcm_stream_status_t *status);
-       int (*stream_prepare)(snd_pcm_t *pcm, int stream);
-       int (*stream_go)(snd_pcm_t *pcm, int stream);
-       int (*sync_go)(snd_pcm_t *pcm, int stream, snd_pcm_sync_t *sync);
-       int (*stream_drain)(snd_pcm_t *pcm, int stream);
-       int (*stream_flush)(snd_pcm_t *pcm, int stream);
-       int (*stream_pause)(snd_pcm_t *pcm, int stream, int enable);
-       int (*stream_state)(snd_pcm_t *pcm, int stream);
-       ssize_t (*stream_frame_io)(snd_pcm_t *pcm, int stream, int update);
-       ssize_t (*stream_frame_data)(snd_pcm_t *pcm, int stream, off_t offset);
-       ssize_t (*write)(snd_pcm_t *pcm, const void *buffer, size_t size);
-       ssize_t (*writev)(snd_pcm_t *pcm, const struct iovec *vector, unsigned long count);
-       ssize_t (*read)(snd_pcm_t *pcm, void *buffer, size_t size);
-       ssize_t (*readv)(snd_pcm_t *pcm, const struct iovec *vector, unsigned long count);
-       int (*mmap_status)(snd_pcm_t *pcm, int stream, snd_pcm_mmap_status_t **status);
-       int (*mmap_control)(snd_pcm_t *pcm, int stream, snd_pcm_mmap_control_t **control);
-       int (*mmap_data)(snd_pcm_t *pcm, int stream, void **buffer, size_t bsize);
-       int (*munmap_status)(snd_pcm_t *pcm, int stream, snd_pcm_mmap_status_t *status);
-       int (*munmap_control)(snd_pcm_t *pcm, int stream, snd_pcm_mmap_control_t *control);
-       int (*munmap_data)(snd_pcm_t *pcm, int stream, void *buffer, size_t bsize);
-       int (*file_descriptor)(snd_pcm_t* pcm, int stream);
-       int (*channels_mask)(snd_pcm_t *pcm, int stream, bitset_t *client_vmask);
+       int (*close)(void *private);
+       int (*nonblock)(void *private, int nonblock);
+       int (*info)(void *private, snd_pcm_info_t *info);
+       int (*params)(void *private, snd_pcm_params_t *params);
+       int (*setup)(void *private, snd_pcm_setup_t *setup);
+       int (*channel_setup)(void *private, snd_pcm_channel_setup_t *setup);
+       int (*status)(void *private, snd_pcm_status_t *status);
+       int (*prepare)(void *private);
+       int (*go)(void *private);
+       int (*sync_go)(void *private, snd_pcm_sync_t *sync);
+       int (*drain)(void *private);
+       int (*flush)(void *private);
+       int (*pause)(void *private, int enable);
+       int (*state)(void *private);
+       ssize_t (*frame_io)(void *private, int update);
+       ssize_t (*frame_data)(void *private, off_t offset);
+       ssize_t (*write)(void *private, const void *buffer, size_t size);
+       ssize_t (*writev)(void *private, const struct iovec *vector, unsigned long count);
+       ssize_t (*read)(void *private, void *buffer, size_t size);
+       ssize_t (*readv)(void *private, const struct iovec *vector, unsigned long count);
+       int (*mmap_status)(void *private, snd_pcm_mmap_status_t **status);
+       int (*mmap_control)(void *private, snd_pcm_mmap_control_t **control);
+       int (*mmap_data)(void *private, void **buffer, size_t bsize);
+       int (*munmap_status)(void *private, snd_pcm_mmap_status_t *status);
+       int (*munmap_control)(void *private, snd_pcm_mmap_control_t *control);
+       int (*munmap_data)(void *private, void *buffer, size_t bsize);
+       int (*file_descriptor)(void *private);
+       int (*channels_mask)(void *private, bitset_t *client_vmask);
 };
 
-typedef struct {
-       snd_pcm_plugin_t *first;
-       snd_pcm_plugin_t *last;
-       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;
+struct snd_pcm {
+       snd_pcm_type_t type;
+       int stream;
        int mode;
        int valid_setup;
-       snd_pcm_stream_setup_t setup;
+       snd_pcm_setup_t setup;
        snd_pcm_channel_area_t *channels;
        size_t bits_per_sample;
        size_t bits_per_frame;
@@ -81,46 +67,48 @@ typedef struct {
        char *mmap_data;
        size_t mmap_data_size;
        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;
-       snd_pcm_stream_t stream[2];
-       int private[0];
+       void *op_arg;
+       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);
-int snd_pcm_plug_slave_params(snd_pcm_stream_params_t *params,
-                             snd_pcm_stream_info_t *slave_info,
-                             snd_pcm_stream_params_t *slave_params);
-int snd_pcm_plug_format(snd_pcm_plugin_handle_t *pcm,
-                       snd_pcm_stream_params_t *params,
-                       snd_pcm_stream_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_read_transfer(snd_pcm_plugin_handle_t *handle, 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,
-                                        const struct iovec *vector, unsigned long count,
+int snd_pcm_plug_slave_params(snd_pcm_params_t *params,
+                             snd_pcm_info_t *slave_info,
+                             snd_pcm_params_t *slave_params);
+int snd_pcm_plug_format(snd_pcm_plug_t *plug,
+                       snd_pcm_params_t *params,
+                       snd_pcm_params_t *slave_params);
+
+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_plug_t *plug, snd_pcm_plugin_channel_t *dst_channels_final, size_t size);
+ssize_t snd_pcm_plug_client_channels_iovec(snd_pcm_plug_t *plug,
+                                          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);
-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,
-                                     bitset_t *client_vmask);
-int snd_pcm_plug_capture_channels_mask(snd_pcm_plugin_handle_t *handle,
-                                    bitset_t *client_vmask);
+int snd_pcm_plug_playback_channels_mask(snd_pcm_plug_t *plug,
+                                       bitset_t *client_vmask);
+int snd_pcm_plug_capture_channels_mask(snd_pcm_plug_t *plug,
+                                      bitset_t *client_vmask);
 int snd_pcm_plugin_client_channels(snd_pcm_plugin_t *plugin,
-                                 size_t frames,
-                                 snd_pcm_plugin_channel_t **channels);
+                                  size_t frames,
+                                  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_unlock(snd_pcm_t *pcm, int stream, void *ptr);
+void *snd_pcm_plug_buf_alloc(snd_pcm_plug_t *plug, size_t size);
+void snd_pcm_plug_buf_unlock(snd_pcm_plug_t *pcm, void *ptr);
 
 #define ROUTE_PLUGIN_RESOLUTION 16
 
@@ -133,7 +121,7 @@ int conv_index(int src_format, int dst_format);
 #define pdprintf( args... ) { ; }
 #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;
        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;
 }
 
-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;
        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;
 }
 
+#define snd_pcm_plug_stream(plug) ((plug)->handle->stream)
index 231fe0cc3c215cd57ed4fc900b7e5e3eb5bd372a..8304975f6f9c233334b015b4056c13c89d1f0485 100644 (file)
 #include <sys/uio.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(pcm);
-        assert(stream >= 0 && stream <= 1);
-       str = &pcm->stream[stream];
-       assert(str->mmap_status && str->mmap_control);
-       if (stream == SND_PCM_STREAM_PLAYBACK)
-               *frames = snd_pcm_mmap_playback_frames_avail(str);
+        assert(handle);
+       assert(handle->mmap_status && handle->mmap_control);
+       if (handle->stream == SND_PCM_STREAM_PLAYBACK)
+               *frames = snd_pcm_mmap_playback_frames_avail(handle);
        else
-               *frames = snd_pcm_mmap_capture_frames_avail(str);
+               *frames = snd_pcm_mmap_capture_frames_avail(handle);
        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;
-       str = &pcm->stream[SND_PCM_STREAM_PLAYBACK];
-       if (str->mmap_status->state == SND_PCM_STATE_XRUN)
+       if (handle->mmap_status->state == SND_PCM_STATE_XRUN)
                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;
-       str = &pcm->stream[SND_PCM_STREAM_CAPTURE];
-       if (str->mmap_status->state == SND_PCM_STATE_XRUN) {
+       if (handle->mmap_status->state == SND_PCM_STATE_XRUN) {
                ret = -EPIPE;
-               if (str->setup.xrun_mode == SND_PCM_XRUN_DRAIN)
+               if (handle->setup.xrun_mode == SND_PCM_XRUN_DRAIN)
                        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 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(pcm);
-        assert(stream >= 0 && stream <= 1);
-       str = &pcm->stream[stream];
-       assert(str->mmap_status && str->mmap_control);
-       assert(str->mmap_status->state >= SND_PCM_STATE_PREPARED);
-       if (stream == SND_PCM_STREAM_PLAYBACK) {
-               return snd_pcm_mmap_playback_ready(pcm);
+        assert(handle);
+       assert(handle->mmap_status && handle->mmap_control);
+       assert(handle->mmap_status->state >= SND_PCM_STATE_PREPARED);
+       if (handle->stream == SND_PCM_STREAM_PLAYBACK) {
+               return snd_pcm_mmap_playback_ready(handle);
        } 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 = str->mmap_control;
+       snd_pcm_mmap_control_t *control = handle->mmap_control;
        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)
                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)
                frames = frames_cont;
        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 = str->mmap_control;
+       snd_pcm_mmap_control_t *control = handle->mmap_control;
        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)
                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)
                frames = frames_cont;
        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(pcm);
-        assert(stream >= 0 && stream <= 1);
-       str = &pcm->stream[stream];
-       assert(str->mmap_status && str->mmap_control);
-       if (stream == SND_PCM_STREAM_PLAYBACK)
-               return snd_pcm_mmap_playback_frames_xfer(pcm, frames);
+        assert(handle);
+       assert(handle->mmap_status && handle->mmap_control);
+       if (handle->stream == SND_PCM_STREAM_PLAYBACK)
+               return snd_pcm_mmap_playback_frames_xfer(handle, frames);
        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(pcm);
-        assert(stream >= 0 && stream <= 1);
-       str = &pcm->stream[stream];
-       assert(str->mmap_control);
-       return str->mmap_control->frame_data % str->setup.buffer_size;
+        assert(handle);
+       assert(handle->mmap_control);
+       return handle->mmap_control->frame_data % handle->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(pcm);
-       assert(stream >= 0 && stream <= 1);
-       str = &pcm->stream[stream];
-       assert(str->mmap_status);
-       return str->mmap_status->state;
+       assert(handle);
+       assert(handle->mmap_status);
+       return handle->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(pcm);
-       assert(stream >= 0 && stream <= 1);
-       str = &pcm->stream[stream];
-       assert(str->mmap_status);
-       return str->mmap_status->frame_io;
+       assert(handle);
+       assert(handle->mmap_status);
+       return handle->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;
-       assert(pcm);
-       assert(stream >= 0 && stream <= 1);
-       str = &pcm->stream[stream];
-       assert(str->mmap_status && str->mmap_control);
-       frame_data = str->mmap_control->frame_data;
+       assert(handle);
+       assert(handle->mmap_status && handle->mmap_control);
+       assert(offset == 0 || handle->type == SND_PCM_TYPE_HW);
+       frame_data = handle->mmap_control->frame_data;
        if (offset == 0)
                return frame_data;
-       switch (str->mmap_status->state) {
+       switch (handle->mmap_status->state) {
        case SND_PCM_STATE_RUNNING:
-               if (str->setup.mode == SND_PCM_MODE_FRAME)
-                       snd_pcm_stream_frame_io(pcm, stream, 1);
+               if (handle->setup.mode == SND_PCM_MODE_FRAME)
+                       snd_pcm_frame_io(handle, 1);
                break;
        case SND_PCM_STATE_PREPARED:
                break;
@@ -171,85 +145,83 @@ ssize_t snd_pcm_mmap_stream_frame_data(snd_pcm_t *pcm, int stream, off_t offset)
                return -EBADFD;
        }
        if (offset < 0) {
-               if (offset < -(ssize_t)str->setup.buffer_size)
-                       offset = -(ssize_t)str->setup.buffer_size;
+               if (offset < -(ssize_t)handle->setup.buffer_size)
+                       offset = -(ssize_t)handle->setup.buffer_size;
                else
-                       offset -= offset % str->setup.frames_align;
+                       offset -= offset % handle->setup.frames_align;
                frame_data += offset;
                if (frame_data < 0)
-                       frame_data += str->setup.frame_boundary;
+                       frame_data += handle->setup.frame_boundary;
        } else {
                size_t frames_avail;
-               if (stream == SND_PCM_STREAM_PLAYBACK)
-                       frames_avail = snd_pcm_mmap_playback_frames_avail(str);
+               if (handle->stream == SND_PCM_STREAM_PLAYBACK)
+                       frames_avail = snd_pcm_mmap_playback_frames_avail(handle);
                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)
                        offset = frames_avail;
-               offset -= offset % str->setup.frames_align;
+               offset -= offset % handle->setup.frames_align;
                frame_data += offset;
-               if ((size_t)frame_data >= str->setup.frame_boundary)
-                       frame_data -= str->setup.frame_boundary;
+               if ((size_t)frame_data >= handle->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;
 }
 
-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;
        size_t offset = 0;
        size_t result = 0;
        int err;
 
-       str = &pcm->stream[SND_PCM_STREAM_PLAYBACK];
-       assert(str->mmap_data && str->mmap_status && str->mmap_control);
-       status = str->mmap_status;
+       assert(handle->mmap_data && handle->mmap_status && handle->mmap_control);
+       status = handle->mmap_status;
        assert(status->state >= SND_PCM_STATE_PREPARED);
-       if (str->setup.mode == SND_PCM_MODE_FRAGMENT) {
-               assert(frames % str->setup.frag_size == 0);
+       if (handle->setup.mode == SND_PCM_MODE_FRAGMENT) {
+               assert(frames % handle->setup.frag_size == 0);
        } else {
                if (status->state == SND_PCM_STATE_RUNNING &&
-                   str->mode & SND_PCM_NONBLOCK)
-                       snd_pcm_stream_frame_io(pcm, SND_PCM_STREAM_PLAYBACK, 1);
+                   handle->mode & SND_PCM_NONBLOCK)
+                       snd_pcm_frame_io(handle, 1);
        }
        while (frames > 0) {
                ssize_t mmap_offset;
                size_t frames1;
-               int ready = snd_pcm_mmap_playback_ready(pcm);
+               int ready = snd_pcm_mmap_playback_ready(handle);
                if (ready < 0)
                        return ready;
                if (!ready) {
                        struct pollfd pfd;
                        if (status->state != SND_PCM_STATE_RUNNING)
                                return result > 0 ? result : -EPIPE;
-                       if (str->mode & SND_PCM_NONBLOCK)
+                       if (handle->mode & SND_PCM_NONBLOCK)
                                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;
                        ready = poll(&pfd, 1, 10000);
                        if (ready < 0)
                                return result > 0 ? result : ready;
                        if (ready && pfd.revents & POLLERR)
                                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);
-               mmap_offset = snd_pcm_mmap_frames_offset(pcm, SND_PCM_STREAM_PLAYBACK);
-               snd_pcm_areas_copy(channels, offset, str->channels, mmap_offset, str->setup.format.channels, frames1, str->setup.format.format);
+               mmap_offset = snd_pcm_mmap_frames_offset(handle);
+               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)
                        return result > 0 ? result : -EPIPE;
-               snd_pcm_stream_frame_data(pcm, SND_PCM_STREAM_PLAYBACK, frames1);
+               snd_pcm_frame_data(handle, frames1);
                frames -= frames1;
                offset += frames1;
                result += frames1;
                if (status->state == SND_PCM_STATE_PREPARED &&
-                   (str->setup.start_mode == SND_PCM_START_DATA ||
-                    (str->setup.start_mode == SND_PCM_START_FULL &&
-                     !snd_pcm_mmap_playback_ready(pcm)))) {
-                       err = snd_pcm_stream_go(pcm, SND_PCM_STREAM_PLAYBACK);
+                   (handle->setup.start_mode == SND_PCM_START_DATA ||
+                    (handle->setup.start_mode == SND_PCM_START_FULL &&
+                     !snd_pcm_mmap_playback_ready(handle)))) {
+                       err = snd_pcm_go(handle);
                        if (err < 0)
                                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;
 }
 
-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;
-       assert(pcm);
-       str = &pcm->stream[SND_PCM_STREAM_PLAYBACK];
-       assert(str->mmap_data && str->mmap_status && str->mmap_control);
+       assert(handle);
+       assert(handle->mmap_data && handle->mmap_status && handle->mmap_control);
        assert(frames == 0 || buffer);
-       nchannels = str->setup.format.channels;
-       assert(str->setup.format.interleave || nchannels == 1);
+       nchannels = handle->setup.format.channels;
+       assert(handle->setup.format.interleave || nchannels == 1);
        {
                snd_pcm_channel_area_t channels[nchannels];
                unsigned int channel;
                for (channel = 0; channel < nchannels; ++channel) {
                        channels[channel].addr = (char*)buffer;
-                       channels[channel].first = str->bits_per_sample * channel;
-                       channels[channel].step = str->bits_per_frame;
+                       channels[channel].first = handle->bits_per_sample * channel;
+                       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;
        unsigned int nchannels;
-       assert(pcm);
-       str = &pcm->stream[SND_PCM_STREAM_PLAYBACK];
-       assert(str->mmap_data && str->mmap_status && str->mmap_control);
+       assert(handle);
+       assert(handle->mmap_data && handle->mmap_status && handle->mmap_control);
        assert(vcount == 0 || vector);
-       nchannels = str->setup.format.channels;
-       if (str->setup.format.interleave) {
+       nchannels = handle->setup.format.channels;
+       if (handle->setup.format.interleave) {
                unsigned int b;
                for (b = 0; b < vcount; b++) {
                        ssize_t ret;
                        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 (result <= 0)
                                        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);
                                channels[v].addr = vector[v].iov_base;
                                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 (result <= 0)
                                        return ret;
@@ -333,60 +301,58 @@ ssize_t snd_pcm_mmap_writev(snd_pcm_t *pcm, const struct iovec *vector, unsigned
        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;
        size_t offset = 0;
        size_t result = 0;
        int err;
 
-       str = &pcm->stream[SND_PCM_STREAM_CAPTURE];
-       assert(str->mmap_data && str->mmap_status && str->mmap_control);
-       status = str->mmap_status;
+       assert(handle->mmap_data && handle->mmap_status && handle->mmap_control);
+       status = handle->mmap_status;
        assert(status->state >= SND_PCM_STATE_PREPARED);
-       if (str->setup.mode == SND_PCM_MODE_FRAGMENT) {
-               assert(frames % str->setup.frag_size == 0);
+       if (handle->setup.mode == SND_PCM_MODE_FRAGMENT) {
+               assert(frames % handle->setup.frag_size == 0);
        } else {
                if (status->state == SND_PCM_STATE_RUNNING &&
-                   str->mode & SND_PCM_NONBLOCK)
-                       snd_pcm_stream_frame_io(pcm, SND_PCM_STREAM_CAPTURE, 1);
+                   handle->mode & SND_PCM_NONBLOCK)
+                       snd_pcm_frame_io(handle, 1);
        }
        if (status->state == SND_PCM_STATE_PREPARED &&
-           str->setup.start_mode == SND_PCM_START_DATA) {
-               err = snd_pcm_stream_go(pcm, SND_PCM_STREAM_CAPTURE);
+           handle->setup.start_mode == SND_PCM_START_DATA) {
+               err = snd_pcm_go(handle);
                if (err < 0)
                        return err;
        }
        while (frames > 0) {
                ssize_t mmap_offset;
                size_t frames1;
-               int ready = snd_pcm_mmap_capture_ready(pcm);
+               int ready = snd_pcm_mmap_capture_ready(handle);
                if (ready < 0)
                        return ready;
                if (!ready) {
                        struct pollfd pfd;
                        if (status->state != SND_PCM_STATE_RUNNING)
                                return result > 0 ? result : -EPIPE;
-                       if (str->mode & SND_PCM_NONBLOCK)
+                       if (handle->mode & SND_PCM_NONBLOCK)
                                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;
                        ready = poll(&pfd, 1, 10000);
                        if (ready < 0)
                                return result > 0 ? result : ready;
                        if (ready && pfd.revents & POLLERR)
                                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);
-               mmap_offset = snd_pcm_mmap_frames_offset(pcm, SND_PCM_STREAM_CAPTURE);
-               snd_pcm_areas_copy(str->channels, mmap_offset, channels, offset, str->setup.format.channels, frames1, str->setup.format.format);
+               mmap_offset = snd_pcm_mmap_frames_offset(handle);
+               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 &&
-                   str->setup.xrun_mode == SND_PCM_XRUN_DRAIN)
+                   handle->setup.xrun_mode == SND_PCM_XRUN_DRAIN)
                        return result > 0 ? result : -EPIPE;
-               snd_pcm_stream_frame_data(pcm, SND_PCM_STREAM_CAPTURE, frames1);
+               snd_pcm_frame_data(handle, frames1);
                frames -= frames1;
                offset += 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;
 }
 
-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;
-       assert(pcm);
-       str = &pcm->stream[SND_PCM_STREAM_CAPTURE];
-       assert(str->mmap_data && str->mmap_status && str->mmap_control);
+       assert(handle);
+       assert(handle->mmap_data && handle->mmap_status && handle->mmap_control);
        assert(frames == 0 || buffer);
-       nchannels = str->setup.format.channels;
-       assert(str->setup.format.interleave || nchannels == 1);
+       nchannels = handle->setup.format.channels;
+       assert(handle->setup.format.interleave || nchannels == 1);
        {
                snd_pcm_channel_area_t channels[nchannels];
                unsigned int channel;
                for (channel = 0; channel < nchannels; ++channel) {
                        channels[channel].addr = (char*)buffer;
-                       channels[channel].first = str->bits_per_sample * channel;
-                       channels[channel].step = str->bits_per_frame;
+                       channels[channel].first = handle->bits_per_sample * channel;
+                       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;
        unsigned int nchannels;
-       assert(pcm);
-       str = &pcm->stream[SND_PCM_STREAM_CAPTURE];
-       assert(str->mmap_data && str->mmap_status && str->mmap_control);
+       assert(handle);
+       assert(handle->mmap_data && handle->mmap_status && handle->mmap_control);
        assert(vcount == 0 || vector);
-       nchannels = str->setup.format.channels;
-       if (str->setup.format.interleave) {
+       nchannels = handle->setup.format.channels;
+       if (handle->setup.format.interleave) {
                unsigned int b;
                for (b = 0; b < vcount; b++) {
                        ssize_t ret;
                        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 (result <= 0)
                                        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);
                                channels[v].addr = vector[v].iov_base;
                                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 (result <= 0)
                                        return ret;
@@ -470,64 +432,55 @@ ssize_t snd_pcm_mmap_readv(snd_pcm_t *pcm, const struct iovec *vector, unsigned
        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;
-       assert(pcm);
-       assert(stream >= 0 && stream <= 1);
-       str = &pcm->stream[stream];
-       assert(str->valid_setup);
-       if (str->mmap_status) {
+       assert(handle);
+       assert(handle->valid_setup);
+       if (handle->mmap_status) {
                if (status)
-                       *status = str->mmap_status;
+                       *status = handle->mmap_status;
                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;
        if (status)
-               *status = str->mmap_status;
+               *status = handle->mmap_status;
        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;
-       assert(pcm);
-       assert(stream >= 0 && stream <= 1);
-       str = &pcm->stream[stream];
-       assert(str->valid_setup);
-       if (str->mmap_control) {
+       assert(handle);
+       assert(handle->valid_setup);
+       if (handle->mmap_control) {
                if (control)
-                       *control = str->mmap_control;
+                       *control = handle->mmap_control;
                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;
        if (control)
-               *control = str->mmap_control;
+               *control = handle->mmap_control;
        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_area_t *a, *ap;
        unsigned int channel;
        int interleaved = 1, noninterleaved = 1;
        int err;
-       assert(pcm);
-       assert(stream >= 0 && stream <= 1);
-       str = &pcm->stream[stream];
-       assert(str->mmap_data);
-       a = calloc(str->setup.format.channels, sizeof(*areas));
-       for (channel = 0, ap = a; channel < str->setup.format.channels; ++channel, ++ap) {
+       assert(handle);
+       assert(handle->mmap_data);
+       a = calloc(handle->setup.format.channels, sizeof(*areas));
+       for (channel = 0, ap = a; channel < handle->setup.format.channels; ++channel, ++ap) {
                s.channel = channel;
-               err = snd_pcm_channel_setup(pcm, stream, &s);
+               err = snd_pcm_channel_setup(handle, &s);
                if (err < 0) {
                        free(a);
                        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)
                        areas[channel] = 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;
                if (ap->addr != a[0].addr || 
-                   ap->step != str->bits_per_frame || 
-                   ap->first != channel * str->bits_per_sample)
+                   ap->step != handle->bits_per_frame || 
+                   ap->first != channel * handle->bits_per_sample)
                        interleaved = 0;
        }
        if (noninterleaved)
-               str->mmap_type = _NONINTERLEAVED;
+               handle->mmap_type = _NONINTERLEAVED;
        else if (interleaved)
-               str->mmap_type = _INTERLEAVED;
+               handle->mmap_type = _INTERLEAVED;
        else
-               str->mmap_type = _COMPLEX;
-       str->channels = a;
+               handle->mmap_type = _COMPLEX;
+       handle->channels = a;
        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_stream_info_t info;
+       snd_pcm_info_t info;
        size_t bsize;
        int err;
-       assert(pcm);
-       assert(stream >= 0 && stream <= 1);
-       str = &pcm->stream[stream];
-       assert(str->valid_setup);
-       if (str->mmap_data) {
+       assert(handle);
+       assert(handle->valid_setup);
+       if (handle->mmap_data) {
                if (data)
-                       *data = str->mmap_data;
+                       *data = handle->mmap_data;
                return 0;
        }
 
-       info.stream = stream;
-       err = snd_pcm_stream_info(pcm, &info);
+       err = snd_pcm_info(handle, &info);
        if (err < 0)
                return err;
        bsize = info.mmap_size;
-       if (!(info.flags & SND_PCM_STREAM_INFO_MMAP))
+       if (!(info.flags & SND_PCM_INFO_MMAP))
                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;
        if (data) 
-               *data = str->mmap_data;
-       str->mmap_data_size = bsize;
-       err = snd_pcm_mmap_get_areas(pcm, stream, NULL);
+               *data = handle->mmap_data;
+       handle->mmap_data_size = bsize;
+       err = snd_pcm_mmap_get_areas(handle, NULL);
        if (err < 0)
                return err;
        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;
-       err = snd_pcm_mmap_status(pcm, stream, status);
+       err = snd_pcm_mmap_status(handle, status);
        if (err < 0)
                return err;
-       err = snd_pcm_mmap_control(pcm, stream, control);
+       err = snd_pcm_mmap_control(handle, control);
        if (err < 0) {
-               snd_pcm_munmap_status(pcm, stream);
+               snd_pcm_munmap_status(handle);
                return err;
        }
-       err = snd_pcm_mmap_data(pcm, stream, data);
+       err = snd_pcm_mmap_data(handle, data);
        if (err < 0) {
-               snd_pcm_munmap_status(pcm, stream);
-               snd_pcm_munmap_control(pcm, stream);
+               snd_pcm_munmap_status(handle);
+               snd_pcm_munmap_control(handle);
                return err;
        }
        return 0;
 }
 
-int snd_pcm_munmap_status(snd_pcm_t *pcm, int stream)
+int snd_pcm_munmap_status(snd_pcm_t *handle)
 {
        int err;
-       snd_pcm_stream_t *str;
-       assert(pcm);
-       assert(stream >= 0 && stream <= 1);
-       str = &pcm->stream[stream];
-       assert(str->mmap_status);
-       if ((err = pcm->ops->munmap_status(pcm, stream, str->mmap_status)) < 0)
+       assert(handle);
+       assert(handle->mmap_status);
+       if ((err = handle->ops->munmap_status(handle->op_arg, handle->mmap_status)) < 0)
                return err;
-       str->mmap_status = 0;
+       handle->mmap_status = 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;
-       snd_pcm_stream_t *str;
-       assert(pcm);
-       assert(stream >= 0 && stream <= 1);
-       str = &pcm->stream[stream];
-       assert(str->mmap_control);
-       if ((err = pcm->ops->munmap_control(pcm, stream, str->mmap_control)) < 0)
+       assert(handle);
+       assert(handle->mmap_control);
+       if ((err = handle->ops->munmap_control(handle->op_arg, handle->mmap_control)) < 0)
                return err;
-       str->mmap_control = 0;
+       handle->mmap_control = 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;
-       snd_pcm_stream_t *str;
-       assert(pcm);
-       assert(stream >= 0 && stream <= 1);
-       str = &pcm->stream[stream];
-       assert(str->mmap_data);
-       if ((err = pcm->ops->munmap_data(pcm, stream, str->mmap_data, str->mmap_data_size)) < 0)
+       assert(handle);
+       assert(handle->mmap_data);
+       if ((err = handle->ops->munmap_data(handle->op_arg, handle->mmap_data, handle->mmap_data_size)) < 0)
                return err;
-       free(str->channels);
-       str->channels = 0;
-       str->mmap_data = 0;
-       str->mmap_data_size = 0;
+       free(handle->channels);
+       handle->channels = 0;
+       handle->mmap_data = 0;
+       handle->mmap_data_size = 0;
        return 0;
 }
 
-int snd_pcm_munmap(snd_pcm_t *pcm, int stream)
+int snd_pcm_munmap(snd_pcm_t *handle)
 {
        int err;
-       err = snd_pcm_munmap_status(pcm, stream);
+       err = snd_pcm_munmap_status(handle);
        if (err < 0)
                return err;
-       err = snd_pcm_munmap_control(pcm, stream);
+       err = snd_pcm_munmap_control(handle);
        if (err < 0)
                return err;
-       return snd_pcm_munmap_data(pcm, stream);
+       return snd_pcm_munmap_data(handle);
 }