summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJaroslav Kysela <perex@perex.cz>2000-09-24 09:57:26 +0000
committerJaroslav Kysela <perex@perex.cz>2000-09-24 09:57:26 +0000
commit6962a9d6cef35b0bbbfc90c80584e6b2beac3841 (patch)
tree69e647500c337b71d262da26307416c7cfd8a2d8
parent40d1ee071dcc41fc12823d1169f993c2a2feb66f (diff)
downloadalsa-lib-6962a9d6cef35b0bbbfc90c80584e6b2beac3841.tar.gz
Merged pcmplug branch.
-rw-r--r--TODO4
-rw-r--r--acinclude.m42
-rw-r--r--include/aserver.h23
-rw-r--r--include/control.h2
-rw-r--r--include/header.h1
-rw-r--r--include/hwdep.h2
-rw-r--r--include/mixer.h2
-rw-r--r--include/pcm.h258
-rw-r--r--include/rawmidi.h2
-rw-r--r--include/seq.h2
-rw-r--r--include/timer.h2
-rw-r--r--src/Makefile.am2
-rw-r--r--src/aserver/aserver.c107
-rw-r--r--src/conf/conf.c14
-rw-r--r--src/control/control.c4
-rw-r--r--src/control/control_client.c4
-rw-r--r--src/control/control_hw.c4
-rw-r--r--src/control/control_local.h2
-rw-r--r--src/hwdep/hwdep.c2
-rw-r--r--src/mixer/mixer.c4
-rw-r--r--src/pcm/Makefile.am12
-rw-r--r--src/pcm/pcm.c1280
-rw-r--r--src/pcm/pcm_adpcm.c652
-rw-r--r--src/pcm/pcm_alaw.c519
-rw-r--r--src/pcm/pcm_client.c326
-rw-r--r--src/pcm/pcm_common.c1274
-rw-r--r--src/pcm/pcm_file.c447
-rw-r--r--src/pcm/pcm_hw.c296
-rw-r--r--src/pcm/pcm_linear.c360
-rw-r--r--src/pcm/pcm_local.h152
-rw-r--r--src/pcm/pcm_misc.c3
-rw-r--r--src/pcm/pcm_mmap.c676
-rw-r--r--src/pcm/pcm_mulaw.c536
-rw-r--r--src/pcm/pcm_multi.c662
-rw-r--r--src/pcm/pcm_plug.c1137
-rw-r--r--src/pcm/pcm_plugin.c394
-rw-r--r--src/pcm/pcm_plugin.h105
-rw-r--r--src/pcm/pcm_rate.c693
-rw-r--r--src/pcm/pcm_route.c963
-rw-r--r--src/pcm/plugin/Makefile.am8
-rw-r--r--src/pcm/plugin/adpcm.c417
-rw-r--r--src/pcm/plugin/alaw.c291
-rw-r--r--src/pcm/plugin/copy.c94
-rw-r--r--src/pcm/plugin/io.c161
-rw-r--r--src/pcm/plugin/linear.c161
-rw-r--r--src/pcm/plugin/mmap.c315
-rw-r--r--src/pcm/plugin/mulaw.c309
-rw-r--r--src/pcm/plugin/rate.c390
-rw-r--r--src/pcm/plugin/route.c621
-rw-r--r--src/pcm/plugin_ops.h (renamed from src/pcm/plugin/plugin_ops.h)0
-rw-r--r--src/rawmidi/rawmidi.c2
-rw-r--r--src/seq/seq.c2
-rw-r--r--src/timer/timer.c2
-rw-r--r--test/latency.c12
-rw-r--r--test/loopback.c2
-rw-r--r--test/pause.c6
-rw-r--r--test/pcm.c14
-rw-r--r--test/playmidi1.c4
-rw-r--r--test/seq-decoder.c2
-rw-r--r--test/seq-sender.c22
-rw-r--r--test/timer.c2
61 files changed, 7098 insertions, 6669 deletions
diff --git a/TODO b/TODO
index 99b87739..4f523d91 100644
--- a/TODO
+++ b/TODO
@@ -1,4 +1,4 @@
+H solve multi/server mmap'ing problem
+H add now_ptr stuff and fix appl_ptr seek
M add abstraction layer to timer, rawmidi, hwdep, seq
-M plug sync and pos problems
-M Loopback implementation?
L move OSS emulation to user space? (pseudo device driver and daemon)
diff --git a/acinclude.m4 b/acinclude.m4
index 59ef07e9..1bf50ad9 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -10,7 +10,7 @@ void main(void)
#if !defined(SND_PROTOCOL_VERSION) || !defined(SND_PROTOCOL_INCOMPATIBLE)
#error not found
#else
-#if !defined(SND_PCM_IOCTL_HW_PTR)
+#if !defined(SND_PCM_IOCTL_APPL_PTR)
#error wrong version
#endif
exit(0);
diff --git a/include/aserver.h b/include/aserver.h
index fb7164ed..aef553a8 100644
--- a/include/aserver.h
+++ b/include/aserver.h
@@ -19,13 +19,16 @@
*/
-#define SND_PCM_IOCTL_MMAP_DATA _IO ('A', 0xf0)
-#define SND_PCM_IOCTL_MMAP_CONTROL _IO ('A', 0xf1)
-#define SND_PCM_IOCTL_MMAP_STATUS _IO ('A', 0xf2)
-#define SND_PCM_IOCTL_MUNMAP_DATA _IO ('A', 0xf3)
-#define SND_PCM_IOCTL_MUNMAP_CONTROL _IO ('A', 0xf4)
-#define SND_PCM_IOCTL_MUNMAP_STATUS _IO ('A', 0xf5)
-#define SND_PCM_IOCTL_CLOSE _IO ('A', 0xf6)
+#define SND_PCM_IOCTL_STATE _IO ('A', 0xf0)
+#define SND_PCM_IOCTL_MMAP_DATA _IO ('A', 0xf1)
+#define SND_PCM_IOCTL_MMAP_CONTROL _IO ('A', 0xf2)
+#define SND_PCM_IOCTL_MMAP_STATUS _IO ('A', 0xf3)
+#define SND_PCM_IOCTL_MUNMAP_DATA _IO ('A', 0xf4)
+#define SND_PCM_IOCTL_MUNMAP_CONTROL _IO ('A', 0xf5)
+#define SND_PCM_IOCTL_MUNMAP_STATUS _IO ('A', 0xf6)
+#define SND_PCM_IOCTL_MMAP_FORWARD _IOW('A', 0xf7, size_t)
+#define SND_PCM_IOCTL_AVAIL_UPDATE _IO ('A', 0xf8)
+#define SND_PCM_IOCTL_CLOSE _IO ('A', 0xf9)
typedef struct {
int result;
@@ -36,6 +39,7 @@ typedef struct {
snd_pcm_params_info_t params_info;
snd_pcm_setup_t setup;
snd_pcm_status_t status;
+ ssize_t delay;
int pause;
snd_pcm_channel_info_t channel_info;
snd_pcm_channel_params_t channel_params;
@@ -43,10 +47,7 @@ typedef struct {
off_t appl_ptr;
int hw_ptr;
int link;
- snd_xfer_t read;
- snd_xfer_t write;
- snd_xferv_t readv;
- snd_xferv_t writev;
+ size_t mmap_forward;
} u;
char data[0];
} snd_pcm_client_shm_t;
diff --git a/include/control.h b/include/control.h
index f68b5ac0..07ad251e 100644
--- a/include/control.h
+++ b/include/control.h
@@ -42,7 +42,7 @@ int snd_ctl_client_open(snd_ctl_t **handlep, char *host, int port, int transport
snd_ctl_type_t snd_ctl_type(snd_ctl_t *handle);
int snd_ctl_open(snd_ctl_t **handle, char *name);
int snd_ctl_close(snd_ctl_t *handle);
-int snd_ctl_file_descriptor(snd_ctl_t *handle);
+int snd_ctl_poll_descriptor(snd_ctl_t *handle);
int snd_ctl_hw_info(snd_ctl_t *handle, snd_ctl_hw_info_t *info);
int snd_ctl_clist(snd_ctl_t *handle, snd_control_list_t * list);
int snd_ctl_cinfo(snd_ctl_t *handle, snd_control_info_t * sw);
diff --git a/include/header.h b/include/header.h
index 6c667bd2..6875e256 100644
--- a/include/header.h
+++ b/include/header.h
@@ -30,6 +30,7 @@
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
+#include <sys/uio.h>
#ifndef ATTRIBUTE_UNUSED
#define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
diff --git a/include/hwdep.h b/include/hwdep.h
index 81918192..6446543b 100644
--- a/include/hwdep.h
+++ b/include/hwdep.h
@@ -18,7 +18,7 @@ typedef struct snd_hwdep snd_hwdep_t;
int snd_hwdep_open(snd_hwdep_t **handle, int card, int device, int mode);
int snd_hwdep_close(snd_hwdep_t *handle);
-int snd_hwdep_file_descriptor(snd_hwdep_t *handle);
+int snd_hwdep_poll_descriptor(snd_hwdep_t *handle);
int snd_hwdep_block_mode(snd_hwdep_t *handle, int enable);
int snd_hwdep_info(snd_hwdep_t *handle, snd_hwdep_info_t * info);
int snd_hwdep_ioctl(snd_hwdep_t *handle, int request, void * arg);
diff --git a/include/mixer.h b/include/mixer.h
index 1daef64e..f7eab69b 100644
--- a/include/mixer.h
+++ b/include/mixer.h
@@ -13,7 +13,7 @@ extern "C" {
int snd_mixer_open(snd_mixer_t **handle, char *name);
int snd_mixer_close(snd_mixer_t *handle);
-int snd_mixer_file_descriptor(snd_mixer_t *handle);
+int snd_mixer_poll_descriptor(snd_mixer_t *handle);
#ifdef __cplusplus
}
diff --git a/include/pcm.h b/include/pcm.h
index 25a20e02..a559176e 100644
--- a/include/pcm.h
+++ b/include/pcm.h
@@ -98,18 +98,42 @@ static inline size_t bitset_count(bitset_t *bitset, size_t nbits)
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_CLIENT } snd_pcm_type_t;
+typedef enum {
+ SND_PCM_TYPE_HW,
+ SND_PCM_TYPE_MULTI,
+ SND_PCM_TYPE_FILE,
+ SND_PCM_TYPE_NULL,
+ SND_PCM_TYPE_CLIENT,
+ SND_PCM_TYPE_LINEAR,
+ SND_PCM_TYPE_ALAW,
+ SND_PCM_TYPE_MULAW,
+ SND_PCM_TYPE_ADPCM,
+ SND_PCM_TYPE_RATE,
+ SND_PCM_TYPE_ROUTE,
+ SND_PCM_TYPE_COPY,
+ SND_PCM_TYPE_PLUG,
+ SND_PCM_TYPE_DROUTE,
+ SND_PCM_TYPE_LBSERVER,
+} snd_pcm_type_t;
int snd_pcm_open(snd_pcm_t **handle, char *name,
int stream, int mode);
+/* Obsolete functions */
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);
+int snd_pcm_hw_open_device(snd_pcm_t **handle, int card, int device, int stream, int mode);
+int snd_pcm_plug_open_subdevice(snd_pcm_t **handle, int card, int device, int subdevice, int stream, int mode);
+int snd_pcm_plug_open_device(snd_pcm_t **handle, int card, int device, int stream, int mode);
+#define snd_pcm_write snd_pcm_writei
+#define snd_pcm_read snd_pcm_readi
+ssize_t snd_pcm_writev(snd_pcm_t *handle, const struct iovec *vector, int count);
+ssize_t snd_pcm_readv(snd_pcm_t *handle, const struct iovec *vector, int count);
+
snd_pcm_type_t snd_pcm_type(snd_pcm_t *handle);
int snd_pcm_close(snd_pcm_t *handle);
-int snd_pcm_file_descriptor(snd_pcm_t *handle);
+int snd_pcm_poll_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_params_info(snd_pcm_t *handle, snd_pcm_params_info_t *info);
@@ -120,65 +144,55 @@ int snd_pcm_channel_params(snd_pcm_t *handle, snd_pcm_channel_params_t *params);
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_drain(snd_pcm_t *handle);
+int snd_pcm_start(snd_pcm_t *handle);
+int snd_pcm_stop(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_hw_ptr(snd_pcm_t *handle, int update);
+int snd_pcm_delay(snd_pcm_t *handle, ssize_t *delayp);
+size_t snd_pcm_hw_ptr(snd_pcm_t *handle);
ssize_t snd_pcm_appl_ptr(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 *handle, const struct iovec *vector, unsigned long count);
-ssize_t snd_pcm_readv(snd_pcm_t *handle, const struct iovec *vector, unsigned long count);
+ssize_t snd_pcm_writei(snd_pcm_t *handle, const void *buffer, size_t size);
+ssize_t snd_pcm_readi(snd_pcm_t *handle, void *buffer, size_t size);
+ssize_t snd_pcm_writen(snd_pcm_t *handle, void **bufs, size_t size);
+ssize_t snd_pcm_readn(snd_pcm_t *handle, void **bufs, size_t size);
int snd_pcm_dump_setup(snd_pcm_t *handle, FILE *fp);
int snd_pcm_dump(snd_pcm_t *handle, FILE *fp);
+int snd_pcm_dump_status(snd_pcm_status_t *status, FILE *fp);
int snd_pcm_link(snd_pcm_t *handle1, snd_pcm_t *handle2);
int snd_pcm_unlink(snd_pcm_t *handle);
-int snd_pcm_channels_mask(snd_pcm_t *handle, bitset_t *client_vmask);
+int snd_pcm_channels_mask(snd_pcm_t *handle, bitset_t *cmask);
+int snd_pcm_wait(snd_pcm_t *pcm, int timeout);
+ssize_t snd_pcm_avail_update(snd_pcm_t *pcm);
+
/* 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_mmap(snd_pcm_t *handle, void **buffer);
int snd_pcm_munmap(snd_pcm_t *handle);
-int snd_pcm_mmap_state(snd_pcm_t *handle);
-ssize_t snd_pcm_mmap_hw_ptr(snd_pcm_t *handle);
-ssize_t snd_pcm_mmap_appl_ptr(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_avail(snd_pcm_t *handle, ssize_t *frames);
-ssize_t snd_pcm_mmap_xfer(snd_pcm_t *handle, size_t frames);
-ssize_t snd_pcm_mmap_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);
-
+ssize_t snd_pcm_mmap_forward(snd_pcm_t *pcm, size_t size);
+size_t snd_pcm_mmap_offset(snd_pcm_t *pcm);
+size_t snd_pcm_mmap_xfer(snd_pcm_t *pcm, size_t size);
+ssize_t snd_pcm_mmap_writei(snd_pcm_t *handle, const void *buffer, size_t size);
+ssize_t snd_pcm_mmap_readi(snd_pcm_t *handle, void *buffer, size_t size);
+ssize_t snd_pcm_mmap_writen(snd_pcm_t *handle, void **bufs, size_t size);
+ssize_t snd_pcm_mmap_readn(snd_pcm_t *handle, void **bufs, size_t size);
const char *snd_pcm_format_name(int format);
const char *snd_pcm_format_description(int format);
int snd_pcm_format_value(const char* name);
-int snd_pcm_area_silence(const snd_pcm_channel_area_t *dst_channel, size_t dst_offset,
+int snd_pcm_area_silence(snd_pcm_channel_area_t *dst_channel, size_t dst_offset,
size_t samples, int format);
-int snd_pcm_areas_silence(const snd_pcm_channel_area_t *dst_channels, size_t dst_offset,
+int snd_pcm_areas_silence(snd_pcm_channel_area_t *dst_channels, size_t dst_offset,
size_t vcount, size_t frames, int format);
-int snd_pcm_area_copy(const snd_pcm_channel_area_t *src_channel, size_t src_offset,
- const snd_pcm_channel_area_t *dst_channel, size_t dst_offset,
+int snd_pcm_area_copy(snd_pcm_channel_area_t *src_channel, size_t src_offset,
+ snd_pcm_channel_area_t *dst_channel, size_t dst_offset,
size_t samples, int format);
-int snd_pcm_areas_copy(const snd_pcm_channel_area_t *src_channels, size_t src_offset,
- const snd_pcm_channel_area_t *dst_channels, size_t dst_offset,
- size_t vcount, size_t frames, int format);
+int snd_pcm_areas_copy(snd_pcm_channel_area_t *src_channels, size_t src_offset,
+ snd_pcm_channel_area_t *dst_channels, size_t dst_offset,
+ size_t channels, size_t frames, int format);
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);
@@ -207,165 +221,3 @@ ssize_t snd_pcm_format_set_silence(int format, void *buf, size_t count);
}
#endif
-/*
- * PCM Plug-In interface
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct snd_stru_pcm_plugin snd_pcm_plugin_t;
-#define snd_pcm_plug_t struct snd_pcm_plug
-
-typedef enum {
- INIT = 0,
- PREPARE = 1,
- DRAIN = 2,
- FLUSH = 3,
- PAUSE = 4,
-} snd_pcm_plugin_action_t;
-
-typedef struct snd_stru_pcm_plugin_channel {
- snd_pcm_channel_area_t area;
- unsigned int enabled:1; /* channel need to be processed */
- unsigned int wanted:1; /* channel is wanted */
-} snd_pcm_plugin_channel_t;
-
-struct snd_stru_pcm_plugin {
- char *name; /* plug-in name */
- int stream;
- snd_pcm_format_t src_format; /* source format */
- snd_pcm_format_t dst_format; /* destination format */
- int src_width; /* sample width in bits */
- int dst_width; /* sample width in bits */
- ssize_t (*src_frames)(snd_pcm_plugin_t *plugin, size_t dst_frames);
- ssize_t (*dst_frames)(snd_pcm_plugin_t *plugin, size_t src_frames);
- ssize_t (*client_channels)(snd_pcm_plugin_t *plugin,
- size_t frames,
- snd_pcm_plugin_channel_t **channels);
- int (*src_channels_mask)(snd_pcm_plugin_t *plugin,
- bitset_t *dst_vmask,
- bitset_t **src_vmask);
- int (*dst_channels_mask)(snd_pcm_plugin_t *plugin,
- bitset_t *src_vmask,
- bitset_t **dst_vmask);
- ssize_t (*transfer)(snd_pcm_plugin_t *plugin,
- const snd_pcm_plugin_channel_t *src_channels,
- snd_pcm_plugin_channel_t *dst_channels,
- size_t frames);
- int (*action)(snd_pcm_plugin_t *plugin,
- snd_pcm_plugin_action_t action,
- unsigned long data);
- int (*parameter_set)(snd_pcm_plugin_t *plugin,
- const char *name,
- unsigned long value);
- int (*parameter_get)(snd_pcm_plugin_t *plugin,
- const char *name,
- unsigned long *value);
- void (*dump)(snd_pcm_plugin_t *plugin, FILE *fp);
- snd_pcm_plugin_t *prev;
- snd_pcm_plugin_t *next;
- snd_pcm_plug_t *plug;
- void *private_data;
- void (*private_free)(snd_pcm_plugin_t *plugin);
- 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_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_plugin_insert(snd_pcm_plugin_t *plugin);
-int snd_pcm_plugin_append(snd_pcm_plugin_t *plugin);
-void snd_pcm_plugin_dump(snd_pcm_plugin_t *plugin, FILE *fp);
-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_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_plug_t *plug,
- snd_pcm_format_t *format,
- snd_pcm_plugin_t **r_plugin);
-int snd_pcm_plugin_build_mmap(snd_pcm_plug_t *plug,
- snd_pcm_format_t *format,
- snd_pcm_plugin_t **r_plugin);
-
-#define ROUTE_PLUGIN_USE_FLOAT 1
-#if ROUTE_PLUGIN_USE_FLOAT
-#define FULL 1.0
-#define HALF 0.5
-typedef float route_ttable_entry_t;
-#else
-#define FULL ROUTE_PLUGIN_RESOLUTION
-#define HALF ROUTE_PLUGIN_RESOLUTION / 2
-typedef int route_ttable_entry_t;
-#endif
-
-/* conversion plugins */
-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_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_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_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_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_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_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_plug_t *plug,
- snd_pcm_format_t *src_format,
- snd_pcm_format_t *dst_format,
- snd_pcm_plugin_t **r_plugin);
-
-int snd_pcm_multi_create(snd_pcm_t **handlep, size_t slaves_count,
- snd_pcm_t **slaves_handle, size_t *slaves_channels_count,
- size_t binds_count, unsigned int *binds_client_channel,
- unsigned int *binds_slave, unsigned int *binds_slave_channel,
- int close_slaves);
-
-int snd_pcm_client_create(snd_pcm_t **handlep, char *host, int port, int transport, char *name, int stream, int mode);
-
-#ifdef __cplusplus
-}
-#endif
-
diff --git a/include/rawmidi.h b/include/rawmidi.h
index 087b8821..5bdab976 100644
--- a/include/rawmidi.h
+++ b/include/rawmidi.h
@@ -20,7 +20,7 @@ typedef struct snd_rawmidi snd_rawmidi_t;
int snd_rawmidi_open(snd_rawmidi_t **handle, int card, int device, int mode);
int snd_rawmidi_close(snd_rawmidi_t *handle);
-int snd_rawmidi_file_descriptor(snd_rawmidi_t *handle);
+int snd_rawmidi_poll_descriptor(snd_rawmidi_t *handle);
int snd_rawmidi_block_mode(snd_rawmidi_t *handle, int enable);
int snd_rawmidi_info(snd_rawmidi_t *handle, snd_rawmidi_info_t * info);
int snd_rawmidi_stream_params(snd_rawmidi_t *handle, snd_rawmidi_params_t * params);
diff --git a/include/seq.h b/include/seq.h
index 7e358060..3bd4989d 100644
--- a/include/seq.h
+++ b/include/seq.h
@@ -17,7 +17,7 @@ typedef struct snd_seq snd_seq_t;
int snd_seq_open(snd_seq_t **handle, int mode);
int snd_seq_close(snd_seq_t *handle);
-int snd_seq_file_descriptor(snd_seq_t *handle);
+int snd_seq_poll_descriptor(snd_seq_t *handle);
int snd_seq_block_mode(snd_seq_t *handle, int enable);
int snd_seq_client_id(snd_seq_t *handle);
int snd_seq_output_buffer_size(snd_seq_t *handle);
diff --git a/include/timer.h b/include/timer.h
index 49c69437..a406d9c0 100644
--- a/include/timer.h
+++ b/include/timer.h
@@ -13,7 +13,7 @@ typedef struct snd_timer snd_timer_t;
int snd_timer_open(snd_timer_t **handle);
int snd_timer_close(snd_timer_t *handle);
-int snd_timer_file_descriptor(snd_timer_t *handle);
+int snd_timer_poll_descriptor(snd_timer_t *handle);
int snd_timer_general_info(snd_timer_t *handle, snd_timer_general_info_t * info);
int snd_timer_select(snd_timer_t *handle, snd_timer_select_t *tselect);
int snd_timer_info(snd_timer_t *handle, snd_timer_info_t *timer);
diff --git a/src/Makefile.am b/src/Makefile.am
index 60eb8612..c6985ed6 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -6,7 +6,7 @@ libasound_la_SOURCES = error.c
libasound_la_LIBADD = control/libcontrol.la mixer/libmixer.la pcm/libpcm.la \
rawmidi/librawmidi.la timer/libtimer.la \
hwdep/libhwdep.la seq/libseq.la instr/libinstr.la \
- compat/libcompat.la conf/libconf.la
+ compat/libcompat.la conf/libconf.la -ldl
libasound_la_LDFLAGS = -version-info $(COMPATNUM)
diff --git a/src/aserver/aserver.c b/src/aserver/aserver.c
index a4e7449b..4a77a952 100644
--- a/src/aserver/aserver.c
+++ b/src/aserver/aserver.c
@@ -287,7 +287,7 @@ int pcm_shm_open(client_t *client, int *cookie)
if (err < 0)
return err;
client->device.pcm.handle = pcm;
- client->device.pcm.fd = snd_pcm_file_descriptor(pcm);
+ client->device.pcm.fd = snd_pcm_poll_descriptor(pcm);
shmid = shmget(IPC_PRIVATE, PCM_SHM_SIZE, 0666);
if (shmid < 0) {
@@ -368,20 +368,26 @@ int pcm_shm_cmd(client_t *client)
case SND_PCM_IOCTL_STATUS:
ctrl->result = snd_pcm_status(pcm, &ctrl->u.status);
break;
- case SND_PCM_IOCTL_HW_PTR:
- ctrl->result = snd_pcm_hw_ptr(pcm, ctrl->u.hw_ptr);
+ case SND_PCM_IOCTL_STATE:
+ ctrl->result = snd_pcm_state(pcm);
+ break;
+ case SND_PCM_IOCTL_DELAY:
+ ctrl->result = snd_pcm_delay(pcm, &ctrl->u.delay);
+ break;
+ case SND_PCM_IOCTL_AVAIL_UPDATE:
+ ctrl->result = snd_pcm_avail_update(pcm);
break;
case SND_PCM_IOCTL_PREPARE:
ctrl->result = snd_pcm_prepare(pcm);
break;
- case SND_PCM_IOCTL_GO:
- ctrl->result = snd_pcm_go(pcm);
+ case SND_PCM_IOCTL_START:
+ ctrl->result = snd_pcm_start(pcm);
break;
case SND_PCM_IOCTL_FLUSH:
ctrl->result = snd_pcm_flush(pcm);
break;
- case SND_PCM_IOCTL_DRAIN:
- ctrl->result = snd_pcm_drain(pcm);
+ case SND_PCM_IOCTL_STOP:
+ ctrl->result = snd_pcm_stop(pcm);
break;
case SND_PCM_IOCTL_PAUSE:
ctrl->result = snd_pcm_pause(pcm, ctrl->u.pause);
@@ -395,86 +401,6 @@ int pcm_shm_cmd(client_t *client)
case SND_PCM_IOCTL_CHANNEL_SETUP:
ctrl->result = snd_pcm_channel_setup(pcm, &ctrl->u.channel_setup);
break;
- case SND_PCM_IOCTL_WRITE_FRAMES:
- {
- size_t maxsize = PCM_SHM_DATA_MAXLEN;
- maxsize = snd_pcm_bytes_to_frames(pcm, maxsize);
- if (ctrl->u.write.count > maxsize) {
- ctrl->result = -EFAULT;
- break;
- }
- /* FIXME: blocking */
- ctrl->result = snd_pcm_write(pcm, ctrl->data, ctrl->u.write.count);
- break;
- }
- case SND_PCM_IOCTL_READ_FRAMES:
- {
- size_t maxsize = PCM_SHM_DATA_MAXLEN;
- maxsize = snd_pcm_bytes_to_frames(pcm, maxsize);
- if (ctrl->u.read.count > maxsize) {
- ctrl->result = -EFAULT;
- break;
- }
- /* FIXME: blocking */
- ctrl->result = snd_pcm_read(pcm, ctrl->data, ctrl->u.read.count);
- break;
- }
- case SND_PCM_IOCTL_WRITEV_FRAMES:
- {
- /* FIXME: interleaved */
- size_t maxsize = PCM_SHM_DATA_MAXLEN;
- unsigned long k;
- struct iovec *vector;
- size_t vecsize;
- char *base;
- int bits_per_sample = snd_pcm_samples_to_bytes(pcm, 8);
- vecsize = ctrl->u.writev.count * sizeof(struct iovec);
- if (vecsize > maxsize) {
- ctrl->result = -EFAULT;
- break;
- }
- maxsize -= vecsize;
- vector = (struct iovec *) ctrl->data;
- base = ctrl->data + vecsize;
- for (k = 0; k < ctrl->u.writev.count; ++k) {
- unsigned long ofs = (unsigned long) vector[k].iov_base;
- size_t len = vector[k].iov_len * bits_per_sample / 8;
- if (ofs + len > maxsize)
- return -EFAULT;
- vector[k].iov_base = base + ofs;
- }
- /* FIXME: blocking */
- ctrl->result = snd_pcm_writev(pcm, vector, ctrl->u.writev.count);
- break;
- }
- case SND_PCM_IOCTL_READV_FRAMES:
- {
- /* FIXME: interleaved */
- size_t maxsize = PCM_SHM_DATA_MAXLEN;
- unsigned long k;
- struct iovec *vector;
- size_t vecsize;
- char *base;
- int bits_per_sample = snd_pcm_samples_to_bytes(pcm, 8);
- vecsize = ctrl->u.readv.count * sizeof(struct iovec);
- if (vecsize > maxsize) {
- ctrl->result = -EFAULT;
- break;
- }
- maxsize -= vecsize;
- vector = (struct iovec *) ctrl->data;
- base = ctrl->data + vecsize;
- for (k = 0; k < ctrl->u.readv.count; ++k) {
- unsigned long ofs = (unsigned long) vector[k].iov_base;
- size_t len = vector[k].iov_len * bits_per_sample / 8;
- if (ofs + len > maxsize)
- return -EFAULT;
- vector[k].iov_base = base + ofs;
- }
- /* FIXME: blocking */
- ctrl->result = snd_pcm_readv(pcm, vector, ctrl->u.readv.count);
- break;
- }
case SND_PCM_IOCTL_APPL_PTR:
ctrl->result = snd_pcm_appl_ptr(pcm, ctrl->u.appl_ptr);
break;
@@ -510,13 +436,14 @@ int pcm_shm_cmd(client_t *client)
ctrl->result = 0;
return 0;
}
-#if 0
case SND_PCM_IOCTL_MUNMAP_DATA:
case SND_PCM_IOCTL_MUNMAP_CONTROL:
case SND_PCM_IOCTL_MUNMAP_STATUS:
ctrl->result = 0;
break;
-#endif
+ case SND_PCM_IOCTL_MMAP_FORWARD:
+ ctrl->result = snd_pcm_mmap_forward(pcm, ctrl->u.mmap_forward);
+ break;
case SND_PCM_IOCTL_CLOSE:
client->ops->close(client);
break;
@@ -571,7 +498,7 @@ int ctl_shm_open(client_t *client, int *cookie)
if (err < 0)
return err;
client->device.control.handle = ctl;
- client->device.control.fd = snd_ctl_file_descriptor(ctl);
+ client->device.control.fd = snd_ctl_poll_descriptor(ctl);
shmid = shmget(IPC_PRIVATE, CTL_SHM_SIZE, 0666);
if (shmid < 0) {
diff --git a/src/conf/conf.c b/src/conf/conf.c
index 4607b6d5..de4e6bfb 100644
--- a/src/conf/conf.c
+++ b/src/conf/conf.c
@@ -186,7 +186,7 @@ static int get_quotedchar(input_t *input)
}
}
-static int get_freestring(char **string, input_t *input)
+static int get_freestring(char **string, int id, input_t *input)
{
const size_t bufsize = 256;
char _buf[bufsize];
@@ -197,13 +197,15 @@ static int get_freestring(char **string, input_t *input)
while (1) {
c = get_char(input);
switch (c) {
+ case '.':
+ if (!id)
+ break;
case ' ':
case '\f':
case '\t':
case '\n':
case '\r':
case EOF:
- case '.':
case '=':
case '{':
case '}':
@@ -283,7 +285,7 @@ static int get_delimstring(char **string, int delim, input_t *input)
}
/* Return 0 for free string, 1 for delimited string */
-static int get_string(char **string, input_t *input)
+static int get_string(char **string, int id, input_t *input)
{
int c = get_nonwhite(input);
int err;
@@ -312,7 +314,7 @@ static int get_string(char **string, input_t *input)
return 1;
default:
unget_char(c, input);
- err = get_freestring(string, input);
+ err = get_freestring(string, id, input);
if (err < 0)
return err;
return 0;
@@ -401,7 +403,7 @@ static int parse_def(snd_config_t *father, input_t *input)
#else
mode = MERGE;
#endif
- err = get_string(&id, input);
+ err = get_string(&id, 1, input);
if (err < 0)
return err;
c = get_nonwhite(input);
@@ -472,7 +474,7 @@ static int parse_def(snd_config_t *father, input_t *input)
{
char *s;
unget_char(c, input);
- err = get_string(&s, input);
+ err = get_string(&s, 0, input);
if (err < 0)
return err;
if (!err && ((s[0] >= '0' && s[0] <= '9') || s[0] == '-')) {
diff --git a/src/control/control.c b/src/control/control.c
index bfd38045..2ed0f38b 100644
--- a/src/control/control.c
+++ b/src/control/control.c
@@ -43,10 +43,10 @@ int snd_ctl_close(snd_ctl_t *ctl)
return res;
}
-int snd_ctl_file_descriptor(snd_ctl_t *ctl)
+int snd_ctl_poll_descriptor(snd_ctl_t *ctl)
{
assert(ctl);
- return ctl->ops->file_descriptor(ctl);
+ return ctl->ops->poll_descriptor(ctl);
}
int snd_ctl_hw_info(snd_ctl_t *ctl, snd_ctl_hw_info_t *info)
diff --git a/src/control/control_client.c b/src/control/control_client.c
index 264f4b3a..ef323e60 100644
--- a/src/control/control_client.c
+++ b/src/control/control_client.c
@@ -101,7 +101,7 @@ static int snd_ctl_client_shm_close(snd_ctl_t *ctl)
return result;
}
-static int snd_ctl_client_file_descriptor(snd_ctl_t *ctl)
+static int snd_ctl_client_poll_descriptor(snd_ctl_t *ctl)
{
snd_ctl_client_t *client = ctl->private;
return client->data_fd;
@@ -255,7 +255,7 @@ static int snd_ctl_client_shm_read(snd_ctl_t *ctl, snd_ctl_event_t *event)
struct snd_ctl_ops snd_ctl_client_ops = {
close: snd_ctl_client_shm_close,
- file_descriptor: snd_ctl_client_file_descriptor,
+ poll_descriptor: snd_ctl_client_poll_descriptor,
hw_info: snd_ctl_client_shm_hw_info,
clist: snd_ctl_client_shm_clist,
cinfo: snd_ctl_client_shm_cinfo,
diff --git a/src/control/control_hw.c b/src/control/control_hw.c
index 496ce220..8ca8b8b5 100644
--- a/src/control/control_hw.c
+++ b/src/control/control_hw.c
@@ -48,7 +48,7 @@ static int snd_ctl_hw_close(snd_ctl_t *handle)
return res;
}
-static int snd_ctl_hw_file_descriptor(snd_ctl_t *handle)
+static int snd_ctl_hw_poll_descriptor(snd_ctl_t *handle)
{
snd_ctl_hw_t *hw = handle->private;
return hw->fd;
@@ -134,7 +134,7 @@ static int snd_ctl_hw_read(snd_ctl_t *handle, snd_ctl_event_t *event)
struct snd_ctl_ops snd_ctl_hw_ops = {
close: snd_ctl_hw_close,
- file_descriptor: snd_ctl_hw_file_descriptor,
+ poll_descriptor: snd_ctl_hw_poll_descriptor,
hw_info: snd_ctl_hw_hw_info,
clist: snd_ctl_hw_clist,
cinfo: snd_ctl_hw_cinfo,
diff --git a/src/control/control_local.h b/src/control/control_local.h
index d396df5a..cf1a5828 100644
--- a/src/control/control_local.h
+++ b/src/control/control_local.h
@@ -25,7 +25,7 @@
struct snd_ctl_ops {
int (*close)(snd_ctl_t *handle);
- int (*file_descriptor)(snd_ctl_t *handle);
+ int (*poll_descriptor)(snd_ctl_t *handle);
int (*hw_info)(snd_ctl_t *handle, snd_ctl_hw_info_t *info);
int (*clist)(snd_ctl_t *handle, snd_control_list_t *list);
int (*cinfo)(snd_ctl_t *handle, snd_control_info_t *info);
diff --git a/src/hwdep/hwdep.c b/src/hwdep/hwdep.c
index dfcbb936..e6440536 100644
--- a/src/hwdep/hwdep.c
+++ b/src/hwdep/hwdep.c
@@ -86,7 +86,7 @@ int snd_hwdep_close(snd_hwdep_t *hwdep)
return res;
}
-int snd_hwdep_file_descriptor(snd_hwdep_t *hwdep)
+int snd_hwdep_poll_descriptor(snd_hwdep_t *hwdep)
{
if (!hwdep)
return -EINVAL;
diff --git a/src/mixer/mixer.c b/src/mixer/mixer.c
index ed22bf34..b534ffdb 100644
--- a/src/mixer/mixer.c
+++ b/src/mixer/mixer.c
@@ -77,11 +77,11 @@ int snd_mixer_close(snd_mixer_t *handle)
return err;
}
-int snd_mixer_file_descriptor(snd_mixer_t *handle)
+int snd_mixer_poll_descriptor(snd_mixer_t *handle)
{
if (handle == NULL || handle->ctl_handle == NULL)
return -EIO;
- return snd_ctl_file_descriptor(handle->ctl_handle);
+ return snd_ctl_poll_descriptor(handle->ctl_handle);
}
const char *snd_mixer_simple_channel_name(int channel)
diff --git a/src/pcm/Makefile.am b/src/pcm/Makefile.am
index f08c8369..82da9063 100644
--- a/src/pcm/Makefile.am
+++ b/src/pcm/Makefile.am
@@ -1,15 +1,11 @@
-SUBDIRS = plugin
EXTRA_LTLIBRARIES = libpcm.la
-libpcm_la_SOURCES = pcm.c pcm_hw.c pcm_plug.c pcm_common.c \
- pcm_misc.c pcm_mmap.c pcm_multi.c pcm_client.c
-libpcm_la_LIBADD = plugin/libpcmplugin.la
-noinst_HEADERS = pcm_local.h
+libpcm_la_SOURCES = pcm.c pcm_hw.c pcm_plugin.c pcm_linear.c pcm_route.c \
+ pcm_mulaw.c pcm_alaw.c pcm_adpcm.c pcm_rate.c pcm_plug.c \
+ pcm_misc.c pcm_mmap.c pcm_multi.c pcm_client.c pcm_file.c
+noinst_HEADERS = pcm_local.h pcm_plugin.h
all: libpcm.la
-plugin/libpcmplugin.la:
- $(MAKE) -C plugin libpcmplugin.la
-
INCLUDES=-I$(top_srcdir)/include
diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c
index 82a7a218..fbf8bff7 100644
--- a/src/pcm/pcm.c
+++ b/src/pcm/pcm.c
@@ -25,256 +25,287 @@
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/poll.h>
-#include <sys/uio.h>
+#include <dlfcn.h>
#include "pcm_local.h"
#include "list.h"
-snd_pcm_type_t snd_pcm_type(snd_pcm_t *handle)
+int snd_pcm_init(snd_pcm_t *pcm)
{
- assert(handle);
- return handle->type;
+ int err;
+ err = snd_pcm_mmap_status(pcm, NULL);
+ if (err < 0)
+ return err;
+ err = snd_pcm_mmap_control(pcm, NULL);
+ if (err < 0)
+ return err;
+ return 0;
+}
+
+snd_pcm_type_t snd_pcm_type(snd_pcm_t *pcm)
+{
+ assert(pcm);
+ return pcm->type;
}
-snd_pcm_type_t snd_pcm(snd_pcm_t *handle)
+snd_pcm_type_t snd_pcm(snd_pcm_t *pcm)
{
- assert(handle);
- return handle->stream;
+ assert(pcm);
+ return pcm->stream;
}
-int snd_pcm_close(snd_pcm_t *handle)
+int snd_pcm_close(snd_pcm_t *pcm)
{
int ret = 0;
int err;
- assert(handle);
- if (handle->mmap_status) {
- if ((err = snd_pcm_munmap_status(handle)) < 0)
+ assert(pcm);
+ if (pcm->mmap_status) {
+ if ((err = snd_pcm_munmap_status(pcm)) < 0)
ret = err;
}
- if (handle->mmap_control) {
- if ((err = snd_pcm_munmap_control(handle)) < 0)
+ if (pcm->mmap_control) {
+ if ((err = snd_pcm_munmap_control(pcm)) < 0)
ret = err;
}
- if (handle->mmap_data) {
- if ((err = snd_pcm_munmap_data(handle)) < 0)
+ if (pcm->mmap_data) {
+ if ((err = snd_pcm_munmap_data(pcm)) < 0)
ret = err;
}
- if ((err = handle->ops->close(handle->op_arg)) < 0)
+ if ((err = pcm->ops->close(pcm->op_arg)) < 0)
ret = err;
- handle->valid_setup = 0;
- free(handle);
+ pcm->valid_setup = 0;
+ free(pcm);
return ret;
}
-int snd_pcm_nonblock(snd_pcm_t *handle, int nonblock)
+int snd_pcm_nonblock(snd_pcm_t *pcm, int nonblock)
{
int err;
- assert(handle);
- if ((err = handle->fast_ops->nonblock(handle->fast_op_arg, nonblock)) < 0)
+ assert(pcm);
+ if ((err = pcm->ops->nonblock(pcm->fast_op_arg, nonblock)) < 0)
return err;
if (nonblock)
- handle->mode |= SND_PCM_NONBLOCK;
+ pcm->mode |= SND_PCM_NONBLOCK;
else
- handle->mode &= ~SND_PCM_NONBLOCK;
+ pcm->mode &= ~SND_PCM_NONBLOCK;
return 0;
}
-int snd_pcm_info(snd_pcm_t *handle, snd_pcm_info_t *info)
+int snd_pcm_info(snd_pcm_t *pcm, snd_pcm_info_t *info)
{
- assert(handle && info);
- return handle->ops->info(handle->op_arg, info);
+ assert(pcm && info);
+ return pcm->ops->info(pcm->op_arg, info);
}
-int snd_pcm_params_info(snd_pcm_t *handle, snd_pcm_params_info_t *info)
+int snd_pcm_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t *info)
{
- assert(handle && info);
- return handle->ops->params_info(handle->op_arg, info);
+ assert(pcm && info);
+ return pcm->ops->params_info(pcm->op_arg, info);
}
-int snd_pcm_setup(snd_pcm_t *handle, snd_pcm_setup_t *setup)
+int snd_pcm_setup(snd_pcm_t *pcm, snd_pcm_setup_t *setup)
{
int err;
- assert(handle && setup);
- if (handle->valid_setup) {
- *setup = handle->setup;
+ assert(pcm && setup);
+ if (pcm->valid_setup) {
+ *setup = pcm->setup;
return 0;
}
- if ((err = handle->ops->setup(handle->op_arg, &handle->setup)) < 0)
+ if ((err = pcm->ops->setup(pcm->op_arg, &pcm->setup)) < 0)
return err;
- *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;
+ *setup = pcm->setup;
+ pcm->bits_per_sample = snd_pcm_format_physical_width(setup->format.sfmt);
+ pcm->bits_per_frame = pcm->bits_per_sample * setup->format.channels;
+ pcm->valid_setup = 1;
return 0;
}
-int snd_pcm_channel_info(snd_pcm_t *handle, snd_pcm_channel_info_t *info)
+int snd_pcm_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info)
{
- assert(handle && info);
- return handle->fast_ops->channel_info(handle->fast_op_arg, info);
+ assert(pcm && info);
+ assert(pcm->valid_setup);
+ assert(info->channel < pcm->setup.format.channels);
+ return pcm->ops->channel_info(pcm->op_arg, info);
}
-int snd_pcm_channel_params(snd_pcm_t *handle, snd_pcm_channel_params_t *params)
+int snd_pcm_channel_params(snd_pcm_t *pcm, snd_pcm_channel_params_t *params)
{
- assert(handle && params);
- return handle->fast_ops->channel_params(handle->fast_op_arg, params);
+ assert(pcm && params);
+ assert(pcm->valid_setup);
+ assert(params->channel < pcm->setup.format.channels);
+ return pcm->ops->channel_params(pcm->op_arg, params);
}
-int snd_pcm_channel_setup(snd_pcm_t *handle, snd_pcm_channel_setup_t *setup)
+int snd_pcm_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t *setup)
{
- assert(handle && setup);
- assert(handle->valid_setup);
- return handle->fast_ops->channel_setup(handle->fast_op_arg, setup);
+ assert(pcm && setup);
+ assert(pcm->valid_setup);
+ assert(setup->channel < pcm->setup.format.channels);
+ return pcm->ops->channel_setup(pcm->op_arg, setup);
}
-int snd_pcm_params(snd_pcm_t *handle, snd_pcm_params_t *params)
+int snd_pcm_params(snd_pcm_t *pcm, snd_pcm_params_t *params)
{
int err;
snd_pcm_setup_t setup;
- assert(handle && params);
- assert(!handle->mmap_data);
- if ((err = handle->ops->params(handle->op_arg, params)) < 0)
+ assert(pcm && params);
+ assert(!pcm->mmap_data);
+ if ((err = pcm->ops->params(pcm->op_arg, params)) < 0)
return err;
- handle->valid_setup = 0;
- return snd_pcm_setup(handle, &setup);
+ pcm->valid_setup = 0;
+ return snd_pcm_setup(pcm, &setup);
}
-int snd_pcm_status(snd_pcm_t *handle, snd_pcm_status_t *status)
+int snd_pcm_status(snd_pcm_t *pcm, snd_pcm_status_t *status)
{
- assert(handle && status);
- return handle->fast_ops->status(handle->fast_op_arg, status);
+ assert(pcm && status);
+ return pcm->fast_ops->status(pcm->fast_op_arg, status);
}
-int snd_pcm_state(snd_pcm_t *handle)
+int snd_pcm_state(snd_pcm_t *pcm)
{
- assert(handle);
- if (handle->mmap_status)
- return handle->mmap_status->state;
- return handle->fast_ops->state(handle->fast_op_arg);
+ assert(pcm);
+ return pcm->fast_ops->state(pcm->fast_op_arg);
}
-ssize_t snd_pcm_hw_ptr(snd_pcm_t *handle, int update)
+int snd_pcm_delay(snd_pcm_t *pcm, ssize_t *delayp)
{
- assert(handle);
- assert(handle->valid_setup);
- if (handle->mmap_status && !update)
- return handle->mmap_status->hw_ptr;
- return handle->fast_ops->hw_ptr(handle->fast_op_arg, update);
+ assert(pcm);
+ return pcm->fast_ops->delay(pcm->fast_op_arg, delayp);
}
-int snd_pcm_prepare(snd_pcm_t *handle)
+int snd_pcm_prepare(snd_pcm_t *pcm)
{
- assert(handle);
- return handle->fast_ops->prepare(handle->fast_op_arg);
+ assert(pcm);
+ return pcm->fast_ops->prepare(pcm->fast_op_arg);
}
-int snd_pcm_go(snd_pcm_t *handle)
+int snd_pcm_start(snd_pcm_t *pcm)
{
- assert(handle);
- return handle->fast_ops->go(handle->fast_op_arg);
+ assert(pcm);
+ return pcm->fast_ops->start(pcm->fast_op_arg);
}
-int snd_pcm_drain(snd_pcm_t *handle)
+int snd_pcm_stop(snd_pcm_t *pcm)
{
- assert(handle);
- return handle->fast_ops->drain(handle->fast_op_arg);
+ assert(pcm);
+ return pcm->fast_ops->stop(pcm->fast_op_arg);
}
-int snd_pcm_flush(snd_pcm_t *handle)
+int snd_pcm_flush(snd_pcm_t *pcm)
{
- assert(handle);
- return handle->fast_ops->flush(handle->fast_op_arg);
+ assert(pcm);
+ return pcm->fast_ops->flush(pcm->fast_op_arg);
}
-int snd_pcm_pause(snd_pcm_t *handle, int enable)
+int snd_pcm_pause(snd_pcm_t *pcm, int enable)
{
- assert(handle);
- return handle->fast_ops->pause(handle->fast_op_arg, enable);
+ assert(pcm);
+ return pcm->fast_ops->pause(pcm->fast_op_arg, enable);
}
-ssize_t snd_pcm_appl_ptr(snd_pcm_t *handle, off_t offset)
+ssize_t snd_pcm_appl_ptr(snd_pcm_t *pcm, off_t offset)
{
- assert(handle);
- assert(handle->valid_setup);
- if (handle->mmap_control) {
+ assert(pcm);
+ assert(pcm->valid_setup);
+ if (pcm->mmap_control) {
if (offset == 0)
- return handle->mmap_control->appl_ptr;
+ return pcm->mmap_control->appl_ptr;
}
- return handle->fast_ops->appl_ptr(handle->fast_op_arg, offset);
+ return pcm->fast_ops->appl_ptr(pcm->fast_op_arg, offset);
}
-ssize_t snd_pcm_write(snd_pcm_t *handle, const void *buffer, size_t size)
+ssize_t snd_pcm_writei(snd_pcm_t *pcm, const void *buffer, size_t size)
{
- assert(handle);
+ assert(pcm);
assert(size == 0 || buffer);
- assert(handle->valid_setup);
- assert(size % handle->setup.align == 0);
- return handle->fast_ops->write(handle->fast_op_arg, 0, buffer, size);
+ assert(pcm->valid_setup);
+ assert(pcm->setup.xfer_mode == SND_PCM_XFER_INTERLEAVED);
+ assert(!pcm->mmap_data);
+ return pcm->fast_ops->writei(pcm->fast_op_arg, buffer, size);
}
-ssize_t snd_pcm_writev(snd_pcm_t *handle, const struct iovec *vector, unsigned long count)
+ssize_t snd_pcm_writen(snd_pcm_t *pcm, void **bufs, size_t size)
{
- assert(handle);
- assert(count == 0 || vector);
- assert(handle->valid_setup);
- assert(handle->setup.format.interleave ||
- count % handle->setup.format.channels == 0);
- return handle->fast_ops->writev(handle->fast_op_arg, 0, vector, count);
+ assert(pcm);
+ assert(size == 0 || bufs);
+ assert(pcm->valid_setup);
+ assert(pcm->setup.xfer_mode == SND_PCM_XFER_NONINTERLEAVED);
+ assert(!pcm->mmap_data);
+ return pcm->fast_ops->writen(pcm->fast_op_arg, bufs, size);
}
-ssize_t snd_pcm_read(snd_pcm_t *handle, void *buffer, size_t size)
+ssize_t snd_pcm_readi(snd_pcm_t *pcm, void *buffer, size_t size)
{
- assert(handle);
+ assert(pcm);
assert(size == 0 || buffer);
- assert(handle->valid_setup);
- assert(size % handle->setup.align == 0);
- return handle->fast_ops->read(handle->fast_op_arg, 0, buffer, size);
+ assert(pcm->valid_setup);
+ assert(pcm->setup.xfer_mode == SND_PCM_XFER_INTERLEAVED);
+ assert(!pcm->mmap_data);
+ return pcm->fast_ops->readi(pcm->fast_op_arg, buffer, size);
}
-ssize_t snd_pcm_readv(snd_pcm_t *handle, const struct iovec *vector, unsigned long count)
+ssize_t snd_pcm_readn(snd_pcm_t *pcm, void **bufs, size_t size)
{
- assert(handle);
- assert(count == 0 || vector);
- assert(handle->valid_setup);
- return handle->fast_ops->readv(handle->fast_op_arg, 0, vector, count);
+ assert(pcm);
+ assert(size == 0 || bufs);
+ assert(pcm->valid_setup);
+ assert(pcm->setup.xfer_mode == SND_PCM_XFER_NONINTERLEAVED);
+ assert(!pcm->mmap_data);
+ return pcm->fast_ops->readn(pcm->fast_op_arg, bufs, size);
}
-int snd_pcm_link(snd_pcm_t *handle1, snd_pcm_t *handle2)
+ssize_t snd_pcm_writev(snd_pcm_t *pcm, const struct iovec *vector, int count)
{
- int fd1, fd2;
- switch (handle1->type) {
- case SND_PCM_TYPE_HW:
- case SND_PCM_TYPE_PLUG:
- case SND_PCM_TYPE_MULTI:
- fd1 = snd_pcm_file_descriptor(handle1);
- break;
- default:
- errno = -ENOSYS;
- return -1;
+ void **bufs;
+ int k;
+ assert(pcm);
+ assert(pcm->valid_setup);
+ assert((int)pcm->setup.format.channels == count);
+ bufs = alloca(sizeof(*bufs) * count);
+ for (k = 0; k < count; ++k) {
+ bufs[k] = vector[k].iov_base;
+ assert(vector[k].iov_len == vector[0].iov_len);
}
- switch (handle2->type) {
- case SND_PCM_TYPE_HW:
- case SND_PCM_TYPE_PLUG:
- case SND_PCM_TYPE_MULTI:
- fd2 = snd_pcm_file_descriptor(handle2);
- break;
- default:
- errno = -ENOSYS;
- return -1;
+ return snd_pcm_writen(pcm, bufs, vector[0].iov_len);
+}
+
+ssize_t snd_pcm_readv(snd_pcm_t *pcm, const struct iovec *vector, int count)
+{
+ void **bufs;
+ int k;
+ assert(pcm);
+ assert(pcm->valid_setup);
+ assert((int)pcm->setup.format.channels == count);
+ bufs = alloca(sizeof(*bufs) * count);
+ for (k = 0; k < count; ++k) {
+ bufs[k] = vector[k].iov_base;
+ assert(vector[k].iov_len == vector[0].iov_len);
}
+ return snd_pcm_readn(pcm, bufs, vector[0].iov_len);
+}
+
+/* FIXME */
+#define snd_pcm_link_descriptor snd_pcm_poll_descriptor
+
+int snd_pcm_link(snd_pcm_t *pcm1, snd_pcm_t *pcm2)
+{
+ int fd1 = snd_pcm_link_descriptor(pcm1);
+ int fd2 = snd_pcm_link_descriptor(pcm2);
+ if (fd1 < 0 || fd2 < 0)
+ return -ENOSYS;
if (ioctl(fd1, SND_PCM_IOCTL_LINK, fd2) < 0)
return -errno;
return 0;
}
-int snd_pcm_unlink(snd_pcm_t *handle)
+int snd_pcm_unlink(snd_pcm_t *pcm)
{
int fd;
- switch (handle->type) {
+ switch (pcm->type) {
case SND_PCM_TYPE_HW:
- case SND_PCM_TYPE_PLUG:
case SND_PCM_TYPE_MULTI:
- fd = snd_pcm_file_descriptor(handle);
+ fd = snd_pcm_poll_descriptor(pcm);
break;
default:
errno = -ENOSYS;
@@ -285,17 +316,17 @@ int snd_pcm_unlink(snd_pcm_t *handle)
return 0;
}
-int snd_pcm_file_descriptor(snd_pcm_t *handle)
+int snd_pcm_poll_descriptor(snd_pcm_t *pcm)
{
- assert(handle);
- return handle->fast_ops->file_descriptor(handle->fast_op_arg);
+ assert(pcm);
+ return pcm->fast_ops->poll_descriptor(pcm->fast_op_arg);
}
-int snd_pcm_channels_mask(snd_pcm_t *handle, bitset_t *client_vmask)
+int snd_pcm_channels_mask(snd_pcm_t *pcm, bitset_t *cmask)
{
- assert(handle);
- assert(handle->valid_setup);
- return handle->fast_ops->channels_mask(handle->fast_op_arg, client_vmask);
+ assert(pcm);
+ assert(pcm->valid_setup);
+ return pcm->fast_ops->channels_mask(pcm->fast_op_arg, cmask);
}
typedef struct {
@@ -306,7 +337,7 @@ typedef struct {
static assoc_t *assoc_value(int value, assoc_t *alist)
{
- while (alist->desc) {
+ while (alist->name) {
if (value == alist->value)
return alist;
alist++;
@@ -333,86 +364,112 @@ static const char *assoc(int value, assoc_t *alist)
return "UNKNOWN";
}
+#define STATE(v) { SND_PCM_STATE_##v, #v, #v }
#define STREAM(v) { SND_PCM_STREAM_##v, #v, #v }
-#define MODE(v) { SND_PCM_MODE_##v, #v, #v }
-#define FMT(v, d) { SND_PCM_SFMT_##v, #v, d }
+#define READY(v) { SND_PCM_READY_##v, #v, #v }
#define XRUN(v) { SND_PCM_XRUN_##v, #v, #v }
+#define XFER(v) { SND_PCM_XFER_##v, #v, #v }
+#define MMAP(v) { SND_PCM_MMAP_##v, #v, #v }
+#define SFMT(v, d) { SND_PCM_SFMT_##v, #v, d }
+#define XRUN_ACT(v) { SND_PCM_XRUN_ACT_##v, #v, #v }
#define START(v) { SND_PCM_START_##v, #v, #v }
#define FILL(v) { SND_PCM_FILL_##v, #v, #v }
#define END { 0, NULL, NULL }
+static assoc_t states[] = { STATE(NOTREADY), STATE(READY), STATE(PREPARED),
+ STATE(RUNNING), STATE(XRUN), STATE(PAUSED), END };
static assoc_t streams[] = { STREAM(PLAYBACK), STREAM(CAPTURE), END };
-static assoc_t modes[] = { MODE(FRAME), MODE(FRAGMENT), END };
+static assoc_t xruns[] = { XRUN(ASAP), XRUN(FRAGMENT), END };
static assoc_t fmts[] = {
- FMT(S8, "Signed 8-bit"),
- FMT(U8, "Unsigned 8-bit"),
- FMT(S16_LE, "Signed 16-bit Little Endian"),
- FMT(S16_BE, "Signed 16-bit Big Endian"),
- FMT(U16_LE, "Unsigned 16-bit Little Endian"),
- FMT(U16_BE, "Unsigned 16-bit Big Endian"),
- FMT(S24_LE, "Signed 24-bit Little Endian"),
- FMT(S24_BE, "Signed 24-bit Big Endian"),
- FMT(U24_LE, "Unsigned 24-bit Little Endian"),
- FMT(U24_BE, "Unsigned 24-bit Big Endian"),
- FMT(S32_LE, "Signed 32-bit Little Endian"),
- FMT(S32_BE, "Signed 32-bit Big Endian"),
- FMT(U32_LE, "Unsigned 32-bit Little Endian"),
- FMT(U32_BE, "Unsigned 32-bit Big Endian"),
- FMT(FLOAT_LE, "Float Little Endian"),
- FMT(FLOAT_BE, "Float Big Endian"),
- FMT(FLOAT64_LE, "Float64 Little Endian"),
- FMT(FLOAT64_BE, "Float64 Big Endian"),
- FMT(IEC958_SUBFRAME_LE, "IEC-958 Little Endian"),
- FMT(IEC958_SUBFRAME_BE, "IEC-958 Big Endian"),
- FMT(MU_LAW, "Mu-Law"),
- FMT(A_LAW, "A-Law"),
- FMT(IMA_ADPCM, "Ima-ADPCM"),
- FMT(MPEG, "MPEG"),
- FMT(GSM, "GSM"),
- FMT(SPECIAL, "Special"),
+ SFMT(S8, "Signed 8-bit"),
+ SFMT(U8, "Unsigned 8-bit"),
+ SFMT(S16_LE, "Signed 16-bit Little Endian"),
+ SFMT(S16_BE, "Signed 16-bit Big Endian"),
+ SFMT(U16_LE, "Unsigned 16-bit Little Endian"),
+ SFMT(U16_BE, "Unsigned 16-bit Big Endian"),
+ SFMT(S24_LE, "Signed 24-bit Little Endian"),
+ SFMT(S24_BE, "Signed 24-bit Big Endian"),
+ SFMT(U24_LE, "Unsigned 24-bit Little Endian"),
+ SFMT(U24_BE, "Unsigned 24-bit Big Endian"),
+ SFMT(S32_LE, "Signed 32-bit Little Endian"),
+ SFMT(S32_BE, "Signed 32-bit Big Endian"),
+ SFMT(U32_LE, "Unsigned 32-bit Little Endian"),
+ SFMT(U32_BE, "Unsigned 32-bit Big Endian"),
+ SFMT(FLOAT_LE, "Float Little Endian"),
+ SFMT(FLOAT_BE, "Float Big Endian"),
+ SFMT(FLOAT64_LE, "Float64 Little Endian"),
+ SFMT(FLOAT64_BE, "Float64 Big Endian"),
+ SFMT(IEC958_SUBFRAME_LE, "IEC-958 Little Endian"),
+ SFMT(IEC958_SUBFRAME_BE, "IEC-958 Big Endian"),
+ SFMT(MU_LAW, "Mu-Law"),
+ SFMT(A_LAW, "A-Law"),
+ SFMT(IMA_ADPCM, "Ima-ADPCM"),
+ SFMT(MPEG, "MPEG"),
+ SFMT(GSM, "GSM"),
+ SFMT(SPECIAL, "Special"),
END
};
-static assoc_t starts[] = { START(GO), START(DATA), START(FULL), END };
-static assoc_t xruns[] = { XRUN(FLUSH), XRUN(DRAIN), END };
-static assoc_t fills[] = { FILL(NONE), FILL(SILENCE_WHOLE), FILL(SILENCE), END };
+static assoc_t starts[] = { START(EXPLICIT), START(DATA), END };
+static assoc_t readys[] = { READY(FRAGMENT), READY(ASAP), END };
+static assoc_t xfers[] = { XFER(INTERLEAVED), XFER(NONINTERLEAVED), END };
+static assoc_t mmaps[] = { MMAP(INTERLEAVED), MMAP(NONINTERLEAVED), END };
+static assoc_t xrun_acts[] = { XRUN_ACT(FLUSH), XRUN_ACT(DRAIN), END };
static assoc_t onoff[] = { {0, "OFF", NULL}, {1, "ON", NULL}, {-1, "ON", NULL}, END };
-int snd_pcm_dump_setup(snd_pcm_t *handle, FILE *fp)
+int snd_pcm_dump_setup(snd_pcm_t *pcm, FILE *fp)
{
snd_pcm_setup_t *setup;
- assert(handle);
+ assert(pcm);
assert(fp);
- 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);
- fprintf(fp, "rate: %d (%d/%d=%g)\n", setup->format.rate, setup->rate_master, setup->rate_divisor, (double) setup->rate_master / setup->rate_divisor);
+ assert(pcm->valid_setup);
+ setup = &pcm->setup;
+ fprintf(fp, "stream : %s\n", assoc(pcm->stream, streams));
+ fprintf(fp, "format : %s\n", assoc(setup->format.sfmt, fmts));
+ fprintf(fp, "channels : %d\n", setup->format.channels);
+ fprintf(fp, "rate : %d (%d/%d=%g)\n", setup->format.rate, setup->rate_master, setup->rate_divisor, (double) setup->rate_master / setup->rate_divisor);
// digital
- fprintf(fp, "start_mode: %s\n", assoc(setup->start_mode, starts));
- fprintf(fp, "xrun_mode: %s\n", assoc(setup->xrun_mode, xruns));
- fprintf(fp, "time: %s\n", assoc(setup->time, onoff));
- // ust_time
+ fprintf(fp, "start_mode : %s\n", assoc(setup->start_mode, starts));
+ fprintf(fp, "ready_mode : %s\n", assoc(setup->ready_mode, readys));
+ fprintf(fp, "avail_min : %ld\n", (long)setup->avail_min);
+ fprintf(fp, "xfer_mode : %s\n", assoc(setup->xfer_mode, xfers));
+ fprintf(fp, "xfer_min : %ld\n", (long)setup->xfer_min);
+ fprintf(fp, "xfer_align : %ld\n", (long)setup->xfer_align);
+ fprintf(fp, "xrun_mode : %s\n", assoc(setup->xrun_mode, xruns));
+ fprintf(fp, "xrun_act : %s\n", assoc(setup->xrun_act, xrun_acts));
+ fprintf(fp, "xrun_max : %ld\n", (long)setup->xrun_max);
+ fprintf(fp, "mmap_shape : %s\n", assoc(setup->mmap_shape, mmaps));
fprintf(fp, "buffer_size: %ld\n", (long)setup->buffer_size);
- fprintf(fp, "frag_size: %ld\n", (long)setup->frag_size);
- fprintf(fp, "frags: %ld\n", (long)setup->frags);
- fprintf(fp, "boundary: %ld\n", (long)setup->boundary);
- fprintf(fp, "msbits_per_sample: %d\n", setup->msbits_per_sample);
- fprintf(fp, "avail_min: %ld\n", (long)setup->avail_min);
- fprintf(fp, "align: %ld\n", (long)setup->align);
- fprintf(fp, "xrun_max: %ld\n", (long)setup->xrun_max);
- fprintf(fp, "fill_mode: %s\n", assoc(setup->fill_mode, fills));
- fprintf(fp, "fill_max: %ld\n", (long)setup->fill_max);
+ fprintf(fp, "frag_size : %ld\n", (long)setup->frag_size);
+ fprintf(fp, "boundary : %ld\n", (long)setup->boundary);
+ fprintf(fp, "time : %s\n", assoc(setup->time, onoff));
+ fprintf(fp, "frags : %ld\n", (long)setup->frags);
+ fprintf(fp, "msbits : %d\n", setup->msbits);
+ return 0;
+}
+
+int snd_pcm_dump_status(snd_pcm_status_t *status, FILE *fp)
+{
+ assert(status);
+ fprintf(fp, "state : %s\n", assoc(status->state, states));
+ fprintf(fp, "trigger_time: %ld.%06ld\n",
+ status->trigger_time.tv_sec, status->trigger_time.tv_usec);
+ fprintf(fp, "tstamp : %ld.%06ld\n",
+ status->tstamp.tv_sec, status->tstamp.tv_usec);
+ fprintf(fp, "delay : %ld\n", (long)status->delay);
+ fprintf(fp, "avail_max : %ld\n", (long)status->avail_max);
+ fprintf(fp, "xruns : %ld\n", (long)status->xruns);
+ fprintf(fp, "appl_ptr : %ld\n", (long)status->appl_ptr);
+ fprintf(fp, "hw_ptr : %ld\n", (long)status->hw_ptr);
+ fprintf(fp, "avail : %ld\n", (long)status->avail);
return 0;
}
-int snd_pcm_dump(snd_pcm_t *handle, FILE *fp)
+int snd_pcm_dump(snd_pcm_t *pcm, FILE *fp)
{
- assert(handle);
+ assert(pcm);
assert(fp);
- handle->ops->dump(handle->op_arg, fp);
+ pcm->ops->dump(pcm->op_arg, fp);
return 0;
}
@@ -440,401 +497,548 @@ int snd_pcm_format_value(const char* name)
return -1;
}
-ssize_t snd_pcm_bytes_to_frames(snd_pcm_t *handle, ssize_t bytes)
+ssize_t snd_pcm_bytes_to_frames(snd_pcm_t *pcm, ssize_t bytes)
{
- assert(handle);
- assert(handle->valid_setup);
- return bytes * 8 / handle->bits_per_frame;
+ assert(pcm);
+ assert(pcm->valid_setup);
+ return bytes * 8 / pcm->bits_per_frame;
}
-ssize_t snd_pcm_frames_to_bytes(snd_pcm_t *handle, ssize_t frames)
+ssize_t snd_pcm_frames_to_bytes(snd_pcm_t *pcm, ssize_t frames)
{
- assert(handle);
- assert(handle->valid_setup);
- return frames * handle->bits_per_frame / 8;
+ assert(pcm);
+ assert(pcm->valid_setup);
+ return frames * pcm->bits_per_frame / 8;
}
-ssize_t snd_pcm_bytes_to_samples(snd_pcm_t *handle, ssize_t bytes)
+ssize_t snd_pcm_bytes_to_samples(snd_pcm_t *pcm, ssize_t bytes)
{
- assert(handle);
- assert(handle->valid_setup);
- return bytes * 8 / handle->bits_per_sample;
+ assert(pcm);
+ assert(pcm->valid_setup);
+ return bytes * 8 / pcm->bits_per_sample;
}
-ssize_t snd_pcm_samples_to_bytes(snd_pcm_t *handle, ssize_t samples)
+ssize_t snd_pcm_samples_to_bytes(snd_pcm_t *pcm, ssize_t samples)
{
- assert(handle);
- assert(handle->valid_setup);
- return samples * handle->bits_per_sample / 8;
+ assert(pcm);
+ assert(pcm->valid_setup);
+ return samples * pcm->bits_per_sample / 8;
}
-static int _snd_pcm_open_hw(snd_pcm_t **handlep, snd_config_t *conf,
- int stream, int mode)
+int snd_pcm_open(snd_pcm_t **pcmp, char *name,
+ int stream, int mode)
{
- snd_config_iterator_t i;
- long card = -1, device = -1, subdevice = -1;
char *str;
int err;
- snd_config_foreach(i, conf) {
+ snd_config_t *pcm_conf, *conf, *type_conf;
+ snd_config_iterator_t i;
+ char *lib = NULL, *open = NULL;
+ int (*open_func)(snd_pcm_t **pcmp, char *name, snd_config_t *conf,
+ int stream, int mode);
+ void *h;
+ assert(pcmp && name);
+ err = snd_config_update();
+ if (err < 0)
+ return err;
+ err = snd_config_searchv(snd_config, &pcm_conf, "pcm", name, 0);
+ if (err < 0)
+ return err;
+ if (snd_config_type(pcm_conf) != SND_CONFIG_TYPE_COMPOUND)
+ return -EINVAL;
+ err = snd_config_search(pcm_conf, "stream", &conf);
+ if (err >= 0) {
+ err = snd_config_string_get(conf, &str);
+ if (err < 0)
+ return err;
+ if (strcmp(str, "playback") == 0) {
+ if (stream != SND_PCM_STREAM_PLAYBACK)
+ return -EINVAL;
+ } else if (strcmp(str, "capture") == 0) {
+ if (stream != SND_PCM_STREAM_CAPTURE)
+ return -EINVAL;
+ } else
+ return -EINVAL;
+ }
+ err = snd_config_search(pcm_conf, "type", &conf);
+ if (err < 0)
+ return err;
+ err = snd_config_string_get(conf, &str);
+ if (err < 0)
+ return err;
+ err = snd_config_searchv(snd_config, &type_conf, "pcmtype", str, 0);
+ if (err < 0)
+ return err;
+ snd_config_foreach(i, type_conf) {
snd_config_t *n = snd_config_entry(i);
if (strcmp(n->id, "comment") == 0)
continue;
- if (strcmp(n->id, "type") == 0)
- continue;
- if (strcmp(n->id, "stream") == 0)
- continue;
- if (strcmp(n->id, "card") == 0) {
- err = snd_config_integer_get(n, &card);
- if (err < 0) {
- err = snd_config_string_get(n, &str);
- if (err < 0)
- return -EINVAL;
- card = snd_card_get_index(str);
- if (card < 0)
- return card;
- }
- continue;
- }
- if (strcmp(n->id, "device") == 0) {
- err = snd_config_integer_get(n, &device);
+ if (strcmp(n->id, "lib") == 0) {
+ err = snd_config_string_get(n, &lib);
if (err < 0)
- return err;
+ return -EINVAL;
continue;
}
- if (strcmp(n->id, "subdevice") == 0) {
- err = snd_config_integer_get(n, &subdevice);
+ if (strcmp(n->id, "open") == 0) {
+ err = snd_config_string_get(n, &open);
if (err < 0)
- return err;
+ return -EINVAL;
continue;
+ return -EINVAL;
}
- return -EINVAL;
}
- if (card < 0 || device < 0)
+ if (!open)
return -EINVAL;
- return snd_pcm_hw_open_subdevice(handlep, card, device, subdevice, stream, mode);
+ if (!lib)
+ lib = "libasound.so";
+ h = dlopen(lib, RTLD_NOW);
+ if (!h)
+ return -ENOENT;
+ open_func = dlsym(h, open);
+ dlclose(h);
+ if (!open_func)
+ return -ENXIO;
+ return open_func(pcmp, name, pcm_conf, stream, mode);
}
-
-static int _snd_pcm_open_plug(snd_pcm_t **handlep, snd_config_t *conf,
- int stream, int mode)
+
+void snd_pcm_areas_from_buf(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas,
+ void *buf)
{
- snd_config_iterator_t i;
- char *slave = NULL;
- int err;
- snd_pcm_t *slave_handle;
- snd_config_foreach(i, conf) {
- snd_config_t *n = snd_config_entry(i);
- if (strcmp(n->id, "comment") == 0)
- continue;
- if (strcmp(n->id, "type") == 0)
- continue;
- if (strcmp(n->id, "stream") == 0)
- continue;
- if (strcmp(n->id, "slave") == 0) {
- err = snd_config_string_get(n, &slave);
- if (err < 0)
- return -EINVAL;
- continue;
- }
- return -EINVAL;
+ unsigned int channel;
+ unsigned int channels = pcm->setup.format.channels;
+ for (channel = 0; channel < channels; ++channel, ++areas) {
+ areas->addr = buf;
+ areas->first = channel * pcm->bits_per_sample;
+ areas->step = pcm->bits_per_frame;
}
- if (!slave)
- return -EINVAL;
- /* This is needed cause snd_config_update may destroy config */
- slave = strdup(slave);
- if (!slave)
- return -ENOMEM;
- err = snd_pcm_open(&slave_handle, slave, stream, mode);
- free(slave);
+}
+
+void snd_pcm_areas_from_bufs(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas,
+ void **bufs)
+{
+ unsigned int channel;
+ unsigned int channels = pcm->setup.format.channels;
+ for (channel = 0; channel < channels; ++channel, ++areas, ++bufs) {
+ areas->addr = *bufs;
+ areas->first = 0;
+ areas->step = pcm->bits_per_sample;
+ }
+}
+
+int snd_pcm_wait(snd_pcm_t *pcm, int timeout)
+{
+ struct pollfd pfd;
+ int err;
+#if 0
+ size_t bavail, aavail;
+ struct timeval before, after, diff;
+ bavail = snd_pcm_avail_update(pcm);
+ gettimeofday(&before, 0);
+#endif
+ pfd.fd = snd_pcm_poll_descriptor(pcm);
+ pfd.events = pcm->stream == SND_PCM_STREAM_PLAYBACK ? POLLOUT : POLLIN;
+ err = poll(&pfd, 1, timeout);
if (err < 0)
return err;
- err = snd_pcm_plug_create(handlep, slave_handle, 1);
- if (err < 0)
- snd_pcm_close(slave_handle);
- return err;
+#if 0
+ aavail = snd_pcm_avail_update(pcm);
+ gettimeofday(&after, 0);
+ timersub(&after, &before, &diff);
+ fprintf(stderr, "%s %ld.%06ld: get=%d (%d-%d)\n", pcm->stream == SND_PCM_STREAM_PLAYBACK ? "playback" : "capture", diff.tv_sec, diff.tv_usec, aavail - bavail, aavail, bavail);
+#endif
+ return 0;
}
-
-static int _snd_pcm_open_multi(snd_pcm_t **handlep, snd_config_t *conf,
- int stream, int mode)
+
+ssize_t snd_pcm_avail_update(snd_pcm_t *pcm)
{
- snd_config_iterator_t i, j;
- snd_config_t *slave = NULL;
- snd_config_t *binding = NULL;
- int err;
- unsigned int idx;
- char **slaves_id = NULL;
- char **slaves_name = NULL;
- snd_pcm_t **slaves_handle = NULL;
- size_t *slaves_channels = NULL;
- unsigned int *bindings_cchannel = NULL;
- unsigned int *bindings_slave = NULL;
- unsigned int *bindings_schannel = NULL;
- size_t slaves_count = 0;
- size_t bindings_count = 0;
- snd_config_foreach(i, conf) {
- snd_config_t *n = snd_config_entry(i);
- if (strcmp(n->id, "comment") == 0)
- continue;
- if (strcmp(n->id, "type") == 0)
- continue;
- if (strcmp(n->id, "stream") == 0)
- continue;
- if (strcmp(n->id, "slave") == 0) {
- if (snd_config_type(n) != SND_CONFIG_TYPE_COMPOUND)
- return -EINVAL;
- slave = n;
- continue;
- }
- if (strcmp(n->id, "binding") == 0) {
- if (snd_config_type(n) != SND_CONFIG_TYPE_COMPOUND)
- return -EINVAL;
- binding = n;
- continue;
- }
- return -EINVAL;
+ return pcm->fast_ops->avail_update(pcm->fast_op_arg);
+}
+
+ssize_t snd_pcm_mmap_forward(snd_pcm_t *pcm, size_t size)
+{
+ assert(size > 0);
+ return pcm->fast_ops->mmap_forward(pcm->fast_op_arg, size);
+}
+
+size_t snd_pcm_hw_ptr(snd_pcm_t *pcm)
+{
+ return pcm->mmap_status->hw_ptr;
+}
+
+int snd_pcm_area_silence(snd_pcm_channel_area_t *dst_area, size_t dst_offset,
+ size_t samples, int format)
+{
+ /* FIXME: sub byte resolution and odd dst_offset */
+ char *dst;
+ unsigned int dst_step;
+ int width;
+ u_int64_t silence;
+ if (!dst_area->addr)
+ return 0;
+ dst = snd_pcm_channel_area_addr(dst_area, dst_offset);
+ width = snd_pcm_format_physical_width(format);
+ silence = snd_pcm_format_silence_64(format);
+ if (dst_area->step == (unsigned int) width) {
+ size_t dwords = samples * width / 64;
+ samples -= dwords * 64 / width;
+ while (dwords-- > 0)
+ *((u_int64_t*)dst)++ = silence;
+ if (samples == 0)
+ return 0;
}
- if (!slave || !binding)
- return -EINVAL;
- snd_config_foreach(i, slave) {
- ++slaves_count;
- }
- snd_config_foreach(i, binding) {
- ++bindings_count;
- }
- slaves_id = calloc(slaves_count, sizeof(*slaves_id));
- slaves_name = calloc(slaves_count, sizeof(*slaves_name));
- slaves_handle = calloc(slaves_count, sizeof(*slaves_handle));
- slaves_channels = calloc(slaves_count, sizeof(*slaves_channels));
- bindings_cchannel = calloc(bindings_count, sizeof(*bindings_cchannel));
- bindings_slave = calloc(bindings_count, sizeof(*bindings_slave));
- bindings_schannel = calloc(bindings_count, sizeof(*bindings_schannel));
- idx = 0;
- snd_config_foreach(i, slave) {
- snd_config_t *m = snd_config_entry(i);
- char *pcm = NULL;
- long channels = -1;
- slaves_id[idx] = snd_config_id(m);
- snd_config_foreach(j, m) {
- snd_config_t *n = snd_config_entry(j);
- if (strcmp(n->id, "comment") == 0)
- continue;
- if (strcmp(n->id, "pcm") == 0) {
- err = snd_config_string_get(n, &pcm);
- if (err < 0)
- goto _free;
- continue;
+ dst_step = dst_area->step / 8;
+ switch (width) {
+ case 4: {
+ u_int8_t s0 = silence & 0xf0;
+ u_int8_t s1 = silence & 0x0f;
+ int dstbit = dst_area->first % 8;
+ int dstbit_step = dst_area->step % 8;
+ while (samples-- > 0) {
+ if (dstbit) {
+ *dst &= 0xf0;
+ *dst |= s1;
+ } else {
+ *dst &= 0x0f;
+ *dst |= s0;
}
- if (strcmp(n->id, "channels") == 0) {
- err = snd_config_integer_get(n, &channels);
- if (err < 0)
- goto _free;
- continue;
+ dst += dst_step;
+ dstbit += dstbit_step;
+ if (dstbit == 8) {
+ dst++;
+ dstbit = 0;
}
- err = -EINVAL;
- goto _free;
}
- if (!pcm || channels < 0) {
- err = -EINVAL;
- goto _free;
+ break;
+ }
+ case 8: {
+ u_int8_t sil = silence;
+ while (samples-- > 0) {
+ *dst = sil;
+ dst += dst_step;
}
- slaves_name[idx] = strdup(pcm);
- slaves_channels[idx] = channels;
- ++idx;
- }
-
- idx = 0;
- snd_config_foreach(i, binding) {
- snd_config_t *m = snd_config_entry(i);
- long cchannel = -1, schannel = -1;
- int slave = -1;
- long val;
- char *str;
- snd_config_foreach(j, m) {
- snd_config_t *n = snd_config_entry(j);
- if (strcmp(n->id, "comment") == 0)
- continue;
- if (strcmp(n->id, "client_channel") == 0) {
- err = snd_config_integer_get(n, &cchannel);
- if (err < 0)
- goto _free;
- continue;
- }
- if (strcmp(n->id, "slave") == 0) {
- char buf[32];
- unsigned int k;
- err = snd_config_string_get(n, &str);
- if (err < 0) {
- err = snd_config_integer_get(n, &val);
- if (err < 0)
- goto _free;
- sprintf(buf, "%ld", val);
- str = buf;
- }
- for (k = 0; k < slaves_count; ++k) {
- if (strcmp(slaves_id[k], str) == 0)
- slave = k;
- }
- continue;
+ break;
+ }
+ case 16: {
+ u_int16_t sil = silence;
+ while (samples-- > 0) {
+ *(u_int16_t*)dst = sil;
+ dst += dst_step;
+ }
+ break;
+ }
+ case 32: {
+ u_int32_t sil = silence;
+ while (samples-- > 0) {
+ *(u_int32_t*)dst = sil;
+ dst += dst_step;
+ }
+ break;
+ }
+ case 64: {
+ while (samples-- > 0) {
+ *(u_int64_t*)dst = silence;
+ dst += dst_step;
+ }
+ break;
+ }
+ default:
+ assert(0);
+ }
+ return 0;
+}
+
+int snd_pcm_areas_silence(snd_pcm_channel_area_t *dst_areas, size_t dst_offset,
+ size_t channels, size_t frames, int format)
+{
+ int width = snd_pcm_format_physical_width(format);
+ while (channels > 0) {
+ void *addr = dst_areas->addr;
+ unsigned int step = dst_areas->step;
+ snd_pcm_channel_area_t *begin = dst_areas;
+ int channels1 = channels;
+ unsigned int chns = 0;
+ int err;
+ while (1) {
+ channels1--;
+ chns++;
+ dst_areas++;
+ if (channels1 == 0 ||
+ dst_areas->addr != addr ||
+ dst_areas->step != step ||
+ dst_areas->first != dst_areas[-1].first + width)
+ break;
+ }
+ if (chns > 1 && chns * width == step) {
+ /* Collapse the areas */
+ snd_pcm_channel_area_t d;
+ d.addr = begin->addr;
+ d.first = begin->first;
+ d.step = width;
+ err = snd_pcm_area_silence(&d, dst_offset * chns, frames * chns, format);
+ channels -= chns;
+ } else {
+ err = snd_pcm_area_silence(begin, dst_offset, frames, format);
+ dst_areas = begin + 1;
+ channels--;
+ }
+ if (err < 0)
+ return err;
+ }
+ return 0;
+}
+
+
+int snd_pcm_area_copy(snd_pcm_channel_area_t *src_area, size_t src_offset,
+ snd_pcm_channel_area_t *dst_area, size_t dst_offset,
+ size_t samples, int format)
+{
+ /* FIXME: sub byte resolution and odd dst_offset */
+ char *src, *dst;
+ int width;
+ int src_step, dst_step;
+ if (!src_area->addr)
+ return snd_pcm_area_silence(dst_area, dst_offset, samples, format);
+ src = snd_pcm_channel_area_addr(src_area, src_offset);
+ if (!dst_area->addr)
+ return 0;
+ dst = snd_pcm_channel_area_addr(dst_area, dst_offset);
+ width = snd_pcm_format_physical_width(format);
+ if (src_area->step == (unsigned int) width &&
+ dst_area->step == (unsigned int) width) {
+ size_t bytes = samples * width / 8;
+ samples -= bytes * 8 / width;
+ memcpy(dst, src, bytes);
+ if (samples == 0)
+ return 0;
+ }
+ src_step = src_area->step / 8;
+ dst_step = dst_area->step / 8;
+ switch (width) {
+ case 4: {
+ int srcbit = src_area->first % 8;
+ int srcbit_step = src_area->step % 8;
+ int dstbit = dst_area->first % 8;
+ int dstbit_step = dst_area->step % 8;
+ while (samples-- > 0) {
+ unsigned char srcval;
+ if (srcbit)
+ srcval = *src & 0x0f;
+ else
+ srcval = *src & 0xf0;
+ if (dstbit)
+ *dst &= 0xf0;
+ else
+ *dst &= 0x0f;
+ *dst |= srcval;
+ src += src_step;
+ srcbit += srcbit_step;
+ if (srcbit == 8) {
+ src++;
+ srcbit = 0;
}
- if (strcmp(n->id, "slave_channel") == 0) {
- err = snd_config_integer_get(n, &schannel);
- if (err < 0)
- goto _free;
- continue;
+ dst += dst_step;
+ dstbit += dstbit_step;
+ if (dstbit == 8) {
+ dst++;
+ dstbit = 0;
}
- err = -EINVAL;
- goto _free;
}
- if (cchannel < 0 || slave < 0 || schannel < 0) {
- err = -EINVAL;
- goto _free;
+ break;
+ }
+ case 8: {
+ while (samples-- > 0) {
+ *dst = *src;
+ src += src_step;
+ dst += dst_step;
}
- if ((size_t)slave >= slaves_count) {
- err = -EINVAL;
- goto _free;
+ break;
+ }
+ case 16: {
+ while (samples-- > 0) {
+ *(u_int16_t*)dst = *(u_int16_t*)src;
+ src += src_step;
+ dst += dst_step;
}
- if ((unsigned int) schannel >= slaves_channels[slave]) {
- err = -EINVAL;
- goto _free;
+ break;
+ }
+ case 32: {
+ while (samples-- > 0) {
+ *(u_int32_t*)dst = *(u_int32_t*)src;
+ src += src_step;
+ dst += dst_step;
}
- bindings_cchannel[idx] = cchannel;
- bindings_slave[idx] = slave;
- bindings_schannel[idx] = schannel;
- ++idx;
- }
-
- for (idx = 0; idx < slaves_count; ++idx) {
- err = snd_pcm_open(&slaves_handle[idx], slaves_name[idx], stream, mode);
- if (err < 0)
- goto _free;
- }
- err = snd_pcm_multi_create(handlep, slaves_count, slaves_handle,
- slaves_channels,
- bindings_count, bindings_cchannel,
- bindings_slave, bindings_schannel,
- 1);
-_free:
- if (err < 0) {
- for (idx = 0; idx < slaves_count; ++idx) {
- if (slaves_handle[idx])
- snd_pcm_close(slaves_handle[idx]);
- if (slaves_name[idx])
- free(slaves_name[idx]);
+ break;
+ }
+ case 64: {
+ while (samples-- > 0) {
+ *(u_int64_t*)dst = *(u_int64_t*)src;
+ src += src_step;
+ dst += dst_step;
}
+ break;
}
- if (slaves_name)
- free(slaves_name);
- if (slaves_handle)
- free(slaves_handle);
- if (slaves_channels)
- free(slaves_channels);
- if (bindings_cchannel)
- free(bindings_cchannel);
- if (bindings_slave)
- free(bindings_slave);
- if (bindings_schannel)
- free(bindings_schannel);
- return err;
+ default:
+ assert(0);
+ }
+ return 0;
}
-static int _snd_pcm_open_client(snd_pcm_t **handlep, snd_config_t *conf,
- int stream, int mode)
+int snd_pcm_areas_copy(snd_pcm_channel_area_t *src_areas, size_t src_offset,
+ snd_pcm_channel_area_t *dst_areas, size_t dst_offset,
+ size_t channels, size_t frames, int format)
{
- snd_config_iterator_t i;
- char *socket = NULL;
- char *name = NULL;
- char *host = NULL;
- long port = -1;
- int err;
- snd_config_foreach(i, conf) {
- snd_config_t *n = snd_config_entry(i);
- if (strcmp(n->id, "comment") == 0)
- continue;
- if (strcmp(n->id, "type") == 0)
- continue;
- if (strcmp(n->id, "stream") == 0)
- continue;
- if (strcmp(n->id, "socket") == 0) {
- err = snd_config_string_get(n, &socket);
- if (err < 0)
- return -EINVAL;
- continue;
+ int width = snd_pcm_format_physical_width(format);
+ while (channels > 0) {
+ unsigned int step = src_areas->step;
+ void *src_addr = src_areas->addr;
+ snd_pcm_channel_area_t *src_start = src_areas;
+ void *dst_addr = dst_areas->addr;
+ snd_pcm_channel_area_t *dst_start = dst_areas;
+ int channels1 = channels;
+ unsigned int chns = 0;
+ while (dst_areas->step == step) {
+ channels1--;
+ chns++;
+ src_areas++;
+ dst_areas++;
+ if (channels1 == 0 ||
+ src_areas->step != step ||
+ src_areas->addr != src_addr ||
+ dst_areas->addr != dst_addr ||
+ src_areas->first != src_areas[-1].first + width ||
+ dst_areas->first != dst_areas[-1].first + width)
+ break;
}
- if (strcmp(n->id, "host") == 0) {
- err = snd_config_string_get(n, &host);
- if (err < 0)
- return -EINVAL;
- continue;
+ if (chns > 1 && chns * width == step) {
+ /* Collapse the areas */
+ snd_pcm_channel_area_t s, d;
+ s.addr = src_start->addr;
+ s.first = src_start->first;
+ s.step = width;
+ d.addr = dst_start->addr;
+ d.first = dst_start->first;
+ d.step = width;
+ snd_pcm_area_copy(&s, src_offset * chns, &d, dst_offset * chns, frames * chns, format);
+ channels -= chns;
+ } else {
+ snd_pcm_area_copy(src_start, src_offset, dst_start, dst_offset, frames, format);
+ src_areas = src_start + 1;
+ dst_areas = dst_start + 1;
+ channels--;
}
- if (strcmp(n->id, "port") == 0) {
- err = snd_config_integer_get(n, &port);
- if (err < 0)
- return -EINVAL;
- continue;
+ }
+ return 0;
+}
+
+ssize_t snd_pcm_read_areas(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas,
+ size_t offset, size_t size,
+ snd_pcm_xfer_areas_func_t func)
+{
+ size_t xfer = 0;
+ ssize_t err = 0;
+ int state = snd_pcm_state(pcm);
+ assert(size > 0);
+ assert(state >= SND_PCM_STATE_PREPARED);
+ if (state == SND_PCM_STATE_PREPARED &&
+ pcm->setup.start_mode != SND_PCM_START_EXPLICIT) {
+ err = snd_pcm_start(pcm);
+ if (err < 0)
+ return err;
+ state = SND_PCM_STATE_RUNNING;
+ }
+ while (xfer < size) {
+ ssize_t avail;
+ size_t frames;
+ again:
+ avail = snd_pcm_avail_update(pcm);
+ if (avail < 0) {
+ err = avail;
+ break;
}
- if (strcmp(n->id, "name") == 0) {
- err = snd_config_string_get(n, &name);
+ if ((size_t)avail < pcm->setup.avail_min) {
+ if (state != SND_PCM_STATE_RUNNING) {
+ err = -EPIPE;
+ break;
+ }
+ if (pcm->mode & SND_PCM_NONBLOCK) {
+ err = -EAGAIN;
+ break;
+ }
+ err = snd_pcm_wait(pcm, -1);
if (err < 0)
- return -EINVAL;
- continue;
+ break;
+ state = snd_pcm_state(pcm);
+ goto again;
}
- return -EINVAL;
- }
- if (!name)
- return -EINVAL;
- if (socket) {
- if (port >= 0 || host)
- return -EINVAL;
- return snd_pcm_client_create(handlep, socket, -1, SND_TRANSPORT_TYPE_SHM, name, stream, mode);
- } else {
- if (port < 0 || !name)
- return -EINVAL;
- return snd_pcm_client_create(handlep, host, port, SND_TRANSPORT_TYPE_TCP, name, stream, mode);
+ frames = size - xfer;
+ if (frames > (size_t)avail)
+ frames = avail;
+ err = func(pcm, areas, offset, frames, 0);
+ if (err < 0)
+ break;
+ assert((size_t)err == frames);
+ xfer += err;
+ offset += err;
}
+ if (xfer > 0)
+ return xfer;
+ return err;
}
-
-int snd_pcm_open(snd_pcm_t **handlep, char *name,
- int stream, int mode)
+
+ssize_t snd_pcm_write_areas(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas,
+ size_t offset, size_t size,
+ snd_pcm_xfer_areas_func_t func)
{
- char *str;
- int err;
- snd_config_t *pcm_conf, *conf;
- assert(handlep && name);
- err = snd_config_update();
- if (err < 0)
- return err;
- err = snd_config_searchv(snd_config, &pcm_conf, "pcm", name, 0);
- if (err < 0)
- return err;
- if (snd_config_type(pcm_conf) != SND_CONFIG_TYPE_COMPOUND)
- return -EINVAL;
- err = snd_config_search(pcm_conf, "stream", &conf);
- if (err >= 0) {
- err = snd_config_string_get(conf, &str);
+ size_t xfer = 0;
+ ssize_t err = 0;
+ int state = snd_pcm_state(pcm);
+ assert(size > 0);
+ assert(state >= SND_PCM_STATE_PREPARED);
+ while (xfer < size) {
+ ssize_t avail;
+ size_t frames;
+ again:
+ if (state == SND_PCM_STATE_XRUN) {
+ err = -EPIPE;
+ break;
+ }
+ avail = snd_pcm_avail_update(pcm);
+ if (avail < 0) {
+ err = avail;
+ break;
+ }
+ if ((size_t)avail < pcm->setup.avail_min) {
+ if (state != SND_PCM_STATE_RUNNING) {
+ err = -EPIPE;
+ break;
+ }
+ if (pcm->mode & SND_PCM_NONBLOCK) {
+ err = -EAGAIN;
+ break;
+ }
+ err = snd_pcm_wait(pcm, -1);
+ if (err < 0)
+ break;
+ state = snd_pcm_state(pcm);
+ goto again;
+ }
+ frames = size - xfer;
+ if (frames > (size_t)avail)
+ frames = avail;
+ err = func(pcm, areas, offset, frames, 0);
if (err < 0)
- return err;
- if (strcmp(str, "playback") == 0) {
- if (stream != SND_PCM_STREAM_PLAYBACK)
- return -EINVAL;
- } else if (strcmp(str, "capture") == 0) {
- if (stream != SND_PCM_STREAM_CAPTURE)
- return -EINVAL;
- } else
- return -EINVAL;
+ break;
+ assert((size_t)err == frames);
+ xfer += err;
+ offset += err;
+ if (state == SND_PCM_STATE_PREPARED &&
+ pcm->setup.start_mode != SND_PCM_START_EXPLICIT) {
+ err = snd_pcm_start(pcm);
+ if (err < 0)
+ break;
+ }
}
- err = snd_config_search(pcm_conf, "type", &conf);
- if (err < 0)
- return err;
- err = snd_config_string_get(conf, &str);
- if (err < 0)
- return err;
- if (strcmp(str, "hw") == 0)
- return _snd_pcm_open_hw(handlep, pcm_conf, stream, mode);
- else if (strcmp(str, "plug") == 0)
- return _snd_pcm_open_plug(handlep, pcm_conf, stream, mode);
- else if (strcmp(str, "multi") == 0)
- return _snd_pcm_open_multi(handlep, pcm_conf, stream, mode);
- else if (strcmp(str, "client") == 0)
- return _snd_pcm_open_client(handlep, pcm_conf, stream, mode);
- else
- return -EINVAL;
+ if (xfer > 0)
+ return xfer;
+ return err;
}
+
diff --git a/src/pcm/pcm_adpcm.c b/src/pcm/pcm_adpcm.c
new file mode 100644
index 00000000..f02fbae3
--- /dev/null
+++ b/src/pcm/pcm_adpcm.c
@@ -0,0 +1,652 @@
+/*
+ * PCM - Ima-ADPC conversion
+ * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
+ * Copyright (c) 1999 by Uros Bizjak <uros@kss-loka.si>
+ * Jaroslav Kysela <perex@suse.cz>
+ *
+ * Based on Version 1.2, 18-Dec-92 implementation of Intel/DVI ADPCM code
+ * by Jack Jansen, CWI, Amsterdam <Jack.Jansen@cwi.nl>, Copyright 1992
+ * by Stichting Mathematisch Centrum, Amsterdam, The Netherlands.
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/*
+These routines convert 16 bit linear PCM samples to 4 bit ADPCM code
+and vice versa. The ADPCM code used is the Intel/DVI ADPCM code which
+is being recommended by the IMA Digital Audio Technical Working Group.
+
+The algorithm for this coder was taken from:
+Proposal for Standardized Audio Interstreamge Formats,
+IMA compatability project proceedings, Vol 2, Issue 2, May 1992.
+
+- No, this is *not* a G.721 coder/decoder. The algorithm used by G.721
+ is very complicated, requiring oodles of floating-point ops per
+ sample (resulting in very poor performance). I have not done any
+ tests myself but various people have assured my that 721 quality is
+ actually lower than DVI quality.
+
+- No, it probably isn't a RIFF ADPCM decoder either. Trying to decode
+ RIFF ADPCM with these routines seems to result in something
+ recognizable but very distorted.
+
+- No, it is not a CDROM-XA coder either, as far as I know. I haven't
+ come across a good description of XA yet.
+ */
+
+#include <byteswap.h>
+#include "pcm_local.h"
+#include "pcm_plugin.h"
+
+typedef struct {
+ int pred_val; /* Calculated predicted value */
+ int step_idx; /* Previous StepSize lookup index */
+} adpcm_state_t;
+
+typedef void (*adpcm_f)(snd_pcm_channel_area_t *src_areas,
+ size_t src_offset,
+ snd_pcm_channel_area_t *dst_areas,
+ size_t dst_offset,
+ size_t frames, size_t channels, int getputidx,
+ adpcm_state_t *states);
+
+typedef struct {
+ /* This field need to be the first */
+ snd_pcm_plugin_t plug;
+ int getput_idx;
+ adpcm_f func;
+ int sformat;
+ int cformat;
+ int cxfer_mode, cmmap_shape;
+ adpcm_state_t *states;
+} snd_pcm_adpcm_t;
+
+/* First table lookup for Ima-ADPCM quantizer */
+static char IndexAdjust[8] = { -1, -1, -1, -1, 2, 4, 6, 8 };
+
+/* Second table lookup for Ima-ADPCM quantizer */
+static short StepSize[89] = {
+ 7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
+ 19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
+ 50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
+ 130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
+ 337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
+ 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
+ 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
+ 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
+ 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
+};
+
+static char adpcm_encoder(int sl, adpcm_state_t * state)
+{
+ short diff; /* Difference between sl and predicted sample */
+ short pred_diff; /* Predicted difference to next sample */
+
+ unsigned char sign; /* sign of diff */
+ short step; /* holds previous StepSize value */
+ unsigned char adjust_idx; /* Index to IndexAdjust lookup table */
+
+ int i;
+
+ /* Compute difference to previous predicted value */
+ diff = sl - state->pred_val;
+ sign = (diff < 0) ? 0x8 : 0x0;
+ if (sign) {
+ diff = -diff;
+ }
+
+ /*
+ * This code *approximately* computes:
+ * adjust_idx = diff * 4 / step;
+ * pred_diff = (adjust_idx + 0.5) * step / 4;
+ *
+ * But in shift step bits are dropped. The net result of this is
+ * that even if you have fast mul/div hardware you cannot put it to
+ * good use since the fixup would be too expensive.
+ */
+
+ step = StepSize[state->step_idx];
+
+ /* Divide and clamp */
+ pred_diff = step >> 3;
+ for (adjust_idx = 0, i = 0x4; i; i >>= 1, step >>= 1) {
+ if (diff >= step) {
+ adjust_idx |= i;
+ diff -= step;
+ pred_diff += step;
+ }
+ }
+
+ /* Update and clamp previous predicted value */
+ state->pred_val += sign ? -pred_diff : pred_diff;
+
+ if (state->pred_val > 32767) {
+ state->pred_val = 32767;
+ } else if (state->pred_val < -32768) {
+ state->pred_val = -32768;
+ }
+
+ /* Update and clamp StepSize lookup table index */
+ state->step_idx += IndexAdjust[adjust_idx];
+
+ if (state->step_idx < 0) {
+ state->step_idx = 0;
+ } else if (state->step_idx > 88) {
+ state->step_idx = 88;
+ }
+ return (sign | adjust_idx);
+}
+
+
+static int adpcm_decoder(unsigned char code, adpcm_state_t * state)
+{
+ short pred_diff; /* Predicted difference to next sample */
+ short step; /* holds previous StepSize value */
+ char sign;
+
+ int i;
+
+ /* Separate sign and magnitude */
+ sign = code & 0x8;
+ code &= 0x7;
+
+ /*
+ * Computes pred_diff = (code + 0.5) * step / 4,
+ * but see comment in adpcm_coder.
+ */
+
+ step = StepSize[state->step_idx];
+
+ /* Compute difference and new predicted value */
+ pred_diff = step >> 3;
+ for (i = 0x4; i; i >>= 1, step >>= 1) {
+ if (code & i) {
+ pred_diff += step;
+ }
+ }
+ state->pred_val += (sign) ? -pred_diff : pred_diff;
+
+ /* Clamp output value */
+ if (state->pred_val > 32767) {
+ state->pred_val = 32767;
+ } else if (state->pred_val < -32768) {
+ state->pred_val = -32768;
+ }
+
+ /* Find new StepSize index value */
+ state->step_idx += IndexAdjust[code];
+
+ if (state->step_idx < 0) {
+ state->step_idx = 0;
+ } else if (state->step_idx > 88) {
+ state->step_idx = 88;
+ }
+ return (state->pred_val);
+}
+
+static void adpcm_decode(snd_pcm_channel_area_t *src_areas,
+ size_t src_offset,
+ snd_pcm_channel_area_t *dst_areas,
+ size_t dst_offset,
+ size_t frames, size_t channels, int putidx,
+ adpcm_state_t *states)
+{
+#define PUT_S16_LABELS
+#include "plugin_ops.h"
+#undef PUT_S16_LABELS
+ void *put = put_s16_labels[putidx];
+ size_t channel;
+ for (channel = 0; channel < channels; ++channel, ++states) {
+ char *src;
+ int srcbit;
+ char *dst;
+ int src_step, srcbit_step, dst_step;
+ size_t frames1;
+ snd_pcm_channel_area_t *src_area = &src_areas[channel];
+ snd_pcm_channel_area_t *dst_area = &dst_areas[channel];
+#if 0
+ if (!src_area->enabled) {
+ if (dst_area->wanted)
+ snd_pcm_area_silence(dst_area, dst_offset, frames, dst_sfmt);
+ dst_area->enabled = 0;
+ continue;
+ }
+ dst_area->enabled = 1;
+#endif
+ srcbit = src_area->first + src_area->step * src_offset;
+ src = src_area->addr + srcbit / 8;
+ srcbit %= 8;
+ src_step = src_area->step / 8;
+ srcbit_step = src_area->step % 8;
+ dst = snd_pcm_channel_area_addr(dst_area, dst_offset);
+ dst_step = snd_pcm_channel_area_step(dst_area);
+ frames1 = frames;
+ while (frames1-- > 0) {
+ int16_t sample;
+ int v;
+ if (srcbit)
+ v = *src & 0x0f;
+ else
+ v = (*src >> 4) & 0x0f;
+ sample = adpcm_decoder(v, states);
+ goto *put;
+#define PUT_S16_END after
+#include "plugin_ops.h"
+#undef PUT_S16_END
+ after:
+ src += src_step;
+ srcbit += srcbit_step;
+ if (srcbit == 8) {
+ src++;
+ srcbit = 0;
+ }
+ dst += dst_step;
+ }
+ }
+}
+
+static void adpcm_encode(snd_pcm_channel_area_t *src_areas,
+ size_t src_offset,
+ snd_pcm_channel_area_t *dst_areas,
+ size_t dst_offset,
+ size_t frames, size_t channels, int getidx,
+ adpcm_state_t *states)
+{
+#define GET_S16_LABELS
+#include "plugin_ops.h"
+#undef GET_S16_LABELS
+ void *get = get_s16_labels[getidx];
+ size_t channel;
+ int16_t sample = 0;
+ for (channel = 0; channel < channels; ++channel, ++states) {
+ char *src;
+ char *dst;
+ int dstbit;
+ int src_step, dst_step, dstbit_step;
+ size_t frames1;
+ snd_pcm_channel_area_t *src_area = &src_areas[channel];
+ snd_pcm_channel_area_t *dst_area = &dst_areas[channel];
+#if 0
+ if (!src_area->enabled) {
+ if (dst_area->wanted)
+ snd_pcm_area_silence(dst_area, dst_offset, frames, dst_sfmt);
+ dst_area->enabled = 0;
+ continue;
+ }
+ dst_area->enabled = 1;
+#endif
+ src = snd_pcm_channel_area_addr(src_area, src_offset);
+ src_step = snd_pcm_channel_area_step(src_area);
+ dstbit = dst_area->first + dst_area->step * dst_offset;
+ dst = dst_area->addr + dstbit / 8;
+ dstbit %= 8;
+ dst_step = dst_area->step / 8;
+ dstbit_step = dst_area->step % 8;
+ frames1 = frames;
+ while (frames1-- > 0) {
+ int v;
+ goto *get;
+#define GET_S16_END after
+#include "plugin_ops.h"
+#undef GET_S16_END
+ after:
+ v = adpcm_encoder(sample, states);
+ if (dstbit)
+ *dst = (*dst & 0xf0) | v;
+ else
+ *dst = (*dst & 0x0f) | (v << 4);
+ src += src_step;
+ dst += dst_step;
+ dstbit += dstbit_step;
+ if (dstbit == 8) {
+ dst++;
+ dstbit = 0;
+ }
+ }
+ }
+}
+
+static int snd_pcm_adpcm_close(snd_pcm_t *pcm)
+{
+ snd_pcm_adpcm_t *adpcm = pcm->private;
+ int err = 0;
+ if (adpcm->plug.close_slave)
+ err = snd_pcm_close(adpcm->plug.slave);
+ if (adpcm->states)
+ free(adpcm->states);
+ free(adpcm);
+ return 0;
+}
+
+static int snd_pcm_adpcm_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t * info)
+{
+ snd_pcm_adpcm_t *adpcm = pcm->private;
+ unsigned int req_mask = info->req_mask;
+ unsigned int sfmt = info->req.format.sfmt;
+ int err;
+ if (req_mask & SND_PCM_PARAMS_SFMT) {
+ if (adpcm->sformat == SND_PCM_SFMT_IMA_ADPCM ?
+ !snd_pcm_format_linear(sfmt) :
+ sfmt != SND_PCM_SFMT_IMA_ADPCM) {
+ info->req.fail_mask = SND_PCM_PARAMS_SFMT;
+ info->req.fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
+ return -EINVAL;
+ }
+ }
+ info->req_mask |= SND_PCM_PARAMS_SFMT;
+ info->req_mask &= ~(SND_PCM_PARAMS_MMAP_SHAPE |
+ SND_PCM_PARAMS_XFER_MODE);
+ info->req.format.sfmt = adpcm->sformat;
+ err = snd_pcm_params_info(adpcm->plug.slave, info);
+ info->req_mask = req_mask;
+ info->req.format.sfmt = sfmt;
+ if (err < 0)
+ return err;
+ if (req_mask & SND_PCM_PARAMS_SFMT)
+ info->formats = 1 << sfmt;
+ else
+ info->formats = adpcm->sformat == SND_PCM_SFMT_IMA_ADPCM ?
+ SND_PCM_LINEAR_FORMATS : 1 << SND_PCM_SFMT_IMA_ADPCM;
+ info->flags &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
+ info->flags |= SND_PCM_INFO_INTERLEAVED | SND_PCM_INFO_NONINTERLEAVED;
+ return err;
+}
+
+static int snd_pcm_adpcm_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
+{
+ snd_pcm_adpcm_t *adpcm = pcm->private;
+ snd_pcm_t *slave = adpcm->plug.slave;
+ int err;
+ if (adpcm->sformat == SND_PCM_SFMT_IMA_ADPCM ?
+ !snd_pcm_format_linear(params->format.sfmt) :
+ params->format.sfmt != SND_PCM_SFMT_IMA_ADPCM) {
+ params->fail_mask = SND_PCM_PARAMS_SFMT;
+ params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
+ return -EINVAL;
+ }
+ if (slave->mmap_data) {
+ err = snd_pcm_munmap_data(slave);
+ if (err < 0)
+ return err;
+ }
+ adpcm->cformat = params->format.sfmt;
+ adpcm->cxfer_mode = params->xfer_mode;
+ adpcm->cmmap_shape = params->mmap_shape;
+ params->format.sfmt = adpcm->sformat;
+ params->xfer_mode = SND_PCM_XFER_UNSPECIFIED;
+ params->mmap_shape = SND_PCM_MMAP_UNSPECIFIED;;
+ err = snd_pcm_params(slave, params);
+ params->format.sfmt = adpcm->cformat;
+ params->xfer_mode = adpcm->cxfer_mode;
+ params->mmap_shape = adpcm->cmmap_shape;
+ if (slave->valid_setup) {
+ int r = snd_pcm_mmap_data(slave, NULL);
+ assert(r >= 0);
+ }
+ return err;
+}
+
+static int snd_pcm_adpcm_setup(snd_pcm_t *pcm, snd_pcm_setup_t * setup)
+{
+ snd_pcm_adpcm_t *adpcm = pcm->private;
+ int err = snd_pcm_setup(adpcm->plug.slave, setup);
+ if (err < 0)
+ return err;
+ assert(adpcm->sformat == setup->format.sfmt);
+ if (adpcm->cxfer_mode == SND_PCM_XFER_UNSPECIFIED)
+ setup->xfer_mode = SND_PCM_XFER_NONINTERLEAVED;
+ else
+ setup->xfer_mode = adpcm->cxfer_mode;
+ if (adpcm->cmmap_shape == SND_PCM_MMAP_UNSPECIFIED)
+ setup->mmap_shape = SND_PCM_MMAP_NONINTERLEAVED;
+ else
+ setup->mmap_shape = adpcm->cmmap_shape;
+ setup->format.sfmt = adpcm->cformat;
+ setup->mmap_bytes = 0;
+ if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
+ if (adpcm->sformat == SND_PCM_SFMT_IMA_ADPCM) {
+ adpcm->getput_idx = getput_index(adpcm->cformat);
+ adpcm->func = adpcm_encode;
+ } else {
+ adpcm->getput_idx = getput_index(adpcm->sformat);
+ adpcm->func = adpcm_decode;
+ }
+ } else {
+ if (adpcm->sformat == SND_PCM_SFMT_IMA_ADPCM) {
+ adpcm->getput_idx = getput_index(adpcm->cformat);
+ adpcm->func = adpcm_decode;
+ } else {
+ adpcm->getput_idx = getput_index(adpcm->sformat);
+ adpcm->func = adpcm_encode;
+ }
+ }
+ if (adpcm->states)
+ free(adpcm->states);
+ adpcm->states = malloc(setup->format.channels * sizeof(*adpcm->states));
+ return 0;
+}
+
+static int snd_pcm_adpcm_init(snd_pcm_t *pcm)
+{
+ snd_pcm_adpcm_t *adpcm = pcm->private;
+ unsigned int k;
+ for (k = 0; k < pcm->setup.format.channels; ++k) {
+ adpcm->states[k].pred_val = 0;
+ adpcm->states[k].step_idx = 0;
+ }
+ return 0;
+}
+
+static ssize_t snd_pcm_adpcm_write_areas(snd_pcm_t *pcm,
+ snd_pcm_channel_area_t *areas,
+ size_t offset,
+ size_t size,
+ size_t *slave_sizep)
+{
+ snd_pcm_adpcm_t *adpcm = pcm->private;
+ snd_pcm_t *slave = adpcm->plug.slave;
+ size_t xfer = 0;
+ ssize_t err = 0;
+ if (slave_sizep && *slave_sizep < size)
+ size = *slave_sizep;
+ assert(size > 0);
+ while (xfer < size) {
+ size_t frames = snd_pcm_mmap_playback_xfer(slave, size - xfer);
+ adpcm->func(areas, offset,
+ slave->mmap_areas, snd_pcm_mmap_offset(slave),
+ frames, pcm->setup.format.channels,
+ adpcm->getput_idx, adpcm->states);
+ err = snd_pcm_mmap_forward(slave, frames);
+ if (err < 0)
+ break;
+ assert((size_t)err == frames);
+ offset += err;
+ xfer += err;
+ snd_pcm_mmap_hw_forward(pcm, err);
+ }
+ if (xfer > 0) {
+ if (slave_sizep)
+ *slave_sizep = xfer;
+ return xfer;
+ }
+ return err;
+}
+
+static ssize_t snd_pcm_adpcm_read_areas(snd_pcm_t *pcm,
+ snd_pcm_channel_area_t *areas,
+ size_t offset,
+ size_t size,
+ size_t *slave_sizep)
+{
+ snd_pcm_adpcm_t *adpcm = pcm->private;
+ snd_pcm_t *slave = adpcm->plug.slave;
+ size_t xfer = 0;
+ ssize_t err = 0;
+ if (slave_sizep && *slave_sizep < size)
+ size = *slave_sizep;
+ assert(size > 0);
+ while (xfer < size) {
+ size_t frames = snd_pcm_mmap_capture_xfer(slave, size - xfer);
+ adpcm->func(slave->mmap_areas, snd_pcm_mmap_offset(slave),
+ areas, offset,
+ frames, pcm->setup.format.channels,
+ adpcm->getput_idx, adpcm->states);
+ err = snd_pcm_mmap_forward(slave, frames);
+ if (err < 0)
+ break;
+ assert((size_t)err == frames);
+ offset += err;
+ xfer += err;
+ snd_pcm_mmap_hw_forward(pcm, err);
+ }
+ if (xfer > 0) {
+ if (slave_sizep)
+ *slave_sizep = xfer;
+ return xfer;
+ }
+ return err;
+}
+
+static void snd_pcm_adpcm_dump(snd_pcm_t *pcm, FILE *fp)
+{
+ snd_pcm_adpcm_t *adpcm = pcm->private;
+ fprintf(fp, "Ima-ADPCM conversion PCM (%s)\n",
+ snd_pcm_format_name(adpcm->sformat));
+ if (pcm->valid_setup) {
+ fprintf(fp, "Its setup is:\n");
+ snd_pcm_dump_setup(pcm, fp);
+ }
+ fprintf(fp, "Slave: ");
+ snd_pcm_dump(adpcm->plug.slave, fp);
+}
+
+struct snd_pcm_ops snd_pcm_adpcm_ops = {
+ close: snd_pcm_adpcm_close,
+ info: snd_pcm_plugin_info,
+ params_info: snd_pcm_adpcm_params_info,
+ params: snd_pcm_adpcm_params,
+ setup: snd_pcm_adpcm_setup,
+ channel_info: snd_pcm_plugin_channel_info,
+ channel_params: snd_pcm_plugin_channel_params,
+ channel_setup: snd_pcm_plugin_channel_setup,
+ dump: snd_pcm_adpcm_dump,
+ nonblock: snd_pcm_plugin_nonblock,
+ mmap_status: snd_pcm_plugin_mmap_status,
+ mmap_control: snd_pcm_plugin_mmap_control,
+ mmap_data: snd_pcm_plugin_mmap_data,
+ munmap_status: snd_pcm_plugin_munmap_status,
+ munmap_control: snd_pcm_plugin_munmap_control,
+ munmap_data: snd_pcm_plugin_munmap_data,
+};
+
+int snd_pcm_adpcm_open(snd_pcm_t **handlep, int sformat, snd_pcm_t *slave, int close_slave)
+{
+ snd_pcm_t *handle;
+ snd_pcm_adpcm_t *adpcm;
+ int err;
+ assert(handlep && slave);
+ if (snd_pcm_format_linear(sformat) != 1 &&
+ sformat != SND_PCM_SFMT_IMA_ADPCM)
+ return -EINVAL;
+ adpcm = calloc(1, sizeof(snd_pcm_adpcm_t));
+ if (!adpcm) {
+ return -ENOMEM;
+ }
+ adpcm->sformat = sformat;
+ adpcm->plug.read = snd_pcm_adpcm_read_areas;
+ adpcm->plug.write = snd_pcm_adpcm_write_areas;
+ adpcm->plug.init = snd_pcm_adpcm_init;
+ adpcm->plug.slave = slave;
+ adpcm->plug.close_slave = close_slave;
+
+ handle = calloc(1, sizeof(snd_pcm_t));
+ if (!handle) {
+ free(adpcm);
+ return -ENOMEM;
+ }
+ handle->type = SND_PCM_TYPE_ADPCM;
+ handle->stream = slave->stream;
+ handle->ops = &snd_pcm_adpcm_ops;
+ handle->op_arg = handle;
+ handle->fast_ops = &snd_pcm_plugin_fast_ops;
+ handle->fast_op_arg = handle;
+ handle->mode = slave->mode;
+ handle->private = adpcm;
+ err = snd_pcm_init(handle);
+ if (err < 0) {
+ snd_pcm_close(handle);
+ return err;
+ }
+ *handlep = handle;
+
+ return 0;
+}
+
+int _snd_pcm_adpcm_open(snd_pcm_t **pcmp, char *name,
+ snd_config_t *conf,
+ int stream, int mode)
+{
+ snd_config_iterator_t i;
+ char *sname = NULL;
+ int err;
+ snd_pcm_t *spcm;
+ int sformat = -1;
+ snd_config_foreach(i, conf) {
+ snd_config_t *n = snd_config_entry(i);
+ if (strcmp(n->id, "comment") == 0)
+ continue;
+ if (strcmp(n->id, "type") == 0)
+ continue;
+ if (strcmp(n->id, "stream") == 0)
+ continue;
+ if (strcmp(n->id, "sname") == 0) {
+ err = snd_config_string_get(n, &sname);
+ if (err < 0)
+ return -EINVAL;
+ continue;
+ }
+ if (strcmp(n->id, "sformat") == 0) {
+ char *f;
+ err = snd_config_string_get(n, &f);
+ if (err < 0)
+ return -EINVAL;
+ sformat = snd_pcm_format_value(f);
+ if (sformat < 0)
+ return -EINVAL;
+ if (snd_pcm_format_linear(sformat) != 1 &&
+ sformat != SND_PCM_SFMT_IMA_ADPCM)
+ return -EINVAL;
+ continue;
+ }
+ return -EINVAL;
+ }
+ if (!sname || !sformat)
+ return -EINVAL;
+ /* This is needed cause snd_config_update may destroy config */
+ sname = strdup(sname);
+ if (!sname)
+ return -ENOMEM;
+ err = snd_pcm_open(&spcm, sname, stream, mode);
+ free(sname);
+ if (err < 0)
+ return err;
+ err = snd_pcm_adpcm_open(pcmp, sformat, spcm, 1);
+ if (err < 0)
+ snd_pcm_close(spcm);
+ return err;
+}
+
+
diff --git a/src/pcm/pcm_alaw.c b/src/pcm/pcm_alaw.c
new file mode 100644
index 00000000..570de595
--- /dev/null
+++ b/src/pcm/pcm_alaw.c
@@ -0,0 +1,519 @@
+/*
+ * PCM - A-Law conversion
+ * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
+ *
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <byteswap.h>
+#include "pcm_local.h"
+#include "pcm_plugin.h"
+
+typedef void (*alaw_f)(snd_pcm_channel_area_t *src_areas,
+ size_t src_offset,
+ snd_pcm_channel_area_t *dst_areas,
+ size_t dst_offset,
+ size_t frames, size_t channels, int getputidx);
+
+typedef struct {
+ /* This field need to be the first */
+ snd_pcm_plugin_t plug;
+ int getput_idx;
+ alaw_f func;
+ int sformat;
+ int cformat;
+ int cxfer_mode, cmmap_shape;
+} snd_pcm_alaw_t;
+
+static inline int val_seg(int val)
+{
+ int r = 1;
+ val >>= 8;
+ if (val & 0xf0) {
+ val >>= 4;
+ r += 4;
+ }
+ if (val & 0x0c) {
+ val >>= 2;
+ r += 2;
+ }
+ if (val & 0x02)
+ r += 1;
+ return r;
+}
+
+/*
+ * s16_to_alaw() - Convert a 16-bit linear PCM value to 8-bit A-law
+ *
+ * s16_to_alaw() accepts an 16-bit integer and encodes it as A-law data.
+ *
+ * Linear Input Code Compressed Code
+ * ------------------------ ---------------
+ * 0000000wxyza 000wxyz
+ * 0000001wxyza 001wxyz
+ * 000001wxyzab 010wxyz
+ * 00001wxyzabc 011wxyz
+ * 0001wxyzabcd 100wxyz
+ * 001wxyzabcde 101wxyz
+ * 01wxyzabcdef 110wxyz
+ * 1wxyzabcdefg 111wxyz
+ *
+ * For further information see John C. Bellamy's Digital Telephony, 1982,
+ * John Wiley & Sons, pps 98-111 and 472-476.
+ */
+
+static unsigned char s16_to_alaw(int pcm_val)
+{
+ int mask;
+ int seg;
+ unsigned char aval;
+
+ if (pcm_val >= 0) {
+ mask = 0xD5;
+ } else {
+ mask = 0x55;
+ pcm_val = -pcm_val;
+ if (pcm_val > 0x7fff)
+ pcm_val = 0x7fff;
+ }
+
+ if (pcm_val < 256)
+ aval = pcm_val >> 4;
+ else {
+ /* Convert the scaled magnitude to segment number. */
+ seg = val_seg(pcm_val);
+ aval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0x0f);
+ }
+ return aval ^ mask;
+}
+
+/*
+ * alaw_to_s16() - Convert an A-law value to 16-bit linear PCM
+ *
+ */
+static int alaw_to_s16(unsigned char a_val)
+{
+ int t;
+ int seg;
+
+ a_val ^= 0x55;
+ t = a_val & 0x7f;
+ if (t < 16)
+ t = (t << 4) + 8;
+ else {
+ seg = (t >> 4) & 0x07;
+ t = ((t & 0x0f) << 4) + 0x108;
+ t <<= seg -1;
+ }
+ return ((a_val & 0x80) ? t : -t);
+}
+
+static void alaw_decode(snd_pcm_channel_area_t *src_areas,
+ size_t src_offset,
+ snd_pcm_channel_area_t *dst_areas,
+ size_t dst_offset,
+ size_t frames, size_t channels, int putidx)
+{
+#define PUT_S16_LABELS
+#include "plugin_ops.h"
+#undef PUT_S16_LABELS
+ void *put = put_s16_labels[putidx];
+ size_t channel;
+ for (channel = 0; channel < channels; ++channel) {
+ char *src;
+ char *dst;
+ int src_step, dst_step;
+ size_t frames1;
+ snd_pcm_channel_area_t *src_area = &src_areas[channel];
+ snd_pcm_channel_area_t *dst_area = &dst_areas[channel];
+#if 0
+ if (!src_area->enabled) {
+ if (dst_area->wanted)
+ snd_pcm_area_silence(&dst_areas[channel], dst_offset, frames, dst_sfmt);
+ dst_area->enabled = 0;
+ continue;
+ }
+ dst_area->enabled = 1;
+#endif
+ src = snd_pcm_channel_area_addr(src_area, src_offset);
+ dst = snd_pcm_channel_area_addr(dst_area, dst_offset);
+ src_step = snd_pcm_channel_area_step(src_area);
+ dst_step = snd_pcm_channel_area_step(dst_area);
+ frames1 = frames;
+ while (frames1-- > 0) {
+ int16_t sample = alaw_to_s16(*src);
+ goto *put;
+#define PUT_S16_END after
+#include "plugin_ops.h"
+#undef PUT_S16_END
+ after:
+ src += src_step;
+ dst += dst_step;
+ }
+ }
+}
+
+static void alaw_encode(snd_pcm_channel_area_t *src_areas,
+ size_t src_offset,
+ snd_pcm_channel_area_t *dst_areas,
+ size_t dst_offset,
+ size_t frames, size_t channels, int getidx)
+{
+#define GET_S16_LABELS
+#include "plugin_ops.h"
+#undef GET_S16_LABELS
+ void *get = get_s16_labels[getidx];
+ size_t channel;
+ int16_t sample = 0;
+ for (channel = 0; channel < channels; ++channel) {
+ char *src;
+ char *dst;
+ int src_step, dst_step;
+ size_t frames1;
+ snd_pcm_channel_area_t *src_area = &src_areas[channel];
+ snd_pcm_channel_area_t *dst_area = &dst_areas[channel];
+#if 0
+ if (!src_area->enabled) {
+ if (dst_area->wanted)
+ snd_pcm_area_silence(&dst_area->area, 0, frames, dst_sfmt);
+ dst_area->enabled = 0;
+ continue;
+ }
+ dst_area->enabled = 1;
+#endif
+ src = snd_pcm_channel_area_addr(src_area, src_offset);
+ dst = snd_pcm_channel_area_addr(dst_area, dst_offset);
+ src_step = snd_pcm_channel_area_step(src_area);
+ dst_step = snd_pcm_channel_area_step(dst_area);
+ frames1 = frames;
+ while (frames1-- > 0) {
+ goto *get;
+#define GET_S16_END after
+#include "plugin_ops.h"
+#undef GET_S16_END
+ after:
+ *dst = s16_to_alaw(sample);
+ src += src_step;
+ dst += dst_step;
+ }
+ }
+}
+
+static int snd_pcm_alaw_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t * info)
+{
+ snd_pcm_alaw_t *alaw = pcm->private;
+ unsigned int req_mask = info->req_mask;
+ unsigned int sfmt = info->req.format.sfmt;
+ int err;
+ if (req_mask & SND_PCM_PARAMS_SFMT) {
+ if (alaw->sformat == SND_PCM_SFMT_A_LAW ?
+ !snd_pcm_format_linear(sfmt) :
+ sfmt != SND_PCM_SFMT_A_LAW) {
+ info->req.fail_mask = SND_PCM_PARAMS_SFMT;
+ info->req.fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
+ return -EINVAL;
+ }
+ }
+ info->req_mask |= SND_PCM_PARAMS_SFMT;
+ info->req_mask &= ~(SND_PCM_PARAMS_MMAP_SHAPE |
+ SND_PCM_PARAMS_XFER_MODE);
+ info->req.format.sfmt = alaw->sformat;
+ err = snd_pcm_params_info(alaw->plug.slave, info);
+ info->req_mask = req_mask;
+ info->req.format.sfmt = sfmt;
+ if (err < 0)
+ return err;
+ if (req_mask & SND_PCM_PARAMS_SFMT)
+ info->formats = 1 << sfmt;
+ else
+ info->formats = alaw->sformat == SND_PCM_SFMT_A_LAW ?
+ SND_PCM_LINEAR_FORMATS : 1 << SND_PCM_SFMT_A_LAW;
+ info->flags &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
+ info->flags |= SND_PCM_INFO_INTERLEAVED | SND_PCM_INFO_NONINTERLEAVED;
+ return err;
+}
+
+static int snd_pcm_alaw_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
+{
+ snd_pcm_alaw_t *alaw = pcm->private;
+ snd_pcm_t *slave = alaw->plug.slave;
+ int err;
+ if (alaw->sformat == SND_PCM_SFMT_A_LAW ?
+ !snd_pcm_format_linear(params->format.sfmt) :
+ params->format.sfmt != SND_PCM_SFMT_A_LAW) {
+ params->fail_mask = SND_PCM_PARAMS_SFMT;
+ params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
+ return -EINVAL;
+ }
+ if (slave->mmap_data) {
+ err = snd_pcm_munmap_data(slave);
+ if (err < 0)
+ return err;
+ }
+ alaw->cformat = params->format.sfmt;
+ alaw->cxfer_mode = params->xfer_mode;
+ alaw->cmmap_shape = params->mmap_shape;
+ params->format.sfmt = alaw->sformat;
+ params->xfer_mode = SND_PCM_XFER_UNSPECIFIED;
+ params->mmap_shape = SND_PCM_MMAP_UNSPECIFIED;;
+ err = snd_pcm_params(slave, params);
+ params->format.sfmt = alaw->cformat;
+ params->xfer_mode = alaw->cxfer_mode;
+ params->mmap_shape = alaw->cmmap_shape;
+ if (slave->valid_setup) {
+ int r = snd_pcm_mmap_data(slave, NULL);
+ assert(r >= 0);
+ }
+ return err;
+}
+
+static int snd_pcm_alaw_setup(snd_pcm_t *pcm, snd_pcm_setup_t * setup)
+{
+ snd_pcm_alaw_t *alaw = pcm->private;
+ int err = snd_pcm_setup(alaw->plug.slave, setup);
+ if (err < 0)
+ return err;
+ assert(alaw->sformat == setup->format.sfmt);
+ if (alaw->cxfer_mode == SND_PCM_XFER_UNSPECIFIED)
+ setup->xfer_mode = SND_PCM_XFER_NONINTERLEAVED;
+ else
+ setup->xfer_mode = alaw->cxfer_mode;
+ if (alaw->cmmap_shape == SND_PCM_MMAP_UNSPECIFIED)
+ setup->mmap_shape = SND_PCM_MMAP_NONINTERLEAVED;
+ else
+ setup->mmap_shape = alaw->cmmap_shape;
+ setup->format.sfmt = alaw->cformat;
+ setup->mmap_bytes = 0;
+ if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
+ if (alaw->sformat == SND_PCM_SFMT_A_LAW) {
+ alaw->getput_idx = getput_index(alaw->cformat);
+ alaw->func = alaw_encode;
+ } else {
+ alaw->getput_idx = getput_index(alaw->sformat);
+ alaw->func = alaw_decode;
+ }
+ } else {
+ if (alaw->sformat == SND_PCM_SFMT_A_LAW) {
+ alaw->getput_idx = getput_index(alaw->cformat);
+ alaw->func = alaw_decode;
+ } else {
+ alaw->getput_idx = getput_index(alaw->sformat);
+ alaw->func = alaw_encode;
+ }
+ }
+ return 0;
+}
+
+static ssize_t snd_pcm_alaw_write_areas(snd_pcm_t *pcm,
+ snd_pcm_channel_area_t *areas,
+ size_t offset,
+ size_t size,
+ size_t *slave_sizep)
+{
+ snd_pcm_alaw_t *alaw = pcm->private;
+ snd_pcm_t *slave = alaw->plug.slave;
+ size_t xfer = 0;
+ ssize_t err = 0;
+ if (slave_sizep && *slave_sizep < size)
+ size = *slave_sizep;
+ assert(size > 0);
+ while (xfer < size) {
+ size_t frames = snd_pcm_mmap_playback_xfer(slave, size - xfer);
+ alaw->func(areas, offset,
+ slave->mmap_areas, snd_pcm_mmap_offset(slave),
+ frames, pcm->setup.format.channels,
+ alaw->getput_idx);
+ err = snd_pcm_mmap_forward(slave, frames);
+ if (err < 0)
+ break;
+ assert((size_t)err == frames);
+ offset += err;
+ xfer += err;
+ snd_pcm_mmap_hw_forward(pcm, err);
+ }
+ if (xfer > 0) {
+ if (slave_sizep)
+ *slave_sizep = xfer;
+ return xfer;
+ }
+ return err;
+}
+
+static ssize_t snd_pcm_alaw_read_areas(snd_pcm_t *pcm,
+ snd_pcm_channel_area_t *areas,
+ size_t offset,
+ size_t size,
+ size_t *slave_sizep)
+{
+ snd_pcm_alaw_t *alaw = pcm->private;
+ snd_pcm_t *slave = alaw->plug.slave;
+ size_t xfer = 0;
+ ssize_t err = 0;
+ if (slave_sizep && *slave_sizep < size)
+ size = *slave_sizep;
+ assert(size > 0);
+ while (xfer < size) {
+ size_t frames = snd_pcm_mmap_capture_xfer(slave, size - xfer);
+ alaw->func(slave->mmap_areas, snd_pcm_mmap_offset(slave),
+ areas, offset,
+ frames, pcm->setup.format.channels,
+ alaw->getput_idx);
+ err = snd_pcm_mmap_forward(slave, frames);
+ if (err < 0)
+ break;
+ assert((size_t)err == frames);
+ offset += err;
+ xfer += err;
+ snd_pcm_mmap_hw_forward(pcm, err);
+ }
+ if (xfer > 0) {
+ if (slave_sizep)
+ *slave_sizep = xfer;
+ return xfer;
+ }
+ return err;
+}
+
+static void snd_pcm_alaw_dump(snd_pcm_t *pcm, FILE *fp)
+{
+ snd_pcm_alaw_t *alaw = pcm->private;
+ fprintf(fp, "A-Law conversion PCM (%s)\n",
+ snd_pcm_format_name(alaw->sformat));
+ if (pcm->valid_setup) {
+ fprintf(fp, "Its setup is:\n");
+ snd_pcm_dump_setup(pcm, fp);
+ }
+ fprintf(fp, "Slave: ");
+ snd_pcm_dump(alaw->plug.slave, fp);
+}
+
+struct snd_pcm_ops snd_pcm_alaw_ops = {
+ close: snd_pcm_plugin_close,
+ info: snd_pcm_plugin_info,
+ params_info: snd_pcm_alaw_params_info,
+ params: snd_pcm_alaw_params,
+ setup: snd_pcm_alaw_setup,
+ channel_info: snd_pcm_plugin_channel_info,
+ channel_params: snd_pcm_plugin_channel_params,
+ channel_setup: snd_pcm_plugin_channel_setup,
+ dump: snd_pcm_alaw_dump,
+ nonblock: snd_pcm_plugin_nonblock,
+ mmap_status: snd_pcm_plugin_mmap_status,
+ mmap_control: snd_pcm_plugin_mmap_control,
+ mmap_data: snd_pcm_plugin_mmap_data,
+ munmap_status: snd_pcm_plugin_munmap_status,
+ munmap_control: snd_pcm_plugin_munmap_control,
+ munmap_data: snd_pcm_plugin_munmap_data,
+};
+
+int snd_pcm_alaw_open(snd_pcm_t **handlep, int sformat, snd_pcm_t *slave, int close_slave)
+{
+ snd_pcm_t *handle;
+ snd_pcm_alaw_t *alaw;
+ int err;
+ assert(handlep && slave);
+ if (snd_pcm_format_linear(sformat) != 1 &&
+ sformat != SND_PCM_SFMT_A_LAW)
+ return -EINVAL;
+ alaw = calloc(1, sizeof(snd_pcm_alaw_t));
+ if (!alaw) {
+ return -ENOMEM;
+ }
+ alaw->sformat = sformat;
+ alaw->plug.read = snd_pcm_alaw_read_areas;
+ alaw->plug.write = snd_pcm_alaw_write_areas;
+ alaw->plug.slave = slave;
+ alaw->plug.close_slave = close_slave;
+
+ handle = calloc(1, sizeof(snd_pcm_t));
+ if (!handle) {
+ free(alaw);
+ return -ENOMEM;
+ }
+ handle->type = SND_PCM_TYPE_ALAW;
+ handle->stream = slave->stream;
+ handle->ops = &snd_pcm_alaw_ops;
+ handle->op_arg = handle;
+ handle->fast_ops = &snd_pcm_plugin_fast_ops;
+ handle->fast_op_arg = handle;
+ handle->mode = slave->mode;
+ handle->private = alaw;
+ err = snd_pcm_init(handle);
+ if (err < 0) {
+ snd_pcm_close(handle);
+ return err;
+ }
+ *handlep = handle;
+
+ return 0;
+}
+
+int _snd_pcm_alaw_open(snd_pcm_t **pcmp, char *name,
+ snd_config_t *conf,
+ int stream, int mode)
+{
+ snd_config_iterator_t i;
+ char *sname = NULL;
+ int err;
+ snd_pcm_t *spcm;
+ int sformat = -1;
+ snd_config_foreach(i, conf) {
+ snd_config_t *n = snd_config_entry(i);
+ if (strcmp(n->id, "comment") == 0)
+ continue;
+ if (strcmp(n->id, "type") == 0)
+ continue;
+ if (strcmp(n->id, "stream") == 0)
+ continue;
+ if (strcmp(n->id, "sname") == 0) {
+ err = snd_config_string_get(n, &sname);
+ if (err < 0)
+ return -EINVAL;
+ continue;
+ }
+ if (strcmp(n->id, "sformat") == 0) {
+ char *f;
+ err = snd_config_string_get(n, &f);
+ if (err < 0)
+ return -EINVAL;
+ sformat = snd_pcm_format_value(f);
+ if (sformat < 0)
+ return -EINVAL;
+ if (snd_pcm_format_linear(sformat) != 1 &&
+ sformat != SND_PCM_SFMT_A_LAW)
+ return -EINVAL;
+ continue;
+ }
+ return -EINVAL;
+ }
+ if (!sname || !sformat)
+ return -EINVAL;
+ /* This is needed cause snd_config_update may destroy config */
+ sname = strdup(sname);
+ if (!sname)
+ return -ENOMEM;
+ err = snd_pcm_open(&spcm, sname, stream, mode);
+ free(sname);
+ if (err < 0)
+ return err;
+ err = snd_pcm_alaw_open(pcmp, sformat, spcm, 1);
+ if (err < 0)
+ snd_pcm_close(spcm);
+ return err;
+}
+
+
diff --git a/src/pcm/pcm_client.c b/src/pcm/pcm_client.c
index d0b865bc..7e7799ab 100644
--- a/src/pcm/pcm_client.c
+++ b/src/pcm/pcm_client.c
@@ -291,221 +291,116 @@ static int snd_pcm_client_shm_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
static int snd_pcm_client_shm_state(snd_pcm_t *pcm)
{
- snd_pcm_status_t status;
- int err = snd_pcm_client_shm_status(pcm, &status);
- if (err < 0)
- return err;
- return status.state;
-}
-
-static ssize_t snd_pcm_client_shm_hw_ptr(snd_pcm_t *pcm, int update)
-{
- snd_pcm_client_t *client = pcm->private;
- snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
- int err;
- ctrl->cmd = SND_PCM_IOCTL_HW_PTR;
- ctrl->u.hw_ptr = update;
- err = snd_pcm_client_shm_action(pcm);
- if (err < 0)
- return err;
- return ctrl->result;
-}
-
-static int snd_pcm_client_shm_prepare(snd_pcm_t *pcm)
-{
snd_pcm_client_t *client = pcm->private;
snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
int err;
- ctrl->cmd = SND_PCM_IOCTL_PREPARE;
+ ctrl->cmd = SND_PCM_IOCTL_STATE;
err = snd_pcm_client_shm_action(pcm);
if (err < 0)
return err;
return ctrl->result;
}
-static int snd_pcm_client_shm_go(snd_pcm_t *pcm)
+static int snd_pcm_client_shm_delay(snd_pcm_t *pcm, ssize_t *delayp)
{
snd_pcm_client_t *client = pcm->private;
snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
int err;
- ctrl->cmd = SND_PCM_IOCTL_GO;
+ ctrl->cmd = SND_PCM_IOCTL_DELAY;
err = snd_pcm_client_shm_action(pcm);
if (err < 0)
return err;
+ *delayp = ctrl->u.delay;
return ctrl->result;
}
-static int snd_pcm_client_shm_drain(snd_pcm_t *pcm)
+static ssize_t snd_pcm_client_avail_update(snd_pcm_t *pcm)
{
snd_pcm_client_t *client = pcm->private;
snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
int err;
- ctrl->cmd = SND_PCM_IOCTL_DRAIN;
+ ctrl->cmd = SND_PCM_IOCTL_AVAIL_UPDATE;
err = snd_pcm_client_shm_action(pcm);
if (err < 0)
return err;
return ctrl->result;
}
-static int snd_pcm_client_shm_flush(snd_pcm_t *pcm)
-{
- snd_pcm_client_t *client = pcm->private;
- snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
- int err;
- ctrl->cmd = SND_PCM_IOCTL_FLUSH;
- err = snd_pcm_client_shm_action(pcm);
- if (err < 0)
- return err;
- return ctrl->result;
-}
-
-static int snd_pcm_client_shm_pause(snd_pcm_t *pcm, int enable)
+static int snd_pcm_client_shm_prepare(snd_pcm_t *pcm)
{
snd_pcm_client_t *client = pcm->private;
snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
int err;
- ctrl->cmd = SND_PCM_IOCTL_PAUSE;
- ctrl->u.pause = enable;
+ ctrl->cmd = SND_PCM_IOCTL_PREPARE;
err = snd_pcm_client_shm_action(pcm);
if (err < 0)
return err;
return ctrl->result;
}
-static ssize_t snd_pcm_client_shm_appl_ptr(snd_pcm_t *pcm, off_t offset)
+static int snd_pcm_client_shm_start(snd_pcm_t *pcm)
{
snd_pcm_client_t *client = pcm->private;
snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
int err;
- ctrl->cmd = SND_PCM_IOCTL_APPL_PTR;
- ctrl->u.appl_ptr = offset;
+ ctrl->cmd = SND_PCM_IOCTL_START;
err = snd_pcm_client_shm_action(pcm);
if (err < 0)
return err;
return ctrl->result;
}
-static ssize_t snd_pcm_client_shm_write(snd_pcm_t *pcm, snd_timestamp_t *tstamp, const void *buffer, size_t size)
+static int snd_pcm_client_shm_stop(snd_pcm_t *pcm)
{
snd_pcm_client_t *client = pcm->private;
snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
- size_t maxsize = PCM_SHM_DATA_MAXLEN;
- size_t bytes = snd_pcm_frames_to_bytes(pcm, size);
int err;
- if (bytes > maxsize)
- return -EINVAL;
- ctrl->cmd = SND_PCM_IOCTL_WRITE_FRAMES;
-// ctrl->u.write.tstamp = *tstamp;
- ctrl->u.write.count = size;
- memcpy(ctrl->data, buffer, bytes);
+ ctrl->cmd = SND_PCM_IOCTL_STOP;
err = snd_pcm_client_shm_action(pcm);
if (err < 0)
return err;
return ctrl->result;
}
-static ssize_t snd_pcm_client_shm_writev(snd_pcm_t *pcm, snd_timestamp_t *tstamp, const struct iovec *vector, unsigned long count)
+static int snd_pcm_client_shm_flush(snd_pcm_t *pcm)
{
- /* FIXME: interleaved */
snd_pcm_client_t *client = pcm->private;
snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
- size_t vecsize = count * sizeof(struct iovec);
- size_t maxsize = PCM_SHM_DATA_MAXLEN;
- int bits_per_sample = pcm->bits_per_sample;
- char *base;
- struct iovec *vec;
- unsigned long k;
- size_t ofs;
int err;
- if (vecsize > maxsize)
- return -EINVAL;
- maxsize -= vecsize;
- ctrl->cmd = SND_PCM_IOCTL_WRITEV_FRAMES;
-// ctrl->u.writev.tstamp = *tstamp;
- ctrl->u.writev.count = count;
- memcpy(ctrl->data, vector, vecsize);
- vec = (struct iovec *) ctrl->data;
- base = ctrl->data + vecsize;
- ofs = 0;
- for (k = 0; k < count; ++k) {
- size_t len = vector[k].iov_len * bits_per_sample / 8;
- memcpy(base + ofs, vector[k].iov_base, len);
- vec[k].iov_base = (void *) ofs;
- ofs += len;
- }
+ ctrl->cmd = SND_PCM_IOCTL_FLUSH;
err = snd_pcm_client_shm_action(pcm);
if (err < 0)
return err;
return ctrl->result;
}
-static ssize_t snd_pcm_client_shm_read(snd_pcm_t *pcm, snd_timestamp_t *tstamp, void *buffer, size_t size)
+static int snd_pcm_client_shm_pause(snd_pcm_t *pcm, int enable)
{
snd_pcm_client_t *client = pcm->private;
snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
- size_t maxsize = PCM_SHM_DATA_MAXLEN;
- size_t bytes = snd_pcm_frames_to_bytes(pcm, size);
int err;
- if (bytes > maxsize)
- return -EINVAL;
- ctrl->cmd = SND_PCM_IOCTL_READ_FRAMES;
-// ctrl->u.read.tstamp = *tstamp;
- ctrl->u.read.count = size;
+ ctrl->cmd = SND_PCM_IOCTL_PAUSE;
+ ctrl->u.pause = enable;
err = snd_pcm_client_shm_action(pcm);
if (err < 0)
return err;
- if (ctrl->result <= 0)
- return ctrl->result;
- bytes = snd_pcm_frames_to_bytes(pcm, ctrl->result);
- memcpy(buffer, ctrl->data, bytes);
return ctrl->result;
}
-ssize_t snd_pcm_client_shm_readv(snd_pcm_t *pcm, snd_timestamp_t *tstamp, const struct iovec *vector, unsigned long count)
+static ssize_t snd_pcm_client_shm_appl_ptr(snd_pcm_t *pcm, off_t offset)
{
- /* FIXME: interleaved */
snd_pcm_client_t *client = pcm->private;
snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
- size_t vecsize = count * sizeof(struct iovec);
- size_t maxsize = PCM_SHM_DATA_MAXLEN;
- int bits_per_sample = pcm->bits_per_sample;
- char *base;
- struct iovec *vec;
- unsigned long k;
- size_t ofs, bytes;
int err;
- if (vecsize > maxsize)
- return -EINVAL;
- maxsize -= vecsize;
- ctrl->cmd = SND_PCM_IOCTL_WRITEV_FRAMES;
-// ctrl->u.writev.tstamp = *tstamp;
- ctrl->u.writev.count = count;
- memcpy(ctrl->data, vector, vecsize);
- vec = (struct iovec *) ctrl->data;
- base = ctrl->data + vecsize;
- ofs = 0;
- for (k = 0; k < count; ++k) {
- size_t len = vector[k].iov_len * bits_per_sample / 8;
- vec[k].iov_base = (void *) ofs;
- ofs += len;
- }
+ ctrl->cmd = SND_PCM_IOCTL_APPL_PTR;
+ ctrl->u.appl_ptr = offset;
err = snd_pcm_client_shm_action(pcm);
if (err < 0)
return err;
- if (ctrl->result <= 0)
- return ctrl->result;
- bytes = snd_pcm_frames_to_bytes(pcm, ctrl->result);
- ofs = 0;
- for (k = 0; k < count; ++k) {
- /* FIXME: optimize partial read */
- size_t len = vector[k].iov_len * bits_per_sample / 8;
- memcpy(vector[k].iov_base, base + ofs, len);
- ofs += len;
- }
return ctrl->result;
}
-static int snd_pcm_client_shm_mmap_status(snd_pcm_t *pcm, snd_pcm_mmap_status_t **status)
+static int snd_pcm_client_shm_mmap_status(snd_pcm_t *pcm)
{
snd_pcm_client_t *client = pcm->private;
snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
@@ -515,16 +410,17 @@ static int snd_pcm_client_shm_mmap_status(snd_pcm_t *pcm, snd_pcm_mmap_status_t
fd = snd_pcm_client_shm_action_fd(pcm);
if (fd < 0)
return fd;
+ /* FIXME: not mmap */
ptr = mmap(NULL, sizeof(snd_pcm_mmap_status_t), PROT_READ, MAP_FILE|MAP_SHARED,
fd, SND_PCM_MMAP_OFFSET_STATUS);
close(fd);
if (ptr == MAP_FAILED || ptr == NULL)
return -errno;
- *status = ptr;
+ pcm->mmap_status = ptr;
return 0;
}
-static int snd_pcm_client_shm_mmap_control(snd_pcm_t *pcm, snd_pcm_mmap_control_t **control)
+static int snd_pcm_client_shm_mmap_control(snd_pcm_t *pcm)
{
snd_pcm_client_t *client = pcm->private;
snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
@@ -534,16 +430,17 @@ static int snd_pcm_client_shm_mmap_control(snd_pcm_t *pcm, snd_pcm_mmap_control_
fd = snd_pcm_client_shm_action_fd(pcm);
if (fd < 0)
return fd;
+ /* FIXME: not mmap */
ptr = mmap(NULL, sizeof(snd_pcm_mmap_control_t), PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED,
fd, SND_PCM_MMAP_OFFSET_CONTROL);
close(fd);
if (ptr == MAP_FAILED || ptr == NULL)
return -errno;
- *control = ptr;
+ pcm->mmap_control = ptr;
return 0;
}
-static int snd_pcm_client_shm_mmap_data(snd_pcm_t *pcm, void **buffer, size_t bsize ATTRIBUTE_UNUSED)
+static int snd_pcm_client_shm_mmap_data(snd_pcm_t *pcm)
{
snd_pcm_client_t *client = pcm->private;
snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
@@ -554,19 +451,19 @@ static int snd_pcm_client_shm_mmap_data(snd_pcm_t *pcm, void **buffer, size_t bs
fd = snd_pcm_client_shm_action_fd(pcm);
if (fd < 0)
return fd;
+ /* FIXME: not mmap */
prot = pcm->stream == SND_PCM_STREAM_PLAYBACK ? PROT_WRITE : PROT_READ;
- ptr = mmap(NULL, bsize, prot, MAP_FILE|MAP_SHARED,
+ ptr = mmap(NULL, pcm->setup.mmap_bytes, prot, MAP_FILE|MAP_SHARED,
fd, SND_PCM_MMAP_OFFSET_DATA);
close(fd);
if (ptr == MAP_FAILED || ptr == NULL)
return -errno;
- *buffer = ptr;
+ pcm->mmap_data = ptr;
return 0;
}
-static int snd_pcm_client_shm_munmap_status(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_mmap_status_t *status ATTRIBUTE_UNUSED)
+static int snd_pcm_client_shm_munmap_status(snd_pcm_t *pcm)
{
-#if 0
snd_pcm_client_t *client = pcm->private;
snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
int err;
@@ -574,17 +471,14 @@ static int snd_pcm_client_shm_munmap_status(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd
err = snd_pcm_client_shm_action(pcm);
if (err < 0)
return err;
- return ctrl->result;
-#else
- if (munmap(status, sizeof(*status)) < 0)
+ /* FIXME: not mmap */
+ if (munmap(pcm->mmap_status, sizeof(*pcm->mmap_status)) < 0)
return -errno;
- return 0;
-#endif
+ return ctrl->result;
}
-static int snd_pcm_client_shm_munmap_control(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_mmap_control_t *control ATTRIBUTE_UNUSED)
+static int snd_pcm_client_shm_munmap_control(snd_pcm_t *pcm)
{
-#if 0
snd_pcm_client_t *client = pcm->private;
snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
int err;
@@ -592,17 +486,14 @@ static int snd_pcm_client_shm_munmap_control(snd_pcm_t *pcm ATTRIBUTE_UNUSED, sn
err = snd_pcm_client_shm_action(pcm);
if (err < 0)
return err;
- return ctrl->result;
-#else
- if (munmap(control, sizeof(*control)) < 0)
+ /* FIXME: not mmap */
+ if (munmap(pcm->mmap_control, sizeof(*pcm->mmap_control)) < 0)
return -errno;
- return 0;
-#endif
+ return ctrl->result;
}
-static int snd_pcm_client_shm_munmap_data(snd_pcm_t *pcm ATTRIBUTE_UNUSED, void *buffer, size_t bsize)
+static int snd_pcm_client_shm_munmap_data(snd_pcm_t *pcm)
{
-#if 0
snd_pcm_client_t *client = pcm->private;
snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
int err;
@@ -610,22 +501,33 @@ static int snd_pcm_client_shm_munmap_data(snd_pcm_t *pcm ATTRIBUTE_UNUSED, void
err = snd_pcm_client_shm_action(pcm);
if (err < 0)
return err;
- return ctrl->result;
-#else
- if (munmap(buffer, bsize) < 0)
+ /* FIXME: not mmap */
+ if (munmap(pcm->mmap_data, pcm->setup.mmap_bytes) < 0)
return -errno;
- return 0;
-#endif
+ return ctrl->result;
}
-static int snd_pcm_client_file_descriptor(snd_pcm_t *pcm)
+static ssize_t snd_pcm_client_mmap_forward(snd_pcm_t *pcm, size_t size)
+{
+ snd_pcm_client_t *client = pcm->private;
+ snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
+ int err;
+ ctrl->cmd = SND_PCM_IOCTL_MMAP_FORWARD;
+ ctrl->u.mmap_forward = size;
+ err = snd_pcm_client_shm_action(pcm);
+ if (err < 0)
+ return err;
+ return ctrl->result;
+}
+
+static int snd_pcm_client_poll_descriptor(snd_pcm_t *pcm)
{
snd_pcm_client_t *client = pcm->private;
return client->data_fd;
}
static int snd_pcm_client_channels_mask(snd_pcm_t *pcm ATTRIBUTE_UNUSED,
- bitset_t *client_vmask ATTRIBUTE_UNUSED)
+ bitset_t *cmask ATTRIBUTE_UNUSED)
{
return 0;
}
@@ -645,35 +547,37 @@ struct snd_pcm_ops snd_pcm_client_ops = {
params_info: snd_pcm_client_shm_params_info,
params: snd_pcm_client_shm_params,
setup: snd_pcm_client_shm_setup,
+ channel_info: snd_pcm_client_shm_channel_info,
+ channel_params: snd_pcm_client_shm_channel_params,
+ channel_setup: snd_pcm_client_shm_channel_setup,
dump: snd_pcm_client_dump,
+ nonblock: snd_pcm_client_shm_nonblock,
+ mmap_status: snd_pcm_client_shm_mmap_status,
+ mmap_control: snd_pcm_client_shm_mmap_control,
+ mmap_data: snd_pcm_client_shm_mmap_data,
+ munmap_status: snd_pcm_client_shm_munmap_status,
+ munmap_control: snd_pcm_client_shm_munmap_control,
+ munmap_data: snd_pcm_client_shm_munmap_data,
};
struct snd_pcm_fast_ops snd_pcm_client_fast_ops = {
- nonblock: snd_pcm_client_shm_nonblock,
- channel_info: snd_pcm_client_shm_channel_info,
- channel_params: snd_pcm_client_shm_channel_params,
- channel_setup: snd_pcm_client_shm_channel_setup,
status: snd_pcm_client_shm_status,
- hw_ptr: snd_pcm_client_shm_hw_ptr,
state: snd_pcm_client_shm_state,
+ delay: snd_pcm_client_shm_delay,
prepare: snd_pcm_client_shm_prepare,
- go: snd_pcm_client_shm_go,
- drain: snd_pcm_client_shm_drain,
+ start: snd_pcm_client_shm_start,
+ stop: snd_pcm_client_shm_stop,
flush: snd_pcm_client_shm_flush,
pause: snd_pcm_client_shm_pause,
appl_ptr: snd_pcm_client_shm_appl_ptr,
- write: snd_pcm_client_shm_write,
- writev: snd_pcm_client_shm_writev,
- read: snd_pcm_client_shm_read,
- readv: snd_pcm_client_shm_readv,
- mmap_status: snd_pcm_client_shm_mmap_status,
- mmap_control: snd_pcm_client_shm_mmap_control,
- mmap_data: snd_pcm_client_shm_mmap_data,
- munmap_status: snd_pcm_client_shm_munmap_status,
- munmap_control: snd_pcm_client_shm_munmap_control,
- munmap_data: snd_pcm_client_shm_munmap_data,
- file_descriptor: snd_pcm_client_file_descriptor,
+ writei: snd_pcm_mmap_writei,
+ writen: snd_pcm_mmap_writen,
+ readi: snd_pcm_mmap_readi,
+ readn: snd_pcm_mmap_readn,
+ poll_descriptor: snd_pcm_client_poll_descriptor,
channels_mask: snd_pcm_client_channels_mask,
+ avail_update: snd_pcm_client_avail_update,
+ mmap_forward: snd_pcm_client_mmap_forward,
};
static int make_local_socket(const char *filename)
@@ -830,14 +734,8 @@ int snd_pcm_client_create(snd_pcm_t **handlep, char *host, int port, int transpo
}
}
- handle = calloc(1, sizeof(snd_pcm_t));
- if (!handle) {
- result = -ENOMEM;
- goto _err;
- }
client = calloc(1, sizeof(snd_pcm_client_t));
- if (!handle) {
- free(handle);
+ if (!client) {
result = -ENOMEM;
goto _err;
}
@@ -849,6 +747,13 @@ int snd_pcm_client_create(snd_pcm_t **handlep, char *host, int port, int transpo
client->u.shm.ctrl = ctrl;
break;
}
+
+ handle = calloc(1, sizeof(snd_pcm_t));
+ if (!handle) {
+ free(client);
+ result = -ENOMEM;
+ goto _err;
+ }
handle->type = SND_PCM_TYPE_CLIENT;
handle->stream = stream;
handle->ops = &snd_pcm_client_ops;
@@ -857,6 +762,11 @@ int snd_pcm_client_create(snd_pcm_t **handlep, char *host, int port, int transpo
handle->fast_op_arg = handle;
handle->mode = mode;
handle->private = client;
+ err = snd_pcm_init(handle);
+ if (err < 0) {
+ snd_pcm_close(handle);
+ return err;
+ }
*handlep = handle;
return 0;
@@ -874,3 +784,59 @@ int snd_pcm_client_create(snd_pcm_t **handlep, char *host, int port, int transpo
return result;
}
+int _snd_pcm_client_open(snd_pcm_t **pcmp, char *name, snd_config_t *conf,
+ int stream, int mode)
+{
+ snd_config_iterator_t i;
+ char *socket = NULL;
+ char *sname = NULL;
+ char *host = NULL;
+ long port = -1;
+ int err;
+ snd_config_foreach(i, conf) {
+ snd_config_t *n = snd_config_entry(i);
+ if (strcmp(n->id, "comment") == 0)
+ continue;
+ if (strcmp(n->id, "type") == 0)
+ continue;
+ if (strcmp(n->id, "stream") == 0)
+ continue;
+ if (strcmp(n->id, "socket") == 0) {
+ err = snd_config_string_get(n, &socket);
+ if (err < 0)
+ return -EINVAL;
+ continue;
+ }
+ if (strcmp(n->id, "host") == 0) {
+ err = snd_config_string_get(n, &host);
+ if (err < 0)
+ return -EINVAL;
+ continue;
+ }
+ if (strcmp(n->id, "port") == 0) {
+ err = snd_config_integer_get(n, &port);
+ if (err < 0)
+ return -EINVAL;
+ continue;
+ }
+ if (strcmp(n->id, "sname") == 0) {
+ err = snd_config_string_get(n, &sname);
+ if (err < 0)
+ return -EINVAL;
+ continue;
+ }
+ return -EINVAL;
+ }
+ if (!sname)
+ return -EINVAL;
+ if (socket) {
+ if (port >= 0 || host)
+ return -EINVAL;
+ return snd_pcm_client_create(pcmp, socket, -1, SND_TRANSPORT_TYPE_SHM, sname, stream, mode);
+ } else {
+ if (port < 0 || !name)
+ return -EINVAL;
+ return snd_pcm_client_create(pcmp, host, port, SND_TRANSPORT_TYPE_TCP, sname, stream, mode);
+ }
+}
+
diff --git a/src/pcm/pcm_common.c b/src/pcm/pcm_common.c
deleted file mode 100644
index ae947ecf..00000000
--- a/src/pcm/pcm_common.c
+++ /dev/null
@@ -1,1274 +0,0 @@
-/*
- * PCM Plug-In shared (kernel/library) code
- * Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>
- * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
- *
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Library General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#if 0
-#define PLUGIN_DEBUG
-#endif
-#ifdef __KERNEL__
-#include "../../include/driver.h"
-#include "../../include/pcm.h"
-#define snd_pcm_plug_first(plug) ((plug)->runtime->oss.plugin_first)
-#define snd_pcm_plug_last(plug) ((plug)->runtime->oss.plugin_last)
-#define __vmalloc snd_vmalloc
-#define __vfree snd_vfree
-#else
-#include <malloc.h>
-#include <errno.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/uio.h>
-#include "pcm_local.h"
-#define snd_pcm_plug_first(plug) ((plug)->first)
-#define snd_pcm_plug_last(plug) ((plug)->last)
-#define __vmalloc malloc
-#define __vfree free
-#endif
-
-static int snd_pcm_plugin_src_channels_mask(snd_pcm_plugin_t *plugin,
- bitset_t *dst_vmask,
- bitset_t **src_vmask)
-{
- bitset_t *vmask = plugin->src_vmask;
- bitset_copy(vmask, dst_vmask, plugin->src_format.channels);
- *src_vmask = vmask;
- return 0;
-}
-
-static int snd_pcm_plugin_dst_channels_mask(snd_pcm_plugin_t *plugin,
- bitset_t *src_vmask,
- bitset_t **dst_vmask)
-{
- bitset_t *vmask = plugin->dst_vmask;
- bitset_copy(vmask, src_vmask, plugin->dst_format.channels);
- *dst_vmask = vmask;
- return 0;
-}
-
-static int snd_pcm_plugin_alloc(snd_pcm_plugin_t *plugin, size_t frames)
-{
- snd_pcm_format_t *format;
- ssize_t width;
- size_t size;
- unsigned int channel;
- snd_pcm_plugin_channel_t *c;
- if (plugin->stream == SND_PCM_STREAM_PLAYBACK)
- format = &plugin->src_format;
- else
- format = &plugin->dst_format;
- if ((width = snd_pcm_format_physical_width(format->format)) < 0)
- return width;
- size = frames * format->channels * width;
- assert(size % 8 == 0);
- size /= 8;
- if (plugin->buf_frames < frames) {
- if (plugin->buf)
- __vfree(plugin->buf);
- plugin->buf = __vmalloc(size);
- plugin->buf_frames = frames;
- }
- if (!plugin->buf)
- return -ENOMEM;
- c = plugin->buf_channels;
- if (format->interleave) {
- for (channel = 0; channel < format->channels; channel++, c++) {
- c->enabled = 1;
- c->wanted = 0;
- c->area.addr = plugin->buf;
- c->area.first = channel * width;
- c->area.step = format->channels * width;
- }
- } else {
- assert(size % format->channels == 0);
- size /= format->channels;
- for (channel = 0; channel < format->channels; channel++, c++) {
- c->enabled = 1;
- c->wanted = 0;
- c->area.addr = plugin->buf + (channel * size);
- c->area.first = 0;
- c->area.step = width;
- }
- }
- return 0;
-}
-
-int snd_pcm_plug_alloc(snd_pcm_plug_t *plug, size_t frames)
-{
- int err;
-#ifndef __KERNEL__
- plug->frames_alloc = frames;
-#endif
- assert(snd_pcm_plug_first(plug));
- if (snd_pcm_plug_stream(plug) == SND_PCM_STREAM_PLAYBACK) {
- snd_pcm_plugin_t *plugin = snd_pcm_plug_first(plug);
- while (plugin->next) {
- if (plugin->dst_frames)
- frames = plugin->dst_frames(plugin, frames);
- assert(frames > 0);
- plugin = plugin->next;
- err = snd_pcm_plugin_alloc(plugin, frames);
- if (err < 0)
- return err;
- }
- } else {
- snd_pcm_plugin_t *plugin = snd_pcm_plug_last(plug);
- while (plugin->prev) {
- if (plugin->src_frames)
- frames = plugin->src_frames(plugin, frames);
- assert(frames > 0);
- plugin = plugin->prev;
- err = snd_pcm_plugin_alloc(plugin, frames);
- if (err < 0)
- return err;
- }
- }
- return 0;
-}
-
-
-ssize_t snd_pcm_plugin_client_channels(snd_pcm_plugin_t *plugin,
- size_t frames,
- snd_pcm_plugin_channel_t **channels)
-{
- assert(frames <= plugin->buf_frames);
- *channels = plugin->buf_channels;
- return frames;
-}
-
-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)
-{
- snd_pcm_plugin_t *plugin;
- size_t channels;
-
- assert(plug);
- assert(src_format && dst_format);
- plugin = (snd_pcm_plugin_t *)calloc(1, sizeof(*plugin) + extra);
- if (plugin == NULL)
- return -ENOMEM;
- plugin->name = name ? strdup(name) : NULL;
- plugin->plug = plug;
- plugin->stream = snd_pcm_plug_stream(plug);
- plugin->src_format = *src_format;
- plugin->src_width = snd_pcm_format_physical_width(src_format->format);
- assert(plugin->src_width > 0);
- plugin->dst_format = *dst_format;
- plugin->dst_width = snd_pcm_format_physical_width(dst_format->format);
- assert(plugin->dst_width > 0);
- if (plugin->stream == SND_PCM_STREAM_PLAYBACK)
- channels = src_format->channels;
- else
- channels = dst_format->channels;
- plugin->buf_channels = calloc(channels, sizeof(*plugin->buf_channels));
- if (plugin->buf_channels == NULL) {
- free(plugin);
- return -ENOMEM;
- }
- plugin->src_vmask = bitset_alloc(src_format->channels);
- if (plugin->src_vmask == NULL) {
- free(plugin->buf_channels);
- free(plugin);
- return -ENOMEM;
- }
- plugin->dst_vmask = bitset_alloc(dst_format->channels);
- if (plugin->dst_vmask == NULL) {
- free(plugin->buf_channels);
- free(plugin->src_vmask);
- free(plugin);
- return -ENOMEM;
- }
- plugin->client_channels = snd_pcm_plugin_client_channels;
- plugin->src_channels_mask = snd_pcm_plugin_src_channels_mask;
- plugin->dst_channels_mask = snd_pcm_plugin_dst_channels_mask;
- *ret = plugin;
- return 0;
-}
-
-int snd_pcm_plugin_free(snd_pcm_plugin_t *plugin)
-{
- assert(plugin);
- if (plugin->private_free)
- plugin->private_free(plugin);
- if (plugin->name)
- free(plugin->name);
- free(plugin->buf_channels);
- if (plugin->buf)
- __vfree(plugin->buf);
- free(plugin->src_vmask);
- free(plugin->dst_vmask);
- free(plugin);
- return 0;
-}
-
-ssize_t snd_pcm_plug_client_size(snd_pcm_plug_t *plug, size_t drv_frames)
-{
- snd_pcm_plugin_t *plugin, *plugin_prev, *plugin_next;
- int stream = snd_pcm_plug_stream(plug);
-
- assert(plug);
- if (drv_frames == 0)
- return 0;
- if (stream == SND_PCM_STREAM_PLAYBACK) {
- plugin = snd_pcm_plug_last(plug);
- while (plugin && drv_frames > 0) {
- plugin_prev = plugin->prev;
- if (plugin->src_frames)
- drv_frames = plugin->src_frames(plugin, drv_frames);
- plugin = plugin_prev;
- }
- } else if (stream == SND_PCM_STREAM_CAPTURE) {
- plugin = snd_pcm_plug_first(plug);
- while (plugin && drv_frames > 0) {
- plugin_next = plugin->next;
- if (plugin->dst_frames)
- drv_frames = plugin->dst_frames(plugin, drv_frames);
- plugin = plugin_next;
- }
- } else
- assert(0);
- return drv_frames;
-}
-
-ssize_t snd_pcm_plug_slave_size(snd_pcm_plug_t *plug, size_t clt_frames)
-{
- snd_pcm_plugin_t *plugin, *plugin_prev, *plugin_next;
- ssize_t frames;
- int stream = snd_pcm_plug_stream(plug);
-
- assert(plug);
- if (clt_frames == 0)
- return 0;
- frames = clt_frames;
- if (stream == SND_PCM_STREAM_PLAYBACK) {
- plugin = snd_pcm_plug_first(plug);
- while (plugin && frames > 0) {
- plugin_next = plugin->next;
- if (plugin->dst_frames) {
- frames = plugin->dst_frames(plugin, frames);
- if (frames < 0)
- return frames;
- }
- plugin = plugin_next;
- }
- } else if (stream == SND_PCM_STREAM_CAPTURE) {
- plugin = snd_pcm_plug_last(plug);
- while (plugin) {
- plugin_prev = plugin->prev;
- if (plugin->src_frames) {
- frames = plugin->src_frames(plugin, frames);
- if (frames < 0)
- return frames;
- }
- plugin = plugin_prev;
- }
- } else
- assert(0);
- return frames;
-}
-
-unsigned int snd_pcm_plug_formats(unsigned int formats)
-{
- int linfmts = (SND_PCM_FMT_U8 | SND_PCM_FMT_S8 |
- SND_PCM_FMT_U16_LE | SND_PCM_FMT_S16_LE |
- SND_PCM_FMT_U16_BE | SND_PCM_FMT_S16_BE |
- SND_PCM_FMT_U24_LE | SND_PCM_FMT_S24_LE |
- SND_PCM_FMT_U24_BE | SND_PCM_FMT_S24_BE |
- SND_PCM_FMT_U32_LE | SND_PCM_FMT_S32_LE |
- SND_PCM_FMT_U32_BE | SND_PCM_FMT_S32_BE);
- formats |= SND_PCM_FMT_MU_LAW;
-#ifndef __KERNEL__
- formats |= SND_PCM_FMT_A_LAW | SND_PCM_FMT_IMA_ADPCM;
-#endif
-
- if (formats & linfmts)
- formats |= linfmts;
- return formats;
-}
-
-static int preferred_formats[] = {
- SND_PCM_SFMT_S16_LE,
- SND_PCM_SFMT_S16_BE,
- SND_PCM_SFMT_U16_LE,
- SND_PCM_SFMT_U16_BE,
- SND_PCM_SFMT_S24_LE,
- SND_PCM_SFMT_S24_BE,
- SND_PCM_SFMT_U24_LE,
- SND_PCM_SFMT_U24_BE,
- SND_PCM_SFMT_S32_LE,
- SND_PCM_SFMT_S32_BE,
- SND_PCM_SFMT_U32_LE,
- SND_PCM_SFMT_U32_BE,
- SND_PCM_SFMT_S8,
- SND_PCM_SFMT_U8
-};
-
-int snd_pcm_plug_slave_fmt(int format, snd_pcm_params_info_t *slave_info)
-{
- if ((snd_pcm_plug_formats(slave_info->formats) & (1 << format)) == 0)
- return -EINVAL;
- if (snd_pcm_format_linear(format)) {
- int width = snd_pcm_format_width(format);
- int unsignd = snd_pcm_format_unsigned(format);
- int big = snd_pcm_format_big_endian(format);
- int format1;
- int wid, width1=width;
- int dwidth1 = 8;
- for (wid = 0; wid < 4; ++wid) {
- int end, big1 = big;
- for (end = 0; end < 2; ++end) {
- int sgn, unsignd1 = unsignd;
- for (sgn = 0; sgn < 2; ++sgn) {
- format1 = snd_pcm_build_linear_format(width1, unsignd1, big1);
- if (format1 >= 0 &&
- slave_info->formats & (1 << format1))
- goto _found;
- unsignd1 = !unsignd1;
- }
- big1 = !big1;
- }
- if (width1 == 32) {
- dwidth1 = -dwidth1;
- width1 = width;
- }
- width1 += dwidth1;
- }
- return -EINVAL;
- _found:
- return format1;
- } else {
- unsigned int i;
- switch (format) {
- case SND_PCM_SFMT_MU_LAW:
-#ifndef __KERNEL__
- case SND_PCM_SFMT_A_LAW:
- case SND_PCM_SFMT_IMA_ADPCM:
-#endif
- for (i = 0; i < sizeof(preferred_formats) / sizeof(preferred_formats[0]); ++i) {
- int format1 = preferred_formats[i];
- if (slave_info->formats & (1 << format1))
- return format1;
- }
- default:
- return -EINVAL;
- }
- }
-}
-
-struct {
- unsigned int rate;
- unsigned int flag;
-} snd_pcm_rates[] = {
- { 8000, SND_PCM_RATE_8000 },
- { 11025, SND_PCM_RATE_11025 },
- { 16000, SND_PCM_RATE_16000 },
- { 22050, SND_PCM_RATE_22050 },
- { 32000, SND_PCM_RATE_32000 },
- { 44100, SND_PCM_RATE_44100 },
- { 48000, SND_PCM_RATE_48000 },
- { 88200, SND_PCM_RATE_88200 },
- { 96000, SND_PCM_RATE_96000 },
- { 176400, SND_PCM_RATE_176400 },
- { 192000, SND_PCM_RATE_192000 }
-};
-
-int snd_pcm_plug_slave_rate(unsigned int rate, snd_pcm_params_info_t *slave_info)
-{
- if (rate <= slave_info->min_rate)
- return slave_info->min_rate;
- else if (rate >= slave_info->max_rate)
- return slave_info->max_rate;
- else if (!(slave_info->rates & (SND_PCM_RATE_CONTINUOUS |
- SND_PCM_RATE_KNOT))) {
- unsigned int k;
- unsigned int rate1 = 0, rate2 = 0;
- int delta1, delta2;
- for (k = 0; k < sizeof(snd_pcm_rates) /
- sizeof(snd_pcm_rates[0]); ++k) {
- if (!(snd_pcm_rates[k].flag & slave_info->rates))
- continue;
- if (snd_pcm_rates[k].rate < rate) {
- rate1 = snd_pcm_rates[k].rate;
- } else if (snd_pcm_rates[k].rate >= rate) {
- rate2 = snd_pcm_rates[k].rate;
- break;
- }
- }
- if (rate1 == 0)
- return rate2;
- if (rate2 == 0)
- return rate1;
- delta1 = rate - rate1;
- delta2 = rate2 - rate;
- if (delta1 < delta2)
- return rate1;
- else
- return rate2;
- }
- return rate;
-}
-
-int snd_pcm_plug_slave_format(snd_pcm_format_t *format,
- snd_pcm_info_t *slave_info,
- snd_pcm_params_info_t *slave_params_info,
- snd_pcm_format_t *slave_format)
-{
- int slave_rate;
- *slave_format = *format;
- if ((slave_params_info->formats & (1 << format->format)) == 0) {
- int slave_fmt = snd_pcm_plug_slave_fmt(format->format, slave_params_info);
- if (slave_fmt < 0)
- return slave_fmt;
- slave_format->format = slave_fmt;
- }
-
- /* channels */
- if (format->channels < slave_params_info->min_channels)
- slave_format->channels = slave_params_info->min_channels;
- else if (format->channels > slave_params_info->max_channels)
- slave_format->channels = slave_params_info->max_channels;
-
- /* rate */
- slave_rate = snd_pcm_plug_slave_rate(format->rate, slave_params_info);
- if (slave_rate < 0)
- return slave_rate;
- slave_format->rate = slave_rate;
-
- /* interleave */
- if (!(slave_info->flags & SND_PCM_INFO_INTERLEAVE))
- slave_format->interleave = 0;
- if (!(slave_info->flags & SND_PCM_INFO_NONINTERLEAVE))
- slave_format->interleave = 1;
- return 0;
-}
-
-int snd_pcm_plug_format_plugins(snd_pcm_plug_t *plug,
- snd_pcm_format_t *format,
- snd_pcm_format_t *slave_format)
-{
- snd_pcm_format_t tmpformat;
- snd_pcm_format_t dstformat;
- snd_pcm_format_t *srcformat;
- snd_pcm_plugin_t *plugin;
- int err;
-
- switch (snd_pcm_plug_stream(plug)) {
- case SND_PCM_STREAM_PLAYBACK:
- dstformat = *slave_format;
- srcformat = slave_format;
- *srcformat = *format;
- break;
- case SND_PCM_STREAM_CAPTURE:
- dstformat = *format;
- srcformat = format;
- *srcformat = *slave_format;
- break;
- default:
- assert(0);
- return -EINVAL;
- }
- tmpformat = *srcformat;
-
- pdprintf("srcformat: interleave=%i, format=%i, rate=%i, channels=%i\n",
- srcformat->interleave,
- srcformat->format,
- srcformat->rate,
- srcformat->channels);
- pdprintf("dstformat: interleave=%i, format=%i, rate=%i, channels=%i\n",
- dstformat.interleave,
- dstformat.format,
- dstformat.rate,
- dstformat.channels);
-
- if (srcformat->channels == 1)
- srcformat->interleave = dstformat.interleave;
-
- /* Format change (linearization) */
- if ((srcformat->format != dstformat.format ||
- srcformat->rate != dstformat.rate ||
- srcformat->channels != dstformat.channels) &&
- !snd_pcm_format_linear(srcformat->format)) {
- if (snd_pcm_format_linear(dstformat.format))
- tmpformat.format = dstformat.format;
- else
- tmpformat.format = SND_PCM_SFMT_S16;
- tmpformat.interleave = dstformat.interleave;
- switch (srcformat->format) {
- case SND_PCM_SFMT_MU_LAW:
- err = snd_pcm_plugin_build_mulaw(plug,
- srcformat, &tmpformat,
- &plugin);
- break;
-#ifndef __KERNEL__
- case SND_PCM_SFMT_A_LAW:
- err = snd_pcm_plugin_build_alaw(plug,
- srcformat, &tmpformat,
- &plugin);
- break;
- case SND_PCM_SFMT_IMA_ADPCM:
- err = snd_pcm_plugin_build_adpcm(plug,
- srcformat, &tmpformat,
- &plugin);
- break;
-#endif
- default:
- return -EINVAL;
- }
- pdprintf("format format change: src=%i, dst=%i returns %i\n", srcformat->format, tmpformat.format, err);
- if (err < 0)
- return err;
- err = snd_pcm_plugin_append(plugin);
- if (err < 0) {
- snd_pcm_plugin_free(plugin);
- return err;
- }
- *srcformat = tmpformat;
- }
-
- /* channels reduction */
- if (srcformat->channels > dstformat.channels) {
- int sv = srcformat->channels;
- int dv = dstformat.channels;
- route_ttable_entry_t *ttable = calloc(1, dv*sv*sizeof(*ttable));
-#if 1
- if (sv == 2 && dv == 1) {
- ttable[0] = HALF;
- ttable[1] = HALF;
- } else
-#endif
- {
- int v;
- for (v = 0; v < dv; ++v)
- ttable[v * sv + v] = FULL;
- }
- tmpformat.channels = dstformat.channels;
- tmpformat.interleave = dstformat.interleave;
- if (srcformat->rate == dstformat.rate &&
- snd_pcm_format_linear(dstformat.format))
- tmpformat.format = dstformat.format;
- err = snd_pcm_plugin_build_route(plug,
- srcformat, &tmpformat,
- ttable, &plugin);
- free(ttable);
- pdprintf("format channels reduction: src=%i, dst=%i returns %i\n", srcformat->channels, tmpformat.channels, err);
- if (err < 0) {
- snd_pcm_plugin_free(plugin);
- return err;
- }
- err = snd_pcm_plugin_append(plugin);
- if (err < 0) {
- snd_pcm_plugin_free(plugin);
- return err;
- }
- *srcformat = tmpformat;
- }
-
- /* rate resampling */
- if (srcformat->rate != dstformat.rate) {
- tmpformat.rate = dstformat.rate;
- tmpformat.interleave = dstformat.interleave;
- if (srcformat->channels == dstformat.channels &&
- snd_pcm_format_linear(dstformat.format))
- tmpformat.format = dstformat.format;
- err = snd_pcm_plugin_build_rate(plug,
- srcformat, &tmpformat,
- &plugin);
- pdprintf("format rate down resampling: src=%i, dst=%i returns %i\n", srcformat->rate, tmpformat.rate, err);
- if (err < 0) {
- snd_pcm_plugin_free(plugin);
- return err;
- }
- err = snd_pcm_plugin_append(plugin);
- if (err < 0) {
- snd_pcm_plugin_free(plugin);
- return err;
- }
- *srcformat = tmpformat;
- }
-
- /* channels extension */
- if (srcformat->channels < dstformat.channels) {
- int sv = srcformat->channels;
- int dv = dstformat.channels;
- route_ttable_entry_t *ttable = calloc(1, dv * sv * sizeof(*ttable));
-#if 0
- {
- int v;
- for (v = 0; v < sv; ++v)
- ttable[v * sv + v] = FULL;
- }
-#else
- {
- /* Playback is spreaded on all channels */
- int vd, vs;
- for (vd = 0, vs = 0; vd < dv; ++vd) {
- ttable[vd * sv + vs] = FULL;
- vs++;
- if (vs == sv)
- vs = 0;
- }
- }
-#endif
- tmpformat.channels = dstformat.channels;
- tmpformat.interleave = dstformat.interleave;
- if (snd_pcm_format_linear(dstformat.format))
- tmpformat.format = dstformat.format;
- err = snd_pcm_plugin_build_route(plug,
- srcformat, &tmpformat,
- ttable, &plugin);
- free(ttable);
- pdprintf("format channels extension: src=%i, dst=%i returns %i\n", srcformat->channels, tmpformat.channels, err);
- if (err < 0) {
- snd_pcm_plugin_free(plugin);
- return err;
- }
- err = snd_pcm_plugin_append(plugin);
- if (err < 0) {
- snd_pcm_plugin_free(plugin);
- return err;
- }
- *srcformat = tmpformat;
- }
-
- /* format change */
- if (srcformat->format != dstformat.format) {
- tmpformat.format = dstformat.format;
- tmpformat.interleave = dstformat.interleave;
- if (tmpformat.format == SND_PCM_SFMT_MU_LAW) {
- err = snd_pcm_plugin_build_mulaw(plug,
- srcformat, &tmpformat,
- &plugin);
- }
-#ifndef __KERNEL__
- else if (tmpformat.format == SND_PCM_SFMT_A_LAW) {
- err = snd_pcm_plugin_build_alaw(plug,
- srcformat, &tmpformat,
- &plugin);
- }
- else if (tmpformat.format == SND_PCM_SFMT_IMA_ADPCM) {
- err = snd_pcm_plugin_build_adpcm(plug,
- srcformat, &tmpformat,
- &plugin);
- }
-#endif
- else if (snd_pcm_format_linear(srcformat->format) &&
- snd_pcm_format_linear(tmpformat.format)) {
- err = snd_pcm_plugin_build_linear(plug,
- srcformat, &tmpformat,
- &plugin);
- }
- else
- return -EINVAL;
- pdprintf("format format change: src=%i, dst=%i returns %i\n", srcformat->format, tmpformat.format, err);
- if (err < 0)
- return err;
- err = snd_pcm_plugin_append(plugin);
- if (err < 0) {
- snd_pcm_plugin_free(plugin);
- return err;
- }
- *srcformat = tmpformat;
- }
-
- /* interleave */
- if (srcformat->interleave != dstformat.interleave) {
- tmpformat.interleave = dstformat.interleave;
- err = snd_pcm_plugin_build_copy(plug,
- srcformat, &tmpformat,
- &plugin);
- pdprintf("interleave change: src=%i, dst=%i returns %i\n", srcformat->interleave, tmpformat.interleave, err);
- if (err < 0)
- return err;
- err = snd_pcm_plugin_append(plugin);
- if (err < 0) {
- snd_pcm_plugin_free(plugin);
- return err;
- }
- *srcformat = tmpformat;
- }
-
- return 0;
-}
-
-ssize_t snd_pcm_plug_client_channels_buf(snd_pcm_plug_t *plug,
- char *buf,
- size_t count,
- snd_pcm_plugin_channel_t **channels)
-{
- snd_pcm_plugin_t *plugin;
- snd_pcm_plugin_channel_t *v;
- snd_pcm_format_t *format;
- int width, nchannels, channel;
- int stream = snd_pcm_plug_stream(plug);
-
- assert(buf);
- if (stream == SND_PCM_STREAM_PLAYBACK) {
- plugin = snd_pcm_plug_first(plug);
- format = &plugin->src_format;
- }
- else {
- plugin = snd_pcm_plug_last(plug);
- format = &plugin->dst_format;
- }
- v = plugin->buf_channels;
- *channels = v;
- if ((width = snd_pcm_format_physical_width(format->format)) < 0)
- return width;
- nchannels = format->channels;
- assert(format->interleave || format->channels == 1);
- for (channel = 0; channel < nchannels; channel++, v++) {
- v->enabled = 1;
- v->wanted = (stream == SND_PCM_STREAM_CAPTURE);
- v->area.addr = buf;
- v->area.first = channel * width;
- v->area.step = nchannels * width;
- }
- return count;
-}
-
-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)
-{
- snd_pcm_plugin_t *plugin;
- snd_pcm_plugin_channel_t *v;
- snd_pcm_format_t *format;
- int width;
- unsigned int nchannels, channel;
- int stream = snd_pcm_plug_stream(plug);
-
- if (stream == SND_PCM_STREAM_PLAYBACK) {
- plugin = snd_pcm_plug_first(plug);
- format = &plugin->src_format;
- }
- else {
- plugin = snd_pcm_plug_last(plug);
- format = &plugin->dst_format;
- }
- v = plugin->buf_channels;
- *channels = v;
- if ((width = snd_pcm_format_physical_width(format->format)) < 0)
- return width;
- nchannels = format->channels;
- if (format->interleave) {
- assert(count == 1 && vector->iov_base);
-
- for (channel = 0; channel < nchannels; channel++, v++) {
- v->enabled = 1;
- v->wanted = (stream == SND_PCM_STREAM_CAPTURE);
- v->area.addr = vector->iov_base;
- v->area.first = channel * width;
- v->area.step = nchannels * width;
- }
- return vector->iov_len;
- } else {
- size_t len;
- assert(count == nchannels);
- len = vector->iov_len;
- for (channel = 0; channel < nchannels; channel++, v++, vector++) {
- assert(vector->iov_len == len);
- v->enabled = (vector->iov_base != NULL);
- v->wanted = (v->enabled && (stream == SND_PCM_STREAM_CAPTURE));
- v->area.addr = vector->iov_base;
- v->area.first = 0;
- v->area.step = width;
- }
- return len;
- }
-}
-
-int snd_pcm_plug_playback_channels_mask(snd_pcm_plug_t *plug,
- bitset_t *client_vmask)
-{
- snd_pcm_plugin_t *plugin = snd_pcm_plug_last(plug);
- if (plugin == NULL) {
-#ifndef __KERNEL__
- return snd_pcm_channels_mask(plug->slave, client_vmask);
-#else
- return 0;
-#endif
- } else {
- int schannels = plugin->dst_format.channels;
- bitset_t bs[bitset_size(schannels)];
- bitset_t *srcmask;
- bitset_t *dstmask = bs;
- int err;
- bitset_one(dstmask, schannels);
-#ifndef __KERNEL__
- err = snd_pcm_channels_mask(plug->slave, dstmask);
- if (err < 0)
- return err;
-#endif
- if (plugin == NULL) {
- bitset_and(client_vmask, dstmask, schannels);
- return 0;
- }
- while (1) {
- err = plugin->src_channels_mask(plugin, dstmask, &srcmask);
- if (err < 0)
- return err;
- dstmask = srcmask;
- if (plugin->prev == NULL)
- break;
- plugin = plugin->prev;
- }
- bitset_and(client_vmask, dstmask, plugin->src_format.channels);
- return 0;
- }
-}
-
-int snd_pcm_plug_capture_channels_mask(snd_pcm_plug_t *plug,
- bitset_t *client_vmask)
-{
- snd_pcm_plugin_t *plugin = snd_pcm_plug_first(plug);
- if (plugin == NULL) {
-#ifndef __KERNEL__
- return snd_pcm_channels_mask(plug->slave, client_vmask);
-#else
- return 0;
-#endif
- } else {
- int schannels = plugin->src_format.channels;
- bitset_t bs[bitset_size(schannels)];
- bitset_t *srcmask = bs;
- bitset_t *dstmask;
- int err;
- bitset_one(srcmask, schannels);
-#ifndef __KERNEL__
- err = snd_pcm_channels_mask(plug->slave, srcmask);
- if (err < 0)
- return err;
-#endif
- while (1) {
- err = plugin->dst_channels_mask(plugin, srcmask, &dstmask);
- if (err < 0)
- return err;
- srcmask = dstmask;
- if (plugin->next == NULL)
- break;
- plugin = plugin->next;
- }
- bitset_and(client_vmask, srcmask, plugin->dst_format.channels);
- return 0;
- }
-}
-
-static int snd_pcm_plug_playback_disable_useless_channels(snd_pcm_plug_t *plug,
- snd_pcm_plugin_channel_t *src_channels)
-{
- snd_pcm_plugin_t *plugin = snd_pcm_plug_first(plug);
- unsigned int nchannels = plugin->src_format.channels;
- bitset_t bs[bitset_size(nchannels)];
- bitset_t *srcmask = bs;
- int err;
- unsigned int channel;
- for (channel = 0; channel < nchannels; channel++) {
- if (src_channels[channel].enabled)
- bitset_set(srcmask, channel);
- else
- bitset_reset(srcmask, channel);
- }
- err = snd_pcm_plug_playback_channels_mask(plug, srcmask);
- if (err < 0)
- return err;
- for (channel = 0; channel < nchannels; channel++) {
- if (!bitset_get(srcmask, channel))
- src_channels[channel].enabled = 0;
- }
- return 0;
-}
-
-static int snd_pcm_plug_capture_disable_useless_channels(snd_pcm_plug_t *plug,
- snd_pcm_plugin_channel_t *src_channels,
- snd_pcm_plugin_channel_t *client_channels)
-{
- snd_pcm_plugin_t *plugin = snd_pcm_plug_last(plug);
- unsigned int nchannels = plugin->dst_format.channels;
- bitset_t bs[bitset_size(nchannels)];
- bitset_t *dstmask = bs;
- bitset_t *srcmask;
- int err;
- unsigned int channel;
- for (channel = 0; channel < nchannels; channel++) {
- if (client_channels[channel].enabled)
- bitset_set(dstmask, channel);
- else
- bitset_reset(dstmask, channel);
- }
- while (plugin) {
- err = plugin->src_channels_mask(plugin, dstmask, &srcmask);
- if (err < 0)
- return err;
- dstmask = srcmask;
- plugin = plugin->prev;
- }
-#ifndef __KERNEL__
- err = snd_pcm_channels_mask(plug->slave, dstmask);
- if (err < 0)
- return err;
-#endif
- plugin = snd_pcm_plug_first(plug);
- nchannels = plugin->src_format.channels;
- for (channel = 0; channel < nchannels; channel++) {
- if (!bitset_get(dstmask, channel))
- src_channels[channel].enabled = 0;
- }
- return 0;
-}
-
-ssize_t snd_pcm_plug_write_transfer(snd_pcm_plug_t *plug, snd_pcm_plugin_channel_t *src_channels, size_t size)
-{
- snd_pcm_plugin_t *plugin, *next;
- snd_pcm_plugin_channel_t *dst_channels;
- int err;
- ssize_t frames = size;
-
- if ((err = snd_pcm_plug_playback_disable_useless_channels(plug, src_channels)) < 0)
- return err;
-
- plugin = snd_pcm_plug_first(plug);
- while (plugin && frames > 0) {
- if ((next = plugin->next) != NULL) {
- ssize_t frames1 = frames;
- if (plugin->dst_frames)
- frames1 = plugin->dst_frames(plugin, frames);
- if ((err = next->client_channels(next, frames1, &dst_channels)) < 0) {
- return err;
- }
- if (err != frames1) {
- frames = err;
- if (plugin->src_frames)
- frames = plugin->src_frames(plugin, frames1);
- }
- } else
- dst_channels = 0;
- pdprintf("write plugin: %s, %i\n", plugin->name, frames);
- if ((frames = plugin->transfer(plugin, src_channels, dst_channels, frames)) < 0)
- return frames;
- src_channels = dst_channels;
- plugin = next;
- }
- return snd_pcm_plug_client_size(plug, frames);
-}
-
-ssize_t snd_pcm_plug_read_transfer(snd_pcm_plug_t *plug, snd_pcm_plugin_channel_t *dst_channels_final, size_t size)
-{
- snd_pcm_plugin_t *plugin, *next;
- snd_pcm_plugin_channel_t *src_channels, *dst_channels;
- ssize_t frames = size;
- int err;
-
- frames = snd_pcm_plug_slave_size(plug, frames);
- if (frames < 0)
- return frames;
-
- src_channels = 0;
- plugin = snd_pcm_plug_first(plug);
- while (plugin && frames > 0) {
- if ((next = plugin->next) != NULL) {
- if ((err = plugin->client_channels(plugin, frames, &dst_channels)) < 0) {
- return err;
- }
- frames = err;
- if (!plugin->prev) {
- if ((err = snd_pcm_plug_capture_disable_useless_channels(plug, dst_channels, dst_channels_final) < 0))
- return err;
- }
- } else {
- dst_channels = dst_channels_final;
- }
- pdprintf("read plugin: %s, %i\n", plugin->name, frames);
- if ((frames = plugin->transfer(plugin, src_channels, dst_channels, frames)) < 0)
- return frames;
- plugin = next;
- src_channels = dst_channels;
- }
- return frames;
-}
-
-int snd_pcm_area_silence(const snd_pcm_channel_area_t *dst_area, size_t dst_offset,
- size_t samples, int format)
-{
- /* FIXME: sub byte resolution and odd dst_offset */
- char *dst;
- unsigned int dst_step;
- int width;
- u_int64_t silence;
- if (!dst_area->addr)
- return 0;
- dst = dst_area->addr + (dst_area->first + dst_area->step * dst_offset) / 8;
- width = snd_pcm_format_physical_width(format);
- silence = snd_pcm_format_silence_64(format);
- if (dst_area->step == (unsigned int) width) {
- size_t dwords = samples * width / 64;
- samples -= dwords * 64 / width;
- while (dwords-- > 0)
- *((u_int64_t*)dst)++ = silence;
- if (samples == 0)
- return 0;
- }
- dst_step = dst_area->step / 8;
- switch (width) {
- case 4: {
- u_int8_t s0 = silence & 0xf0;
- u_int8_t s1 = silence & 0x0f;
- int dstbit = dst_area->first % 8;
- int dstbit_step = dst_area->step % 8;
- while (samples-- > 0) {
- if (dstbit) {
- *dst &= 0xf0;
- *dst |= s1;
- } else {
- *dst &= 0x0f;
- *dst |= s0;
- }
- dst += dst_step;
- dstbit += dstbit_step;
- if (dstbit == 8) {
- dst++;
- dstbit = 0;
- }
- }
- break;
- }
- case 8: {
- u_int8_t sil = silence;
- while (samples-- > 0) {
- *dst = sil;
- dst += dst_step;
- }
- break;
- }
- case 16: {
- u_int16_t sil = silence;
- while (samples-- > 0) {
- *(u_int16_t*)dst = sil;
- dst += dst_step;
- }
- break;
- }
- case 32: {
- u_int32_t sil = silence;
- while (samples-- > 0) {
- *(u_int32_t*)dst = sil;
- dst += dst_step;
- }
- break;
- }
- case 64: {
- while (samples-- > 0) {
- *(u_int64_t*)dst = silence;
- dst += dst_step;
- }
- break;
- }
- default:
- assert(0);
- }
- return 0;
-}
-
-int snd_pcm_areas_silence(const snd_pcm_channel_area_t *dst_areas, size_t dst_offset,
- size_t vcount, size_t frames, int format)
-{
- int width = snd_pcm_format_physical_width(format);
- while (vcount > 0) {
- void *addr = dst_areas->addr;
- unsigned int step = dst_areas->step;
- const snd_pcm_channel_area_t *begin = dst_areas;
- int vc = vcount;
- unsigned int v = 0;
- int err;
- while (1) {
- vc--;
- v++;
- dst_areas++;
- if (vc == 0 ||
- dst_areas->addr != addr ||
- dst_areas->step != step ||
- dst_areas->first != dst_areas[-1].first + width)
- break;
- }
- if (v > 1 && v * width == step) {
- /* Collapse the areas */
- snd_pcm_channel_area_t d;
- d.addr = begin->addr;
- d.first = begin->first;
- d.step = width;
- err = snd_pcm_area_silence(&d, dst_offset * v, frames * v, format);
- vcount -= v;
- } else {
- err = snd_pcm_area_silence(begin, dst_offset, frames, format);
- dst_areas = begin + 1;
- vcount--;
- }
- if (err < 0)
- return err;
- }
- return 0;
-}
-
-
-int snd_pcm_area_copy(const snd_pcm_channel_area_t *src_area, size_t src_offset,
- const snd_pcm_channel_area_t *dst_area, size_t dst_offset,
- size_t samples, int format)
-{
- /* FIXME: sub byte resolution and odd dst_offset */
- char *src, *dst;
- int width;
- int src_step, dst_step;
- src = src_area->addr + (src_area->first + src_area->step * src_offset) / 8;
- if (!src_area->addr)
- return snd_pcm_area_silence(dst_area, dst_offset, samples, format);
- dst = dst_area->addr + (dst_area->first + dst_area->step * dst_offset) / 8;
- if (!dst_area->addr)
- return 0;
- width = snd_pcm_format_physical_width(format);
- if (src_area->step == (unsigned int) width &&
- dst_area->step == (unsigned int) width) {
- size_t bytes = samples * width / 8;
- samples -= bytes * 8 / width;
- memcpy(dst, src, bytes);
- if (samples == 0)
- return 0;
- }
- src_step = src_area->step / 8;
- dst_step = dst_area->step / 8;
- switch (width) {
- case 4: {
- int srcbit = src_area->first % 8;
- int srcbit_step = src_area->step % 8;
- int dstbit = dst_area->first % 8;
- int dstbit_step = dst_area->step % 8;
- while (samples-- > 0) {
- unsigned char srcval;
- if (srcbit)
- srcval = *src & 0x0f;
- else
- srcval = *src & 0xf0;
- if (dstbit)
- *dst &= 0xf0;
- else
- *dst &= 0x0f;
- *dst |= srcval;
- src += src_step;
- srcbit += srcbit_step;
- if (srcbit == 8) {
- src++;
- srcbit = 0;
- }
- dst += dst_step;
- dstbit += dstbit_step;
- if (dstbit == 8) {
- dst++;
- dstbit = 0;
- }
- }
- break;
- }
- case 8: {
- while (samples-- > 0) {
- *dst = *src;
- src += src_step;
- dst += dst_step;
- }
- break;
- }
- case 16: {
- while (samples-- > 0) {
- *(u_int16_t*)dst = *(u_int16_t*)src;
- src += src_step;
- dst += dst_step;
- }
- break;
- }
- case 32: {
- while (samples-- > 0) {
- *(u_int32_t*)dst = *(u_int32_t*)src;
- src += src_step;
- dst += dst_step;
- }
- break;
- }
- case 64: {
- while (samples-- > 0) {
- *(u_int64_t*)dst = *(u_int64_t*)src;
- src += src_step;
- dst += dst_step;
- }
- break;
- }
- default:
- assert(0);
- }
- return 0;
-}
-
-int snd_pcm_areas_copy(const snd_pcm_channel_area_t *src_areas, size_t src_offset,
- const snd_pcm_channel_area_t *dst_areas, size_t dst_offset,
- size_t vcount, size_t frames, int format)
-{
- int width = snd_pcm_format_physical_width(format);
- while (vcount > 0) {
- unsigned int step = src_areas->step;
- void *src_addr = src_areas->addr;
- const snd_pcm_channel_area_t *src_start = src_areas;
- void *dst_addr = dst_areas->addr;
- const snd_pcm_channel_area_t *dst_start = dst_areas;
- int vc = vcount;
- unsigned int v = 0;
- while (dst_areas->step == step) {
- vc--;
- v++;
- src_areas++;
- dst_areas++;
- if (vc == 0 ||
- src_areas->step != step ||
- src_areas->addr != src_addr ||
- dst_areas->addr != dst_addr ||
- src_areas->first != src_areas[-1].first + width ||
- dst_areas->first != dst_areas[-1].first + width)
- break;
- }
- if (v > 1 && v * width == step) {
- /* Collapse the areas */
- snd_pcm_channel_area_t s, d;
- s.addr = src_start->addr;
- s.first = src_start->first;
- s.step = width;
- d.addr = dst_start->addr;
- d.first = dst_start->first;
- d.step = width;
- snd_pcm_area_copy(&s, src_offset * v, &d, dst_offset * v, frames * v, format);
- vcount -= v;
- } else {
- snd_pcm_area_copy(src_start, src_offset, dst_start, dst_offset, frames, format);
- src_areas = src_start + 1;
- dst_areas = dst_start + 1;
- vcount--;
- }
- }
- return 0;
-}
diff --git a/src/pcm/pcm_file.c b/src/pcm/pcm_file.c
new file mode 100644
index 00000000..644aae34
--- /dev/null
+++ b/src/pcm/pcm_file.c
@@ -0,0 +1,447 @@
+/*
+ * PCM - File plugin
+ * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
+ *
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <byteswap.h>
+#include "pcm_local.h"
+#include "pcm_plugin.h"
+
+typedef struct {
+ snd_pcm_t *slave;
+ int close_slave;
+ char *fname;
+ int fd;
+} snd_pcm_file_t;
+
+static int snd_pcm_file_close(snd_pcm_t *pcm)
+{
+ snd_pcm_file_t *file = pcm->private;
+ int err = 0;
+ if (file->close_slave)
+ err = snd_pcm_close(file->slave);
+ if (file->fname) {
+ free(file->fname);
+ close(file->fd);
+ }
+ free(file);
+ return 0;
+}
+
+static int snd_pcm_file_nonblock(snd_pcm_t *pcm, int nonblock)
+{
+ snd_pcm_file_t *file = pcm->private;
+ return snd_pcm_nonblock(file->slave, nonblock);
+}
+
+static int snd_pcm_file_info(snd_pcm_t *pcm, snd_pcm_info_t * info)
+{
+ snd_pcm_file_t *file = pcm->private;
+ return snd_pcm_info(file->slave, info);
+}
+
+static int snd_pcm_file_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info)
+{
+ snd_pcm_file_t *file = pcm->private;
+ return snd_pcm_channel_info(file->slave, info);
+}
+
+static int snd_pcm_file_channel_params(snd_pcm_t *pcm, snd_pcm_channel_params_t * params)
+{
+ snd_pcm_file_t *file = pcm->private;
+ return snd_pcm_channel_params(file->slave, params);
+}
+
+static int snd_pcm_file_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t * setup)
+{
+ snd_pcm_file_t *file = pcm->private;
+ return snd_pcm_channel_setup(file->slave, setup);
+}
+
+static int snd_pcm_file_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
+{
+ snd_pcm_file_t *file = pcm->private;
+ return snd_pcm_status(file->slave, status);
+}
+
+static int snd_pcm_file_state(snd_pcm_t *pcm)
+{
+ snd_pcm_file_t *file = pcm->private;
+ return snd_pcm_state(file->slave);
+}
+
+static int snd_pcm_file_delay(snd_pcm_t *pcm, ssize_t *delayp)
+{
+ snd_pcm_file_t *file = pcm->private;
+ return snd_pcm_delay(file->slave, delayp);
+}
+
+static int snd_pcm_file_prepare(snd_pcm_t *pcm)
+{
+ snd_pcm_file_t *file = pcm->private;
+ return snd_pcm_prepare(file->slave);
+}
+
+static int snd_pcm_file_start(snd_pcm_t *pcm)
+{
+ snd_pcm_file_t *file = pcm->private;
+ return snd_pcm_start(file->slave);
+}
+
+static int snd_pcm_file_stop(snd_pcm_t *pcm)
+{
+ snd_pcm_file_t *file = pcm->private;
+ return snd_pcm_stop(file->slave);
+}
+
+static int snd_pcm_file_flush(snd_pcm_t *pcm)
+{
+ snd_pcm_file_t *file = pcm->private;
+ return snd_pcm_flush(file->slave);
+}
+
+static int snd_pcm_file_pause(snd_pcm_t *pcm, int enable)
+{
+ snd_pcm_file_t *file = pcm->private;
+ return snd_pcm_pause(file->slave, enable);
+}
+
+static ssize_t snd_pcm_file_appl_ptr(snd_pcm_t *pcm, off_t offset)
+{
+ snd_pcm_file_t *file = pcm->private;
+ return snd_pcm_appl_ptr(file->slave, offset);
+}
+
+static void snd_pcm_file_write_areas(snd_pcm_t *pcm,
+ snd_pcm_channel_area_t *areas,
+ size_t offset, size_t frames)
+{
+ snd_pcm_file_t *file = pcm->private;
+ size_t bytes = snd_pcm_frames_to_bytes(pcm, frames);
+ char buf[bytes];
+ size_t channels = pcm->setup.format.channels;
+ snd_pcm_channel_area_t buf_areas[channels];
+ size_t channel;
+ ssize_t r;
+ for (channel = 0; channel < channels; ++channel) {
+ snd_pcm_channel_area_t *a = &buf_areas[channel];
+ a->addr = buf;
+ a->first = pcm->bits_per_sample * channel;
+ a->step = pcm->bits_per_frame;
+ }
+ snd_pcm_areas_copy(areas, offset, buf_areas, 0,
+ channels, frames, pcm->setup.format.sfmt);
+ r = write(file->fd, buf, bytes);
+ assert(r == (ssize_t)bytes);
+}
+
+static ssize_t snd_pcm_file_writei(snd_pcm_t *pcm, const void *buffer, size_t size)
+{
+ snd_pcm_file_t *file = pcm->private;
+ ssize_t n = snd_pcm_writei(file->slave, buffer, size);
+ if (n > 0) {
+ size_t bytes = snd_pcm_frames_to_bytes(pcm, n);
+ ssize_t r = write(file->fd, buffer, bytes);
+ assert(r == (ssize_t)bytes);
+ }
+ return n;
+}
+
+static ssize_t snd_pcm_file_writen(snd_pcm_t *pcm, void **bufs, size_t size)
+{
+ snd_pcm_file_t *file = pcm->private;
+ snd_pcm_channel_area_t areas[pcm->setup.format.channels];
+ ssize_t n = snd_pcm_writen(file->slave, bufs, size);
+ if (n > 0) {
+ snd_pcm_areas_from_bufs(pcm, areas, bufs);
+ snd_pcm_file_write_areas(pcm, areas, 0, n);
+ }
+ return n;
+}
+
+static ssize_t snd_pcm_file_readi(snd_pcm_t *pcm, void *buffer, size_t size)
+{
+ snd_pcm_file_t *file = pcm->private;
+ ssize_t n = snd_pcm_readi(file->slave, buffer, size);
+ if (n > 0) {
+ size_t bytes = snd_pcm_frames_to_bytes(pcm, n);
+ ssize_t r = write(file->fd, buffer, bytes);
+ assert(r == (ssize_t)bytes);
+ }
+ return n;
+}
+
+static ssize_t snd_pcm_file_readn(snd_pcm_t *pcm, void **bufs, size_t size)
+{
+ snd_pcm_file_t *file = pcm->private;
+ snd_pcm_channel_area_t areas[pcm->setup.format.channels];
+ ssize_t n = snd_pcm_writen(file->slave, bufs, size);
+ if (n > 0) {
+ snd_pcm_areas_from_bufs(pcm, areas, bufs);
+ snd_pcm_file_write_areas(pcm, areas, 0, n);
+ }
+ return n;
+}
+
+static ssize_t snd_pcm_file_mmap_forward(snd_pcm_t *pcm, size_t size)
+{
+ snd_pcm_file_t *file = pcm->private;
+ size_t ofs = pcm->mmap_control->appl_ptr % pcm->setup.buffer_size;
+ ssize_t n = snd_pcm_mmap_forward(file->slave, size);
+ size_t xfer = 0;
+ if (n <= 0)
+ return n;
+ while (xfer < (size_t)n) {
+ size_t frames = size - xfer;
+ size_t cont = pcm->setup.buffer_size - ofs;
+ if (cont < frames)
+ frames = cont;
+ snd_pcm_file_write_areas(pcm, pcm->mmap_areas, ofs, frames);
+ ofs += frames;
+ if (ofs == pcm->setup.buffer_size)
+ ofs = 0;
+ xfer += frames;
+ }
+ return n;
+}
+
+static ssize_t snd_pcm_file_avail_update(snd_pcm_t *pcm)
+{
+ snd_pcm_file_t *file = pcm->private;
+ return snd_pcm_avail_update(file->slave);
+}
+
+static int snd_pcm_file_mmap_status(snd_pcm_t *pcm)
+{
+ snd_pcm_file_t *file = pcm->private;
+ return snd_pcm_mmap_status(file->slave, &pcm->mmap_status);
+}
+
+static int snd_pcm_file_mmap_control(snd_pcm_t *pcm)
+{
+ snd_pcm_file_t *file = pcm->private;
+ return snd_pcm_mmap_control(file->slave, &pcm->mmap_control);
+}
+
+static int snd_pcm_file_mmap_data(snd_pcm_t *pcm)
+{
+ snd_pcm_file_t *file = pcm->private;
+ return snd_pcm_mmap_data(file->slave, &pcm->mmap_data);
+}
+
+static int snd_pcm_file_munmap_status(snd_pcm_t *pcm)
+{
+ snd_pcm_file_t *file = pcm->private;
+ return snd_pcm_munmap_status(file->slave);
+}
+
+static int snd_pcm_file_munmap_control(snd_pcm_t *pcm)
+{
+ snd_pcm_file_t *file = pcm->private;
+ return snd_pcm_munmap_control(file->slave);
+}
+
+static int snd_pcm_file_munmap_data(snd_pcm_t *pcm)
+{
+ snd_pcm_file_t *file = pcm->private;
+ return snd_pcm_munmap_data(file->slave);
+}
+
+static int snd_pcm_file_poll_descriptor(snd_pcm_t *pcm)
+{
+ snd_pcm_file_t *file = pcm->private;
+ return snd_pcm_poll_descriptor(file->slave);
+}
+
+static int snd_pcm_file_channels_mask(snd_pcm_t *pcm, bitset_t *cmask)
+{
+ snd_pcm_file_t *file = pcm->private;
+ return snd_pcm_channels_mask(file->slave, cmask);
+}
+
+static int snd_pcm_file_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t * info)
+{
+ snd_pcm_file_t *file = pcm->private;
+ return snd_pcm_params_info(file->slave, info);
+}
+
+static int snd_pcm_file_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
+{
+ snd_pcm_file_t *file = pcm->private;
+ return snd_pcm_params(file->slave, params);
+}
+
+static int snd_pcm_file_setup(snd_pcm_t *pcm, snd_pcm_setup_t * setup)
+{
+ snd_pcm_file_t *file = pcm->private;
+ return snd_pcm_setup(file->slave, setup);
+}
+
+static void snd_pcm_file_dump(snd_pcm_t *pcm, FILE *fp)
+{
+ snd_pcm_file_t *file = pcm->private;
+ if (file->fname)
+ fprintf(fp, "File PCM (file=%s)\n", file->fname);
+ else
+ fprintf(fp, "File PCM (fd=%d)\n", file->fd);
+ if (pcm->valid_setup) {
+ fprintf(fp, "Its setup is:\n");
+ snd_pcm_dump_setup(pcm, fp);
+ }
+ fprintf(fp, "Slave: ");
+ snd_pcm_dump(file->slave, fp);
+}
+
+struct snd_pcm_ops snd_pcm_file_ops = {
+ close: snd_pcm_file_close,
+ info: snd_pcm_file_info,
+ params_info: snd_pcm_file_params_info,
+ params: snd_pcm_file_params,
+ setup: snd_pcm_file_setup,
+ channel_info: snd_pcm_file_channel_info,
+ channel_params: snd_pcm_file_channel_params,
+ channel_setup: snd_pcm_file_channel_setup,
+ dump: snd_pcm_file_dump,
+ nonblock: snd_pcm_file_nonblock,
+ mmap_status: snd_pcm_file_mmap_status,
+ mmap_control: snd_pcm_file_mmap_control,
+ mmap_data: snd_pcm_file_mmap_data,
+ munmap_status: snd_pcm_file_munmap_status,
+ munmap_control: snd_pcm_file_munmap_control,
+ munmap_data: snd_pcm_file_munmap_data,
+};
+
+struct snd_pcm_fast_ops snd_pcm_file_fast_ops = {
+ status: snd_pcm_file_status,
+ state: snd_pcm_file_state,
+ delay: snd_pcm_file_delay,
+ prepare: snd_pcm_file_prepare,
+ start: snd_pcm_file_start,
+ stop: snd_pcm_file_stop,
+ flush: snd_pcm_file_flush,
+ pause: snd_pcm_file_pause,
+ appl_ptr: snd_pcm_file_appl_ptr,
+ writei: snd_pcm_file_writei,
+ writen: snd_pcm_file_writen,
+ readi: snd_pcm_file_readi,
+ readn: snd_pcm_file_readn,
+ poll_descriptor: snd_pcm_file_poll_descriptor,
+ channels_mask: snd_pcm_file_channels_mask,
+ avail_update: snd_pcm_file_avail_update,
+ mmap_forward: snd_pcm_file_mmap_forward,
+};
+
+int snd_pcm_file_open(snd_pcm_t **handlep, char *fname, int fd, snd_pcm_t *slave, int close_slave)
+{
+ snd_pcm_t *handle;
+ snd_pcm_file_t *file;
+ int err;
+ assert(handlep && slave);
+ if (fname) {
+ fd = open(fname, O_WRONLY|O_CREAT, 0666);
+ if (fd < 0)
+ return -errno;
+ }
+ file = calloc(1, sizeof(snd_pcm_file_t));
+ if (!file) {
+ return -ENOMEM;
+ }
+ file->fname = fname;
+ file->fd = fd;
+ file->slave = slave;
+ file->close_slave = close_slave;
+
+ handle = calloc(1, sizeof(snd_pcm_t));
+ if (!handle) {
+ free(file);
+ return -ENOMEM;
+ }
+ handle->type = SND_PCM_TYPE_FILE;
+ handle->stream = slave->stream;
+ handle->ops = &snd_pcm_file_ops;
+ handle->op_arg = handle;
+ handle->fast_ops = &snd_pcm_file_fast_ops;
+ handle->fast_op_arg = handle;
+ handle->mode = slave->mode;
+ handle->private = file;
+ err = snd_pcm_init(handle);
+ if (err < 0) {
+ snd_pcm_close(handle);
+ return err;
+ }
+ *handlep = handle;
+
+ return 0;
+}
+
+int _snd_pcm_file_open(snd_pcm_t **pcmp, char *name,
+ snd_config_t *conf,
+ int stream, int mode)
+{
+ snd_config_iterator_t i;
+ char *sname = NULL;
+ int err;
+ snd_pcm_t *spcm;
+ char *fname = NULL;
+ long fd = -1;
+ snd_config_foreach(i, conf) {
+ snd_config_t *n = snd_config_entry(i);
+ if (strcmp(n->id, "comment") == 0)
+ continue;
+ if (strcmp(n->id, "type") == 0)
+ continue;
+ if (strcmp(n->id, "stream") == 0)
+ continue;
+ if (strcmp(n->id, "sname") == 0) {
+ err = snd_config_string_get(n, &sname);
+ if (err < 0)
+ return -EINVAL;
+ continue;
+ }
+ if (strcmp(n->id, "file") == 0) {
+ err = snd_config_string_get(n, &fname);
+ if (err < 0) {
+ err = snd_config_integer_get(n, &fd);
+ if (err < 0)
+ return -EINVAL;
+ }
+ continue;
+ }
+ return -EINVAL;
+ }
+ if (!sname || (!fname && fd < 0))
+ return -EINVAL;
+ if (fname) {
+ fname = strdup(fname);
+ if (!fname)
+ return -ENOMEM;
+ }
+ /* This is needed cause snd_config_update may destroy config */
+ sname = strdup(sname);
+ if (!sname)
+ return -ENOMEM;
+ err = snd_pcm_open(&spcm, sname, stream, mode);
+ free(sname);
+ if (err < 0)
+ return err;
+ err = snd_pcm_file_open(pcmp, fname, fd, spcm, 1);
+ if (err < 0)
+ snd_pcm_close(spcm);
+ return err;
+}
diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c
index 01d94291..d3adac9f 100644
--- a/src/pcm/pcm_hw.c
+++ b/src/pcm/pcm_hw.c
@@ -32,7 +32,7 @@
typedef struct {
int fd;
int card, device, subdevice;
- void *mmap_data_ptr;
+ int mmap_emulation;
} snd_pcm_hw_t;
#define SND_FILE_PCM_STREAM_PLAYBACK "/dev/snd/pcmC%iD%ip"
@@ -100,6 +100,14 @@ static int snd_pcm_hw_setup(snd_pcm_t *pcm, snd_pcm_setup_t * setup)
int fd = hw->fd;
if (ioctl(fd, SND_PCM_IOCTL_SETUP, setup) < 0)
return -errno;
+ if (setup->mmap_shape == SND_PCM_MMAP_UNSPECIFIED) {
+ if (setup->xfer_mode == SND_PCM_XFER_INTERLEAVED)
+ setup->mmap_shape = SND_PCM_MMAP_INTERLEAVED;
+ else
+ setup->mmap_shape = SND_PCM_MMAP_NONINTERLEAVED;
+ hw->mmap_emulation = 1;
+ } else
+ hw->mmap_emulation = 0;
return 0;
}
@@ -127,7 +135,18 @@ static int snd_pcm_hw_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t * se
int fd = hw->fd;
if (ioctl(fd, SND_PCM_IOCTL_CHANNEL_SETUP, setup) < 0)
return -errno;
- setup->area.addr = (char *)hw->mmap_data_ptr + (long)setup->area.addr;
+ if (hw->mmap_emulation) {
+ if (pcm->setup.mmap_shape == SND_PCM_MMAP_INTERLEAVED) {
+ setup->area.addr = pcm->mmap_data;
+ setup->area.first = setup->channel * pcm->bits_per_sample;
+ setup->area.step = pcm->bits_per_frame;
+ } else {
+ setup->area.addr = pcm->mmap_data + setup->channel * pcm->setup.buffer_size * pcm->bits_per_sample / 8;
+ setup->area.first = 0;
+ setup->area.step = pcm->bits_per_sample;
+ }
+ } else
+ setup->area.addr = (char *)pcm->mmap_data + (long)setup->area.addr;
return 0;
}
@@ -145,19 +164,20 @@ static int snd_pcm_hw_state(snd_pcm_t *pcm)
snd_pcm_hw_t *hw = pcm->private;
int fd = hw->fd;
snd_pcm_status_t status;
- if (ioctl(fd, SND_PCM_IOCTL_STATUS, status) < 0)
+ if (pcm->mmap_status)
+ return pcm->mmap_status->state;
+ if (ioctl(fd, SND_PCM_IOCTL_STATUS, &status) < 0)
return -errno;
return status.state;
}
-static ssize_t snd_pcm_hw_hw_ptr(snd_pcm_t *pcm, int update ATTRIBUTE_UNUSED)
+static int snd_pcm_hw_delay(snd_pcm_t *pcm, ssize_t *delayp)
{
snd_pcm_hw_t *hw = pcm->private;
int fd = hw->fd;
- ssize_t pos = ioctl(fd, SND_PCM_IOCTL_HW_PTR);
- if (pos < 0)
+ if (ioctl(fd, SND_PCM_IOCTL_DELAY, delayp) < 0)
return -errno;
- return pos;
+ return 0;
}
static int snd_pcm_hw_prepare(snd_pcm_t *pcm)
@@ -169,20 +189,20 @@ static int snd_pcm_hw_prepare(snd_pcm_t *pcm)
return 0;
}
-static int snd_pcm_hw_go(snd_pcm_t *pcm)
+static int snd_pcm_hw_start(snd_pcm_t *pcm)
{
snd_pcm_hw_t *hw = pcm->private;
int fd = hw->fd;
- if (ioctl(fd, SND_PCM_IOCTL_GO) < 0)
+ if (ioctl(fd, SND_PCM_IOCTL_START) < 0)
return -errno;
return 0;
}
-static int snd_pcm_hw_drain(snd_pcm_t *pcm)
+static int snd_pcm_hw_stop(snd_pcm_t *pcm)
{
snd_pcm_hw_t *hw = pcm->private;
int fd = hw->fd;
- if (ioctl(fd, SND_PCM_IOCTL_DRAIN) < 0)
+ if (ioctl(fd, SND_PCM_IOCTL_STOP) < 0)
return -errno;
return 0;
}
@@ -218,79 +238,63 @@ static ssize_t snd_pcm_hw_appl_ptr(snd_pcm_t *pcm, off_t offset)
return result;
}
-static ssize_t snd_pcm_hw_write(snd_pcm_t *pcm, snd_timestamp_t *tstamp, const void *buffer, size_t size)
+static ssize_t snd_pcm_hw_writei(snd_pcm_t *pcm, const void *buffer, size_t size)
{
ssize_t result;
snd_pcm_hw_t *hw = pcm->private;
int fd = hw->fd;
- snd_xfer_t xfer;
- if (tstamp)
- xfer.tstamp = *tstamp;
- else
- xfer.tstamp.tv_sec = xfer.tstamp.tv_usec = 0;
- xfer.buf = (char*) buffer;
- xfer.count = size;
- result = ioctl(fd, SND_PCM_IOCTL_WRITE_FRAMES, &xfer);
+ snd_xferi_t xferi;
+ xferi.buf = (char*) buffer;
+ xferi.frames = size;
+ result = ioctl(fd, SND_PCM_IOCTL_WRITEI_FRAMES, &xferi);
if (result < 0)
return -errno;
return result;
}
-static ssize_t snd_pcm_hw_writev(snd_pcm_t *pcm, snd_timestamp_t *tstamp, const struct iovec *vector, unsigned long count)
+static ssize_t snd_pcm_hw_writen(snd_pcm_t *pcm, void **bufs, size_t size)
{
ssize_t result;
snd_pcm_hw_t *hw = pcm->private;
int fd = hw->fd;
- snd_xferv_t xferv;
- if (tstamp)
- xferv.tstamp = *tstamp;
- else
- xferv.tstamp.tv_sec = xferv.tstamp.tv_usec = 0;
- xferv.vector = vector;
- xferv.count = count;
- result = ioctl(fd, SND_PCM_IOCTL_WRITEV_FRAMES, &xferv);
+ snd_xfern_t xfern;
+ xfern.bufs = bufs;
+ xfern.frames = size;
+ result = ioctl(fd, SND_PCM_IOCTL_WRITEN_FRAMES, &xfern);
if (result < 0)
return -errno;
return result;
}
-static ssize_t snd_pcm_hw_read(snd_pcm_t *pcm, snd_timestamp_t *tstamp, void *buffer, size_t size)
+static ssize_t snd_pcm_hw_readi(snd_pcm_t *pcm, void *buffer, size_t size)
{
ssize_t result;
snd_pcm_hw_t *hw = pcm->private;
int fd = hw->fd;
- snd_xfer_t xfer;
- if (tstamp)
- xfer.tstamp = *tstamp;
- else
- xfer.tstamp.tv_sec = xfer.tstamp.tv_usec = 0;
- xfer.buf = buffer;
- xfer.count = size;
- result = ioctl(fd, SND_PCM_IOCTL_READ_FRAMES, &xfer);
+ snd_xferi_t xferi;
+ xferi.buf = buffer;
+ xferi.frames = size;
+ result = ioctl(fd, SND_PCM_IOCTL_READI_FRAMES, &xferi);
if (result < 0)
return -errno;
return result;
}
-ssize_t snd_pcm_hw_readv(snd_pcm_t *pcm, snd_timestamp_t *tstamp, const struct iovec *vector, unsigned long count)
+ssize_t snd_pcm_hw_readn(snd_pcm_t *pcm, void **bufs, size_t size)
{
ssize_t result;
snd_pcm_hw_t *hw = pcm->private;
int fd = hw->fd;
- snd_xferv_t xferv;
- if (tstamp)
- xferv.tstamp = *tstamp;
- else
- xferv.tstamp.tv_sec = xferv.tstamp.tv_usec = 0;
- xferv.vector = vector;
- xferv.count = count;
- result = ioctl(fd, SND_PCM_IOCTL_READV_FRAMES, &xferv);
+ snd_xfern_t xfern;
+ xfern.bufs = bufs;
+ xfern.frames = size;
+ result = ioctl(fd, SND_PCM_IOCTL_READN_FRAMES, &xfern);
if (result < 0)
return -errno;
return result;
}
-static int snd_pcm_hw_mmap_status(snd_pcm_t *pcm, snd_pcm_mmap_status_t **status)
+static int snd_pcm_hw_mmap_status(snd_pcm_t *pcm)
{
snd_pcm_hw_t *hw = pcm->private;
void *ptr;
@@ -298,11 +302,11 @@ static int snd_pcm_hw_mmap_status(snd_pcm_t *pcm, snd_pcm_mmap_status_t **status
hw->fd, SND_PCM_MMAP_OFFSET_STATUS);
if (ptr == MAP_FAILED || ptr == NULL)
return -errno;
- *status = ptr;
+ pcm->mmap_status = ptr;
return 0;
}
-static int snd_pcm_hw_mmap_control(snd_pcm_t *pcm, snd_pcm_mmap_control_t **control)
+static int snd_pcm_hw_mmap_control(snd_pcm_t *pcm)
{
snd_pcm_hw_t *hw = pcm->private;
void *ptr;
@@ -310,59 +314,97 @@ static int snd_pcm_hw_mmap_control(snd_pcm_t *pcm, snd_pcm_mmap_control_t **cont
hw->fd, SND_PCM_MMAP_OFFSET_CONTROL);
if (ptr == MAP_FAILED || ptr == NULL)
return -errno;
- *control = ptr;
+ pcm->mmap_control = ptr;
return 0;
}
-static int snd_pcm_hw_mmap_data(snd_pcm_t *pcm, void **buffer, size_t bsize)
+static int snd_pcm_hw_mmap_data(snd_pcm_t *pcm)
{
snd_pcm_hw_t *hw = pcm->private;
void *ptr;
- int prot;
-#if 0
- prot = pcm->stream == SND_PCM_STREAM_PLAYBACK ? PROT_WRITE : PROT_READ;
-#else
- prot = PROT_WRITE | PROT_READ;
-#endif
- ptr = mmap(NULL, bsize, prot, MAP_FILE|MAP_SHARED,
- hw->fd, SND_PCM_MMAP_OFFSET_DATA);
- if (ptr == MAP_FAILED || ptr == NULL)
- return -errno;
- *buffer = hw->mmap_data_ptr = ptr;
+ if (hw->mmap_emulation) {
+ ptr = malloc(snd_pcm_frames_to_bytes(pcm, pcm->setup.buffer_size));
+ if (!ptr)
+ return -ENOMEM;
+ } else {
+ int prot;
+ prot = PROT_WRITE | PROT_READ;
+ ptr = mmap(NULL, pcm->setup.mmap_bytes,
+ prot, MAP_FILE|MAP_SHARED,
+ hw->fd, SND_PCM_MMAP_OFFSET_DATA);
+ if (ptr == MAP_FAILED || ptr == NULL)
+ return -errno;
+ }
+ pcm->mmap_data = ptr;
return 0;
}
-static int snd_pcm_hw_munmap_status(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_mmap_status_t *status)
+static int snd_pcm_hw_munmap_status(snd_pcm_t *pcm)
{
- if (munmap(status, sizeof(*status)) < 0)
+ if (munmap(pcm->mmap_status, sizeof(*pcm->mmap_status)) < 0)
return -errno;
return 0;
}
-static int snd_pcm_hw_munmap_control(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_mmap_control_t *control)
+static int snd_pcm_hw_munmap_control(snd_pcm_t *pcm)
{
- if (munmap(control, sizeof(*control)) < 0)
+ if (munmap(pcm->mmap_control, sizeof(*pcm->mmap_control)) < 0)
return -errno;
return 0;
}
-static int snd_pcm_hw_munmap_data(snd_pcm_t *pcm, void *buffer, size_t bsize)
+static int snd_pcm_hw_munmap_data(snd_pcm_t *pcm)
{
snd_pcm_hw_t *hw = pcm->private;
- if (munmap(buffer, bsize) < 0)
- return -errno;
- hw->mmap_data_ptr = NULL;
+ if (hw->mmap_emulation)
+ free(pcm->mmap_data);
+ else
+ if (munmap(pcm->mmap_data, pcm->setup.mmap_bytes) < 0)
+ return -errno;
return 0;
}
-static int snd_pcm_hw_file_descriptor(snd_pcm_t *pcm)
+static ssize_t snd_pcm_hw_mmap_forward(snd_pcm_t *pcm, size_t size)
+{
+ snd_pcm_hw_t *hw = pcm->private;
+ if (hw->mmap_emulation && pcm->stream == SND_PCM_STREAM_PLAYBACK)
+ return snd_pcm_write_mmap(pcm, size);
+ snd_pcm_mmap_appl_forward(pcm, size);
+ return size;
+}
+
+static ssize_t snd_pcm_hw_avail_update(snd_pcm_t *pcm)
+{
+ snd_pcm_hw_t *hw = pcm->private;
+ int fd = hw->fd;
+ size_t avail;
+ ssize_t err;
+ if (pcm->setup.ready_mode == SND_PCM_READY_ASAP) {
+ ssize_t d;
+ int err = ioctl(fd, SND_PCM_IOCTL_DELAY, &d);
+ if (err < 0)
+ return -errno;
+ }
+ avail = snd_pcm_mmap_avail(pcm);
+ if (avail > 0 && hw->mmap_emulation &&
+ pcm->stream == SND_PCM_STREAM_CAPTURE) {
+ err = snd_pcm_read_mmap(pcm, avail);
+ if (err < 0)
+ return err;
+ assert((size_t)err == avail);
+ return err;
+ }
+ return avail;
+}
+
+static int snd_pcm_hw_poll_descriptor(snd_pcm_t *pcm)
{
snd_pcm_hw_t *hw = pcm->private;
return hw->fd;
}
static int snd_pcm_hw_channels_mask(snd_pcm_t *pcm ATTRIBUTE_UNUSED,
- bitset_t *client_vmask ATTRIBUTE_UNUSED)
+ bitset_t *cmask ATTRIBUTE_UNUSED)
{
return 0;
}
@@ -387,35 +429,37 @@ struct snd_pcm_ops snd_pcm_hw_ops = {
params_info: snd_pcm_hw_params_info,
params: snd_pcm_hw_params,
setup: snd_pcm_hw_setup,
+ channel_info: snd_pcm_hw_channel_info,
+ channel_params: snd_pcm_hw_channel_params,
+ channel_setup: snd_pcm_hw_channel_setup,
dump: snd_pcm_hw_dump,
+ nonblock: snd_pcm_hw_nonblock,
+ mmap_status: snd_pcm_hw_mmap_status,
+ mmap_control: snd_pcm_hw_mmap_control,
+ mmap_data: snd_pcm_hw_mmap_data,
+ munmap_status: snd_pcm_hw_munmap_status,
+ munmap_control: snd_pcm_hw_munmap_control,
+ munmap_data: snd_pcm_hw_munmap_data,
};
struct snd_pcm_fast_ops snd_pcm_hw_fast_ops = {
- nonblock: snd_pcm_hw_nonblock,
- channel_info: snd_pcm_hw_channel_info,
- channel_params: snd_pcm_hw_channel_params,
- channel_setup: snd_pcm_hw_channel_setup,
status: snd_pcm_hw_status,
- hw_ptr: snd_pcm_hw_hw_ptr,
state: snd_pcm_hw_state,
+ delay: snd_pcm_hw_delay,
prepare: snd_pcm_hw_prepare,
- go: snd_pcm_hw_go,
- drain: snd_pcm_hw_drain,
+ start: snd_pcm_hw_start,
+ stop: snd_pcm_hw_stop,
flush: snd_pcm_hw_flush,
pause: snd_pcm_hw_pause,
appl_ptr: snd_pcm_hw_appl_ptr,
- write: snd_pcm_hw_write,
- writev: snd_pcm_hw_writev,
- read: snd_pcm_hw_read,
- readv: snd_pcm_hw_readv,
- mmap_status: snd_pcm_hw_mmap_status,
- mmap_control: snd_pcm_hw_mmap_control,
- mmap_data: snd_pcm_hw_mmap_data,
- munmap_status: snd_pcm_hw_munmap_status,
- munmap_control: snd_pcm_hw_munmap_control,
- munmap_data: snd_pcm_hw_munmap_data,
- file_descriptor: snd_pcm_hw_file_descriptor,
+ writei: snd_pcm_hw_writei,
+ writen: snd_pcm_hw_writen,
+ readi: snd_pcm_hw_readi,
+ readn: snd_pcm_hw_readn,
+ poll_descriptor: snd_pcm_hw_poll_descriptor,
channels_mask: snd_pcm_hw_channels_mask,
+ avail_update: snd_pcm_hw_avail_update,
+ mmap_forward: snd_pcm_hw_mmap_forward,
};
int snd_pcm_hw_open_subdevice(snd_pcm_t **handlep, int card, int device, int subdevice, int stream, int mode)
@@ -432,7 +476,6 @@ int snd_pcm_hw_open_subdevice(snd_pcm_t **handlep, int card, int device, int sub
snd_pcm_hw_t *hw;
assert(handlep);
- *handlep = 0;
if ((ret = snd_ctl_hw_open(&ctl, card)) < 0)
return ret;
@@ -482,14 +525,8 @@ int snd_pcm_hw_open_subdevice(snd_pcm_t **handlep, int card, int device, int sub
goto __again;
}
}
- handle = calloc(1, sizeof(snd_pcm_t));
- if (!handle) {
- ret = -ENOMEM;
- goto __end;
- }
hw = calloc(1, sizeof(snd_pcm_hw_t));
- if (!handle) {
- free(handle);
+ if (!hw) {
ret = -ENOMEM;
goto __end;
}
@@ -497,6 +534,13 @@ int snd_pcm_hw_open_subdevice(snd_pcm_t **handlep, int card, int device, int sub
hw->device = device;
hw->subdevice = subdevice;
hw->fd = fd;
+
+ handle = calloc(1, sizeof(snd_pcm_t));
+ if (!handle) {
+ free(hw);
+ ret = -ENOMEM;
+ goto __end;
+ }
handle->type = SND_PCM_TYPE_HW;
handle->stream = stream;
handle->ops = &snd_pcm_hw_ops;
@@ -505,6 +549,12 @@ int snd_pcm_hw_open_subdevice(snd_pcm_t **handlep, int card, int device, int sub
handle->fast_op_arg = handle;
handle->mode = mode;
handle->private = hw;
+ ret = snd_pcm_init(handle);
+ if (ret < 0) {
+ snd_pcm_close(handle);
+ snd_ctl_close(ctl);
+ return ret;
+ }
*handlep = handle;
__end:
@@ -514,8 +564,54 @@ int snd_pcm_hw_open_subdevice(snd_pcm_t **handlep, int card, int device, int sub
return ret;
}
-int snd_pcm_hw_open(snd_pcm_t **handlep, int card, int device, int stream, int mode)
+int snd_pcm_hw_open_device(snd_pcm_t **handlep, int card, int device, int stream, int mode)
{
return snd_pcm_hw_open_subdevice(handlep, card, device, -1, stream, mode);
}
+int _snd_pcm_hw_open(snd_pcm_t **pcmp, char *name, snd_config_t *conf,
+ int stream, int mode)
+{
+ snd_config_iterator_t i;
+ long card = -1, device = 0, subdevice = -1;
+ char *str;
+ int err;
+ snd_config_foreach(i, conf) {
+ snd_config_t *n = snd_config_entry(i);
+ if (strcmp(n->id, "comment") == 0)
+ continue;
+ if (strcmp(n->id, "type") == 0)
+ continue;
+ if (strcmp(n->id, "stream") == 0)
+ continue;
+ if (strcmp(n->id, "card") == 0) {
+ err = snd_config_integer_get(n, &card);
+ if (err < 0) {
+ err = snd_config_string_get(n, &str);
+ if (err < 0)
+ return -EINVAL;
+ card = snd_card_get_index(str);
+ if (card < 0)
+ return card;
+ }
+ continue;
+ }
+ if (strcmp(n->id, "device") == 0) {
+ err = snd_config_integer_get(n, &device);
+ if (err < 0)
+ return err;
+ continue;
+ }
+ if (strcmp(n->id, "subdevice") == 0) {
+ err = snd_config_integer_get(n, &subdevice);
+ if (err < 0)
+ return err;
+ continue;
+ }
+ return -EINVAL;
+ }
+ if (card < 0)
+ return -EINVAL;
+ return snd_pcm_hw_open_subdevice(pcmp, card, device, subdevice, stream, mode);
+}
+
diff --git a/src/pcm/pcm_linear.c b/src/pcm/pcm_linear.c
new file mode 100644
index 00000000..277be5b1
--- /dev/null
+++ b/src/pcm/pcm_linear.c
@@ -0,0 +1,360 @@
+/*
+ * PCM - Linear conversion
+ * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
+ *
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <byteswap.h>
+#include "pcm_local.h"
+#include "pcm_plugin.h"
+
+typedef struct {
+ /* This field need to be the first */
+ snd_pcm_plugin_t plug;
+ int conv_idx;
+ int sformat;
+ int cformat;
+ int cxfer_mode, cmmap_shape;
+} snd_pcm_linear_t;
+
+static void linear_transfer(snd_pcm_channel_area_t *src_areas, size_t src_offset,
+ snd_pcm_channel_area_t *dst_areas, size_t dst_offset,
+ size_t frames, size_t channels, int convidx)
+{
+#define CONV_LABELS
+#include "plugin_ops.h"
+#undef CONV_LABELS
+ void *conv = conv_labels[convidx];
+ unsigned int channel;
+ for (channel = 0; channel < channels; ++channel) {
+ char *src;
+ char *dst;
+ int src_step, dst_step;
+ size_t frames1;
+ snd_pcm_channel_area_t *src_area = &src_areas[channel];
+ snd_pcm_channel_area_t *dst_area = &dst_areas[channel];
+#if 0
+ if (!src_area->enabled) {
+ if (dst_area->wanted)
+ snd_pcm_area_silence(dst_area, dst_offset, frames, dst_sfmt);
+ dst_area->enabled = 0;
+ continue;
+ }
+ dst_area->enabled = 1;
+#endif
+ src = snd_pcm_channel_area_addr(src_area, src_offset);
+ dst = snd_pcm_channel_area_addr(dst_area, dst_offset);
+ src_step = snd_pcm_channel_area_step(src_area);
+ dst_step = snd_pcm_channel_area_step(dst_area);
+ frames1 = frames;
+ while (frames1-- > 0) {
+ goto *conv;
+#define CONV_END after
+#include "plugin_ops.h"
+#undef CONV_END
+ after:
+ src += src_step;
+ dst += dst_step;
+ }
+ }
+}
+
+static int snd_pcm_linear_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t * info)
+{
+ snd_pcm_linear_t *linear = pcm->private;
+ unsigned int req_mask = info->req_mask;
+ unsigned int sfmt = info->req.format.sfmt;
+ int err;
+ if (req_mask & SND_PCM_PARAMS_SFMT &&
+ !snd_pcm_format_linear(sfmt)) {
+ info->req.fail_mask = SND_PCM_PARAMS_SFMT;
+ info->req.fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
+ return -EINVAL;
+ }
+ info->req_mask |= SND_PCM_PARAMS_SFMT;
+ info->req_mask &= ~(SND_PCM_PARAMS_MMAP_SHAPE |
+ SND_PCM_PARAMS_XFER_MODE);
+ info->req.format.sfmt = linear->sformat;
+ err = snd_pcm_params_info(linear->plug.slave, info);
+ info->req_mask = req_mask;
+ info->req.format.sfmt = sfmt;
+ if (err < 0)
+ return err;
+ if (req_mask & SND_PCM_PARAMS_SFMT)
+ info->formats = 1 << sfmt;
+ else
+ info->formats = SND_PCM_LINEAR_FORMATS;
+ info->flags &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
+ info->flags |= SND_PCM_INFO_INTERLEAVED | SND_PCM_INFO_NONINTERLEAVED;
+ return err;
+}
+
+static int snd_pcm_linear_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
+{
+ snd_pcm_linear_t *linear = pcm->private;
+ snd_pcm_t *slave = linear->plug.slave;
+ int err;
+ if (!snd_pcm_format_linear(params->format.sfmt)) {
+ params->fail_mask = SND_PCM_PARAMS_SFMT;
+ params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
+ return -EINVAL;
+ }
+ if (slave->mmap_data) {
+ err = snd_pcm_munmap_data(slave);
+ if (err < 0)
+ return err;
+ }
+ linear->cformat = params->format.sfmt;
+ linear->cxfer_mode = params->xfer_mode;
+ linear->cmmap_shape = params->mmap_shape;
+ params->format.sfmt = linear->sformat;
+ params->xfer_mode = SND_PCM_XFER_UNSPECIFIED;
+ params->mmap_shape = SND_PCM_MMAP_UNSPECIFIED;
+ err = snd_pcm_params(slave, params);
+ params->format.sfmt = linear->cformat;
+ params->xfer_mode = linear->cxfer_mode;
+ params->mmap_shape = linear->cmmap_shape;
+ if (slave->valid_setup) {
+ int r = snd_pcm_mmap_data(slave, NULL);
+ assert(r >= 0);
+ }
+ return err;
+}
+
+static int snd_pcm_linear_setup(snd_pcm_t *pcm, snd_pcm_setup_t * setup)
+{
+ snd_pcm_linear_t *linear = pcm->private;
+ int err = snd_pcm_setup(linear->plug.slave, setup);
+ if (err < 0)
+ return err;
+ assert(linear->sformat == setup->format.sfmt);
+
+ if (linear->cxfer_mode == SND_PCM_XFER_UNSPECIFIED)
+ setup->xfer_mode = SND_PCM_XFER_NONINTERLEAVED;
+ else
+ setup->xfer_mode = linear->cxfer_mode;
+ if (linear->cmmap_shape == SND_PCM_MMAP_UNSPECIFIED)
+ setup->mmap_shape = SND_PCM_MMAP_NONINTERLEAVED;
+ else
+ setup->mmap_shape = linear->cmmap_shape;
+ setup->format.sfmt = linear->cformat;
+ setup->mmap_bytes = 0;
+ if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
+ linear->conv_idx = conv_index(linear->cformat,
+ linear->sformat);
+ else
+ linear->conv_idx = conv_index(linear->sformat,
+ linear->cformat);
+ return 0;
+}
+
+static ssize_t snd_pcm_linear_write_areas(snd_pcm_t *pcm,
+ snd_pcm_channel_area_t *areas,
+ size_t offset,
+ size_t size,
+ size_t *slave_sizep)
+{
+ snd_pcm_linear_t *linear = pcm->private;
+ snd_pcm_t *slave = linear->plug.slave;
+ size_t xfer = 0;
+ ssize_t err = 0;
+ if (slave_sizep && *slave_sizep < size)
+ size = *slave_sizep;
+ assert(size > 0);
+ while (xfer < size) {
+ size_t frames = snd_pcm_mmap_playback_xfer(slave, size - xfer);
+ linear_transfer(areas, offset,
+ slave->mmap_areas, snd_pcm_mmap_offset(slave),
+ frames, pcm->setup.format.channels, linear->conv_idx);
+ err = snd_pcm_mmap_forward(slave, frames);
+ if (err < 0)
+ break;
+ assert((size_t)err == frames);
+ offset += err;
+ xfer += err;
+ snd_pcm_mmap_hw_forward(pcm, err);
+ }
+ if (xfer > 0) {
+ if (slave_sizep)
+ *slave_sizep = xfer;
+ return xfer;
+ }
+ return err;
+}
+
+static ssize_t snd_pcm_linear_read_areas(snd_pcm_t *pcm,
+ snd_pcm_channel_area_t *areas,
+ size_t offset,
+ size_t size,
+ size_t *slave_sizep)
+{
+ snd_pcm_linear_t *linear = pcm->private;
+ snd_pcm_t *slave = linear->plug.slave;
+ size_t xfer = 0;
+ ssize_t err = 0;
+ if (slave_sizep && *slave_sizep < size)
+ size = *slave_sizep;
+ assert(size > 0);
+ while (xfer < size) {
+ size_t frames = snd_pcm_mmap_capture_xfer(slave, size - xfer);
+ linear_transfer(slave->mmap_areas, snd_pcm_mmap_offset(slave),
+ areas, offset,
+ frames, pcm->setup.format.channels, linear->conv_idx);
+ err = snd_pcm_mmap_forward(slave, frames);
+ if (err < 0)
+ break;
+ assert((size_t)err == frames);
+ offset += err;
+ xfer += err;
+ snd_pcm_mmap_hw_forward(pcm, err);
+ }
+ if (xfer > 0) {
+ if (slave_sizep)
+ *slave_sizep = xfer;
+ return xfer;
+ }
+ return err;
+}
+
+static void snd_pcm_linear_dump(snd_pcm_t *pcm, FILE *fp)
+{
+ snd_pcm_linear_t *linear = pcm->private;
+ fprintf(fp, "Linear conversion PCM (%s)\n",
+ snd_pcm_format_name(linear->sformat));
+ if (pcm->valid_setup) {
+ fprintf(fp, "Its setup is:\n");
+ snd_pcm_dump_setup(pcm, fp);
+ }
+ fprintf(fp, "Slave: ");
+ snd_pcm_dump(linear->plug.slave, fp);
+}
+
+struct snd_pcm_ops snd_pcm_linear_ops = {
+ close: snd_pcm_plugin_close,
+ info: snd_pcm_plugin_info,
+ params_info: snd_pcm_linear_params_info,
+ params: snd_pcm_linear_params,
+ setup: snd_pcm_linear_setup,
+ channel_info: snd_pcm_plugin_channel_info,
+ channel_params: snd_pcm_plugin_channel_params,
+ channel_setup: snd_pcm_plugin_channel_setup,
+ dump: snd_pcm_linear_dump,
+ nonblock: snd_pcm_plugin_nonblock,
+ mmap_status: snd_pcm_plugin_mmap_status,
+ mmap_control: snd_pcm_plugin_mmap_control,
+ mmap_data: snd_pcm_plugin_mmap_data,
+ munmap_status: snd_pcm_plugin_munmap_status,
+ munmap_control: snd_pcm_plugin_munmap_control,
+ munmap_data: snd_pcm_plugin_munmap_data,
+};
+
+int snd_pcm_linear_open(snd_pcm_t **handlep, int sformat, snd_pcm_t *slave, int close_slave)
+{
+ snd_pcm_t *handle;
+ snd_pcm_linear_t *linear;
+ int err;
+ assert(handlep && slave);
+ if (snd_pcm_format_linear(sformat) != 1)
+ return -EINVAL;
+ linear = calloc(1, sizeof(snd_pcm_linear_t));
+ if (!linear) {
+ return -ENOMEM;
+ }
+ linear->sformat = sformat;
+ linear->plug.read = snd_pcm_linear_read_areas;
+ linear->plug.write = snd_pcm_linear_write_areas;
+ linear->plug.slave = slave;
+ linear->plug.close_slave = close_slave;
+
+ handle = calloc(1, sizeof(snd_pcm_t));
+ if (!handle) {
+ free(linear);
+ return -ENOMEM;
+ }
+ handle->type = SND_PCM_TYPE_LINEAR;
+ handle->stream = slave->stream;
+ handle->ops = &snd_pcm_linear_ops;
+ handle->op_arg = handle;
+ handle->fast_ops = &snd_pcm_plugin_fast_ops;
+ handle->fast_op_arg = handle;
+ handle->mode = slave->mode;
+ handle->private = linear;
+ err = snd_pcm_init(handle);
+ if (err < 0) {
+ snd_pcm_close(handle);
+ return err;
+ }
+ *handlep = handle;
+
+ return 0;
+}
+
+int _snd_pcm_linear_open(snd_pcm_t **pcmp, char *name,
+ snd_config_t *conf,
+ int stream, int mode)
+{
+ snd_config_iterator_t i;
+ char *sname = NULL;
+ int err;
+ snd_pcm_t *spcm;
+ int sformat = -1;
+ snd_config_foreach(i, conf) {
+ snd_config_t *n = snd_config_entry(i);
+ if (strcmp(n->id, "comment") == 0)
+ continue;
+ if (strcmp(n->id, "type") == 0)
+ continue;
+ if (strcmp(n->id, "stream") == 0)
+ continue;
+ if (strcmp(n->id, "sname") == 0) {
+ err = snd_config_string_get(n, &sname);
+ if (err < 0)
+ return -EINVAL;
+ continue;
+ }
+ if (strcmp(n->id, "sformat") == 0) {
+ char *f;
+ err = snd_config_string_get(n, &f);
+ if (err < 0)
+ return -EINVAL;
+ sformat = snd_pcm_format_value(f);
+ if (sformat < 0)
+ return -EINVAL;
+ if (snd_pcm_format_linear(sformat) != 1)
+ return -EINVAL;
+ continue;
+ }
+ return -EINVAL;
+ }
+ if (!sname || !sformat)
+ return -EINVAL;
+ /* This is needed cause snd_config_update may destroy config */
+ sname = strdup(sname);
+ if (!sname)
+ return -ENOMEM;
+ err = snd_pcm_open(&spcm, sname, stream, mode);
+ free(sname);
+ if (err < 0)
+ return err;
+ err = snd_pcm_linear_open(pcmp, sformat, spcm, 1);
+ if (err < 0)
+ snd_pcm_close(spcm);
+ return err;
+}
+
+
diff --git a/src/pcm/pcm_local.h b/src/pcm/pcm_local.h
index 8cabad13..35154c7a 100644
--- a/src/pcm/pcm_local.h
+++ b/src/pcm/pcm_local.h
@@ -20,43 +20,49 @@
*/
#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/uio.h>
+#include <errno.h>
#include "asoundlib.h"
struct snd_pcm_ops {
int (*close)(snd_pcm_t *pcm);
+ int (*nonblock)(snd_pcm_t *pcm, int nonblock);
int (*info)(snd_pcm_t *pcm, snd_pcm_info_t *info);
int (*params_info)(snd_pcm_t *pcm, snd_pcm_params_info_t *info);
int (*params)(snd_pcm_t *pcm, snd_pcm_params_t *params);
int (*setup)(snd_pcm_t *pcm, snd_pcm_setup_t *setup);
+ int (*channel_info)(snd_pcm_t *pcm, snd_pcm_channel_info_t *info);
+ int (*channel_params)(snd_pcm_t *pcm, snd_pcm_channel_params_t *params);
+ int (*channel_setup)(snd_pcm_t *pcm, snd_pcm_channel_setup_t *setup);
void (*dump)(snd_pcm_t *pcm, FILE *fp);
+ int (*mmap_status)(snd_pcm_t *pcm);
+ int (*mmap_control)(snd_pcm_t *pcm);
+ int (*mmap_data)(snd_pcm_t *pcm);
+ int (*munmap_status)(snd_pcm_t *pcm);
+ int (*munmap_control)(snd_pcm_t *pcm);
+ int (*munmap_data)(snd_pcm_t *pcm);
};
struct snd_pcm_fast_ops {
- int (*nonblock)(snd_pcm_t *pcm, int nonblock);
int (*status)(snd_pcm_t *pcm, snd_pcm_status_t *status);
- int (*channel_info)(snd_pcm_t *pcm, snd_pcm_channel_info_t *info);
- int (*channel_params)(snd_pcm_t *pcm, snd_pcm_channel_params_t *params);
- int (*channel_setup)(snd_pcm_t *pcm, snd_pcm_channel_setup_t *setup);
int (*prepare)(snd_pcm_t *pcm);
- int (*go)(snd_pcm_t *pcm);
- int (*drain)(snd_pcm_t *pcm);
+ int (*start)(snd_pcm_t *pcm);
+ int (*stop)(snd_pcm_t *pcm);
int (*flush)(snd_pcm_t *pcm);
int (*pause)(snd_pcm_t *pcm, int enable);
int (*state)(snd_pcm_t *pcm);
- ssize_t (*hw_ptr)(snd_pcm_t *pcm, int update);
+ int (*delay)(snd_pcm_t *pcm, ssize_t *delayp);
ssize_t (*appl_ptr)(snd_pcm_t *pcm, off_t offset);
- ssize_t (*write)(snd_pcm_t *pcm, snd_timestamp_t *tstamp, const void *buffer, size_t size);
- ssize_t (*writev)(snd_pcm_t *pcm, snd_timestamp_t *tstamp, const struct iovec *vector, unsigned long count);
- ssize_t (*read)(snd_pcm_t *pcm, snd_timestamp_t *tstamp, void *buffer, size_t size);
- ssize_t (*readv)(snd_pcm_t *pcm, snd_timestamp_t *tstamp, const struct iovec *vector, unsigned long count);
- int (*file_descriptor)(snd_pcm_t *pcm);
- int (*channels_mask)(snd_pcm_t *pcm, bitset_t *client_vmask);
- int (*mmap_status)(snd_pcm_t *pcm, snd_pcm_mmap_status_t **status);
- int (*mmap_control)(snd_pcm_t *pcm, snd_pcm_mmap_control_t **control);
- int (*mmap_data)(snd_pcm_t *pcm, void **buffer, size_t bsize);
- int (*munmap_status)(snd_pcm_t *pcm, snd_pcm_mmap_status_t *status);
- int (*munmap_control)(snd_pcm_t *pcm, snd_pcm_mmap_control_t *control);
- int (*munmap_data)(snd_pcm_t *pcm, void *buffer, size_t bsize);
+ ssize_t (*writei)(snd_pcm_t *pcm, const void *buffer, size_t size);
+ ssize_t (*writen)(snd_pcm_t *pcm, void **bufs, size_t size);
+ ssize_t (*readi)(snd_pcm_t *pcm, void *buffer, size_t size);
+ ssize_t (*readn)(snd_pcm_t *pcm, void **bufs, size_t size);
+ int (*poll_descriptor)(snd_pcm_t *pcm);
+ int (*channels_mask)(snd_pcm_t *pcm, bitset_t *cmask);
+ ssize_t (*avail_update)(snd_pcm_t *pcm);
+ ssize_t (*mmap_forward)(snd_pcm_t *pcm, size_t size);
};
struct snd_pcm {
@@ -65,13 +71,12 @@ struct snd_pcm {
int mode;
int valid_setup;
snd_pcm_setup_t setup;
- snd_pcm_channel_area_t *channels;
size_t bits_per_sample;
size_t bits_per_frame;
snd_pcm_mmap_status_t *mmap_status;
snd_pcm_mmap_control_t *mmap_control;
- char *mmap_data;
- enum { _INTERLEAVED, _NONINTERLEAVED, _COMPLEX } mmap_type;
+ void *mmap_data;
+ snd_pcm_channel_area_t *mmap_areas;
struct snd_pcm_ops *ops;
struct snd_pcm_fast_ops *fast_ops;
snd_pcm_t *op_arg;
@@ -79,74 +84,67 @@ struct snd_pcm {
void *private;
};
-#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 slave_formats);
-int snd_pcm_plug_slave_fmt(int format, snd_pcm_params_info_t *slave_info);
-int snd_pcm_plug_slave_rate(unsigned int rate, snd_pcm_params_info_t *slave_info);
-int snd_pcm_plug_slave_format(snd_pcm_format_t *format,
- snd_pcm_info_t *slave_info,
- snd_pcm_params_info_t *slave_params_info,
- snd_pcm_format_t *slave_format);
-int snd_pcm_plug_format_plugins(snd_pcm_plug_t *plug,
- snd_pcm_format_t *format,
- snd_pcm_format_t *slave_format);
+int snd_pcm_init(snd_pcm_t *pcm);
+void snd_pcm_areas_from_buf(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas, void *buf);
+void snd_pcm_areas_from_bufs(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas, void **bufs);
-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);
+int snd_pcm_mmap_status(snd_pcm_t *pcm, snd_pcm_mmap_status_t **status);
+int snd_pcm_mmap_control(snd_pcm_t *pcm, snd_pcm_mmap_control_t **control);
+int snd_pcm_mmap_data(snd_pcm_t *pcm, void **buffer);
+int snd_pcm_munmap_status(snd_pcm_t *pcm);
+int snd_pcm_munmap_control(snd_pcm_t *pcm);
+int snd_pcm_munmap_data(snd_pcm_t *pcm);
+int snd_pcm_mmap_ready(snd_pcm_t *pcm);
+ssize_t snd_pcm_mmap_appl_ptr(snd_pcm_t *pcm, off_t offset);
+void snd_pcm_mmap_appl_forward(snd_pcm_t *pcm, size_t frames);
+void snd_pcm_mmap_hw_forward(snd_pcm_t *pcm, size_t frames);
+size_t snd_pcm_mmap_hw_offset(snd_pcm_t *pcm);
+size_t snd_pcm_mmap_avail(snd_pcm_t *pcm);
+size_t snd_pcm_mmap_playback_xfer(snd_pcm_t *pcm, size_t frames);
+size_t snd_pcm_mmap_capture_xfer(snd_pcm_t *pcm, size_t frames);
-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);
-ssize_t snd_pcm_plugin_client_channels(snd_pcm_plugin_t *plugin,
- size_t frames,
- snd_pcm_plugin_channel_t **channels);
+typedef ssize_t (*snd_pcm_xfer_areas_func_t)(snd_pcm_t *pcm,
+ snd_pcm_channel_area_t *areas,
+ size_t offset, size_t size,
+ size_t *slave_sizep);
-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);
+ssize_t snd_pcm_read_areas(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas,
+ size_t offset, size_t size,
+ snd_pcm_xfer_areas_func_t func);
+ssize_t snd_pcm_write_areas(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas,
+ size_t offset, size_t size,
+ snd_pcm_xfer_areas_func_t func);
+ssize_t snd_pcm_read_mmap(snd_pcm_t *pcm, size_t size);
+ssize_t snd_pcm_write_mmap(snd_pcm_t *pcm, size_t size);
-#define ROUTE_PLUGIN_RESOLUTION 16
-
-int getput_index(int format);
-int conv_index(int src_format, int dst_format);
-
-#ifdef PLUGIN_DEBUG
-#define pdprintf( args... ) fprintf(stderr, "plugin: " ##args)
-#else
-#define pdprintf( args... ) { ; }
-#endif
-
-static inline size_t snd_pcm_mmap_playback_avail(snd_pcm_t *str)
+static inline size_t snd_pcm_mmap_playback_avail(snd_pcm_t *pcm)
{
ssize_t avail;
- avail = str->mmap_status->hw_ptr + str->setup.buffer_size - str->mmap_control->appl_ptr;
+ avail = pcm->mmap_status->hw_ptr + pcm->setup.buffer_size - pcm->mmap_control->appl_ptr;
if (avail < 0)
- avail += str->setup.boundary;
+ avail += pcm->setup.boundary;
return avail;
}
-static inline size_t snd_pcm_mmap_capture_avail(snd_pcm_t *str)
+static inline size_t snd_pcm_mmap_capture_avail(snd_pcm_t *pcm)
{
ssize_t avail;
- avail = str->mmap_status->hw_ptr - str->mmap_control->appl_ptr;
+ avail = pcm->mmap_status->hw_ptr - pcm->mmap_control->appl_ptr;
if (avail < 0)
- avail += str->setup.boundary;
+ avail += pcm->setup.boundary;
return avail;
}
-#define snd_pcm_plug_stream(plug) ((plug)->handle->stream)
+static inline void *snd_pcm_channel_area_addr(snd_pcm_channel_area_t *area, size_t offset)
+{
+ size_t bitofs = area->first + area->step * offset;
+ assert(bitofs % 8 == 0);
+ return area->addr + bitofs / 8;
+}
+
+static inline size_t snd_pcm_channel_area_step(snd_pcm_channel_area_t *area)
+{
+ assert(area->step % 8 == 0);
+ return area->step / 8;
+}
+
diff --git a/src/pcm/pcm_misc.c b/src/pcm/pcm_misc.c
index b829f5c9..57bfcf21 100644
--- a/src/pcm/pcm_misc.c
+++ b/src/pcm/pcm_misc.c
@@ -23,6 +23,9 @@
#include "../include/driver.h"
#include "../include/pcm.h"
#include "../include/pcm_plugin.h"
+#define bswap_16 swab16
+#define bswap_32 swab32
+#define bswap_64 swab64
#else
#include <stdio.h>
#include <stdlib.h>
diff --git a/src/pcm/pcm_mmap.c b/src/pcm/pcm_mmap.c
index fdb5a08e..2be47c53 100644
--- a/src/pcm/pcm_mmap.c
+++ b/src/pcm/pcm_mmap.c
@@ -26,461 +26,313 @@
#include <sys/uio.h>
#include "pcm_local.h"
-int snd_pcm_avail(snd_pcm_t *handle, ssize_t *frames)
+size_t snd_pcm_mmap_avail(snd_pcm_t *pcm)
{
- assert(handle);
- assert(handle->mmap_status && handle->mmap_control);
- if (handle->stream == SND_PCM_STREAM_PLAYBACK)
- *frames = snd_pcm_mmap_playback_avail(handle);
+ assert(pcm);
+ assert(pcm->mmap_status && pcm->mmap_control);
+ if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
+ return snd_pcm_mmap_playback_avail(pcm);
else
- *frames = snd_pcm_mmap_capture_avail(handle);
+ return snd_pcm_mmap_capture_avail(pcm);
return 0;
}
-static int snd_pcm_mmap_playback_ready(snd_pcm_t *handle)
+static int snd_pcm_mmap_playback_ready(snd_pcm_t *pcm)
{
- if (handle->mmap_status->state == SND_PCM_STATE_XRUN)
+ if (pcm->mmap_status->state == SND_PCM_STATE_XRUN)
return -EPIPE;
- return snd_pcm_mmap_playback_avail(handle) >= handle->setup.avail_min;
+ return snd_pcm_mmap_playback_avail(pcm) >= pcm->setup.avail_min;
}
-static int snd_pcm_mmap_capture_ready(snd_pcm_t *handle)
+static int snd_pcm_mmap_capture_ready(snd_pcm_t *pcm)
{
int ret = 0;
- if (handle->mmap_status->state == SND_PCM_STATE_XRUN) {
+ if (pcm->mmap_status->state == SND_PCM_STATE_XRUN) {
ret = -EPIPE;
- if (handle->setup.xrun_mode == SND_PCM_XRUN_DRAIN)
+ if (pcm->setup.xrun_act == SND_PCM_XRUN_ACT_DRAIN)
return -EPIPE;
}
- if (snd_pcm_mmap_capture_avail(handle) >= handle->setup.avail_min)
+ if (snd_pcm_mmap_capture_avail(pcm) >= pcm->setup.avail_min)
return 1;
return ret;
}
-int snd_pcm_mmap_ready(snd_pcm_t *handle)
+int snd_pcm_mmap_ready(snd_pcm_t *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);
+ assert(pcm);
+ assert(pcm->mmap_status && pcm->mmap_control);
+ assert(pcm->mmap_status->state >= SND_PCM_STATE_PREPARED);
+ if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
+ return snd_pcm_mmap_playback_ready(pcm);
} else {
- return snd_pcm_mmap_capture_ready(handle);
+ return snd_pcm_mmap_capture_ready(pcm);
}
}
-static size_t snd_pcm_mmap_playback_xfer(snd_pcm_t *handle, size_t frames)
+size_t snd_pcm_mmap_playback_xfer(snd_pcm_t *pcm, size_t frames)
{
- snd_pcm_mmap_control_t *control = handle->mmap_control;
+ snd_pcm_mmap_control_t *control = pcm->mmap_control;
size_t cont;
- size_t avail = snd_pcm_mmap_playback_avail(handle);
+ size_t avail = snd_pcm_mmap_playback_avail(pcm);
if (avail < frames)
frames = avail;
- cont = handle->setup.buffer_size - control->appl_ptr % handle->setup.buffer_size;
+ cont = pcm->setup.buffer_size - control->appl_ptr % pcm->setup.buffer_size;
if (cont < frames)
frames = cont;
return frames;
}
-static size_t snd_pcm_mmap_capture_xfer(snd_pcm_t *handle, size_t frames)
+size_t snd_pcm_mmap_capture_xfer(snd_pcm_t *pcm, size_t frames)
{
- snd_pcm_mmap_control_t *control = handle->mmap_control;
+ snd_pcm_mmap_control_t *control = pcm->mmap_control;
size_t cont;
- size_t avail = snd_pcm_mmap_capture_avail(handle);
+ size_t avail = snd_pcm_mmap_capture_avail(pcm);
if (avail < frames)
frames = avail;
- cont = handle->setup.buffer_size - control->appl_ptr % handle->setup.buffer_size;
+ cont = pcm->setup.buffer_size - control->appl_ptr % pcm->setup.buffer_size;
if (cont < frames)
frames = cont;
return frames;
}
-ssize_t snd_pcm_mmap_xfer(snd_pcm_t *handle, size_t frames)
+size_t snd_pcm_mmap_xfer(snd_pcm_t *pcm, size_t frames)
{
- assert(handle);
- assert(handle->mmap_status && handle->mmap_control);
- if (handle->stream == SND_PCM_STREAM_PLAYBACK)
- return snd_pcm_mmap_playback_xfer(handle, frames);
+ assert(pcm);
+ assert(pcm->mmap_status && pcm->mmap_control);
+ if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
+ return snd_pcm_mmap_playback_xfer(pcm, frames);
else
- return snd_pcm_mmap_capture_xfer(handle, frames);
+ return snd_pcm_mmap_capture_xfer(pcm, frames);
}
-ssize_t snd_pcm_mmap_offset(snd_pcm_t *handle)
+size_t snd_pcm_mmap_offset(snd_pcm_t *pcm)
{
- assert(handle);
- assert(handle->mmap_control);
- return handle->mmap_control->appl_ptr % handle->setup.buffer_size;
+ assert(pcm);
+ assert(pcm->mmap_control);
+ return pcm->mmap_control->appl_ptr % pcm->setup.buffer_size;
}
-int snd_pcm_mmap_state(snd_pcm_t *handle)
+size_t snd_pcm_mmap_hw_offset(snd_pcm_t *pcm)
{
- assert(handle);
- assert(handle->mmap_status);
- return handle->mmap_status->state;
+ assert(pcm);
+ assert(pcm->mmap_status);
+ return pcm->mmap_status->hw_ptr % pcm->setup.buffer_size;
}
-ssize_t snd_pcm_mmap_hw_ptr(snd_pcm_t *handle)
+int snd_pcm_mmap_state(snd_pcm_t *pcm)
{
- assert(handle);
- assert(handle->mmap_status);
- return handle->mmap_status->hw_ptr;
+ assert(pcm);
+ assert(pcm->mmap_status);
+ return pcm->mmap_status->state;
}
-ssize_t snd_pcm_mmap_appl_ptr(snd_pcm_t *handle, off_t offset)
+ssize_t snd_pcm_mmap_hw_ptr(snd_pcm_t *pcm)
+{
+ assert(pcm);
+ assert(pcm->mmap_status);
+ return pcm->mmap_status->hw_ptr;
+}
+
+ssize_t snd_pcm_mmap_appl_ptr(snd_pcm_t *pcm, off_t offset)
{
ssize_t appl_ptr;
- assert(handle);
- assert(handle->mmap_status && handle->mmap_control);
- assert(offset == 0 || handle->type == SND_PCM_TYPE_HW);
- appl_ptr = handle->mmap_control->appl_ptr;
+ assert(pcm);
+ assert(pcm->mmap_status && pcm->mmap_control);
+ assert(offset == 0 || pcm->type == SND_PCM_TYPE_HW);
+ appl_ptr = pcm->mmap_control->appl_ptr;
if (offset == 0)
return appl_ptr;
- switch (handle->mmap_status->state) {
+ switch (pcm->mmap_status->state) {
case SND_PCM_STATE_RUNNING:
- if (handle->setup.mode == SND_PCM_MODE_FRAME)
- snd_pcm_hw_ptr(handle, 1);
+ if (pcm->setup.xrun_mode == SND_PCM_XRUN_ASAP)
+ snd_pcm_avail_update(pcm);
break;
case SND_PCM_STATE_READY:
case SND_PCM_STATE_NOTREADY:
return -EBADFD;
}
if (offset < 0) {
- if (offset < -(ssize_t)handle->setup.buffer_size)
- offset = -(ssize_t)handle->setup.buffer_size;
- else
- offset -= offset % handle->setup.align;
+ if (offset < -(ssize_t)pcm->setup.buffer_size)
+ offset = -(ssize_t)pcm->setup.buffer_size;
appl_ptr += offset;
if (appl_ptr < 0)
- appl_ptr += handle->setup.boundary;
+ appl_ptr += pcm->setup.boundary;
} else {
size_t avail;
- if (handle->stream == SND_PCM_STREAM_PLAYBACK)
- avail = snd_pcm_mmap_playback_avail(handle);
+ if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
+ avail = snd_pcm_mmap_playback_avail(pcm);
else
- avail = snd_pcm_mmap_capture_avail(handle);
+ avail = snd_pcm_mmap_capture_avail(pcm);
if ((size_t)offset > avail)
offset = avail;
- offset -= offset % handle->setup.align;
appl_ptr += offset;
- if ((size_t)appl_ptr >= handle->setup.boundary)
- appl_ptr -= handle->setup.boundary;
+ if ((size_t)appl_ptr >= pcm->setup.boundary)
+ appl_ptr -= pcm->setup.boundary;
}
- handle->mmap_control->appl_ptr = appl_ptr;
+ pcm->mmap_control->appl_ptr = appl_ptr;
return appl_ptr;
}
-ssize_t snd_pcm_mmap_write_areas(snd_pcm_t *handle, snd_pcm_channel_area_t *channels, size_t frames)
+void snd_pcm_mmap_appl_forward(snd_pcm_t *pcm, size_t frames)
{
- snd_pcm_mmap_status_t *status;
- size_t offset = 0;
- size_t result = 0;
- int err;
-
- assert(handle->mmap_data && handle->mmap_status && handle->mmap_control);
- status = handle->mmap_status;
- assert(status->state >= SND_PCM_STATE_PREPARED);
- if (handle->setup.mode == SND_PCM_MODE_FRAGMENT) {
- assert(frames % handle->setup.frag_size == 0);
- } else {
- if (status->state == SND_PCM_STATE_RUNNING &&
- handle->mode & SND_PCM_NONBLOCK)
- snd_pcm_hw_ptr(handle, 1);
- }
- while (frames > 0) {
- ssize_t mmap_offset;
- size_t frames1;
- 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 (handle->mode & SND_PCM_NONBLOCK)
- return result > 0 ? result : -EAGAIN;
- 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(handle));
- }
- frames1 = snd_pcm_mmap_playback_xfer(handle, frames);
- assert(frames1 > 0);
- mmap_offset = snd_pcm_mmap_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_appl_ptr(handle, frames1);
- frames -= frames1;
- offset += frames1;
- result += frames1;
- if (status->state == SND_PCM_STATE_PREPARED &&
- (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;
- }
- }
- return result;
+ size_t appl_ptr = pcm->mmap_control->appl_ptr;
+ appl_ptr += frames;
+ if (appl_ptr >= pcm->setup.boundary)
+ appl_ptr -= pcm->setup.boundary;
+ pcm->mmap_control->appl_ptr = appl_ptr;
}
-ssize_t snd_pcm_mmap_write(snd_pcm_t *handle, const void *buffer, size_t frames)
+void snd_pcm_mmap_hw_forward(snd_pcm_t *pcm, size_t frames)
{
- unsigned int nchannels;
- assert(handle);
- assert(handle->mmap_data && handle->mmap_status && handle->mmap_control);
- assert(frames == 0 || buffer);
- 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 = handle->bits_per_sample * channel;
- channels[channel].step = handle->bits_per_frame;
- }
- return snd_pcm_mmap_write_areas(handle, channels, frames);
- }
+ size_t hw_ptr = pcm->mmap_status->hw_ptr;
+ hw_ptr += frames;
+ if (hw_ptr >= pcm->setup.boundary)
+ hw_ptr -= pcm->setup.boundary;
+ pcm->mmap_status->hw_ptr = hw_ptr;
}
-ssize_t snd_pcm_mmap_writev(snd_pcm_t *handle, const struct iovec *vector, unsigned long vcount)
+ssize_t snd_pcm_mmap_write_areas(snd_pcm_t *pcm,
+ snd_pcm_channel_area_t *areas,
+ size_t offset,
+ size_t size,
+ size_t *slave_sizep)
{
- size_t result = 0;
- unsigned int nchannels;
- assert(handle);
- assert(handle->mmap_data && handle->mmap_status && handle->mmap_control);
- assert(vcount == 0 || vector);
- 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(handle, vector[b].iov_base, frames);
- if (ret < 0) {
- if (result <= 0)
- return ret;
- break;
- }
- result += ret;
- }
- } else {
- snd_pcm_channel_area_t channels[nchannels];
- unsigned long bcount;
- unsigned int b;
- assert(vcount % nchannels == 0);
- bcount = vcount / nchannels;
- for (b = 0; b < bcount; b++) {
- unsigned int v;
- ssize_t ret;
- size_t frames = vector[0].iov_len;
- for (v = 0; v < nchannels; ++v) {
- assert(vector[v].iov_len == frames);
- channels[v].addr = vector[v].iov_base;
- channels[v].first = 0;
- channels[v].step = handle->bits_per_sample;
- }
- ret = snd_pcm_mmap_write_areas(handle, channels, frames);
- if (ret < 0) {
- if (result <= 0)
- return ret;
- break;
- }
- result += ret;
- if ((size_t)ret != frames)
- break;
- vector += nchannels;
- }
+ size_t xfer;
+ ssize_t err = 0;
+ if (slave_sizep && *slave_sizep < size)
+ size = *slave_sizep;
+ xfer = 0;
+ while (xfer < size) {
+ size_t frames = snd_pcm_mmap_playback_xfer(pcm, size - xfer);
+ snd_pcm_areas_copy(areas, offset,
+ pcm->mmap_areas, snd_pcm_mmap_offset(pcm),
+ pcm->setup.format.channels,
+ frames, pcm->setup.format.sfmt);
+ err = snd_pcm_mmap_forward(pcm, frames);
+ if (err < 0)
+ break;
+ assert((size_t)err == frames);
+ offset += err;
+ xfer += err;
+ }
+ if (xfer > 0) {
+ if (slave_sizep)
+ *slave_sizep = xfer;
+ return xfer;
}
- return result;
+ return err;
}
-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_areas(snd_pcm_t *pcm,
+ snd_pcm_channel_area_t *areas,
+ size_t offset,
+ size_t size,
+ size_t *slave_sizep)
{
- snd_pcm_mmap_status_t *status;
- size_t offset = 0;
- size_t result = 0;
- int err;
-
- assert(handle->mmap_data && handle->mmap_status && handle->mmap_control);
- status = handle->mmap_status;
- assert(status->state >= SND_PCM_STATE_PREPARED);
- if (handle->setup.mode == SND_PCM_MODE_FRAGMENT) {
- assert(frames % handle->setup.frag_size == 0);
- } else {
- if (status->state == SND_PCM_STATE_RUNNING &&
- handle->mode & SND_PCM_NONBLOCK)
- snd_pcm_hw_ptr(handle, 1);
- }
- if (status->state == SND_PCM_STATE_PREPARED &&
- handle->setup.start_mode == SND_PCM_START_DATA) {
- err = snd_pcm_go(handle);
+ size_t xfer;
+ ssize_t err = 0;
+ if (slave_sizep && *slave_sizep < size)
+ size = *slave_sizep;
+ xfer = 0;
+ while (xfer < size) {
+ size_t frames = snd_pcm_mmap_capture_xfer(pcm, size - xfer);
+ snd_pcm_areas_copy(pcm->mmap_areas, snd_pcm_mmap_offset(pcm),
+ areas, offset,
+ pcm->setup.format.channels,
+ frames, pcm->setup.format.sfmt);
+ err = snd_pcm_mmap_forward(pcm, frames);
if (err < 0)
- return err;
+ break;
+ assert((size_t)err == frames);
+ offset += err;
+ xfer += err;
}
- while (frames > 0) {
- ssize_t mmap_offset;
- size_t frames1;
- 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 (handle->mode & SND_PCM_NONBLOCK)
- return result > 0 ? result : -EAGAIN;
- 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(handle));
- }
- frames1 = snd_pcm_mmap_capture_xfer(handle, frames);
- assert(frames1 > 0);
- mmap_offset = snd_pcm_mmap_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 &&
- handle->setup.xrun_mode == SND_PCM_XRUN_DRAIN)
- return result > 0 ? result : -EPIPE;
- snd_pcm_appl_ptr(handle, frames1);
- frames -= frames1;
- offset += frames1;
- result += frames1;
+ if (xfer > 0) {
+ if (slave_sizep)
+ *slave_sizep = xfer;
+ return xfer;
}
- return result;
+ return err;
}
-ssize_t snd_pcm_mmap_read(snd_pcm_t *handle, void *buffer, size_t frames)
+ssize_t snd_pcm_mmap_writei(snd_pcm_t *pcm, const void *buffer, size_t size)
{
- unsigned int nchannels;
- assert(handle);
- assert(handle->mmap_data && handle->mmap_status && handle->mmap_control);
- assert(frames == 0 || buffer);
- 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 = handle->bits_per_sample * channel;
- channels[channel].step = handle->bits_per_frame;
- }
- return snd_pcm_mmap_read_areas(handle, channels, frames);
- }
+ snd_pcm_channel_area_t areas[pcm->setup.format.channels];
+ snd_pcm_areas_from_buf(pcm, areas, (void*)buffer);
+ return snd_pcm_write_areas(pcm, areas, 0, size,
+ snd_pcm_mmap_write_areas);
}
-ssize_t snd_pcm_mmap_readv(snd_pcm_t *handle, const struct iovec *vector, unsigned long vcount)
+ssize_t snd_pcm_mmap_writen(snd_pcm_t *pcm, void **bufs, size_t size)
{
- size_t result = 0;
- unsigned int nchannels;
- assert(handle);
- assert(handle->mmap_data && handle->mmap_status && handle->mmap_control);
- assert(vcount == 0 || vector);
- 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(handle, vector[b].iov_base, frames);
- if (ret < 0) {
- if (result <= 0)
- return ret;
- break;
- }
- result += ret;
- }
- } else {
- snd_pcm_channel_area_t channels[nchannels];
- unsigned long bcount;
- unsigned int b;
- assert(vcount % nchannels == 0);
- bcount = vcount / nchannels;
- for (b = 0; b < bcount; b++) {
- unsigned int v;
- ssize_t ret;
- size_t frames = vector[0].iov_len;
- for (v = 0; v < nchannels; ++v) {
- assert(vector[v].iov_len == frames);
- channels[v].addr = vector[v].iov_base;
- channels[v].first = 0;
- channels[v].step = handle->bits_per_sample;
- }
- ret = snd_pcm_mmap_read_areas(handle, channels, frames);
- if (ret < 0) {
- if (result <= 0)
- return ret;
- break;
- }
- result += ret;
- if ((size_t)ret != frames)
- break;
- vector += nchannels;
- }
- }
- return result;
+ snd_pcm_channel_area_t areas[pcm->setup.format.channels];
+ snd_pcm_areas_from_bufs(pcm, areas, bufs);
+ return snd_pcm_write_areas(pcm, areas, 0, size,
+ snd_pcm_mmap_write_areas);
}
-int snd_pcm_mmap_status(snd_pcm_t *handle, snd_pcm_mmap_status_t **status)
+ssize_t snd_pcm_mmap_readi(snd_pcm_t *pcm, void *buffer, size_t size)
+{
+ snd_pcm_channel_area_t areas[pcm->setup.format.channels];
+ snd_pcm_areas_from_buf(pcm, areas, buffer);
+ return snd_pcm_read_areas(pcm, areas, 0, size,
+ snd_pcm_mmap_read_areas);
+}
+
+ssize_t snd_pcm_mmap_readn(snd_pcm_t *pcm, void **bufs, size_t size)
+{
+ snd_pcm_channel_area_t areas[pcm->setup.format.channels];
+ snd_pcm_areas_from_bufs(pcm, areas, bufs);
+ return snd_pcm_read_areas(pcm, areas, 0, size,
+ snd_pcm_mmap_read_areas);
+}
+
+int snd_pcm_mmap_status(snd_pcm_t *pcm, snd_pcm_mmap_status_t **status)
{
int err;
- assert(handle);
- assert(handle->valid_setup);
- if (handle->mmap_status) {
+ assert(pcm);
+ if (pcm->mmap_status) {
if (status)
- *status = handle->mmap_status;
+ *status = pcm->mmap_status;
return 0;
}
- if ((err = handle->fast_ops->mmap_status(handle->fast_op_arg, &handle->mmap_status)) < 0)
+ if ((err = pcm->ops->mmap_status(pcm->op_arg)) < 0)
return err;
if (status)
- *status = handle->mmap_status;
+ *status = pcm->mmap_status;
return 0;
}
-int snd_pcm_mmap_control(snd_pcm_t *handle, snd_pcm_mmap_control_t **control)
+int snd_pcm_mmap_control(snd_pcm_t *pcm, snd_pcm_mmap_control_t **control)
{
int err;
- assert(handle);
- assert(handle->valid_setup);
- if (handle->mmap_control) {
+ assert(pcm);
+ if (pcm->mmap_control) {
if (control)
- *control = handle->mmap_control;
+ *control = pcm->mmap_control;
return 0;
}
- if ((err = handle->fast_ops->mmap_control(handle->fast_op_arg, &handle->mmap_control)) < 0)
+ if ((err = pcm->ops->mmap_control(pcm->op_arg)) < 0)
return err;
if (control)
- *control = handle->mmap_control;
+ *control = pcm->mmap_control;
return 0;
}
-int snd_pcm_mmap_get_areas(snd_pcm_t *handle, snd_pcm_channel_area_t *areas)
+int snd_pcm_mmap_get_areas(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas)
{
snd_pcm_channel_setup_t s;
snd_pcm_channel_area_t *a, *ap;
unsigned int channel;
- int interleaved = 1, noninterleaved = 1;
int err;
- 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) {
+ assert(pcm);
+ assert(pcm->mmap_data);
+ a = calloc(pcm->setup.format.channels, sizeof(*areas));
+ for (channel = 0, ap = a; channel < pcm->setup.format.channels; ++channel, ++ap) {
s.channel = channel;
- err = snd_pcm_channel_setup(handle, &s);
+ err = snd_pcm_channel_setup(pcm, &s);
if (err < 0) {
free(a);
return err;
@@ -488,110 +340,146 @@ int snd_pcm_mmap_get_areas(snd_pcm_t *handle, snd_pcm_channel_area_t *areas)
if (areas)
areas[channel] = s.area;
*ap = s.area;
- if (ap->step != handle->bits_per_sample || ap->first != 0)
- noninterleaved = 0;
- if (ap->addr != a[0].addr ||
- ap->step != handle->bits_per_frame ||
- ap->first != channel * handle->bits_per_sample)
- interleaved = 0;
}
- if (noninterleaved)
- handle->mmap_type = _NONINTERLEAVED;
- else if (interleaved)
- handle->mmap_type = _INTERLEAVED;
- else
- handle->mmap_type = _COMPLEX;
- handle->channels = a;
+ pcm->mmap_areas = a;
return 0;
}
-int snd_pcm_mmap_data(snd_pcm_t *handle, void **data)
+int snd_pcm_mmap_data(snd_pcm_t *pcm, void **data)
{
int err;
- assert(handle);
- assert(handle->valid_setup);
- if (handle->mmap_data) {
+ assert(pcm);
+ assert(pcm->valid_setup);
+ if (pcm->mmap_data) {
if (data)
- *data = handle->mmap_data;
+ *data = pcm->mmap_data;
return 0;
}
- if (handle->setup.mmap_bytes == 0)
- return -ENXIO;
- if ((err = handle->fast_ops->mmap_data(handle->fast_op_arg, (void**)&handle->mmap_data, handle->setup.mmap_bytes)) < 0)
+ if ((err = pcm->ops->mmap_data(pcm->op_arg)) < 0)
return err;
if (data)
- *data = handle->mmap_data;
- err = snd_pcm_mmap_get_areas(handle, NULL);
+ *data = pcm->mmap_data;
+ err = snd_pcm_mmap_get_areas(pcm, NULL);
if (err < 0)
return err;
return 0;
}
-int snd_pcm_mmap(snd_pcm_t *handle, snd_pcm_mmap_status_t **status, snd_pcm_mmap_control_t **control, void **data)
+int snd_pcm_munmap_status(snd_pcm_t *pcm)
{
int err;
- err = snd_pcm_mmap_status(handle, status);
- if (err < 0)
+ assert(pcm);
+ assert(pcm->mmap_status);
+ if ((err = pcm->ops->munmap_status(pcm->op_arg)) < 0)
return err;
- err = snd_pcm_mmap_control(handle, control);
- if (err < 0) {
- snd_pcm_munmap_status(handle);
- return err;
- }
- err = snd_pcm_mmap_data(handle, data);
- if (err < 0) {
- snd_pcm_munmap_status(handle);
- snd_pcm_munmap_control(handle);
- return err;
- }
+ pcm->mmap_status = 0;
return 0;
}
-int snd_pcm_munmap_status(snd_pcm_t *handle)
+int snd_pcm_munmap_control(snd_pcm_t *pcm)
{
int err;
- assert(handle);
- assert(handle->mmap_status);
- if ((err = handle->fast_ops->munmap_status(handle->fast_op_arg, handle->mmap_status)) < 0)
+ assert(pcm);
+ assert(pcm->mmap_control);
+ if ((err = pcm->ops->munmap_control(pcm->op_arg)) < 0)
return err;
- handle->mmap_status = 0;
+ pcm->mmap_control = 0;
return 0;
}
-int snd_pcm_munmap_control(snd_pcm_t *handle)
+int snd_pcm_munmap_data(snd_pcm_t *pcm)
{
int err;
- assert(handle);
- assert(handle->mmap_control);
- if ((err = handle->fast_ops->munmap_control(handle->fast_op_arg, handle->mmap_control)) < 0)
+ assert(pcm);
+ assert(pcm->mmap_data);
+ if ((err = pcm->ops->munmap_data(pcm->op_arg)) < 0)
return err;
- handle->mmap_control = 0;
+ free(pcm->mmap_areas);
+ pcm->mmap_areas = 0;
+ pcm->mmap_data = 0;
return 0;
}
-int snd_pcm_munmap_data(snd_pcm_t *handle)
+int snd_pcm_mmap(snd_pcm_t *pcm, void **data)
{
- int err;
- assert(handle);
- assert(handle->mmap_data);
- if ((err = handle->fast_ops->munmap_data(handle->fast_op_arg, handle->mmap_data, handle->setup.mmap_bytes)) < 0)
- return err;
- free(handle->channels);
- handle->channels = 0;
- handle->mmap_data = 0;
- return 0;
+ return snd_pcm_mmap_data(pcm, data);
}
-int snd_pcm_munmap(snd_pcm_t *handle)
+int snd_pcm_munmap(snd_pcm_t *pcm)
{
- int err;
- err = snd_pcm_munmap_status(handle);
- if (err < 0)
- return err;
- err = snd_pcm_munmap_control(handle);
- if (err < 0)
- return err;
- return snd_pcm_munmap_data(handle);
+ return snd_pcm_munmap_data(pcm);
}
+
+ssize_t snd_pcm_write_mmap(snd_pcm_t *pcm, size_t size)
+{
+ size_t xfer = 0;
+ ssize_t err = 0;
+ assert(size > 0);
+ while (xfer < size) {
+ size_t frames = size - xfer;
+ size_t offset = snd_pcm_mmap_hw_offset(pcm);
+ size_t cont = pcm->setup.buffer_size - offset;
+ if (cont < frames)
+ frames = cont;
+ if (pcm->setup.xfer_mode == SND_PCM_XFER_INTERLEAVED) {
+ snd_pcm_channel_area_t *a = pcm->mmap_areas;
+ char *buf = snd_pcm_channel_area_addr(a, offset);
+ assert(pcm->setup.mmap_shape == SND_PCM_MMAP_INTERLEAVED);
+ err = snd_pcm_writei(pcm, buf, frames);
+ } else {
+ size_t channels = pcm->setup.format.channels;
+ unsigned int c;
+ void *bufs[channels];
+ assert(pcm->setup.mmap_shape == SND_PCM_MMAP_NONINTERLEAVED);
+ for (c = 0; c < channels; ++c) {
+ snd_pcm_channel_area_t *a = &pcm->mmap_areas[c];
+ bufs[c] = snd_pcm_channel_area_addr(a, offset);
+ }
+ err = snd_pcm_writen(pcm, bufs, frames);
+ }
+ if (err < 0)
+ break;
+ xfer += frames;
+ }
+ if (xfer > 0)
+ return xfer;
+ return err;
+}
+
+ssize_t snd_pcm_read_mmap(snd_pcm_t *pcm, size_t size)
+{
+ size_t xfer = 0;
+ ssize_t err = 0;
+ assert(size > 0);
+ while (xfer < size) {
+ size_t frames = size - xfer;
+ size_t offset = snd_pcm_mmap_hw_offset(pcm);
+ size_t cont = pcm->setup.buffer_size - offset;
+ if (cont < frames)
+ frames = cont;
+ if (pcm->setup.xfer_mode == SND_PCM_XFER_INTERLEAVED) {
+ snd_pcm_channel_area_t *a = pcm->mmap_areas;
+ char *buf = snd_pcm_channel_area_addr(a, offset);
+ assert(pcm->setup.mmap_shape == SND_PCM_MMAP_INTERLEAVED);
+ err = snd_pcm_readi(pcm, buf, frames);
+ } else {
+ size_t channels = pcm->setup.format.channels;
+ unsigned int c;
+ void *bufs[channels];
+ assert(pcm->setup.mmap_shape == SND_PCM_MMAP_NONINTERLEAVED);
+ for (c = 0; c < channels; ++c) {
+ snd_pcm_channel_area_t *a = &pcm->mmap_areas[c];
+ bufs[c] = snd_pcm_channel_area_addr(a, offset);
+ }
+ err = snd_pcm_readn(pcm, bufs, frames);
+ }
+ if (err < 0)
+ break;
+ xfer += frames;
+ }
+ if (xfer > 0)
+ return xfer;
+ return err;
+}
diff --git a/src/pcm/pcm_mulaw.c b/src/pcm/pcm_mulaw.c
new file mode 100644
index 00000000..14fc3c3a
--- /dev/null
+++ b/src/pcm/pcm_mulaw.c
@@ -0,0 +1,536 @@
+/*
+ * PCM - Mu-Law conversion
+ * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
+ *
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <byteswap.h>
+#include "pcm_local.h"
+#include "pcm_plugin.h"
+
+typedef void (*mulaw_f)(snd_pcm_channel_area_t *src_areas,
+ size_t src_offset,
+ snd_pcm_channel_area_t *dst_areas,
+ size_t dst_offset,
+ size_t frames, size_t channels, int getputidx);
+
+typedef struct {
+ /* This field need to be the first */
+ snd_pcm_plugin_t plug;
+ int getput_idx;
+ mulaw_f func;
+ int sformat;
+ int cformat;
+ int cxfer_mode, cmmap_shape;
+} snd_pcm_mulaw_t;
+
+static inline int val_seg(int val)
+{
+ int r = 0;
+ val >>= 7;
+ if (val & 0xf0) {
+ val >>= 4;
+ r += 4;
+ }
+ if (val & 0x0c) {
+ val >>= 2;
+ r += 2;
+ }
+ if (val & 0x02)
+ r += 1;
+ return r;
+}
+
+/*
+ * s16_to_ulaw() - Convert a linear PCM value to u-law
+ *
+ * In order to simplify the encoding process, the original linear magnitude
+ * is biased by adding 33 which shifts the encoding range from (0 - 8158) to
+ * (33 - 8191). The result can be seen in the following encoding table:
+ *
+ * Biased Linear Input Code Compressed Code
+ * ------------------------ ---------------
+ * 00000001wxyza 000wxyz
+ * 0000001wxyzab 001wxyz
+ * 000001wxyzabc 010wxyz
+ * 00001wxyzabcd 011wxyz
+ * 0001wxyzabcde 100wxyz
+ * 001wxyzabcdef 101wxyz
+ * 01wxyzabcdefg 110wxyz
+ * 1wxyzabcdefgh 111wxyz
+ *
+ * Each biased linear code has a leading 1 which identifies the segment
+ * number. The value of the segment number is equal to 7 minus the number
+ * of leading 0's. The quantization interval is directly available as the
+ * four bits wxyz. * The trailing bits (a - h) are ignored.
+ *
+ * Ordinarily the complement of the resulting code word is used for
+ * transmission, and so the code word is complemented before it is returned.
+ *
+ * For further information see John C. Bellamy's Digital Telephony, 1982,
+ * John Wiley & Sons, pps 98-111 and 472-476.
+ */
+
+static unsigned char s16_to_ulaw(int pcm_val) /* 2's complement (16-bit range) */
+{
+ int mask;
+ int seg;
+ unsigned char uval;
+
+ if (pcm_val < 0) {
+ pcm_val = -pcm_val + 0x84;
+ mask = 0x7f;
+ } else {
+ pcm_val += 0x84;
+ mask = 0xff;
+ }
+ if (pcm_val > 0x7fff)
+ pcm_val = 0x7fff;
+
+ /* Convert the scaled magnitude to segment number. */
+ seg = val_seg(pcm_val);
+
+ /*
+ * Combine the sign, segment, quantization bits;
+ * and complement the code word.
+ */
+ uval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0x0f);
+ return uval ^ mask;
+}
+
+/*
+ * ulaw_to_s16() - Convert a u-law value to 16-bit linear PCM
+ *
+ * First, a biased linear code is derived from the code word. An unbiased
+ * output can then be obtained by subtracting 33 from the biased code.
+ *
+ * Note that this function expects to be passed the complement of the
+ * original code word. This is in keeping with ISDN conventions.
+ */
+static int ulaw_to_s16(unsigned char u_val)
+{
+ int t;
+
+ /* Complement to obtain normal u-law value. */
+ u_val = ~u_val;
+
+ /*
+ * Extract and bias the quantization bits. Then
+ * shift up by the segment number and subtract out the bias.
+ */
+ t = ((u_val & 0x0f) << 3) + 0x84;
+ t <<= (u_val & 0x70) >> 4;
+
+ return ((u_val & 0x80) ? (0x84 - t) : (t - 0x84));
+}
+
+static void mulaw_decode(snd_pcm_channel_area_t *src_areas,
+ size_t src_offset,
+ snd_pcm_channel_area_t *dst_areas,
+ size_t dst_offset,
+ size_t frames, size_t channels, int putidx)
+{
+#define PUT_S16_LABELS
+#include "plugin_ops.h"
+#undef PUT_S16_LABELS
+ void *put = put_s16_labels[putidx];
+ size_t channel;
+ for (channel = 0; channel < channels; ++channel) {
+ char *src;
+ char *dst;
+ int src_step, dst_step;
+ size_t frames1;
+ snd_pcm_channel_area_t *src_area = &src_areas[channel];
+ snd_pcm_channel_area_t *dst_area = &dst_areas[channel];
+#if 0
+ if (!src_area->enabled) {
+ if (dst_area->wanted)
+ snd_pcm_area_silence(&dst_areas[channel], dst_offset, frames, dst_sfmt);
+ dst_area->enabled = 0;
+ continue;
+ }
+ dst_area->enabled = 1;
+#endif
+ src = snd_pcm_channel_area_addr(src_area, src_offset);
+ dst = snd_pcm_channel_area_addr(dst_area, dst_offset);
+ src_step = snd_pcm_channel_area_step(src_area);
+ dst_step = snd_pcm_channel_area_step(dst_area);
+ frames1 = frames;
+ while (frames1-- > 0) {
+ int16_t sample = ulaw_to_s16(*src);
+ goto *put;
+#define PUT_S16_END after
+#include "plugin_ops.h"
+#undef PUT_S16_END
+ after:
+ src += src_step;
+ dst += dst_step;
+ }
+ }
+}
+
+static void mulaw_encode(snd_pcm_channel_area_t *src_areas,
+ size_t src_offset,
+ snd_pcm_channel_area_t *dst_areas,
+ size_t dst_offset,
+ size_t frames, size_t channels, int getidx)
+{
+#define GET_S16_LABELS
+#include "plugin_ops.h"
+#undef GET_S16_LABELS
+ void *get = get_s16_labels[getidx];
+ size_t channel;
+ int16_t sample = 0;
+ for (channel = 0; channel < channels; ++channel) {
+ char *src;
+ char *dst;
+ int src_step, dst_step;
+ size_t frames1;
+ snd_pcm_channel_area_t *src_area = &src_areas[channel];
+ snd_pcm_channel_area_t *dst_area = &dst_areas[channel];
+#if 0
+ if (!src_area->enabled) {
+ if (dst_area->wanted)
+ snd_pcm_area_silence(&dst_area->area, 0, frames, dst_sfmt);
+ dst_area->enabled = 0;
+ continue;
+ }
+ dst_area->enabled = 1;
+#endif
+ src = snd_pcm_channel_area_addr(src_area, src_offset);
+ dst = snd_pcm_channel_area_addr(dst_area, dst_offset);
+ src_step = snd_pcm_channel_area_step(src_area);
+ dst_step = snd_pcm_channel_area_step(dst_area);
+ frames1 = frames;
+ while (frames1-- > 0) {
+ goto *get;
+#define GET_S16_END after
+#include "plugin_ops.h"
+#undef GET_S16_END
+ after:
+ *dst = s16_to_ulaw(sample);
+ src += src_step;
+ dst += dst_step;
+ }
+ }
+}
+
+static int snd_pcm_mulaw_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t * info)
+{
+ snd_pcm_mulaw_t *mulaw = pcm->private;
+ unsigned int req_mask = info->req_mask;
+ unsigned int sfmt = info->req.format.sfmt;
+ int err;
+ if (req_mask & SND_PCM_PARAMS_SFMT) {
+ if (mulaw->sformat == SND_PCM_SFMT_MU_LAW ?
+ !snd_pcm_format_linear(sfmt) :
+ sfmt != SND_PCM_SFMT_MU_LAW) {
+ info->req.fail_mask = SND_PCM_PARAMS_SFMT;
+ info->req.fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
+ return -EINVAL;
+ }
+ }
+ info->req_mask |= SND_PCM_PARAMS_SFMT;
+ info->req_mask &= ~(SND_PCM_PARAMS_MMAP_SHAPE |
+ SND_PCM_PARAMS_XFER_MODE);
+ info->req.format.sfmt = mulaw->sformat;
+ err = snd_pcm_params_info(mulaw->plug.slave, info);
+ info->req_mask = req_mask;
+ info->req.format.sfmt = sfmt;
+ if (err < 0)
+ return err;
+ if (req_mask & SND_PCM_PARAMS_SFMT)
+ info->formats = 1 << sfmt;
+ else
+ info->formats = mulaw->sformat == SND_PCM_SFMT_MU_LAW ?
+ SND_PCM_LINEAR_FORMATS : 1 << SND_PCM_SFMT_MU_LAW;
+ info->flags &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
+ info->flags |= SND_PCM_INFO_INTERLEAVED | SND_PCM_INFO_NONINTERLEAVED;
+ return err;
+}
+
+static int snd_pcm_mulaw_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
+{
+ snd_pcm_mulaw_t *mulaw = pcm->private;
+ snd_pcm_t *slave = mulaw->plug.slave;
+ int err;
+ if (mulaw->sformat == SND_PCM_SFMT_MU_LAW ?
+ !snd_pcm_format_linear(params->format.sfmt) :
+ params->format.sfmt != SND_PCM_SFMT_MU_LAW) {
+ params->fail_mask = SND_PCM_PARAMS_SFMT;
+ params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
+ return -EINVAL;
+ }
+ if (slave->mmap_data) {
+ err = snd_pcm_munmap_data(slave);
+ if (err < 0)
+ return err;
+ }
+ mulaw->cformat = params->format.sfmt;
+ mulaw->cxfer_mode = params->xfer_mode;
+ mulaw->cmmap_shape = params->mmap_shape;
+ params->format.sfmt = mulaw->sformat;
+ params->xfer_mode = SND_PCM_XFER_UNSPECIFIED;
+ params->mmap_shape = SND_PCM_MMAP_UNSPECIFIED;;
+ err = snd_pcm_params(slave, params);
+ params->format.sfmt = mulaw->cformat;
+ params->xfer_mode = mulaw->cxfer_mode;
+ params->mmap_shape = mulaw->cmmap_shape;
+ if (slave->valid_setup) {
+ int r = snd_pcm_mmap_data(slave, NULL);
+ assert(r >= 0);
+ }
+ return err;
+}
+
+static int snd_pcm_mulaw_setup(snd_pcm_t *pcm, snd_pcm_setup_t * setup)
+{
+ snd_pcm_mulaw_t *mulaw = pcm->private;
+ int err = snd_pcm_setup(mulaw->plug.slave, setup);
+ if (err < 0)
+ return err;
+ assert(mulaw->sformat == setup->format.sfmt);
+ if (mulaw->cxfer_mode == SND_PCM_XFER_UNSPECIFIED)
+ setup->xfer_mode = SND_PCM_XFER_NONINTERLEAVED;
+ else
+ setup->xfer_mode = mulaw->cxfer_mode;
+ if (mulaw->cmmap_shape == SND_PCM_MMAP_UNSPECIFIED)
+ setup->mmap_shape = SND_PCM_MMAP_NONINTERLEAVED;
+ else
+ setup->mmap_shape = mulaw->cmmap_shape;
+ setup->format.sfmt = mulaw->cformat;
+ setup->mmap_bytes = 0;
+ if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
+ if (mulaw->sformat == SND_PCM_SFMT_MU_LAW) {
+ mulaw->getput_idx = getput_index(mulaw->cformat);
+ mulaw->func = mulaw_encode;
+ } else {
+ mulaw->getput_idx = getput_index(mulaw->sformat);
+ mulaw->func = mulaw_decode;
+ }
+ } else {
+ if (mulaw->sformat == SND_PCM_SFMT_MU_LAW) {
+ mulaw->getput_idx = getput_index(mulaw->cformat);
+ mulaw->func = mulaw_decode;
+ } else {
+ mulaw->getput_idx = getput_index(mulaw->sformat);
+ mulaw->func = mulaw_encode;
+ }
+ }
+ return 0;
+}
+
+static ssize_t snd_pcm_mulaw_write_areas(snd_pcm_t *pcm,
+ snd_pcm_channel_area_t *areas,
+ size_t offset,
+ size_t size,
+ size_t *slave_sizep)
+{
+ snd_pcm_mulaw_t *mulaw = pcm->private;
+ snd_pcm_t *slave = mulaw->plug.slave;
+ size_t xfer = 0;
+ ssize_t err = 0;
+ if (slave_sizep && *slave_sizep < size)
+ size = *slave_sizep;
+ assert(size > 0);
+ while (xfer < size) {
+ size_t frames = snd_pcm_mmap_playback_xfer(slave, size - xfer);
+ mulaw->func(areas, offset,
+ slave->mmap_areas, snd_pcm_mmap_offset(slave),
+ frames, pcm->setup.format.channels,
+ mulaw->getput_idx);
+ err = snd_pcm_mmap_forward(slave, frames);
+ if (err < 0)
+ break;
+ assert((size_t)err == frames);
+ offset += err;
+ xfer += err;
+ snd_pcm_mmap_hw_forward(pcm, err);
+ }
+ if (xfer > 0) {
+ if (slave_sizep)
+ *slave_sizep = xfer;
+ return xfer;
+ }
+ return err;
+}
+
+static ssize_t snd_pcm_mulaw_read_areas(snd_pcm_t *pcm,
+ snd_pcm_channel_area_t *areas,
+ size_t offset,
+ size_t size,
+ size_t *slave_sizep)
+{
+ snd_pcm_mulaw_t *mulaw = pcm->private;
+ snd_pcm_t *slave = mulaw->plug.slave;
+ size_t xfer = 0;
+ ssize_t err = 0;
+ if (slave_sizep && *slave_sizep < size)
+ size = *slave_sizep;
+ assert(size > 0);
+ while (xfer < size) {
+ size_t frames = snd_pcm_mmap_capture_xfer(slave, size - xfer);
+ mulaw->func(slave->mmap_areas, snd_pcm_mmap_offset(slave),
+ areas, offset,
+ frames, pcm->setup.format.channels,
+ mulaw->getput_idx);
+ err = snd_pcm_mmap_forward(slave, frames);
+ if (err < 0)
+ break;
+ assert((size_t)err == frames);
+ offset += err;
+ xfer += err;
+ snd_pcm_mmap_hw_forward(pcm, err);
+ }
+ if (xfer > 0) {
+ if (slave_sizep)
+ *slave_sizep = xfer;
+ return xfer;
+ }
+ return err;
+}
+
+static void snd_pcm_mulaw_dump(snd_pcm_t *pcm, FILE *fp)
+{
+ snd_pcm_mulaw_t *mulaw = pcm->private;
+ fprintf(fp, "Mu-Law conversion PCM (%s)\n",
+ snd_pcm_format_name(mulaw->sformat));
+ if (pcm->valid_setup) {
+ fprintf(fp, "Its setup is:\n");
+ snd_pcm_dump_setup(pcm, fp);
+ }
+ fprintf(fp, "Slave: ");
+ snd_pcm_dump(mulaw->plug.slave, fp);
+}
+
+struct snd_pcm_ops snd_pcm_mulaw_ops = {
+ close: snd_pcm_plugin_close,
+ info: snd_pcm_plugin_info,
+ params_info: snd_pcm_mulaw_params_info,
+ params: snd_pcm_mulaw_params,
+ setup: snd_pcm_mulaw_setup,
+ channel_info: snd_pcm_plugin_channel_info,
+ channel_params: snd_pcm_plugin_channel_params,
+ channel_setup: snd_pcm_plugin_channel_setup,
+ dump: snd_pcm_mulaw_dump,
+ nonblock: snd_pcm_plugin_nonblock,
+ mmap_status: snd_pcm_plugin_mmap_status,
+ mmap_control: snd_pcm_plugin_mmap_control,
+ mmap_data: snd_pcm_plugin_mmap_data,
+ munmap_status: snd_pcm_plugin_munmap_status,
+ munmap_control: snd_pcm_plugin_munmap_control,
+ munmap_data: snd_pcm_plugin_munmap_data,
+};
+
+int snd_pcm_mulaw_open(snd_pcm_t **handlep, int sformat, snd_pcm_t *slave, int close_slave)
+{
+ snd_pcm_t *handle;
+ snd_pcm_mulaw_t *mulaw;
+ int err;
+ assert(handlep && slave);
+ if (snd_pcm_format_linear(sformat) != 1 &&
+ sformat != SND_PCM_SFMT_MU_LAW)
+ return -EINVAL;
+ mulaw = calloc(1, sizeof(snd_pcm_mulaw_t));
+ if (!mulaw) {
+ return -ENOMEM;
+ }
+ mulaw->sformat = sformat;
+ mulaw->plug.read = snd_pcm_mulaw_read_areas;
+ mulaw->plug.write = snd_pcm_mulaw_write_areas;
+ mulaw->plug.slave = slave;
+ mulaw->plug.close_slave = close_slave;
+
+ handle = calloc(1, sizeof(snd_pcm_t));
+ if (!handle) {
+ free(mulaw);
+ return -ENOMEM;
+ }
+ handle->type = SND_PCM_TYPE_MULAW;
+ handle->stream = slave->stream;
+ handle->ops = &snd_pcm_mulaw_ops;
+ handle->op_arg = handle;
+ handle->fast_ops = &snd_pcm_plugin_fast_ops;
+ handle->fast_op_arg = handle;
+ handle->mode = slave->mode;
+ handle->private = mulaw;
+ err = snd_pcm_init(handle);
+ if (err < 0) {
+ snd_pcm_close(handle);
+ return err;
+ }
+ *handlep = handle;
+
+ return 0;
+}
+
+int _snd_pcm_mulaw_open(snd_pcm_t **pcmp, char *name,
+ snd_config_t *conf,
+ int stream, int mode)
+{
+ snd_config_iterator_t i;
+ char *sname = NULL;
+ int err;
+ snd_pcm_t *spcm;
+ int sformat = -1;
+ snd_config_foreach(i, conf) {
+ snd_config_t *n = snd_config_entry(i);
+ if (strcmp(n->id, "comment") == 0)
+ continue;
+ if (strcmp(n->id, "type") == 0)
+ continue;
+ if (strcmp(n->id, "stream") == 0)
+ continue;
+ if (strcmp(n->id, "sname") == 0) {
+ err = snd_config_string_get(n, &sname);
+ if (err < 0)
+ return -EINVAL;
+ continue;
+ }
+ if (strcmp(n->id, "sformat") == 0) {
+ char *f;
+ err = snd_config_string_get(n, &f);
+ if (err < 0)
+ return -EINVAL;
+ sformat = snd_pcm_format_value(f);
+ if (sformat < 0)
+ return -EINVAL;
+ if (snd_pcm_format_linear(sformat) != 1 &&
+ sformat != SND_PCM_SFMT_MU_LAW)
+ return -EINVAL;
+ continue;
+ }
+ return -EINVAL;
+ }
+ if (!sname || !sformat)
+ return -EINVAL;
+ /* This is needed cause snd_config_update may destroy config */
+ sname = strdup(sname);
+ if (!sname)
+ return -ENOMEM;
+ err = snd_pcm_open(&spcm, sname, stream, mode);
+ free(sname);
+ if (err < 0)
+ return err;
+ err = snd_pcm_mulaw_open(pcmp, sformat, spcm, 1);
+ if (err < 0)
+ snd_pcm_close(spcm);
+ return err;
+}
+
+
diff --git a/src/pcm/pcm_multi.c b/src/pcm/pcm_multi.c
index 433e58f8..f697bd95 100644
--- a/src/pcm/pcm_multi.c
+++ b/src/pcm/pcm_multi.c
@@ -32,9 +32,6 @@ typedef struct {
snd_pcm_t *handle;
unsigned int channels_total;
int close_slave;
- char *buf;
- snd_pcm_channel_area_t *areas;
- struct iovec *iovec;
} snd_pcm_multi_slave_t;
typedef struct {
@@ -49,9 +46,7 @@ typedef struct {
size_t bindings_count;
snd_pcm_multi_bind_t *bindings;
size_t channels_count;
- size_t frames_alloc;
- int interleave;
- int one_to_many;
+ int xfer_mode, mmap_shape;
} snd_pcm_multi_t;
static int snd_pcm_multi_close(snd_pcm_t *pcm)
@@ -68,12 +63,6 @@ static int snd_pcm_multi_close(snd_pcm_t *pcm)
ret = err;
} else
snd_pcm_unlink(slave->handle);
- if (slave->buf) {
- free(slave->buf);
- free(slave->areas);
- }
- if (slave->iovec)
- free(slave->iovec);
}
free(multi->slaves);
free(multi->bindings);
@@ -91,23 +80,12 @@ static int snd_pcm_multi_nonblock(snd_pcm_t *pcm, int nonblock)
static int snd_pcm_multi_info(snd_pcm_t *pcm, snd_pcm_info_t *info)
{
snd_pcm_multi_t *multi = pcm->private;
- unsigned int i;
int err;
snd_pcm_t *handle_0 = multi->slaves[0].handle;
+ /* FIXME */
err = snd_pcm_info(handle_0, info);
if (err < 0)
return err;
- for (i = 1; i < multi->slaves_count; ++i) {
- snd_pcm_t *handle_i = multi->slaves[i].handle;
- snd_pcm_info_t info_i;
- memset(&info_i, 0, sizeof(info_i));
- err = snd_pcm_info(handle_i, &info_i);
- if (err < 0)
- return err;
- info->flags &= info_i.flags;
- }
- if (multi->one_to_many)
- info->flags &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
return 0;
}
@@ -118,7 +96,9 @@ static int snd_pcm_multi_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t *info
int err;
snd_pcm_t *handle_0 = multi->slaves[0].handle;
unsigned int old_mask = info->req_mask;
- info->req_mask &= ~SND_PCM_PARAMS_CHANNELS;
+ info->req_mask &= ~(SND_PCM_PARAMS_CHANNELS |
+ SND_PCM_PARAMS_MMAP_SHAPE |
+ SND_PCM_PARAMS_XFER_MODE);
err = snd_pcm_params_info(handle_0, info);
if (err < 0)
return err;
@@ -128,6 +108,8 @@ static int snd_pcm_multi_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t *info
snd_pcm_t *handle_i = multi->slaves[i].handle;
snd_pcm_params_info_t info_i;
info_i = *info;
+ info_i.req_mask |= SND_PCM_PARAMS_CHANNELS;
+ info_i.req.format.channels = multi->slaves[i].channels_total;
err = snd_pcm_params_info(handle_i, &info_i);
if (err < 0)
return err;
@@ -147,6 +129,7 @@ static int snd_pcm_multi_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t *info
info->min_fragments = info_i.min_fragments;
if (info_i.max_fragments < info->max_fragments)
info->max_fragments = info_i.max_fragments;
+ info->flags &= info_i.flags;
}
info->req_mask = old_mask;
return 0;
@@ -159,36 +142,39 @@ static int snd_pcm_multi_params(snd_pcm_t *pcm, snd_pcm_params_t *params)
snd_pcm_params_t p;
if (params->format.channels != multi->channels_count)
return -EINVAL;
+ multi->xfer_mode = params->xfer_mode;
+ multi->mmap_shape = params->mmap_shape;
p = *params;
- multi->interleave = params->format.interleave;
for (i = 0; i < multi->slaves_count; ++i) {
int err;
snd_pcm_t *handle = multi->slaves[i].handle;
- snd_pcm_info_t info;
- err = snd_pcm_info(handle, &info);
- if (err < 0)
- return err;
- p.format.interleave = params->format.interleave;
- if (!(info.flags & SND_PCM_INFO_INTERLEAVE))
- p.format.interleave = 0;
- else if (!(info.flags & SND_PCM_INFO_NONINTERLEAVE))
- p.format.interleave = 1;
+ if (handle->mmap_data) {
+ err = snd_pcm_munmap_data(handle);
+ if (err < 0)
+ return err;
+ }
+ p.xfer_mode = SND_PCM_XFER_UNSPECIFIED;
+ p.mmap_shape = SND_PCM_MMAP_UNSPECIFIED;
p.format.channels = multi->slaves[i].channels_total;
#if 1
p.xrun_max = ~0;
#endif
err = snd_pcm_params(handle, &p);
- if (err < 0)
+ if (err < 0) {
+ params->fail_mask = p.fail_mask;
+ params->fail_reason = p.fail_reason;
return err;
- if (i == 0 && params->mode == SND_PCM_MODE_FRAGMENT) {
- snd_pcm_setup_t s;
- err = snd_pcm_setup(handle, &s);
- if (err < 0)
- return err;
- p.frag_size = s.frag_size;
- p.buffer_size = s.buffer_size;
}
}
+ for (i = 0; i < multi->slaves_count; ++i) {
+ snd_pcm_t *handle = multi->slaves[i].handle;
+ int err = snd_pcm_mmap_data(handle, NULL);
+ if (err < 0)
+ return err;
+ if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
+ snd_pcm_areas_silence(handle->mmap_areas, 0, handle->setup.format.channels,
+ handle->setup.buffer_size, handle->setup.format.sfmt);
+ }
return 0;
}
@@ -202,7 +188,6 @@ static int snd_pcm_multi_setup(snd_pcm_t *pcm, snd_pcm_setup_t *setup)
if (err < 0)
return err;
frames_alloc = multi->slaves[0].handle->setup.frag_size;
- multi->frames_alloc = 0;
for (i = 1; i < multi->slaves_count; ++i) {
snd_pcm_setup_t s;
snd_pcm_t *sh = multi->slaves[i].handle;
@@ -211,53 +196,21 @@ static int snd_pcm_multi_setup(snd_pcm_t *pcm, snd_pcm_setup_t *setup)
return err;
if (setup->format.rate != s.format.rate)
return -EINVAL;
- if (setup->align % s.align != 0)
+ /* mmap is not feasible */
+ if (setup->buffer_size != s.buffer_size)
return -EINVAL;
+ if (setup->mmap_shape != SND_PCM_MMAP_NONINTERLEAVED ||
+ s.mmap_shape != SND_PCM_MMAP_NONINTERLEAVED)
+ setup->mmap_shape = SND_PCM_MMAP_COMPLEX;
}
- setup->format.interleave = multi->interleave;
setup->format.channels = multi->channels_count;
- for (i = 0; i < multi->slaves_count; ++i) {
- snd_pcm_multi_slave_t *s = &multi->slaves[i];
- snd_pcm_t *sh = s->handle;
- unsigned int c;
- if (s->buf) {
- free(s->buf);
- s->buf = 0;
- free(s->areas);
- s->areas = 0;
- }
- if (s->iovec)
- free(s->iovec);
- if (!sh->setup.format.interleave) {
- s->iovec = calloc(s->channels_total, sizeof(*s->iovec));
- if (!pcm->setup.format.interleave)
- continue;
- }
- s->buf = malloc(frames_alloc * sh->bits_per_frame / 8);
- if (!s->buf)
- return -ENOMEM;
- snd_pcm_format_set_silence(sh->setup.format.format, s->buf,
- sh->setup.frag_size * sh->setup.format.channels);
- s->areas = calloc(s->channels_total, sizeof(*s->areas));
- if (!s->areas)
- return -ENOMEM;
- for (c = 0; c < s->channels_total; ++c) {
- snd_pcm_channel_area_t *a = &s->areas[c];
- if (sh->setup.format.interleave) {
- a->addr = s->buf;
- a->first = c * sh->bits_per_sample;
- a->step = sh->bits_per_frame;
- } else {
- a->addr = s->buf + sh->setup.frag_size * sh->bits_per_sample / 8;
- a->first = 0;
- a->step = sh->bits_per_sample;
- s->iovec[c].iov_base = a->addr;
- }
- }
- }
- multi->frames_alloc = frames_alloc;
- /* Loaded with a value != 0 if mmap is feasible */
- setup->mmap_bytes = !multi->one_to_many;
+ if (multi->xfer_mode == SND_PCM_XFER_UNSPECIFIED)
+ setup->xfer_mode = SND_PCM_XFER_NONINTERLEAVED;
+ else
+ setup->xfer_mode = multi->xfer_mode;
+ if (multi->mmap_shape != SND_PCM_MMAP_UNSPECIFIED &&
+ multi->mmap_shape != setup->mmap_shape)
+ return -EINVAL;
return 0;
}
@@ -275,11 +228,18 @@ static int snd_pcm_multi_state(snd_pcm_t *pcm)
return snd_pcm_state(handle);
}
-static ssize_t snd_pcm_multi_hw_ptr(snd_pcm_t *pcm, int update)
+static int snd_pcm_multi_delay(snd_pcm_t *pcm, ssize_t *delayp)
{
snd_pcm_multi_t *multi = pcm->private;
snd_pcm_t *handle = multi->slaves[0].handle;
- return snd_pcm_hw_ptr(handle, update);
+ return snd_pcm_delay(handle, delayp);
+}
+
+static ssize_t snd_pcm_multi_avail_update(snd_pcm_t *pcm)
+{
+ snd_pcm_multi_t *multi = pcm->private;
+ snd_pcm_t *handle = multi->slaves[0].handle;
+ return snd_pcm_avail_update(handle);
}
static int snd_pcm_multi_prepare(snd_pcm_t *pcm)
@@ -288,16 +248,16 @@ static int snd_pcm_multi_prepare(snd_pcm_t *pcm)
return snd_pcm_prepare(multi->slaves[0].handle);
}
-static int snd_pcm_multi_go(snd_pcm_t *pcm)
+static int snd_pcm_multi_start(snd_pcm_t *pcm)
{
snd_pcm_multi_t *multi = pcm->private;
- return snd_pcm_go(multi->slaves[0].handle);
+ return snd_pcm_start(multi->slaves[0].handle);
}
-static int snd_pcm_multi_drain(snd_pcm_t *pcm)
+static int snd_pcm_multi_stop(snd_pcm_t *pcm)
{
snd_pcm_multi_t *multi = pcm->private;
- return snd_pcm_drain(multi->slaves[0].handle);
+ return snd_pcm_stop(multi->slaves[0].handle);
}
static int snd_pcm_multi_flush(snd_pcm_t *pcm)
@@ -394,206 +354,21 @@ static ssize_t snd_pcm_multi_appl_ptr(snd_pcm_t *pcm, off_t offset)
return newpos;
}
-static int snd_pcm_multi_write_copy(snd_pcm_t *pcm, const void *buf,
- size_t offset, size_t count)
-{
- snd_pcm_multi_t *multi = pcm->private;
- unsigned int i;
- snd_pcm_channel_area_t area;
- area.addr = (void *) buf + offset * pcm->bits_per_frame;
- area.step = pcm->bits_per_frame;
- for (i = 0; i < multi->bindings_count; ++i) {
- snd_pcm_multi_bind_t *bind = &multi->bindings[i];
- snd_pcm_multi_slave_t *slave = &multi->slaves[bind->slave];
- int err;
- assert(slave->buf);
- area.first = pcm->bits_per_sample * bind->client_channel;
- err = snd_pcm_area_copy(&area, 0, &slave->areas[bind->slave_channel], 0, count, pcm->setup.format.format);
- if (err < 0)
- return err;
- if (!slave->handle->setup.format.interleave) {
- struct iovec *vec = &slave->iovec[bind->slave_channel];
- vec->iov_len = count;
- }
- }
- return 0;
-}
-
-static int snd_pcm_multi_writev_copy(snd_pcm_t *pcm, const struct iovec *vec,
- size_t offset, size_t count)
-{
- snd_pcm_multi_t *multi = pcm->private;
- unsigned int i;
- snd_pcm_channel_area_t area;
- area.first = 0;
- area.step = pcm->bits_per_sample;
- for (i = 0; i < multi->bindings_count; ++i) {
- snd_pcm_multi_bind_t *bind = &multi->bindings[i];
- snd_pcm_multi_slave_t *slave = &multi->slaves[bind->slave];
- int err;
- area.addr = vec[bind->client_channel].iov_base +
- offset * pcm->bits_per_sample;
- if (slave->handle->setup.format.interleave) {
- assert(slave->buf);
- err = snd_pcm_area_copy(&area, 0, &slave->areas[bind->slave_channel], 0, count, pcm->setup.format.format);
- if (err < 0)
- return err;
- } else {
- struct iovec *vec = &slave->iovec[bind->slave_channel];
- vec->iov_base = area.addr;
- vec->iov_len = count;
- }
- }
- return 0;
-}
-
-static ssize_t snd_pcm_multi_write_io(snd_pcm_t *pcm, size_t count)
-{
- snd_pcm_multi_t *multi = pcm->private;
- unsigned int i;
- ssize_t frames = count;
- for (i = 0; i < multi->slaves_count; ++i) {
- snd_pcm_multi_slave_t *slave = &multi->slaves[i];
- snd_pcm_t *sh = slave->handle;
- if (sh->setup.format.interleave) {
- frames = snd_pcm_write(sh, slave->buf, frames);
- } else {
- int channels = sh->setup.format.channels;
- frames = snd_pcm_writev(sh, slave->iovec, channels);
- }
- if (frames <= 0)
- break;
- }
- return frames;
-}
-
-static ssize_t snd_pcm_multi_write(snd_pcm_t *pcm, snd_timestamp_t *timestamp ATTRIBUTE_UNUSED, const void *buf, size_t count)
-{
- snd_pcm_multi_t *multi = pcm->private;
- size_t result = 0;
- while (count > 0) {
- int err;
- ssize_t ret;
- size_t frames = count;
- if (frames > multi->frames_alloc)
- frames = multi->frames_alloc;
- err = snd_pcm_multi_write_copy(pcm, buf, result, frames);
- if (err < 0)
- return err;
- ret = snd_pcm_multi_write_io(pcm, frames);
- if (ret > 0)
- result += ret;
- if (ret != (ssize_t)frames) {
- if (result > 0)
- return result;
- return ret;
- }
- count -= ret;
- }
- return result;
-}
-
-static ssize_t snd_pcm_multi_writev1(snd_pcm_t *pcm, const struct iovec *vector, size_t count)
-{
- snd_pcm_multi_t *multi = pcm->private;
- size_t result = 0;
- while (count > 0) {
- int err;
- ssize_t ret;
- size_t frames = count;
- if (frames > multi->frames_alloc)
- frames = multi->frames_alloc;
- err = snd_pcm_multi_writev_copy(pcm, vector, result, frames);
- if (err < 0)
- return err;
- ret = snd_pcm_multi_write_io(pcm, frames);
- if (ret > 0)
- result += ret;
- if (ret != (ssize_t) frames) {
- if (result > 0)
- return result;
- return ret;
- }
- count -= ret;
- }
- return result;
-}
-
-static ssize_t snd_pcm_multi_writev(snd_pcm_t *pcm, snd_timestamp_t *timestamp ATTRIBUTE_UNUSED, const struct iovec *vector, unsigned long count)
-{
- unsigned int k, step;
- size_t result = 0;
- if (pcm->setup.format.interleave)
- step = 1;
- else
- step = pcm->setup.format.channels;
- for (k = 0; k < count; k += step) {
- ssize_t ret;
- if (pcm->setup.format.interleave)
- ret = snd_pcm_multi_write(pcm, timestamp, vector->iov_base, vector->iov_len);
- else
- ret = snd_pcm_multi_writev1(pcm, vector, vector->iov_len);
- if (ret > 0)
- result += ret;
- if (ret != (ssize_t) vector->iov_len) {
- if (result > 0)
- return result;
- return ret;
- }
- vector += step;
- }
- return result;
-}
-
-static ssize_t snd_pcm_multi_read(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_timestamp_t *timestamp ATTRIBUTE_UNUSED, void *buf ATTRIBUTE_UNUSED, size_t count ATTRIBUTE_UNUSED)
-{
- // snd_pcm_multi_t *multi = pcm->private;
- return -ENOSYS;
-}
-
-static ssize_t snd_pcm_multi_readv(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_timestamp_t *timestamp ATTRIBUTE_UNUSED, const struct iovec *vector ATTRIBUTE_UNUSED, unsigned long count ATTRIBUTE_UNUSED)
-{
- // snd_pcm_multi_t *multi = pcm->private;
- return -ENOSYS;
-}
-
-static int snd_pcm_multi_mmap_status(snd_pcm_t *pcm, snd_pcm_mmap_status_t **status)
+static int snd_pcm_multi_mmap_status(snd_pcm_t *pcm)
{
snd_pcm_multi_t *multi = pcm->private;
- unsigned int i;
- for (i = 0; i < multi->slaves_count; ++i) {
- snd_pcm_t *handle = multi->slaves[i].handle;
- int err = snd_pcm_mmap_status(handle, status);
- if (err < 0)
- return err;
- }
- *status = multi->slaves[0].handle->mmap_status;
+ pcm->mmap_status = multi->slaves[0].handle->mmap_status;
return 0;
}
-static int snd_pcm_multi_mmap_control(snd_pcm_t *pcm, snd_pcm_mmap_control_t **control)
+static int snd_pcm_multi_mmap_control(snd_pcm_t *pcm)
{
snd_pcm_multi_t *multi = pcm->private;
- snd_pcm_setup_t *setup_0 = &multi->slaves[0].handle->setup;
- unsigned int i;
- for (i = 1; i < multi->slaves_count; ++i) {
- snd_pcm_setup_t *setup = &multi->slaves[i].handle->setup;
- /* Don't permit mmap if appl_ptr's have
- different ranges */
- if (setup->buffer_size != setup_0->buffer_size)
- return -EBADFD;
- }
- for (i = 0; i < multi->slaves_count; ++i) {
- snd_pcm_t *handle = multi->slaves[i].handle;
- int err = snd_pcm_mmap_control(handle, control);
- if (err < 0)
- return err;
- }
- *control = multi->slaves[0].handle->mmap_control;
+ pcm->mmap_control = multi->slaves[0].handle->mmap_control;
return 0;
}
-static int snd_pcm_multi_mmap_data(snd_pcm_t *pcm, void **buffer, size_t bsize ATTRIBUTE_UNUSED)
+static int snd_pcm_multi_mmap_data(snd_pcm_t *pcm)
{
snd_pcm_multi_t *multi = pcm->private;
unsigned int i;
@@ -609,95 +384,97 @@ static int snd_pcm_multi_mmap_data(snd_pcm_t *pcm, void **buffer, size_t bsize A
err = snd_pcm_mmap_get_areas(handle, areas);
if (err < 0)
return err;
- err = snd_pcm_areas_silence(areas, 0, setup->format.channels, setup->buffer_size, setup->format.format);
+ err = snd_pcm_areas_silence(areas, 0, setup->format.channels, setup->buffer_size, setup->format.sfmt);
if (err < 0)
return err;
}
}
- *buffer = multi->slaves[0].handle->mmap_data;
+ pcm->mmap_data = multi->slaves[0].handle->mmap_data;
return 0;
}
-static int snd_pcm_multi_munmap_status(snd_pcm_t *pcm, snd_pcm_mmap_status_t *status ATTRIBUTE_UNUSED)
+static int snd_pcm_multi_munmap_status(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
{
- snd_pcm_multi_t *multi = pcm->private;
- unsigned int i;
- int ret = 0;
- for (i = 0; i < multi->slaves_count; ++i) {
- snd_pcm_t *handle = multi->slaves[i].handle;
- int err = snd_pcm_munmap_status(handle);
- if (err < 0)
- ret = err;
- }
- return ret;
+ return 0;
+}
+
+static int snd_pcm_multi_munmap_control(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
+{
+ return 0;
}
-static int snd_pcm_multi_munmap_control(snd_pcm_t *pcm, snd_pcm_mmap_control_t *control ATTRIBUTE_UNUSED)
+static int snd_pcm_multi_munmap_data(snd_pcm_t *pcm)
{
snd_pcm_multi_t *multi = pcm->private;
unsigned int i;
int ret = 0;
for (i = 0; i < multi->slaves_count; ++i) {
snd_pcm_t *handle = multi->slaves[i].handle;
- int err = snd_pcm_munmap_control(handle);
+ int err = snd_pcm_munmap_data(handle);
if (err < 0)
ret = err;
}
return ret;
}
-static int snd_pcm_multi_munmap_data(snd_pcm_t *pcm, void *buffer ATTRIBUTE_UNUSED, size_t size ATTRIBUTE_UNUSED)
+static ssize_t snd_pcm_multi_mmap_forward(snd_pcm_t *pcm, size_t size)
{
snd_pcm_multi_t *multi = pcm->private;
unsigned int i;
- int ret = 0;
+
for (i = 0; i < multi->slaves_count; ++i) {
snd_pcm_t *handle = multi->slaves[i].handle;
- int err = snd_pcm_munmap_data(handle);
- if (err < 0)
- ret = err;
+ ssize_t frames = snd_pcm_mmap_forward(handle, size);
+ if (frames < 0)
+ return frames;
+ if (i == 0) {
+ size = frames;
+ continue;
+ }
+ if ((size_t) frames != size)
+ return -EBADFD;
}
- return ret;
+ return size;
}
-
-static int snd_pcm_multi_channels_mask(snd_pcm_t *pcm, bitset_t *client_vmask)
+
+static int snd_pcm_multi_channels_mask(snd_pcm_t *pcm, bitset_t *cmask)
{
snd_pcm_multi_t *multi = pcm->private;
unsigned int i;
- bitset_t *vmasks[multi->slaves_count];
+ bitset_t *cmasks[multi->slaves_count];
int err;
for (i = 0; i < multi->slaves_count; ++i)
- vmasks[i] = bitset_alloc(multi->slaves[i].channels_total);
+ cmasks[i] = bitset_alloc(multi->slaves[i].channels_total);
for (i = 0; i < multi->bindings_count; ++i) {
snd_pcm_multi_bind_t *b = &multi->bindings[i];
- if (bitset_get(client_vmask, b->client_channel))
- bitset_set(vmasks[b->slave], b->slave_channel);
+ if (bitset_get(cmask, b->client_channel))
+ bitset_set(cmasks[b->slave], b->slave_channel);
}
for (i = 0; i < multi->slaves_count; ++i) {
snd_pcm_t *handle = multi->slaves[i].handle;
- err = snd_pcm_channels_mask(handle, vmasks[i]);
+ err = snd_pcm_channels_mask(handle, cmasks[i]);
if (err < 0) {
for (i = 0; i <= multi->slaves_count; ++i)
- free(vmasks[i]);
+ free(cmasks[i]);
return err;
}
}
- bitset_zero(client_vmask, pcm->setup.format.channels);
+ bitset_zero(cmask, pcm->setup.format.channels);
for (i = 0; i < multi->bindings_count; ++i) {
snd_pcm_multi_bind_t *b = &multi->bindings[i];
- if (bitset_get(vmasks[b->slave], b->slave_channel))
- bitset_set(client_vmask, b->client_channel);
+ if (bitset_get(cmasks[b->slave], b->slave_channel))
+ bitset_set(cmask, b->client_channel);
}
for (i = 0; i < multi->slaves_count; ++i)
- free(vmasks[i]);
+ free(cmasks[i]);
return 0;
}
-int snd_pcm_multi_file_descriptor(snd_pcm_t *pcm)
+int snd_pcm_multi_poll_descriptor(snd_pcm_t *pcm)
{
snd_pcm_multi_t *multi = pcm->private;
snd_pcm_t *handle = multi->slaves[0].handle;
- return snd_pcm_file_descriptor(handle);
+ return snd_pcm_poll_descriptor(handle);
}
static void snd_pcm_multi_dump(snd_pcm_t *pcm, FILE *fp)
@@ -728,35 +505,37 @@ struct snd_pcm_ops snd_pcm_multi_ops = {
params_info: snd_pcm_multi_params_info,
params: snd_pcm_multi_params,
setup: snd_pcm_multi_setup,
+ channel_info: snd_pcm_multi_channel_info,
+ channel_params: snd_pcm_multi_channel_params,
+ channel_setup: snd_pcm_multi_channel_setup,
dump: snd_pcm_multi_dump,
+ nonblock: snd_pcm_multi_nonblock,
+ mmap_status: snd_pcm_multi_mmap_status,
+ mmap_control: snd_pcm_multi_mmap_control,
+ mmap_data: snd_pcm_multi_mmap_data,
+ munmap_status: snd_pcm_multi_munmap_status,
+ munmap_control: snd_pcm_multi_munmap_control,
+ munmap_data: snd_pcm_multi_munmap_data,
};
struct snd_pcm_fast_ops snd_pcm_multi_fast_ops = {
- nonblock: snd_pcm_multi_nonblock,
- channel_info: snd_pcm_multi_channel_info,
- channel_params: snd_pcm_multi_channel_params,
- channel_setup: snd_pcm_multi_channel_setup,
status: snd_pcm_multi_status,
- hw_ptr: snd_pcm_multi_hw_ptr,
state: snd_pcm_multi_state,
+ delay: snd_pcm_multi_delay,
prepare: snd_pcm_multi_prepare,
- go: snd_pcm_multi_go,
- drain: snd_pcm_multi_drain,
+ start: snd_pcm_multi_start,
+ stop: snd_pcm_multi_stop,
flush: snd_pcm_multi_flush,
pause: snd_pcm_multi_pause,
- write: snd_pcm_multi_write,
- writev: snd_pcm_multi_writev,
- read: snd_pcm_multi_read,
- readv: snd_pcm_multi_readv,
+ writei: snd_pcm_mmap_writei,
+ writen: snd_pcm_mmap_writen,
+ readi: snd_pcm_mmap_readi,
+ readn: snd_pcm_mmap_readn,
appl_ptr: snd_pcm_multi_appl_ptr,
- mmap_status: snd_pcm_multi_mmap_status,
- mmap_control: snd_pcm_multi_mmap_control,
- mmap_data: snd_pcm_multi_mmap_data,
- munmap_status: snd_pcm_multi_munmap_status,
- munmap_control: snd_pcm_multi_munmap_control,
- munmap_data: snd_pcm_multi_munmap_data,
- file_descriptor: snd_pcm_multi_file_descriptor,
+ poll_descriptor: snd_pcm_multi_poll_descriptor,
channels_mask: snd_pcm_multi_channels_mask,
+ avail_update: snd_pcm_multi_avail_update,
+ mmap_forward: snd_pcm_multi_mmap_forward,
};
int snd_pcm_multi_create(snd_pcm_t **handlep, size_t slaves_count,
@@ -769,6 +548,7 @@ int snd_pcm_multi_create(snd_pcm_t **handlep, size_t slaves_count,
snd_pcm_multi_t *multi;
size_t channels = 0;
unsigned int i;
+ int err;
int stream;
char client_map[32] = { 0 };
char slave_map[32][32] = { { 0 } };
@@ -777,12 +557,8 @@ int snd_pcm_multi_create(snd_pcm_t **handlep, size_t slaves_count,
assert(slaves_count > 0 && slaves_handle && schannels_count);
assert(bindings_count > 0 && bindings_slave && bindings_cchannel && bindings_schannel);
- handle = calloc(1, sizeof(snd_pcm_t));
- if (!handle)
- return -ENOMEM;
multi = calloc(1, sizeof(snd_pcm_multi_t));
if (!multi) {
- free(handle);
return -ENOMEM;
}
@@ -808,21 +584,20 @@ int snd_pcm_multi_create(snd_pcm_t **handlep, size_t slaves_count,
bind->client_channel = bindings_cchannel[i];
bind->slave = bindings_slave[i];
bind->slave_channel = bindings_schannel[i];
- if (slave_map[bindings_slave[i]][bindings_schannel[i]]) {
- assert(stream == SND_PCM_STREAM_CAPTURE);
- multi->one_to_many = 1;
- }
+ assert(!slave_map[bindings_slave[i]][bindings_schannel[i]]);
slave_map[bindings_slave[i]][bindings_schannel[i]] = 1;
- if (client_map[bindings_cchannel[i]]) {
- assert(stream == SND_PCM_STREAM_PLAYBACK);
- multi->one_to_many = 1;
- }
+ assert(!client_map[bindings_cchannel[i]]);
client_map[bindings_cchannel[i]] = 1;
if (bindings_cchannel[i] >= channels)
channels = bindings_cchannel[i] + 1;
}
multi->channels_count = channels;
+ handle = calloc(1, sizeof(snd_pcm_t));
+ if (!handle) {
+ free(multi);
+ return -ENOMEM;
+ }
handle->type = SND_PCM_TYPE_MULTI;
handle->stream = stream;
handle->mode = multi->slaves[0].handle->mode;
@@ -831,6 +606,195 @@ int snd_pcm_multi_create(snd_pcm_t **handlep, size_t slaves_count,
handle->fast_ops = &snd_pcm_multi_fast_ops;
handle->fast_op_arg = handle;
handle->private = multi;
+ err = snd_pcm_init(handle);
+ if (err < 0) {
+ snd_pcm_close(handle);
+ return err;
+ }
*handlep = handle;
return 0;
}
+
+int _snd_pcm_multi_open(snd_pcm_t **pcmp, char *name, snd_config_t *conf,
+ int stream, int mode)
+{
+ snd_config_iterator_t i, j;
+ snd_config_t *slave = NULL;
+ snd_config_t *binding = NULL;
+ int err;
+ unsigned int idx;
+ char **slaves_id = NULL;
+ char **slaves_name = NULL;
+ snd_pcm_t **slaves_pcm = NULL;
+ size_t *slaves_channels = NULL;
+ unsigned int *bindings_cchannel = NULL;
+ unsigned int *bindings_slave = NULL;
+ unsigned int *bindings_schannel = NULL;
+ size_t slaves_count = 0;
+ size_t bindings_count = 0;
+ snd_config_foreach(i, conf) {
+ snd_config_t *n = snd_config_entry(i);
+ if (strcmp(n->id, "comment") == 0)
+ continue;
+ if (strcmp(n->id, "type") == 0)
+ continue;
+ if (strcmp(n->id, "stream") == 0)
+ continue;
+ if (strcmp(n->id, "slave") == 0) {
+ if (snd_config_type(n) != SND_CONFIG_TYPE_COMPOUND)
+ return -EINVAL;
+ slave = n;
+ continue;
+ }
+ if (strcmp(n->id, "binding") == 0) {
+ if (snd_config_type(n) != SND_CONFIG_TYPE_COMPOUND)
+ return -EINVAL;
+ binding = n;
+ continue;
+ }
+ return -EINVAL;
+ }
+ if (!slave || !binding)
+ return -EINVAL;
+ snd_config_foreach(i, slave) {
+ ++slaves_count;
+ }
+ snd_config_foreach(i, binding) {
+ ++bindings_count;
+ }
+ slaves_id = calloc(slaves_count, sizeof(*slaves_id));
+ slaves_name = calloc(slaves_count, sizeof(*slaves_name));
+ slaves_pcm = calloc(slaves_count, sizeof(*slaves_pcm));
+ slaves_channels = calloc(slaves_count, sizeof(*slaves_channels));
+ bindings_cchannel = calloc(bindings_count, sizeof(*bindings_cchannel));
+ bindings_slave = calloc(bindings_count, sizeof(*bindings_slave));
+ bindings_schannel = calloc(bindings_count, sizeof(*bindings_schannel));
+ idx = 0;
+ snd_config_foreach(i, slave) {
+ snd_config_t *m = snd_config_entry(i);
+ char *pcm = NULL;
+ long channels = -1;
+ slaves_id[idx] = snd_config_id(m);
+ snd_config_foreach(j, m) {
+ snd_config_t *n = snd_config_entry(j);
+ if (strcmp(n->id, "comment") == 0)
+ continue;
+ if (strcmp(n->id, "pcm") == 0) {
+ err = snd_config_string_get(n, &pcm);
+ if (err < 0)
+ goto _free;
+ continue;
+ }
+ if (strcmp(n->id, "channels") == 0) {
+ err = snd_config_integer_get(n, &channels);
+ if (err < 0)
+ goto _free;
+ continue;
+ }
+ err = -EINVAL;
+ goto _free;
+ }
+ if (!pcm || channels < 0) {
+ err = -EINVAL;
+ goto _free;
+ }
+ slaves_name[idx] = strdup(pcm);
+ slaves_channels[idx] = channels;
+ ++idx;
+ }
+
+ idx = 0;
+ snd_config_foreach(i, binding) {
+ snd_config_t *m = snd_config_entry(i);
+ long cchannel = -1, schannel = -1;
+ int slave = -1;
+ long val;
+ char *str;
+ snd_config_foreach(j, m) {
+ snd_config_t *n = snd_config_entry(j);
+ if (strcmp(n->id, "comment") == 0)
+ continue;
+ if (strcmp(n->id, "client_channel") == 0) {
+ err = snd_config_integer_get(n, &cchannel);
+ if (err < 0)
+ goto _free;
+ continue;
+ }
+ if (strcmp(n->id, "slave") == 0) {
+ char buf[32];
+ unsigned int k;
+ err = snd_config_string_get(n, &str);
+ if (err < 0) {
+ err = snd_config_integer_get(n, &val);
+ if (err < 0)
+ goto _free;
+ sprintf(buf, "%ld", val);
+ str = buf;
+ }
+ for (k = 0; k < slaves_count; ++k) {
+ if (strcmp(slaves_id[k], str) == 0)
+ slave = k;
+ }
+ continue;
+ }
+ if (strcmp(n->id, "slave_channel") == 0) {
+ err = snd_config_integer_get(n, &schannel);
+ if (err < 0)
+ goto _free;
+ continue;
+ }
+ err = -EINVAL;
+ goto _free;
+ }
+ if (cchannel < 0 || slave < 0 || schannel < 0) {
+ err = -EINVAL;
+ goto _free;
+ }
+ if ((size_t)slave >= slaves_count) {
+ err = -EINVAL;
+ goto _free;
+ }
+ if ((unsigned int) schannel >= slaves_channels[slave]) {
+ err = -EINVAL;
+ goto _free;
+ }
+ bindings_cchannel[idx] = cchannel;
+ bindings_slave[idx] = slave;
+ bindings_schannel[idx] = schannel;
+ ++idx;
+ }
+
+ for (idx = 0; idx < slaves_count; ++idx) {
+ err = snd_pcm_open(&slaves_pcm[idx], slaves_name[idx], stream, mode);
+ if (err < 0)
+ goto _free;
+ }
+ err = snd_pcm_multi_create(pcmp, slaves_count, slaves_pcm,
+ slaves_channels,
+ bindings_count, bindings_cchannel,
+ bindings_slave, bindings_schannel,
+ 1);
+_free:
+ if (err < 0) {
+ for (idx = 0; idx < slaves_count; ++idx) {
+ if (slaves_pcm[idx])
+ snd_pcm_close(slaves_pcm[idx]);
+ if (slaves_name[idx])
+ free(slaves_name[idx]);
+ }
+ }
+ if (slaves_name)
+ free(slaves_name);
+ if (slaves_pcm)
+ free(slaves_pcm);
+ if (slaves_channels)
+ free(slaves_channels);
+ if (bindings_cchannel)
+ free(bindings_cchannel);
+ if (bindings_slave)
+ free(bindings_slave);
+ if (bindings_schannel)
+ free(bindings_schannel);
+ return err;
+}
+
diff --git a/src/pcm/pcm_plug.c b/src/pcm/pcm_plug.c
index adb41aae..adf491fa 100644
--- a/src/pcm/pcm_plug.c
+++ b/src/pcm/pcm_plug.c
@@ -19,125 +19,168 @@
*
*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <math.h>
-#include <sys/uio.h>
-#include <limits.h>
#include "pcm_local.h"
+#include "pcm_plugin.h"
-/* snd_pcm_plugin externs */
-int snd_pcm_plugin_insert(snd_pcm_plugin_t *plugin)
-{
- snd_pcm_plug_t *plug;
- assert(plugin);
- plug = plugin->plug;
- plugin->next = plug->first;
- plugin->prev = NULL;
- if (plug->first) {
- plug->first->prev = plugin;
- plug->first = plugin;
- } else {
- plug->last =
- plug->first = plugin;
- }
- return 0;
-}
+typedef struct {
+ snd_pcm_t *req_slave;
+ int close_slave;
+ snd_pcm_t *slave;
+ ttable_entry_t *ttable;
+ unsigned int tt_ssize, tt_cused, tt_sused;
+} snd_pcm_plug_t;
+
+
+unsigned int snd_pcm_plug_formats(unsigned int formats)
+{
+ int fmts = (SND_PCM_LINEAR_FORMATS | SND_PCM_FMT_MU_LAW |
+ SND_PCM_FMT_A_LAW | SND_PCM_FMT_IMA_ADPCM);
+ if (formats & fmts)
+ formats |= fmts;
+ return formats;
+}
+
+static int preferred_formats[] = {
+ SND_PCM_SFMT_S16_LE,
+ SND_PCM_SFMT_S16_BE,
+ SND_PCM_SFMT_U16_LE,
+ SND_PCM_SFMT_U16_BE,
+ SND_PCM_SFMT_S24_LE,
+ SND_PCM_SFMT_S24_BE,
+ SND_PCM_SFMT_U24_LE,
+ SND_PCM_SFMT_U24_BE,
+ SND_PCM_SFMT_S32_LE,
+ SND_PCM_SFMT_S32_BE,
+ SND_PCM_SFMT_U32_LE,
+ SND_PCM_SFMT_U32_BE,
+ SND_PCM_SFMT_S8,
+ SND_PCM_SFMT_U8
+};
-int snd_pcm_plugin_append(snd_pcm_plugin_t *plugin)
+static int snd_pcm_plug_slave_fmt(int format,
+ snd_pcm_params_info_t *slave_info)
{
- snd_pcm_plug_t *plug;
- assert(plugin);
- plug = plugin->plug;
- plugin->next = NULL;
- plugin->prev = plug->last;
- if (plug->last) {
- plug->last->next = plugin;
- plug->last = plugin;
+ if ((snd_pcm_plug_formats(slave_info->formats) & (1 << format)) == 0)
+ return -EINVAL;
+ if (snd_pcm_format_linear(format)) {
+ int width = snd_pcm_format_width(format);
+ int unsignd = snd_pcm_format_unsigned(format);
+ int big = snd_pcm_format_big_endian(format);
+ int format1;
+ int wid, width1=width;
+ int dwidth1 = 8;
+ for (wid = 0; wid < 4; ++wid) {
+ int end, big1 = big;
+ for (end = 0; end < 2; ++end) {
+ int sgn, unsignd1 = unsignd;
+ for (sgn = 0; sgn < 2; ++sgn) {
+ format1 = snd_pcm_build_linear_format(width1, unsignd1, big1);
+ if (format1 >= 0 &&
+ slave_info->formats & (1 << format1))
+ goto _found;
+ unsignd1 = !unsignd1;
+ }
+ big1 = !big1;
+ }
+ if (width1 == 32) {
+ dwidth1 = -dwidth1;
+ width1 = width;
+ }
+ width1 += dwidth1;
+ }
+ return -EINVAL;
+ _found:
+ return format1;
} else {
- plug->last =
- plug->first = plugin;
- }
- return 0;
-}
-
-void snd_pcm_plugin_dump(snd_pcm_plugin_t *plugin, FILE *fp)
-{
- fprintf(fp, "----------- %s\n", plugin->name);
- fprintf(fp, "Buffer: %ld frames\n", (long)plugin->buf_frames);
- if (plugin->src_format.interleave != plugin->dst_format.interleave) {
- if (plugin->src_format.interleave)
- fprintf(fp, "Interleaved -> Non interleaved\n");
- else
- fprintf(fp, "Non interleaved -> Interleaved\n");
- }
- if (plugin->src_format.channels != plugin->dst_format.channels) {
- fprintf(fp, "Channels: %d -> %d\n",
- plugin->src_format.channels,
- plugin->dst_format.channels);
- }
- if (plugin->src_format.format != plugin->dst_format.format) {
- fprintf(fp, "Format: %s -> %s\n",
- snd_pcm_format_name(plugin->src_format.format),
- snd_pcm_format_name(plugin->dst_format.format));
- }
- if (plugin->src_format.rate != plugin->dst_format.rate) {
- fprintf(fp, "Rate: %d -> %d\n",
- plugin->src_format.rate,
- plugin->dst_format.rate);
+ unsigned int i;
+ switch (format) {
+ case SND_PCM_SFMT_MU_LAW:
+ case SND_PCM_SFMT_A_LAW:
+ case SND_PCM_SFMT_IMA_ADPCM:
+ for (i = 0; i < sizeof(preferred_formats) / sizeof(preferred_formats[0]); ++i) {
+ int format1 = preferred_formats[i];
+ if (slave_info->formats & (1 << format1))
+ return format1;
+ }
+ default:
+ return -EINVAL;
+ }
}
- if (plugin->dump)
- plugin->dump(plugin, fp);
}
-/* snd_pcm_plug externs */
+struct {
+ unsigned int rate;
+ unsigned int flag;
+} snd_pcm_rates[] = {
+ { 8000, SND_PCM_RATE_8000 },
+ { 11025, SND_PCM_RATE_11025 },
+ { 16000, SND_PCM_RATE_16000 },
+ { 22050, SND_PCM_RATE_22050 },
+ { 32000, SND_PCM_RATE_32000 },
+ { 44100, SND_PCM_RATE_44100 },
+ { 48000, SND_PCM_RATE_48000 },
+ { 88200, SND_PCM_RATE_88200 },
+ { 96000, SND_PCM_RATE_96000 },
+ { 176400, SND_PCM_RATE_176400 },
+ { 192000, SND_PCM_RATE_192000 }
+};
-int snd_pcm_plug_clear(snd_pcm_plug_t *plug)
-{
- snd_pcm_plugin_t *plugin, *plugin_next;
-
- assert(plug);
-
- plugin = plug->first;
- plug->first = NULL;
- plug->last = NULL;
- while (plugin) {
- plugin_next = plugin->next;
- snd_pcm_plugin_free(plugin);
- plugin = plugin_next;
+static int snd_pcm_plug_slave_rate(unsigned int rate,
+ snd_pcm_params_info_t *slave_info)
+{
+ if (rate <= slave_info->min_rate)
+ return slave_info->min_rate;
+ else if (rate >= slave_info->max_rate)
+ return slave_info->max_rate;
+ else if (!(slave_info->rates & (SND_PCM_RATE_CONTINUOUS |
+ SND_PCM_RATE_KNOT))) {
+ unsigned int k;
+ unsigned int rate1 = 0, rate2 = 0;
+ int delta1, delta2;
+ for (k = 0; k < sizeof(snd_pcm_rates) /
+ sizeof(snd_pcm_rates[0]); ++k) {
+ if (!(snd_pcm_rates[k].flag & slave_info->rates))
+ continue;
+ if (snd_pcm_rates[k].rate < rate) {
+ rate1 = snd_pcm_rates[k].rate;
+ } else if (snd_pcm_rates[k].rate >= rate) {
+ rate2 = snd_pcm_rates[k].rate;
+ break;
+ }
+ }
+ if (rate1 == 0)
+ return rate2;
+ if (rate2 == 0)
+ return rate1;
+ delta1 = rate - rate1;
+ delta2 = rate2 - rate;
+ if (delta1 < delta2)
+ return rate1;
+ else
+ return rate2;
}
- return 0;
+ return rate;
}
-snd_pcm_plugin_t *snd_pcm_plug_first(snd_pcm_plug_t *plug)
-{
- assert(plug);
- return plug->first;
-}
-
-snd_pcm_plugin_t *snd_pcm_plug_last(snd_pcm_plug_t *plug)
-{
- assert(plug);
- return plug->last;
-}
-
-/*
- *
- */
-
static int snd_pcm_plug_close(snd_pcm_t *pcm)
{
snd_pcm_plug_t *plug = pcm->private;
- snd_pcm_plug_clear(plug);
- free(plug->handle->fast_ops);
- if (plug->close_slave)
- return snd_pcm_close(plug->slave);
+ int err, result = 0;
+ if (plug->ttable)
+ free(plug->ttable);
+ if (plug->slave != plug->req_slave) {
+ err = snd_pcm_close(plug->slave);
+ if (err < 0)
+ result = err;
+ }
+ if (plug->close_slave) {
+ err = snd_pcm_close(plug->req_slave);
+ if (err < 0)
+ result = err;
+ }
free(plug);
- return 0;
+ return result;
}
static int snd_pcm_plug_nonblock(snd_pcm_t *pcm, int nonblock)
@@ -148,13 +191,12 @@ static int snd_pcm_plug_nonblock(snd_pcm_t *pcm, int nonblock)
static int snd_pcm_plug_info(snd_pcm_t *pcm, snd_pcm_info_t *info)
{
- int err;
snd_pcm_plug_t *plug = pcm->private;
+ snd_pcm_t *slave = plug->req_slave;
+ int err;
- if ((err = snd_pcm_info(plug->slave, info)) < 0)
+ if ((err = snd_pcm_info(slave, info)) < 0)
return err;
- info->flags &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
- info->flags |= SND_PCM_INFO_INTERLEAVE | SND_PCM_INFO_NONINTERLEAVE;
return 0;
}
@@ -162,12 +204,12 @@ static int snd_pcm_plug_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t *info)
{
int err;
snd_pcm_plug_t *plug = pcm->private;
+ snd_pcm_t *slave = plug->req_slave;
snd_pcm_params_info_t slave_info;
- int rate;
- int slave_format, slave_rate;
- unsigned int slave_channels;
+ int sformat, srate;
+ unsigned int schannels;
+ int crate;
- memset(&info->formats, 0, (char*)(info + 1) - (char*) &info->formats);
info->req.fail_reason = 0;
info->req.fail_mask = 0;
@@ -178,8 +220,8 @@ static int snd_pcm_plug_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t *info)
info->min_rate = 4000;
info->max_rate = 192000;
}
- /* ??? */
info->rates = SND_PCM_RATE_CONTINUOUS | SND_PCM_RATE_8000_192000;
+
if (info->req_mask & SND_PCM_PARAMS_CHANNELS) {
info->min_channels = info->req.format.channels;
info->max_channels = info->req.format.channels;
@@ -189,30 +231,34 @@ static int snd_pcm_plug_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t *info)
}
memset(&slave_info, 0, sizeof(slave_info));
- if ((err = snd_pcm_params_info(plug->slave, &slave_info)) < 0)
+ if ((err = snd_pcm_params_info(slave, &slave_info)) < 0)
return err;
- if (info->req_mask & SND_PCM_PARAMS_FORMAT)
- info->formats = 1 << info->req.format.format;
- else
- info->formats = snd_pcm_plug_formats(slave_info.formats);
+ info->flags = slave_info.flags;
+ info->flags |= SND_PCM_INFO_INTERLEAVED | SND_PCM_INFO_NONINTERLEAVED;
info->min_fragments = slave_info.min_fragments;
info->max_fragments = slave_info.max_fragments;
- if (!(info->req_mask & SND_PCM_PARAMS_FORMAT))
+ if (info->req_mask & SND_PCM_PARAMS_SFMT)
+ info->formats = 1 << info->req.format.sfmt;
+ else {
+ info->formats = snd_pcm_plug_formats(slave_info.formats);
return 0;
- slave_format = snd_pcm_plug_slave_fmt(info->req.format.format, &slave_info);
- if (slave_format < 0) {
- info->req.fail_mask = SND_PCM_PARAMS_FORMAT;
+ }
+
+ sformat = snd_pcm_plug_slave_fmt(info->req.format.sfmt, &slave_info);
+ if (sformat < 0) {
+ info->req.fail_mask = SND_PCM_PARAMS_SFMT;
info->req.fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
return -EINVAL;
}
if (!(info->req_mask & SND_PCM_PARAMS_RATE))
return 0;
- slave_rate = snd_pcm_plug_slave_rate(info->req.format.rate, &slave_info);
- if (slave_rate < 0) {
+ crate = info->req.format.rate;
+ srate = snd_pcm_plug_slave_rate(crate, &slave_info);
+ if (srate < 0) {
info->req.fail_mask = SND_PCM_PARAMS_RATE;
info->req.fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
return -EINVAL;
@@ -220,619 +266,418 @@ static int snd_pcm_plug_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t *info)
if (!(info->req_mask & SND_PCM_PARAMS_CHANNELS))
return 0;
- slave_channels = info->req.format.rate;
- if (slave_channels < info->min_channels)
- slave_channels = info->min_channels;
- else if (slave_channels > info->max_channels)
- slave_channels = info->max_channels;
+ schannels = info->req.format.channels;
+ if (schannels < info->min_channels)
+ schannels = info->min_channels;
+ else if (schannels > info->max_channels)
+ schannels = info->max_channels;
- slave_info.req_mask = (SND_PCM_PARAMS_FORMAT |
+ slave_info.req_mask = (SND_PCM_PARAMS_SFMT |
SND_PCM_PARAMS_CHANNELS |
SND_PCM_PARAMS_RATE);
- slave_info.req.format.format = info->req.format.format;
- slave_info.req.format.channels = info->req.format.channels;
- slave_info.req.format.rate = info->req.format.rate;
- if ((err = snd_pcm_params_info(plug->slave, &slave_info)) < 0) {
+ slave_info.req.format.sfmt = sformat;
+ slave_info.req.format.channels = schannels;
+ slave_info.req.format.rate = srate;
+ if ((err = snd_pcm_params_info(slave, &slave_info)) < 0) {
info->req.fail_mask = slave_info.req.fail_mask;
info->req.fail_reason = slave_info.req.fail_reason;
return err;
}
- rate = info->req.format.rate;
- info->buffer_size = slave_info.buffer_size * rate / slave_rate;
- info->min_fragment_size = slave_info.min_fragment_size * rate / slave_rate;
- info->max_fragment_size = slave_info.max_fragment_size * rate / slave_rate;
- info->fragment_align = slave_info.fragment_align * rate / slave_rate;
+ info->buffer_size = muldiv64(slave_info.buffer_size, crate, srate);
+ info->min_fragment_size = muldiv64(slave_info.min_fragment_size, crate, srate);
+ info->max_fragment_size = muldiv64(slave_info.max_fragment_size, crate, srate);
+ info->fragment_align = muldiv64(slave_info.fragment_align, crate, srate);
+ if (sformat != info->req.format.sfmt ||
+ (unsigned int) srate != info->req.format.rate ||
+ schannels != info->req.format.channels)
+ info->flags &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
return 0;
}
-static int snd_pcm_plug_action(snd_pcm_plug_t *plug, int action,
- unsigned long data)
+static void snd_pcm_plug_clear(snd_pcm_t *pcm)
{
- int err;
- snd_pcm_plugin_t *plugin = plug->first;
- while (plugin) {
- if (plugin->action) {
- if ((err = plugin->action(plugin, action, data))<0)
- return err;
- }
- plugin = plugin->next;
+ snd_pcm_plug_t *plug = pcm->private;
+ snd_pcm_t *slave = plug->req_slave;
+ /* Clear old plugins */
+ if (plug->slave != slave) {
+ snd_pcm_close(plug->slave);
+ plug->slave = slave;
+ pcm->fast_ops = slave->fast_ops;
+ pcm->fast_op_arg = slave->fast_op_arg;
}
- return 0;
}
-static int snd_pcm_plug_setup(snd_pcm_t *pcm, snd_pcm_setup_t *setup)
+static int snd_pcm_plug_change_rate(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_format_t *clt, snd_pcm_format_t *slv)
{
- int err;
snd_pcm_plug_t *plug = pcm->private;
-
- err = snd_pcm_setup(plug->slave, setup);
- if (err < 0)
- return err;
- if (!plug->first)
+ int err;
+ assert(snd_pcm_format_linear(slv->sfmt));
+ if (clt->rate == slv->rate)
return 0;
- setup->boundary /= setup->frag_size;
- setup->frag_size = snd_pcm_plug_client_size(plug, setup->frag_size);
- setup->boundary *= setup->frag_size;
- setup->buffer_size = setup->frags * setup->frag_size;
- setup->avail_min = snd_pcm_plug_client_size(plug, setup->avail_min);
- setup->align = snd_pcm_plug_client_size(plug, setup->align);
- setup->xrun_max = snd_pcm_plug_client_size(plug, setup->xrun_max);
- setup->fill_max = snd_pcm_plug_client_size(plug, setup->fill_max);
- setup->mmap_bytes = 0;
- if (plug->handle->stream == SND_PCM_STREAM_PLAYBACK)
- setup->format = plug->first->src_format;
- else
- setup->format = plug->last->dst_format;
- /* FIXME: this is not exact */
- setup->rate_master = setup->format.rate;
- setup->rate_divisor = 1;
- err = snd_pcm_plug_alloc(plug, setup->frag_size);
+ err = snd_pcm_rate_open(new, slv->sfmt, slv->rate, plug->slave, plug->slave != plug->req_slave);
if (err < 0)
return err;
- return 0;
+ slv->rate = clt->rate;
+ if (snd_pcm_format_linear(clt->sfmt))
+ slv->sfmt = clt->sfmt;
+ return 1;
}
-static int snd_pcm_plug_status(snd_pcm_t *pcm, snd_pcm_status_t *status)
+static int snd_pcm_plug_change_channels(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_format_t *clt, snd_pcm_format_t *slv)
{
- int err;
snd_pcm_plug_t *plug = pcm->private;
-
- err = snd_pcm_status(plug->slave, status);
+ unsigned int tt_ssize, tt_cused, tt_sused;
+ ttable_entry_t *ttable;
+ int err;
+ assert(snd_pcm_format_linear(slv->sfmt));
+ if (clt->channels == slv->channels)
+ return 0;
+ if (clt->rate != slv->rate &&
+ clt->channels > slv->channels)
+ return 0;
+
+ ttable = plug->ttable;
+ if (ttable) {
+ tt_ssize = plug->tt_ssize;
+ tt_cused = plug->tt_cused;
+ tt_sused = plug->tt_sused;
+ } else {
+ unsigned int k;
+ unsigned int c = 0, s = 0;
+ int n;
+ tt_ssize = slv->channels;
+ tt_cused = clt->channels;
+ tt_sused = slv->channels;
+ ttable = alloca(tt_cused * tt_sused * sizeof(*ttable));
+ for (k = 0; k < tt_cused * tt_sused; ++k)
+ ttable[k] = 0;
+ if (clt->channels > slv->channels) {
+ n = clt->channels;
+ } else {
+ n = slv->channels;
+ }
+ while (n-- > 0) {
+ ttable_entry_t v = FULL;
+ if (pcm->stream == SND_PCM_STREAM_PLAYBACK &&
+ clt->channels > slv->channels) {
+ int srcs = clt->channels / slv->channels;
+ if (s < clt->channels % slv->channels)
+ srcs++;
+ v /= srcs;
+ } else if (pcm->stream == SND_PCM_STREAM_CAPTURE &&
+ slv->channels > clt->channels) {
+ int srcs = slv->channels / clt->channels;
+ if (s < slv->channels % clt->channels)
+ srcs++;
+ v /= srcs;
+ }
+ ttable[c * tt_ssize + s] = v;
+ if (++c == clt->channels)
+ c = 0;
+ if (++s == slv->channels)
+ s = 0;
+ }
+ }
+ err = snd_pcm_route_open(new, slv->sfmt, slv->channels, ttable, tt_ssize, tt_cused, tt_sused, plug->slave, plug->slave != plug->req_slave);
if (err < 0)
return err;
-
- status->hw_ptr = snd_pcm_plug_client_size(plug, status->hw_ptr);
- status->appl_ptr = snd_pcm_plug_client_size(plug, status->appl_ptr);
- status->avail = snd_pcm_plug_client_size(plug, status->avail);
- status->avail_max = snd_pcm_plug_client_size(plug, status->avail_max);
- return 0;
-}
-
-static int snd_pcm_plug_state(snd_pcm_t *pcm)
-{
- snd_pcm_plug_t *plug = pcm->private;
- return snd_pcm_state(plug->slave);
+ slv->channels = clt->channels;
+ if (snd_pcm_format_linear(clt->sfmt))
+ slv->sfmt = clt->sfmt;
+ return 1;
}
-static ssize_t snd_pcm_plug_hw_ptr(snd_pcm_t *pcm, int update)
+static int snd_pcm_plug_change_format(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_format_t *clt, snd_pcm_format_t *slv)
{
snd_pcm_plug_t *plug = pcm->private;
- ssize_t hw_ptr = snd_pcm_hw_ptr(plug->slave, update);
- if (hw_ptr < 0)
- return hw_ptr;
- return snd_pcm_plug_client_size(plug, hw_ptr);
-}
-
-static int snd_pcm_plug_prepare(snd_pcm_t *pcm)
-{
- snd_pcm_plug_t *plug = pcm->private;
- int err;
- err = snd_pcm_prepare(plug->slave);
+ int err, cfmt;
+ int (*f)(snd_pcm_t **handle, int sformat, snd_pcm_t *slave, int close_slave);
+ if (snd_pcm_format_linear(slv->sfmt)) {
+ /* Conversion is done in another plugin */
+ if (clt->sfmt == slv->sfmt ||
+ clt->rate != slv->rate ||
+ clt->channels != slv->channels)
+ return 0;
+ } else {
+ /* No conversion is needed */
+ if (clt->sfmt == slv->sfmt &&
+ clt->rate == slv->rate &&
+ clt->channels == clt->channels)
+ return 0;
+ }
+ if (snd_pcm_format_linear(slv->sfmt)) {
+ cfmt = clt->sfmt;
+ switch (clt->sfmt) {
+ case SND_PCM_SFMT_MU_LAW:
+ f = snd_pcm_mulaw_open;
+ break;
+ case SND_PCM_SFMT_A_LAW:
+ f = snd_pcm_alaw_open;
+ break;
+ case SND_PCM_SFMT_IMA_ADPCM:
+ f = snd_pcm_adpcm_open;
+ break;
+ default:
+ assert(snd_pcm_format_linear(clt->sfmt));
+ f = snd_pcm_linear_open;
+ break;
+ }
+ } else {
+ switch (slv->sfmt) {
+ case SND_PCM_SFMT_MU_LAW:
+ f = snd_pcm_mulaw_open;
+ break;
+ case SND_PCM_SFMT_A_LAW:
+ f = snd_pcm_alaw_open;
+ break;
+ case SND_PCM_SFMT_IMA_ADPCM:
+ f = snd_pcm_adpcm_open;
+ break;
+ default:
+ assert(0);
+ return -EINVAL;
+ }
+ if (snd_pcm_format_linear(clt->sfmt))
+ cfmt = clt->sfmt;
+ else
+ cfmt = SND_PCM_SFMT_S16;
+ }
+ err = f(new, slv->sfmt, plug->slave, plug->slave != plug->req_slave);
if (err < 0)
return err;
- if ((err = snd_pcm_plug_action(plug, PREPARE, 0))<0)
- return err;
- return 0;
+ slv->sfmt = cfmt;
+ return 1;
}
-static int snd_pcm_plug_go(snd_pcm_t *pcm)
+static int snd_pcm_plug_insert_plugins(snd_pcm_t *pcm,
+ snd_pcm_format_t *client_fmt,
+ snd_pcm_format_t *slave_fmt)
{
snd_pcm_plug_t *plug = pcm->private;
- return snd_pcm_go(plug->slave);
+ int (*funcs[])(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_format_t *s, snd_pcm_format_t *d) = {
+ snd_pcm_plug_change_format,
+ snd_pcm_plug_change_channels,
+ snd_pcm_plug_change_rate,
+ snd_pcm_plug_change_channels,
+ snd_pcm_plug_change_format
+ };
+ snd_pcm_format_t sfmt = *slave_fmt;
+ unsigned int k = 0;
+ while (1) {
+ snd_pcm_t *new;
+ int err;
+ if (client_fmt->sfmt == sfmt.sfmt &&
+ client_fmt->channels == sfmt.channels &&
+ client_fmt->rate == sfmt.rate)
+ return 0;
+ assert(k < sizeof(funcs)/sizeof(*funcs));
+ err = funcs[k](pcm, &new, client_fmt, &sfmt);
+ if (err < 0) {
+ snd_pcm_plug_clear(pcm);
+ return err;
+ }
+ if (err) {
+ plug->slave = new;
+ pcm->fast_ops = new->fast_ops;
+ pcm->fast_op_arg = new->fast_op_arg;
+ }
+ k++;
+ }
+ assert(0);
+ return 0;
}
-static int snd_pcm_plug_drain(snd_pcm_t *pcm)
+static int snd_pcm_plug_params(snd_pcm_t *pcm, snd_pcm_params_t *params)
{
snd_pcm_plug_t *plug = pcm->private;
+ snd_pcm_t *slave = plug->req_slave;
+ snd_pcm_format_t *slave_format, *format;
+ snd_pcm_params_info_t slave_info;
+ int srate;
int err;
-
- if ((err = snd_pcm_drain(plug->slave)) < 0)
- return err;
- if ((err = snd_pcm_plug_action(plug, DRAIN, 0))<0)
+
+ memset(&slave_info, 0, sizeof(slave_info));
+ err = snd_pcm_params_info(slave, &slave_info);
+ if (err < 0)
return err;
- return 0;
-}
-static int snd_pcm_plug_flush(snd_pcm_t *pcm)
-{
- snd_pcm_plug_t *plug = pcm->private;
- int err;
+ slave_info.req = *params;
+ format = &params->format;
+ slave_format = &slave_info.req.format;
- if ((err = snd_pcm_flush(plug->slave)) < 0)
- return err;
- if ((err = snd_pcm_plug_action(plug, FLUSH, 0))<0)
- return err;
- return 0;
-}
+ if ((slave_info.formats & (1 << format->sfmt)) == 0) {
+ int slave_fmt = snd_pcm_plug_slave_fmt(format->sfmt, &slave_info);
+ if (slave_fmt < 0) {
+ params->fail_mask = SND_PCM_PARAMS_SFMT;
+ params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
+ return slave_fmt;
+ }
+ slave_format->sfmt = slave_fmt;
+ }
-static int snd_pcm_plug_pause(snd_pcm_t *pcm, int enable)
-{
- snd_pcm_plug_t *plug = pcm->private;
- int err;
-
- if ((err = snd_pcm_pause(plug->slave, enable)) < 0)
- return err;
- if ((err = snd_pcm_plug_action(plug, PAUSE, 0))<0)
+ if (format->channels < slave_info.min_channels)
+ slave_format->channels = slave_info.min_channels;
+ else if (format->channels > slave_info.max_channels)
+ slave_format->channels = slave_info.max_channels;
+
+ srate = snd_pcm_plug_slave_rate(format->rate, &slave_info);
+ if (srate < 0) {
+ params->fail_mask = SND_PCM_PARAMS_RATE;
+ params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
+ return srate;
+ }
+ slave_format->rate = srate;
+
+ slave_info.req_mask = ~0;
+ err = snd_pcm_params_info(slave, &slave_info);
+ if (err < 0) {
+ params->fail_mask = slave_info.req.fail_mask;
+ params->fail_reason = slave_info.req.fail_reason;
return err;
- return 0;
-}
+ }
-static int snd_pcm_plug_channel_info(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_channel_info_t *info ATTRIBUTE_UNUSED)
-{
- /* FIXME: if route plugin is not inserted or its ttable is trivial
- this should be implemented */
- return -ENOSYS;
-}
+ if (slave_format->rate - slave_info.min_rate < slave_info.max_rate - slave_format->rate)
+ slave_format->rate = slave_info.min_rate;
+ else
+ slave_format->rate = slave_info.max_rate;
-static int snd_pcm_plug_channel_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_channel_params_t *params ATTRIBUTE_UNUSED)
-{
- /* FIXME: if route plugin is not inserted or its ttable is trivial
- this should be implemented */
- return -ENOSYS;
-}
+ err = snd_pcm_plug_insert_plugins(pcm, format, slave_format);
+ if (err < 0)
+ return err;
+ slave = plug->slave;
-static int snd_pcm_plug_channel_setup(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_channel_setup_t *setup ATTRIBUTE_UNUSED)
-{
- /* FIXME: if route plugin is not inserted or its ttable is trivial
- this should be implemented for non mmap setups */
- return -ENOSYS;
+ err = snd_pcm_params(slave, params);
+ if (err < 0)
+ snd_pcm_plug_clear(pcm);
+ return err;
}
-static ssize_t snd_pcm_plug_appl_ptr(snd_pcm_t *pcm, off_t offset)
+static int snd_pcm_plug_setup(snd_pcm_t *pcm, snd_pcm_setup_t *setup)
{
- ssize_t ret;
snd_pcm_plug_t *plug = pcm->private;
- if (offset < 0) {
- offset = snd_pcm_plug_slave_size(plug, -offset);
- if (offset < 0)
- return offset;
- offset = -offset;
- } else {
- offset = snd_pcm_plug_slave_size(plug, offset);
- if (offset < 0)
- return offset;
- }
- ret = snd_pcm_appl_ptr(plug->slave, offset);
- if (ret < 0)
- return ret;
- return snd_pcm_plug_client_size(plug, ret);
-}
-
-ssize_t snd_pcm_plug_writev(snd_pcm_t *pcm, snd_timestamp_t *tstamp ATTRIBUTE_UNUSED, const struct iovec *vector, unsigned long count)
-{
- snd_pcm_plug_t *plug = pcm->private;
- snd_pcm_t *handle = plug->handle;
- unsigned int k, step;
- size_t result = 0;
- assert(plug->frames_alloc);
- if (handle->setup.format.interleave)
- step = 1;
- else
- step = handle->setup.format.channels;
- for (k = 0; k < count; k += step) {
- snd_pcm_plugin_channel_t *channels;
- ssize_t frames;
- frames = snd_pcm_plug_client_channels_iovec(plug, vector, step, &channels);
- if (frames < 0) {
- if (result > 0)
- return result;
- return frames;
- }
- while (1) {
- unsigned int c;
- ssize_t ret;
- size_t frames1 = frames;
- if (frames1 > plug->frames_alloc)
- frames1 = plug->frames_alloc;
- ret = snd_pcm_plug_write_transfer(plug, channels, frames1);
- if (ret < 0) {
- if (result > 0)
- return result;
- return ret;
- }
- result += ret;
- frames -= ret;
- if (frames == 0)
- break;
- for (c = 0; c < handle->setup.format.channels; ++c)
- channels[c].area.addr += ret * channels[c].area.step / 8;
- }
- vector += step;
- }
- return result;
+ return snd_pcm_setup(plug->slave, setup);
}
-ssize_t snd_pcm_plug_readv(snd_pcm_t *pcm, snd_timestamp_t *tstamp ATTRIBUTE_UNUSED, const struct iovec *vector, unsigned long count)
+static int snd_pcm_plug_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info)
{
snd_pcm_plug_t *plug = pcm->private;
- snd_pcm_t *handle = plug->handle;
- unsigned int k, step;
- size_t result = 0;
- assert(plug->frames_alloc);
- if (handle->setup.format.interleave)
- step = 1;
- else
- step = handle->setup.format.channels;
- for (k = 0; k < count; k += step) {
- snd_pcm_plugin_channel_t *channels;
- ssize_t frames;
- frames = snd_pcm_plug_client_channels_iovec(plug, vector, step, &channels);
- if (frames < 0) {
- if (result > 0)
- return result;
- return frames;
- }
- while (1) {
- unsigned int c;
- ssize_t ret;
- size_t frames1 = frames;
- if (frames1 > plug->frames_alloc)
- frames1 = plug->frames_alloc;
- ret = snd_pcm_plug_read_transfer(plug, channels, frames1);
- if (ret < 0) {
- if (result > 0)
- return result;
- return ret;
- }
- result += ret;
- frames -= ret;
- if (frames == 0)
- break;
- for (c = 0; c < handle->setup.format.channels; ++c)
- channels[c].area.addr += ret * channels[c].area.step / 8;
- }
- vector += step;
- }
- return result;
+ return snd_pcm_channel_info(plug->slave, info);
}
-ssize_t snd_pcm_plug_write(snd_pcm_t *pcm, snd_timestamp_t *tstamp ATTRIBUTE_UNUSED, const void *buf, size_t count)
+static int snd_pcm_plug_channel_params(snd_pcm_t *pcm, snd_pcm_channel_params_t *params)
{
snd_pcm_plug_t *plug = pcm->private;
- snd_pcm_t *handle = plug->handle;
- ssize_t frames;
- snd_pcm_plugin_channel_t *channels;
- size_t size = 0;
- assert(plug->frames_alloc);
- frames = snd_pcm_plug_client_channels_buf(plug, (char *)buf, count, &channels);
- if (frames < 0)
- return frames;
-
- while (1) {
- unsigned int c;
- ssize_t ret;
- size_t frames1 = frames;
- if (frames1 > plug->frames_alloc)
- frames1 = plug->frames_alloc;
- ret = snd_pcm_plug_write_transfer(plug, channels, frames1);
- if (ret < 0) {
- if (size > 0)
- return size;
- return ret;
- }
- size += ret;
- frames -= ret;
- if (frames == 0)
- break;
- for (c = 0; c < handle->setup.format.channels; ++c)
- channels[c].area.addr += ret * channels[c].area.step / 8;
- }
- return size;
+ return snd_pcm_channel_params(plug->slave, params);
}
-ssize_t snd_pcm_plug_read(snd_pcm_t *pcm, snd_timestamp_t *tstamp ATTRIBUTE_UNUSED, void *buf, size_t count)
+static int snd_pcm_plug_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t *setup)
{
snd_pcm_plug_t *plug = pcm->private;
- snd_pcm_t *handle = plug->handle;
- ssize_t frames;
- snd_pcm_plugin_channel_t *channels;
- size_t size = 0;
- assert(plug->frames_alloc);
- frames = snd_pcm_plug_client_channels_buf(plug, buf, count, &channels);
- if (frames < 0)
- return frames;
-
- while (1) {
- unsigned int c;
- ssize_t ret;
- size_t frames1 = frames;
- if (frames1 > plug->frames_alloc)
- frames1 = plug->frames_alloc;
- ret = snd_pcm_plug_read_transfer(plug, channels, frames1);
- if (ret < 0) {
- if (size > 0)
- return size;
- return ret;
- }
- size += ret;
- frames -= ret;
- if (frames == 0)
- break;
- for (c = 0; c < handle->setup.format.channels; ++c)
- channels[c].area.addr += ret * channels[c].area.step / 8;
- }
- return size;
+ return snd_pcm_channel_setup(plug->slave, setup);
}
-static int snd_pcm_plug_mmap_status(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_mmap_status_t **status ATTRIBUTE_UNUSED)
+static int snd_pcm_plug_mmap_status(snd_pcm_t *pcm)
{
- return -EBADFD;
+ snd_pcm_plug_t *plug = pcm->private;
+ return snd_pcm_mmap_status(plug->slave, NULL);
}
-static int snd_pcm_plug_mmap_control(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_mmap_control_t **control ATTRIBUTE_UNUSED)
+static int snd_pcm_plug_mmap_control(snd_pcm_t *pcm)
{
- return -EBADFD;
+ snd_pcm_plug_t *plug = pcm->private;
+ return snd_pcm_mmap_control(plug->slave, NULL);
}
-static int snd_pcm_plug_mmap_data(snd_pcm_t *pcm ATTRIBUTE_UNUSED, void **buffer ATTRIBUTE_UNUSED, size_t bsize ATTRIBUTE_UNUSED)
+static int snd_pcm_plug_mmap_data(snd_pcm_t *pcm)
{
- return -EBADFD;
+ snd_pcm_plug_t *plug = pcm->private;
+ return snd_pcm_mmap_data(plug->slave, NULL);
}
-static int snd_pcm_plug_munmap_status(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_mmap_status_t *status ATTRIBUTE_UNUSED)
-{
- return -EBADFD;
-}
-
-static int snd_pcm_plug_munmap_control(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_mmap_control_t *control ATTRIBUTE_UNUSED)
+static int snd_pcm_plug_munmap_status(snd_pcm_t *pcm)
{
- return -EBADFD;
-}
-
-static int snd_pcm_plug_munmap_data(snd_pcm_t *pcm ATTRIBUTE_UNUSED, void *buffer ATTRIBUTE_UNUSED, size_t size ATTRIBUTE_UNUSED)
-{
- return -EBADFD;
+ snd_pcm_plug_t *plug = pcm->private;
+ return snd_pcm_munmap_status(plug->slave);
}
-static int snd_pcm_plug_channels_mask(snd_pcm_t *pcm,
- bitset_t *client_vmask)
+static int snd_pcm_plug_munmap_control(snd_pcm_t *pcm)
{
snd_pcm_plug_t *plug = pcm->private;
- if (plug->handle->stream == SND_PCM_STREAM_PLAYBACK)
- return snd_pcm_plug_playback_channels_mask(plug, client_vmask);
- else
- return snd_pcm_plug_capture_channels_mask(plug, client_vmask);
+ return snd_pcm_munmap_control(plug->slave);
}
-
-int snd_pcm_plug_file_descriptor(snd_pcm_t *pcm)
+
+static int snd_pcm_plug_munmap_data(snd_pcm_t *pcm)
{
snd_pcm_plug_t *plug = pcm->private;
- return snd_pcm_file_descriptor(plug->slave);
+ return snd_pcm_munmap_data(plug->slave);
}
-
+
static void snd_pcm_plug_dump(snd_pcm_t *pcm, FILE *fp)
{
snd_pcm_plug_t *plug = pcm->private;
- snd_pcm_t *handle = plug->handle;
- snd_pcm_plugin_t *plugin;
- if (!plug->first) {
- fprintf(fp, "Plug PCM -> ");
- snd_pcm_dump(plug->slave, fp);
- return;
- }
- fprintf(fp, "Plug PCM\n");
- if (handle->valid_setup) {
- fprintf(fp, "\nIts setup is:\n");
- snd_pcm_dump_setup(handle, fp);
- }
- fprintf(fp, "\nPlugins:\n");
- plugin = plug->first;
- while (plugin) {
- snd_pcm_plugin_dump(plugin, fp);
- plugin = plugin->next;
- }
- fprintf(fp, "\n");
+ fprintf(fp, "Plug PCM: ");
+ snd_pcm_dump(plug->slave, fp);
}
-static int snd_pcm_plug_params(snd_pcm_t *pcm, snd_pcm_params_t *params);
-
struct snd_pcm_ops snd_pcm_plug_ops = {
close: snd_pcm_plug_close,
info: snd_pcm_plug_info,
params_info: snd_pcm_plug_params_info,
params: snd_pcm_plug_params,
setup: snd_pcm_plug_setup,
- dump: snd_pcm_plug_dump,
-};
-
-struct snd_pcm_fast_ops snd_pcm_plug_fast_ops = {
- nonblock: snd_pcm_plug_nonblock,
channel_info: snd_pcm_plug_channel_info,
channel_params: snd_pcm_plug_channel_params,
channel_setup: snd_pcm_plug_channel_setup,
- status: snd_pcm_plug_status,
- hw_ptr: snd_pcm_plug_hw_ptr,
- state: snd_pcm_plug_state,
- prepare: snd_pcm_plug_prepare,
- go: snd_pcm_plug_go,
- drain: snd_pcm_plug_drain,
- flush: snd_pcm_plug_flush,
- pause: snd_pcm_plug_pause,
- appl_ptr: snd_pcm_plug_appl_ptr,
- write: snd_pcm_plug_write,
- writev: snd_pcm_plug_writev,
- read: snd_pcm_plug_read,
- readv: snd_pcm_plug_readv,
+ dump: snd_pcm_plug_dump,
+ nonblock: snd_pcm_plug_nonblock,
mmap_status: snd_pcm_plug_mmap_status,
mmap_control: snd_pcm_plug_mmap_control,
mmap_data: snd_pcm_plug_mmap_data,
munmap_status: snd_pcm_plug_munmap_status,
munmap_control: snd_pcm_plug_munmap_control,
munmap_data: snd_pcm_plug_munmap_data,
- file_descriptor: snd_pcm_plug_file_descriptor,
- channels_mask: snd_pcm_plug_channels_mask,
};
-static void snd_pcm_plug_slave_params(snd_pcm_plug_t *plug,
- snd_pcm_params_t *params,
- snd_pcm_params_t *slave_params)
-{
- /* compute right sizes */
- slave_params->frag_size = snd_pcm_plug_slave_size(plug, params->frag_size);
- slave_params->buffer_size = snd_pcm_plug_slave_size(plug, params->buffer_size);
- slave_params->fill_max = snd_pcm_plug_slave_size(plug, params->fill_max);
- slave_params->avail_min = snd_pcm_plug_slave_size(plug, params->avail_min);
- slave_params->xrun_max = snd_pcm_plug_slave_size(plug, params->xrun_max);
- slave_params->align = snd_pcm_plug_slave_size(plug, params->align);
- if (slave_params->boundary == 0 || slave_params->boundary > LONG_MAX)
- slave_params->boundary = LONG_MAX;
- assert(params->buffer_size > 0);
- slave_params->boundary /= params->buffer_size;
- if (slave_params->boundary > LONG_MAX / slave_params->buffer_size)
- slave_params->boundary = LONG_MAX;
- else
- slave_params->boundary *= slave_params->buffer_size;
-}
-
-
-
-static int snd_pcm_plug_params(snd_pcm_t *pcm, snd_pcm_params_t *params)
-{
- snd_pcm_params_t slave_params;
- snd_pcm_info_t slave_info;
- snd_pcm_format_t *req_format, *real_format, format1;
- snd_pcm_params_info_t slave_params_info;
- snd_pcm_plugin_t *plugin;
- snd_pcm_plug_t *plug;
- int err;
- int first = 1;
-
- plug = pcm->private;
-
- /*
- * try to decide, if a conversion is required
- */
-
- memset(&slave_info, 0, sizeof(slave_info));
- if ((err = snd_pcm_info(plug->slave, &slave_info)) < 0) {
- snd_pcm_plug_clear(plug);
- return err;
- }
- memset(&slave_params_info, 0, sizeof(slave_params_info));
- if ((err = snd_pcm_params_info(plug->slave, &slave_params_info)) < 0) {
- snd_pcm_plug_clear(plug);
- return err;
- }
-
- slave_params = *params;
- if ((err = snd_pcm_plug_slave_format(&params->format, &slave_info, &slave_params_info, &slave_params.format)) < 0)
- return err;
-
- retry:
- /* add necessary plugins */
- format1 = params->format;
- snd_pcm_plug_clear(plug);
- if ((err = snd_pcm_plug_format_plugins(plug, &format1,
- &slave_params.format)) < 0)
- return err;
-
- /* compute right sizes */
- snd_pcm_plug_slave_params(plug, params, &slave_params);
-
- pdprintf("params requested params: format = %i, rate = %i, channels = %i\n", slave_params.format.format, slave_params.format.rate, slave_params.format.channels);
-
- err = snd_pcm_params(plug->slave, &slave_params);
- if (err < 0) {
- params->fail_mask = slave_params.fail_mask;
- params->fail_reason = slave_params.fail_reason;
- return err;
- }
- req_format = &slave_params.format;
- real_format = &plug->slave->setup.format;
- if (real_format->interleave != req_format->interleave ||
- real_format->format != req_format->format ||
- real_format->rate != req_format->rate ||
- real_format->channels != req_format->channels) {
- assert(first);
- slave_params.format = *real_format;
- first = 0;
- goto retry;
- }
-
- if (!plug->first) {
- *plug->handle->fast_ops = *plug->slave->fast_ops;
- plug->handle->fast_op_arg = plug->slave->fast_op_arg;
- return 0;
- }
-
- *plug->handle->fast_ops = snd_pcm_plug_fast_ops;
- plug->handle->fast_op_arg = pcm;
-
- /*
- * I/O plugins
- */
-
- if (slave_info.flags & SND_PCM_INFO_MMAP) {
- pdprintf("params mmap plugin\n");
- err = snd_pcm_plugin_build_mmap(plug, &slave_params.format, &plugin);
- } else {
- pdprintf("params I/O plugin\n");
- err = snd_pcm_plugin_build_io(plug, &slave_params.format, &plugin);
- }
- if (err < 0)
- return err;
- if (plug->slave->stream == SND_PCM_STREAM_PLAYBACK) {
- err = snd_pcm_plugin_append(plugin);
- } else {
- err = snd_pcm_plugin_insert(plugin);
- }
- if (err < 0) {
- snd_pcm_plugin_free(plugin);
- return err;
- }
-
- err = snd_pcm_plug_action(plug, INIT, 0);
- if (err < 0)
- return err;
- return 0;
-}
-
-int snd_pcm_plug_create(snd_pcm_t **handlep, snd_pcm_t *slave, int close_slave)
+int snd_pcm_plug_open(snd_pcm_t **handlep,
+ ttable_entry_t *ttable,
+ unsigned int tt_ssize,
+ unsigned int tt_cused, unsigned int tt_sused,
+ snd_pcm_t *slave, int close_slave)
{
snd_pcm_t *handle;
snd_pcm_plug_t *plug;
+ int err;
assert(handlep && slave);
- handle = calloc(1, sizeof(snd_pcm_t));
- if (!handle)
- return -ENOMEM;
plug = calloc(1, sizeof(snd_pcm_plug_t));
- if (!plug) {
- free(handle);
+ if (!plug)
return -ENOMEM;
- }
- plug->handle = handle;
- plug->slave = slave;
+ plug->slave = plug->req_slave = slave;
plug->close_slave = close_slave;
+ plug->ttable = ttable;
+ plug->tt_ssize = tt_ssize;
+ plug->tt_cused = tt_cused;
+ plug->tt_sused = tt_sused;
+
+ handle = calloc(1, sizeof(snd_pcm_t));
+ if (!handle) {
+ free(plug);
+ return -ENOMEM;
+ }
handle->type = SND_PCM_TYPE_PLUG;
handle->stream = slave->stream;
handle->ops = &snd_pcm_plug_ops;
handle->op_arg = handle;
- handle->fast_ops = malloc(sizeof(*handle->fast_ops));
- *handle->fast_ops = snd_pcm_plug_fast_ops;
- handle->fast_op_arg = handle;
+ handle->fast_ops = slave->fast_ops;
+ handle->fast_op_arg = slave->fast_op_arg;
handle->mode = slave->mode;
handle->private = plug;
+ err = snd_pcm_init(handle);
+ if (err < 0) {
+ snd_pcm_close(handle);
+ return err;
+ }
*handlep = handle;
+
return 0;
}
@@ -843,12 +688,70 @@ int snd_pcm_plug_open_subdevice(snd_pcm_t **handlep, int card, int device, int s
err = snd_pcm_hw_open_subdevice(&slave, card, device, subdevice, stream, mode);
if (err < 0)
return err;
- return snd_pcm_plug_create(handlep, slave, 1);
+ return snd_pcm_plug_open(handlep, 0, 0, 0, 0, slave, 1);
}
-int snd_pcm_plug_open(snd_pcm_t **handlep, int card, int device, int stream, int mode)
+int snd_pcm_plug_open_card(snd_pcm_t **handlep, int card, int device, int stream, int mode)
{
return snd_pcm_plug_open_subdevice(handlep, card, device, -1, stream, mode);
}
+#define MAX_CHANNELS 32
+int _snd_pcm_plug_open(snd_pcm_t **pcmp, char *name,
+ snd_config_t *conf,
+ int stream, int mode)
+{
+ snd_config_iterator_t i;
+ char *sname = NULL;
+ int err;
+ snd_pcm_t *spcm;
+ snd_config_t *tt = NULL;
+ ttable_entry_t *ttable = NULL;
+ unsigned int cused, sused;
+ snd_config_foreach(i, conf) {
+ snd_config_t *n = snd_config_entry(i);
+ if (strcmp(n->id, "comment") == 0)
+ continue;
+ if (strcmp(n->id, "type") == 0)
+ continue;
+ if (strcmp(n->id, "stream") == 0)
+ continue;
+ if (strcmp(n->id, "sname") == 0) {
+ err = snd_config_string_get(n, &sname);
+ if (err < 0)
+ return -EINVAL;
+ continue;
+ }
+ if (strcmp(n->id, "ttable") == 0) {
+ if (snd_config_type(n) != SND_CONFIG_TYPE_COMPOUND)
+ return -EINVAL;
+ tt = n;
+ continue;
+ }
+ return -EINVAL;
+ }
+ if (!sname)
+ return -EINVAL;
+ if (tt) {
+ ttable = malloc(MAX_CHANNELS * MAX_CHANNELS * sizeof(*ttable));
+ err = snd_pcm_route_load_ttable(tt, ttable, MAX_CHANNELS, MAX_CHANNELS,
+ &cused, &sused, -1);
+ if (err < 0)
+ return err;
+ }
+
+ /* This is needed cause snd_config_update may destroy config */
+ sname = strdup(sname);
+ if (!sname)
+ return -ENOMEM;
+ err = snd_pcm_open(&spcm, sname, stream, mode);
+ free(sname);
+ if (err < 0)
+ return err;
+ err = snd_pcm_plug_open(pcmp, ttable, MAX_CHANNELS, cused, sused, spcm, 1);
+ if (err < 0)
+ snd_pcm_close(spcm);
+ return err;
+}
+
diff --git a/src/pcm/pcm_plugin.c b/src/pcm/pcm_plugin.c
new file mode 100644
index 00000000..28257038
--- /dev/null
+++ b/src/pcm/pcm_plugin.c
@@ -0,0 +1,394 @@
+/*
+ * PCM - Common plugin code
+ * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
+ *
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "pcm_local.h"
+#include "pcm_plugin.h"
+#include <limits.h>
+
+int snd_pcm_plugin_close(snd_pcm_t *pcm)
+{
+ snd_pcm_plugin_t *plugin = pcm->private;
+ int err = 0;
+ if (plugin->close_slave)
+ err = snd_pcm_close(plugin->slave);
+ free(plugin);
+ return 0;
+}
+
+int snd_pcm_plugin_nonblock(snd_pcm_t *pcm, int nonblock)
+{
+ snd_pcm_plugin_t *plugin = pcm->private;
+ return snd_pcm_nonblock(plugin->slave, nonblock);
+}
+
+int snd_pcm_plugin_info(snd_pcm_t *pcm, snd_pcm_info_t * info)
+{
+ snd_pcm_plugin_t *plugin = pcm->private;
+ return snd_pcm_info(plugin->slave, info);
+}
+
+int snd_pcm_plugin_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info)
+{
+ snd_pcm_plugin_t *plugin = pcm->private;
+ return snd_pcm_channel_info(plugin->slave, info);
+}
+
+int snd_pcm_plugin_channel_params(snd_pcm_t *pcm, snd_pcm_channel_params_t * params)
+{
+ snd_pcm_plugin_t *plugin = pcm->private;
+ return snd_pcm_channel_params(plugin->slave, params);
+}
+
+int snd_pcm_plugin_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t * setup)
+{
+ snd_pcm_plugin_t *plugin = pcm->private;
+ int err;
+ err = snd_pcm_channel_setup(plugin->slave, setup);
+ if (err < 0)
+ return err;
+ if (pcm->setup.mmap_shape == SND_PCM_MMAP_INTERLEAVED) {
+ setup->area.addr = pcm->mmap_data;
+ setup->area.first = setup->channel * pcm->bits_per_sample;
+ setup->area.step = pcm->bits_per_frame;
+ } else {
+ setup->area.addr = pcm->mmap_data + setup->channel * pcm->setup.buffer_size * pcm->bits_per_sample / 8;
+ setup->area.first = 0;
+ setup->area.step = pcm->bits_per_sample;
+ }
+ return 0;
+}
+
+int snd_pcm_plugin_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
+{
+ snd_pcm_plugin_t *plugin = pcm->private;
+ int err = snd_pcm_status(plugin->slave, status);
+ if (err < 0)
+ return err;
+ status->hw_ptr = plugin->mmap_status.hw_ptr;
+ status->appl_ptr = plugin->mmap_control.appl_ptr;
+ status->avail = (pcm->stream == SND_PCM_STREAM_PLAYBACK ?
+ snd_pcm_mmap_playback_avail(pcm) :
+ snd_pcm_mmap_capture_avail(pcm));
+ return 0;
+}
+
+int snd_pcm_plugin_state(snd_pcm_t *pcm)
+{
+ snd_pcm_plugin_t *plugin = pcm->private;
+ return snd_pcm_state(plugin->slave);
+}
+
+int snd_pcm_plugin_delay(snd_pcm_t *pcm, ssize_t *delayp)
+{
+ snd_pcm_plugin_t *plugin = pcm->private;
+ ssize_t sd;
+ int err = snd_pcm_delay(plugin->slave, &sd);
+ int d;
+ if (err < 0)
+ return err;
+ if (plugin->client_frames)
+ sd = plugin->client_frames(pcm, sd);
+ if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
+ d = pcm->setup.buffer_size - snd_pcm_mmap_playback_avail(pcm);
+ else
+ d = snd_pcm_mmap_capture_avail(pcm);
+ *delayp = sd + d;
+ return 0;
+}
+
+int snd_pcm_plugin_prepare(snd_pcm_t *pcm)
+{
+ snd_pcm_plugin_t *plugin = pcm->private;
+ int err = snd_pcm_prepare(plugin->slave);
+ if (err < 0)
+ return err;
+ plugin->mmap_status.hw_ptr = 0;
+ plugin->mmap_control.appl_ptr = 0;
+ if (plugin->init) {
+ err = plugin->init(pcm);
+ if (err < 0)
+ return err;
+ }
+ return 0;
+}
+
+int snd_pcm_plugin_start(snd_pcm_t *pcm)
+{
+ snd_pcm_plugin_t *plugin = pcm->private;
+ return snd_pcm_start(plugin->slave);
+}
+
+int snd_pcm_plugin_stop(snd_pcm_t *pcm)
+{
+ snd_pcm_plugin_t *plugin = pcm->private;
+ return snd_pcm_stop(plugin->slave);
+}
+
+int snd_pcm_plugin_flush(snd_pcm_t *pcm)
+{
+ snd_pcm_plugin_t *plugin = pcm->private;
+ return snd_pcm_flush(plugin->slave);
+}
+
+int snd_pcm_plugin_pause(snd_pcm_t *pcm, int enable)
+{
+ snd_pcm_plugin_t *plugin = pcm->private;
+ return snd_pcm_pause(plugin->slave, enable);
+}
+
+ssize_t snd_pcm_plugin_appl_ptr(snd_pcm_t *pcm, off_t offset)
+{
+ /* FIXME */
+ return -ENOSYS;
+}
+
+ssize_t snd_pcm_plugin_writei(snd_pcm_t *pcm, const void *buffer, size_t size)
+{
+ snd_pcm_plugin_t *plugin = pcm->private;
+ snd_pcm_channel_area_t areas[pcm->setup.format.channels];
+ ssize_t frames;
+ snd_pcm_areas_from_buf(pcm, areas, (void*)buffer);
+ frames = snd_pcm_write_areas(pcm, areas, 0, size, plugin->write);
+ if (frames > 0)
+ snd_pcm_mmap_appl_forward(pcm, frames);
+ return frames;
+}
+
+ssize_t snd_pcm_plugin_writen(snd_pcm_t *pcm, void **bufs, size_t size)
+{
+ snd_pcm_plugin_t *plugin = pcm->private;
+ snd_pcm_channel_area_t areas[pcm->setup.format.channels];
+ ssize_t frames;
+ snd_pcm_areas_from_bufs(pcm, areas, bufs);
+ frames = snd_pcm_write_areas(pcm, areas, 0, size, plugin->write);
+ if (frames > 0)
+ snd_pcm_mmap_appl_forward(pcm, frames);
+ return frames;
+}
+
+ssize_t snd_pcm_plugin_readi(snd_pcm_t *pcm, void *buffer, size_t size)
+{
+ snd_pcm_plugin_t *plugin = pcm->private;
+ snd_pcm_channel_area_t areas[pcm->setup.format.channels];
+ ssize_t frames;
+ snd_pcm_areas_from_buf(pcm, areas, buffer);
+ frames = snd_pcm_read_areas(pcm, areas, 0, size, plugin->read);
+ if (frames > 0)
+ snd_pcm_mmap_appl_forward(pcm, frames);
+ return frames;
+}
+
+ssize_t snd_pcm_plugin_readn(snd_pcm_t *pcm, void **bufs, size_t size)
+{
+ snd_pcm_plugin_t *plugin = pcm->private;
+ snd_pcm_channel_area_t areas[pcm->setup.format.channels];
+ ssize_t frames;
+ snd_pcm_areas_from_bufs(pcm, areas, bufs);
+ frames = snd_pcm_read_areas(pcm, areas, 0, size, plugin->read);
+ if (frames > 0)
+ snd_pcm_mmap_appl_forward(pcm, frames);
+ return frames;
+}
+
+ssize_t snd_pcm_plugin_mmap_forward(snd_pcm_t *pcm, size_t client_size)
+{
+ snd_pcm_plugin_t *plugin = pcm->private;
+ snd_pcm_t *slave = plugin->slave;
+ size_t client_xfer = 0;
+ size_t slave_xfer = 0;
+ ssize_t err = 0;
+ ssize_t slave_size;
+ if (pcm->stream == SND_PCM_STREAM_CAPTURE) {
+ snd_pcm_mmap_appl_forward(pcm, client_size);
+ return client_size;
+ }
+ slave_size = snd_pcm_avail_update(slave);
+ if (slave_size <= 0)
+ return slave_size;
+ while (client_xfer < client_size &&
+ slave_xfer < (size_t)slave_size) {
+ size_t slave_frames = slave_size - slave_xfer;
+ size_t client_frames = client_size - client_xfer;
+ size_t cont = pcm->setup.buffer_size - snd_pcm_mmap_hw_offset(pcm);
+ if (cont < client_frames)
+ client_frames = cont;
+ err = plugin->write(pcm, pcm->mmap_areas,
+ snd_pcm_mmap_hw_offset(pcm),
+ client_frames, &slave_frames);
+ if (err < 0)
+ break;
+ snd_pcm_mmap_appl_forward(pcm, err);
+ client_xfer += err;
+ slave_xfer += slave_frames;
+ }
+ if (client_xfer > 0)
+ return client_xfer;
+ return err;
+}
+
+ssize_t snd_pcm_plugin_avail_update(snd_pcm_t *pcm)
+{
+ snd_pcm_plugin_t *plugin = pcm->private;
+ snd_pcm_t *slave = plugin->slave;
+ size_t client_xfer;
+ size_t slave_xfer = 0;
+ ssize_t err = 0;
+ size_t client_size;
+ ssize_t slave_size = snd_pcm_avail_update(slave);
+ if (slave_size <= 0)
+ return slave_size;
+ if (pcm->stream == SND_PCM_STREAM_PLAYBACK ||
+ !pcm->mmap_data)
+ return plugin->client_frames ?
+ plugin->client_frames(pcm, slave_size) : slave_size;
+ client_xfer = snd_pcm_mmap_capture_avail(pcm);
+ client_size = pcm->setup.buffer_size;
+ while (slave_xfer < (size_t)slave_size &&
+ client_xfer < client_size) {
+ size_t slave_frames = slave_size - slave_xfer;
+ size_t client_frames = client_size - client_xfer;
+ size_t cont = pcm->setup.buffer_size - snd_pcm_mmap_hw_offset(pcm);
+ if (cont < client_frames)
+ client_frames = cont;
+ err = plugin->read(pcm, pcm->mmap_areas,
+ snd_pcm_mmap_hw_offset(pcm),
+ client_frames, &slave_frames);
+ if (err < 0)
+ break;
+ client_xfer += err;
+ slave_xfer += slave_frames;
+ }
+ if (client_xfer > 0)
+ return client_xfer;
+ return err;
+}
+
+int snd_pcm_plugin_mmap_status(snd_pcm_t *pcm)
+{
+ snd_pcm_plugin_t *plugin = pcm->private;
+ pcm->mmap_status = &plugin->mmap_status;
+ return 0;
+}
+
+int snd_pcm_plugin_mmap_control(snd_pcm_t *pcm)
+{
+ snd_pcm_plugin_t *plugin = pcm->private;
+ pcm->mmap_control = &plugin->mmap_control;
+ return 0;
+}
+
+int snd_pcm_plugin_mmap_data(snd_pcm_t *pcm)
+{
+ void *ptr = malloc(snd_pcm_frames_to_bytes(pcm, pcm->setup.buffer_size));
+ if (!ptr)
+ return -ENOMEM;
+ pcm->mmap_data = ptr;
+ return 0;
+}
+
+int snd_pcm_plugin_munmap_status(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
+{
+ return 0;
+}
+
+int snd_pcm_plugin_munmap_control(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
+{
+ return 0;
+}
+
+int snd_pcm_plugin_munmap_data(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
+{
+ free(pcm->mmap_data);
+ return 0;
+}
+
+int snd_pcm_plugin_poll_descriptor(snd_pcm_t *pcm)
+{
+ snd_pcm_plugin_t *plugin = pcm->private;
+ return snd_pcm_poll_descriptor(plugin->slave);
+}
+
+int snd_pcm_plugin_channels_mask(snd_pcm_t *pcm, bitset_t *cmask)
+{
+ snd_pcm_plugin_t *plugin = pcm->private;
+ return snd_pcm_channels_mask(plugin->slave, cmask);
+}
+
+int conv_index(int src_format, int dst_format)
+{
+ int src_endian, dst_endian, sign, src_width, dst_width;
+
+ sign = (snd_pcm_format_signed(src_format) !=
+ snd_pcm_format_signed(dst_format));
+#ifdef SND_LITTLE_ENDIAN
+ src_endian = snd_pcm_format_big_endian(src_format);
+ dst_endian = snd_pcm_format_big_endian(dst_format);
+#else
+ src_endian = snd_pcm_format_little_endian(src_format);
+ dst_endian = snd_pcm_format_little_endian(dst_format);
+#endif
+
+ if (src_endian < 0)
+ src_endian = 0;
+ if (dst_endian < 0)
+ dst_endian = 0;
+
+ src_width = snd_pcm_format_width(src_format) / 8 - 1;
+ dst_width = snd_pcm_format_width(dst_format) / 8 - 1;
+
+ return src_width * 32 + src_endian * 16 + sign * 8 + dst_width * 2 + dst_endian;
+}
+
+int getput_index(int format)
+{
+ int sign, width, endian;
+ sign = !snd_pcm_format_signed(format);
+ width = snd_pcm_format_width(format) / 8 - 1;
+#ifdef SND_LITTLE_ENDIAN
+ endian = snd_pcm_format_big_endian(format);
+#else
+ endian = snd_pcm_format_little_endian(format);
+#endif
+ if (endian < 0)
+ endian = 0;
+ return width * 4 + endian * 2 + sign;
+}
+
+struct snd_pcm_fast_ops snd_pcm_plugin_fast_ops = {
+ status: snd_pcm_plugin_status,
+ state: snd_pcm_plugin_state,
+ delay: snd_pcm_plugin_delay,
+ prepare: snd_pcm_plugin_prepare,
+ start: snd_pcm_plugin_start,
+ stop: snd_pcm_plugin_stop,
+ flush: snd_pcm_plugin_flush,
+ pause: snd_pcm_plugin_pause,
+ appl_ptr: snd_pcm_plugin_appl_ptr,
+ writei: snd_pcm_plugin_writei,
+ writen: snd_pcm_plugin_writen,
+ readi: snd_pcm_plugin_readi,
+ readn: snd_pcm_plugin_readn,
+ poll_descriptor: snd_pcm_plugin_poll_descriptor,
+ channels_mask: snd_pcm_plugin_channels_mask,
+ avail_update: snd_pcm_plugin_avail_update,
+ mmap_forward: snd_pcm_plugin_mmap_forward,
+};
+
diff --git a/src/pcm/pcm_plugin.h b/src/pcm/pcm_plugin.h
new file mode 100644
index 00000000..e76993ca
--- /dev/null
+++ b/src/pcm/pcm_plugin.h
@@ -0,0 +1,105 @@
+/*
+ * PCM - Common plugin code
+ * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
+ *
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+typedef struct {
+ snd_pcm_t *slave;
+ int close_slave;
+ snd_pcm_xfer_areas_func_t read;
+ snd_pcm_xfer_areas_func_t write;
+ size_t (*client_frames)(snd_pcm_t *pcm, size_t frames);
+ int (*init)(snd_pcm_t *pcm);
+ snd_pcm_mmap_control_t mmap_control;
+ snd_pcm_mmap_status_t mmap_status;
+} snd_pcm_plugin_t;
+
+int snd_pcm_plugin_close(snd_pcm_t *pcm);
+int snd_pcm_plugin_nonblock(snd_pcm_t *pcm, int nonblock);
+int snd_pcm_plugin_info(snd_pcm_t *pcm, snd_pcm_info_t * info);
+int snd_pcm_plugin_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info);
+int snd_pcm_plugin_channel_params(snd_pcm_t *pcm, snd_pcm_channel_params_t * params);
+int snd_pcm_plugin_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t * setup);
+int snd_pcm_plugin_status(snd_pcm_t *pcm, snd_pcm_status_t * status);
+int snd_pcm_plugin_state(snd_pcm_t *pcm);
+int snd_pcm_plugin_delay(snd_pcm_t *pcm, ssize_t *delayp);
+int snd_pcm_plugin_prepare(snd_pcm_t *pcm);
+int snd_pcm_plugin_start(snd_pcm_t *pcm);
+int snd_pcm_plugin_stop(snd_pcm_t *pcm);
+int snd_pcm_plugin_flush(snd_pcm_t *pcm);
+int snd_pcm_plugin_pause(snd_pcm_t *pcm, int enable);
+ssize_t snd_pcm_plugin_appl_ptr(snd_pcm_t *pcm, off_t offset);
+ssize_t snd_pcm_plugin_writei(snd_pcm_t *pcm, const void *buffer, size_t size);
+ssize_t snd_pcm_plugin_writen(snd_pcm_t *pcm, void **bufs, size_t size);
+ssize_t snd_pcm_plugin_readi(snd_pcm_t *pcm, void *buffer, size_t size);
+ssize_t snd_pcm_plugin_readn(snd_pcm_t *pcm, void **bufs, size_t size);
+ssize_t snd_pcm_plugin_mmap_forward(snd_pcm_t *pcm, size_t size);
+ssize_t snd_pcm_plugin_avail_update(snd_pcm_t *pcm);
+int snd_pcm_plugin_mmap_status(snd_pcm_t *pcm);
+int snd_pcm_plugin_mmap_control(snd_pcm_t *pcm);
+int snd_pcm_plugin_mmap_data(snd_pcm_t *pcm);
+int snd_pcm_plugin_munmap_status(snd_pcm_t *pcm);
+int snd_pcm_plugin_munmap_control(snd_pcm_t *pcm);
+int snd_pcm_plugin_munmap_data(snd_pcm_t *pcm);
+int snd_pcm_plugin_poll_descriptor(snd_pcm_t *pcm);
+int snd_pcm_plugin_channels_mask(snd_pcm_t *pcm, bitset_t *cmask);
+int getput_index(int format);
+int conv_index(int src_format, int dst_format);
+
+#define SND_PCM_LINEAR_FORMATS (SND_PCM_FMT_S8 | SND_PCM_FMT_U8 | \
+ SND_PCM_FMT_S16_LE | SND_PCM_FMT_S16_BE | \
+ SND_PCM_FMT_U16_LE | SND_PCM_FMT_U16_BE | \
+ SND_PCM_FMT_S24_LE | SND_PCM_FMT_S24_BE | \
+ SND_PCM_FMT_U24_LE | SND_PCM_FMT_U24_BE | \
+ SND_PCM_FMT_S32_LE | SND_PCM_FMT_S32_BE | \
+ SND_PCM_FMT_U32_LE | SND_PCM_FMT_U32_BE)
+
+extern struct snd_pcm_fast_ops snd_pcm_plugin_fast_ops;
+
+#define muldiv64(a,b,d) (((int64_t)(a) * (b) + (b) / 2) / (d))
+
+#define ROUTE_PLUGIN_FLOAT 1
+#define ROUTE_PLUGIN_RESOLUTION 16
+
+#if ROUTE_PLUGIN_FLOAT
+typedef float ttable_entry_t;
+#define HALF 0.5
+#define FULL 1.0
+#else
+typedef int ttable_entry_t;
+#define HALF (ROUTE_PLUGIN_RESOLUTION / 2)
+#define FULL ROUTE_PLUGIN_RESOLUTION
+#endif
+
+int snd_pcm_linear_open(snd_pcm_t **handlep, int sformat, snd_pcm_t *slave, int close_slave);
+int snd_pcm_mulaw_open(snd_pcm_t **handlep, int sformat, snd_pcm_t *slave, int close_slave);
+int snd_pcm_alaw_open(snd_pcm_t **handlep, int sformat, snd_pcm_t *slave, int close_slave);
+int snd_pcm_adpcm_open(snd_pcm_t **handlep, int sformat, snd_pcm_t *slave, int close_slave);
+int snd_pcm_route_load_ttable(snd_config_t *tt, ttable_entry_t *ttable,
+ unsigned int tt_csize, unsigned int tt_ssize,
+ unsigned int *tt_cused, unsigned int *tt_sused,
+ int schannels);
+int snd_pcm_route_open(snd_pcm_t **handlep,
+ int sformat, unsigned int schannels,
+ ttable_entry_t *ttable,
+ unsigned int tt_ssize,
+ unsigned int tt_cused, unsigned int tt_sused,
+ snd_pcm_t *slave, int close_slave);
+int snd_pcm_rate_open(snd_pcm_t **handlep, int sformat, int srate, snd_pcm_t *slave, int close_slave);
+
diff --git a/src/pcm/pcm_rate.c b/src/pcm/pcm_rate.c
new file mode 100644
index 00000000..104019f2
--- /dev/null
+++ b/src/pcm/pcm_rate.c
@@ -0,0 +1,693 @@
+/*
+ * PCM - Rate conversion
+ * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
+ *
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <limits.h>
+#include <byteswap.h>
+#include "pcm_local.h"
+#include "pcm_plugin.h"
+
+#define DIV (1<<16)
+
+typedef struct {
+ int16_t sample;
+ int sum;
+ unsigned int pos;
+} rate_state_t;
+
+typedef size_t (*rate_f)(snd_pcm_channel_area_t *src_areas,
+ size_t src_offset, size_t src_frames,
+ snd_pcm_channel_area_t *dst_areas,
+ size_t dst_offset, size_t *dst_framesp,
+ size_t channels,
+ int getidx, int putidx,
+ unsigned int arg,
+ rate_state_t *states);
+
+typedef struct {
+ /* This field need to be the first */
+ snd_pcm_plugin_t plug;
+ int get_idx;
+ int put_idx;
+ unsigned int pitch;
+ rate_f func;
+ int req_sformat;
+ int req_srate;
+ int sformat;
+ int cformat;
+ int srate;
+ int crate;
+ int cxfer_mode, cmmap_shape;
+ rate_state_t *states;
+} snd_pcm_rate_t;
+
+static size_t resample_expand(snd_pcm_channel_area_t *src_areas,
+ size_t src_offset, size_t src_frames,
+ snd_pcm_channel_area_t *dst_areas,
+ size_t dst_offset, size_t *dst_framesp,
+ size_t channels,
+ int getidx, int putidx,
+ unsigned int get_threshold,
+ rate_state_t *states)
+{
+#define GET_S16_LABELS
+#define PUT_S16_LABELS
+#include "plugin_ops.h"
+#undef GET_S16_LABELS
+#undef PUT_S16_LABELS
+ void *get = get_s16_labels[getidx];
+ void *put = put_s16_labels[putidx];
+ unsigned int channel;
+ size_t src_frames1 = 0;
+ size_t dst_frames1 = 0;
+ size_t dst_frames = *dst_framesp;
+ int16_t sample = 0;
+
+ if (src_frames == 0 ||
+ dst_frames == 0)
+ return 0;
+ for (channel = 0; channel < channels; ++channel) {
+ snd_pcm_channel_area_t *src_area = &src_areas[channel];
+ snd_pcm_channel_area_t *dst_area = &dst_areas[channel];
+ char *src, *dst;
+ int src_step, dst_step;
+ int16_t old_sample = states->sample;
+ unsigned int pos = states->pos;
+#if 0
+ if (!src_area->enabled) {
+ if (dst_area->wanted)
+ snd_pcm_area_silence(&dst_area->area, 0, dst_frames, plugin->dst_format.sfmt);
+ dst_area->enabled = 0;
+ continue;
+ }
+ dst_area->enabled = 1;
+#endif
+ src = snd_pcm_channel_area_addr(src_area, src_offset);
+ dst = snd_pcm_channel_area_addr(dst_area, dst_offset);
+ src_step = snd_pcm_channel_area_step(src_area);
+ dst_step = snd_pcm_channel_area_step(dst_area);
+ src_frames1 = 0;
+ dst_frames1 = 0;
+ while (dst_frames1 < dst_frames) {
+ if (pos >= get_threshold) {
+ int16_t new_sample;
+ if (src_frames1 == src_frames)
+ break;
+ pos -= get_threshold;
+ goto *get;
+#define GET_S16_END after_get
+#include "plugin_ops.h"
+#undef GET_S16_END
+ after_get:
+ src += src_step;
+ src_frames1++;
+ new_sample = sample;
+ sample = (old_sample * (DIV - pos) + new_sample * pos) / DIV;
+ old_sample = new_sample;
+ } else
+ sample = old_sample;
+ goto *put;
+#define PUT_S16_END after_put
+#include "plugin_ops.h"
+#undef PUT_S16_END
+ after_put:
+ dst += dst_step;
+ dst_frames1++;
+ pos += DIV;
+ }
+ states->sample = old_sample;
+ states->pos = pos;
+ states++;
+ }
+ *dst_framesp = dst_frames1;
+ return src_frames1;
+}
+
+static size_t resample_shrink(snd_pcm_channel_area_t *src_areas,
+ size_t src_offset, size_t src_frames,
+ snd_pcm_channel_area_t *dst_areas,
+ size_t dst_offset, size_t *dst_framesp,
+ size_t channels,
+ int getidx, int putidx,
+ unsigned int get_increment,
+ rate_state_t *states)
+{
+#define GET_S16_LABELS
+#define PUT_S16_LABELS
+#include "plugin_ops.h"
+#undef GET_S16_LABELS
+#undef PUT_S16_LABELS
+ void *get = get_s16_labels[getidx];
+ void *put = put_s16_labels[putidx];
+ unsigned int channel;
+ size_t src_frames1 = 0;
+ size_t dst_frames1 = 0;
+ size_t dst_frames = *dst_framesp;
+ int16_t sample = 0;
+
+ if (src_frames == 0 ||
+ dst_frames == 0)
+ return 0;
+ for (channel = 0; channel < channels; ++channel) {
+ snd_pcm_channel_area_t *src_area = &src_areas[channel];
+ snd_pcm_channel_area_t *dst_area = &dst_areas[channel];
+ unsigned int pos;
+ int sum;
+ char *src, *dst;
+ int src_step, dst_step;
+ sum = states->sum;
+ pos = states->pos;
+#if 0
+ if (!src_area->enabled) {
+ if (dst_area->wanted)
+ snd_pcm_area_silence(&dst_area->area, 0, dst_frames, plugin->dst_format.sfmt);
+ dst_area->enabled = 0;
+ continue;
+ }
+ dst_area->enabled = 1;
+#endif
+ src = snd_pcm_channel_area_addr(src_area, src_offset);
+ dst = snd_pcm_channel_area_addr(dst_area, dst_offset);
+ src_step = snd_pcm_channel_area_step(src_area);
+ dst_step = snd_pcm_channel_area_step(dst_area);
+ src_frames1 = 0;
+ dst_frames1 = 0;
+ while (src_frames1 < src_frames) {
+
+ goto *get;
+#define GET_S16_END after_get
+#include "plugin_ops.h"
+#undef GET_S16_END
+ after_get:
+ src += src_step;
+ src_frames1++;
+ pos += get_increment;
+ if (pos >= DIV) {
+ int s = sample;
+ pos -= DIV;
+ sum += s * (get_increment - pos);
+ sum /= DIV;
+ sample = sum;
+ goto *put;
+#define PUT_S16_END after_put
+#include "plugin_ops.h"
+#undef PUT_S16_END
+ after_put:
+ dst += dst_step;
+ sum = s * pos;
+ dst_frames1++;
+ if (dst_frames1 == dst_frames)
+ break;
+ } else
+ sum += sample * get_increment;
+ }
+ states->sum = sum;
+ states->pos = pos;
+ states++;
+ }
+ *dst_framesp = dst_frames1;
+ return src_frames1;
+}
+
+static int snd_pcm_rate_close(snd_pcm_t *pcm)
+{
+ snd_pcm_rate_t *rate = pcm->private;
+ int err = 0;
+ if (rate->plug.close_slave)
+ err = snd_pcm_close(rate->plug.slave);
+ if (rate->states)
+ free(rate->states);
+ free(rate);
+ return 0;
+}
+
+static int snd_pcm_rate_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t * info)
+{
+ snd_pcm_rate_t *rate = pcm->private;
+ unsigned int req_mask = info->req_mask;
+ unsigned int sfmt = info->req.format.sfmt;
+ unsigned int crate = info->req.format.rate;
+ unsigned int srate;
+ int err;
+ if (req_mask & SND_PCM_PARAMS_SFMT &&
+ !snd_pcm_format_linear(sfmt)) {
+ info->req.fail_mask = SND_PCM_PARAMS_SFMT;
+ info->req.fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
+ return -EINVAL;
+ }
+ if (rate->req_sformat >= 0) {
+ info->req_mask |= SND_PCM_PARAMS_SFMT;
+ info->req.format.sfmt = rate->req_sformat;
+ }
+ info->req_mask |= SND_PCM_PARAMS_RATE;
+ info->req_mask &= ~(SND_PCM_PARAMS_MMAP_SHAPE |
+ SND_PCM_PARAMS_XFER_MODE);
+ info->req.format.rate = rate->req_srate;
+ err = snd_pcm_params_info(rate->plug.slave, info);
+ info->req_mask = req_mask;
+ info->req.format.sfmt = sfmt;
+ info->req.format.rate = crate;
+ if (err < 0)
+ return err;
+ if (req_mask & SND_PCM_PARAMS_SFMT)
+ info->formats = 1 << sfmt;
+ else
+ info->formats = SND_PCM_LINEAR_FORMATS;
+ if (!(req_mask & SND_PCM_PARAMS_RATE)) {
+ info->min_rate = 4000;
+ info->max_rate = 192000;
+ return 0;
+ }
+ if (rate->req_srate - info->min_rate < info->max_rate - rate->req_srate)
+ srate = info->min_rate;
+ else
+ srate = info->max_rate;
+ info->min_rate = crate;
+ info->max_rate = crate;
+ if (info->buffer_size)
+ info->buffer_size = muldiv64(info->buffer_size, crate, srate);
+ if (info->min_fragment_size)
+ info->min_fragment_size = muldiv64(info->min_fragment_size, crate, srate);
+ if (info->max_fragment_size)
+ info->max_fragment_size = muldiv64(info->max_fragment_size, crate, srate);
+ if (info->fragment_align)
+ info->fragment_align = muldiv64(info->fragment_align, crate, srate);
+ info->flags &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
+ info->flags |= SND_PCM_INFO_INTERLEAVED | SND_PCM_INFO_NONINTERLEAVED;
+ return 0;
+}
+
+static int snd_pcm_rate_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
+{
+ snd_pcm_rate_t *rate = pcm->private;
+ snd_pcm_t *slave = rate->plug.slave;
+ snd_pcm_params_t slave_params;
+ snd_pcm_params_info_t slave_info;
+ int srate, crate;
+ int err;
+ if (!snd_pcm_format_linear(params->format.sfmt)) {
+ params->fail_mask = SND_PCM_PARAMS_SFMT;
+ params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
+ return -EINVAL;
+ }
+ slave_params = *params;
+ rate->cformat = params->format.sfmt;
+ rate->crate = crate = params->format.rate;
+ rate->cxfer_mode = params->xfer_mode;
+ rate->cmmap_shape = params->mmap_shape;
+
+ memset(&slave_info, 0, sizeof(slave_info));
+ slave_info.req = *params;
+ if (rate->req_sformat >= 0)
+ slave_info.req.format.sfmt = rate->req_sformat;
+ slave_info.req.format.rate = rate->req_srate;
+ slave_info.req_mask = ~0;
+ err = snd_pcm_params_info(slave, &slave_info);
+ if (err < 0) {
+ params->fail_mask = slave_info.req.fail_mask;
+ params->fail_reason = slave_info.req.fail_reason;
+ return err;
+ }
+
+ if (slave->mmap_data) {
+ err = snd_pcm_munmap_data(slave);
+ if (err < 0)
+ return err;
+ }
+
+ if (rate->req_srate - slave_info.min_rate < slave_info.max_rate - rate->req_srate)
+ srate = slave_info.min_rate;
+ else
+ srate = slave_info.max_rate;
+
+ slave_params.format.rate = srate;
+ slave_params.avail_min = muldiv64(params->avail_min, srate, crate);
+ slave_params.xfer_min = muldiv64(params->xfer_min, srate, crate);
+ slave_params.buffer_size = muldiv64(params->buffer_size, srate, crate);
+ slave_params.frag_size = muldiv64(params->frag_size, srate, crate);
+ slave_params.xfer_align = muldiv64(params->xfer_align, srate, crate);
+ slave_params.xrun_max = muldiv64(params->xrun_max, srate, crate);
+ /* FIXME: boundary? */
+ slave_params.xfer_mode = SND_PCM_XFER_UNSPECIFIED;
+ slave_params.mmap_shape = SND_PCM_MMAP_UNSPECIFIED;;
+ err = snd_pcm_params(slave, &slave_params);
+ params->fail_mask = slave_params.fail_mask;
+ params->fail_reason = slave_params.fail_reason;
+ if (slave->valid_setup) {
+ int r = snd_pcm_mmap_data(slave, NULL);
+ assert(r >= 0);
+ }
+ return err;
+}
+
+static int snd_pcm_rate_setup(snd_pcm_t *pcm, snd_pcm_setup_t * setup)
+{
+ snd_pcm_rate_t *rate = pcm->private;
+ int src_format, dst_format;
+ int src_rate, dst_rate;
+ int mul, div;
+ int err = snd_pcm_setup(rate->plug.slave, setup);
+ if (err < 0)
+ return err;
+ if (rate->req_sformat >= 0)
+ assert(rate->req_sformat == setup->format.sfmt);
+ rate->sformat = setup->format.sfmt;
+ rate->srate = setup->format.rate;
+ if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
+ src_format = rate->cformat;
+ dst_format = rate->sformat;
+ src_rate = rate->crate;
+ dst_rate = rate->srate;
+ } else {
+ src_format = rate->sformat;
+ dst_format = rate->cformat;
+ src_rate = rate->srate;
+ dst_rate = rate->crate;
+ }
+ rate->get_idx = getput_index(src_format);
+ rate->put_idx = getput_index(dst_format);
+ if (src_rate < dst_rate) {
+ rate->func = resample_expand;
+ /* pitch is get_threshold */
+ } else {
+ rate->func = resample_shrink;
+ /* pitch is get_increment */
+ }
+ rate->pitch = (((u_int64_t)dst_rate * DIV) + src_rate / 2) / src_rate;
+ if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
+ mul = DIV;
+ div = rate->pitch;
+ } else {
+ mul = rate->pitch;
+ div = DIV;
+ }
+ rate->crate = muldiv64(rate->srate, mul, div);
+ if (rate->cxfer_mode == SND_PCM_XFER_UNSPECIFIED)
+ setup->xfer_mode = SND_PCM_XFER_NONINTERLEAVED;
+ else
+ setup->xfer_mode = rate->cxfer_mode;
+ if (rate->cmmap_shape == SND_PCM_MMAP_UNSPECIFIED)
+ setup->mmap_shape = SND_PCM_MMAP_NONINTERLEAVED;
+ else
+ setup->mmap_shape = rate->cmmap_shape;
+ setup->format.sfmt = rate->cformat;
+ setup->format.rate = rate->crate;
+ /* FIXME */
+ setup->rate_master = rate->crate;
+ setup->rate_divisor = 1;
+ setup->mmap_bytes = 0;
+ setup->avail_min = muldiv64(setup->avail_min, mul, div);
+ setup->xfer_min = muldiv64(setup->xfer_min, mul, div);
+ setup->xrun_max = muldiv64(setup->xrun_max, mul, div);
+
+ /* FIXME: the three above are not a lot sensible */
+ setup->buffer_size = muldiv64(setup->buffer_size, mul, div);
+ setup->frag_size = muldiv64(setup->frag_size, mul, div);
+ setup->xfer_align = muldiv64(setup->xfer_align, mul, div);
+
+ /* FIXME */
+ setup->boundary = LONG_MAX - LONG_MAX % setup->buffer_size;
+
+ if (rate->states)
+ free(rate->states);
+ rate->states = malloc(setup->format.channels * sizeof(*rate->states));
+ return 0;
+}
+
+static int snd_pcm_rate_init(snd_pcm_t *pcm)
+{
+ snd_pcm_rate_t *rate = pcm->private;
+ unsigned int k;
+ for (k = 0; k < pcm->setup.format.channels; ++k) {
+ rate->states[k].sum = 0;
+ rate->states[k].sample = 0;
+ if (rate->func == resample_expand) {
+ /* Get a sample on entry */
+ rate->states[k].pos = rate->pitch + DIV;
+ } else {
+ rate->states[k].pos = 0;
+ }
+ }
+ return 0;
+}
+
+static ssize_t snd_pcm_rate_write_areas(snd_pcm_t *pcm,
+ snd_pcm_channel_area_t *areas,
+ size_t client_offset,
+ size_t client_size,
+ size_t *slave_sizep)
+{
+ snd_pcm_rate_t *rate = pcm->private;
+ snd_pcm_t *slave = rate->plug.slave;
+ size_t client_xfer = 0;
+ size_t slave_xfer = 0;
+ ssize_t err = 0;
+ size_t slave_size;
+ if (slave_sizep)
+ slave_size = *slave_sizep;
+ else
+ slave_size = INT_MAX;
+ assert(client_size > 0 && slave_size > 0);
+ while (client_xfer < client_size &&
+ slave_xfer < slave_size) {
+ size_t src_frames, dst_frames;
+ src_frames = client_size - client_xfer;
+ dst_frames = snd_pcm_mmap_playback_xfer(slave, slave_size - slave_xfer);
+ src_frames = rate->func(areas, client_offset, src_frames,
+ slave->mmap_areas, snd_pcm_mmap_offset(slave),
+ &dst_frames,
+ pcm->setup.format.channels,
+ rate->get_idx, rate->put_idx,
+ rate->pitch, rate->states);
+ err = snd_pcm_mmap_forward(slave, dst_frames);
+ if (err < 0)
+ break;
+ assert((size_t)err == dst_frames);
+ client_offset += src_frames;
+ client_xfer += src_frames;
+ snd_pcm_mmap_hw_forward(pcm, src_frames);
+ slave_xfer += dst_frames;
+ }
+ if (client_xfer > 0 || slave_xfer > 0) {
+ if (slave_sizep)
+ *slave_sizep = slave_xfer;
+ return client_xfer;
+ }
+ return err;
+}
+
+static ssize_t snd_pcm_rate_read_areas(snd_pcm_t *pcm,
+ snd_pcm_channel_area_t *areas,
+ size_t client_offset,
+ size_t client_size,
+ size_t *slave_sizep)
+
+{
+ snd_pcm_rate_t *rate = pcm->private;
+ snd_pcm_t *slave = rate->plug.slave;
+ size_t client_xfer = 0;
+ size_t slave_xfer = 0;
+ ssize_t err = 0;
+ size_t slave_size;
+ if (slave_sizep)
+ slave_size = *slave_sizep;
+ else
+ slave_size = INT_MAX;
+ assert(client_size > 0 && slave_size > 0);
+ while (client_xfer < client_size &&
+ slave_xfer < slave_size) {
+ size_t src_frames, dst_frames;
+ dst_frames = client_size - client_xfer;
+ src_frames = snd_pcm_mmap_capture_xfer(slave, slave_size - slave_xfer);
+ src_frames = rate->func(slave->mmap_areas, snd_pcm_mmap_offset(slave),
+ src_frames,
+ areas, client_offset, &dst_frames,
+ pcm->setup.format.channels,
+ rate->get_idx, rate->put_idx,
+ rate->pitch, rate->states);
+ err = snd_pcm_mmap_forward(slave, src_frames);
+ if (err < 0)
+ break;
+ assert((size_t)err == src_frames);
+ client_offset += dst_frames;
+ client_xfer += dst_frames;
+ snd_pcm_mmap_hw_forward(pcm, dst_frames);
+ slave_xfer += src_frames;
+ }
+ if (client_xfer > 0 || slave_xfer > 0) {
+ if (slave_sizep)
+ *slave_sizep = slave_xfer;
+ return client_xfer;
+ }
+ return err;
+}
+
+size_t snd_pcm_rate_client_frames(snd_pcm_t *pcm, size_t frames)
+{
+ snd_pcm_rate_t *rate = pcm->private;
+ /* Round toward zero */
+ if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
+ return (int64_t)frames * DIV / rate->pitch;
+ else
+ return (int64_t)frames * rate->pitch / DIV;
+}
+
+static void snd_pcm_rate_dump(snd_pcm_t *pcm, FILE *fp)
+{
+ snd_pcm_rate_t *rate = pcm->private;
+ if (rate->req_sformat < 0)
+ fprintf(fp, "Rate conversion PCM (%d)\n",
+ rate->req_srate);
+ else
+ fprintf(fp, "Rate conversion PCM (%d, sformat=%s)\n",
+ rate->req_srate,
+ snd_pcm_format_name(rate->req_sformat));
+ if (pcm->valid_setup) {
+ fprintf(fp, "Its setup is:\n");
+ snd_pcm_dump_setup(pcm, fp);
+ }
+ fprintf(fp, "Slave: ");
+ snd_pcm_dump(rate->plug.slave, fp);
+}
+
+struct snd_pcm_ops snd_pcm_rate_ops = {
+ close: snd_pcm_rate_close,
+ info: snd_pcm_plugin_info,
+ params_info: snd_pcm_rate_params_info,
+ params: snd_pcm_rate_params,
+ setup: snd_pcm_rate_setup,
+ channel_info: snd_pcm_plugin_channel_info,
+ channel_params: snd_pcm_plugin_channel_params,
+ channel_setup: snd_pcm_plugin_channel_setup,
+ dump: snd_pcm_rate_dump,
+ nonblock: snd_pcm_plugin_nonblock,
+ mmap_status: snd_pcm_plugin_mmap_status,
+ mmap_control: snd_pcm_plugin_mmap_control,
+ mmap_data: snd_pcm_plugin_mmap_data,
+ munmap_status: snd_pcm_plugin_munmap_status,
+ munmap_control: snd_pcm_plugin_munmap_control,
+ munmap_data: snd_pcm_plugin_munmap_data,
+};
+
+int snd_pcm_rate_open(snd_pcm_t **handlep, int sformat, int srate, snd_pcm_t *slave, int close_slave)
+{
+ snd_pcm_t *handle;
+ snd_pcm_rate_t *rate;
+ int err;
+ assert(handlep && slave);
+ if (sformat >= 0 && snd_pcm_format_linear(sformat) != 1)
+ return -EINVAL;
+ rate = calloc(1, sizeof(snd_pcm_rate_t));
+ if (!rate) {
+ return -ENOMEM;
+ }
+ rate->req_srate = srate;
+ rate->req_sformat = sformat;
+ rate->plug.read = snd_pcm_rate_read_areas;
+ rate->plug.write = snd_pcm_rate_write_areas;
+ rate->plug.client_frames = snd_pcm_rate_client_frames;
+ rate->plug.init = snd_pcm_rate_init;
+ rate->plug.slave = slave;
+ rate->plug.close_slave = close_slave;
+
+ handle = calloc(1, sizeof(snd_pcm_t));
+ if (!handle) {
+ free(rate);
+ return -ENOMEM;
+ }
+ handle->type = SND_PCM_TYPE_RATE;
+ handle->stream = slave->stream;
+ handle->ops = &snd_pcm_rate_ops;
+ handle->op_arg = handle;
+ handle->fast_ops = &snd_pcm_plugin_fast_ops;
+ handle->fast_op_arg = handle;
+ handle->mode = slave->mode;
+ handle->private = rate;
+ err = snd_pcm_init(handle);
+ if (err < 0) {
+ snd_pcm_close(handle);
+ return err;
+ }
+ *handlep = handle;
+
+ return 0;
+}
+
+int _snd_pcm_rate_open(snd_pcm_t **pcmp, char *name,
+ snd_config_t *conf,
+ int stream, int mode)
+{
+ snd_config_iterator_t i;
+ char *sname = NULL;
+ int err;
+ snd_pcm_t *spcm;
+ int sformat = -1;
+ long srate = -1;
+ snd_config_foreach(i, conf) {
+ snd_config_t *n = snd_config_entry(i);
+ if (strcmp(n->id, "comment") == 0)
+ continue;
+ if (strcmp(n->id, "type") == 0)
+ continue;
+ if (strcmp(n->id, "stream") == 0)
+ continue;
+ if (strcmp(n->id, "sname") == 0) {
+ err = snd_config_string_get(n, &sname);
+ if (err < 0)
+ return -EINVAL;
+ continue;
+ }
+ if (strcmp(n->id, "sformat") == 0) {
+ char *f;
+ err = snd_config_string_get(n, &f);
+ if (err < 0)
+ return -EINVAL;
+ sformat = snd_pcm_format_value(f);
+ if (sformat < 0)
+ return -EINVAL;
+ if (snd_pcm_format_linear(sformat) != 1)
+ return -EINVAL;
+ continue;
+ }
+ if (strcmp(n->id, "srate") == 0) {
+ err = snd_config_integer_get(n, &srate);
+ if (err < 0)
+ return -EINVAL;
+ continue;
+ }
+ return -EINVAL;
+ }
+ if (!sname || !srate)
+ return -EINVAL;
+ /* This is needed cause snd_config_update may destroy config */
+ sname = strdup(sname);
+ if (!sname)
+ return -ENOMEM;
+ err = snd_pcm_open(&spcm, sname, stream, mode);
+ free(sname);
+ if (err < 0)
+ return err;
+ err = snd_pcm_rate_open(pcmp, sformat, srate, spcm, 1);
+ if (err < 0)
+ snd_pcm_close(spcm);
+ return err;
+}
+
+
diff --git a/src/pcm/pcm_route.c b/src/pcm/pcm_route.c
new file mode 100644
index 00000000..406f9f34
--- /dev/null
+++ b/src/pcm/pcm_route.c
@@ -0,0 +1,963 @@
+/*
+ * PCM - Linear conversion
+ * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
+ *
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <byteswap.h>
+#include <math.h>
+#include "pcm_local.h"
+#include "pcm_plugin.h"
+
+/* The best possible hack to support missing optimization in gcc 2.7.2.3 */
+#if ROUTE_PLUGIN_RESOLUTION & (ROUTE_PLUGIN_RESOLUTION - 1) != 0
+#define div(a) a /= ROUTE_PLUGIN_RESOLUTION
+#elif ROUTE_PLUGIN_RESOLUTION == 16
+#define div(a) a >>= 4
+#else
+#error "Add some code here"
+#endif
+
+typedef struct {
+ int channel;
+ int as_int;
+#if ROUTE_PLUGIN_FLOAT
+ float as_float;
+#endif
+} ttable_src_t;
+
+typedef struct ttable_dst ttable_dst_t;
+
+typedef struct {
+ enum {UINT32=0, UINT64=1, FLOAT=2} sum_idx;
+ int get_idx;
+ int put_idx;
+ int conv_idx;
+ int src_size;
+ int dst_sfmt;
+ size_t ndsts;
+ ttable_dst_t *dsts;
+} route_params_t;
+
+
+typedef void (*route_f)(snd_pcm_channel_area_t *src_areas,
+ size_t src_offset,
+ snd_pcm_channel_area_t *dst_area,
+ size_t dst_offset,
+ size_t frames,
+ ttable_dst_t *ttable,
+ route_params_t *params);
+
+struct ttable_dst {
+ int att; /* Attenuated */
+ unsigned int nsrcs;
+ ttable_src_t* srcs;
+ route_f func;
+};
+
+typedef union {
+ u_int32_t as_uint32;
+ u_int64_t as_uint64;
+#if ROUTE_PLUGIN_FLOAT
+ float as_float;
+#endif
+} sum_t;
+
+typedef struct {
+ /* This field need to be the first */
+ snd_pcm_plugin_t plug;
+ int req_sformat, req_schannels;
+ int sformat;
+ int cformat;
+ int schannels;
+ int cchannels;
+ int cxfer_mode, cmmap_shape;
+ route_params_t params;
+} snd_pcm_route_t;
+
+
+static void route1_zero(snd_pcm_channel_area_t *src_areas ATTRIBUTE_UNUSED,
+ size_t src_offset ATTRIBUTE_UNUSED,
+ snd_pcm_channel_area_t *dst_area,
+ size_t dst_offset,
+ size_t frames,
+ ttable_dst_t* ttable ATTRIBUTE_UNUSED,
+ route_params_t *params)
+{
+#if 0
+ if (dst_area->wanted)
+ snd_pcm_area_silence(dst_area, dst_offset, frames, params->dst_sfmt);
+ dsts_area->enabled = 0;
+#else
+ snd_pcm_area_silence(dst_area, dst_offset, frames, params->dst_sfmt);
+#endif
+}
+
+static void route1_one(snd_pcm_channel_area_t *src_areas,
+ size_t src_offset,
+ snd_pcm_channel_area_t *dst_area,
+ size_t dst_offset,
+ size_t frames,
+ ttable_dst_t* ttable,
+ route_params_t *params)
+{
+#define CONV_LABELS
+#include "plugin_ops.h"
+#undef CONV_LABELS
+ void *conv;
+ snd_pcm_channel_area_t *src_area = 0;
+ unsigned int srcidx;
+ char *src, *dst;
+ int src_step, dst_step;
+ for (srcidx = 0; srcidx < ttable->nsrcs; ++srcidx) {
+ src_area = &src_areas[ttable->srcs[srcidx].channel];
+ if (src_area->addr != NULL)
+ break;
+ }
+ if (srcidx == ttable->nsrcs) {
+ route1_zero(src_areas, src_offset, dst_area, dst_offset, frames, ttable, params);
+ return;
+ }
+
+#if 0
+ dst_area->enabled = 1;
+#endif
+ conv = conv_labels[params->conv_idx];
+ src = snd_pcm_channel_area_addr(src_area, src_offset);
+ dst = snd_pcm_channel_area_addr(dst_area, dst_offset);
+ src_step = snd_pcm_channel_area_step(src_area);
+ dst_step = snd_pcm_channel_area_step(dst_area);
+ while (frames-- > 0) {
+ goto *conv;
+#define CONV_END after
+#include "plugin_ops.h"
+#undef CONV_END
+ after:
+ src += src_step;
+ dst += dst_step;
+ }
+}
+
+static void route1_many(snd_pcm_channel_area_t *src_areas,
+ size_t src_offset,
+ snd_pcm_channel_area_t *dst_area,
+ size_t dst_offset,
+ size_t frames,
+ ttable_dst_t* ttable,
+ route_params_t *params)
+{
+#define GET_U_LABELS
+#define PUT_U32_LABELS
+#include "plugin_ops.h"
+#undef GET_U_LABELS
+#undef PUT_U32_LABELS
+ static void *zero_labels[3] = { &&zero_int32, &&zero_int64,
+#if ROUTE_PLUGIN_FLOAT
+ &&zero_float
+#endif
+ };
+ /* sum_type att */
+ static void *add_labels[3 * 2] = { &&add_int32_noatt, &&add_int32_att,
+ &&add_int64_noatt, &&add_int64_att,
+#if ROUTE_PLUGIN_FLOAT
+ &&add_float_noatt, &&add_float_att
+#endif
+ };
+ /* sum_type att shift */
+ static void *norm_labels[3 * 2 * 4] = { 0,
+ &&norm_int32_8_noatt,
+ &&norm_int32_16_noatt,
+ &&norm_int32_24_noatt,
+ 0,
+ &&norm_int32_8_att,
+ &&norm_int32_16_att,
+ &&norm_int32_24_att,
+ &&norm_int64_0_noatt,
+ &&norm_int64_8_noatt,
+ &&norm_int64_16_noatt,
+ &&norm_int64_24_noatt,
+ &&norm_int64_0_att,
+ &&norm_int64_8_att,
+ &&norm_int64_16_att,
+ &&norm_int64_24_att,
+#if ROUTE_PLUGIN_FLOAT
+ &&norm_float_0,
+ &&norm_float_8,
+ &&norm_float_16,
+ &&norm_float_24,
+ &&norm_float_0,
+ &&norm_float_8,
+ &&norm_float_16,
+ &&norm_float_24,
+#endif
+ };
+ void *zero, *get, *add, *norm, *put_u32;
+ int nsrcs = ttable->nsrcs;
+ char *dst;
+ int dst_step;
+ char *srcs[nsrcs];
+ int src_steps[nsrcs];
+ ttable_src_t src_tt[nsrcs];
+ u_int32_t sample = 0;
+ int srcidx, srcidx1 = 0;
+ for (srcidx = 0; srcidx < nsrcs; ++srcidx) {
+ snd_pcm_channel_area_t *src_area = &src_areas[ttable->srcs[srcidx].channel];
+#if 0
+ if (!src_area->enabled)
+ continue;
+#endif
+ srcs[srcidx1] = snd_pcm_channel_area_addr(src_area, src_offset);
+ src_steps[srcidx1] = snd_pcm_channel_area_step(src_area);
+ src_tt[srcidx1] = ttable->srcs[srcidx];
+ srcidx1++;
+ }
+ nsrcs = srcidx1;
+ if (nsrcs == 0) {
+ route1_zero(src_areas, src_offset, dst_area, dst_offset, frames, ttable, params);
+ return;
+ } else if (nsrcs == 1 && src_tt[0].as_int == ROUTE_PLUGIN_RESOLUTION) {
+ route1_one(src_areas, src_offset, dst_area, dst_offset, frames, ttable, params);
+ return;
+ }
+
+#if 0
+ dst_area->enabled = 1;
+#endif
+ zero = zero_labels[params->sum_idx];
+ get = get_u_labels[params->get_idx];
+ add = add_labels[params->sum_idx * 2 + ttable->att];
+ norm = norm_labels[params->sum_idx * 8 + ttable->att * 4 + 4 - params->src_size];
+ put_u32 = put_u32_labels[params->put_idx];
+ dst = snd_pcm_channel_area_addr(dst_area, dst_offset);
+ dst_step = snd_pcm_channel_area_step(dst_area);
+
+ while (frames-- > 0) {
+ ttable_src_t *ttp = src_tt;
+ sum_t sum;
+
+ /* Zero sum */
+ goto *zero;
+ zero_int32:
+ sum.as_uint32 = 0;
+ goto zero_end;
+ zero_int64:
+ sum.as_uint64 = 0;
+ goto zero_end;
+#if ROUTE_PLUGIN_FLOAT
+ zero_float:
+ sum.as_float = 0.0;
+ goto zero_end;
+#endif
+ zero_end:
+ for (srcidx = 0; srcidx < nsrcs; ++srcidx) {
+ char *src = srcs[srcidx];
+
+ /* Get sample */
+ goto *get;
+#define GET_U_END after_get
+#include "plugin_ops.h"
+#undef GET_U_END
+ after_get:
+
+ /* Sum */
+ goto *add;
+ add_int32_att:
+ sum.as_uint32 += sample * ttp->as_int;
+ goto after_sum;
+ add_int32_noatt:
+ if (ttp->as_int)
+ sum.as_uint32 += sample;
+ goto after_sum;
+ add_int64_att:
+ sum.as_uint64 += (u_int64_t) sample * ttp->as_int;
+ goto after_sum;
+ add_int64_noatt:
+ if (ttp->as_int)
+ sum.as_uint64 += sample;
+ goto after_sum;
+#if ROUTE_PLUGIN_FLOAT
+ add_float_att:
+ sum.as_float += sample * ttp->as_float;
+ goto after_sum;
+ add_float_noatt:
+ if (ttp->as_int)
+ sum.as_float += sample;
+ goto after_sum;
+#endif
+ after_sum:
+ srcs[srcidx] += src_steps[srcidx];
+ ttp++;
+ }
+
+ /* Normalization */
+ goto *norm;
+ norm_int32_8_att:
+ sum.as_uint64 = sum.as_uint32;
+ norm_int64_8_att:
+ sum.as_uint64 <<= 8;
+ norm_int64_0_att:
+ div(sum.as_uint64);
+ goto norm_int;
+
+ norm_int32_16_att:
+ sum.as_uint64 = sum.as_uint32;
+ norm_int64_16_att:
+ sum.as_uint64 <<= 16;
+ div(sum.as_uint64);
+ goto norm_int;
+
+ norm_int32_24_att:
+ sum.as_uint64 = sum.as_uint32;
+ norm_int64_24_att:
+ sum.as_uint64 <<= 24;
+ div(sum.as_uint64);
+ goto norm_int;
+
+ norm_int32_8_noatt:
+ sum.as_uint64 = sum.as_uint32;
+ norm_int64_8_noatt:
+ sum.as_uint64 <<= 8;
+ goto norm_int;
+
+ norm_int32_16_noatt:
+ sum.as_uint64 = sum.as_uint32;
+ norm_int64_16_noatt:
+ sum.as_uint64 <<= 16;
+ goto norm_int;
+
+ norm_int32_24_noatt:
+ sum.as_uint64 = sum.as_uint32;
+ norm_int64_24_noatt:
+ sum.as_uint64 <<= 24;
+ goto norm_int;
+
+ norm_int64_0_noatt:
+ norm_int:
+ if (sum.as_uint64 > (u_int32_t)0xffffffff)
+ sample = (u_int32_t)0xffffffff;
+ else
+ sample = sum.as_uint64;
+ goto after_norm;
+
+#if ROUTE_PLUGIN_FLOAT
+ norm_float_8:
+ sum.as_float *= 1 << 8;
+ goto norm_float;
+ norm_float_16:
+ sum.as_float *= 1 << 16;
+ goto norm_float;
+ norm_float_24:
+ sum.as_float *= 1 << 24;
+ goto norm_float;
+ norm_float_0:
+ norm_float:
+ sum.as_float = floor(sum.as_float + 0.5);
+ if (sum.as_float > (u_int32_t)0xffffffff)
+ sample = (u_int32_t)0xffffffff;
+ else
+ sample = sum.as_float;
+ goto after_norm;
+#endif
+ after_norm:
+
+ /* Put sample */
+ goto *put_u32;
+#define PUT_U32_END after_put_u32
+#include "plugin_ops.h"
+#undef PUT_U32_END
+ after_put_u32:
+
+ dst += dst_step;
+ }
+}
+
+static void route_transfer(snd_pcm_channel_area_t *src_areas,
+ size_t src_offset,
+ snd_pcm_channel_area_t *dst_areas,
+ size_t dst_offset,
+ size_t frames,
+ size_t dst_channels,
+ route_params_t *params)
+{
+ size_t dst_channel;
+ ttable_dst_t *dstp;
+ snd_pcm_channel_area_t *dst_area;
+
+ dstp = params->dsts;
+ dst_area = dst_areas;
+ for (dst_channel = 0; dst_channel < dst_channels; ++dst_channel) {
+ if (dst_channel >= params->ndsts)
+ route1_zero(src_areas, src_offset, dst_area, dst_offset, frames, dstp, params);
+ else
+ dstp->func(src_areas, src_offset, dst_area, dst_offset, frames, dstp, params);
+ dstp++;
+ dst_area++;
+ }
+}
+
+static int snd_pcm_route_close(snd_pcm_t *pcm)
+{
+ snd_pcm_route_t *route = pcm->private;
+ route_params_t *params = &route->params;
+ int err = 0;
+ size_t dst_channel;
+ if (route->plug.close_slave)
+ err = snd_pcm_close(route->plug.slave);
+ if (params->dsts) {
+ for (dst_channel = 0; dst_channel < params->ndsts; ++dst_channel) {
+ if (params->dsts[dst_channel].srcs != NULL)
+ free(params->dsts[dst_channel].srcs);
+ }
+ free(params->dsts);
+ }
+ free(route);
+ return 0;
+}
+
+static int snd_pcm_route_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t * info)
+{
+ snd_pcm_route_t *route = pcm->private;
+ unsigned int req_mask = info->req_mask;
+ unsigned int sfmt = info->req.format.sfmt;
+ unsigned int channels = info->req.format.channels;
+ int err;
+ if (req_mask & SND_PCM_PARAMS_SFMT &&
+ !snd_pcm_format_linear(sfmt)) {
+ info->req.fail_mask = SND_PCM_PARAMS_SFMT;
+ info->req.fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
+ return -EINVAL;
+ }
+ if (route->req_sformat >= 0) {
+ info->req_mask |= SND_PCM_PARAMS_SFMT;
+ info->req.format.sfmt = route->req_sformat;
+ }
+ if (route->req_schannels >= 0) {
+ info->req_mask |= SND_PCM_PARAMS_CHANNELS;
+ info->req.format.channels = route->req_schannels;
+ }
+ info->req_mask &= ~(SND_PCM_PARAMS_MMAP_SHAPE |
+ SND_PCM_PARAMS_XFER_MODE);
+ err = snd_pcm_params_info(route->plug.slave, info);
+ info->req_mask = req_mask;
+ info->req.format.sfmt = sfmt;
+ info->req.format.channels = channels;
+ if (err < 0)
+ return err;
+ if (req_mask & SND_PCM_PARAMS_SFMT)
+ info->formats = 1 << sfmt;
+ else
+ info->formats = SND_PCM_LINEAR_FORMATS;
+ if (req_mask & SND_PCM_PARAMS_CHANNELS) {
+ info->min_channels = channels;
+ info->max_channels = channels;
+ } else {
+ info->min_channels = 1;
+ info->max_channels = 1024;
+ }
+ info->flags &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
+ info->flags |= SND_PCM_INFO_INTERLEAVED | SND_PCM_INFO_NONINTERLEAVED;
+ return err;
+}
+
+static int snd_pcm_route_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
+{
+ snd_pcm_route_t *route = pcm->private;
+ snd_pcm_t *slave = route->plug.slave;
+ int err;
+ if (!snd_pcm_format_linear(params->format.sfmt)) {
+ params->fail_mask = SND_PCM_PARAMS_SFMT;
+ params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
+ return -EINVAL;
+ }
+ if (slave->mmap_data) {
+ err = snd_pcm_munmap_data(slave);
+ if (err < 0)
+ return err;
+ }
+ route->cformat = params->format.sfmt;
+ route->cchannels = params->format.channels;
+ route->cxfer_mode = params->xfer_mode;
+ route->cmmap_shape = params->mmap_shape;
+ if (route->req_sformat >= 0)
+ params->format.sfmt = route->req_sformat;
+ if (route->req_schannels >= 0)
+ params->format.channels = route->req_schannels;
+ params->xfer_mode = SND_PCM_XFER_UNSPECIFIED;
+ params->mmap_shape = SND_PCM_MMAP_UNSPECIFIED;;
+ err = snd_pcm_params(slave, params);
+ params->format.sfmt = route->cformat;
+ params->format.channels = route->cchannels;
+ params->xfer_mode = route->cxfer_mode;
+ params->mmap_shape = route->cmmap_shape;
+ if (slave->valid_setup) {
+ int r = snd_pcm_mmap_data(slave, NULL);
+ assert(r >= 0);
+ }
+ return err;
+}
+
+static int snd_pcm_route_setup(snd_pcm_t *pcm, snd_pcm_setup_t * setup)
+{
+ snd_pcm_route_t *route = pcm->private;
+ int src_format, dst_format;
+ int err = snd_pcm_setup(route->plug.slave, setup);
+ if (err < 0)
+ return err;
+ if (route->req_sformat >= 0)
+ assert(route->req_sformat == setup->format.sfmt);
+ route->sformat = setup->format.sfmt;
+ route->schannels = setup->format.channels;
+ if (route->cxfer_mode == SND_PCM_XFER_UNSPECIFIED)
+ setup->xfer_mode = SND_PCM_XFER_NONINTERLEAVED;
+ else
+ setup->xfer_mode = route->cxfer_mode;
+ if (route->cmmap_shape == SND_PCM_MMAP_UNSPECIFIED)
+ setup->mmap_shape = SND_PCM_MMAP_NONINTERLEAVED;
+ else
+ setup->mmap_shape = route->cmmap_shape;
+ setup->format.sfmt = route->cformat;
+ setup->format.channels = route->cchannels;
+ setup->mmap_bytes = 0;
+ if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
+ src_format = route->cformat;
+ dst_format = route->sformat;
+ } else {
+ src_format = route->sformat;
+ dst_format = route->cformat;
+ }
+ route->params.get_idx = getput_index(src_format);
+ route->params.put_idx = getput_index(dst_format);
+ route->params.conv_idx = conv_index(src_format, dst_format);
+ route->params.src_size = snd_pcm_format_width(src_format) / 8;
+ route->params.dst_sfmt = dst_format;
+#if ROUTE_PLUGIN_FLOAT
+ route->params.sum_idx = FLOAT;
+#else
+ if (src_size == 4)
+ route->params.sum_idx = UINT64;
+ else
+ route->params.sum_idx = UINT32;
+#endif
+ return 0;
+}
+
+static ssize_t snd_pcm_route_write_areas(snd_pcm_t *pcm,
+ snd_pcm_channel_area_t *areas,
+ size_t offset,
+ size_t size,
+ size_t *slave_sizep)
+{
+ snd_pcm_route_t *route = pcm->private;
+ snd_pcm_t *slave = route->plug.slave;
+ size_t xfer = 0;
+ ssize_t err = 0;
+ if (slave_sizep && *slave_sizep < size)
+ size = *slave_sizep;
+ assert(size > 0);
+ while (xfer < size) {
+ size_t frames = snd_pcm_mmap_playback_xfer(slave, size - xfer);
+ route_transfer(areas, offset,
+ slave->mmap_areas, snd_pcm_mmap_offset(slave),
+ frames, route->schannels, &route->params);
+ err = snd_pcm_mmap_forward(slave, frames);
+ if (err < 0)
+ break;
+ assert((size_t)err == frames);
+ offset += err;
+ xfer += err;
+ snd_pcm_mmap_hw_forward(pcm, err);
+ }
+ if (xfer > 0) {
+ if (slave_sizep)
+ *slave_sizep = xfer;
+ return xfer;
+ }
+ return err;
+}
+
+static int snd_pcm_route_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t * setup)
+{
+#if 0
+ snd_pcm_plugin_t *plugin = pcm->private;
+ int err;
+ err = snd_pcm_channel_setup(plugin->slave, setup);
+ if (err < 0)
+ return err;
+#endif
+ if (pcm->setup.mmap_shape == SND_PCM_MMAP_INTERLEAVED) {
+ setup->area.addr = pcm->mmap_data;
+ setup->area.first = setup->channel * pcm->bits_per_sample;
+ setup->area.step = pcm->bits_per_frame;
+ } else {
+ setup->area.addr = pcm->mmap_data + setup->channel * pcm->setup.buffer_size * pcm->bits_per_sample / 8;
+ setup->area.first = 0;
+ setup->area.step = pcm->bits_per_sample;
+ }
+ return 0;
+}
+
+static ssize_t snd_pcm_route_read_areas(snd_pcm_t *pcm,
+ snd_pcm_channel_area_t *areas,
+ size_t offset,
+ size_t size,
+ size_t *slave_sizep)
+{
+ snd_pcm_route_t *route = pcm->private;
+ snd_pcm_t *slave = route->plug.slave;
+ size_t xfer = 0;
+ ssize_t err = 0;
+ if (slave_sizep && *slave_sizep < size)
+ size = *slave_sizep;
+ assert(size > 0);
+ while (xfer < size) {
+ size_t frames = snd_pcm_mmap_capture_xfer(slave, size - xfer);
+ route_transfer(slave->mmap_areas, snd_pcm_mmap_offset(slave),
+ areas, offset,
+ frames, route->cchannels, &route->params);
+ err = snd_pcm_mmap_forward(slave, frames);
+ if (err < 0)
+ break;
+ assert((size_t)err == frames);
+ offset += err;
+ xfer += err;
+ snd_pcm_mmap_hw_forward(pcm, err);
+ }
+ if (xfer > 0) {
+ if (slave_sizep)
+ *slave_sizep = xfer;
+ return xfer;
+ }
+ return err;
+}
+
+static void snd_pcm_route_dump(snd_pcm_t *pcm, FILE *fp)
+{
+ snd_pcm_route_t *route = pcm->private;
+ unsigned int dst;
+ if (route->req_sformat < 0)
+ fprintf(fp, "Route conversion PCM\n");
+ else
+ fprintf(fp, "Route conversion PCM (sformat=%s)\n",
+ snd_pcm_format_name(route->req_sformat));
+ fputs("Transformation table:\n", fp);
+ for (dst = 0; dst < route->params.ndsts; dst++) {
+ ttable_dst_t *d = &route->params.dsts[dst];
+ unsigned int src;
+ if (d->nsrcs == 0)
+ continue;
+ fprintf(fp, "%d <- ", dst);
+ src = 0;
+ while (1) {
+ ttable_src_t *s = &d->srcs[src];
+ if (d->att)
+ fprintf(fp, "%d*%g", s->channel, s->as_float);
+ else
+ fprintf(fp, "%d", s->channel);
+ src++;
+ if (src == d->nsrcs)
+ break;
+ fputs(" + ", fp);
+ }
+ putc('\n', fp);
+ }
+ if (pcm->valid_setup) {
+ fprintf(fp, "Its setup is:\n");
+ snd_pcm_dump_setup(pcm, fp);
+ }
+ fprintf(fp, "Slave: ");
+ snd_pcm_dump(route->plug.slave, fp);
+}
+
+struct snd_pcm_ops snd_pcm_route_ops = {
+ close: snd_pcm_route_close,
+ info: snd_pcm_plugin_info,
+ params_info: snd_pcm_route_params_info,
+ params: snd_pcm_route_params,
+ setup: snd_pcm_route_setup,
+ channel_info: snd_pcm_plugin_channel_info,
+ channel_params: snd_pcm_plugin_channel_params,
+ channel_setup: snd_pcm_route_channel_setup,
+ dump: snd_pcm_route_dump,
+ nonblock: snd_pcm_plugin_nonblock,
+ mmap_status: snd_pcm_plugin_mmap_status,
+ mmap_control: snd_pcm_plugin_mmap_control,
+ mmap_data: snd_pcm_plugin_mmap_data,
+ munmap_status: snd_pcm_plugin_munmap_status,
+ munmap_control: snd_pcm_plugin_munmap_control,
+ munmap_data: snd_pcm_plugin_munmap_data,
+};
+
+int route_load_ttable(route_params_t *params, int stream,
+ unsigned int tt_ssize,
+ ttable_entry_t *ttable,
+ unsigned int tt_cused, unsigned int tt_sused)
+{
+ unsigned int src_channel, dst_channel;
+ ttable_dst_t *dptr;
+ unsigned int sused, dused, smul, dmul;
+ if (stream == SND_PCM_STREAM_PLAYBACK) {
+ sused = tt_cused;
+ dused = tt_sused;
+ smul = tt_ssize;
+ dmul = 1;
+ } else {
+ sused = tt_sused;
+ dused = tt_cused;
+ smul = 1;
+ dmul = tt_ssize;
+ }
+ params->ndsts = dused;
+ dptr = calloc(dused, sizeof(*params->dsts));
+ if (!dptr)
+ return -ENOMEM;
+ params->dsts = dptr;
+ for (dst_channel = 0; dst_channel < dused; ++dst_channel) {
+ ttable_entry_t t = 0;
+ int att = 0;
+ int nsrcs = 0;
+ ttable_src_t srcs[sused];
+ for (src_channel = 0; src_channel < sused; ++src_channel) {
+ ttable_entry_t v;
+ v = ttable[src_channel * smul + dst_channel * dmul];
+ assert(v >= 0 && v <= FULL);
+ if (v != 0) {
+ srcs[nsrcs].channel = src_channel;
+#if ROUTE_PLUGIN_FLOAT
+ /* Also in user space for non attenuated */
+ srcs[nsrcs].as_int = (v == FULL ? ROUTE_PLUGIN_RESOLUTION : 0);
+ srcs[nsrcs].as_float = v;
+#else
+ srcs[nsrcs].as_int = v;
+#endif
+ if (v != FULL)
+ att = 1;
+ t += v;
+ nsrcs++;
+ }
+ }
+#if 0
+ assert(t <= FULL);
+#endif
+ dptr->att = att;
+ dptr->nsrcs = nsrcs;
+ if (nsrcs == 0)
+ dptr->func = route1_zero;
+ else if (nsrcs == 1 && !att)
+ dptr->func = route1_one;
+ else
+ dptr->func = route1_many;
+ if (nsrcs > 0) {
+ dptr->srcs = calloc(nsrcs, sizeof(*srcs));
+ if (!dptr->srcs)
+ return -ENOMEM;
+ memcpy(dptr->srcs, srcs, sizeof(*srcs) * nsrcs);
+ } else
+ dptr->srcs = 0;
+ dptr++;
+ }
+ return 0;
+}
+
+
+int snd_pcm_route_open(snd_pcm_t **handlep,
+ int sformat, unsigned int schannels,
+ ttable_entry_t *ttable,
+ unsigned int tt_ssize,
+ unsigned int tt_cused, unsigned int tt_sused,
+ snd_pcm_t *slave, int close_slave)
+{
+ snd_pcm_t *handle;
+ snd_pcm_route_t *route;
+ int err;
+ assert(handlep && slave && ttable);
+ if (sformat >= 0 && snd_pcm_format_linear(sformat) != 1)
+ return -EINVAL;
+ route = calloc(1, sizeof(snd_pcm_route_t));
+ if (!route) {
+ return -ENOMEM;
+ }
+ route->req_sformat = sformat;
+ route->req_schannels = schannels;
+ route->plug.read = snd_pcm_route_read_areas;
+ route->plug.write = snd_pcm_route_write_areas;
+ route->plug.slave = slave;
+ route->plug.close_slave = close_slave;
+
+ handle = calloc(1, sizeof(snd_pcm_t));
+ if (!handle) {
+ free(route);
+ return -ENOMEM;
+ }
+ handle->type = SND_PCM_TYPE_ROUTE;
+ handle->stream = slave->stream;
+ handle->ops = &snd_pcm_route_ops;
+ handle->op_arg = handle;
+ handle->fast_ops = &snd_pcm_plugin_fast_ops;
+ handle->fast_op_arg = handle;
+ handle->mode = slave->mode;
+ handle->private = route;
+ err = snd_pcm_init(handle);
+ if (err < 0) {
+ snd_pcm_close(handle);
+ return err;
+ }
+ err = route_load_ttable(&route->params, handle->stream, tt_ssize, ttable, tt_cused, tt_sused);
+ if (err < 0) {
+ snd_pcm_close(handle);
+ return err;
+ }
+ *handlep = handle;
+
+ return 0;
+}
+
+int snd_pcm_route_load_ttable(snd_config_t *tt, ttable_entry_t *ttable,
+ unsigned int tt_csize, unsigned int tt_ssize,
+ unsigned int *tt_cused, unsigned int *tt_sused,
+ int schannels)
+{
+ int cused = -1;
+ int sused = -1;
+ snd_config_iterator_t i;
+ unsigned int k;
+ for (k = 0; k < tt_csize * tt_ssize; ++k)
+ ttable[k] = 0.0;
+ snd_config_foreach(i, tt) {
+ snd_config_t *in = snd_config_entry(i);
+ snd_config_iterator_t j;
+ char *p;
+ long cchannel;
+ errno = 0;
+ cchannel = strtol(in->id, &p, 10);
+ if (errno || *p ||
+ cchannel < 0 || (unsigned int) cchannel > tt_csize)
+ return -EINVAL;
+ if (snd_config_type(in) != SND_CONFIG_TYPE_COMPOUND)
+ return -EINVAL;
+ snd_config_foreach(j, in) {
+ snd_config_t *jn = snd_config_entry(j);
+ double value;
+ long schannel;
+ int err;
+ errno = 0;
+ schannel = strtol(jn->id, &p, 10);
+ if (errno || *p ||
+ schannel < 0 || (unsigned int) schannel > tt_ssize ||
+ (schannels > 0 && schannel >= schannels))
+ return -EINVAL;
+ err = snd_config_real_get(jn, &value);
+ if (err < 0) {
+ long v;
+ err = snd_config_integer_get(jn, &v);
+ if (err < 0)
+ return -EINVAL;
+ value = v;
+ }
+ ttable[cchannel * tt_ssize + schannel] = value;
+ if (schannel > sused)
+ sused = schannel;
+ }
+ if (cchannel > cused)
+ cused = cchannel;
+ }
+ *tt_sused = sused + 1;
+ *tt_cused = cused + 1;
+ return 0;
+}
+
+#define MAX_CHANNELS 32
+
+int _snd_pcm_route_open(snd_pcm_t **pcmp, char *name,
+ snd_config_t *conf,
+ int stream, int mode)
+{
+ snd_config_iterator_t i;
+ char *sname = NULL;
+ int err;
+ snd_pcm_t *spcm;
+ int sformat = -1;
+ long schannels = -1;
+ snd_config_t *tt = NULL;
+ ttable_entry_t ttable[MAX_CHANNELS*MAX_CHANNELS];
+ unsigned int cused, sused;
+ snd_config_foreach(i, conf) {
+ snd_config_t *n = snd_config_entry(i);
+ if (strcmp(n->id, "comment") == 0)
+ continue;
+ if (strcmp(n->id, "type") == 0)
+ continue;
+ if (strcmp(n->id, "stream") == 0)
+ continue;
+ if (strcmp(n->id, "sname") == 0) {
+ err = snd_config_string_get(n, &sname);
+ if (err < 0)
+ return -EINVAL;
+ continue;
+ }
+ if (strcmp(n->id, "sformat") == 0) {
+ char *f;
+ err = snd_config_string_get(n, &f);
+ if (err < 0)
+ return -EINVAL;
+ sformat = snd_pcm_format_value(f);
+ if (sformat < 0)
+ return -EINVAL;
+ if (snd_pcm_format_linear(sformat) != 1)
+ return -EINVAL;
+ continue;
+ }
+ if (strcmp(n->id, "schannels") == 0) {
+ err = snd_config_integer_get(n, &schannels);
+ if (err < 0)
+ return -EINVAL;
+ continue;
+ }
+ if (strcmp(n->id, "ttable") == 0) {
+ if (snd_config_type(n) != SND_CONFIG_TYPE_COMPOUND)
+ return -EINVAL;
+ tt = n;
+ continue;
+ }
+ return -EINVAL;
+ }
+ if (!sname || !tt)
+ return -EINVAL;
+
+ err = snd_pcm_route_load_ttable(tt, ttable, MAX_CHANNELS, MAX_CHANNELS,
+ &cused, &sused, schannels);
+ if (err < 0)
+ return err;
+
+ /* This is needed cause snd_config_update may destroy config */
+ sname = strdup(sname);
+ if (!sname)
+ return -ENOMEM;
+ err = snd_pcm_open(&spcm, sname, stream, mode);
+ free(sname);
+ if (err < 0)
+ return err;
+ err = snd_pcm_route_open(pcmp, sformat, schannels,
+ ttable, MAX_CHANNELS,
+ cused, sused,
+ spcm, 1);
+ if (err < 0)
+ snd_pcm_close(spcm);
+ return err;
+}
+
+
diff --git a/src/pcm/plugin/Makefile.am b/src/pcm/plugin/Makefile.am
deleted file mode 100644
index 5d79297e..00000000
--- a/src/pcm/plugin/Makefile.am
+++ /dev/null
@@ -1,8 +0,0 @@
-EXTRA_LTLIBRARIES = libpcmplugin.la
-
-libpcmplugin_la_SOURCES = io.c mmap.c copy.c linear.c \
- mulaw.c alaw.c adpcm.c rate.c route.c
-all: libpcmplugin.la
-
-
-INCLUDES=-I$(top_srcdir)/include
diff --git a/src/pcm/plugin/adpcm.c b/src/pcm/plugin/adpcm.c
deleted file mode 100644
index efac226b..00000000
--- a/src/pcm/plugin/adpcm.c
+++ /dev/null
@@ -1,417 +0,0 @@
-/*
- * Ima-ADPCM conversion Plug-In Interface
- * Copyright (c) 1999 by Uros Bizjak <uros@kss-loka.si>
- * Jaroslav Kysela <perex@suse.cz>
- *
- * Based on Version 1.2, 18-Dec-92 implementation of Intel/DVI ADPCM code
- * by Jack Jansen, CWI, Amsterdam <Jack.Jansen@cwi.nl>, Copyright 1992
- * by Stichting Mathematisch Centrum, Amsterdam, The Netherlands.
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Library General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-/*
-These routines convert 16 bit linear PCM samples to 4 bit ADPCM code
-and vice versa. The ADPCM code used is the Intel/DVI ADPCM code which
-is being recommended by the IMA Digital Audio Technical Working Group.
-
-The algorithm for this coder was taken from:
-Proposal for Standardized Audio Interstreamge Formats,
-IMA compatability project proceedings, Vol 2, Issue 2, May 1992.
-
-- No, this is *not* a G.721 coder/decoder. The algorithm used by G.721
- is very complicated, requiring oodles of floating-point ops per
- sample (resulting in very poor performance). I have not done any
- tests myself but various people have assured my that 721 quality is
- actually lower than DVI quality.
-
-- No, it probably isn't a RIFF ADPCM decoder either. Trying to decode
- RIFF ADPCM with these routines seems to result in something
- recognizable but very distorted.
-
-- No, it is not a CDROM-XA coder either, as far as I know. I haven't
- come across a good description of XA yet.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <byteswap.h>
-#include "../pcm_local.h"
-
-/* First table lookup for Ima-ADPCM quantizer */
-static char IndexAdjust[8] = { -1, -1, -1, -1, 2, 4, 6, 8 };
-
-/* Second table lookup for Ima-ADPCM quantizer */
-static short StepSize[89] = {
- 7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
- 19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
- 50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
- 130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
- 337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
- 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
- 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
- 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
- 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
-};
-
-typedef struct {
- int pred_val; /* Calculated predicted value */
- int step_idx; /* Previous StepSize lookup index */
-} adpcm_channel_t;
-
-typedef void (*adpcm_f)(snd_pcm_plugin_t *plugin,
- const snd_pcm_plugin_channel_t *src_channels,
- snd_pcm_plugin_channel_t *dst_channels,
- size_t frames);
-
-typedef struct adpcm_private_data {
- adpcm_f func;
- int conv;
- adpcm_channel_t channels[0];
-} adpcm_t;
-
-
-static void adpcm_init(snd_pcm_plugin_t *plugin)
-{
- unsigned int channel;
- adpcm_t *data = (adpcm_t *)plugin->extra_data;
- for (channel = 0; channel < plugin->src_format.channels; channel++) {
- adpcm_channel_t *v = &data->channels[channel];
- v->pred_val = 0;
- v->step_idx = 0;
- }
-}
-
-static char adpcm_encoder(int sl, adpcm_channel_t * state)
-{
- short diff; /* Difference between sl and predicted sample */
- short pred_diff; /* Predicted difference to next sample */
-
- unsigned char sign; /* sign of diff */
- short step; /* holds previous StepSize value */
- unsigned char adjust_idx; /* Index to IndexAdjust lookup table */
-
- int i;
-
- /* Compute difference to previous predicted value */
- diff = sl - state->pred_val;
- sign = (diff < 0) ? 0x8 : 0x0;
- if (sign) {
- diff = -diff;
- }
-
- /*
- * This code *approximately* computes:
- * adjust_idx = diff * 4 / step;
- * pred_diff = (adjust_idx + 0.5) * step / 4;
- *
- * But in shift step bits are dropped. The net result of this is
- * that even if you have fast mul/div hardware you cannot put it to
- * good use since the fixup would be too expensive.
- */
-
- step = StepSize[state->step_idx];
-
- /* Divide and clamp */
- pred_diff = step >> 3;
- for (adjust_idx = 0, i = 0x4; i; i >>= 1, step >>= 1) {
- if (diff >= step) {
- adjust_idx |= i;
- diff -= step;
- pred_diff += step;
- }
- }
-
- /* Update and clamp previous predicted value */
- state->pred_val += sign ? -pred_diff : pred_diff;
-
- if (state->pred_val > 32767) {
- state->pred_val = 32767;
- } else if (state->pred_val < -32768) {
- state->pred_val = -32768;
- }
-
- /* Update and clamp StepSize lookup table index */
- state->step_idx += IndexAdjust[adjust_idx];
-
- if (state->step_idx < 0) {
- state->step_idx = 0;
- } else if (state->step_idx > 88) {
- state->step_idx = 88;
- }
- return (sign | adjust_idx);
-}
-
-
-static int adpcm_decoder(unsigned char code, adpcm_channel_t * state)
-{
- short pred_diff; /* Predicted difference to next sample */
- short step; /* holds previous StepSize value */
- char sign;
-
- int i;
-
- /* Separate sign and magnitude */
- sign = code & 0x8;
- code &= 0x7;
-
- /*
- * Computes pred_diff = (code + 0.5) * step / 4,
- * but see comment in adpcm_coder.
- */
-
- step = StepSize[state->step_idx];
-
- /* Compute difference and new predicted value */
- pred_diff = step >> 3;
- for (i = 0x4; i; i >>= 1, step >>= 1) {
- if (code & i) {
- pred_diff += step;
- }
- }
- state->pred_val += (sign) ? -pred_diff : pred_diff;
-
- /* Clamp output value */
- if (state->pred_val > 32767) {
- state->pred_val = 32767;
- } else if (state->pred_val < -32768) {
- state->pred_val = -32768;
- }
-
- /* Find new StepSize index value */
- state->step_idx += IndexAdjust[code];
-
- if (state->step_idx < 0) {
- state->step_idx = 0;
- } else if (state->step_idx > 88) {
- state->step_idx = 88;
- }
- return (state->pred_val);
-}
-
-/*
- * Basic Ima-ADPCM plugin
- */
-
-static void adpcm_decode(snd_pcm_plugin_t *plugin,
- const snd_pcm_plugin_channel_t *src_channels,
- snd_pcm_plugin_channel_t *dst_channels,
- size_t frames)
-{
-#define PUT_S16_LABELS
-#include "plugin_ops.h"
-#undef PUT_S16_LABELS
- adpcm_t *data = (adpcm_t *)plugin->extra_data;
- void *put = put_s16_labels[data->conv];
- int channel;
- int nchannels = plugin->src_format.channels;
- for (channel = 0; channel < nchannels; ++channel) {
- char *src;
- int srcbit;
- char *dst;
- int src_step, srcbit_step, dst_step;
- size_t frames1;
- adpcm_channel_t *state;
- if (!src_channels[channel].enabled) {
- if (dst_channels[channel].wanted)
- snd_pcm_area_silence(&dst_channels[channel].area, 0, frames, plugin->dst_format.format);
- dst_channels[channel].enabled = 0;
- continue;
- }
- dst_channels[channel].enabled = 1;
- src = src_channels[channel].area.addr + src_channels[channel].area.first / 8;
- srcbit = src_channels[channel].area.first % 8;
- dst = dst_channels[channel].area.addr + dst_channels[channel].area.first / 8;
- src_step = src_channels[channel].area.step / 8;
- srcbit_step = src_channels[channel].area.step % 8;
- dst_step = dst_channels[channel].area.step / 8;
- state = &data->channels[channel];
- frames1 = frames;
- while (frames1-- > 0) {
- signed short sample;
- int v;
- if (srcbit)
- v = *src & 0x0f;
- else
- v = (*src >> 4) & 0x0f;
- sample = adpcm_decoder(v, state);
- goto *put;
-#define PUT_S16_END after
-#include "plugin_ops.h"
-#undef PUT_S16_END
- after:
- src += src_step;
- srcbit += srcbit_step;
- if (srcbit == 8) {
- src++;
- srcbit = 0;
- }
- dst += dst_step;
- }
- }
-}
-
-static void adpcm_encode(snd_pcm_plugin_t *plugin,
- const snd_pcm_plugin_channel_t *src_channels,
- snd_pcm_plugin_channel_t *dst_channels,
- size_t frames)
-{
-#define GET_S16_LABELS
-#include "plugin_ops.h"
-#undef GET_S16_LABELS
- adpcm_t *data = (adpcm_t *)plugin->extra_data;
- void *get = get_s16_labels[data->conv];
- int channel;
- int nchannels = plugin->src_format.channels;
- signed short sample = 0;
- for (channel = 0; channel < nchannels; ++channel) {
- char *src;
- char *dst;
- int dstbit;
- int src_step, dst_step, dstbit_step;
- size_t frames1;
- adpcm_channel_t *state;
- if (!src_channels[channel].enabled) {
- if (dst_channels[channel].wanted)
- snd_pcm_area_silence(&dst_channels[channel].area, 0, frames, plugin->dst_format.format);
- dst_channels[channel].enabled = 0;
- continue;
- }
- dst_channels[channel].enabled = 1;
- src = src_channels[channel].area.addr + src_channels[channel].area.first / 8;
- dst = dst_channels[channel].area.addr + dst_channels[channel].area.first / 8;
- dstbit = dst_channels[channel].area.first % 8;
- src_step = src_channels[channel].area.step / 8;
- dst_step = dst_channels[channel].area.step / 8;
- dstbit_step = dst_channels[channel].area.step % 8;
- state = &data->channels[channel];
- frames1 = frames;
- while (frames1-- > 0) {
- int v;
- goto *get;
-#define GET_S16_END after
-#include "plugin_ops.h"
-#undef GET_S16_END
- after:
- v = adpcm_encoder(sample, state);
- if (dstbit)
- *dst = (*dst & 0xf0) | v;
- else
- *dst = (*dst & 0x0f) | (v << 4);
- src += src_step;
- dst += dst_step;
- dstbit += dstbit_step;
- if (dstbit == 8) {
- dst++;
- dstbit = 0;
- }
- }
- }
-}
-
-static ssize_t adpcm_transfer(snd_pcm_plugin_t *plugin,
- const snd_pcm_plugin_channel_t *src_channels,
- snd_pcm_plugin_channel_t *dst_channels,
- size_t frames)
-{
- adpcm_t *data;
- unsigned int channel;
-
- assert(plugin && src_channels && dst_channels);
- if (frames == 0)
- return 0;
- for (channel = 0; channel < plugin->src_format.channels; channel++) {
- if (plugin->src_format.format == SND_PCM_SFMT_IMA_ADPCM) {
- assert(src_channels[channel].area.first % 4 == 0 &&
- src_channels[channel].area.step % 4 == 0 &&
- dst_channels[channel].area.first % 8 == 0 &&
- dst_channels[channel].area.step % 8 == 0);
- } else {
- assert(src_channels[channel].area.first % 8 == 0 &&
- src_channels[channel].area.step % 8 == 0 &&
- dst_channels[channel].area.first % 4 == 0 &&
- dst_channels[channel].area.step % 4 == 0);
- }
- }
- data = (adpcm_t *)plugin->extra_data;
- data->func(plugin, src_channels, dst_channels, frames);
- return frames;
-}
-
-static int adpcm_action(snd_pcm_plugin_t * plugin,
- snd_pcm_plugin_action_t action,
- unsigned long udata ATTRIBUTE_UNUSED)
-{
- assert(plugin);
- switch (action) {
- case INIT:
- case PREPARE:
- case DRAIN:
- case FLUSH:
- adpcm_init(plugin);
- break;
- default:
- break;
- }
- return 0; /* silenty ignore other actions */
-}
-
-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 err;
- struct adpcm_private_data *data;
- snd_pcm_plugin_t *plugin;
- snd_pcm_format_t *format;
- adpcm_f func;
-
- assert(r_plugin);
- *r_plugin = NULL;
-
- assert(src_format->rate == dst_format->rate);
- assert(src_format->channels == dst_format->channels);
-
- if (dst_format->format == SND_PCM_SFMT_IMA_ADPCM) {
- format = src_format;
- func = adpcm_encode;
- }
- else if (src_format->format == SND_PCM_SFMT_IMA_ADPCM) {
- format = dst_format;
- func = adpcm_decode;
- }
- else
- assert(0);
- assert(snd_pcm_format_linear(format->format));
-
- err = snd_pcm_plugin_build(plug, "Ima-ADPCM<->linear conversion",
- src_format, dst_format,
- sizeof(adpcm_t) + src_format->channels * sizeof(adpcm_channel_t),
- &plugin);
- if (err < 0)
- return err;
- data = (adpcm_t *)plugin->extra_data;
- data->func = func;
- data->conv = getput_index(format->format);
- plugin->transfer = adpcm_transfer;
- plugin->action = adpcm_action;
- *r_plugin = plugin;
- return 0;
-}
diff --git a/src/pcm/plugin/alaw.c b/src/pcm/plugin/alaw.c
deleted file mode 100644
index b563b01b..00000000
--- a/src/pcm/plugin/alaw.c
+++ /dev/null
@@ -1,291 +0,0 @@
-/*
- * A-Law conversion Plug-In Interface
- * Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>
- * Uros Bizjak <uros@kss-loka.si>
- *
- * Based on reference implementation by Sun Microsystems, Inc.
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Library General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <byteswap.h>
-#include <sys/uio.h>
-#include "../pcm_local.h"
-
-#define SIGN_BIT (0x80) /* Sign bit for a A-law byte. */
-#define QUANT_MASK (0xf) /* Quantization field mask. */
-#define NSEGS (8) /* Number of A-law segments. */
-#define SEG_SHIFT (4) /* Left shift for segment number. */
-#define SEG_MASK (0x70) /* Segment field mask. */
-
-static short alaw_seg_end[8] = {0xFF, 0x1FF, 0x3FF, 0x7FF,
- 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF};
-
-static inline int search(int val, short *table, int size)
-{
- int i;
-
- for (i = 0; i < size; i++) {
- if (val <= *table++)
- return (i);
- }
- return (size);
-}
-
-/*
- * linear2alaw() - Convert a 16-bit linear PCM value to 8-bit A-law
- *
- * linear2alaw() accepts an 16-bit integer and encodes it as A-law data.
- *
- * Linear Input Code Compressed Code
- * ------------------------ ---------------
- * 0000000wxyza 000wxyz
- * 0000001wxyza 001wxyz
- * 000001wxyzab 010wxyz
- * 00001wxyzabc 011wxyz
- * 0001wxyzabcd 100wxyz
- * 001wxyzabcde 101wxyz
- * 01wxyzabcdef 110wxyz
- * 1wxyzabcdefg 111wxyz
- *
- * For further information see John C. Bellamy's Digital Telephony, 1982,
- * John Wiley & Sons, pps 98-111 and 472-476.
- */
-static unsigned char linear2alaw(int pcm_val) /* 2's complement (16-bit range) */
-{
- int mask;
- int seg;
- unsigned char aval;
-
- if (pcm_val >= 0) {
- mask = 0xD5; /* sign (7th) bit = 1 */
- } else {
- mask = 0x55; /* sign bit = 0 */
- pcm_val = -pcm_val - 8;
- }
-
- /* Convert the scaled magnitude to segment number. */
- seg = search(pcm_val, alaw_seg_end, NSEGS);
-
- /* Combine the sign, segment, and quantization bits. */
-
- if (seg >= 8) /* out of range, return maximum value. */
- return (0x7F ^ mask);
- else {
- aval = seg << SEG_SHIFT;
- if (seg < 2)
- aval |= (pcm_val >> 4) & QUANT_MASK;
- else
- aval |= (pcm_val >> (seg + 3)) & QUANT_MASK;
- return (aval ^ mask);
- }
-}
-
-/*
- * alaw2linear() - Convert an A-law value to 16-bit linear PCM
- *
- */
-static int alaw2linear(unsigned char a_val)
-{
- int t;
- int seg;
-
- a_val ^= 0x55;
-
- t = (a_val & QUANT_MASK) << 4;
- seg = ((unsigned)a_val & SEG_MASK) >> SEG_SHIFT;
- switch (seg) {
- case 0:
- t += 8;
- break;
- case 1:
- t += 0x108;
- break;
- default:
- t += 0x108;
- t <<= seg - 1;
- }
- return ((a_val & SIGN_BIT) ? t : -t);
-}
-
-
-/*
- * Basic A-Law plugin
- */
-
-typedef void (*alaw_f)(snd_pcm_plugin_t *plugin,
- const snd_pcm_plugin_channel_t *src_channels,
- snd_pcm_plugin_channel_t *dst_channels,
- size_t frames);
-
-typedef struct alaw_private_data {
- alaw_f func;
- int conv;
-} alaw_t;
-
-static void alaw_decode(snd_pcm_plugin_t *plugin,
- const snd_pcm_plugin_channel_t *src_channels,
- snd_pcm_plugin_channel_t *dst_channels,
- size_t frames)
-{
-#define PUT_S16_LABELS
-#include "plugin_ops.h"
-#undef PUT_S16_LABELS
- alaw_t *data = (alaw_t *)plugin->extra_data;
- void *put = put_s16_labels[data->conv];
- int channel;
- int nchannels = plugin->src_format.channels;
- for (channel = 0; channel < nchannels; ++channel) {
- char *src;
- char *dst;
- int src_step, dst_step;
- size_t frames1;
- if (!src_channels[channel].enabled) {
- if (dst_channels[channel].wanted)
- snd_pcm_area_silence(&dst_channels[channel].area, 0, frames, plugin->dst_format.format);
- dst_channels[channel].enabled = 0;
- continue;
- }
- dst_channels[channel].enabled = 1;
- src = src_channels[channel].area.addr + src_channels[channel].area.first / 8;
- dst = dst_channels[channel].area.addr + dst_channels[channel].area.first / 8;
- src_step = src_channels[channel].area.step / 8;
- dst_step = dst_channels[channel].area.step / 8;
- frames1 = frames;
- while (frames1-- > 0) {
- signed short sample = alaw2linear(*src);
- goto *put;
-#define PUT_S16_END after
-#include "plugin_ops.h"
-#undef PUT_S16_END
- after:
- src += src_step;
- dst += dst_step;
- }
- }
-}
-
-static void alaw_encode(snd_pcm_plugin_t *plugin,
- const snd_pcm_plugin_channel_t *src_channels,
- snd_pcm_plugin_channel_t *dst_channels,
- size_t frames)
-{
-#define GET_S16_LABELS
-#include "plugin_ops.h"
-#undef GET_S16_LABELS
- alaw_t *data = (alaw_t *)plugin->extra_data;
- void *get = get_s16_labels[data->conv];
- int channel;
- int nchannels = plugin->src_format.channels;
- signed short sample = 0;
- for (channel = 0; channel < nchannels; ++channel) {
- char *src;
- char *dst;
- int src_step, dst_step;
- size_t frames1;
- if (!src_channels[channel].enabled) {
- if (dst_channels[channel].wanted)
- snd_pcm_area_silence(&dst_channels[channel].area, 0, frames, plugin->dst_format.format);
- dst_channels[channel].enabled = 0;
- continue;
- }
- dst_channels[channel].enabled = 1;
- src = src_channels[channel].area.addr + src_channels[channel].area.first / 8;
- dst = dst_channels[channel].area.addr + dst_channels[channel].area.first / 8;
- src_step = src_channels[channel].area.step / 8;
- dst_step = dst_channels[channel].area.step / 8;
- frames1 = frames;
- while (frames1-- > 0) {
- goto *get;
-#define GET_S16_END after
-#include "plugin_ops.h"
-#undef GET_S16_END
- after:
- *dst = linear2alaw(sample);
- src += src_step;
- dst += dst_step;
- }
- }
-}
-
-static ssize_t alaw_transfer(snd_pcm_plugin_t *plugin,
- const snd_pcm_plugin_channel_t *src_channels,
- snd_pcm_plugin_channel_t *dst_channels,
- size_t frames)
-{
- alaw_t *data;
- unsigned int channel;
-
- assert(plugin && src_channels && dst_channels);
- if (frames == 0)
- return 0;
- for (channel = 0; channel < plugin->src_format.channels; channel++) {
- assert(src_channels[channel].area.first % 8 == 0 &&
- src_channels[channel].area.step % 8 == 0);
- assert(dst_channels[channel].area.first % 8 == 0 &&
- dst_channels[channel].area.step % 8 == 0);
- }
- data = (alaw_t *)plugin->extra_data;
- data->func(plugin, src_channels, dst_channels, frames);
- return frames;
-}
-
-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 err;
- alaw_t *data;
- snd_pcm_plugin_t *plugin;
- snd_pcm_format_t *format;
- alaw_f func;
-
- assert(r_plugin);
- *r_plugin = NULL;
-
- assert(src_format->rate == dst_format->rate);
- assert(src_format->channels == dst_format->channels);
-
- if (dst_format->format == SND_PCM_SFMT_A_LAW) {
- format = src_format;
- func = alaw_encode;
- }
- else if (src_format->format == SND_PCM_SFMT_A_LAW) {
- format = dst_format;
- func = alaw_decode;
- }
- else
- assert(0);
- assert(snd_pcm_format_linear(format->format));
-
- err = snd_pcm_plugin_build(plug, "A-Law<->linear conversion",
- src_format, dst_format,
- sizeof(alaw_t), &plugin);
- if (err < 0)
- return err;
- data = (alaw_t*)plugin->extra_data;
- data->func = func;
- data->conv = getput_index(format->format);
- plugin->transfer = alaw_transfer;
- *r_plugin = plugin;
- return 0;
-}
diff --git a/src/pcm/plugin/copy.c b/src/pcm/plugin/copy.c
deleted file mode 100644
index de4762dd..00000000
--- a/src/pcm/plugin/copy.c
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Linear conversion Plug-In
- * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
- *
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Library General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#ifdef __KERNEL__
-#include "../../include/driver.h"
-#include "../../include/pcm.h"
-#include "../../include/pcm_plugin.h"
-#else
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <byteswap.h>
-#include <sys/uio.h>
-#include "../pcm_local.h"
-#endif
-
-static ssize_t copy_transfer(snd_pcm_plugin_t *plugin,
- const snd_pcm_plugin_channel_t *src_channels,
- snd_pcm_plugin_channel_t *dst_channels,
- size_t frames)
-{
- unsigned int channel;
- unsigned int nchannels;
-
- assert(plugin && src_channels && dst_channels);
- if (frames == 0)
- return 0;
- nchannels = plugin->src_format.channels;
- for (channel = 0; channel < nchannels; channel++) {
- assert(src_channels->area.first % 8 == 0 &&
- src_channels->area.step % 8 == 0);
- assert(dst_channels->area.first % 8 == 0 &&
- dst_channels->area.step % 8 == 0);
- if (!src_channels->enabled) {
- if (dst_channels->wanted)
- snd_pcm_area_silence(&dst_channels->area, 0, frames, plugin->dst_format.format);
- dst_channels->enabled = 0;
- continue;
- }
- dst_channels->enabled = 1;
- snd_pcm_area_copy(&src_channels->area, 0, &dst_channels->area, 0, frames, plugin->src_format.format);
- src_channels++;
- dst_channels++;
- }
- return frames;
-}
-
-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)
-{
- int err;
- snd_pcm_plugin_t *plugin;
- int width;
-
- assert(r_plugin);
- *r_plugin = NULL;
-
- assert(src_format->format == dst_format->format);
- assert(src_format->rate == dst_format->rate);
- assert(src_format->channels == dst_format->channels);
-
- width = snd_pcm_format_physical_width(src_format->format);
- assert(width > 0);
-
- err = snd_pcm_plugin_build(plug, "copy", src_format, dst_format,
- 0, &plugin);
- if (err < 0)
- return err;
- plugin->transfer = copy_transfer;
- *r_plugin = plugin;
- return 0;
-}
diff --git a/src/pcm/plugin/io.c b/src/pcm/plugin/io.c
deleted file mode 100644
index 6ef33cdd..00000000
--- a/src/pcm/plugin/io.c
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * PCM I/O Plug-In Interface
- * Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>
- *
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Library General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#ifdef __KERNEL__
-#include "../../include/driver.h"
-#include "../../include/pcm.h"
-#include "../../include/pcm_plugin.h"
-#define pcm_write(plug,buf,count) snd_pcm_oss_write3(plug,buf,count,1)
-#define pcm_writev(plug,vec,count) snd_pcm_oss_writev3(plug,vec,count,1)
-#define pcm_read(plug,buf,count) snd_pcm_oss_read3(plug,buf,count,1)
-#define pcm_readv(plug,vec,count) snd_pcm_oss_readv3(plug,vec,count,1)
-#else
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <sys/uio.h>
-#include "../pcm_local.h"
-#define pcm_write(plug,buf,count) snd_pcm_write(plug->slave,buf,count)
-#define pcm_writev(plug,vec,count) snd_pcm_writev(plug->slave,vec,count)
-#define pcm_read(plug,buf,count) snd_pcm_read(plug->slave,buf,count)
-#define pcm_readv(plug,vec,count) snd_pcm_readv(plug->slave,vec,count)
-#endif
-
-/*
- * Basic io plugin
- */
-
-static ssize_t io_playback_transfer(snd_pcm_plugin_t *plugin,
- const snd_pcm_plugin_channel_t *src_channels,
- snd_pcm_plugin_channel_t *dst_channels ATTRIBUTE_UNUSED,
- size_t frames)
-{
- struct iovec *vec;
- int count, channel;
-
- assert(plugin);
- vec = (struct iovec *)plugin->extra_data;
- assert(vec);
- assert(src_channels);
- count = plugin->src_format.channels;
- if (plugin->src_format.interleave) {
- return pcm_write(plugin->plug, src_channels->area.addr, frames);
- } else {
- for (channel = 0; channel < count; channel++) {
- if (src_channels[channel].enabled)
- vec[channel].iov_base = src_channels[channel].area.addr;
- else
- vec[channel].iov_base = 0;
- vec[channel].iov_len = frames;
- }
- return pcm_writev(plugin->plug, vec, count);
- }
-}
-
-static ssize_t io_capture_transfer(snd_pcm_plugin_t *plugin,
- const snd_pcm_plugin_channel_t *src_channels ATTRIBUTE_UNUSED,
- snd_pcm_plugin_channel_t *dst_channels,
- size_t frames)
-{
- struct iovec *vec;
- int count, channel;
-
- assert(plugin);
- vec = (struct iovec *)plugin->extra_data;
- assert(vec);
- assert(dst_channels);
- count = plugin->dst_format.channels;
- if (plugin->dst_format.interleave) {
- return pcm_read(plugin->plug, dst_channels->area.addr, frames);
- } else {
- for (channel = 0; channel < count; channel++) {
- if (dst_channels[channel].enabled)
- vec[channel].iov_base = dst_channels[channel].area.addr;
- else
- vec[channel].iov_base = 0;
- vec[channel].iov_len = frames;
- }
- return pcm_readv(plugin->plug, vec, count);
- }
- return 0;
-}
-
-static ssize_t io_src_channels(snd_pcm_plugin_t *plugin,
- size_t frames,
- snd_pcm_plugin_channel_t **channels)
-{
- int err;
- unsigned int channel;
- snd_pcm_plugin_channel_t *v;
- err = snd_pcm_plugin_client_channels(plugin, frames, &v);
- if (err < 0)
- return err;
- *channels = v;
- if (plugin->src_format.interleave) {
- for (channel = 0; channel < plugin->src_format.channels; ++channel, ++v)
- v->wanted = 1;
- }
- return frames;
-}
-
-#ifndef __KERNEL__
-static void io_dump(snd_pcm_plugin_t *plugin, FILE *fp)
-{
- snd_pcm_t *slave = plugin->plug->slave;
- if (slave->valid_setup) {
- fprintf(fp, "Slave: ");
- snd_pcm_dump(slave, fp);
- }
-}
-#endif
-
-int snd_pcm_plugin_build_io(snd_pcm_plug_t *plug,
- snd_pcm_format_t *format,
- snd_pcm_plugin_t **r_plugin)
-{
- int err;
- snd_pcm_plugin_t *plugin;
-
- assert(r_plugin);
- *r_plugin = NULL;
- assert(plug && format);
- err = snd_pcm_plugin_build(plug, "I/O io",
- format, format,
- sizeof(struct iovec) * format->channels,
- &plugin);
- if (err < 0)
- return err;
- if (snd_pcm_plug_stream(plug) == SND_PCM_STREAM_PLAYBACK) {
- plugin->transfer = io_playback_transfer;
- if (format->interleave)
- plugin->client_channels = io_src_channels;
- } else {
- plugin->transfer = io_capture_transfer;
- }
-#ifndef __KERNEL__
- plugin->dump = io_dump;
-#endif
-
- *r_plugin = plugin;
- return 0;
-}
diff --git a/src/pcm/plugin/linear.c b/src/pcm/plugin/linear.c
deleted file mode 100644
index 83b5e9b7..00000000
--- a/src/pcm/plugin/linear.c
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Linear conversion Plug-In
- * Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>,
- * Abramo Bagnara <abramo@alsa-project.org>
- *
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Library General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#ifdef __KERNEL__
-#include "../../include/driver.h"
-#include "../../include/pcm.h"
-#include "../../include/pcm_plugin.h"
-#else
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <byteswap.h>
-#include <sys/uio.h>
-#include "../pcm_local.h"
-#endif
-
-/*
- * Basic linear conversion plugin
- */
-
-typedef struct linear_private_data {
- int conv;
-} linear_t;
-
-static void convert(snd_pcm_plugin_t *plugin,
- const snd_pcm_plugin_channel_t *src_channels,
- snd_pcm_plugin_channel_t *dst_channels,
- size_t frames)
-{
-#define CONV_LABELS
-#include "plugin_ops.h"
-#undef CONV_LABELS
- linear_t *data = (linear_t *)plugin->extra_data;
- void *conv = conv_labels[data->conv];
- int channel;
- int nchannels = plugin->src_format.channels;
- for (channel = 0; channel < nchannels; ++channel) {
- char *src;
- char *dst;
- int src_step, dst_step;
- size_t frames1;
- if (!src_channels[channel].enabled) {
- if (dst_channels[channel].wanted)
- snd_pcm_area_silence(&dst_channels[channel].area, 0, frames, plugin->dst_format.format);
- dst_channels[channel].enabled = 0;
- continue;
- }
- dst_channels[channel].enabled = 1;
- src = src_channels[channel].area.addr + src_channels[channel].area.first / 8;
- dst = dst_channels[channel].area.addr + dst_channels[channel].area.first / 8;
- src_step = src_channels[channel].area.step / 8;
- dst_step = dst_channels[channel].area.step / 8;
- frames1 = frames;
- while (frames1-- > 0) {
- goto *conv;
-#define CONV_END after
-#include "plugin_ops.h"
-#undef CONV_END
- after:
- src += src_step;
- dst += dst_step;
- }
- }
-}
-
-static ssize_t linear_transfer(snd_pcm_plugin_t *plugin,
- const snd_pcm_plugin_channel_t *src_channels,
- snd_pcm_plugin_channel_t *dst_channels,
- size_t frames)
-{
- linear_t *data;
- unsigned int channel;
-
- assert(plugin && src_channels && dst_channels);
- data = (linear_t *)plugin->extra_data;
- if (frames == 0)
- return 0;
- for (channel = 0; channel < plugin->src_format.channels; channel++) {
- assert(src_channels[channel].area.first % 8 == 0 &&
- src_channels[channel].area.step % 8 == 0);
- assert(dst_channels[channel].area.first % 8 == 0 &&
- dst_channels[channel].area.step % 8 == 0);
- }
- convert(plugin, src_channels, dst_channels, frames);
- return frames;
-}
-
-int conv_index(int src_format, int dst_format)
-{
- int src_endian, dst_endian, sign, src_width, dst_width;
-
- sign = (snd_pcm_format_signed(src_format) !=
- snd_pcm_format_signed(dst_format));
-#ifdef SND_LITTLE_ENDIAN
- src_endian = snd_pcm_format_big_endian(src_format);
- dst_endian = snd_pcm_format_big_endian(dst_format);
-#else
- src_endian = snd_pcm_format_little_endian(src_format);
- dst_endian = snd_pcm_format_little_endian(dst_format);
-#endif
-
- if (src_endian < 0)
- src_endian = 0;
- if (dst_endian < 0)
- dst_endian = 0;
-
- src_width = snd_pcm_format_width(src_format) / 8 - 1;
- dst_width = snd_pcm_format_width(dst_format) / 8 - 1;
-
- return src_width * 32 + src_endian * 16 + sign * 8 + dst_width * 2 + dst_endian;
-}
-
-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 err;
- struct linear_private_data *data;
- snd_pcm_plugin_t *plugin;
-
- assert(r_plugin);
- *r_plugin = NULL;
-
- assert(src_format->rate == dst_format->rate);
- assert(src_format->channels == dst_format->channels);
- assert(snd_pcm_format_linear(src_format->format) &&
- snd_pcm_format_linear(dst_format->format));
-
- err = snd_pcm_plugin_build(plug, "linear format conversion",
- src_format, dst_format,
- sizeof(linear_t), &plugin);
- if (err < 0)
- return err;
- data = (linear_t *)plugin->extra_data;
- data->conv = conv_index(src_format->format, dst_format->format);
- plugin->transfer = linear_transfer;
- *r_plugin = plugin;
- return 0;
-}
diff --git a/src/pcm/plugin/mmap.c b/src/pcm/plugin/mmap.c
deleted file mode 100644
index db1f6a49..00000000
--- a/src/pcm/plugin/mmap.c
+++ /dev/null
@@ -1,315 +0,0 @@
-/*
- * PCM MMAP Plug-In Interface
- * Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>
- *
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Library General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <assert.h>
-#include <sys/poll.h>
-#include <sys/uio.h>
-#include "../pcm_local.h"
-
-/*
- * Basic mmap plugin
- */
-
-typedef struct mmap_private_data {
- void *buffer;
-#if 0
- char *silence;
-#endif
-} mmap_t;
-
-
-static ssize_t mmap_src_channels(snd_pcm_plugin_t *plugin,
- size_t frames,
- snd_pcm_plugin_channel_t **channels)
-{
- mmap_t *data;
- snd_pcm_plugin_channel_t *sv;
- snd_pcm_channel_area_t *dv;
- snd_pcm_t *stream;
- snd_pcm_setup_t *setup;
- size_t pos;
- int ready;
- unsigned int channel;
-
- assert(plugin && channels);
- data = (mmap_t *)plugin->extra_data;
- stream = plugin->plug->slave;
-
- setup = &stream->setup;
- if (snd_pcm_mmap_state(stream) < SND_PCM_STATE_PREPARED)
- return -EBADFD;
-
- ready = snd_pcm_mmap_ready(stream);
- if (ready < 0)
- return ready;
- if (!ready) {
- struct pollfd pfd;
- if (snd_pcm_mmap_state(stream) != SND_PCM_STATE_RUNNING)
- return -EPIPE;
- if (stream->mode & SND_PCM_NONBLOCK)
- return -EAGAIN;
- pfd.fd = snd_pcm_file_descriptor(stream);
- pfd.events = POLLOUT | POLLERR;
- ready = poll(&pfd, 1, 10000);
- if (ready < 0)
- return ready;
- if (ready == 0 || (pfd.revents & POLLERR))
- return -EPIPE;
- assert(snd_pcm_mmap_ready(stream));
- }
- pos = snd_pcm_mmap_offset(stream);
- assert(pos % setup->align == 0);
-
- sv = plugin->buf_channels;
- dv = stream->channels;
- *channels = sv;
- for (channel = 0; channel < plugin->src_format.channels; ++channel) {
- sv->enabled = 1;
-#if 0
- sv->wanted = !data->silence[channel * setup->frags + f];
-#else
- sv->wanted = 1;
-#endif
- sv->area.addr = dv->addr + dv->step * pos / 8;
- sv->area.first = dv->first;
- sv->area.step = dv->step;
- ++sv;
- ++dv;
- }
- return snd_pcm_mmap_xfer(stream, frames);
-}
-
-static ssize_t mmap_dst_channels(snd_pcm_plugin_t *plugin,
- size_t frames,
- snd_pcm_plugin_channel_t **channels)
-{
- mmap_t *data;
- int err;
- unsigned int channel;
- snd_pcm_plugin_channel_t *dv;
- snd_pcm_channel_area_t *sv;
- snd_pcm_t *stream;
- snd_pcm_setup_t *setup;
- size_t pos;
- int ready;
-
- assert(plugin && channels);
- data = (mmap_t *)plugin->extra_data;
- stream = plugin->plug->slave;
-
- setup = &stream->setup;
- if (snd_pcm_mmap_state(stream) < SND_PCM_STATE_PREPARED)
- return -EBADFD;
- if (snd_pcm_mmap_state(stream) == SND_PCM_STATE_PREPARED &&
- stream->setup.start_mode == SND_PCM_START_DATA) {
- err = snd_pcm_go(stream);
- if (err < 0)
- return err;
- }
- ready = snd_pcm_mmap_ready(stream);
- if (ready < 0)
- return ready;
- if (!ready) {
- struct pollfd pfd;
- if (snd_pcm_mmap_state(stream) != SND_PCM_STATE_RUNNING)
- return -EPIPE;
- if (stream->mode & SND_PCM_NONBLOCK)
- return -EAGAIN;
- pfd.fd = snd_pcm_file_descriptor(stream);
- pfd.events = POLLIN | POLLERR;
- ready = poll(&pfd, 1, 10000);
- if (ready < 0)
- return ready;
- if (ready == 0 || (pfd.revents & POLLERR))
- return -EPIPE;
- assert(snd_pcm_mmap_ready(stream));
- }
- pos = snd_pcm_mmap_offset(stream);
- assert(pos % setup->align == 0);
-
- sv = stream->channels;
- dv = plugin->buf_channels;
- *channels = dv;
- for (channel = 0; channel < plugin->dst_format.channels; ++channel) {
- dv->enabled = 1;
- dv->wanted = 0;
- dv->area.addr = sv->addr + sv->step * pos / 8;
- dv->area.first = sv->first;
- dv->area.step = sv->step;
- ++sv;
- ++dv;
- }
- return snd_pcm_mmap_xfer(stream, frames);
-}
-
-static ssize_t mmap_playback_transfer(snd_pcm_plugin_t *plugin,
- const snd_pcm_plugin_channel_t *src_channels,
- snd_pcm_plugin_channel_t *dst_channels ATTRIBUTE_UNUSED,
- size_t frames)
-{
- mmap_t *data;
- snd_pcm_setup_t *setup;
- snd_pcm_t *stream;
- int err;
-
- assert(plugin && plugin->prev);
- assert(src_channels);
- data = (mmap_t *)plugin->extra_data;
- stream = plugin->plug->slave;
- setup = &stream->setup;
-
-#if 0
- for (channel = 0; channel < plugin->src_format.channels; channel++) {
- if (src_channels[channel].enabled)
- data->silence[channel * setup->frags + f] = 0;
- }
-#endif
-
- err = snd_pcm_appl_ptr(stream, frames);
- if (err < 0)
- return err;
- if (snd_pcm_mmap_state(stream) == SND_PCM_STATE_PREPARED &&
- (setup->start_mode == SND_PCM_START_DATA ||
- (setup->start_mode == SND_PCM_START_FULL &&
- !snd_pcm_mmap_ready(stream)))) {
- err = snd_pcm_go(stream);
- if (err < 0)
- return err;
- }
- return frames;
-}
-
-static ssize_t mmap_capture_transfer(snd_pcm_plugin_t *plugin,
- const snd_pcm_plugin_channel_t *src_channels ATTRIBUTE_UNUSED,
- snd_pcm_plugin_channel_t *dst_channels ATTRIBUTE_UNUSED,
- size_t frames)
-{
- mmap_t *data;
- snd_pcm_t *stream;
- int err;
-
- assert(plugin && plugin->next);
- data = (mmap_t *)plugin->extra_data;
- stream = plugin->plug->slave;
-
- /* FIXME: not here the increment */
- err = snd_pcm_appl_ptr(stream, frames);
- if (err < 0)
- return err;
-
- return frames;
-}
-
-static int mmap_action(snd_pcm_plugin_t *plugin,
- snd_pcm_plugin_action_t action,
- unsigned long udata ATTRIBUTE_UNUSED)
-{
- struct mmap_private_data *data;
- snd_pcm_t *stream;
-
- assert(plugin);
- stream = plugin->plug->slave;
- data = (mmap_t *)plugin->extra_data;
- if (action == INIT) {
- snd_pcm_setup_t *setup;
- int result;
-
- if (data->buffer) {
- snd_pcm_munmap(stream);
- data->buffer = 0;
- }
- result = snd_pcm_mmap(stream, NULL, NULL, (void **)&data->buffer);
- if (result < 0)
- return result;
- setup = &stream->setup;
-
-#if 0
- if (plugin->stream == SND_PCM_STREAM_PLAYBACK) {
- data->silence = malloc(setup->frags * setup->format.channels);
- memset(data->silence, 0, setup->frags * setup->format.channels);
- } else
- data->silence = 0;
-#endif
- return 0;
- }
- return 0; /* silenty ignore other actions */
-}
-
-static void mmap_free(snd_pcm_plugin_t *plugin)
-{
- struct mmap_private_data *data;
-
- if (plugin == NULL)
- return;
- data = (mmap_t *)plugin->extra_data;
-#if 0
- if (data->silence)
- free(data->silence);
-#endif
- if (data->buffer)
- snd_pcm_munmap(plugin->plug->slave);
-}
-
-static void mmap_dump(snd_pcm_plugin_t *plugin, FILE *fp)
-{
- snd_pcm_t *slave = plugin->plug->slave;
- if (slave->valid_setup) {
- fprintf(fp, "Slave: ");
- snd_pcm_dump(slave, fp);
- }
-}
-
-int snd_pcm_plugin_build_mmap(snd_pcm_plug_t *plug,
- snd_pcm_format_t *format,
- snd_pcm_plugin_t **r_plugin)
-{
- int err;
- mmap_t *data;
- snd_pcm_plugin_t *plugin;
-
- assert(r_plugin);
- *r_plugin = NULL;
- assert(plug);
- err = snd_pcm_plugin_build(plug, "I/O mmap",
- format, format,
- sizeof(mmap_t) + sizeof(snd_pcm_plugin_channel_t) * format->channels,
- &plugin);
- if (err < 0)
- return err;
- data = (mmap_t *)plugin->extra_data;
- if (plug->handle->stream == SND_PCM_STREAM_PLAYBACK) {
- plugin->client_channels = mmap_src_channels;
- plugin->transfer = mmap_playback_transfer;
- } else {
- plugin->client_channels = mmap_dst_channels;
- plugin->transfer = mmap_capture_transfer;
- }
- plugin->action = mmap_action;
- plugin->private_free = mmap_free;
- plugin->dump = mmap_dump;
- *r_plugin = plugin;
- return 0;
-}
diff --git a/src/pcm/plugin/mulaw.c b/src/pcm/plugin/mulaw.c
deleted file mode 100644
index 74beeb30..00000000
--- a/src/pcm/plugin/mulaw.c
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
- * Mu-Law conversion Plug-In Interface
- * Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>
- * Uros Bizjak <uros@kss-loka.si>
- *
- * Based on reference implementation by Sun Microsystems, Inc.
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Library General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#ifdef __KERNEL__
-#include "../../include/driver.h"
-#include "../../include/pcm.h"
-#include "../../include/pcm_plugin.h"
-#else
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <byteswap.h>
-#include <sys/uio.h>
-#include "../pcm_local.h"
-#endif
-
-#define SIGN_BIT (0x80) /* Sign bit for a u-law byte. */
-#define QUANT_MASK (0xf) /* Quantization field mask. */
-#define NSEGS (8) /* Number of u-law segments. */
-#define SEG_SHIFT (4) /* Left shift for segment number. */
-#define SEG_MASK (0x70) /* Segment field mask. */
-
-static short ulaw_seg_end[8] = {0xFF, 0x1FF, 0x3FF, 0x7FF,
- 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF};
-
-static inline int search(int val, short *table, int size)
-{
- int i;
-
- for (i = 0; i < size; i++) {
- if (val <= *table++)
- return (i);
- }
- return size;
-}
-
-#define BIAS (0x84) /* Bias for linear code. */
-
-/*
- * linear2ulaw() - Convert a linear PCM value to u-law
- *
- * In order to simplify the encoding process, the original linear magnitude
- * is biased by adding 33 which shifts the encoding range from (0 - 8158) to
- * (33 - 8191). The result can be seen in the following encoding table:
- *
- * Biased Linear Input Code Compressed Code
- * ------------------------ ---------------
- * 00000001wxyza 000wxyz
- * 0000001wxyzab 001wxyz
- * 000001wxyzabc 010wxyz
- * 00001wxyzabcd 011wxyz
- * 0001wxyzabcde 100wxyz
- * 001wxyzabcdef 101wxyz
- * 01wxyzabcdefg 110wxyz
- * 1wxyzabcdefgh 111wxyz
- *
- * Each biased linear code has a leading 1 which identifies the segment
- * number. The value of the segment number is equal to 7 minus the number
- * of leading 0's. The quantization interval is directly available as the
- * four bits wxyz. * The trailing bits (a - h) are ignored.
- *
- * Ordinarily the complement of the resulting code word is used for
- * transmission, and so the code word is complemented before it is returned.
- *
- * For further information see John C. Bellamy's Digital Telephony, 1982,
- * John Wiley & Sons, pps 98-111 and 472-476.
- */
-static unsigned char linear2ulaw(int pcm_val) /* 2's complement (16-bit range) */
-{
- int mask;
- int seg;
- unsigned char uval;
-
- /* Get the sign and the magnitude of the value. */
- if (pcm_val < 0) {
- pcm_val = BIAS - pcm_val;
- mask = 0x7F;
- } else {
- pcm_val += BIAS;
- mask = 0xFF;
- }
-
- /* Convert the scaled magnitude to segment number. */
- seg = search(pcm_val, ulaw_seg_end, NSEGS);
-
- /*
- * Combine the sign, segment, quantization bits;
- * and complement the code word.
- */
- if (seg >= 8) /* out of range, return maximum value. */
- return 0x7F ^ mask;
- else {
- uval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0xF);
- return uval ^ mask;
- }
-}
-
-/*
- * ulaw2linear() - Convert a u-law value to 16-bit linear PCM
- *
- * First, a biased linear code is derived from the code word. An unbiased
- * output can then be obtained by subtracting 33 from the biased code.
- *
- * Note that this function expects to be passed the complement of the
- * original code word. This is in keeping with ISDN conventions.
- */
-static int ulaw2linear(unsigned char u_val)
-{
- int t;
-
- /* Complement to obtain normal u-law value. */
- u_val = ~u_val;
-
- /*
- * Extract and bias the quantization bits. Then
- * shift up by the segment number and subtract out the bias.
- */
- t = ((u_val & QUANT_MASK) << 3) + BIAS;
- t <<= ((unsigned)u_val & SEG_MASK) >> SEG_SHIFT;
-
- return ((u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS));
-}
-
-/*
- * Basic Mu-Law plugin
- */
-
-typedef void (*mulaw_f)(snd_pcm_plugin_t *plugin,
- const snd_pcm_plugin_channel_t *src_channels,
- snd_pcm_plugin_channel_t *dst_channels,
- size_t frames);
-
-typedef struct mulaw_private_data {
- mulaw_f func;
- int conv;
-} mulaw_t;
-
-static void mulaw_decode(snd_pcm_plugin_t *plugin,
- const snd_pcm_plugin_channel_t *src_channels,
- snd_pcm_plugin_channel_t *dst_channels,
- size_t frames)
-{
-#define PUT_S16_LABELS
-#include "plugin_ops.h"
-#undef PUT_S16_LABELS
- mulaw_t *data = (mulaw_t *)plugin->extra_data;
- void *put = put_s16_labels[data->conv];
- int channel;
- int nchannels = plugin->src_format.channels;
- for (channel = 0; channel < nchannels; ++channel) {
- char *src;
- char *dst;
- int src_step, dst_step;
- size_t frames1;
- if (!src_channels[channel].enabled) {
- if (dst_channels[channel].wanted)
- snd_pcm_area_silence(&dst_channels[channel].area, 0, frames, plugin->dst_format.format);
- dst_channels[channel].enabled = 0;
- continue;
- }
- dst_channels[channel].enabled = 1;
- src = src_channels[channel].area.addr + src_channels[channel].area.first / 8;
- dst = dst_channels[channel].area.addr + dst_channels[channel].area.first / 8;
- src_step = src_channels[channel].area.step / 8;
- dst_step = dst_channels[channel].area.step / 8;
- frames1 = frames;
- while (frames1-- > 0) {
- signed short sample = ulaw2linear(*src);
- goto *put;
-#define PUT_S16_END after
-#include "plugin_ops.h"
-#undef PUT_S16_END
- after:
- src += src_step;
- dst += dst_step;
- }
- }
-}
-
-static void mulaw_encode(snd_pcm_plugin_t *plugin,
- const snd_pcm_plugin_channel_t *src_channels,
- snd_pcm_plugin_channel_t *dst_channels,
- size_t frames)
-{
-#define GET_S16_LABELS
-#include "plugin_ops.h"
-#undef GET_S16_LABELS
- mulaw_t *data = (mulaw_t *)plugin->extra_data;
- void *get = get_s16_labels[data->conv];
- int channel;
- int nchannels = plugin->src_format.channels;
- signed short sample = 0;
- for (channel = 0; channel < nchannels; ++channel) {
- char *src;
- char *dst;
- int src_step, dst_step;
- size_t frames1;
- if (!src_channels[channel].enabled) {
- if (dst_channels[channel].wanted)
- snd_pcm_area_silence(&dst_channels[channel].area, 0, frames, plugin->dst_format.format);
- dst_channels[channel].enabled = 0;
- continue;
- }
- dst_channels[channel].enabled = 1;
- src = src_channels[channel].area.addr + src_channels[channel].area.first / 8;
- dst = dst_channels[channel].area.addr + dst_channels[channel].area.first / 8;
- src_step = src_channels[channel].area.step / 8;
- dst_step = dst_channels[channel].area.step / 8;
- frames1 = frames;
- while (frames1-- > 0) {
- goto *get;
-#define GET_S16_END after
-#include "plugin_ops.h"
-#undef GET_S16_END
- after:
- *dst = linear2ulaw(sample);
- src += src_step;
- dst += dst_step;
- }
- }
-}
-
-static ssize_t mulaw_transfer(snd_pcm_plugin_t *plugin,
- const snd_pcm_plugin_channel_t *src_channels,
- snd_pcm_plugin_channel_t *dst_channels,
- size_t frames)
-{
- mulaw_t *data;
- unsigned int channel;
-
- assert(plugin && src_channels && dst_channels);
- if (frames == 0)
- return 0;
- for (channel = 0; channel < plugin->src_format.channels; channel++) {
- assert(src_channels[channel].area.first % 8 == 0 &&
- src_channels[channel].area.step % 8 == 0);
- assert(dst_channels[channel].area.first % 8 == 0 &&
- dst_channels[channel].area.step % 8 == 0);
- }
- data = (mulaw_t *)plugin->extra_data;
- data->func(plugin, src_channels, dst_channels, frames);
- return frames;
-}
-
-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 err;
- mulaw_t *data;
- snd_pcm_plugin_t *plugin;
- snd_pcm_format_t *format;
- mulaw_f func;
-
- assert(r_plugin);
- *r_plugin = NULL;
-
- assert(src_format->rate == dst_format->rate);
- assert(src_format->channels == dst_format->channels);
-
- if (dst_format->format == SND_PCM_SFMT_MU_LAW) {
- format = src_format;
- func = mulaw_encode;
- }
- else if (src_format->format == SND_PCM_SFMT_MU_LAW) {
- format = dst_format;
- func = mulaw_decode;
- }
- else {
- assert(0);
- return -EINVAL;
- }
- assert(snd_pcm_format_linear(format->format));
-
- err = snd_pcm_plugin_build(plug, "Mu-Law<->linear conversion",
- src_format, dst_format,
- sizeof(mulaw_t), &plugin);
- if (err < 0)
- return err;
- data = (mulaw_t*)plugin->extra_data;
- data->func = func;
- data->conv = getput_index(format->format);
- plugin->transfer = mulaw_transfer;
- *r_plugin = plugin;
- return 0;
-}
diff --git a/src/pcm/plugin/rate.c b/src/pcm/plugin/rate.c
deleted file mode 100644
index 18f4a9f5..00000000
--- a/src/pcm/plugin/rate.c
+++ /dev/null
@@ -1,390 +0,0 @@
-/*
- * Rate conversion Plug-In
- * Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>
- *
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Library General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#ifdef __KERNEL__
-#include "../../include/driver.h"
-#include "../../include/pcm.h"
-#include "../../include/pcm_plugin.h"
-#else
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <byteswap.h>
-#include "../pcm_local.h"
-#endif
-
-#define SHIFT 11
-#define BITS (1<<SHIFT)
-#define MASK (BITS-1)
-
-/*
- * Basic rate conversion plugin
- */
-
-typedef struct {
- signed short last_S1;
- signed short last_S2;
-} rate_channel_t;
-
-typedef void (*rate_f)(snd_pcm_plugin_t *plugin,
- const snd_pcm_plugin_channel_t *src_channels,
- snd_pcm_plugin_channel_t *dst_channels,
- int src_frames, int dst_frames);
-
-typedef struct rate_private_data {
- unsigned int pitch;
- unsigned int pos;
- rate_f func;
- int get, put;
- ssize_t old_src_frames, old_dst_frames;
- rate_channel_t channels[0];
-} rate_t;
-
-static void rate_init(snd_pcm_plugin_t *plugin)
-{
- unsigned int channel;
- rate_t *data = (rate_t *)plugin->extra_data;
- data->pos = 0;
- for (channel = 0; channel < plugin->src_format.channels; channel++) {
- data->channels[channel].last_S1 = 0;
- data->channels[channel].last_S2 = 0;
- }
-}
-
-static void resample_expand(snd_pcm_plugin_t *plugin,
- const snd_pcm_plugin_channel_t *src_channels,
- snd_pcm_plugin_channel_t *dst_channels,
- int src_frames, int dst_frames)
-{
- unsigned int pos = 0;
- signed int val;
- signed short S1, S2;
- char *src, *dst;
- unsigned int channel;
- int src_step, dst_step;
- int src_frames1, dst_frames1;
- rate_t *data = (rate_t *)plugin->extra_data;
- rate_channel_t *rchannels = data->channels;
-
-#define GET_S16_LABELS
-#define PUT_S16_LABELS
-#include "plugin_ops.h"
-#undef GET_S16_LABELS
-#undef PUT_S16_LABELS
- void *get = get_s16_labels[data->get];
- void *put = put_s16_labels[data->put];
- void *get_s16_end = 0;
- signed short sample = 0;
-#define GET_S16_END *get_s16_end
-#include "plugin_ops.h"
-#undef GET_S16_END
-
- for (channel = 0; channel < plugin->src_format.channels; channel++) {
- pos = data->pos;
- S1 = rchannels->last_S1;
- S2 = rchannels->last_S2;
- if (!src_channels[channel].enabled) {
- if (dst_channels[channel].wanted)
- snd_pcm_area_silence(&dst_channels[channel].area, 0, dst_frames, plugin->dst_format.format);
- dst_channels[channel].enabled = 0;
- continue;
- }
- dst_channels[channel].enabled = 1;
- src = (char *)src_channels[channel].area.addr + src_channels[channel].area.first / 8;
- dst = (char *)dst_channels[channel].area.addr + dst_channels[channel].area.first / 8;
- src_step = src_channels[channel].area.step / 8;
- dst_step = dst_channels[channel].area.step / 8;
- src_frames1 = src_frames;
- dst_frames1 = dst_frames;
- if (pos & ~MASK) {
- get_s16_end = &&after_get1;
- goto *get;
- after_get1:
- pos &= MASK;
- S1 = S2;
- S2 = sample;
- src += src_step;
- src_frames--;
- }
- while (dst_frames1-- > 0) {
- if (pos & ~MASK) {
- pos &= MASK;
- S1 = S2;
- if (src_frames1-- > 0) {
- get_s16_end = &&after_get2;
- goto *get;
- after_get2:
- S2 = sample;
- src += src_step;
- }
- }
- val = S1 + ((S2 - S1) * (signed int)pos) / BITS;
- if (val < -32768)
- val = -32768;
- else if (val > 32767)
- val = 32767;
- sample = val;
- goto *put;
-#define PUT_S16_END after_put
-#include "plugin_ops.h"
-#undef PUT_S16_END
- after_put:
- dst += dst_step;
- pos += data->pitch;
- }
- rchannels->last_S1 = S1;
- rchannels->last_S2 = S2;
- rchannels++;
- }
- data->pos = pos;
-}
-
-static void resample_shrink(snd_pcm_plugin_t *plugin,
- const snd_pcm_plugin_channel_t *src_channels,
- snd_pcm_plugin_channel_t *dst_channels,
- int src_frames, int dst_frames)
-{
- unsigned int pos = 0;
- signed int val;
- signed short S1, S2;
- char *src, *dst;
- unsigned int channel;
- int src_step, dst_step;
- int src_frames1, dst_frames1;
- rate_t *data = (rate_t *)plugin->extra_data;
- rate_channel_t *rchannels = data->channels;
-
-#define GET_S16_LABELS
-#define PUT_S16_LABELS
-#include "plugin_ops.h"
-#undef GET_S16_LABELS
-#undef PUT_S16_LABELS
- void *get = get_s16_labels[data->get];
- void *put = put_s16_labels[data->put];
- signed short sample = 0;
-
- for (channel = 0; channel < plugin->src_format.channels; ++channel) {
- pos = data->pos;
- S1 = rchannels->last_S1;
- S2 = rchannels->last_S2;
- if (!src_channels[channel].enabled) {
- if (dst_channels[channel].wanted)
- snd_pcm_area_silence(&dst_channels[channel].area, 0, dst_frames, plugin->dst_format.format);
- dst_channels[channel].enabled = 0;
- continue;
- }
- dst_channels[channel].enabled = 1;
- src = (char *)src_channels[channel].area.addr + src_channels[channel].area.first / 8;
- dst = (char *)dst_channels[channel].area.addr + dst_channels[channel].area.first / 8;
- src_step = src_channels[channel].area.step / 8;
- dst_step = dst_channels[channel].area.step / 8;
- src_frames1 = src_frames;
- dst_frames1 = dst_frames;
- while (dst_frames1 > 0) {
- S1 = S2;
- if (src_frames1-- > 0) {
- goto *get;
-#define GET_S16_END after_get
-#include "plugin_ops.h"
-#undef GET_S16_END
- after_get:
- S2 = sample;
- src += src_step;
- }
- if (pos & ~MASK) {
- pos &= MASK;
- val = S1 + ((S2 - S1) * (signed int)pos) / BITS;
- if (val < -32768)
- val = -32768;
- else if (val > 32767)
- val = 32767;
- sample = val;
- goto *put;
-#define PUT_S16_END after_put
-#include "plugin_ops.h"
-#undef PUT_S16_END
- after_put:
- dst += dst_step;
- dst_frames1--;
- }
- pos += data->pitch;
- }
- rchannels->last_S1 = S1;
- rchannels->last_S2 = S2;
- rchannels++;
- }
- data->pos = pos;
-}
-
-static ssize_t rate_src_frames(snd_pcm_plugin_t *plugin, size_t frames)
-{
- rate_t *data;
- ssize_t res;
-
- assert(plugin);
- if (frames == 0)
- return 0;
- data = (rate_t *)plugin->extra_data;
- if (plugin->src_format.rate < plugin->dst_format.rate) {
- res = (((frames * data->pitch) + (BITS/2)) >> SHIFT);
- } else {
- res = (((frames << SHIFT) + (data->pitch / 2)) / data->pitch);
- }
- if (data->old_src_frames > 0) {
- ssize_t frames1 = frames, res1 = data->old_dst_frames;
- while (data->old_src_frames < frames1) {
- frames1 >>= 1;
- res1 <<= 1;
- }
- while (data->old_src_frames > frames1) {
- frames1 <<= 1;
- res1 >>= 1;
- }
- if (data->old_src_frames == frames1)
- return res1;
- }
- data->old_src_frames = frames;
- data->old_dst_frames = res;
- return res;
-}
-
-static ssize_t rate_dst_frames(snd_pcm_plugin_t *plugin, size_t frames)
-{
- rate_t *data;
- ssize_t res;
-
- assert(plugin);
- if (frames == 0)
- return 0;
- data = (rate_t *)plugin->extra_data;
- if (plugin->src_format.rate < plugin->dst_format.rate) {
- res = (((frames << SHIFT) + (data->pitch / 2)) / data->pitch);
- } else {
- res = (((frames * data->pitch) + (BITS/2)) >> SHIFT);
- }
- if (data->old_dst_frames > 0) {
- ssize_t frames1 = frames, res1 = data->old_src_frames;
- while (data->old_dst_frames < frames1) {
- frames1 >>= 1;
- res1 <<= 1;
- }
- while (data->old_dst_frames > frames1) {
- frames1 <<= 1;
- res1 >>= 1;
- }
- if (data->old_dst_frames == frames1)
- return res1;
- }
- data->old_dst_frames = frames;
- data->old_src_frames = res;
- return res;
-}
-
-static ssize_t rate_transfer(snd_pcm_plugin_t *plugin,
- const snd_pcm_plugin_channel_t *src_channels,
- snd_pcm_plugin_channel_t *dst_channels,
- size_t frames)
-{
- size_t dst_frames;
- unsigned int channel;
- rate_t *data;
-
- assert(plugin && src_channels && dst_channels);
- if (frames == 0)
- return 0;
- for (channel = 0; channel < plugin->src_format.channels; channel++) {
- assert(src_channels[channel].area.first % 8 == 0 &&
- src_channels[channel].area.step % 8 == 0);
- assert(dst_channels[channel].area.first % 8 == 0 &&
- dst_channels[channel].area.step % 8 == 0);
- }
-
- dst_frames = rate_dst_frames(plugin, frames);
- data = (rate_t *)plugin->extra_data;
- data->func(plugin, src_channels, dst_channels, frames, dst_frames);
- return dst_frames;
-}
-
-static int rate_action(snd_pcm_plugin_t *plugin,
- snd_pcm_plugin_action_t action,
- unsigned long udata ATTRIBUTE_UNUSED)
-{
- assert(plugin);
- switch (action) {
- case INIT:
- case PREPARE:
- case DRAIN:
- case FLUSH:
- rate_init(plugin);
- break;
- default:
- break;
- }
- return 0; /* silenty ignore other actions */
-}
-
-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 err;
- rate_t *data;
- snd_pcm_plugin_t *plugin;
-
- assert(r_plugin);
- *r_plugin = NULL;
-
- assert(src_format->channels == dst_format->channels);
- assert(src_format->channels > 0);
- assert(snd_pcm_format_linear(src_format->format) > 0);
- assert(snd_pcm_format_linear(dst_format->format) > 0);
- assert(src_format->rate != dst_format->rate);
-
- err = snd_pcm_plugin_build(plug, "rate conversion",
- src_format, dst_format,
- sizeof(rate_t) + src_format->channels * sizeof(rate_channel_t),
- &plugin);
- if (err < 0)
- return err;
- data = (rate_t *)plugin->extra_data;
- data->get = getput_index(src_format->format);
- data->put = getput_index(dst_format->format);
-
- if (src_format->rate < dst_format->rate) {
- data->pitch = ((src_format->rate << SHIFT) + (dst_format->rate >> 1)) / dst_format->rate;
- data->func = resample_expand;
- } else {
- data->pitch = ((dst_format->rate << SHIFT) + (src_format->rate >> 1)) / src_format->rate;
- data->func = resample_shrink;
- }
- data->pos = 0;
- rate_init(plugin);
- data->old_src_frames = data->old_dst_frames = 0;
- plugin->transfer = rate_transfer;
- plugin->src_frames = rate_src_frames;
- plugin->dst_frames = rate_dst_frames;
- plugin->action = rate_action;
- *r_plugin = plugin;
- return 0;
-}
diff --git a/src/pcm/plugin/route.c b/src/pcm/plugin/route.c
deleted file mode 100644
index 448c47d8..00000000
--- a/src/pcm/plugin/route.c
+++ /dev/null
@@ -1,621 +0,0 @@
-/*
- * Attenuated route Plug-In
- * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
- *
- *
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Library General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#ifdef __KERNEL__
-#include "../../include/driver.h"
-#include "../../include/pcm.h"
-#include "../../include/pcm_plugin.h"
-#else
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <byteswap.h>
-#include <math.h>
-#include "../pcm_local.h"
-#endif
-
-/* The best possible hack to support missing optimization in gcc 2.7.2.3 */
-#if ROUTE_PLUGIN_RESOLUTION & (ROUTE_PLUGIN_RESOLUTION - 1) != 0
-#define div(a) a /= ROUTE_PLUGIN_RESOLUTION
-#elif ROUTE_PLUGIN_RESOLUTION == 16
-#define div(a) a >>= 4
-#else
-#error "Add some code here"
-#endif
-
-typedef struct ttable_dst ttable_dst_t;
-typedef struct route_private_data route_t;
-
-typedef void (*route_channel_f)(snd_pcm_plugin_t *plugin,
- const snd_pcm_plugin_channel_t *src_channels,
- snd_pcm_plugin_channel_t *dst_channel,
- ttable_dst_t* ttable, size_t frames);
-
-typedef struct {
- int channel;
- int as_int;
-#if ROUTE_PLUGIN_USE_FLOAT
- float as_float;
-#endif
-} ttable_src_t;
-
-struct ttable_dst {
- int att; /* Attenuated */
- unsigned int nsrcs;
- ttable_src_t* srcs;
- route_channel_f func;
-};
-
-struct route_private_data {
- enum {UINT32=0, UINT64=1, FLOAT=2} sum_type;
- int get, put;
- int conv;
- int src_sample_size;
- ttable_dst_t ttable[0];
-};
-
-typedef union {
- u_int32_t as_uint32;
- u_int64_t as_uint64;
-#if ROUTE_PLUGIN_USE_FLOAT
- float as_float;
-#endif
-} sum_t;
-
-
-static void route_to_channel_from_zero(snd_pcm_plugin_t *plugin,
- const snd_pcm_plugin_channel_t *src_channels ATTRIBUTE_UNUSED,
- snd_pcm_plugin_channel_t *dst_channel,
- ttable_dst_t* ttable ATTRIBUTE_UNUSED, size_t frames)
-{
- if (dst_channel->wanted)
- snd_pcm_area_silence(&dst_channel->area, 0, frames, plugin->dst_format.format);
- dst_channel->enabled = 0;
-}
-
-static void route_to_channel_from_one(snd_pcm_plugin_t *plugin,
- const snd_pcm_plugin_channel_t *src_channels,
- snd_pcm_plugin_channel_t *dst_channel,
- ttable_dst_t* ttable, size_t frames)
-{
-#define CONV_LABELS
-#include "plugin_ops.h"
-#undef CONV_LABELS
- route_t *data = (route_t *)plugin->extra_data;
- void *conv;
- const snd_pcm_plugin_channel_t *src_channel = 0;
- unsigned int srcidx;
- char *src, *dst;
- int src_step, dst_step;
- for (srcidx = 0; srcidx < ttable->nsrcs; ++srcidx) {
- src_channel = &src_channels[ttable->srcs[srcidx].channel];
- if (src_channel->area.addr != NULL)
- break;
- }
- if (srcidx == ttable->nsrcs) {
- route_to_channel_from_zero(plugin, src_channels, dst_channel, ttable, frames);
- return;
- }
-
- dst_channel->enabled = 1;
- conv = conv_labels[data->conv];
- src = src_channel->area.addr + src_channel->area.first / 8;
- src_step = src_channel->area.step / 8;
- dst = dst_channel->area.addr + dst_channel->area.first / 8;
- dst_step = dst_channel->area.step / 8;
- while (frames-- > 0) {
- goto *conv;
-#define CONV_END after
-#include "plugin_ops.h"
-#undef CONV_END
- after:
- src += src_step;
- dst += dst_step;
- }
-}
-
-static void route_to_channel(snd_pcm_plugin_t *plugin,
- const snd_pcm_plugin_channel_t *src_channels,
- snd_pcm_plugin_channel_t *dst_channel,
- ttable_dst_t* ttable, size_t frames)
-{
-#define GET_U_LABELS
-#define PUT_U32_LABELS
-#include "plugin_ops.h"
-#undef GET_U_LABELS
-#undef PUT_U32_LABELS
- static void *zero_labels[3] = { &&zero_int32, &&zero_int64,
-#if ROUTE_PLUGIN_USE_FLOAT
- &&zero_float
-#endif
- };
- /* sum_type att */
- static void *add_labels[3 * 2] = { &&add_int32_noatt, &&add_int32_att,
- &&add_int64_noatt, &&add_int64_att,
-#if ROUTE_PLUGIN_USE_FLOAT
- &&add_float_noatt, &&add_float_att
-#endif
- };
- /* sum_type att shift */
- static void *norm_labels[3 * 2 * 4] = { 0,
- &&norm_int32_8_noatt,
- &&norm_int32_16_noatt,
- &&norm_int32_24_noatt,
- 0,
- &&norm_int32_8_att,
- &&norm_int32_16_att,
- &&norm_int32_24_att,
- &&norm_int64_0_noatt,
- &&norm_int64_8_noatt,
- &&norm_int64_16_noatt,
- &&norm_int64_24_noatt,
- &&norm_int64_0_att,
- &&norm_int64_8_att,
- &&norm_int64_16_att,
- &&norm_int64_24_att,
-#if ROUTE_PLUGIN_USE_FLOAT
- &&norm_float_0,
- &&norm_float_8,
- &&norm_float_16,
- &&norm_float_24,
- &&norm_float_0,
- &&norm_float_8,
- &&norm_float_16,
- &&norm_float_24,
-#endif
- };
- route_t *data = (route_t *)plugin->extra_data;
- void *zero, *get, *add, *norm, *put_u32;
- int nsrcs = ttable->nsrcs;
- char *dst;
- int dst_step;
- char *srcs[nsrcs];
- int src_steps[nsrcs];
- ttable_src_t src_tt[nsrcs];
- u_int32_t sample = 0;
- int srcidx, srcidx1 = 0;
- for (srcidx = 0; srcidx < nsrcs; ++srcidx) {
- const snd_pcm_plugin_channel_t *src_channel = &src_channels[ttable->srcs[srcidx].channel];
- if (!src_channel->enabled)
- continue;
- srcs[srcidx1] = src_channel->area.addr + src_channels->area.first / 8;
- src_steps[srcidx1] = src_channel->area.step / 8;
- src_tt[srcidx1] = ttable->srcs[srcidx];
- srcidx1++;
- }
- nsrcs = srcidx1;
- if (nsrcs == 0) {
- route_to_channel_from_zero(plugin, src_channels, dst_channel, ttable, frames);
- return;
- } else if (nsrcs == 1 && src_tt[0].as_int == ROUTE_PLUGIN_RESOLUTION) {
- route_to_channel_from_one(plugin, src_channels, dst_channel, ttable, frames);
- return;
- }
-
- dst_channel->enabled = 1;
- zero = zero_labels[data->sum_type];
- get = get_u_labels[data->get];
- add = add_labels[data->sum_type * 2 + ttable->att];
- norm = norm_labels[data->sum_type * 8 + ttable->att * 4 + 4 - data->src_sample_size];
- put_u32 = put_u32_labels[data->put];
- dst = dst_channel->area.addr + dst_channel->area.first / 8;
- dst_step = dst_channel->area.step / 8;
-
- while (frames-- > 0) {
- ttable_src_t *ttp = src_tt;
- sum_t sum;
-
- /* Zero sum */
- goto *zero;
- zero_int32:
- sum.as_uint32 = 0;
- goto zero_end;
- zero_int64:
- sum.as_uint64 = 0;
- goto zero_end;
-#if ROUTE_PLUGIN_USE_FLOAT
- zero_float:
- sum.as_float = 0.0;
- goto zero_end;
-#endif
- zero_end:
- for (srcidx = 0; srcidx < nsrcs; ++srcidx) {
- char *src = srcs[srcidx];
-
- /* Get sample */
- goto *get;
-#define GET_U_END after_get
-#include "plugin_ops.h"
-#undef GET_U_END
- after_get:
-
- /* Sum */
- goto *add;
- add_int32_att:
- sum.as_uint32 += sample * ttp->as_int;
- goto after_sum;
- add_int32_noatt:
- if (ttp->as_int)
- sum.as_uint32 += sample;
- goto after_sum;
- add_int64_att:
- sum.as_uint64 += (u_int64_t) sample * ttp->as_int;
- goto after_sum;
- add_int64_noatt:
- if (ttp->as_int)
- sum.as_uint64 += sample;
- goto after_sum;
-#if ROUTE_PLUGIN_USE_FLOAT
- add_float_att:
- sum.as_float += sample * ttp->as_float;
- goto after_sum;
- add_float_noatt:
- if (ttp->as_int)
- sum.as_float += sample;
- goto after_sum;
-#endif
- after_sum:
- srcs[srcidx] += src_steps[srcidx];
- ttp++;
- }
-
- /* Normalization */
- goto *norm;
- norm_int32_8_att:
- sum.as_uint64 = sum.as_uint32;
- norm_int64_8_att:
- sum.as_uint64 <<= 8;
- norm_int64_0_att:
- div(sum.as_uint64);
- goto norm_int;
-
- norm_int32_16_att:
- sum.as_uint64 = sum.as_uint32;
- norm_int64_16_att:
- sum.as_uint64 <<= 16;
- div(sum.as_uint64);
- goto norm_int;
-
- norm_int32_24_att:
- sum.as_uint64 = sum.as_uint32;
- norm_int64_24_att:
- sum.as_uint64 <<= 24;
- div(sum.as_uint64);
- goto norm_int;
-
- norm_int32_8_noatt:
- sum.as_uint64 = sum.as_uint32;
- norm_int64_8_noatt:
- sum.as_uint64 <<= 8;
- goto norm_int;
-
- norm_int32_16_noatt:
- sum.as_uint64 = sum.as_uint32;
- norm_int64_16_noatt:
- sum.as_uint64 <<= 16;
- goto norm_int;
-
- norm_int32_24_noatt:
- sum.as_uint64 = sum.as_uint32;
- norm_int64_24_noatt:
- sum.as_uint64 <<= 24;
- goto norm_int;
-
- norm_int64_0_noatt:
- norm_int:
- if (sum.as_uint64 > (u_int32_t)0xffffffff)
- sample = (u_int32_t)0xffffffff;
- else
- sample = sum.as_uint64;
- goto after_norm;
-
-#if ROUTE_PLUGIN_USE_FLOAT
- norm_float_8:
- sum.as_float *= 1 << 8;
- goto norm_float;
- norm_float_16:
- sum.as_float *= 1 << 16;
- goto norm_float;
- norm_float_24:
- sum.as_float *= 1 << 24;
- goto norm_float;
- norm_float_0:
- norm_float:
- sum.as_float = floor(sum.as_float + 0.5);
- if (sum.as_float > (u_int32_t)0xffffffff)
- sample = (u_int32_t)0xffffffff;
- else
- sample = sum.as_float;
- goto after_norm;
-#endif
- after_norm:
-
- /* Put sample */
- goto *put_u32;
-#define PUT_U32_END after_put_u32
-#include "plugin_ops.h"
-#undef PUT_U32_END
- after_put_u32:
-
- dst += dst_step;
- }
-}
-
-int route_src_channels_mask(snd_pcm_plugin_t *plugin,
- bitset_t *dst_vmask,
- bitset_t **src_vmask)
-{
- route_t *data = (route_t *)plugin->extra_data;
- int schannels = plugin->src_format.channels;
- int dchannels = plugin->dst_format.channels;
- bitset_t *vmask = plugin->src_vmask;
- int channel;
- ttable_dst_t *dp = data->ttable;
- bitset_zero(vmask, schannels);
- for (channel = 0; channel < dchannels; channel++, dp++) {
- unsigned int src;
- ttable_src_t *sp;
- if (!bitset_get(dst_vmask, channel))
- continue;
- sp = dp->srcs;
- for (src = 0; src < dp->nsrcs; src++, sp++)
- bitset_set(vmask, sp->channel);
- }
- *src_vmask = vmask;
- return 0;
-}
-
-int route_dst_channels_mask(snd_pcm_plugin_t *plugin,
- bitset_t *src_vmask,
- bitset_t **dst_vmask)
-{
- route_t *data = (route_t *)plugin->extra_data;
- int dchannels = plugin->dst_format.channels;
- bitset_t *vmask = plugin->dst_vmask;
- int channel;
- ttable_dst_t *dp = data->ttable;
- bitset_zero(vmask, dchannels);
- for (channel = 0; channel < dchannels; channel++, dp++) {
- unsigned int src;
- ttable_src_t *sp;
- sp = dp->srcs;
- for (src = 0; src < dp->nsrcs; src++, sp++) {
- if (bitset_get(src_vmask, sp->channel)) {
- bitset_set(vmask, channel);
- break;
- }
- }
- }
- *dst_vmask = vmask;
- return 0;
-}
-
-static void route_free(snd_pcm_plugin_t *plugin)
-{
- route_t *data = (route_t *)plugin->extra_data;
- unsigned int dst_channel;
- for (dst_channel = 0; dst_channel < plugin->dst_format.channels; ++dst_channel) {
- if (data->ttable[dst_channel].srcs != NULL)
- free(data->ttable[dst_channel].srcs);
- }
-}
-
-static int route_load_ttable(snd_pcm_plugin_t *plugin,
- const route_ttable_entry_t* src_ttable)
-{
- route_t *data;
- unsigned int src_channel, dst_channel;
- const route_ttable_entry_t *sptr;
- ttable_dst_t *dptr;
- if (src_ttable == NULL)
- return 0;
- data = (route_t *)plugin->extra_data;
- dptr = data->ttable;
- sptr = src_ttable;
- plugin->private_free = route_free;
- for (dst_channel = 0; dst_channel < plugin->dst_format.channels; ++dst_channel) {
- route_ttable_entry_t t = 0;
- int att = 0;
- int nsrcs = 0;
- ttable_src_t srcs[plugin->src_format.channels];
- for (src_channel = 0; src_channel < plugin->src_format.channels; ++src_channel) {
- assert(*sptr >= 0 && *sptr <= FULL);
- if (*sptr != 0) {
- srcs[nsrcs].channel = src_channel;
-#if ROUTE_PLUGIN_USE_FLOAT
- /* Also in user space for non attenuated */
- srcs[nsrcs].as_int = (*sptr == FULL ? ROUTE_PLUGIN_RESOLUTION : 0);
- srcs[nsrcs].as_float = *sptr;
-#else
- srcs[nsrcs].as_int = *sptr;
-#endif
- if (*sptr != FULL)
- att = 1;
- t += *sptr;
- nsrcs++;
- }
- sptr++;
- }
-#if 0
- assert(t <= FULL);
-#endif
- dptr->att = att;
- dptr->nsrcs = nsrcs;
- switch (nsrcs) {
- case 0:
- dptr->func = route_to_channel_from_zero;
- break;
- case 1:
- dptr->func = route_to_channel_from_one;
- break;
- default:
- dptr->func = route_to_channel;
- break;
- }
- if (nsrcs > 0) {
- dptr->srcs = calloc(nsrcs, sizeof(*srcs));
- memcpy(dptr->srcs, srcs, sizeof(*srcs) * nsrcs);
- } else
- dptr->srcs = 0;
- dptr++;
- }
- return 0;
-}
-
-static ssize_t route_transfer(snd_pcm_plugin_t *plugin,
- const snd_pcm_plugin_channel_t *src_channels,
- snd_pcm_plugin_channel_t *dst_channels,
- size_t frames)
-{
- route_t *data;
- int src_nchannels, dst_nchannels;
- int src_channel, dst_channel;
- ttable_dst_t *ttp;
- snd_pcm_plugin_channel_t *dvp;
-
- assert(plugin && src_channels && dst_channels);
- if (frames == 0)
- return 0;
- data = (route_t *)plugin->extra_data;
-
- src_nchannels = plugin->src_format.channels;
- for (src_channel = 0; src_channel < src_nchannels; ++src_channel) {
- assert(src_channels[src_channel].area.first % 8 == 0 &&
- src_channels[src_channel].area.step % 8 == 0);
- }
-
- dst_nchannels = plugin->dst_format.channels;
- for (dst_channel = 0; dst_channel < dst_nchannels; ++dst_channel) {
- assert(dst_channels[dst_channel].area.first % 8 == 0 &&
- dst_channels[dst_channel].area.step % 8 == 0);
- }
-
- ttp = data->ttable;
- dvp = dst_channels;
- for (dst_channel = 0; dst_channel < dst_nchannels; ++dst_channel) {
- ttp->func(plugin, src_channels, dvp, ttp, frames);
- dvp++;
- ttp++;
- }
- return frames;
-}
-
-int getput_index(int format)
-{
- int sign, width, endian;
- sign = !snd_pcm_format_signed(format);
- width = snd_pcm_format_width(format) / 8 - 1;
-#ifdef SND_LITTLE_ENDIAN
- endian = snd_pcm_format_big_endian(format);
-#else
- endian = snd_pcm_format_little_endian(format);
-#endif
- if (endian < 0)
- endian = 0;
- return width * 4 + endian * 2 + sign;
-}
-
-#ifndef __KERNEL__
-static void route_dump(snd_pcm_plugin_t *plugin, FILE *fp)
-{
- route_t *data;
- ttable_dst_t *tdp;
- unsigned int dst_channel, dst_nchannels;
- data = (route_t *)plugin->extra_data;
- tdp = data->ttable;
- dst_nchannels = plugin->dst_format.channels;
- for (dst_channel = 0; dst_channel < dst_nchannels; ++dst_channel) {
- unsigned int k;
- ttable_src_t *tsp = tdp->srcs;
- fprintf(fp, "Channel %d = ", dst_channel);
- for (k = 0; k < tdp->nsrcs; ++k) {
- if (k > 0)
- fprintf(fp, " + ");
- fprintf(fp, "[%d]", tsp->channel);
- if (tdp->att) {
-#if ROUTE_PLUGIN_USE_FLOAT
- fprintf(fp, "*%g", tsp->as_float);
-#else
- fprintf(fp, "*%d/%d", tsp->as_int, ROUTE_PLUGIN_RESOLUTION);
-#endif
- }
- ++tsp;
- }
- fprintf(fp, "\n");
- ++tdp;
- }
-}
-#endif
-
-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)
-{
- route_t *data;
- snd_pcm_plugin_t *plugin;
- int err;
-
- assert(r_plugin);
- *r_plugin = NULL;
- assert(src_format->rate == dst_format->rate);
- assert(snd_pcm_format_linear(src_format->format) &&
- snd_pcm_format_linear(dst_format->format));
-
- err = snd_pcm_plugin_build(plug, "attenuated route conversion",
- src_format, dst_format,
- sizeof(route_t) + sizeof(data->ttable[0]) * dst_format->channels,
- &plugin);
- if (err < 0)
- return err;
-
- data = (route_t *) plugin->extra_data;
-
- data->get = getput_index(src_format->format);
- data->put = getput_index(dst_format->format);
- data->conv = conv_index(src_format->format, dst_format->format);
-
-#if ROUTE_PLUGIN_USE_FLOAT
- data->sum_type = FLOAT;
-#else
- if (snd_pcm_format_width(src_format->format) == 32)
- data->sum_type = UINT64;
- else
- data->sum_type = UINT32;
-#endif
- data->src_sample_size = snd_pcm_format_width(src_format->format) / 8;
-
- if ((err = route_load_ttable(plugin, ttable)) < 0) {
- snd_pcm_plugin_free(plugin);
- return err;
- }
- plugin->transfer = route_transfer;
- plugin->src_channels_mask = route_src_channels_mask;
- plugin->dst_channels_mask = route_dst_channels_mask;
-#ifndef __KERNEL__
- plugin->dump = route_dump;
-#endif
- *r_plugin = plugin;
- return 0;
-}
diff --git a/src/pcm/plugin/plugin_ops.h b/src/pcm/plugin_ops.h
index ed91a2c1..ed91a2c1 100644
--- a/src/pcm/plugin/plugin_ops.h
+++ b/src/pcm/plugin_ops.h
diff --git a/src/rawmidi/rawmidi.c b/src/rawmidi/rawmidi.c
index f733a35c..1a0cad07 100644
--- a/src/rawmidi/rawmidi.c
+++ b/src/rawmidi/rawmidi.c
@@ -86,7 +86,7 @@ int snd_rawmidi_close(snd_rawmidi_t *rmidi)
return res;
}
-int snd_rawmidi_file_descriptor(snd_rawmidi_t *rmidi)
+int snd_rawmidi_poll_descriptor(snd_rawmidi_t *rmidi)
{
if (!rmidi)
return -EINVAL;
diff --git a/src/seq/seq.c b/src/seq/seq.c
index 771f18b3..ebf16e40 100644
--- a/src/seq/seq.c
+++ b/src/seq/seq.c
@@ -119,7 +119,7 @@ int snd_seq_close(snd_seq_t *seq)
/*
* returns the file descriptor of the client
*/
-int snd_seq_file_descriptor(snd_seq_t *seq)
+int snd_seq_poll_descriptor(snd_seq_t *seq)
{
if (!seq)
return -EINVAL;
diff --git a/src/timer/timer.c b/src/timer/timer.c
index 41f42d7c..7201b0cf 100644
--- a/src/timer/timer.c
+++ b/src/timer/timer.c
@@ -78,7 +78,7 @@ int snd_timer_close(snd_timer_t *handle)
return res;
}
-int snd_timer_file_descriptor(snd_timer_t *handle)
+int snd_timer_poll_descriptor(snd_timer_t *handle)
{
snd_timer_t *tmr;
diff --git a/test/latency.c b/test/latency.c
index 961d1e68..6daf446b 100644
--- a/test/latency.c
+++ b/test/latency.c
@@ -47,11 +47,11 @@ int setparams(snd_pcm_t *phandle, snd_pcm_t *chandle, int *bufsize)
params.mode = SND_PCM_MODE_FRAME;
#endif
params.format.interleave = 1;
- params.format.format = SND_PCM_SFMT_S16_LE;
+ params.format.sfmt = SND_PCM_SFMT_S16_LE;
params.format.channels = 2;
params.format.rate = USED_RATE;
- params.start_mode = SND_PCM_START_GO;
- params.xrun_mode = SND_PCM_XRUN_DRAIN;
+ params.start_mode = SND_PCM_START_EXPLICIT;
+ params.xrun_action = SND_PCM_XRUN_ACT_DRAIN;
params.time = 1;
*bufsize += 4;
@@ -152,7 +152,7 @@ long readbuf(snd_pcm_t *handle, char *buf, long len, size_t *frames)
long r;
do {
- r = snd_pcm_read(handle, buf, len);
+ r = snd_pcm_readi(handle, buf, len);
} while (r == -EAGAIN);
if (r > 0)
*frames += r;
@@ -166,7 +166,7 @@ long writebuf(snd_pcm_t *handle, char *buf, long len, size_t *frames)
long r;
while (len > 0) {
- r = snd_pcm_write(handle, buf, len);
+ r = snd_pcm_writei(handle, buf, len);
if (r == -EAGAIN)
continue;
// printf("write = %li\n", r);
@@ -225,7 +225,7 @@ int main(void)
break;
}
- if ((err = snd_pcm_go(phandle)) < 0) {
+ if ((err = snd_pcm_start(phandle)) < 0) {
printf("Go error: %s\n", snd_strerror(err));
exit(0);
}
diff --git a/test/loopback.c b/test/loopback.c
index d9e0cdbe..83265955 100644
--- a/test/loopback.c
+++ b/test/loopback.c
@@ -15,7 +15,7 @@ static void show_format1(const char *prefix, snd_pcm_format_t *format)
format->interleave ? 1 : 0,
format->rate,
format->voices,
- format->format);
+ format->sfmt);
}
static void show_format(snd_pcm_loopback_t *handle)
diff --git a/test/pause.c b/test/pause.c
index 7c865ab0..0da03421 100644
--- a/test/pause.c
+++ b/test/pause.c
@@ -39,7 +39,7 @@ int main(void)
fprintf(stderr, "open failed: %s\n", snd_strerror(err));
return 0;
}
- format.format = SND_PCM_SFMT_MU_LAW;
+ format.sfmt = SND_PCM_SFMT_MU_LAW;
format.rate = 8000;
format.channels = 1;
if ((err = snd_pcm_playback_format(handle, &format)) < 0) {
@@ -82,7 +82,7 @@ int main(void)
}
count1 = status.fragment_size * 12;
show_playback_status(handle);
- size = snd_pcm_write(handle, buffer1, count1);
+ size = snd_pcm_writei(handle, buffer1, count1);
sleep(2);
show_playback_status(handle);
printf("Pause.. Bytes written %i from %i...\n", size, count1);
@@ -94,7 +94,7 @@ int main(void)
printf("Pause end..\n");
snd_pcm_playback_pause(handle, 0);
show_playback_status(handle);
- size = snd_pcm_write(handle, buffer1, count);
+ size = snd_pcm_writei(handle, buffer1, count);
printf("Pause end.. Bytes written %i from %i...\n", size, count);
snd_pcm_close(handle);
free(buffer);
diff --git a/test/pcm.c b/test/pcm.c
index 643a0c19..d48c25c4 100644
--- a/test/pcm.c
+++ b/test/pcm.c
@@ -18,7 +18,7 @@ void setformat(void *phandle, void *rhandle)
snd_pcm_format_t format;
bzero(&format, sizeof(format));
- format.format = SND_PCM_SFMT_S16_LE;
+ format.sfmt = SND_PCM_SFMT_S16_LE;
format.channels = 2;
format.rate = 22050;
if ((err = snd_pcm_playback_format(phandle, &format)) < 0) {
@@ -46,14 +46,14 @@ void method1(void)
setformat(phandle, rhandle);
printf("Recording... ");
fflush(stdout);
- if ((err = snd_pcm_read(rhandle, buffer, sizeof(buffer))) != sizeof(buffer)) {
+ if ((err = snd_pcm_readi(rhandle, buffer, sizeof(buffer))) != sizeof(buffer)) {
printf("Read error: %s\n", err < 0 ? snd_strerror(err) : xitoa(err));
return;
}
printf("done...\n");
printf("Playback... ");
fflush(stdout);
- if ((err = snd_pcm_write(phandle, buffer, sizeof(buffer))) != sizeof(buffer)) {
+ if ((err = snd_pcm_writei(phandle, buffer, sizeof(buffer))) != sizeof(buffer)) {
printf("Write error: %s\n", err < 0 ? snd_strerror(err) : xitoa(err));
return;
}
@@ -81,7 +81,7 @@ void method2(void)
setformat(phandle, rhandle);
printf("Recording... ");
fflush(stdout);
- if ((err = snd_pcm_read(rhandle, buffer, sizeof(buffer))) != sizeof(buffer)) {
+ if ((err = snd_pcm_readi(rhandle, buffer, sizeof(buffer))) != sizeof(buffer)) {
printf("Read error: %s\n", err < 0 ? snd_strerror(err) : xitoa(err));
return;
}
@@ -93,7 +93,7 @@ void method2(void)
printf("Record flush done...\n");
printf("Playback... ");
fflush(stdout);
- if ((err = snd_pcm_write(phandle, buffer, sizeof(buffer))) != sizeof(buffer)) {
+ if ((err = snd_pcm_writei(phandle, buffer, sizeof(buffer))) != sizeof(buffer)) {
printf("Write error: %s\n", err < 0 ? snd_strerror(err) : xitoa(err));
return;
}
@@ -122,7 +122,7 @@ void method3(void)
setformat(handle, handle);
printf("Recording... ");
fflush(stdout);
- if ((err = snd_pcm_read(handle, buffer, sizeof(buffer))) != sizeof(buffer)) {
+ if ((err = snd_pcm_readi(handle, buffer, sizeof(buffer))) != sizeof(buffer)) {
printf("Read error: %s\n", err < 0 ? snd_strerror(err) : xitoa(err));
return;
}
@@ -134,7 +134,7 @@ void method3(void)
printf("Record flush done...\n");
printf("Playback... ");
fflush(stdout);
- if ((err = snd_pcm_write(handle, buffer, sizeof(buffer))) != sizeof(buffer)) {
+ if ((err = snd_pcm_writei(handle, buffer, sizeof(buffer))) != sizeof(buffer)) {
printf("Write error: %s\n", err < 0 ? snd_strerror(err) : xitoa(err));
return;
}
diff --git a/test/playmidi1.c b/test/playmidi1.c
index 85c76bd9..c2e6ec9e 100644
--- a/test/playmidi1.c
+++ b/test/playmidi1.c
@@ -116,7 +116,7 @@ static void write_ev(snd_seq_event_t *ev)
while ((rc = snd_seq_event_output(seq_handle, ev)) < 0) {
int seqfd;
fd_set fds;
- seqfd = snd_seq_file_descriptor(seq_handle);
+ seqfd = snd_seq_poll_descriptor(seq_handle);
FD_ZERO(&fds);
FD_SET(seqfd, &fds);
if ((rc = select(seqfd + 1, NULL, &fds, NULL, NULL)) < 0) {
@@ -366,7 +366,7 @@ static snd_seq_event_t *wait_for_event(void)
input_event == NULL) {
int seqfd;
fd_set fds;
- seqfd = snd_seq_file_descriptor(seq_handle);
+ seqfd = snd_seq_poll_descriptor(seq_handle);
FD_ZERO(&fds);
FD_SET(seqfd, &fds);
if ((left = select(seqfd + 1, &fds, NULL, NULL, NULL)) < 0) {
diff --git a/test/seq-decoder.c b/test/seq-decoder.c
index a87943a3..e3b075e0 100644
--- a/test/seq-decoder.c
+++ b/test/seq-decoder.c
@@ -481,7 +481,7 @@ void event_decoder(snd_seq_t *handle, int argc, char *argv[])
while (1) {
FD_ZERO(&in);
- FD_SET(max = snd_seq_file_descriptor(handle), &in);
+ FD_SET(max = snd_seq_poll_descriptor(handle), &in);
if (select(max + 1, &in, NULL, NULL, NULL) < 0)
break;
do {
diff --git a/test/seq-sender.c b/test/seq-sender.c
index d00eaf5b..8905ac82 100644
--- a/test/seq-sender.c
+++ b/test/seq-sender.c
@@ -14,7 +14,7 @@ void set_format(snd_pcm_t *phandle)
snd_pcm_format_t format;
bzero(&format, sizeof(format));
- format.format = SND_PCM_SFMT_S16_LE;
+ format.sfmt = SND_PCM_SFMT_S16_LE;
format.channels = 2;
format.rate = 44100;
if ((err = snd_pcm_playback_format(phandle, &format)) < 0) {
@@ -225,31 +225,31 @@ void event_sender(snd_seq_t *handle, int argc, char *argv[])
while (1) {
FD_ZERO(&out);
FD_ZERO(&in);
- max = snd_seq_file_descriptor(handle);
- FD_SET(snd_seq_file_descriptor(handle), &in);
+ max = snd_seq_poll_descriptor(handle);
+ FD_SET(snd_seq_poll_descriptor(handle), &in);
if (snd_seq_event_output_pending(handle)) {
- FD_SET(snd_seq_file_descriptor(handle), &out);
+ FD_SET(snd_seq_poll_descriptor(handle), &out);
}
#ifdef USE_PCM
if (phandle) {
- if (snd_pcm_file_descriptor(phandle) > max)
- max = snd_pcm_file_descriptor(phandle);
- FD_SET(snd_pcm_file_descriptor(phandle), &out);
+ if (snd_pcm_poll_descriptor(phandle) > max)
+ max = snd_pcm_poll_descriptor(phandle);
+ FD_SET(snd_pcm_poll_descriptor(phandle), &out);
}
#endif
if (select(max + 1, &in, &out, NULL, NULL) < 0)
break;
#ifdef USE_PCM
- if (phandle && FD_ISSET(snd_pcm_file_descriptor(phandle), &out)) {
- if (snd_pcm_write(phandle, pbuf, pfragment_size) != pfragment_size) {
+ if (phandle && FD_ISSET(snd_pcm_poll_descriptor(phandle), &out)) {
+ if (snd_pcm_writei(phandle, pbuf, pfragment_size) != pfragment_size) {
fprintf(stderr, "Playback write error!!\n");
exit(0);
}
}
#endif
- if (FD_ISSET(snd_seq_file_descriptor(handle), &out))
+ if (FD_ISSET(snd_seq_poll_descriptor(handle), &out))
snd_seq_flush_output(handle);
- if (FD_ISSET(snd_seq_file_descriptor(handle), &in)) {
+ if (FD_ISSET(snd_seq_poll_descriptor(handle), &in)) {
do {
if ((err = snd_seq_event_input(handle, &ev))<0)
break;
diff --git a/test/timer.c b/test/timer.c
index 99fa7813..24953014 100644
--- a/test/timer.c
+++ b/test/timer.c
@@ -28,7 +28,7 @@ void read_loop(void *handle, int master_ticks, int timeout)
while (master_ticks-- > 0) {
FD_ZERO(&in);
- max = snd_timer_file_descriptor(handle);
+ max = snd_timer_poll_descriptor(handle);
FD_SET(max, &in);
tv.tv_sec = timeout;
tv.tv_usec = 0;