summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJaroslav Kysela <perex@perex.cz>2000-11-20 20:10:46 +0000
committerJaroslav Kysela <perex@perex.cz>2000-11-20 20:10:46 +0000
commit41bb7068f2e8b54c73874f40efcc89204f9992e0 (patch)
tree849db082c98e4442e480d5b673bd42c2ab0ec339
parent3cc2b957fbe73dcdf34f34ce70e6b85e06d915d0 (diff)
Merged pcmfinal branch.
-rw-r--r--TODO2
-rw-r--r--aserver/aserver.c49
-rw-r--r--include/aserver.h12
-rw-r--r--include/conf.h6
-rw-r--r--include/control.h16
-rw-r--r--include/header.h2
-rw-r--r--include/hwdep.h2
-rw-r--r--include/instr.h2
-rw-r--r--include/mixer.h12
-rw-r--r--include/pcm.h144
-rw-r--r--include/rawmidi.h28
-rw-r--r--include/seq.h20
-rw-r--r--include/timer.h3
-rw-r--r--src/control/cards.c1
-rw-r--r--src/control/control.c16
-rw-r--r--src/control/control_hw.c2
-rw-r--r--src/control/control_local.h19
-rw-r--r--src/control/control_shm.c2
-rw-r--r--src/error.c14
-rw-r--r--src/hwdep/hwdep.c2
-rw-r--r--src/instr/iwffff.c2
-rw-r--r--src/mixer/mixer_local.h10
-rw-r--r--src/pcm/pcm.c1869
-rw-r--r--src/pcm/pcm_adpcm.c142
-rw-r--r--src/pcm/pcm_alaw.c138
-rw-r--r--src/pcm/pcm_file.c114
-rw-r--r--src/pcm/pcm_hw.c170
-rw-r--r--src/pcm/pcm_linear.c116
-rw-r--r--src/pcm/pcm_local.h129
-rw-r--r--src/pcm/pcm_misc.c296
-rw-r--r--src/pcm/pcm_mmap.c318
-rw-r--r--src/pcm/pcm_mulaw.c138
-rw-r--r--src/pcm/pcm_multi.c252
-rw-r--r--src/pcm/pcm_null.c166
-rw-r--r--src/pcm/pcm_plug.c572
-rw-r--r--src/pcm/pcm_plugin.c91
-rw-r--r--src/pcm/pcm_plugin.h39
-rw-r--r--src/pcm/pcm_rate.c313
-rw-r--r--src/pcm/pcm_route.c203
-rw-r--r--src/pcm/pcm_share.c404
-rw-r--r--src/pcm/pcm_shm.c218
-rw-r--r--src/rawmidi/Makefile.am4
-rw-r--r--src/rawmidi/rawmidi.c323
-rw-r--r--src/rawmidi/rawmidi_hw.c320
-rw-r--r--src/rawmidi/rawmidi_local.h60
-rw-r--r--src/seq/Makefile.am4
-rw-r--r--src/seq/seq.c570
-rw-r--r--src/seq/seq_hw.c545
-rw-r--r--src/seq/seq_local.h105
-rw-r--r--src/seq/seq_priv.h40
-rw-r--r--src/seq/seqmid.c2
-rw-r--r--src/timer/timer.c14
-rw-r--r--test/latency.c4
-rw-r--r--test/pause.c2
-rw-r--r--test/pcm.c2
-rw-r--r--test/pcmtest.c48
-rw-r--r--test/seq-sender.c2
57 files changed, 5100 insertions, 2999 deletions
diff --git a/TODO b/TODO
index ecf105a4..d89b5909 100644
--- a/TODO
+++ b/TODO
@@ -1,3 +1,3 @@
M think about xrun recovery helpers
-M add abstraction layer to timer, rawmidi, hwdep, seq
+M add abstraction layer to timer, hwdep
L move OSS emulation to user space? (pseudo device driver and daemon)
diff --git a/aserver/aserver.c b/aserver/aserver.c
index 5e54d0b0..3b326ff8 100644
--- a/aserver/aserver.c
+++ b/aserver/aserver.c
@@ -379,14 +379,20 @@ int pcm_shm_cmd(client_t *client)
case SND_PCM_IOCTL_INFO:
ctrl->result = snd_pcm_info(pcm, (snd_pcm_info_t *) &ctrl->u.info);
break;
- case SND_PCM_IOCTL_PARAMS:
- ctrl->result = snd_pcm_params(pcm, (snd_pcm_params_t *) &ctrl->u.params);
+ case SND_PCM_IOCTL_HW_INFO:
+ ctrl->result = snd_pcm_hw_info(pcm, (snd_pcm_hw_info_t *) &ctrl->u.hw_info);
break;
- case SND_PCM_IOCTL_PARAMS_INFO:
- ctrl->result = snd_pcm_params_info(pcm, (snd_pcm_params_info_t *) &ctrl->u.params_info);
+ case SND_PCM_IOCTL_HW_PARAMS:
+ ctrl->result = snd_pcm_hw_params(pcm, (snd_pcm_hw_params_t *) &ctrl->u.hw_params);
break;
- case SND_PCM_IOCTL_SETUP:
- ctrl->result = snd_pcm_setup(pcm, (snd_pcm_setup_t *) &ctrl->u.setup);
+ case SND_PCM_IOCTL_SW_PARAMS:
+ ctrl->result = snd_pcm_sw_params(pcm, (snd_pcm_sw_params_t *) &ctrl->u.sw_params);
+ break;
+ case SND_PCM_IOCTL_DIG_PARAMS:
+ ctrl->result = snd_pcm_dig_params(pcm, (snd_pcm_dig_params_t *) &ctrl->u.dig_params);
+ break;
+ case SND_PCM_IOCTL_DIG_INFO:
+ ctrl->result = snd_pcm_dig_info(pcm, (snd_pcm_dig_info_t *) &ctrl->u.dig_info);
break;
case SND_PCM_IOCTL_STATUS:
ctrl->result = snd_pcm_status(pcm, (snd_pcm_status_t *) &ctrl->u.status);
@@ -422,12 +428,9 @@ int pcm_shm_cmd(client_t *client)
break;
case SND_PCM_IOCTL_CHANNEL_INFO:
ctrl->result = snd_pcm_channel_info(pcm, (snd_pcm_channel_info_t *) &ctrl->u.channel_info);
- break;
- case SND_PCM_IOCTL_CHANNEL_PARAMS:
- ctrl->result = snd_pcm_channel_params(pcm, (snd_pcm_channel_params_t *) &ctrl->u.channel_params);
- break;
- case SND_PCM_IOCTL_CHANNEL_SETUP:
- ctrl->result = snd_pcm_channel_setup(pcm, (snd_pcm_channel_setup_t *) &ctrl->u.channel_setup);
+ if (ctrl->result >= 0 &&
+ ctrl->u.channel_info.type == SND_PCM_AREA_MMAP)
+ return shm_ack_fd(client, ctrl->u.channel_info.u.mmap.fd);
break;
case SND_PCM_IOCTL_REWIND:
ctrl->result = snd_pcm_rewind(pcm, ctrl->u.rewind.frames);
@@ -444,27 +447,7 @@ int pcm_shm_cmd(client_t *client)
break;
case SND_PCM_IOCTL_MMAP:
{
- err = snd_pcm_mmap(pcm);
- if (err < 0)
- ctrl->result = err;
- else
- ctrl->result = pcm->mmap_info_count;
- break;
- }
- case SND_PCM_IOCTL_MMAP_INFO:
- {
- unsigned int index = ctrl->u.mmap_info.index;
- snd_pcm_mmap_info_t *i = &pcm->mmap_info[index];
- if (index >= pcm->mmap_info_count) {
- ctrl->result = -EINVAL;
- break;
- }
- ctrl->u.mmap_info = *i;
- ctrl->u.mmap_info.index = index;
- ctrl->result = 0;
- if (i->type == SND_PCM_MMAP_USER)
- break;
- return shm_ack_fd(client, i->u.kernel.fd);
+ ctrl->result = snd_pcm_mmap(pcm);
}
case SND_PCM_IOCTL_MUNMAP:
{
diff --git a/include/aserver.h b/include/aserver.h
index 85823fd8..6106d43a 100644
--- a/include/aserver.h
+++ b/include/aserver.h
@@ -28,7 +28,6 @@
#define SND_PCM_IOCTL_AVAIL_UPDATE _IO ('A', 0xf8)
#define SND_PCM_IOCTL_ASYNC _IO ('A', 0xf9)
#define SND_PCM_IOCTL_CLOSE _IO ('A', 0xfa)
-#define SND_PCM_IOCTL_MMAP_INFO _IO ('A', 0xfb)
#define SND_PCM_IOCTL_POLL_DESCRIPTOR _IO ('A', 0xfc)
#define SND_PCM_IOCTL_SET_AVAIL_MIN _IO ('A', 0xfd)
@@ -42,11 +41,12 @@ typedef struct {
int sig;
pid_t pid;
} async;
- snd_pcm_mmap_info_t mmap_info;
snd_pcm_info_t info;
- snd_pcm_params_t params;
- snd_pcm_params_info_t params_info;
- snd_pcm_setup_t setup;
+ snd_pcm_hw_info_t hw_info;
+ snd_pcm_hw_params_t hw_params;
+ snd_pcm_sw_params_t sw_params;
+ snd_pcm_dig_params_t dig_params;
+ snd_pcm_dig_info_t dig_info;
snd_pcm_status_t status;
struct {
ssize_t frames;
@@ -55,8 +55,6 @@ typedef struct {
int enable;
} pause;
snd_pcm_channel_info_t channel_info;
- snd_pcm_channel_params_t channel_params;
- snd_pcm_channel_setup_t channel_setup;
struct {
ssize_t frames;
} rewind;
diff --git a/include/conf.h b/include/conf.h
index d2858380..00ae6f99 100644
--- a/include/conf.h
+++ b/include/conf.h
@@ -1,14 +1,14 @@
-typedef enum {
+typedef enum _snd_config_type {
SND_CONFIG_TYPE_INTEGER,
SND_CONFIG_TYPE_REAL,
SND_CONFIG_TYPE_STRING,
SND_CONFIG_TYPE_COMPOUND,
} snd_config_type_t;
-typedef struct snd_config snd_config_t;
+typedef struct _snd_config snd_config_t;
-struct snd_config {
+struct _snd_config {
char *id;
snd_config_type_t type;
union {
diff --git a/include/control.h b/include/control.h
index 864a39e4..f786b014 100644
--- a/include/control.h
+++ b/include/control.h
@@ -5,14 +5,14 @@
* *
****************************************************************************/
-typedef struct snd_ctl snd_ctl_t;
+typedef struct _snd_ctl snd_ctl_t;
-typedef enum { SND_CTL_TYPE_HW,
+typedef enum _snd_ctl_type { SND_CTL_TYPE_HW,
SND_CTL_TYPE_SHM,
SND_CTL_TYPE_INET
} snd_ctl_type_t;
-typedef struct snd_ctl_callbacks {
+typedef struct _snd_ctl_callbacks {
void *private_data; /* may be used by an application */
void (*rebuild) (snd_ctl_t *handle, void *private_data);
void (*value) (snd_ctl_t *handle, void *private_data, snd_control_id_t * id);
@@ -40,8 +40,6 @@ int snd_defaults_pcm_device(void);
int snd_defaults_rawmidi_card(void);
int snd_defaults_rawmidi_device(void);
-int snd_ctl_hw_open(snd_ctl_t **handle, char *name, int card);
-int snd_ctl_shm_open(snd_ctl_t **handlep, char *name, char *socket, char *sname);
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);
@@ -82,10 +80,10 @@ struct list_head {
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
-typedef struct snd_hcontrol_list_stru snd_hcontrol_list_t;
-typedef struct snd_hcontrol_stru snd_hcontrol_t;
+typedef struct _snd_hcontrol_list snd_hcontrol_list_t;
+typedef struct _snd_hcontrol snd_hcontrol_t;
-struct snd_hcontrol_list_stru {
+struct _snd_hcontrol_list {
unsigned int controls_offset; /* W: first control ID to get */
unsigned int controls_request; /* W: count of control IDs to get */
unsigned int controls_count; /* R: count of available (set) controls */
@@ -93,7 +91,7 @@ struct snd_hcontrol_list_stru {
snd_control_id_t *pids; /* W: IDs */
};
-struct snd_hcontrol_stru {
+struct _snd_hcontrol {
snd_control_id_t id; /* must be always on top */
struct list_head list; /* links for list of all hcontrols */
int change: 1, /* structure change */
diff --git a/include/header.h b/include/header.h
index 6875e256..8ce91f67 100644
--- a/include/header.h
+++ b/include/header.h
@@ -46,3 +46,5 @@
#define SND_TRANSPORT_TYPE_SHM 0
#define SND_TRANSPORT_TYPE_TCP 1
+extern void snd_lib_error(const char *file, int line, const char *function, int err, const char *fmt, ...) __attribute__ ((weak, format (printf, 5, 6)));
+
diff --git a/include/hwdep.h b/include/hwdep.h
index 6446543b..ecd79581 100644
--- a/include/hwdep.h
+++ b/include/hwdep.h
@@ -14,7 +14,7 @@
extern "C" {
#endif
-typedef struct snd_hwdep snd_hwdep_t;
+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);
diff --git a/include/instr.h b/include/instr.h
index a9922d76..c1c29315 100644
--- a/include/instr.h
+++ b/include/instr.h
@@ -40,7 +40,7 @@ int snd_instr_simple_free(snd_instr_simple_t *simple);
/* InterWave FFFF support */
typedef void snd_instr_iwffff_t;
-typedef struct snd_iwffff_handle snd_iwffff_handle_t;
+typedef struct _snd_iwffff_handle snd_iwffff_handle_t;
#ifdef __cplusplus
extern "C" {
diff --git a/include/mixer.h b/include/mixer.h
index f7eab69b..c53de78c 100644
--- a/include/mixer.h
+++ b/include/mixer.h
@@ -5,7 +5,7 @@
* *
****************************************************************************/
-typedef struct snd_mixer snd_mixer_t;
+typedef struct _snd_mixer snd_mixer_t;
#ifdef __cplusplus
extern "C" {
@@ -23,7 +23,7 @@ int snd_mixer_poll_descriptor(snd_mixer_t *handle);
* Simple (legacy) mixer API
*/
-typedef enum {
+typedef enum _snd_mixer_channel_id {
SND_MIXER_CHN_FRONT_LEFT = 0,
SND_MIXER_CHN_FRONT_RIGHT,
SND_MIXER_CHN_FRONT_CENTER,
@@ -51,12 +51,12 @@ typedef enum {
#define SND_MIXER_SCTCAP_JOINTLY_CAPTURE (1<<5)
#define SND_MIXER_SCTCAP_EXCL_CAPTURE (1<<6)
-typedef struct snd_mixer_sid {
+typedef struct _snd_mixer_sid {
unsigned char name[60];
unsigned int index;
} snd_mixer_sid_t;
-typedef struct snd_mixer_simple_control_list {
+typedef struct _snd_mixer_simple_control_list {
unsigned int controls_offset; /* W: first control ID to get */
unsigned int controls_request; /* W: count of control IDs to get */
unsigned int controls_count; /* R: count of available (set) IDs */
@@ -65,7 +65,7 @@ typedef struct snd_mixer_simple_control_list {
char reserved[50];
} snd_mixer_simple_control_list_t;
-typedef struct snd_mixer_simple_control {
+typedef struct _snd_mixer_simple_control {
snd_mixer_sid_t sid; /* WR: simple control identification */
unsigned int caps; /* RO: capabilities */
unsigned int channels; /* RO: bitmap of active channels */
@@ -88,7 +88,7 @@ typedef struct snd_mixer_simple_control {
} volume; /* RW */
} snd_mixer_simple_control_t;
-typedef struct snd_mixer_simple_callbacks {
+typedef struct _snd_mixer_simple_callbacks {
void *private_data; /* may be used by an application */
void (*rebuild) (snd_mixer_t *handle, void *private_data);
void (*value) (snd_mixer_t *handle, void *private_data, snd_mixer_sid_t *id);
diff --git a/include/pcm.h b/include/pcm.h
index 364ec5c4..c0ecee92 100644
--- a/include/pcm.h
+++ b/include/pcm.h
@@ -12,94 +12,9 @@
extern "C" {
#endif
-typedef unsigned int bitset_t;
+typedef struct _snd_pcm snd_pcm_t;
-static inline size_t bitset_size(size_t nbits)
-{
- return (nbits + sizeof(bitset_t) * 8 - 1) / (sizeof(bitset_t) * 8);
-}
-
-static inline bitset_t *bitset_alloc(size_t nbits)
-{
- return (bitset_t*) calloc(bitset_size(nbits), sizeof(bitset_t));
-}
-
-static inline void bitset_set(bitset_t *bitmap, unsigned int pos)
-{
- size_t bits = sizeof(*bitmap) * 8;
- bitmap[pos / bits] |= 1U << (pos % bits);
-}
-
-static inline void bitset_reset(bitset_t *bitmap, unsigned int pos)
-{
- size_t bits = sizeof(*bitmap) * 8;
- bitmap[pos / bits] &= ~(1U << (pos % bits));
-}
-
-static inline int bitset_get(bitset_t *bitmap, unsigned int pos)
-{
- size_t bits = sizeof(*bitmap) * 8;
- return !!(bitmap[pos / bits] & (1U << (pos % bits)));
-}
-
-static inline void bitset_copy(bitset_t *dst, bitset_t *src, size_t nbits)
-{
- memcpy(dst, src, bitset_size(nbits) * sizeof(bitset_t));
-}
-
-static inline void bitset_and(bitset_t *dst, bitset_t *bs, size_t nbits)
-{
- bitset_t *end = dst + bitset_size(nbits);
- while (dst < end)
- *dst++ &= *bs++;
-}
-
-static inline void bitset_or(bitset_t *dst, bitset_t *bs, size_t nbits)
-{
- bitset_t *end = dst + bitset_size(nbits);
- while (dst < end)
- *dst++ |= *bs++;
-}
-
-static inline void bitset_zero(bitset_t *dst, size_t nbits)
-{
- bitset_t *end = dst + bitset_size(nbits);
- while (dst < end)
- *dst++ = 0;
-}
-
-static inline void bitset_one(bitset_t *dst, size_t nbits)
-{
- bitset_t *end = dst + bitset_size(nbits);
- while (dst < end)
- *dst++ = ~(bitset_t)0;
-}
-
-static inline size_t hweight32(bitset_t v)
-{
- v = (v & 0x55555555) + ((v >> 1) & 0x55555555);
- v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
- v = (v & 0x0F0F0F0F) + ((v >> 4) & 0x0F0F0F0F);
- v = (v & 0x00FF00FF) + ((v >> 8) & 0x00FF00FF);
- return (v & 0x0000FFFF) + ((v >> 16) & 0x0000FFFF);
-}
-
-/* Count bits set */
-static inline size_t bitset_count(bitset_t *bitset, size_t nbits)
-{
- bitset_t *end = bitset + bitset_size(nbits) - 1;
- size_t bits = sizeof(*bitset) * 8;
- size_t count = 0;
- while (bitset < end)
- count += hweight32(*bitset++);
- count += hweight32(*bitset & ((1U << (nbits % bits)) - 1));
- return count;
-}
-
-typedef struct snd_pcm snd_pcm_t;
-typedef struct snd_pcm_loopback snd_pcm_loopback_t;
-
-typedef enum {
+typedef enum _snd_pcm_type {
SND_PCM_TYPE_HW,
SND_PCM_TYPE_MULTI,
SND_PCM_TYPE_FILE,
@@ -119,16 +34,28 @@ typedef enum {
SND_PCM_TYPE_LBSERVER,
} snd_pcm_type_t;
-extern void snd_pcm_error(const char *file, int line, const char *function, int err, const char *fmt, ...) __attribute__ ((weak, format (printf, 5, 6)));
+enum {
+ SND_PCM_RULE_PAR_MASK = 0x00ff,
+ SND_PCM_RULE_REL_LT = 0x100,
+ SND_PCM_RULE_REL_GT = 0x200,
+ SND_PCM_RULE_REL_EQ = 0x300,
+ SND_PCM_RULE_REL_LE = 0x400,
+ SND_PCM_RULE_REL_GE = 0x500,
+ SND_PCM_RULE_REL_NEAR = 0x600,
+ SND_PCM_RULE_REL_BITS = 0x700,
+ SND_PCM_RULE_REL_MASK = 0xff00
+};
+
+typedef struct _snd_pcm_channel_area {
+ void *addr; /* base address of channel samples */
+ unsigned int first; /* offset to first sample in bits */
+ unsigned int step; /* samples distance in bits */
+} snd_pcm_channel_area_t;
int snd_pcm_open(snd_pcm_t **pcm, char *name,
int stream, int mode);
/* Obsolete functions */
-int snd_pcm_hw_open_subdevice(snd_pcm_t **pcm, int card, int device, int subdevice, int stream, int mode);
-int snd_pcm_hw_open_device(snd_pcm_t **pcm, int card, int device, int stream, int mode);
-int snd_pcm_plug_open_subdevice(snd_pcm_t **pcm, int card, int device, int subdevice, int stream, int mode);
-int snd_pcm_plug_open_device(snd_pcm_t **pcm, 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 *pcm, const struct iovec *vector, int count);
@@ -141,12 +68,11 @@ int snd_pcm_poll_descriptor(snd_pcm_t *pcm);
int snd_pcm_nonblock(snd_pcm_t *pcm, int nonblock);
int snd_pcm_async(snd_pcm_t *pcm, int sig, pid_t pid);
int snd_pcm_info(snd_pcm_t *pcm, snd_pcm_info_t *info);
-int snd_pcm_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t *info);
-int snd_pcm_params(snd_pcm_t *pcm, snd_pcm_params_t *params);
-int snd_pcm_setup(snd_pcm_t *pcm, snd_pcm_setup_t *setup);
-int snd_pcm_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info);
-int snd_pcm_channel_params(snd_pcm_t *pcm, snd_pcm_channel_params_t *params);
-int snd_pcm_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t *setup);
+int snd_pcm_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t *info);
+int snd_pcm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params);
+int snd_pcm_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *params);
+int snd_pcm_dig_info(snd_pcm_t *pcm, snd_pcm_dig_info_t *info);
+int snd_pcm_dig_params(snd_pcm_t *pcm, snd_pcm_dig_params_t *params);
int snd_pcm_status(snd_pcm_t *pcm, snd_pcm_status_t *status);
int snd_pcm_prepare(snd_pcm_t *pcm);
int snd_pcm_start(snd_pcm_t *pcm);
@@ -160,23 +86,35 @@ ssize_t snd_pcm_writei(snd_pcm_t *pcm, const void *buffer, size_t size);
ssize_t snd_pcm_readi(snd_pcm_t *pcm, void *buffer, size_t size);
ssize_t snd_pcm_writen(snd_pcm_t *pcm, void **bufs, size_t size);
ssize_t snd_pcm_readn(snd_pcm_t *pcm, void **bufs, size_t size);
+
+int snd_pcm_dump_hw_setup(snd_pcm_t *pcm, FILE *fp);
+int snd_pcm_dump_sw_setup(snd_pcm_t *pcm, FILE *fp);
int snd_pcm_dump_setup(snd_pcm_t *pcm, FILE *fp);
+int snd_pcm_dump_hw_params_fail(snd_pcm_hw_params_t *params, FILE *fp);
+int snd_pcm_dump_sw_params_fail(snd_pcm_sw_params_t *params, FILE *fp);
int snd_pcm_dump(snd_pcm_t *pcm, FILE *fp);
int snd_pcm_dump_status(snd_pcm_status_t *status, FILE *fp);
int snd_pcm_link(snd_pcm_t *pcm1, snd_pcm_t *pcm2);
int snd_pcm_unlink(snd_pcm_t *pcm);
-int snd_pcm_channels_mask(snd_pcm_t *pcm, bitset_t *cmask);
int snd_pcm_wait(snd_pcm_t *pcm, int timeout);
ssize_t snd_pcm_avail_update(snd_pcm_t *pcm);
int snd_pcm_set_avail_min(snd_pcm_t *pcm, size_t size);
-
+int snd_pcm_hw_params_rules(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+ unsigned int count, int *rules);
+int snd_pcm_hw_params_rulesv(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, ...);
+int snd_pcm_hw_info_rules(snd_pcm_t *pcm,
+ snd_pcm_hw_info_t *info,
+ snd_pcm_hw_params_t *params,
+ unsigned int count, int *rules);
+int snd_pcm_hw_info_rulesv(snd_pcm_t *pcm,
+ snd_pcm_hw_info_t *info,
+ snd_pcm_hw_params_t *params, ...);
/* mmap */
-int snd_pcm_mmap(snd_pcm_t *pcm);
-int snd_pcm_munmap(snd_pcm_t *pcm);
snd_pcm_channel_area_t *snd_pcm_mmap_areas(snd_pcm_t *pcm);
-int snd_pcm_mmap_get_areas(snd_pcm_t *pcm, snd_pcm_channel_area_t *stopped_areas, snd_pcm_channel_area_t *running_areas);
+snd_pcm_channel_area_t *snd_pcm_mmap_running_areas(snd_pcm_t *pcm);
+snd_pcm_channel_area_t *snd_pcm_mmap_stopped_areas(snd_pcm_t *pcm);
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);
diff --git a/include/rawmidi.h b/include/rawmidi.h
index 2d4a65b7..f75ef0c2 100644
--- a/include/rawmidi.h
+++ b/include/rawmidi.h
@@ -5,31 +5,37 @@
* *
****************************************************************************/
-#define SND_RAWMIDI_OPEN_OUTPUT (O_WRONLY)
-#define SND_RAWMIDI_OPEN_OUTPUT_APPEND (O_WRONLY|O_APPEND|O_NONBLOCK)
-#define SND_RAWMIDI_OPEN_INPUT (O_RDONLY)
-#define SND_RAWMIDI_OPEN_DUPLEX (O_RDWR)
-#define SND_RAWMIDI_OPEN_DUPLEX_APPEND (O_RDWR|O_APPEND|O_NONBLOCK)
-#define SND_RAWMIDI_OPEN_NONBLOCK (O_NONBLOCK)
+#define SND_RAWMIDI_OPEN_OUTPUT (1<<SND_RAWMIDI_STREAM_OUTPUT)
+#define SND_RAWMIDI_OPEN_INPUT (1<<SND_RAWMIDI_STREAM_INPUT)
+#define SND_RAWMIDI_OPEN_DUPLEX (SND_RAWMIDI_OPEN_OUTPUT|SND_RAWMIDI_OPEN_INPUT)
+
+#define SND_RAWMIDI_APPEND 1
+#define SND_RAWMIDI_NONBLOCK 2
#ifdef __cplusplus
extern "C" {
#endif
-typedef struct snd_rawmidi snd_rawmidi_t;
+typedef struct _snd_rawmidi snd_rawmidi_t;
+
+typedef enum _snd_rawmidi_type {
+ SND_RAWMIDI_TYPE_HW,
+ SND_RAWMIDI_TYPE_SHM,
+ SND_RAWMIDI_TYPE_INET,
+} snd_rawmidi_type_t;
-int snd_rawmidi_open_subdevice(snd_rawmidi_t **handle, int card, int device, int subdevice, int mode);
-int snd_rawmidi_open(snd_rawmidi_t **handle, int card, int device, int mode);
+int snd_rawmidi_open(snd_rawmidi_t **handle, char *name, int streams, int mode);
int snd_rawmidi_close(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_nonblock(snd_rawmidi_t *handle, int nonblock);
int snd_rawmidi_info(snd_rawmidi_t *handle, snd_rawmidi_info_t * info);
int snd_rawmidi_params(snd_rawmidi_t *handle, snd_rawmidi_params_t * params);
int snd_rawmidi_status(snd_rawmidi_t *handle, snd_rawmidi_status_t * status);
int snd_rawmidi_output_drop(snd_rawmidi_t *handle);
int snd_rawmidi_output_drain(snd_rawmidi_t *handle);
int snd_rawmidi_input_drain(snd_rawmidi_t *handle);
-int snd_rawmidi_stream_drain(snd_rawmidi_t *handle, int channel);
+int snd_rawmidi_drain(snd_rawmidi_t *handle, int channel);
+int snd_rawmidi_drop(snd_rawmidi_t *handle, int channel);
ssize_t snd_rawmidi_write(snd_rawmidi_t *handle, const void *buffer, size_t size);
ssize_t snd_rawmidi_read(snd_rawmidi_t *handle, void *buffer, size_t size);
diff --git a/include/seq.h b/include/seq.h
index 2ba07c6c..b2a566f5 100644
--- a/include/seq.h
+++ b/include/seq.h
@@ -5,20 +5,28 @@
* *
****************************************************************************/
-#define SND_SEQ_OPEN_OUT (O_WRONLY)
-#define SND_SEQ_OPEN_IN (O_RDONLY)
-#define SND_SEQ_OPEN (O_RDWR)
+#define SND_SEQ_OPEN_OUTPUT 1
+#define SND_SEQ_OPEN_INPUT 2
+#define SND_SEQ_OPEN_DUPLEX (SND_SEQ_OPEN_OUTPUT|SND_SEQ_OPEN_INPUT)
+
+#define SND_SEQ_NONBLOCK 1
#ifdef __cplusplus
extern "C" {
#endif
-typedef struct snd_seq snd_seq_t;
+typedef enum _snd_seq_type {
+ SND_SEQ_TYPE_HW,
+ SND_SEQ_TYPE_SHM,
+ SND_SEQ_TYPE_INET,
+} snd_seq_type_t;
+
+typedef struct _snd_seq snd_seq_t;
-int snd_seq_open(snd_seq_t **handle, int mode);
+int snd_seq_open(snd_seq_t **handle, char *name, int streams, int mode);
int snd_seq_close(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_nonblock(snd_seq_t *handle, int nonblock);
int snd_seq_client_id(snd_seq_t *handle);
int snd_seq_output_buffer_size(snd_seq_t *handle);
int snd_seq_input_buffer_size(snd_seq_t *handle);
diff --git a/include/timer.h b/include/timer.h
index a406d9c0..d01c57eb 100644
--- a/include/timer.h
+++ b/include/timer.h
@@ -9,7 +9,7 @@
extern "C" {
#endif
-typedef struct snd_timer snd_timer_t;
+typedef struct _snd_timer snd_timer_t;
int snd_timer_open(snd_timer_t **handle);
int snd_timer_close(snd_timer_t *handle);
@@ -18,7 +18,6 @@ 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);
int snd_timer_params(snd_timer_t *handle, snd_timer_params_t *params);
-int snd_timer_setup(snd_timer_t *handle, snd_timer_setup_t *setup);
int snd_timer_status(snd_timer_t *handle, snd_timer_status_t *status);
int snd_timer_start(snd_timer_t *handle);
int snd_timer_stop(snd_timer_t *handle);
diff --git a/src/control/cards.c b/src/control/cards.c
index b139e0c8..064e6dbf 100644
--- a/src/control/cards.c
+++ b/src/control/cards.c
@@ -27,6 +27,7 @@
#include <ctype.h>
#include <fcntl.h>
#include <sys/ioctl.h>
+#include "control_local.h"
#include "asoundlib.h"
#define SND_FILE_CONTROL "/dev/snd/controlC%i"
diff --git a/src/control/control.c b/src/control/control.c
index 40c90075..2aa84f2e 100644
--- a/src/control/control.c
+++ b/src/control/control.c
@@ -21,6 +21,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include <stdarg.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
@@ -170,8 +171,16 @@ int snd_ctl_open(snd_ctl_t **ctlp, char *name)
return err;
err = snd_config_searchv(snd_config, &ctl_conf, "ctl", name, 0);
if (err < 0) {
- int cardno = snd_card_get_index(name);
- return snd_ctl_hw_open(ctlp, name, cardno);
+ int card;
+ char socket[256], sname[256];
+ err = sscanf(name, "hw:%d", &card);
+ if (err == 1)
+ return snd_ctl_hw_open(ctlp, NULL, card);
+ err = sscanf(name, "shm:%256s,%256s", socket, sname);
+ if (err == 2)
+ return snd_ctl_shm_open(ctlp, NULL, socket, sname);
+ ERR("Unknown control %s", name);
+ return -ENOENT;
}
if (snd_config_type(ctl_conf) != SND_CONFIG_TYPE_COMPOUND)
return -EINVAL;
@@ -182,8 +191,6 @@ int snd_ctl_open(snd_ctl_t **ctlp, char *name)
if (err < 0)
return err;
err = snd_config_searchv(snd_config, &type_conf, "ctltype", 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)
@@ -215,3 +222,4 @@ int snd_ctl_open(snd_ctl_t **ctlp, char *name)
return -ENXIO;
return open_func(ctlp, name, ctl_conf);
}
+
diff --git a/src/control/control_hw.c b/src/control/control_hw.c
index eb805ae9..152e99c7 100644
--- a/src/control/control_hw.c
+++ b/src/control/control_hw.c
@@ -140,7 +140,7 @@ static int snd_ctl_hw_read(snd_ctl_t *handle, snd_ctl_event_t *event)
return read(hw->fd, event, sizeof(*event));
}
-struct snd_ctl_ops snd_ctl_hw_ops = {
+snd_ctl_ops_t snd_ctl_hw_ops = {
close: snd_ctl_hw_close,
poll_descriptor: snd_ctl_hw_poll_descriptor,
hw_info: snd_ctl_hw_hw_info,
diff --git a/src/control/control_local.h b/src/control/control_local.h
index 8f912ccb..3cfb7f55 100644
--- a/src/control/control_local.h
+++ b/src/control/control_local.h
@@ -23,7 +23,15 @@
#include "asoundlib.h"
#include "list.h"
-struct snd_ctl_ops {
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)
+#define ERR(...) snd_lib_error(__FILE__, __LINE__, __FUNCTION__, 0, __VA_ARGS__)
+#define SYSERR(...) snd_lib_error(__FILE__, __LINE__, __FUNCTION__, errno, __VA_ARGS__)
+#else
+#define ERR(args...) snd_lib_error(__FILE__, __LINE__, __FUNCTION__, 0, ##args)
+#define SYSERR(args...) snd_lib_error(__FILE__, __LINE__, __FUNCTION__, errno, ##args)
+#endif
+
+typedef struct {
int (*close)(snd_ctl_t *handle);
int (*poll_descriptor)(snd_ctl_t *handle);
int (*hw_info)(snd_ctl_t *handle, snd_ctl_hw_info_t *info);
@@ -37,13 +45,13 @@ struct snd_ctl_ops {
int (*rawmidi_info)(snd_ctl_t *handle, snd_rawmidi_info_t * info);
int (*rawmidi_prefer_subdevice)(snd_ctl_t *handle, int subdev);
int (*read)(snd_ctl_t *handle, snd_ctl_event_t *event);
-};
+} snd_ctl_ops_t;
-struct snd_ctl {
+struct _snd_ctl {
char *name;
snd_ctl_type_t type;
- struct snd_ctl_ops *ops;
+ snd_ctl_ops_t *ops;
void *private;
int hcount;
int herr;
@@ -56,3 +64,6 @@ struct snd_ctl {
snd_ctl_hcallback_add_t *callback_add;
void *callback_add_private_data;
};
+
+int snd_ctl_hw_open(snd_ctl_t **handle, char *name, int card);
+int snd_ctl_shm_open(snd_ctl_t **handlep, char *name, char *socket, char *sname);
diff --git a/src/control/control_shm.c b/src/control/control_shm.c
index 02210c74..e8086f19 100644
--- a/src/control/control_shm.c
+++ b/src/control/control_shm.c
@@ -266,7 +266,7 @@ static int snd_ctl_shm_read(snd_ctl_t *ctl, snd_ctl_event_t *event)
return err;
}
-struct snd_ctl_ops snd_ctl_shm_ops = {
+snd_ctl_ops_t snd_ctl_shm_ops = {
close: snd_ctl_shm_close,
poll_descriptor: snd_ctl_shm_poll_descriptor,
hw_info: snd_ctl_shm_hw_info,
diff --git a/src/error.c b/src/error.c
index 47fb5ec8..b5871f9a 100644
--- a/src/error.c
+++ b/src/error.c
@@ -23,6 +23,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include <stdarg.h>
#include <string.h>
#include "asoundlib.h"
@@ -42,3 +43,16 @@ const char *snd_strerror(int errnum)
return "Unknown error";
return snd_error_codes[errnum];
}
+
+void snd_lib_error(const char *file, int line, const char *function, int err, const char *fmt, ...)
+{
+ va_list arg;
+ va_start(arg, fmt);
+ fprintf(stderr, "ALSA lib %s:%i:(%s) ", file, line, function);
+ vfprintf(stderr, fmt, arg);
+ if (err)
+ fprintf(stderr, ": %s", snd_strerror(err));
+ putc('\n', stderr);
+ va_end(arg);
+}
+
diff --git a/src/hwdep/hwdep.c b/src/hwdep/hwdep.c
index e6440536..d8e428f9 100644
--- a/src/hwdep/hwdep.c
+++ b/src/hwdep/hwdep.c
@@ -31,7 +31,7 @@
#define SND_FILE_HWDEP "/dev/snd/hwC%iD%i"
#define SND_HWDEP_VERSION_MAX SND_PROTOCOL_VERSION(1, 0, 0)
-struct snd_hwdep {
+struct _snd_hwdep {
int card;
int device;
int fd;
diff --git a/src/instr/iwffff.c b/src/instr/iwffff.c
index 90b3f585..383b40ac 100644
--- a/src/instr/iwffff.c
+++ b/src/instr/iwffff.c
@@ -171,7 +171,7 @@ struct envelope_record {
#define copyright_header IW_ID_VALUE('C', 'P', 'R', 'T')
#endif
-struct snd_iwffff_handle {
+struct _snd_iwffff_handle {
int rom;
unsigned char *fff_data;
size_t fff_size;
diff --git a/src/mixer/mixer_local.h b/src/mixer/mixer_local.h
index 956be64e..a5eb3adb 100644
--- a/src/mixer/mixer_local.h
+++ b/src/mixer/mixer_local.h
@@ -23,8 +23,8 @@
#include "asoundlib.h"
#include "list.h"
-typedef struct mixer_simple mixer_simple_t;
-typedef struct mixer_simple_hcontrol_private mixer_simple_hcontrol_private_t;
+typedef struct _mixer_simple mixer_simple_t;
+typedef struct _mixer_simple_hcontrol_private mixer_simple_hcontrol_private_t;
typedef int (mixer_simple_get_t) (snd_mixer_t *handle, mixer_simple_t *simple, snd_mixer_simple_control_t *control);
typedef int (mixer_simple_put_t) (snd_mixer_t *handle, mixer_simple_t *simple, snd_mixer_simple_control_t *control);
@@ -43,7 +43,7 @@ typedef int (mixer_simple_event_add_t) (snd_mixer_t *handle, snd_hcontrol_t *hco
#define MIXER_PRESENT_CAPTURE_ROUTE (1<<10)
#define MIXER_PRESENT_CAPTURE_SOURCE (1<<11)
-struct mixer_simple {
+struct _mixer_simple {
/* this may be moved to a private area */
unsigned int present; /* present controls */
unsigned int global_values;
@@ -74,11 +74,11 @@ struct mixer_simple {
unsigned long private_value;
};
-struct mixer_simple_hcontrol_private {
+struct _mixer_simple_hcontrol_private {
void *simples; /* list of associated hcontrols */
};
-struct snd_mixer {
+struct _snd_mixer {
snd_ctl_t *ctl_handle;
int simple_valid;
int simple_changes; /* total number of changes */
diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c
index 71fd8827..b8285fa8 100644
--- a/src/pcm/pcm.c
+++ b/src/pcm/pcm.c
@@ -28,6 +28,7 @@
#include <sys/poll.h>
#include <sys/shm.h>
#include <sys/mman.h>
+#include <limits.h>
#include <dlfcn.h>
#include "pcm_local.h"
#include "list.h"
@@ -38,7 +39,7 @@ snd_pcm_type_t snd_pcm_type(snd_pcm_t *pcm)
return pcm->type;
}
-snd_pcm_type_t snd_pcm(snd_pcm_t *pcm)
+snd_pcm_type_t snd_pcm_stream(snd_pcm_t *pcm)
{
assert(pcm);
return pcm->stream;
@@ -49,23 +50,23 @@ int snd_pcm_close(snd_pcm_t *pcm)
int ret = 0;
int err;
assert(pcm);
- if (pcm->valid_setup) {
+ if (pcm->setup) {
if (pcm->mode & SND_PCM_NONBLOCK)
snd_pcm_drop(pcm);
else
snd_pcm_drain(pcm);
}
- if (pcm->mmap_info) {
+ if (pcm->mmap_channels) {
if ((err = snd_pcm_munmap(pcm)) < 0)
ret = err;
}
if ((err = pcm->ops->close(pcm->op_arg)) < 0)
ret = err;
- pcm->valid_setup = 0;
+ pcm->setup = 0;
if (pcm->name)
free(pcm->name);
free(pcm);
- return ret;
+ return 0;
}
int snd_pcm_nonblock(snd_pcm_t *pcm, int nonblock)
@@ -93,84 +94,176 @@ int snd_pcm_info(snd_pcm_t *pcm, snd_pcm_info_t *info)
return pcm->ops->info(pcm->op_arg, info);
}
-int snd_pcm_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t *info)
-{
- assert(pcm && info);
- return pcm->ops->params_info(pcm->op_arg, info);
-}
-
-int snd_pcm_setup(snd_pcm_t *pcm, snd_pcm_setup_t *setup)
+int snd_pcm_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t *info)
{
int err;
- assert(pcm && setup);
- if (pcm->valid_setup) {
- *setup = pcm->setup;
- return 0;
- }
- if ((err = pcm->ops->setup(pcm->op_arg, &pcm->setup)) < 0)
- return err;
- *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;
+ assert(pcm && info);
+#if 0
+ fprintf(stderr, "hw_info entered:\n");
+ snd_pcm_dump_hw_info(info, stderr);
+ fprintf(stderr, "\n");
+#endif
+ err = pcm->ops->hw_info(pcm->op_arg, info);
+#if 0
+ fprintf(stderr, "hw_info return %d:\n", err);
+ snd_pcm_dump_hw_info(info, stderr);
+ fprintf(stderr, "\n");
+#endif
+ return err;
}
-int snd_pcm_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info)
+void snd_pcm_hw_params_to_info(snd_pcm_hw_params_t *params, snd_pcm_hw_info_t *info)
{
- assert(pcm && info);
- assert(pcm->valid_setup);
- assert(info->channel < pcm->setup.format.channels);
- return pcm->ops->channel_info(pcm->op_arg, info);
+ info->access_mask = 1U << params->access;
+ info->format_mask = 1U << params->format;
+ info->subformat_mask = 1U << params->subformat;
+ info->channels_min = info->channels_max = params->channels;
+ info->rate_min = info->rate_max = params->rate;
+ info->fragment_size_min = info->fragment_size_max = params->fragment_size;
+ info->fragments_min = info->fragments_max = params->fragments;
}
-int snd_pcm_channel_params(snd_pcm_t *pcm, snd_pcm_channel_params_t *params)
+void snd_pcm_hw_info_to_params(snd_pcm_hw_info_t *info, snd_pcm_hw_params_t *params)
{
- assert(pcm && params);
- assert(pcm->valid_setup);
- assert(params->channel < pcm->setup.format.channels);
- return pcm->ops->channel_params(pcm->op_arg, params);
+ assert(info->access_mask &&
+ !(info->access_mask & (info->access_mask - 1)));
+ params->access = ffs(info->access_mask) - 1;
+ assert(info->format_mask &&
+ !(info->format_mask & (info->format_mask - 1)));
+ params->format = ffs(info->format_mask) - 1;
+ assert(info->subformat_mask &&
+ !(info->subformat_mask & (info->subformat_mask - 1)));
+ params->subformat = ffs(info->subformat_mask) - 1;
+ assert(info->channels_min == info->channels_max);
+ params->channels = info->channels_min;
+ assert(info->rate_min == info->rate_max);
+ params->rate = info->rate_min;
+ assert(info->fragment_size_min == info->fragment_size_max);
+ params->fragment_size = info->fragment_size_min;
+ assert(info->fragments_min == info->fragments_max);
+ params->fragments = info->fragments_min;
}
-int snd_pcm_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t *setup)
+void snd_pcm_hw_info_to_params_fail(snd_pcm_hw_info_t *info, snd_pcm_hw_params_t *params)
{
- assert(pcm && setup);
- assert(pcm->valid_setup);
- assert(setup->channel < pcm->setup.format.channels);
- return pcm->ops->channel_setup(pcm->op_arg, setup);
+ unsigned int f = 0;
+ if (info->access_mask == 0)
+ f |= SND_PCM_HW_PARBIT_ACCESS;
+ if (info->format_mask == 0)
+ f |= SND_PCM_HW_PARBIT_FORMAT;
+ if (info->subformat_mask == 0)
+ f |= SND_PCM_HW_PARBIT_SUBFORMAT;
+ if (info->channels_min > info->channels_max)
+ f |= SND_PCM_HW_PARBIT_CHANNELS;
+ if (info->rate_min > info->rate_max)
+ f |= SND_PCM_HW_PARBIT_RATE;
+ if (info->fragment_size_min > info->fragment_size_max)
+ f |= SND_PCM_HW_PARBIT_FRAGMENT_SIZE;
+ if (info->fragments_min > info->fragments_max)
+ f |= SND_PCM_HW_PARBIT_FRAGMENTS;
+ assert(f);
+ params->fail_mask = f;
}
-int _snd_pcm_params(snd_pcm_t *pcm, snd_pcm_params_t *params)
+int _snd_pcm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{
int err;
- snd_pcm_setup_t setup;
- if ((err = pcm->ops->params(pcm->op_arg, params)) < 0)
+ snd_pcm_hw_info_t info;
+
+ snd_pcm_hw_params_to_info(params, &info);
+ err = snd_pcm_hw_info(pcm, &info);
+ if (err < 0) {
+ snd_pcm_hw_info_to_params_fail(&info, params);
return err;
- pcm->valid_setup = 0;
- return snd_pcm_setup(pcm, &setup);
+ }
+ snd_pcm_hw_info_to_params(&info, params);
+ if ((err = pcm->ops->hw_params(pcm->op_arg, params)) < 0)
+ return err;
+ pcm->setup = 1;
+ pcm->access = params->access;
+ pcm->format = params->format;
+ pcm->subformat = params->subformat;
+ pcm->rate = params->rate;
+ pcm->channels = params->channels;
+ pcm->fragment_size = params->fragment_size;
+ pcm->fragments = params->fragments;
+ pcm->bits_per_sample = snd_pcm_format_physical_width(params->format);
+ pcm->bits_per_frame = pcm->bits_per_sample * params->channels;
+ pcm->buffer_size = params->fragment_size * params->fragments;
+
+ pcm->info = info.info;
+ pcm->msbits = info.msbits;
+ pcm->rate_master = info.rate_master;
+ pcm->rate_divisor = info.rate_divisor;
+ pcm->fifo_size = info.fifo_size;
+
+ /* Default sw params */
+ pcm->start_mode = SND_PCM_START_DATA;
+ pcm->ready_mode = SND_PCM_READY_FRAGMENT;
+ pcm->xrun_mode = SND_PCM_XRUN_FRAGMENT;
+ pcm->avail_min = pcm->fragment_size;
+ pcm->xfer_min = pcm->fragment_size;
+ pcm->xfer_align = pcm->fragment_size;
+ pcm->time = 0;
+ pcm->boundary = LONG_MAX - pcm->buffer_size * 2 - LONG_MAX % pcm->buffer_size;
+ return 0;
}
-int snd_pcm_params_mmap(snd_pcm_t *pcm, snd_pcm_params_t *params)
+int snd_pcm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{
int err;
- if (pcm->mmap_info) {
+ assert(pcm && params);
+ if (pcm->setup && pcm->mmap_channels &&
+ (pcm->mmap_rw ||
+ (pcm->access == SND_PCM_ACCESS_MMAP_INTERLEAVED ||
+ pcm->access == SND_PCM_ACCESS_MMAP_NONINTERLEAVED ||
+ pcm->access == SND_PCM_ACCESS_MMAP_COMPLEX))) {
err = snd_pcm_munmap(pcm);
if (err < 0)
return err;
}
- err = _snd_pcm_params(pcm, params);
- if (pcm->valid_setup)
- snd_pcm_mmap(pcm);
+ err = _snd_pcm_hw_params(pcm, params);
+ if (pcm->setup &&
+ (pcm->mmap_rw ||
+ (pcm->access == SND_PCM_ACCESS_MMAP_INTERLEAVED ||
+ pcm->access == SND_PCM_ACCESS_MMAP_NONINTERLEAVED ||
+ pcm->access == SND_PCM_ACCESS_MMAP_COMPLEX))) {
+ int err;
+ err = snd_pcm_mmap(pcm);
+ if (err < 0)
+ return err;
+ }
return err;
}
-int snd_pcm_params(snd_pcm_t *pcm, snd_pcm_params_t *params)
+int snd_pcm_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)
{
+ int err;
assert(pcm && params);
- if (pcm->mmap_auto)
- return snd_pcm_params_mmap(pcm, params);
- assert(!pcm->mmap_info);
- return _snd_pcm_params(pcm, params);
+ assert(pcm->setup);
+ if ((err = pcm->ops->sw_params(pcm->op_arg, params)) < 0)
+ return err;
+ pcm->start_mode = params->start_mode;
+ pcm->ready_mode = params->ready_mode;
+ pcm->xrun_mode = params->xrun_mode;
+ pcm->avail_min = params->avail_min;
+ pcm->xfer_min = params->xfer_min;
+ pcm->xfer_align = params->xfer_align;
+ pcm->time = params->time;
+ pcm->boundary = params->boundary;
+ return 0;
+}
+
+int snd_pcm_dig_params(snd_pcm_t *pcm, snd_pcm_dig_params_t *params)
+{
+ assert(pcm && params);
+ return pcm->ops->dig_params(pcm->op_arg, params);
+}
+
+int snd_pcm_dig_info(snd_pcm_t *pcm, snd_pcm_dig_info_t *info)
+{
+ assert(pcm && info);
+ return pcm->ops->dig_info(pcm->op_arg, info);
}
int snd_pcm_status(snd_pcm_t *pcm, snd_pcm_status_t *status)
@@ -188,44 +281,42 @@ int snd_pcm_state(snd_pcm_t *pcm)
int snd_pcm_delay(snd_pcm_t *pcm, ssize_t *delayp)
{
assert(pcm);
- assert(pcm->valid_setup);
+ assert(pcm->setup);
return pcm->fast_ops->delay(pcm->fast_op_arg, delayp);
}
int snd_pcm_prepare(snd_pcm_t *pcm)
{
assert(pcm);
- assert(pcm->valid_setup);
+ assert(pcm->setup);
return pcm->fast_ops->prepare(pcm->fast_op_arg);
}
int snd_pcm_start(snd_pcm_t *pcm)
{
assert(pcm);
- assert(pcm->valid_setup);
- assert(pcm->stream != SND_PCM_STREAM_PLAYBACK ||
- snd_pcm_mmap_playback_hw_avail(pcm) > 0);
+ assert(pcm->setup);
return pcm->fast_ops->start(pcm->fast_op_arg);
}
int snd_pcm_drop(snd_pcm_t *pcm)
{
assert(pcm);
- assert(pcm->valid_setup);
+ assert(pcm->setup);
return pcm->fast_ops->drop(pcm->fast_op_arg);
}
int snd_pcm_drain(snd_pcm_t *pcm)
{
assert(pcm);
- assert(pcm->valid_setup);
+ assert(pcm->setup);
return pcm->fast_ops->drain(pcm->fast_op_arg);
}
int snd_pcm_pause(snd_pcm_t *pcm, int enable)
{
assert(pcm);
- assert(pcm->valid_setup);
+ assert(pcm->setup);
return pcm->fast_ops->pause(pcm->fast_op_arg, enable);
}
@@ -233,7 +324,7 @@ int snd_pcm_pause(snd_pcm_t *pcm, int enable)
ssize_t snd_pcm_rewind(snd_pcm_t *pcm, size_t frames)
{
assert(pcm);
- assert(pcm->valid_setup);
+ assert(pcm->setup);
assert(frames > 0);
return pcm->fast_ops->rewind(pcm->fast_op_arg, frames);
}
@@ -242,12 +333,12 @@ int snd_pcm_set_avail_min(snd_pcm_t *pcm, size_t frames)
{
int err;
assert(pcm);
- assert(pcm->valid_setup);
+ assert(pcm->setup);
assert(frames > 0);
err = pcm->fast_ops->set_avail_min(pcm->fast_op_arg, frames);
if (err < 0)
return err;
- pcm->setup.avail_min = frames;
+ pcm->avail_min = frames;
return 0;
}
@@ -255,9 +346,8 @@ ssize_t snd_pcm_writei(snd_pcm_t *pcm, const void *buffer, size_t size)
{
assert(pcm);
assert(size == 0 || buffer);
- assert(pcm->valid_setup);
- assert(pcm->setup.xfer_mode == SND_PCM_XFER_INTERLEAVED);
- assert(!pcm->mmap_info || pcm->mmap_auto);
+ assert(pcm->setup);
+ assert(pcm->access == SND_PCM_ACCESS_RW_INTERLEAVED);
return _snd_pcm_writei(pcm, buffer, size);
}
@@ -265,9 +355,8 @@ ssize_t snd_pcm_writen(snd_pcm_t *pcm, void **bufs, size_t size)
{
assert(pcm);
assert(size == 0 || bufs);
- assert(pcm->valid_setup);
- assert(pcm->setup.xfer_mode == SND_PCM_XFER_NONINTERLEAVED);
- assert(!pcm->mmap_info || pcm->mmap_auto);
+ assert(pcm->setup);
+ assert(pcm->access == SND_PCM_ACCESS_RW_NONINTERLEAVED);
return _snd_pcm_writen(pcm, bufs, size);
}
@@ -275,9 +364,8 @@ ssize_t snd_pcm_readi(snd_pcm_t *pcm, void *buffer, size_t size)
{
assert(pcm);
assert(size == 0 || buffer);
- assert(pcm->valid_setup);
- assert(pcm->setup.xfer_mode == SND_PCM_XFER_INTERLEAVED);
- assert(!pcm->mmap_info || pcm->mmap_auto);
+ assert(pcm->setup);
+ assert(pcm->access == SND_PCM_ACCESS_RW_INTERLEAVED);
return _snd_pcm_readi(pcm, buffer, size);
}
@@ -285,9 +373,8 @@ ssize_t snd_pcm_readn(snd_pcm_t *pcm, void **bufs, size_t size)
{
assert(pcm);
assert(size == 0 || bufs);
- assert(pcm->valid_setup);
- assert(pcm->setup.xfer_mode == SND_PCM_XFER_NONINTERLEAVED);
- assert(!pcm->mmap_info || pcm->mmap_auto);
+ assert(pcm->setup);
+ assert(pcm->access == SND_PCM_ACCESS_RW_NONINTERLEAVED);
return _snd_pcm_readn(pcm, bufs, size);
}
@@ -296,8 +383,8 @@ ssize_t snd_pcm_writev(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);
+ assert(pcm->setup);
+ assert((int)pcm->channels == count);
bufs = alloca(sizeof(*bufs) * count);
for (k = 0; k < count; ++k) {
bufs[k] = vector[k].iov_base;
@@ -311,8 +398,8 @@ 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);
+ assert(pcm->setup);
+ assert((int)pcm->channels == count);
bufs = alloca(sizeof(*bufs) * count);
for (k = 0; k < count; ++k) {
bufs[k] = vector[k].iov_base;
@@ -400,80 +487,329 @@ static const char *assoc(int value, assoc_t *alist)
#define STREAM(v) { SND_PCM_STREAM_##v, #v, #v }
#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 ACCESS(v) { SND_PCM_ACCESS_##v, #v, #v }
+#define FORMAT(v, d) { SND_PCM_FORMAT_##v, #v, d }
+#define SUBFORMAT(v, d) { SND_PCM_SUBFORMAT_##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 HW_PARAM(v) { SND_PCM_HW_PARAM_##v, #v, #v }
+#define SW_PARAM(v) { SND_PCM_SW_PARAM_##v, #v, #v }
#define END { 0, NULL, NULL }
-static assoc_t states[] = { STATE(OPEN), STATE(SETUP), STATE(PREPARED),
- STATE(RUNNING), STATE(XRUN), STATE(PAUSED), END };
-static assoc_t streams[] = { STREAM(PLAYBACK), STREAM(CAPTURE), END };
-static assoc_t xruns[] = { XRUN(ASAP), XRUN(FRAGMENT), XRUN(NONE), END };
-static assoc_t fmts[] = {
- 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"),
+static assoc_t streams[] = {
+ STREAM(PLAYBACK),
+ STREAM(CAPTURE),
+ END
+};
+
+static assoc_t states[] = {
+ STATE(OPEN),
+ STATE(SETUP),
+ STATE(PREPARED),
+ STATE(RUNNING),
+ STATE(XRUN),
+ STATE(PAUSED),
+ END
+};
+
+#if 0
+static assoc_t hw_params[] = {
+ HW_PARAM(ACCESS),
+ HW_PARAM(FORMAT),
+ HW_PARAM(SUBFORMAT),
+ HW_PARAM(CHANNELS),
+ HW_PARAM(RATE),
+ HW_PARAM(FRAGMENT_SIZE),
+ HW_PARAM(FRAGMENTS),
+ END
+};
+
+static assoc_t sw_params[] = {
+ SW_PARAM(START_MODE),
+ SW_PARAM(READY_MODE),
+ SW_PARAM(AVAIL_MIN),
+ SW_PARAM(XFER_MIN),
+ SW_PARAM(XFER_ALIGN),
+ SW_PARAM(XRUN_MODE),
+ SW_PARAM(TIME),
+ END
+};
+#endif
+
+static assoc_t accesses[] = {
+ ACCESS(MMAP_INTERLEAVED),
+ ACCESS(MMAP_NONINTERLEAVED),
+ ACCESS(MMAP_COMPLEX),
+ ACCESS(RW_INTERLEAVED),
+ ACCESS(RW_NONINTERLEAVED),
+ END
+};
+
+static assoc_t formats[] = {
+ FORMAT(S8, "Signed 8-bit"),
+ FORMAT(U8, "Unsigned 8-bit"),
+ FORMAT(S16_LE, "Signed 16-bit Little Endian"),
+ FORMAT(S16_BE, "Signed 16-bit Big Endian"),
+ FORMAT(U16_LE, "Unsigned 16-bit Little Endian"),
+ FORMAT(U16_BE, "Unsigned 16-bit Big Endian"),
+ FORMAT(S24_LE, "Signed 24-bit Little Endian"),
+ FORMAT(S24_BE, "Signed 24-bit Big Endian"),
+ FORMAT(U24_LE, "Unsigned 24-bit Little Endian"),
+ FORMAT(U24_BE, "Unsigned 24-bit Big Endian"),
+ FORMAT(S32_LE, "Signed 32-bit Little Endian"),
+ FORMAT(S32_BE, "Signed 32-bit Big Endian"),
+ FORMAT(U32_LE, "Unsigned 32-bit Little Endian"),
+ FORMAT(U32_BE, "Unsigned 32-bit Big Endian"),
+ FORMAT(FLOAT_LE, "Float Little Endian"),
+ FORMAT(FLOAT_BE, "Float Big Endian"),
+ FORMAT(FLOAT64_LE, "Float64 Little Endian"),
+ FORMAT(FLOAT64_BE, "Float64 Big Endian"),
+ FORMAT(IEC958_SUBFRAME_LE, "IEC-958 Little Endian"),
+ FORMAT(IEC958_SUBFRAME_BE, "IEC-958 Big Endian"),
+ FORMAT(MU_LAW, "Mu-Law"),
+ FORMAT(A_LAW, "A-Law"),
+ FORMAT(IMA_ADPCM, "Ima-ADPCM"),
+ FORMAT(MPEG, "MPEG"),
+ FORMAT(GSM, "GSM"),
+ FORMAT(SPECIAL, "Special"),
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 onoff[] = { {0, "OFF", NULL}, {1, "ON", NULL}, {-1, "ON", NULL}, END };
+static assoc_t subformats[] = {
+ SUBFORMAT(STD, "Standard"),
+ END
+};
-int snd_pcm_dump_setup(snd_pcm_t *pcm, FILE *fp)
+static assoc_t starts[] = {
+ START(EXPLICIT),
+ START(DATA),
+ END
+};
+static assoc_t readys[] = {
+ READY(FRAGMENT),
+ READY(ASAP),
+ END
+};
+
+static assoc_t xruns[] = {
+ XRUN(ASAP),
+ XRUN(FRAGMENT),
+ XRUN(NONE),
+ END
+};
+
+static assoc_t onoff[] = {
+ {0, "OFF", NULL},
+ {1, "ON", NULL},
+ {-1, "ON", NULL},
+ END
+};
+
+int snd_pcm_dump_hw_setup(snd_pcm_t *pcm, FILE *fp)
+{
+ assert(pcm);
+ assert(fp);
+ assert(pcm->setup);
+ fprintf(fp, "stream : %s\n", assoc(pcm->stream, streams));
+ fprintf(fp, "access : %s\n", assoc(pcm->access, accesses));
+ fprintf(fp, "format : %s\n", assoc(pcm->format, formats));
+ fprintf(fp, "subformat : %s\n", assoc(pcm->subformat, subformats));
+ fprintf(fp, "channels : %d\n", pcm->channels);
+ fprintf(fp, "rate : %d\n", pcm->rate);
+ fprintf(fp, "rate : %g (%d/%d)\n", (double) pcm->rate_master / pcm->rate_divisor, pcm->rate_master, pcm->rate_divisor);
+ fprintf(fp, "msbits : %d\n", pcm->msbits);
+ fprintf(fp, "fragment_size: %ld\n", (long)pcm->fragment_size);
+ fprintf(fp, "fragments : %d\n", pcm->fragments);
+ return 0;
+}
+
+int snd_pcm_dump_sw_setup(snd_pcm_t *pcm, FILE *fp)
{
- snd_pcm_setup_t *setup;
assert(pcm);
assert(fp);
- 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, "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, "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, "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);
+ assert(pcm->setup);
+ fprintf(fp, "start_mode : %s\n", assoc(pcm->start_mode, starts));
+ fprintf(fp, "ready_mode : %s\n", assoc(pcm->ready_mode, readys));
+ fprintf(fp, "xrun_mode : %s\n", assoc(pcm->xrun_mode, xruns));
+ fprintf(fp, "avail_min : %ld\n", (long)pcm->avail_min);
+ fprintf(fp, "xfer_min : %ld\n", (long)pcm->xfer_min);
+ fprintf(fp, "xfer_align : %ld\n", (long)pcm->xfer_align);
+ fprintf(fp, "time : %s\n", assoc(pcm->time, onoff));
+ fprintf(fp, "boundary : %ld\n", (long)pcm->boundary);
+ return 0;
+}
+
+int snd_pcm_dump_setup(snd_pcm_t *pcm, FILE *fp)
+{
+ snd_pcm_dump_hw_setup(pcm, fp);
+ snd_pcm_dump_sw_setup(pcm, fp);
+ return 0;
+}
+
+int snd_pcm_dump_hw_info(snd_pcm_hw_info_t *info,
+ FILE *fp)
+{
+ unsigned int k;
+ fputs("access:", fp);
+ if (info->access_mask) {
+ for (k = 0; k <= SND_PCM_ACCESS_LAST; ++k)
+ if (info->access_mask & (1U << k)) {
+ putc(' ', fp);
+ fputs(assoc(k, accesses), fp);
+ }
+ } else
+ fputs(" NONE", fp);
+ putc('\n', fp);
+
+ fputs("format:", fp);
+ if (info->format_mask) {
+ for (k = 0; k <= SND_PCM_FORMAT_LAST; ++k)
+ if (info->format_mask & (1U << k)) {
+ putc(' ', fp);
+ fputs(assoc(k, formats), fp);
+ }
+ } else
+ fputs(" NONE", fp);
+ putc('\n', fp);
+
+ fputs("subformat:", fp);
+ if (info->subformat_mask) {
+ for (k = 0; k <= SND_PCM_SUBFORMAT_LAST; ++k)
+ if (info->subformat_mask & (1U << k)) {
+ putc(' ', fp);
+ fputs(assoc(k, subformats), fp);
+ }
+ } else
+ fputs(" NONE", fp);
+ putc('\n', fp);
+
+ fputs("channels: ", fp);
+ if (info->channels_min == 0 && info->channels_max == UINT_MAX)
+ fputs("ALL", fp);
+ else if (info->channels_min > info->channels_max)
+ fputs("NONE", fp);
+ else {
+ fprintf(fp, "%u", info->channels_min);
+ if (info->channels_min < info->channels_max)
+ fprintf(fp, " - %u", info->channels_max);
+ }
+ putc('\n', fp);
+
+ fputs("rate: ", fp);
+ if (info->rate_min == 0 && info->rate_max == UINT_MAX)
+ fputs("ALL", fp);
+ else if (info->rate_min > info->rate_max)
+ fputs("NONE", fp);
+ else {
+ fprintf(fp, "%u", info->rate_min);
+ if (info->rate_min < info->rate_max)
+ fprintf(fp, " - %u", info->rate_max);
+ }
+ putc('\n', fp);
+
+ fputs("fragment_size: ", fp);
+ if (info->fragment_size_min <= 1 &&
+ info->fragment_size_max == ULONG_MAX)
+ fputs("ALL", fp);
+ else if (info->fragment_size_min > info->fragment_size_max)
+ fputs("NONE", fp);
+ else {
+ fprintf(fp, "%lu", (unsigned long)info->fragment_size_min);
+ if (info->fragment_size_min < info->fragment_size_max)
+ fprintf(fp, " - %lu", (unsigned long)info->fragment_size_max);
+ }
+ putc('\n', fp);
+
+ fputs("fragments: ", fp);
+ if (info->fragments_min <= 1 && info->fragments_max == UINT_MAX)
+ fputs("ALL", fp);
+ else if (info->fragments_min > info->fragments_max)
+ fputs("NONE", fp);
+ else {
+ fprintf(fp, "%u", info->fragments_min);
+ if (info->fragments_min < info->fragments_max)
+ fprintf(fp, " - %u", info->fragments_max);
+ }
+ putc('\n', fp);
+ return 0;
+}
+
+int snd_pcm_dump_hw_params_fail(snd_pcm_hw_params_t *params, FILE *fp)
+{
+ int k;
+ if (params->fail_mask == 0)
+ return 0;
+ fprintf(fp, "hw_params failed on the following field value(s):\n");
+ for (k = 0; k <= SND_PCM_HW_PARAM_LAST; ++k) {
+ if (!(params->fail_mask & (1U << k)))
+ continue;
+ switch (k) {
+ case SND_PCM_HW_PARAM_ACCESS:
+ fprintf(fp, "access: %s\n", assoc(params->access, accesses));
+ break;
+ case SND_PCM_HW_PARAM_FORMAT:
+ fprintf(fp, "format: %s\n", assoc(params->format, formats));
+ break;
+ case SND_PCM_HW_PARAM_SUBFORMAT:
+ fprintf(fp, "subformat: %s\n", assoc(params->subformat, subformats));
+ break;
+ case SND_PCM_HW_PARAM_CHANNELS:
+ fprintf(fp, "channels: %d\n", params->channels);
+ break;
+ case SND_PCM_HW_PARAM_RATE:
+ fprintf(fp, "rate: %d\n", params->rate);
+ break;
+ case SND_PCM_HW_PARAM_FRAGMENT_SIZE:
+ fprintf(fp, "fragment_size: %ld\n", (long)params->fragment_size);
+ break;
+ case SND_PCM_HW_PARAM_FRAGMENTS:
+ fprintf(fp, "fragments: %d\n", params->fragments);
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ }
+ return 0;
+}
+
+int snd_pcm_dump_sw_params_fail(snd_pcm_sw_params_t *params, FILE *fp)
+{
+ int k;
+ if (params->fail_mask == 0)
+ return 0;
+ fprintf(fp, "sw_params failed on the following field value(s):\n");
+ for (k = 0; k <= SND_PCM_SW_PARAM_LAST; ++k) {
+ if (!(params->fail_mask & (1U << k)))
+ continue;
+ switch (k) {
+ case SND_PCM_SW_PARAM_START_MODE:
+ fprintf(fp, "start_mode: %s\n", assoc(params->start_mode, starts));
+ break;
+ case SND_PCM_SW_PARAM_READY_MODE:
+ fprintf(fp, "ready_mode: %s\n", assoc(params->ready_mode, readys));
+ break;
+ case SND_PCM_SW_PARAM_XRUN_MODE:
+ fprintf(fp, "xrun_mode: %s\n", assoc(params->xrun_mode, xruns));
+ break;
+ case SND_PCM_SW_PARAM_AVAIL_MIN:
+ fprintf(fp, "avail_min: %ld\n", (long)params->avail_min);
+ break;
+ case SND_PCM_SW_PARAM_XFER_MIN:
+ fprintf(fp, "xfer_min: %ld\n", (long)params->xfer_min);
+ break;
+ case SND_PCM_SW_PARAM_XFER_ALIGN:
+ fprintf(fp, "xfer_align: %ld\n", (long)params->xfer_align);
+ break;
+ case SND_PCM_SW_PARAM_TIME:
+ fprintf(fp, "time: %d\n", params->time);
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ }
return 0;
}
@@ -501,7 +837,7 @@ int snd_pcm_dump(snd_pcm_t *pcm, FILE *fp)
const char *snd_pcm_format_name(int format)
{
- assoc_t *a = assoc_value(format, fmts);
+ assoc_t *a = assoc_value(format, formats);
if (a)
return a->name;
return 0;
@@ -509,7 +845,7 @@ const char *snd_pcm_format_name(int format)
const char *snd_pcm_format_description(int format)
{
- assoc_t *a = assoc_value(format, fmts);
+ assoc_t *a = assoc_value(format, formats);
if (a)
return a->desc;
return "Unknown";
@@ -517,7 +853,7 @@ const char *snd_pcm_format_description(int format)
int snd_pcm_format_value(const char* name)
{
- assoc_t *a = assoc_name(name, fmts);
+ assoc_t *a = assoc_name(name, formats);
if (a)
return a->value;
return -1;
@@ -526,28 +862,28 @@ int snd_pcm_format_value(const char* name)
ssize_t snd_pcm_bytes_to_frames(snd_pcm_t *pcm, ssize_t bytes)
{
assert(pcm);
- assert(pcm->valid_setup);
+ assert(pcm->setup);
return bytes * 8 / pcm->bits_per_frame;
}
ssize_t snd_pcm_frames_to_bytes(snd_pcm_t *pcm, ssize_t frames)
{
assert(pcm);
- assert(pcm->valid_setup);
+ assert(pcm->setup);
return frames * pcm->bits_per_frame / 8;
}
ssize_t snd_pcm_bytes_to_samples(snd_pcm_t *pcm, ssize_t bytes)
{
assert(pcm);
- assert(pcm->valid_setup);
+ assert(pcm->setup);
return bytes * 8 / pcm->bits_per_sample;
}
ssize_t snd_pcm_samples_to_bytes(snd_pcm_t *pcm, ssize_t samples)
{
assert(pcm);
- assert(pcm->valid_setup);
+ assert(pcm->setup);
return samples * pcm->bits_per_sample / 8;
}
@@ -568,8 +904,44 @@ int snd_pcm_open(snd_pcm_t **pcmp, char *name,
return err;
err = snd_config_searchv(snd_config, &pcm_conf, "pcm", name, 0);
if (err < 0) {
+ int card, dev, subdev;
+ char socket[256], sname[256];
+ char format[16], file[256];
+ err = sscanf(name, "hw:%d,%d,%d", &card, &dev, &subdev);
+ if (err == 3)
+ return snd_pcm_hw_open(pcmp, name, card, dev, subdev, stream, mode);
+ err = sscanf(name, "hw:%d,%d", &card, &dev);
+ if (err == 2)
+ return snd_pcm_hw_open(pcmp, name, card, dev, -1, stream, mode);
+ err = sscanf(name, "plug:%d,%d,%d", &card, &dev, &subdev);
+ if (err == 3)
+ return snd_pcm_plug_open_hw(pcmp, name, card, dev, subdev, stream, mode);
+ err = sscanf(name, "plug:%d,%d", &card, &dev);
+ if (err == 2)
+ return snd_pcm_plug_open_hw(pcmp, name, card, dev, -1, stream, mode);
+ err = sscanf(name, "shm:%256s,%256s", socket, sname);
+ if (err == 2)
+ return snd_pcm_shm_open(pcmp, NULL, socket, sname, stream, mode);
+ err = sscanf(name, "file:%256s,%16s", file, format);
+ if (err == 2) {
+ snd_pcm_t *slave;
+ err = snd_pcm_null_open(&slave, NULL, stream, mode);
+ if (err < 0)
+ return err;
+ return snd_pcm_file_open(pcmp, NULL, file, -1, format, slave, 1);
+ }
+ err = sscanf(name, "file:%256s", file);
+ if (err == 1) {
+ snd_pcm_t *slave;
+ err = snd_pcm_null_open(&slave, NULL, stream, mode);
+ if (err < 0)
+ return err;
+ return snd_pcm_file_open(pcmp, NULL, file, -1, "raw", slave, 1);
+ }
+ if (strcmp(name, "null") == 0)
+ return snd_pcm_null_open(pcmp, NULL, stream, mode);
ERR("Unknown PCM %s", name);
- return err;
+ return -ENOENT;
}
if (snd_config_type(pcm_conf) != SND_CONFIG_TYPE_COMPOUND) {
ERR("Invalid type for PCM definition");
@@ -655,7 +1027,7 @@ void snd_pcm_areas_from_buf(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas,
void *buf)
{
unsigned int channel;
- unsigned int channels = pcm->setup.format.channels;
+ unsigned int channels = pcm->channels;
for (channel = 0; channel < channels; ++channel, ++areas) {
areas->addr = buf;
areas->first = channel * pcm->bits_per_sample;
@@ -667,7 +1039,7 @@ 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;
+ unsigned int channels = pcm->channels;
for (channel = 0; channel < channels; ++channel, ++areas, ++bufs) {
areas->addr = *bufs;
areas->first = 0;
@@ -974,7 +1346,7 @@ ssize_t snd_pcm_read_areas(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas,
assert(size > 0);
assert(state >= SND_PCM_STATE_PREPARED);
if (state == SND_PCM_STATE_PREPARED &&
- pcm->setup.start_mode != SND_PCM_START_EXPLICIT) {
+ pcm->start_mode != SND_PCM_START_EXPLICIT) {
err = snd_pcm_start(pcm);
if (err < 0)
return err;
@@ -989,7 +1361,7 @@ ssize_t snd_pcm_read_areas(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas,
err = avail;
break;
}
- if ((size_t)avail < pcm->setup.avail_min) {
+ if ((size_t)avail < pcm->avail_min) {
if (state != SND_PCM_STATE_RUNNING) {
err = -EPIPE;
break;
@@ -1041,7 +1413,7 @@ ssize_t snd_pcm_write_areas(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas,
err = avail;
break;
}
- if ((size_t)avail < pcm->setup.avail_min) {
+ if ((size_t)avail < pcm->avail_min) {
if (state != SND_PCM_STATE_RUNNING) {
err = -EPIPE;
break;
@@ -1066,7 +1438,7 @@ ssize_t snd_pcm_write_areas(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas,
xfer += err;
offset += err;
if (state == SND_PCM_STATE_PREPARED &&
- pcm->setup.start_mode != SND_PCM_START_EXPLICIT) {
+ pcm->start_mode != SND_PCM_START_EXPLICIT) {
err = snd_pcm_start(pcm);
if (err < 0)
break;
@@ -1078,10 +1450,11 @@ ssize_t snd_pcm_write_areas(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas,
return err;
}
+#if 0
int snd_pcm_alloc_user_mmap(snd_pcm_t *pcm, snd_pcm_mmap_info_t *i)
{
i->type = SND_PCM_MMAP_USER;
- i->size = snd_pcm_frames_to_bytes(pcm, pcm->setup.buffer_size);
+ i->size = snd_pcm_frames_to_bytes(pcm, pcm->buffer_size);
i->u.user.shmid = shmget(IPC_PRIVATE, i->size, 0666);
if (i->u.user.shmid < 0) {
SYSERR("shmget failed");
@@ -1098,8 +1471,9 @@ int snd_pcm_alloc_user_mmap(snd_pcm_t *pcm, snd_pcm_mmap_info_t *i)
int snd_pcm_alloc_kernel_mmap(snd_pcm_t *pcm, snd_pcm_mmap_info_t *i, int fd)
{
i->type = SND_PCM_MMAP_KERNEL;
- i->size = pcm->setup.mmap_bytes;
- i->addr = mmap(NULL, pcm->setup.mmap_bytes,
+ /* FIXME */
+ i->size = PAGE_ALIGN(snd_pcm_frames_to_bytes(pcm, pcm->buffer_size));
+ i->addr = mmap(NULL, i->size,
PROT_WRITE | PROT_READ,
MAP_FILE|MAP_SHARED,
fd, SND_PCM_MMAP_OFFSET_DATA);
@@ -1131,15 +1505,1176 @@ int snd_pcm_free_mmap(snd_pcm_t *pcm, snd_pcm_mmap_info_t *i)
}
return 0;
}
+#endif
-void snd_pcm_error(const char *file, int line, const char *function, int err, const char *fmt, ...)
+int snd_pcm_hw_info_bits_per_sample(snd_pcm_hw_info_t *info,
+ unsigned int *min, unsigned int *max)
+{
+ int k;
+ unsigned int bits_min = UINT_MAX, bits_max = 0;
+ int changed = 0;
+ for (k = 0; k <= SND_PCM_FORMAT_LAST; ++k) {
+ int bits;
+ if (!(info->format_mask & (1U << k)))
+ continue;
+ bits = snd_pcm_format_physical_width(k);
+ assert(bits > 0);
+ if ((unsigned) bits < *min || (unsigned)bits > *max) {
+ info->format_mask &= ~(1U << k);
+ changed++;
+ continue;
+ }
+ if ((unsigned)bits < bits_min)
+ bits_min = bits;
+ if ((unsigned)bits > bits_max)
+ bits_max = bits;
+ }
+ *min = bits_min;
+ *max = bits_max;
+ if (info->format_mask == 0)
+ return -EINVAL;
+ return changed;
+}
+
+
+int snd_pcm_hw_info_complete(snd_pcm_hw_info_t *info)
+{
+ if (info->msbits == 0) {
+ unsigned int bits_min = 0, bits_max = UINT_MAX;
+ snd_pcm_hw_info_bits_per_sample(info, &bits_min, &bits_max);
+ if (bits_min == bits_max)
+ info->msbits = bits_min;
+ }
+ if (info->rate_divisor == 0 &&
+ info->rate_min == info->rate_max) {
+ info->rate_master = info->rate_min;
+ info->rate_divisor = 1;
+ }
+ return 0;
+}
+
+struct {
+ unsigned int rate;
+ unsigned int flag;
+} snd_pcm_rates[] = {
+ { 5512, SND_PCM_RATE_5512 },
+ { 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 },
+ { 64000, SND_PCM_RATE_64000 },
+ { 88200, SND_PCM_RATE_88200 },
+ { 96000, SND_PCM_RATE_96000 },
+ { 176400, SND_PCM_RATE_176400 },
+ { 192000, SND_PCM_RATE_192000 }
+};
+
+#define SND_PCM_RATES (sizeof(snd_pcm_rates) / sizeof(snd_pcm_rates[0]))
+
+int snd_pcm_hw_info_rules_access(snd_pcm_t *pcm,
+ snd_pcm_hw_info_t *info,
+ snd_pcm_hw_params_t *params,
+ unsigned int count, int *rules)
+{
+ int k;
+ unsigned int rel, mask;
+ snd_pcm_hw_info_t i;
+ rel = *rules & SND_PCM_RULE_REL_MASK;
+ switch (rel) {
+ case SND_PCM_RULE_REL_LT:
+ mask = (1U << params->access) - 1;
+ break;
+ case SND_PCM_RULE_REL_LE:
+ mask = (1U << (params->access + 1)) - 1;
+ break;
+ case SND_PCM_RULE_REL_GT:
+ mask = ~((1U << (params->access + 1)) - 1);
+ break;
+ case SND_PCM_RULE_REL_GE:
+ mask = ~((1U << params->access) - 1);
+ break;
+ case SND_PCM_RULE_REL_EQ:
+ mask = 1U << params->access;
+ break;
+ case SND_PCM_RULE_REL_NEAR:
+ {
+ unsigned int diff = 0;
+ int n;
+ for (diff = 0; diff < 32; ++diff) {
+ n = (int)params->access - (int)diff;
+ if (n >= 0) {
+ unsigned int bit = 1U << n;
+ if (info->access_mask & bit) {
+ i = *info;
+ i.access_mask = bit;
+ if (snd_pcm_hw_info(pcm, &i) >= 0 &&
+ snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+ *info = i;
+ return 0;
+ }
+ }
+ } else if (params->access + diff > SND_PCM_ACCESS_LAST)
+ break;
+ if (diff == 0)
+ continue;
+ n = params->access + diff;
+ if (n <= SND_PCM_ACCESS_LAST) {
+ unsigned int bit = 1U << n;
+ if (info->access_mask & bit) {
+ i = *info;
+ i.access_mask = bit;
+ if (snd_pcm_hw_info(pcm, &i) >= 0 &&
+ snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+ *info = i;
+ return 0;
+ }
+ }
+ }
+ }
+ info->access_mask = 0;
+ return -EINVAL;
+ }
+ case SND_PCM_RULE_REL_BITS:
+ mask = params->access;
+ break;
+ default:
+ assert(0);
+ return -EINVAL;
+ }
+ info->access_mask &= mask;
+ if (info->access_mask == 0)
+ return -EINVAL;
+ switch (rel) {
+ case SND_PCM_RULE_REL_LE:
+ case SND_PCM_RULE_REL_LT:
+ for (k = SND_PCM_ACCESS_LAST; k >= 0; --k) {
+ if (!(info->access_mask & (1U << k)))
+ continue;
+ i = *info;
+ i.access_mask = 1U << k;
+ if (snd_pcm_hw_info(pcm, &i) >= 0 &&
+ snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+ *info = i;
+ return 0;
+ }
+ }
+ info->access_mask = 0;
+ return -EINVAL;
+ default:
+ for (k = 0; k <= SND_PCM_ACCESS_LAST; ++k) {
+ if (!(info->access_mask & (1U << k)))
+ continue;
+ i = *info;
+ i.access_mask = 1U << k;
+ if (snd_pcm_hw_info(pcm, &i) >= 0 &&
+ snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+ *info = i;
+ return 0;
+ }
+ }
+ info->access_mask = 0;
+ return -EINVAL;
+ }
+ return 0;
+}
+
+int snd_pcm_hw_info_rules_format(snd_pcm_t *pcm,
+ snd_pcm_hw_info_t *info,
+ snd_pcm_hw_params_t *params,
+ unsigned int count, int *rules)
+{
+ int k;
+ unsigned int rel, mask;
+ snd_pcm_hw_info_t i;
+ rel = *rules & SND_PCM_RULE_REL_MASK;
+ switch (rel) {
+ case SND_PCM_RULE_REL_LT:
+ mask = (1U << params->format) - 1;
+ break;
+ case SND_PCM_RULE_REL_LE:
+ mask = (1U << (params->format + 1)) - 1;
+ break;
+ case SND_PCM_RULE_REL_GT:
+ mask = ~((1U << (params->format + 1)) - 1);
+ break;
+ case SND_PCM_RULE_REL_GE:
+ mask = ~((1U << params->format) - 1);
+ break;
+ case SND_PCM_RULE_REL_EQ:
+ mask = 1U << params->format;
+ break;
+ case SND_PCM_RULE_REL_NEAR:
+ {
+ unsigned int diff = 0;
+ int n;
+ for (diff = 0; diff < 32; ++diff) {
+ n = (int)params->format - (int)diff;
+ if (n >= 0) {
+ unsigned int bit = 1U << n;
+ if (info->format_mask & bit) {
+ i = *info;
+ i.format_mask = bit;
+ if (snd_pcm_hw_info(pcm, &i) >= 0 &&
+ snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+ *info = i;
+ return 0;
+ }
+ }
+ } else if (params->format + diff > SND_PCM_FORMAT_LAST)
+ break;
+ if (diff == 0)
+ continue;
+ n = params->format + diff;
+ if (n <= SND_PCM_FORMAT_LAST) {
+ unsigned int bit = 1U << n;
+ if (info->format_mask & bit) {
+ i = *info;
+ i.format_mask = bit;
+ if (snd_pcm_hw_info(pcm, &i) >= 0 &&
+ snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+ *info = i;
+ return 0;
+ }
+ }
+ }
+ }
+ info->format_mask = 0;
+ return -EINVAL;
+ }
+ case SND_PCM_RULE_REL_BITS:
+ mask = params->format;
+ break;
+ default:
+ assert(0);
+ return -EINVAL;
+ }
+ info->format_mask &= mask;
+ if (info->format_mask == 0)
+ return -EINVAL;
+ switch (rel) {
+ case SND_PCM_RULE_REL_LE:
+ case SND_PCM_RULE_REL_LT:
+ for (k = SND_PCM_FORMAT_LAST; k >= 0; --k) {
+ if (!(info->format_mask & (1U << k)))
+ continue;
+ i = *info;
+ i.format_mask = 1U << k;
+ if (snd_pcm_hw_info(pcm, &i) >= 0 &&
+ snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+ *info = i;
+ return 0;
+ }
+ }
+ info->format_mask = 0;
+ return -EINVAL;
+ default:
+ for (k = 0; k <= SND_PCM_FORMAT_LAST; ++k) {
+ if (!(info->format_mask & (1U << k)))
+ continue;
+ i = *info;
+ i.format_mask = 1U << k;
+ if (snd_pcm_hw_info(pcm, &i) >= 0 &&
+ snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+ *info = i;
+ return 0;
+ }
+ }
+ info->format_mask = 0;
+ return -EINVAL;
+ }
+ return 0;
+}
+
+int snd_pcm_hw_info_rules_subformat(snd_pcm_t *pcm,
+ snd_pcm_hw_info_t *info,
+ snd_pcm_hw_params_t *params,
+ unsigned int count, int *rules)
+{
+ int k;
+ unsigned int rel, mask;
+ snd_pcm_hw_info_t i;
+ rel = *rules & SND_PCM_RULE_REL_MASK;
+ switch (rel) {
+ case SND_PCM_RULE_REL_LT:
+ mask = (1U << params->subformat) - 1;
+ break;
+ case SND_PCM_RULE_REL_LE:
+ mask = (1U << (params->subformat + 1)) - 1;
+ break;
+ case SND_PCM_RULE_REL_GT:
+ mask = ~((1U << (params->subformat + 1)) - 1);
+ break;
+ case SND_PCM_RULE_REL_GE:
+ mask = ~((1U << params->subformat) - 1);
+ break;
+ case SND_PCM_RULE_REL_EQ:
+ mask = 1U << params->subformat;
+ break;
+ case SND_PCM_RULE_REL_NEAR:
+ {
+ unsigned int diff = 0;
+ int n;
+ for (diff = 0; diff < 32; ++diff) {
+ n = (int)params->subformat - (int)diff;
+ if (n >= 0) {
+ unsigned int bit = 1U << n;
+ if (info->subformat_mask & bit) {
+ i = *info;
+ i.subformat_mask = bit;
+ if (snd_pcm_hw_info(pcm, &i) >= 0 &&
+ snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+ *info = i;
+ return 0;
+ }
+ }
+ } else if (params->subformat + diff > SND_PCM_SUBFORMAT_LAST)
+ break;
+ if (diff == 0)
+ continue;
+ n = params->subformat + diff;
+ if (n <= SND_PCM_SUBFORMAT_LAST) {
+ unsigned int bit = 1U << n;
+ if (info->subformat_mask & bit) {
+ i = *info;
+ i.subformat_mask = bit;
+ if (snd_pcm_hw_info(pcm, &i) >= 0 &&
+ snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+ *info = i;
+ return 0;
+ }
+ }
+ }
+ }
+ info->subformat_mask = 0;
+ return -EINVAL;
+ }
+ case SND_PCM_RULE_REL_BITS:
+ mask = params->subformat;
+ break;
+ default:
+ assert(0);
+ return -EINVAL;
+ }
+ info->subformat_mask &= mask;
+ if (info->subformat_mask == 0)
+ return -EINVAL;
+ switch (rel) {
+ case SND_PCM_RULE_REL_LE:
+ case SND_PCM_RULE_REL_LT:
+ for (k = SND_PCM_SUBFORMAT_LAST; k >= 0; --k) {
+ if (!(info->subformat_mask & (1U << k)))
+ continue;
+ i = *info;
+ i.subformat_mask = 1U << k;
+ if (snd_pcm_hw_info(pcm, &i) >= 0 &&
+ snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+ *info = i;
+ return 0;
+ }
+ }
+ info->subformat_mask = 0;
+ return -EINVAL;
+ default:
+ for (k = 0; k <= SND_PCM_SUBFORMAT_LAST; ++k) {
+ if (!(info->subformat_mask & (1U << k)))
+ continue;
+ i = *info;
+ i.subformat_mask = 1U << k;
+ if (snd_pcm_hw_info(pcm, &i) >= 0 &&
+ snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+ *info = i;
+ return 0;
+ }
+ }
+ info->subformat_mask = 0;
+ return -EINVAL;
+ }
+ return 0;
+}
+
+int snd_pcm_hw_info_rules_channels(snd_pcm_t *pcm,
+ snd_pcm_hw_info_t *info,
+ snd_pcm_hw_params_t *params,
+ unsigned int count, int *rules)
+{
+ int err;
+ unsigned int rel;
+ snd_pcm_hw_info_t i;
+ rel = *rules & SND_PCM_RULE_REL_MASK;
+ switch (rel) {
+ case SND_PCM_RULE_REL_LT:
+ if (info->channels_max > params->channels - 1)
+ info->channels_max = params->channels - 1;
+ goto _le;
+ case SND_PCM_RULE_REL_LE:
+ if (info->channels_max > params->channels)
+ info->channels_max = params->channels;
+ _le:
+ while (1) {
+ if (info->channels_min > info->channels_max)
+ return -EINVAL;
+ i = *info;
+ err = snd_pcm_hw_info(pcm, &i);
+ if (err < 0) {
+ info->channels_min = i.channels_min;
+ info->channels_max = i.channels_max;
+ return err;
+ }
+ i.channels_min = i.channels_max;
+ if (snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+ *info = i;
+ return 0;
+ }
+ info->channels_max--;
+ }
+ break;
+ case SND_PCM_RULE_REL_GT:
+ if (info->channels_min < params->channels + 1)
+ info->channels_min = params->channels + 1;
+ goto _ge;
+ case SND_PCM_RULE_REL_GE:
+ if (info->channels_min < params->channels)
+ info->channels_min = params->channels;
+ _ge:
+ while (1) {
+ if (info->channels_min > info->channels_max)
+ return -EINVAL;
+ i = *info;
+ err = snd_pcm_hw_info(pcm, &i);
+ if (err < 0) {
+ info->channels_min = i.channels_min;
+ info->channels_max = i.channels_max;
+ return err;
+ }
+ i.channels_max = i.channels_min;
+ if (snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+ *info = i;
+ return 0;
+ }
+ info->channels_min++;
+ }
+ break;
+ case SND_PCM_RULE_REL_EQ:
+ info->channels_min = params->channels;
+ info->channels_max = params->channels;
+ return snd_pcm_hw_info_rules(pcm, info, params, count - 1, rules + 1);
+ break;
+ case SND_PCM_RULE_REL_NEAR:
+ {
+ unsigned int max1, min2;
+ int err1 = -EINVAL, err2 = -EINVAL;
+ max1 = params->channels;
+ min2 = params->channels+1;
+ if (info->channels_min <= max1) {
+ i = *info;
+ i.channels_max = max1;
+ err1 = snd_pcm_hw_info(pcm, &i);
+ /* shortcut for common case */
+ if (err1 >= 0 && max1 == i.channels_max) {
+ i.channels_min = max1;
+ if (snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+ *info = i;
+ return 0;
+ }
+ i.channels_max = max1 - 1;
+ err1 = snd_pcm_hw_info(pcm, &i);
+ }
+ max1 = i.channels_max;
+ }
+ if (min2 <= info->channels_max) {
+ i = *info;
+ i.channels_min = min2;
+ err2 = snd_pcm_hw_info(pcm, &i);
+ min2 = i.channels_min;
+ }
+ while (1) {
+ unsigned int channels;
+ if (err1 >= 0) {
+ if (err2 >= 0) {
+ if (params->channels - max1 <
+ min2 - params->channels)
+ channels = max1;
+ else
+ channels = min2;
+ } else
+ channels = max1;
+ } else if (err2 >= 0)
+ channels = min2;
+ else {
+ info->channels_min = UINT_MAX;
+ info->channels_max = 0;
+ return -EINVAL;
+ }
+ i = *info;
+ i.channels_min = i.channels_max = channels;
+ if (snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+ *info = i;
+ return 0;
+ }
+ if (channels == max1) {
+ max1--;
+ i = *info;
+ i.channels_max = max1;
+ err1 = snd_pcm_hw_info(pcm, &i);
+ max1 = i.channels_max;
+ } else {
+ min2++;
+ i = *info;
+ i.channels_min = min2;
+ err2 = snd_pcm_hw_info(pcm, &i);
+ min2 = i.channels_min;
+ }
+
+ }
+ break;
+ }
+ case SND_PCM_RULE_REL_BITS:
+ {
+ unsigned int k;
+ for (k = info->channels_min; k < 32; ++k) {
+ if (!(params->channels & (1U << k)))
+ continue;
+ info->channels_min = k;
+ if (info->channels_min > info->channels_max)
+ return -EINVAL;
+ i = *info;
+ err = snd_pcm_hw_info(pcm, &i);
+ if (err < 0) {
+ info->channels_min = i.channels_min;
+ info->channels_max = i.channels_max;
+ return err;
+ }
+ i.channels_max = i.channels_min;
+ if (snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+ *info = i;
+ return 0;
+ }
+ }
+ break;
+ }
+ default:
+ assert(0);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+int snd_pcm_hw_info_rules_rate(snd_pcm_t *pcm,
+ snd_pcm_hw_info_t *info,
+ snd_pcm_hw_params_t *params,
+ unsigned int count, int *rules)
+{
+ int err;
+ unsigned int rel;
+ snd_pcm_hw_info_t i;
+ rel = *rules & SND_PCM_RULE_REL_MASK;
+ switch (rel) {
+ case SND_PCM_RULE_REL_LT:
+ if (info->rate_max > params->rate - 1)
+ info->rate_max = params->rate - 1;
+ goto _le;
+ case SND_PCM_RULE_REL_LE:
+ if (info->rate_max > params->rate)
+ info->rate_max = params->rate;
+ _le:
+ while (1) {
+ if (info->rate_min > info->rate_max)
+ return -EINVAL;
+ i = *info;
+ err = snd_pcm_hw_info(pcm, &i);
+ if (err < 0) {
+ info->rate_min = i.rate_min;
+ info->rate_max = i.rate_max;
+ return err;
+ }
+ i.rate_min = i.rate_max;
+ if (snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+ *info = i;
+ return 0;
+ }
+ info->rate_max--;
+ }
+ break;
+ case SND_PCM_RULE_REL_GT:
+ if (info->rate_min < params->rate + 1)
+ info->rate_min = params->rate + 1;
+ goto _ge;
+ case SND_PCM_RULE_REL_GE:
+ if (info->rate_min < params->rate)
+ info->rate_min = params->rate;
+ _ge:
+ while (1) {
+ if (info->rate_min > info->rate_max)
+ return -EINVAL;
+ i = *info;
+ err = snd_pcm_hw_info(pcm, &i);
+ if (err < 0) {
+ info->rate_min = i.rate_min;
+ info->rate_max = i.rate_max;
+ return err;
+ }
+ i.rate_max = i.rate_min;
+ if (snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+ *info = i;
+ return 0;
+ }
+ info->rate_min++;
+ }
+ break;
+ case SND_PCM_RULE_REL_EQ:
+ info->rate_min = params->rate;
+ info->rate_max = params->rate;
+ return snd_pcm_hw_info_rules(pcm, info, params, count - 1, rules + 1);
+ break;
+ case SND_PCM_RULE_REL_NEAR:
+ {
+ unsigned int max1, min2;
+ int err1 = -EINVAL, err2 = -EINVAL;
+ max1 = params->rate;
+ min2 = params->rate+1;
+ if (info->rate_min <= max1) {
+ i = *info;
+ i.rate_max = max1;
+ err1 = snd_pcm_hw_info(pcm, &i);
+ /* shortcut for common case */
+ if (err1 >= 0 && max1 == i.rate_max) {
+ i.rate_min = max1;
+ if (snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+ *info = i;
+ return 0;
+ }
+ i.rate_max = max1 - 1;
+ err1 = snd_pcm_hw_info(pcm, &i);
+ }
+ max1 = i.rate_max;
+ }
+ if (min2 <= info->rate_max) {
+ i = *info;
+ i.rate_min = min2;
+ err2 = snd_pcm_hw_info(pcm, &i);
+ min2 = i.rate_min;
+ }
+ while (1) {
+ unsigned int rate;
+ if (err1 >= 0) {
+ if (err2 >= 0) {
+ if (params->rate - max1 <
+ min2 - params->rate)
+ rate = max1;
+ else
+ rate = min2;
+ } else
+ rate = max1;
+ } else if (err2 >= 0)
+ rate = min2;
+ else {
+ info->rate_min = UINT_MAX;
+ info->rate_max = 0;
+ return -EINVAL;
+ }
+ i = *info;
+ i.rate_min = i.rate_max = rate;
+ if (snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+ *info = i;
+ return 0;
+ }
+ if (rate == max1) {
+ max1--;
+ i = *info;
+ i.rate_max = max1;
+ err1 = snd_pcm_hw_info(pcm, &i);
+ max1 = i.rate_max;
+ } else {
+ min2++;
+ i = *info;
+ i.rate_min = min2;
+ err2 = snd_pcm_hw_info(pcm, &i);
+ min2 = i.rate_min;
+ }
+
+ }
+ break;
+ }
+ case SND_PCM_RULE_REL_BITS:
+ {
+ unsigned int k;
+ for (k = 0; k < SND_PCM_RATES; ++k) {
+ if (snd_pcm_rates[k].rate < info->rate_min)
+ continue;
+ if (!(params->rate & snd_pcm_rates[k].flag))
+ continue;
+ info->rate_min = snd_pcm_rates[k].rate;
+ if (info->rate_min > info->rate_max)
+ return -EINVAL;
+ i = *info;
+ err = snd_pcm_hw_info(pcm, &i);
+ if (err < 0) {
+ info->rate_min = i.rate_min;
+ info->rate_max = i.rate_max;
+ return err;
+ }
+ i.rate_max = i.rate_min;
+ if (snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+ *info = i;
+ return 0;
+ }
+ }
+ break;
+ }
+ default:
+ assert(0);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+int snd_pcm_hw_info_rules_fragment_size(snd_pcm_t *pcm,
+ snd_pcm_hw_info_t *info,
+ snd_pcm_hw_params_t *params,
+ unsigned int count, int *rules)
+{
+ int err;
+ unsigned int rel;
+ snd_pcm_hw_info_t i;
+ rel = *rules & SND_PCM_RULE_REL_MASK;
+ switch (rel) {
+ case SND_PCM_RULE_REL_LT:
+ if (info->fragment_size_max > params->fragment_size - 1)
+ info->fragment_size_max = params->fragment_size - 1;
+ goto _le;
+ case SND_PCM_RULE_REL_LE:
+ if (info->fragment_size_max > params->fragment_size)
+ info->fragment_size_max = params->fragment_size;
+ _le:
+ while (1) {
+ if (info->fragment_size_min > info->fragment_size_max)
+ return -EINVAL;
+ i = *info;
+ err = snd_pcm_hw_info(pcm, &i);
+ if (err < 0) {
+ info->fragment_size_min = i.fragment_size_min;
+ info->fragment_size_max = i.fragment_size_max;
+ return err;
+ }
+ i.fragment_size_min = i.fragment_size_max;
+ if (snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+ *info = i;
+ return 0;
+ }
+ info->fragment_size_max--;
+ }
+ break;
+ case SND_PCM_RULE_REL_GT:
+ if (info->fragment_size_min < params->fragment_size + 1)
+ info->fragment_size_min = params->fragment_size + 1;
+ goto _ge;
+ case SND_PCM_RULE_REL_GE:
+ if (info->fragment_size_min < params->fragment_size)
+ info->fragment_size_min = params->fragment_size;
+ _ge:
+ while (1) {
+ if (info->fragment_size_min > info->fragment_size_max)
+ return -EINVAL;
+ i = *info;
+ err = snd_pcm_hw_info(pcm, &i);
+ if (err < 0) {
+ info->fragment_size_min = i.fragment_size_min;
+ info->fragment_size_max = i.fragment_size_max;
+ return err;
+ }
+ i.fragment_size_max = i.fragment_size_min;
+ if (snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+ *info = i;
+ return 0;
+ }
+ info->fragment_size_min++;
+ }
+ break;
+ case SND_PCM_RULE_REL_EQ:
+ info->fragment_size_min = params->fragment_size;
+ info->fragment_size_max = params->fragment_size;
+ return snd_pcm_hw_info_rules(pcm, info, params, count - 1, rules + 1);
+ break;
+ case SND_PCM_RULE_REL_NEAR:
+ {
+ size_t max1, min2;
+ int err1 = -EINVAL, err2 = -EINVAL;
+ max1 = params->fragment_size;
+ min2 = params->fragment_size+1;
+ if (info->fragment_size_min <= max1) {
+ i = *info;
+ i.fragment_size_max = max1;
+ err1 = snd_pcm_hw_info(pcm, &i);
+ /* shortcut for common case */
+ if (err1 >= 0 && max1 == i.fragment_size_max) {
+ i.fragment_size_min = max1;
+ if (snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+ *info = i;
+ return 0;
+ }
+ i.fragment_size_max = max1 - 1;
+ err1 = snd_pcm_hw_info(pcm, &i);
+ }
+ max1 = i.fragment_size_max;
+ }
+ if (min2 <= info->fragment_size_max) {
+ i = *info;
+ i.fragment_size_min = min2;
+ err2 = snd_pcm_hw_info(pcm, &i);
+ min2 = i.fragment_size_min;
+ }
+ while (1) {
+ size_t fragment_size;
+ if (err1 >= 0) {
+ if (err2 >= 0) {
+ if (params->fragment_size - max1 <
+ min2 - params->fragment_size)
+ fragment_size = max1;
+ else
+ fragment_size = min2;
+ } else
+ fragment_size = max1;
+ } else if (err2 >= 0)
+ fragment_size = min2;
+ else {
+ info->fragment_size_min = ULONG_MAX;
+ info->fragment_size_max = 0;
+ return -EINVAL;
+ }
+ i = *info;
+ i.fragment_size_min = i.fragment_size_max = fragment_size;
+ if (snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+ *info = i;
+ return 0;
+ }
+ if (fragment_size == max1) {
+ max1--;
+ i = *info;
+ i.fragment_size_max = max1;
+ err1 = snd_pcm_hw_info(pcm, &i);
+ max1 = i.fragment_size_max;
+ } else {
+ min2++;
+ i = *info;
+ i.fragment_size_min = min2;
+ err2 = snd_pcm_hw_info(pcm, &i);
+ min2 = i.fragment_size_min;
+ }
+
+ }
+ break;
+ }
+ case SND_PCM_RULE_REL_BITS:
+ {
+ unsigned int k;
+ for (k = info->fragment_size_min; k < 32; ++k) {
+ if (!(params->fragment_size & (1U << k)))
+ continue;
+ info->fragment_size_min = 1U << k;
+ if (info->fragment_size_min > info->fragment_size_max)
+ return -EINVAL;
+ i = *info;
+ err = snd_pcm_hw_info(pcm, &i);
+ if (err < 0) {
+ info->fragment_size_min = i.fragment_size_min;
+ info->fragment_size_max = i.fragment_size_max;
+ return err;
+ }
+ i.fragment_size_max = i.fragment_size_min;
+ if (snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+ *info = i;
+ return 0;
+ }
+ }
+ break;
+ }
+ default:
+ assert(0);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+int snd_pcm_hw_info_rules_fragments(snd_pcm_t *pcm,
+ snd_pcm_hw_info_t *info,
+ snd_pcm_hw_params_t *params,
+ unsigned int count, int *rules)
+{
+ int err;
+ unsigned int rel;
+ snd_pcm_hw_info_t i;
+ rel = *rules & SND_PCM_RULE_REL_MASK;
+ switch (rel) {
+ case SND_PCM_RULE_REL_LT:
+ if (info->fragments_max > params->fragments - 1)
+ info->fragments_max = params->fragments - 1;
+ goto _le;
+ case SND_PCM_RULE_REL_LE:
+ if (info->fragments_max > params->fragments)
+ info->fragments_max = params->fragments;
+ _le:
+ while (1) {
+ if (info->fragments_min > info->fragments_max)
+ return -EINVAL;
+ i = *info;
+ err = snd_pcm_hw_info(pcm, &i);
+ if (err < 0) {
+ info->fragments_min = i.fragments_min;
+ info->fragments_max = i.fragments_max;
+ return err;
+ }
+ i.fragments_min = i.fragments_max;
+ if (snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+ *info = i;
+ return 0;
+ }
+ info->fragments_max--;
+ }
+ break;
+ case SND_PCM_RULE_REL_GT:
+ if (info->fragments_min < params->fragments + 1)
+ info->fragments_min = params->fragments + 1;
+ goto _ge;
+ case SND_PCM_RULE_REL_GE:
+ if (info->fragments_min < params->fragments)
+ info->fragments_min = params->fragments;
+ _ge:
+ while (1) {
+ if (info->fragments_min > info->fragments_max)
+ return -EINVAL;
+ i = *info;
+ err = snd_pcm_hw_info(pcm, &i);
+ if (err < 0) {
+ info->fragments_min = i.fragments_min;
+ info->fragments_max = i.fragments_max;
+ return err;
+ }
+ i.fragments_max = i.fragments_min;
+ if (snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+ *info = i;
+ return 0;
+ }
+ info->fragments_min++;
+ }
+ break;
+ case SND_PCM_RULE_REL_EQ:
+ info->fragments_min = params->fragments;
+ info->fragments_max = params->fragments;
+ return snd_pcm_hw_info_rules(pcm, info, params, count - 1, rules + 1);
+ break;
+ case SND_PCM_RULE_REL_NEAR:
+ {
+ unsigned int max1, min2;
+ int err1 = -EINVAL, err2 = -EINVAL;
+ max1 = params->fragments;
+ min2 = params->fragments+1;
+ if (info->fragments_min <= max1) {
+ i = *info;
+ i.fragments_max = max1;
+ err1 = snd_pcm_hw_info(pcm, &i);
+ /* shortcut for common case */
+ if (err1 >= 0 && max1 == i.fragments_max) {
+ i.fragments_min = max1;
+ if (snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+ *info = i;
+ return 0;
+ }
+ i.fragments_max = max1 - 1;
+ err1 = snd_pcm_hw_info(pcm, &i);
+ }
+ max1 = i.fragments_max;
+ }
+ if (min2 <= info->fragments_max) {
+ i = *info;
+ i.fragments_min = min2;
+ err2 = snd_pcm_hw_info(pcm, &i);
+ min2 = i.fragments_min;
+ }
+ while (1) {
+ unsigned int fragments;
+ if (err1 >= 0) {
+ if (err2 >= 0) {
+ if (params->fragments - max1 <
+ min2 - params->fragments)
+ fragments = max1;
+ else
+ fragments = min2;
+ } else
+ fragments = max1;
+ } else if (err2 >= 0)
+ fragments = min2;
+ else {
+ info->fragments_min = UINT_MAX;
+ info->fragments_max = 0;
+ return -EINVAL;
+ }
+ i = *info;
+ i.fragments_min = i.fragments_max = fragments;
+ if (snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+ *info = i;
+ return 0;
+ }
+ if (fragments == max1) {
+ max1--;
+ i = *info;
+ i.fragments_max = max1;
+ err1 = snd_pcm_hw_info(pcm, &i);
+ max1 = i.fragments_max;
+ } else {
+ min2++;
+ i = *info;
+ i.fragments_min = min2;
+ err2 = snd_pcm_hw_info(pcm, &i);
+ min2 = i.fragments_min;
+ }
+
+ }
+ break;
+ }
+ case SND_PCM_RULE_REL_BITS:
+ {
+ unsigned int k;
+ for (k = info->fragments_min; k < 32; ++k) {
+ if (!(params->fragments & (1U << k)))
+ continue;
+ info->fragments_min = k;
+ if (info->fragments_min > info->fragments_max)
+ return -EINVAL;
+ i = *info;
+ err = snd_pcm_hw_info(pcm, &i);
+ if (err < 0) {
+ info->fragments_min = i.fragments_min;
+ info->fragments_max = i.fragments_max;
+ return err;
+ }
+ i.fragments_max = i.fragments_min;
+ if (snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+ *info = i;
+ return 0;
+ }
+ }
+ break;
+ }
+ default:
+ assert(0);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+int snd_pcm_hw_info_rules(snd_pcm_t *pcm,
+ snd_pcm_hw_info_t *info,
+ snd_pcm_hw_params_t *params,
+ unsigned int count, int *rules)
+{
+ unsigned int par;
+ if (count == 0)
+ return snd_pcm_hw_info(pcm, info);
+ par = rules[0] & SND_PCM_RULE_PAR_MASK;
+ switch (par) {
+ case SND_PCM_HW_PARAM_ACCESS:
+ return snd_pcm_hw_info_rules_access(pcm, info, params, count, rules);
+ case SND_PCM_HW_PARAM_FORMAT:
+ return snd_pcm_hw_info_rules_format(pcm, info, params, count, rules);
+ case SND_PCM_HW_PARAM_SUBFORMAT:
+ return snd_pcm_hw_info_rules_subformat(pcm, info, params, count, rules);
+ case SND_PCM_HW_PARAM_CHANNELS:
+ return snd_pcm_hw_info_rules_channels(pcm, info, params, count, rules);
+ case SND_PCM_HW_PARAM_RATE:
+ return snd_pcm_hw_info_rules_rate(pcm, info, params, count, rules);
+ case SND_PCM_HW_PARAM_FRAGMENT_SIZE:
+ return snd_pcm_hw_info_rules_fragment_size(pcm, info, params, count, rules);
+ case SND_PCM_HW_PARAM_FRAGMENTS:
+ return snd_pcm_hw_info_rules_fragments(pcm, info, params, count, rules);
+ default:
+ assert(0);
+ return -EINVAL;
+ }
+}
+
+int snd_pcm_hw_info_rulesv(snd_pcm_t *pcm,
+ snd_pcm_hw_info_t *info,
+ snd_pcm_hw_params_t *params, ...)
+{
+ va_list arg;
+ unsigned int count = 0;
+ int rules[32];
+ va_start(arg, params);
+ while (1) {
+ int i = va_arg(arg, int);
+ if (i == -1)
+ break;
+ rules[count++] = i;
+ }
+ va_end(arg);
+ return snd_pcm_hw_info_rules(pcm, info, params, count, rules);
+}
+
+int snd_pcm_hw_params_rules(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+ unsigned int count, int *rules)
+{
+ int err;
+ snd_pcm_hw_info_t info;
+ unsigned int k;
+ snd_pcm_hw_params_to_info(params, &info);
+ for (k = 0; k < count; ++k) {
+ switch (rules[k] & SND_PCM_RULE_PAR_MASK) {
+ case SND_PCM_HW_PARAM_ACCESS:
+ info.access_mask = ~0;
+ break;
+ case SND_PCM_HW_PARAM_FORMAT:
+ info.format_mask = ~0;
+ break;
+ case SND_PCM_HW_PARAM_SUBFORMAT:
+ info.subformat_mask = ~0;
+ break;
+ case SND_PCM_HW_PARAM_CHANNELS:
+ info.channels_min = 0;
+ info.channels_max = UINT_MAX;
+ break;
+ case SND_PCM_HW_PARAM_RATE:
+ info.rate_min = 0;
+ info.rate_max = UINT_MAX;
+ break;
+ case SND_PCM_HW_PARAM_FRAGMENT_SIZE:
+ info.fragment_size_min = 0;
+ info.fragment_size_max = ULONG_MAX;
+ break;
+ case SND_PCM_HW_PARAM_FRAGMENTS:
+ info.fragments_min = 0;
+ info.fragments_max = UINT_MAX;
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ }
+ err = snd_pcm_hw_info_rules(pcm, &info, params, count, rules);
+ if (err < 0) {
+ snd_pcm_hw_info_to_params_fail(&info, params);
+ return err;
+ }
+ snd_pcm_hw_info_to_params(&info, params);
+ return snd_pcm_hw_params(pcm, params);
+}
+
+int snd_pcm_hw_params_rulesv(snd_pcm_t *pcm,
+ snd_pcm_hw_params_t *params, ...)
{
va_list arg;
- va_start(arg, fmt);
- fprintf(stderr, "ALSA PCM lib %s:%i:(%s) ", file, line, function);
- vfprintf(stderr, fmt, arg);
- if (err)
- fprintf(stderr, ": %s", snd_strerror(err));
- putc('\n', stderr);
+ unsigned int count = 0;
+ int rules[32];
+ va_start(arg, params);
+ while (1) {
+ int i = va_arg(arg, int);
+ if (i == -1)
+ break;
+ rules[count++] = i;
+ }
va_end(arg);
+ return snd_pcm_hw_params_rules(pcm, params, count, rules);
}
+
diff --git a/src/pcm/pcm_adpcm.c b/src/pcm/pcm_adpcm.c
index 2c58b1da..d6be0e57 100644
--- a/src/pcm/pcm_adpcm.c
+++ b/src/pcm/pcm_adpcm.c
@@ -69,8 +69,6 @@ typedef struct {
int getput_idx;
adpcm_f func;
int sformat;
- int cformat;
- int cxfer_mode, cmmap_shape;
adpcm_state_t *states;
} snd_pcm_adpcm_t;
@@ -331,102 +329,82 @@ static int snd_pcm_adpcm_close(snd_pcm_t *pcm)
return 0;
}
-static int snd_pcm_adpcm_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t * info)
+static int snd_pcm_adpcm_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t * info)
{
snd_pcm_adpcm_t *adpcm = pcm->private;
- unsigned int req_mask = info->req_mask;
- unsigned int sfmt = info->req.format.sfmt;
+ unsigned int format_mask, access_mask;
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->access_mask &= (SND_PCM_ACCBIT_MMAP_INTERLEAVED |
+ SND_PCM_ACCBIT_RW_INTERLEAVED |
+ SND_PCM_ACCBIT_MMAP_NONINTERLEAVED |
+ SND_PCM_ACCBIT_RW_NONINTERLEAVED);
+ access_mask = info->access_mask;
+ if (access_mask == 0)
+ return -EINVAL;
+ if (adpcm->sformat == SND_PCM_FORMAT_IMA_ADPCM)
+ info->format_mask &= SND_PCM_FMTBIT_LINEAR;
+ else
+ info->format_mask &= SND_PCM_FMTBIT_IMA_ADPCM;
+ format_mask = info->format_mask;
+ if (format_mask == 0)
+ return -EINVAL;
+
+ info->format_mask = 1U << adpcm->sformat;
+ info->access_mask = SND_PCM_ACCBIT_MMAP;
+ err = snd_pcm_hw_info(adpcm->plug.slave, info);
+ if (info->format_mask)
+ info->format_mask = format_mask;
+ if (info->access_mask) {
+ adpcm->plug.saccess_mask = info->access_mask;
+ info->access_mask = access_mask;
}
- 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;
+ info->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
+ snd_pcm_hw_info_complete(info);
+ return 0;
}
-static int snd_pcm_adpcm_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
+static int snd_pcm_adpcm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
{
snd_pcm_adpcm_t *adpcm = pcm->private;
snd_pcm_t *slave = adpcm->plug.slave;
+ unsigned int format, access;
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;
- }
- 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_mmap(slave, params);
- params->format.sfmt = adpcm->cformat;
- params->xfer_mode = adpcm->cxfer_mode;
- params->mmap_shape = adpcm->cmmap_shape;
- 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);
+ format = params->format;
+ access = params->access;
+ params->format = adpcm->sformat;
+ if (adpcm->plug.saccess_mask & SND_PCM_ACCBIT_MMAP_INTERLEAVED)
+ params->access = SND_PCM_ACCESS_MMAP_INTERLEAVED;
+ else if (adpcm->plug.saccess_mask & SND_PCM_ACCBIT_MMAP_NONINTERLEAVED)
+ params->access = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;
+ else
+ assert(0);
+ err = snd_pcm_hw_params(slave, params);
+ params->format = format;
+ params->access = access;
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 = get_index(adpcm->cformat, SND_PCM_SFMT_S16);
+ if (adpcm->sformat == SND_PCM_FORMAT_IMA_ADPCM) {
+ adpcm->getput_idx = get_index(format, SND_PCM_FORMAT_S16);
adpcm->func = adpcm_encode;
} else {
- adpcm->getput_idx = put_index(SND_PCM_SFMT_S16, adpcm->sformat);
+ adpcm->getput_idx = put_index(SND_PCM_FORMAT_S16, adpcm->sformat);
adpcm->func = adpcm_decode;
}
} else {
- if (adpcm->sformat == SND_PCM_SFMT_IMA_ADPCM) {
- adpcm->getput_idx = put_index(SND_PCM_SFMT_S16, adpcm->cformat);
+ if (adpcm->sformat == SND_PCM_FORMAT_IMA_ADPCM) {
+ adpcm->getput_idx = put_index(SND_PCM_FORMAT_S16, format);
adpcm->func = adpcm_decode;
} else {
- adpcm->getput_idx = get_index(adpcm->sformat, SND_PCM_SFMT_S16);
+ adpcm->getput_idx = get_index(adpcm->sformat, SND_PCM_FORMAT_S16);
adpcm->func = adpcm_encode;
}
}
if (adpcm->states)
free(adpcm->states);
- adpcm->states = malloc(setup->format.channels * sizeof(*adpcm->states));
+ adpcm->states = malloc(params->channels * sizeof(*adpcm->states));
return 0;
}
@@ -434,7 +412,7 @@ 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) {
+ for (k = 0; k < pcm->channels; ++k) {
adpcm->states[k].pred_val = 0;
adpcm->states[k].step_idx = 0;
}
@@ -458,7 +436,7 @@ static ssize_t snd_pcm_adpcm_write_areas(snd_pcm_t *pcm,
size_t frames = snd_pcm_mmap_playback_xfer(slave, size - xfer);
adpcm->func(areas, offset,
snd_pcm_mmap_areas(slave), snd_pcm_mmap_offset(slave),
- frames, pcm->setup.format.channels,
+ frames, pcm->channels,
adpcm->getput_idx, adpcm->states);
err = snd_pcm_mmap_forward(slave, frames);
if (err < 0)
@@ -493,7 +471,7 @@ static ssize_t snd_pcm_adpcm_read_areas(snd_pcm_t *pcm,
size_t frames = snd_pcm_mmap_capture_xfer(slave, size - xfer);
adpcm->func(snd_pcm_mmap_areas(slave), snd_pcm_mmap_offset(slave),
areas, offset,
- frames, pcm->setup.format.channels,
+ frames, pcm->channels,
adpcm->getput_idx, adpcm->states);
err = snd_pcm_mmap_forward(slave, frames);
if (err < 0)
@@ -516,7 +494,7 @@ 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) {
+ if (pcm->setup) {
fprintf(fp, "Its setup is:\n");
snd_pcm_dump_setup(pcm, fp);
}
@@ -527,12 +505,12 @@ static void snd_pcm_adpcm_dump(snd_pcm_t *pcm, FILE *fp)
snd_pcm_ops_t 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,
+ hw_info: snd_pcm_adpcm_hw_info,
+ hw_params: snd_pcm_adpcm_hw_params,
+ sw_params: snd_pcm_plugin_sw_params,
+ dig_info: snd_pcm_plugin_dig_info,
+ dig_params: snd_pcm_plugin_dig_params,
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,
async: snd_pcm_plugin_async,
@@ -546,7 +524,7 @@ int snd_pcm_adpcm_open(snd_pcm_t **pcmp, char *name, int sformat, snd_pcm_t *sla
snd_pcm_adpcm_t *adpcm;
assert(pcmp && slave);
if (snd_pcm_format_linear(sformat) != 1 &&
- sformat != SND_PCM_SFMT_IMA_ADPCM)
+ sformat != SND_PCM_FORMAT_IMA_ADPCM)
return -EINVAL;
adpcm = calloc(1, sizeof(snd_pcm_adpcm_t));
if (!adpcm) {
@@ -614,7 +592,7 @@ int _snd_pcm_adpcm_open(snd_pcm_t **pcmp, char *name,
if (sformat < 0)
return -EINVAL;
if (snd_pcm_format_linear(sformat) != 1 &&
- sformat != SND_PCM_SFMT_IMA_ADPCM)
+ sformat != SND_PCM_FORMAT_IMA_ADPCM)
return -EINVAL;
continue;
}
diff --git a/src/pcm/pcm_alaw.c b/src/pcm/pcm_alaw.c
index de8f944e..fd5f619c 100644
--- a/src/pcm/pcm_alaw.c
+++ b/src/pcm/pcm_alaw.c
@@ -35,8 +35,6 @@ typedef struct {
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)
@@ -213,96 +211,76 @@ static void alaw_encode(snd_pcm_channel_area_t *src_areas,
}
}
-static int snd_pcm_alaw_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t * info)
+static int snd_pcm_alaw_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t * info)
{
snd_pcm_alaw_t *alaw = pcm->private;
- unsigned int req_mask = info->req_mask;
- unsigned int sfmt = info->req.format.sfmt;
+ unsigned int format_mask, access_mask;
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->access_mask &= (SND_PCM_ACCBIT_MMAP_INTERLEAVED |
+ SND_PCM_ACCBIT_RW_INTERLEAVED |
+ SND_PCM_ACCBIT_MMAP_NONINTERLEAVED |
+ SND_PCM_ACCBIT_RW_NONINTERLEAVED);
+ access_mask = info->access_mask;
+ if (access_mask == 0)
+ return -EINVAL;
+ if (alaw->sformat == SND_PCM_FORMAT_MU_LAW)
+ info->format_mask &= SND_PCM_FMTBIT_LINEAR;
+ else
+ info->format_mask &= SND_PCM_FMTBIT_MU_LAW;
+ format_mask = info->format_mask;
+ if (format_mask == 0)
+ return -EINVAL;
+
+ info->format_mask = 1U << alaw->sformat;
+ info->access_mask = SND_PCM_ACCBIT_MMAP;
+ err = snd_pcm_hw_info(alaw->plug.slave, info);
+ if (info->format_mask)
+ info->format_mask = format_mask;
+ if (info->access_mask) {
+ alaw->plug.saccess_mask = info->access_mask;
+ info->access_mask = access_mask;
}
- 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;
+ info->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
+ snd_pcm_hw_info_complete(info);
+ return 0;
}
-static int snd_pcm_alaw_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
+static int snd_pcm_alaw_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
{
snd_pcm_alaw_t *alaw = pcm->private;
snd_pcm_t *slave = alaw->plug.slave;
+ unsigned int format, access;
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;
- }
- 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_mmap(slave, params);
- params->format.sfmt = alaw->cformat;
- params->xfer_mode = alaw->cxfer_mode;
- params->mmap_shape = alaw->cmmap_shape;
- 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);
+ format = params->format;
+ access = params->access;
+ params->format = alaw->sformat;
+ if (alaw->plug.saccess_mask & SND_PCM_ACCBIT_MMAP_INTERLEAVED)
+ params->access = SND_PCM_ACCESS_MMAP_INTERLEAVED;
+ else if (alaw->plug.saccess_mask & SND_PCM_ACCBIT_MMAP_NONINTERLEAVED)
+ params->access = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;
+ else
+ assert(0);
+ err = snd_pcm_hw_params(slave, params);
+ params->format = format;
+ params->access = access;
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 = get_index(alaw->cformat, SND_PCM_SFMT_S16);
+ if (alaw->sformat == SND_PCM_FORMAT_MU_LAW) {
+ alaw->getput_idx = get_index(format, SND_PCM_FORMAT_S16);
alaw->func = alaw_encode;
} else {
- alaw->getput_idx = put_index(SND_PCM_SFMT_S16, alaw->sformat);
+ alaw->getput_idx = put_index(SND_PCM_FORMAT_S16, alaw->sformat);
alaw->func = alaw_decode;
}
} else {
- if (alaw->sformat == SND_PCM_SFMT_A_LAW) {
- alaw->getput_idx = put_index(SND_PCM_SFMT_S16, alaw->cformat);
+ if (alaw->sformat == SND_PCM_FORMAT_MU_LAW) {
+ alaw->getput_idx = put_index(SND_PCM_FORMAT_S16, format);
alaw->func = alaw_decode;
} else {
- alaw->getput_idx = get_index(alaw->sformat, SND_PCM_SFMT_S16);
+ alaw->getput_idx = get_index(alaw->sformat, SND_PCM_FORMAT_S16);
alaw->func = alaw_encode;
}
}
@@ -326,7 +304,7 @@ static ssize_t snd_pcm_alaw_write_areas(snd_pcm_t *pcm,
size_t frames = snd_pcm_mmap_playback_xfer(slave, size - xfer);
alaw->func(areas, offset,
snd_pcm_mmap_areas(slave), snd_pcm_mmap_offset(slave),
- frames, pcm->setup.format.channels,
+ frames, pcm->channels,
alaw->getput_idx);
err = snd_pcm_mmap_forward(slave, frames);
if (err < 0)
@@ -361,7 +339,7 @@ static ssize_t snd_pcm_alaw_read_areas(snd_pcm_t *pcm,
size_t frames = snd_pcm_mmap_capture_xfer(slave, size - xfer);
alaw->func(snd_pcm_mmap_areas(slave), snd_pcm_mmap_offset(slave),
areas, offset,
- frames, pcm->setup.format.channels,
+ frames, pcm->channels,
alaw->getput_idx);
err = snd_pcm_mmap_forward(slave, frames);
if (err < 0)
@@ -384,7 +362,7 @@ 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) {
+ if (pcm->setup) {
fprintf(fp, "Its setup is:\n");
snd_pcm_dump_setup(pcm, fp);
}
@@ -395,12 +373,12 @@ static void snd_pcm_alaw_dump(snd_pcm_t *pcm, FILE *fp)
snd_pcm_ops_t 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,
+ hw_info: snd_pcm_alaw_hw_info,
+ hw_params: snd_pcm_alaw_hw_params,
+ sw_params: snd_pcm_plugin_sw_params,
+ dig_info: snd_pcm_plugin_dig_info,
+ dig_params: snd_pcm_plugin_dig_params,
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,
async: snd_pcm_plugin_async,
@@ -414,7 +392,7 @@ int snd_pcm_alaw_open(snd_pcm_t **pcmp, char *name, int sformat, snd_pcm_t *slav
snd_pcm_alaw_t *alaw;
assert(pcmp && slave);
if (snd_pcm_format_linear(sformat) != 1 &&
- sformat != SND_PCM_SFMT_A_LAW)
+ sformat != SND_PCM_FORMAT_A_LAW)
return -EINVAL;
alaw = calloc(1, sizeof(snd_pcm_alaw_t));
if (!alaw) {
@@ -481,7 +459,7 @@ int _snd_pcm_alaw_open(snd_pcm_t **pcmp, char *name,
if (sformat < 0)
return -EINVAL;
if (snd_pcm_format_linear(sformat) != 1 &&
- sformat != SND_PCM_SFMT_A_LAW)
+ sformat != SND_PCM_FORMAT_A_LAW)
return -EINVAL;
continue;
}
diff --git a/src/pcm/pcm_file.c b/src/pcm/pcm_file.c
index 192bccc6..4130812e 100644
--- a/src/pcm/pcm_file.c
+++ b/src/pcm/pcm_file.c
@@ -23,11 +23,16 @@
#include "pcm_local.h"
#include "pcm_plugin.h"
+enum {
+ SND_PCM_FILE_FORMAT_RAW
+};
+
typedef struct {
snd_pcm_t *slave;
int close_slave;
char *fname;
int fd;
+ int format;
} snd_pcm_file_t;
static int snd_pcm_file_close(snd_pcm_t *pcm)
@@ -68,18 +73,6 @@ static int snd_pcm_file_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * in
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;
@@ -148,11 +141,16 @@ static void snd_pcm_file_write_areas(snd_pcm_t *pcm,
snd_pcm_file_t *file = pcm->private;
size_t bytes = snd_pcm_frames_to_bytes(pcm, frames);
char *buf;
- size_t channels = pcm->setup.format.channels;
+ size_t channels = pcm->channels;
snd_pcm_channel_area_t buf_areas[channels];
size_t channel;
ssize_t r;
- if (pcm->setup.mmap_shape != SND_PCM_MMAP_INTERLEAVED) {
+ switch (pcm->access) {
+ case SND_PCM_ACCESS_MMAP_INTERLEAVED:
+ case SND_PCM_ACCESS_RW_INTERLEAVED:
+ buf = snd_pcm_channel_area_addr(areas, offset);
+ break;
+ default:
buf = alloca(bytes);
for (channel = 0; channel < channels; ++channel) {
snd_pcm_channel_area_t *a = &buf_areas[channel];
@@ -161,9 +159,8 @@ static void snd_pcm_file_write_areas(snd_pcm_t *pcm,
a->step = pcm->bits_per_frame;
}
snd_pcm_areas_copy(areas, offset, buf_areas, 0,
- channels, frames, pcm->setup.format.sfmt);
- } else
- buf = snd_pcm_channel_area_addr(areas, offset);
+ channels, frames, pcm->format);
+ }
r = write(file->fd, buf, bytes);
assert(r == (ssize_t)bytes);
}
@@ -183,7 +180,7 @@ static ssize_t snd_pcm_file_writei(snd_pcm_t *pcm, const void *buffer, size_t si
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];
+ snd_pcm_channel_area_t areas[pcm->channels];
ssize_t n = snd_pcm_writen(file->slave, bufs, size);
if (n > 0) {
snd_pcm_areas_from_bufs(pcm, areas, bufs);
@@ -207,7 +204,7 @@ static ssize_t snd_pcm_file_readi(snd_pcm_t *pcm, void *buffer, size_t size)
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];
+ snd_pcm_channel_area_t areas[pcm->channels];
ssize_t n = snd_pcm_writen(file->slave, bufs, size);
if (n > 0) {
snd_pcm_areas_from_bufs(pcm, areas, bufs);
@@ -226,12 +223,12 @@ static ssize_t snd_pcm_file_mmap_forward(snd_pcm_t *pcm, size_t size)
return n;
while (xfer < (size_t)n) {
size_t frames = size - xfer;
- size_t cont = pcm->setup.buffer_size - ofs;
+ size_t cont = pcm->buffer_size - ofs;
if (cont < frames)
frames = cont;
snd_pcm_file_write_areas(pcm, snd_pcm_mmap_areas(file->slave), ofs, frames);
ofs += frames;
- if (ofs == pcm->setup.buffer_size)
+ if (ofs == pcm->buffer_size)
ofs = 0;
xfer += frames;
}
@@ -250,44 +247,46 @@ static int snd_pcm_file_set_avail_min(snd_pcm_t *pcm, size_t frames)
return snd_pcm_set_avail_min(file->slave, frames);
}
-static int snd_pcm_file_mmap(snd_pcm_t *pcm)
+static int snd_pcm_file_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t * info)
{
snd_pcm_file_t *file = pcm->private;
- int err = snd_pcm_mmap(file->slave);
- if (err < 0)
- return err;
- pcm->mmap_info_count = file->slave->mmap_info_count;
- pcm->mmap_info = file->slave->mmap_info;
- return 0;
+ return snd_pcm_hw_info(file->slave, info);
}
-static int snd_pcm_file_munmap(snd_pcm_t *pcm)
+static int snd_pcm_file_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
{
snd_pcm_file_t *file = pcm->private;
- int err = snd_pcm_munmap(file->slave);
- if (err < 0)
- return err;
- pcm->mmap_info_count = 0;
- pcm->mmap_info = 0;
- return 0;
+ return snd_pcm_hw_params(file->slave, params);
+}
+
+static int snd_pcm_file_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params)
+{
+ snd_pcm_file_t *file = pcm->private;
+ return snd_pcm_sw_params(file->slave, params);
+}
+
+static int snd_pcm_file_dig_info(snd_pcm_t *pcm, snd_pcm_dig_info_t * info)
+{
+ snd_pcm_file_t *file = pcm->private;
+ return snd_pcm_dig_info(file->slave, info);
}
-static int snd_pcm_file_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t * info)
+static int snd_pcm_file_dig_params(snd_pcm_t *pcm, snd_pcm_dig_params_t * params)
{
snd_pcm_file_t *file = pcm->private;
- return snd_pcm_params_info(file->slave, info);
+ return snd_pcm_dig_params(file->slave, params);
}
-static int snd_pcm_file_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
+static int snd_pcm_file_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
{
snd_pcm_file_t *file = pcm->private;
- return snd_pcm_params(file->slave, params);
+ return snd_pcm_mmap(file->slave);
}
-static int snd_pcm_file_setup(snd_pcm_t *pcm, snd_pcm_setup_t * setup)
+static int snd_pcm_file_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
{
snd_pcm_file_t *file = pcm->private;
- return snd_pcm_setup(file->slave, setup);
+ return snd_pcm_munmap(file->slave);
}
static void snd_pcm_file_dump(snd_pcm_t *pcm, FILE *fp)
@@ -297,7 +296,7 @@ static void snd_pcm_file_dump(snd_pcm_t *pcm, FILE *fp)
fprintf(fp, "File PCM (file=%s)\n", file->fname);
else
fprintf(fp, "File PCM (fd=%d)\n", file->fd);
- if (pcm->valid_setup) {
+ if (pcm->setup) {
fprintf(fp, "Its setup is:\n");
snd_pcm_dump_setup(pcm, fp);
}
@@ -308,12 +307,12 @@ static void snd_pcm_file_dump(snd_pcm_t *pcm, FILE *fp)
snd_pcm_ops_t 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,
+ hw_info: snd_pcm_file_hw_info,
+ hw_params: snd_pcm_file_hw_params,
+ sw_params: snd_pcm_file_sw_params,
+ dig_info: snd_pcm_file_dig_info,
+ dig_params: snd_pcm_file_dig_params,
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,
async: snd_pcm_file_async,
@@ -340,11 +339,11 @@ snd_pcm_fast_ops_t snd_pcm_file_fast_ops = {
set_avail_min: snd_pcm_file_set_avail_min,
};
-int snd_pcm_file_open(snd_pcm_t **pcmp, char *name, char *fname, int fd, snd_pcm_t *slave, int close_slave)
+int snd_pcm_file_open(snd_pcm_t **pcmp, char *name, char *fname, int fd, char *fmt, snd_pcm_t *slave, int close_slave)
{
snd_pcm_t *pcm;
snd_pcm_file_t *file;
- assert(pcmp && slave);
+ assert(pcmp);
if (fname) {
fd = open(fname, O_WRONLY|O_CREAT, 0666);
if (fd < 0) {
@@ -354,8 +353,16 @@ int snd_pcm_file_open(snd_pcm_t **pcmp, char *name, char *fname, int fd, snd_pcm
}
file = calloc(1, sizeof(snd_pcm_file_t));
if (!file) {
+ if (fname)
+ close(fd);
return -ENOMEM;
}
+ if (fmt == NULL ||
+ strcmp(fmt, "raw") == 0)
+ file->format = SND_PCM_FILE_FORMAT_RAW;
+ else
+ ERR("file format %s is unknown", fmt);
+
file->fname = fname;
file->fd = fd;
file->slave = slave;
@@ -393,6 +400,7 @@ int _snd_pcm_file_open(snd_pcm_t **pcmp, char *name,
int err;
snd_pcm_t *spcm;
char *fname = NULL;
+ char *format = NULL;
long fd = -1;
snd_config_foreach(i, conf) {
snd_config_t *n = snd_config_entry(i);
@@ -408,6 +416,12 @@ int _snd_pcm_file_open(snd_pcm_t **pcmp, char *name,
return -EINVAL;
continue;
}
+ if (strcmp(n->id, "format") == 0) {
+ err = snd_config_string_get(n, &format);
+ if (err < 0)
+ return -EINVAL;
+ continue;
+ }
if (strcmp(n->id, "file") == 0) {
err = snd_config_string_get(n, &fname);
if (err < 0) {
@@ -434,7 +448,7 @@ int _snd_pcm_file_open(snd_pcm_t **pcmp, char *name,
free(sname);
if (err < 0)
return err;
- err = snd_pcm_file_open(pcmp, name, fname, fd, spcm, 1);
+ err = snd_pcm_file_open(pcmp, name, fname, fd, format, 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 63eb82bb..f9bf3ba2 100644
--- a/src/pcm/pcm_hw.c
+++ b/src/pcm/pcm_hw.c
@@ -29,17 +29,24 @@
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/shm.h>
+#include <asm/page.h>
#include "pcm_local.h"
+#include "../control/control_local.h"
#ifndef F_SETSIG
#define F_SETSIG 10
#endif
+#ifndef PAGE_ALIGN
+#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK)
+#endif
+
typedef struct {
int fd;
int card, device, subdevice;
volatile snd_pcm_mmap_status_t *mmap_status;
snd_pcm_mmap_control_t *mmap_control;
+ int shmid;
} snd_pcm_hw_t;
#define SND_FILE_PCM_STREAM_PLAYBACK "/dev/snd/pcmC%iD%ip"
@@ -102,7 +109,7 @@ static int snd_pcm_hw_async(snd_pcm_t *pcm, int sig, pid_t pid)
return 0;
}
-static int snd_pcm_hw_info(snd_pcm_t *pcm, snd_pcm_info_t * info)
+static int _snd_pcm_hw_info(snd_pcm_t *pcm, snd_pcm_info_t * info)
{
snd_pcm_hw_t *hw = pcm->private;
int fd = hw->fd;
@@ -113,93 +120,82 @@ static int snd_pcm_hw_info(snd_pcm_t *pcm, snd_pcm_info_t * info)
return 0;
}
-static int snd_pcm_hw_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t * info)
+static int snd_pcm_hw_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t * info)
{
snd_pcm_hw_t *hw = pcm->private;
int fd = hw->fd;
- if (ioctl(fd, SND_PCM_IOCTL_PARAMS_INFO, info) < 0) {
- SYSERR("SND_PCM_IOCTL_PARAMS_INFO failed");
+ if (ioctl(fd, SND_PCM_IOCTL_HW_INFO, info) < 0) {
+ // SYSERR("SND_PCM_IOCTL_HW_INFO failed");
return -errno;
}
return 0;
}
-static int snd_pcm_hw_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
+static int snd_pcm_hw_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
{
snd_pcm_hw_t *hw = pcm->private;
int fd = hw->fd;
- if (ioctl(fd, SND_PCM_IOCTL_PARAMS, params) < 0) {
- SYSERR("SND_PCM_IOCTL_PARAMS failed");
+ if (ioctl(fd, SND_PCM_IOCTL_HW_PARAMS, params) < 0) {
+ SYSERR("SND_PCM_IOCTL_HW_PARAMS failed");
return -errno;
}
return 0;
}
-static int snd_pcm_hw_setup(snd_pcm_t *pcm, snd_pcm_setup_t * setup)
+static int snd_pcm_hw_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params)
{
snd_pcm_hw_t *hw = pcm->private;
int fd = hw->fd;
- if (ioctl(fd, SND_PCM_IOCTL_SETUP, setup) < 0) {
- SYSERR("SND_PCM_IOCTL_SETUP failed");
+ if (ioctl(fd, SND_PCM_IOCTL_SW_PARAMS, params) < 0) {
+ SYSERR("SND_PCM_IOCTL_SW_PARAMS failed");
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;
- }
return 0;
}
-static int snd_pcm_hw_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info)
+static int snd_pcm_hw_dig_info(snd_pcm_t *pcm, snd_pcm_dig_info_t * info)
{
snd_pcm_hw_t *hw = pcm->private;
int fd = hw->fd;
- if (ioctl(fd, SND_PCM_IOCTL_CHANNEL_INFO, info) < 0) {
- SYSERR("SND_PCM_IOCTL_CHANNEL_INFO failed");
+ if (ioctl(fd, SND_PCM_IOCTL_DIG_INFO, info) < 0) {
+ SYSERR("SND_PCM_IOCTL_DIG_INFO failed");
return -errno;
}
return 0;
}
-static int snd_pcm_hw_channel_params(snd_pcm_t *pcm, snd_pcm_channel_params_t * params)
+static int snd_pcm_hw_dig_params(snd_pcm_t *pcm, snd_pcm_dig_params_t * params)
{
snd_pcm_hw_t *hw = pcm->private;
int fd = hw->fd;
- if (ioctl(fd, SND_PCM_IOCTL_CHANNEL_PARAMS, params) < 0) {
- SYSERR("SND_PCM_IOCTL_CHANNEL_PARAMS failed");
+ if (ioctl(fd, SND_PCM_IOCTL_DIG_PARAMS, params) < 0) {
+ SYSERR("SND_PCM_IOCTL_DIG_PARAMS failed");
return -errno;
}
return 0;
}
-static int snd_pcm_hw_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t * setup)
+static int snd_pcm_hw_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info)
{
snd_pcm_hw_t *hw = pcm->private;
+ snd_pcm_hw_channel_info_t hw_info;
int fd = hw->fd;
- if (ioctl(fd, SND_PCM_IOCTL_CHANNEL_SETUP, setup) < 0) {
- SYSERR("SND_PCM_IOCTL_CHANNEL_SETUP failed");
+ hw_info.channel = info->channel;
+ if (ioctl(fd, SND_PCM_IOCTL_CHANNEL_INFO, &hw_info) < 0) {
+ SYSERR("SND_PCM_IOCTL_CHANNEL_INFO failed");
return -errno;
}
- if (!pcm->mmap_info)
+ info->channel = hw_info.channel;
+ if (pcm->info & SND_PCM_INFO_MMAP) {
+ info->addr = 0;
+ info->first = hw_info.first;
+ info->step = hw_info.step;
+ info->type = SND_PCM_AREA_MMAP;
+ info->u.mmap.fd = fd;
+ info->u.mmap.offset = hw_info.offset;
return 0;
- if (pcm->setup.mmap_shape == SND_PCM_MMAP_UNSPECIFIED) {
- if (pcm->setup.xfer_mode == SND_PCM_XFER_INTERLEAVED) {
- setup->running_area.addr = pcm->mmap_info->addr;
- setup->running_area.first = setup->channel * pcm->bits_per_sample;
- setup->running_area.step = pcm->bits_per_frame;
- } else {
- setup->running_area.addr = pcm->mmap_info->addr + setup->channel * pcm->setup.buffer_size * pcm->bits_per_sample / 8;
- setup->running_area.first = 0;
- setup->running_area.step = pcm->bits_per_sample;
- }
- setup->stopped_area = setup->running_area;
- } else {
- setup->running_area.addr = pcm->mmap_info->addr + (long)setup->running_area.addr;
- setup->stopped_area.addr = setup->running_area.addr;
}
- return 0;
+ return snd_pcm_channel_info_shm(pcm, info, hw->shmid);
}
static int snd_pcm_hw_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
@@ -245,6 +241,8 @@ static int snd_pcm_hw_start(snd_pcm_t *pcm)
{
snd_pcm_hw_t *hw = pcm->private;
int fd = hw->fd;
+ assert(pcm->stream != SND_PCM_STREAM_PLAYBACK ||
+ snd_pcm_mmap_playback_hw_avail(pcm) > 0);
if (ioctl(fd, SND_PCM_IOCTL_START) < 0) {
SYSERR("SND_PCM_IOCTL_START failed");
return -errno;
@@ -288,7 +286,7 @@ static int snd_pcm_hw_pause(snd_pcm_t *pcm, int enable)
static ssize_t snd_pcm_hw_rewind(snd_pcm_t *pcm, size_t frames)
{
ssize_t hw_avail;
- if (pcm->setup.xrun_mode == SND_PCM_XRUN_ASAP) {
+ if (pcm->xrun_mode == SND_PCM_XRUN_ASAP) {
ssize_t d;
int err = snd_pcm_hw_delay(pcm, &d);
if (err < 0)
@@ -363,7 +361,7 @@ static int snd_pcm_hw_mmap_status(snd_pcm_t *pcm)
{
snd_pcm_hw_t *hw = pcm->private;
void *ptr;
- ptr = mmap(NULL, sizeof(snd_pcm_mmap_status_t), PROT_READ, MAP_FILE|MAP_SHARED,
+ ptr = mmap(NULL, PAGE_ALIGN(sizeof(snd_pcm_mmap_status_t)), PROT_READ, MAP_FILE|MAP_SHARED,
hw->fd, SND_PCM_MMAP_OFFSET_STATUS);
if (ptr == MAP_FAILED || ptr == NULL) {
SYSERR("status mmap failed");
@@ -378,7 +376,7 @@ static int snd_pcm_hw_mmap_control(snd_pcm_t *pcm)
{
snd_pcm_hw_t *hw = pcm->private;
void *ptr;
- ptr = mmap(NULL, sizeof(snd_pcm_mmap_control_t), PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED,
+ ptr = mmap(NULL, PAGE_ALIGN(sizeof(snd_pcm_mmap_control_t)), PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED,
hw->fd, SND_PCM_MMAP_OFFSET_CONTROL);
if (ptr == MAP_FAILED || ptr == NULL) {
SYSERR("control mmap failed");
@@ -389,31 +387,6 @@ static int snd_pcm_hw_mmap_control(snd_pcm_t *pcm)
return 0;
}
-static int snd_pcm_hw_mmap(snd_pcm_t *pcm)
-{
- snd_pcm_hw_t *hw = pcm->private;
- snd_pcm_mmap_info_t *i = calloc(1, sizeof(*i));
- int err;
- if (!i)
- return -ENOMEM;
- if (pcm->setup.mmap_shape == SND_PCM_MMAP_UNSPECIFIED) {
- err = snd_pcm_alloc_user_mmap(pcm, i);
- if (err < 0) {
- free(i);
- return err;
- }
- } else {
- err = snd_pcm_alloc_kernel_mmap(pcm, i, hw->fd);
- if (err < 0) {
- free(i);
- return err;
- }
- }
- pcm->mmap_info = i;
- pcm->mmap_info_count = 1;
- return 0;
-}
-
static int snd_pcm_hw_munmap_status(snd_pcm_t *pcm)
{
snd_pcm_hw_t *hw = pcm->private;
@@ -434,34 +407,50 @@ static int snd_pcm_hw_munmap_control(snd_pcm_t *pcm)
return 0;
}
+static int snd_pcm_hw_mmap(snd_pcm_t *pcm)
+{
+ snd_pcm_hw_t *hw = pcm->private;
+ if (!(pcm->info & SND_PCM_INFO_MMAP)) {
+ size_t size = snd_pcm_frames_to_bytes(pcm, pcm->buffer_size);
+ int id = shmget(IPC_PRIVATE, size, 0666);
+ if (id < 0) {
+ SYSERR("shmget failed");
+ return -errno;
+ }
+ hw->shmid = id;
+ }
+ return 0;
+}
+
static int snd_pcm_hw_munmap(snd_pcm_t *pcm)
{
- int err = snd_pcm_free_mmap(pcm, pcm->mmap_info);
- if (err < 0)
- return err;
- pcm->mmap_info_count = 0;
- free(pcm->mmap_info);
- pcm->mmap_info = 0;
+ snd_pcm_hw_t *hw = pcm->private;
+ if (!(pcm->info & SND_PCM_INFO_MMAP)) {
+ if (shmctl(hw->shmid, IPC_RMID, 0) < 0) {
+ SYSERR("shmctl IPC_RMID failed");
+ return -errno;
+ }
+ }
return 0;
}
static int snd_pcm_hw_close(snd_pcm_t *pcm)
{
snd_pcm_hw_t *hw = pcm->private;
- int fd = hw->fd;
- free(hw);
- if (close(fd)) {
+ if (close(hw->fd)) {
SYSERR("close failed\n");
return -errno;
}
snd_pcm_hw_munmap_status(pcm);
snd_pcm_hw_munmap_control(pcm);
+ free(hw);
return 0;
}
static ssize_t snd_pcm_hw_mmap_forward(snd_pcm_t *pcm, size_t size)
{
- if (pcm->setup.mmap_shape == SND_PCM_MMAP_UNSPECIFIED && pcm->stream == SND_PCM_STREAM_PLAYBACK)
+ if (!(pcm->info & SND_PCM_INFO_MMAP) &&
+ pcm->stream == SND_PCM_STREAM_PLAYBACK)
return snd_pcm_write_mmap(pcm, size);
snd_pcm_mmap_appl_forward(pcm, size);
return size;
@@ -471,8 +460,8 @@ static ssize_t snd_pcm_hw_avail_update(snd_pcm_t *pcm)
{
size_t avail;
ssize_t err;
- if (pcm->setup.ready_mode == SND_PCM_READY_ASAP ||
- pcm->setup.xrun_mode == SND_PCM_XRUN_ASAP) {
+ if (pcm->ready_mode == SND_PCM_READY_ASAP ||
+ pcm->xrun_mode == SND_PCM_XRUN_ASAP) {
ssize_t d;
int err = snd_pcm_hw_delay(pcm, &d);
if (err < 0)
@@ -482,7 +471,8 @@ static ssize_t snd_pcm_hw_avail_update(snd_pcm_t *pcm)
avail = snd_pcm_mmap_playback_avail(pcm);
} else {
avail = snd_pcm_mmap_capture_avail(pcm);
- if (avail > 0 && pcm->setup.mmap_shape == SND_PCM_MMAP_UNSPECIFIED) {
+ if (avail > 0 &&
+ !(pcm->info & SND_PCM_INFO_MMAP)) {
err = snd_pcm_read_mmap(pcm, avail);
if (err < 0)
return err;
@@ -490,7 +480,7 @@ static ssize_t snd_pcm_hw_avail_update(snd_pcm_t *pcm)
return err;
}
}
- if (avail > pcm->setup.buffer_size)
+ if (avail > pcm->buffer_size)
return -EPIPE;
return avail;
}
@@ -510,7 +500,7 @@ static void snd_pcm_hw_dump(snd_pcm_t *pcm, FILE *fp)
fprintf(fp, "Hardware PCM card %d '%s' device %d subdevice %d\n",
hw->card, name, hw->device, hw->subdevice);
free(name);
- if (pcm->valid_setup) {
+ if (pcm->setup) {
fprintf(fp, "\nIts setup is:\n");
snd_pcm_dump_setup(pcm, fp);
}
@@ -518,13 +508,13 @@ static void snd_pcm_hw_dump(snd_pcm_t *pcm, FILE *fp)
snd_pcm_ops_t snd_pcm_hw_ops = {
close: snd_pcm_hw_close,
- info: snd_pcm_hw_info,
- params_info: snd_pcm_hw_params_info,
- params: snd_pcm_hw_params,
- setup: snd_pcm_hw_setup,
+ info: _snd_pcm_hw_info,
+ hw_info: snd_pcm_hw_hw_info,
+ hw_params: snd_pcm_hw_hw_params,
+ sw_params: snd_pcm_hw_sw_params,
+ dig_info: snd_pcm_hw_dig_info,
+ dig_params: snd_pcm_hw_dig_params,
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,
async: snd_pcm_hw_async,
diff --git a/src/pcm/pcm_linear.c b/src/pcm/pcm_linear.c
index b0cc2393..74ada49c 100644
--- a/src/pcm/pcm_linear.c
+++ b/src/pcm/pcm_linear.c
@@ -28,8 +28,6 @@ typedef struct {
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,
@@ -74,83 +72,65 @@ static void linear_transfer(snd_pcm_channel_area_t *src_areas, size_t src_offset
}
}
-static int snd_pcm_linear_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t * info)
+static int snd_pcm_linear_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t * info)
{
snd_pcm_linear_t *linear = pcm->private;
- unsigned int req_mask = info->req_mask;
- unsigned int sfmt = info->req.format.sfmt;
+ unsigned int format_mask, access_mask;
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;
+ info->access_mask &= (SND_PCM_ACCBIT_MMAP_INTERLEAVED |
+ SND_PCM_ACCBIT_RW_INTERLEAVED |
+ SND_PCM_ACCBIT_MMAP_NONINTERLEAVED |
+ SND_PCM_ACCBIT_RW_NONINTERLEAVED);
+ access_mask = info->access_mask;
+ if (access_mask == 0)
return -EINVAL;
+ info->format_mask &= SND_PCM_FMTBIT_LINEAR;
+ format_mask = info->format_mask;
+ if (format_mask == 0)
+ return -EINVAL;
+
+ info->format_mask = 1U << linear->sformat;
+ info->access_mask = SND_PCM_ACCBIT_MMAP;
+ err = snd_pcm_hw_info(linear->plug.slave, info);
+ if (info->format_mask)
+ info->format_mask = format_mask;
+ if (info->access_mask) {
+ linear->plug.saccess_mask = info->access_mask;
+ info->access_mask = access_mask;
}
- 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;
+ info->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
+ snd_pcm_hw_info_complete(info);
+ return 0;
}
-static int snd_pcm_linear_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
+static int snd_pcm_linear_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{
snd_pcm_linear_t *linear = pcm->private;
snd_pcm_t *slave = linear->plug.slave;
+ unsigned int format, access;
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;
- }
- 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_mmap(slave, params);
- params->format.sfmt = linear->cformat;
- params->xfer_mode = linear->cxfer_mode;
- params->mmap_shape = linear->cmmap_shape;
- 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);
+ format = params->format;
+ access = params->access;
+ params->format = linear->sformat;
+ if (linear->plug.saccess_mask & SND_PCM_ACCBIT_MMAP_INTERLEAVED)
+ params->access = SND_PCM_ACCESS_MMAP_INTERLEAVED;
+ else if (linear->plug.saccess_mask & SND_PCM_ACCBIT_MMAP_NONINTERLEAVED)
+ params->access = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;
+ else
+ assert(0);
+ err = snd_pcm_hw_params(slave, params);
+ params->format = format;
+ params->access = access;
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->conv_idx = conv_index(format,
linear->sformat);
else
linear->conv_idx = conv_index(linear->sformat,
- linear->cformat);
+ format);
return 0;
}
@@ -171,7 +151,7 @@ static ssize_t snd_pcm_linear_write_areas(snd_pcm_t *pcm,
size_t frames = snd_pcm_mmap_playback_xfer(slave, size - xfer);
linear_transfer(areas, offset,
snd_pcm_mmap_areas(slave), snd_pcm_mmap_offset(slave),
- frames, pcm->setup.format.channels, linear->conv_idx);
+ frames, pcm->channels, linear->conv_idx);
err = snd_pcm_mmap_forward(slave, frames);
if (err < 0)
break;
@@ -205,7 +185,7 @@ static ssize_t snd_pcm_linear_read_areas(snd_pcm_t *pcm,
size_t frames = snd_pcm_mmap_capture_xfer(slave, size - xfer);
linear_transfer(snd_pcm_mmap_areas(slave), snd_pcm_mmap_offset(slave),
areas, offset,
- frames, pcm->setup.format.channels, linear->conv_idx);
+ frames, pcm->channels, linear->conv_idx);
err = snd_pcm_mmap_forward(slave, frames);
if (err < 0)
break;
@@ -227,7 +207,7 @@ 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) {
+ if (pcm->setup) {
fprintf(fp, "Its setup is:\n");
snd_pcm_dump_setup(pcm, fp);
}
@@ -238,12 +218,12 @@ static void snd_pcm_linear_dump(snd_pcm_t *pcm, FILE *fp)
snd_pcm_ops_t 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,
+ hw_info: snd_pcm_linear_hw_info,
+ hw_params: snd_pcm_linear_hw_params,
+ sw_params: snd_pcm_plugin_sw_params,
+ dig_info: snd_pcm_plugin_dig_info,
+ dig_params: snd_pcm_plugin_dig_params,
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,
async: snd_pcm_plugin_async,
diff --git a/src/pcm/pcm_local.h b/src/pcm/pcm_local.h
index 8d70ace1..d3b4bb10 100644
--- a/src/pcm/pcm_local.h
+++ b/src/pcm/pcm_local.h
@@ -22,29 +22,48 @@
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
+#include <limits.h>
#include <sys/uio.h>
#include <errno.h>
#include "asoundlib.h"
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)
-#define ERR(...) snd_pcm_error(__FILE__, __LINE__, __FUNCTION__, 0, __VA_ARGS__)
-#define SYSERR(...) snd_pcm_error(__FILE__, __LINE__, __FUNCTION__, errno, __VA_ARGS__)
+#define ERR(...) snd_lib_error(__FILE__, __LINE__, __FUNCTION__, 0, __VA_ARGS__)
+#define SYSERR(...) snd_lib_error(__FILE__, __LINE__, __FUNCTION__, errno, __VA_ARGS__)
#else
-#define ERR(args...) snd_pcm_error(__FILE__, __LINE__, __FUNCTION__, 0, ##args)
-#define SYSERR(args...) snd_pcm_error(__FILE__, __LINE__, __FUNCTION__, errno, ##args)
+#define ERR(args...) snd_lib_error(__FILE__, __LINE__, __FUNCTION__, 0, ##args)
+#define SYSERR(args...) snd_lib_error(__FILE__, __LINE__, __FUNCTION__, errno, ##args)
#endif
+typedef struct _snd_pcm_channel_info {
+ unsigned int channel;
+ void *addr; /* base address of channel samples */
+ unsigned int first; /* offset to first sample in bits */
+ unsigned int step; /* samples distance in bits */
+ enum { SND_PCM_AREA_SHM, SND_PCM_AREA_MMAP } type;
+ union {
+ struct {
+ int shmid;
+ } shm;
+ struct {
+ int fd;
+ off_t offset;
+ } mmap;
+ } u;
+ char reserved[64];
+} snd_pcm_channel_info_t;
+
typedef struct {
int (*close)(snd_pcm_t *pcm);
int (*nonblock)(snd_pcm_t *pcm, int nonblock);
int (*async)(snd_pcm_t *pcm, int sig, pid_t pid);
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 (*hw_info)(snd_pcm_t *pcm, snd_pcm_hw_info_t *info);
+ int (*hw_params)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params);
+ int (*sw_params)(snd_pcm_t *pcm, snd_pcm_sw_params_t *params);
+ int (*dig_info)(snd_pcm_t *pcm, snd_pcm_dig_info_t *info);
+ int (*dig_params)(snd_pcm_t *pcm, snd_pcm_dig_params_t *params);
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)(snd_pcm_t *pcm);
int (*munmap)(snd_pcm_t *pcm);
@@ -69,38 +88,43 @@ typedef struct {
int (*set_avail_min)(snd_pcm_t *pcm, size_t frames);
} snd_pcm_fast_ops_t;
-typedef struct {
- unsigned int index;
- enum { SND_PCM_MMAP_KERNEL, SND_PCM_MMAP_USER } type;
- void *addr;
- size_t size;
- union {
- struct {
- int shmid;
- } user;
- struct {
- int fd;
- } kernel;
- } u;
-} snd_pcm_mmap_info_t;
-
-struct snd_pcm {
+struct _snd_pcm {
char *name;
snd_pcm_type_t type;
int stream;
int mode;
int poll_fd;
- int valid_setup;
- snd_pcm_setup_t setup;
+ int setup;
+ unsigned int access; /* access mode */
+ unsigned int format; /* SND_PCM_FORMAT_* */
+ unsigned int subformat; /* subformat */
+ unsigned int rate; /* rate in Hz */
+ unsigned int channels; /* channels */
+ size_t fragment_size; /* fragment size */
+ unsigned int fragments; /* fragments */
+ unsigned int start_mode; /* start mode */
+ unsigned int ready_mode; /* ready detection mode */
+ unsigned int xrun_mode; /* xrun detection mode */
+ size_t avail_min; /* min avail frames for wakeup */
+ size_t xfer_min; /* xfer min size */
+ size_t xfer_align; /* xfer size need to be a multiple */
+ unsigned int time: 1; /* timestamp switch */
+ size_t boundary; /* pointers wrap point */
+ unsigned int info; /* Info for returned setup */
+ unsigned int msbits; /* used most significant bits */
+ unsigned int rate_master; /* Exact rate is rate_master / */
+ unsigned int rate_divisor; /* rate_divisor */
+ size_t fifo_size; /* chip FIFO size in frames */
+ size_t buffer_size;
size_t bits_per_sample;
size_t bits_per_frame;
size_t *appl_ptr;
volatile size_t *hw_ptr;
- int mmap_auto;
- size_t mmap_info_count;
- snd_pcm_mmap_info_t *mmap_info;
+ int mmap_rw;
+ snd_pcm_channel_info_t *mmap_channels;
snd_pcm_channel_area_t *running_areas;
snd_pcm_channel_area_t *stopped_areas;
+ void *stopped;
snd_pcm_ops_t *ops;
snd_pcm_fast_ops_t *fast_ops;
snd_pcm_t *op_arg;
@@ -108,10 +132,18 @@ struct snd_pcm {
void *private;
};
+int snd_pcm_hw_open(snd_pcm_t **pcm, char *name, int card, int device, int subdevice, int stream, int mode);
+int snd_pcm_plug_open_hw(snd_pcm_t **pcm, char *name, int card, int device, int subdevice, int stream, int mode);
+int snd_pcm_shm_open(snd_pcm_t **pcmp, char *name, char *socket, char *sname, int stream, int mode);
+int snd_pcm_file_open(snd_pcm_t **pcmp, char *name, char *fname, int fd, char *fmt, snd_pcm_t *slave, int close_slave);
+int snd_pcm_null_open(snd_pcm_t **pcmp, char *name, int stream, int mode);
+
+
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);
-int snd_pcm_params_mmap(snd_pcm_t *pcm, snd_pcm_params_t *params);
+int snd_pcm_mmap(snd_pcm_t *pcm);
+int snd_pcm_munmap(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_backward(snd_pcm_t *pcm, size_t frames);
@@ -135,16 +167,19 @@ ssize_t snd_pcm_write_areas(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas,
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);
-int snd_pcm_alloc_user_mmap(snd_pcm_t *pcm, snd_pcm_mmap_info_t *i);
-int snd_pcm_alloc_kernel_mmap(snd_pcm_t *pcm, snd_pcm_mmap_info_t *i, int fd);
-int snd_pcm_free_mmap(snd_pcm_t *pcm, snd_pcm_mmap_info_t *i);
+int snd_pcm_hw_info_complete(snd_pcm_hw_info_t *info);
+void snd_pcm_hw_params_to_info(snd_pcm_hw_params_t *params, snd_pcm_hw_info_t *info);
+void snd_pcm_hw_info_to_params(snd_pcm_hw_info_t *info, snd_pcm_hw_params_t *params);
+void snd_pcm_hw_info_to_params_fail(snd_pcm_hw_info_t *info, snd_pcm_hw_params_t *params);
+int snd_pcm_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info);
+int snd_pcm_channel_info_shm(snd_pcm_t *pcm, snd_pcm_channel_info_t *info, int shmid);
static inline size_t snd_pcm_mmap_playback_avail(snd_pcm_t *pcm)
{
ssize_t avail;
- avail = *pcm->hw_ptr + pcm->setup.buffer_size - *pcm->appl_ptr;
+ avail = *pcm->hw_ptr + pcm->buffer_size - *pcm->appl_ptr;
if (avail < 0)
- avail += pcm->setup.boundary;
+ avail += pcm->boundary;
return avail;
}
@@ -153,7 +188,7 @@ static inline size_t snd_pcm_mmap_capture_avail(snd_pcm_t *pcm)
ssize_t avail;
avail = *pcm->hw_ptr - *pcm->appl_ptr;
if (avail < 0)
- avail += pcm->setup.boundary;
+ avail += pcm->boundary;
return avail;
}
@@ -162,19 +197,19 @@ static inline size_t snd_pcm_mmap_avail(snd_pcm_t *pcm)
ssize_t avail;
avail = *pcm->hw_ptr - *pcm->appl_ptr;
if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
- avail += pcm->setup.buffer_size;
+ avail += pcm->buffer_size;
if (avail < 0)
- avail += pcm->setup.boundary;
+ avail += pcm->boundary;
return avail;
}
static inline ssize_t snd_pcm_mmap_playback_hw_avail(snd_pcm_t *pcm)
{
ssize_t avail;
- avail = *pcm->hw_ptr + pcm->setup.buffer_size - *pcm->appl_ptr;
+ avail = *pcm->hw_ptr + pcm->buffer_size - *pcm->appl_ptr;
if (avail < 0)
- avail += pcm->setup.boundary;
- return pcm->setup.buffer_size - avail;
+ avail += pcm->boundary;
+ return pcm->buffer_size - avail;
}
static inline ssize_t snd_pcm_mmap_capture_hw_avail(snd_pcm_t *pcm)
@@ -182,8 +217,8 @@ static inline ssize_t snd_pcm_mmap_capture_hw_avail(snd_pcm_t *pcm)
ssize_t avail;
avail = *pcm->hw_ptr - *pcm->appl_ptr;
if (avail < 0)
- avail += pcm->setup.boundary;
- return pcm->setup.buffer_size - avail;
+ avail += pcm->boundary;
+ return pcm->buffer_size - avail;
}
static inline ssize_t snd_pcm_mmap_hw_avail(snd_pcm_t *pcm)
@@ -191,10 +226,10 @@ static inline ssize_t snd_pcm_mmap_hw_avail(snd_pcm_t *pcm)
ssize_t avail;
avail = *pcm->hw_ptr - *pcm->appl_ptr;
if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
- avail += pcm->setup.buffer_size;
+ avail += pcm->buffer_size;
if (avail < 0)
- avail += pcm->setup.boundary;
- return pcm->setup.buffer_size - avail;
+ avail += pcm->boundary;
+ return pcm->buffer_size - avail;
}
#define snd_pcm_mmap_playback_delay snd_pcm_mmap_playback_hw_avail
diff --git a/src/pcm/pcm_misc.c b/src/pcm/pcm_misc.c
index 57bfcf21..a6790215 100644
--- a/src/pcm/pcm_misc.c
+++ b/src/pcm/pcm_misc.c
@@ -39,21 +39,21 @@
int snd_pcm_format_signed(int format)
{
switch (format) {
- case SND_PCM_SFMT_S8:
- case SND_PCM_SFMT_S16_LE:
- case SND_PCM_SFMT_S16_BE:
- case SND_PCM_SFMT_S24_LE:
- case SND_PCM_SFMT_S24_BE:
- case SND_PCM_SFMT_S32_LE:
- case SND_PCM_SFMT_S32_BE:
+ case SND_PCM_FORMAT_S8:
+ case SND_PCM_FORMAT_S16_LE:
+ case SND_PCM_FORMAT_S16_BE:
+ case SND_PCM_FORMAT_S24_LE:
+ case SND_PCM_FORMAT_S24_BE:
+ case SND_PCM_FORMAT_S32_LE:
+ case SND_PCM_FORMAT_S32_BE:
return 1;
- case SND_PCM_SFMT_U8:
- case SND_PCM_SFMT_U16_LE:
- case SND_PCM_SFMT_U16_BE:
- case SND_PCM_SFMT_U24_LE:
- case SND_PCM_SFMT_U24_BE:
- case SND_PCM_SFMT_U32_LE:
- case SND_PCM_SFMT_U32_BE:
+ case SND_PCM_FORMAT_U8:
+ case SND_PCM_FORMAT_U16_LE:
+ case SND_PCM_FORMAT_U16_BE:
+ case SND_PCM_FORMAT_U24_LE:
+ case SND_PCM_FORMAT_U24_BE:
+ case SND_PCM_FORMAT_U32_LE:
+ case SND_PCM_FORMAT_U32_BE:
return 0;
default:
return -EINVAL;
@@ -78,25 +78,25 @@ int snd_pcm_format_linear(int format)
int snd_pcm_format_little_endian(int format)
{
switch (format) {
- case SND_PCM_SFMT_S16_LE:
- case SND_PCM_SFMT_U16_LE:
- case SND_PCM_SFMT_S24_LE:
- case SND_PCM_SFMT_U24_LE:
- case SND_PCM_SFMT_S32_LE:
- case SND_PCM_SFMT_U32_LE:
- case SND_PCM_SFMT_FLOAT_LE:
- case SND_PCM_SFMT_FLOAT64_LE:
- case SND_PCM_SFMT_IEC958_SUBFRAME_LE:
+ case SND_PCM_FORMAT_S16_LE:
+ case SND_PCM_FORMAT_U16_LE:
+ case SND_PCM_FORMAT_S24_LE:
+ case SND_PCM_FORMAT_U24_LE:
+ case SND_PCM_FORMAT_S32_LE:
+ case SND_PCM_FORMAT_U32_LE:
+ case SND_PCM_FORMAT_FLOAT_LE:
+ case SND_PCM_FORMAT_FLOAT64_LE:
+ case SND_PCM_FORMAT_IEC958_SUBFRAME_LE:
return 1;
- case SND_PCM_SFMT_S16_BE:
- case SND_PCM_SFMT_U16_BE:
- case SND_PCM_SFMT_S24_BE:
- case SND_PCM_SFMT_U24_BE:
- case SND_PCM_SFMT_S32_BE:
- case SND_PCM_SFMT_U32_BE:
- case SND_PCM_SFMT_FLOAT_BE:
- case SND_PCM_SFMT_FLOAT64_BE:
- case SND_PCM_SFMT_IEC958_SUBFRAME_BE:
+ case SND_PCM_FORMAT_S16_BE:
+ case SND_PCM_FORMAT_U16_BE:
+ case SND_PCM_FORMAT_S24_BE:
+ case SND_PCM_FORMAT_U24_BE:
+ case SND_PCM_FORMAT_S32_BE:
+ case SND_PCM_FORMAT_U32_BE:
+ case SND_PCM_FORMAT_FLOAT_BE:
+ case SND_PCM_FORMAT_FLOAT64_BE:
+ case SND_PCM_FORMAT_IEC958_SUBFRAME_BE:
return 0;
default:
return -EINVAL;
@@ -116,36 +116,36 @@ int snd_pcm_format_big_endian(int format)
int snd_pcm_format_width(int format)
{
switch (format) {
- case SND_PCM_SFMT_S8:
- case SND_PCM_SFMT_U8:
+ case SND_PCM_FORMAT_S8:
+ case SND_PCM_FORMAT_U8:
return 8;
- case SND_PCM_SFMT_S16_LE:
- case SND_PCM_SFMT_S16_BE:
- case SND_PCM_SFMT_U16_LE:
- case SND_PCM_SFMT_U16_BE:
+ case SND_PCM_FORMAT_S16_LE:
+ case SND_PCM_FORMAT_S16_BE:
+ case SND_PCM_FORMAT_U16_LE:
+ case SND_PCM_FORMAT_U16_BE:
return 16;
- case SND_PCM_SFMT_S24_LE:
- case SND_PCM_SFMT_S24_BE:
- case SND_PCM_SFMT_U24_LE:
- case SND_PCM_SFMT_U24_BE:
+ case SND_PCM_FORMAT_S24_LE:
+ case SND_PCM_FORMAT_S24_BE:
+ case SND_PCM_FORMAT_U24_LE:
+ case SND_PCM_FORMAT_U24_BE:
return 24;
- case SND_PCM_SFMT_S32_LE:
- case SND_PCM_SFMT_S32_BE:
- case SND_PCM_SFMT_U32_LE:
- case SND_PCM_SFMT_U32_BE:
- case SND_PCM_SFMT_FLOAT_LE:
- case SND_PCM_SFMT_FLOAT_BE:
+ case SND_PCM_FORMAT_S32_LE:
+ case SND_PCM_FORMAT_S32_BE:
+ case SND_PCM_FORMAT_U32_LE:
+ case SND_PCM_FORMAT_U32_BE:
+ case SND_PCM_FORMAT_FLOAT_LE:
+ case SND_PCM_FORMAT_FLOAT_BE:
return 32;
- case SND_PCM_SFMT_FLOAT64_LE:
- case SND_PCM_SFMT_FLOAT64_BE:
+ case SND_PCM_FORMAT_FLOAT64_LE:
+ case SND_PCM_FORMAT_FLOAT64_BE:
return 64;
- case SND_PCM_SFMT_IEC958_SUBFRAME_LE:
- case SND_PCM_SFMT_IEC958_SUBFRAME_BE:
+ case SND_PCM_FORMAT_IEC958_SUBFRAME_LE:
+ case SND_PCM_FORMAT_IEC958_SUBFRAME_BE:
return 24;
- case SND_PCM_SFMT_MU_LAW:
- case SND_PCM_SFMT_A_LAW:
+ case SND_PCM_FORMAT_MU_LAW:
+ case SND_PCM_FORMAT_A_LAW:
return 8;
- case SND_PCM_SFMT_IMA_ADPCM:
+ case SND_PCM_FORMAT_IMA_ADPCM:
return 4;
default:
return -EINVAL;
@@ -155,34 +155,34 @@ int snd_pcm_format_width(int format)
int snd_pcm_format_physical_width(int format)
{
switch (format) {
- case SND_PCM_SFMT_S8:
- case SND_PCM_SFMT_U8:
+ case SND_PCM_FORMAT_S8:
+ case SND_PCM_FORMAT_U8:
return 8;
- case SND_PCM_SFMT_S16_LE:
- case SND_PCM_SFMT_S16_BE:
- case SND_PCM_SFMT_U16_LE:
- case SND_PCM_SFMT_U16_BE:
+ case SND_PCM_FORMAT_S16_LE:
+ case SND_PCM_FORMAT_S16_BE:
+ case SND_PCM_FORMAT_U16_LE:
+ case SND_PCM_FORMAT_U16_BE:
return 16;
- case SND_PCM_SFMT_S24_LE:
- case SND_PCM_SFMT_S24_BE:
- case SND_PCM_SFMT_U24_LE:
- case SND_PCM_SFMT_U24_BE:
- case SND_PCM_SFMT_S32_LE:
- case SND_PCM_SFMT_S32_BE:
- case SND_PCM_SFMT_U32_LE:
- case SND_PCM_SFMT_U32_BE:
- case SND_PCM_SFMT_FLOAT_LE:
- case SND_PCM_SFMT_FLOAT_BE:
- case SND_PCM_SFMT_IEC958_SUBFRAME_LE:
- case SND_PCM_SFMT_IEC958_SUBFRAME_BE:
+ case SND_PCM_FORMAT_S24_LE:
+ case SND_PCM_FORMAT_S24_BE:
+ case SND_PCM_FORMAT_U24_LE:
+ case SND_PCM_FORMAT_U24_BE:
+ case SND_PCM_FORMAT_S32_LE:
+ case SND_PCM_FORMAT_S32_BE:
+ case SND_PCM_FORMAT_U32_LE:
+ case SND_PCM_FORMAT_U32_BE:
+ case SND_PCM_FORMAT_FLOAT_LE:
+ case SND_PCM_FORMAT_FLOAT_BE:
+ case SND_PCM_FORMAT_IEC958_SUBFRAME_LE:
+ case SND_PCM_FORMAT_IEC958_SUBFRAME_BE:
return 32;
- case SND_PCM_SFMT_FLOAT64_LE:
- case SND_PCM_SFMT_FLOAT64_BE:
+ case SND_PCM_FORMAT_FLOAT64_LE:
+ case SND_PCM_FORMAT_FLOAT64_BE:
return 64;
- case SND_PCM_SFMT_MU_LAW:
- case SND_PCM_SFMT_A_LAW:
+ case SND_PCM_FORMAT_MU_LAW:
+ case SND_PCM_FORMAT_A_LAW:
return 8;
- case SND_PCM_SFMT_IMA_ADPCM:
+ case SND_PCM_FORMAT_IMA_ADPCM:
return 4;
default:
return -EINVAL;
@@ -192,35 +192,35 @@ int snd_pcm_format_physical_width(int format)
ssize_t snd_pcm_format_size(int format, size_t samples)
{
switch (format) {
- case SND_PCM_SFMT_S8:
- case SND_PCM_SFMT_U8:
+ case SND_PCM_FORMAT_S8:
+ case SND_PCM_FORMAT_U8:
return samples;
- case SND_PCM_SFMT_S16_LE:
- case SND_PCM_SFMT_S16_BE:
- case SND_PCM_SFMT_U16_LE:
- case SND_PCM_SFMT_U16_BE:
+ case SND_PCM_FORMAT_S16_LE:
+ case SND_PCM_FORMAT_S16_BE:
+ case SND_PCM_FORMAT_U16_LE:
+ case SND_PCM_FORMAT_U16_BE:
return samples * 2;
- case SND_PCM_SFMT_S24_LE:
- case SND_PCM_SFMT_S24_BE:
- case SND_PCM_SFMT_U24_LE:
- case SND_PCM_SFMT_U24_BE:
- case SND_PCM_SFMT_S32_LE:
- case SND_PCM_SFMT_S32_BE:
- case SND_PCM_SFMT_U32_LE:
- case SND_PCM_SFMT_U32_BE:
- case SND_PCM_SFMT_FLOAT_LE:
- case SND_PCM_SFMT_FLOAT_BE:
+ case SND_PCM_FORMAT_S24_LE:
+ case SND_PCM_FORMAT_S24_BE:
+ case SND_PCM_FORMAT_U24_LE:
+ case SND_PCM_FORMAT_U24_BE:
+ case SND_PCM_FORMAT_S32_LE:
+ case SND_PCM_FORMAT_S32_BE:
+ case SND_PCM_FORMAT_U32_LE:
+ case SND_PCM_FORMAT_U32_BE:
+ case SND_PCM_FORMAT_FLOAT_LE:
+ case SND_PCM_FORMAT_FLOAT_BE:
return samples * 4;
- case SND_PCM_SFMT_FLOAT64_LE:
- case SND_PCM_SFMT_FLOAT64_BE:
+ case SND_PCM_FORMAT_FLOAT64_LE:
+ case SND_PCM_FORMAT_FLOAT64_BE:
return samples * 8;
- case SND_PCM_SFMT_IEC958_SUBFRAME_LE:
- case SND_PCM_SFMT_IEC958_SUBFRAME_BE:
+ case SND_PCM_FORMAT_IEC958_SUBFRAME_LE:
+ case SND_PCM_FORMAT_IEC958_SUBFRAME_BE:
return samples * 4;
- case SND_PCM_SFMT_MU_LAW:
- case SND_PCM_SFMT_A_LAW:
+ case SND_PCM_FORMAT_MU_LAW:
+ case SND_PCM_FORMAT_A_LAW:
return samples;
- case SND_PCM_SFMT_IMA_ADPCM:
+ case SND_PCM_FORMAT_IMA_ADPCM:
if (samples & 1)
return -EINVAL;
return samples / 2;
@@ -232,44 +232,44 @@ ssize_t snd_pcm_format_size(int format, size_t samples)
u_int64_t snd_pcm_format_silence_64(int format)
{
switch (format) {
- case SND_PCM_SFMT_S8:
- case SND_PCM_SFMT_S16_LE:
- case SND_PCM_SFMT_S16_BE:
- case SND_PCM_SFMT_S24_LE:
- case SND_PCM_SFMT_S24_BE:
- case SND_PCM_SFMT_S32_LE:
- case SND_PCM_SFMT_S32_BE:
+ case SND_PCM_FORMAT_S8:
+ case SND_PCM_FORMAT_S16_LE:
+ case SND_PCM_FORMAT_S16_BE:
+ case SND_PCM_FORMAT_S24_LE:
+ case SND_PCM_FORMAT_S24_BE:
+ case SND_PCM_FORMAT_S32_LE:
+ case SND_PCM_FORMAT_S32_BE:
return 0;
- case SND_PCM_SFMT_U8:
+ case SND_PCM_FORMAT_U8:
return 0x8080808080808080ULL;
#ifdef SND_LITTLE_ENDIAN
- case SND_PCM_SFMT_U16_LE:
+ case SND_PCM_FORMAT_U16_LE:
return 0x8000800080008000ULL;
- case SND_PCM_SFMT_U24_LE:
+ case SND_PCM_FORMAT_U24_LE:
return 0x0080000000800000ULL;
- case SND_PCM_SFMT_U32_LE:
+ case SND_PCM_FORMAT_U32_LE:
return 0x8000000080000000ULL;
- case SND_PCM_SFMT_U16_BE:
+ case SND_PCM_FORMAT_U16_BE:
return 0x0080008000800080ULL;
- case SND_PCM_SFMT_U24_BE:
+ case SND_PCM_FORMAT_U24_BE:
return 0x0000800000008000ULL;
- case SND_PCM_SFMT_U32_BE:
+ case SND_PCM_FORMAT_U32_BE:
return 0x0000008000000080ULL;
#else
- case SND_PCM_SFMT_U16_LE:
+ case SND_PCM_FORMAT_U16_LE:
return 0x0080008000800080ULL;
- case SND_PCM_SFMT_U24_LE:
+ case SND_PCM_FORMAT_U24_LE:
return 0x0000800000008000ULL;
- case SND_PCM_SFMT_U32_LE:
+ case SND_PCM_FORMAT_U32_LE:
return 0x0000008000000080ULL;
- case SND_PCM_SFMT_U16_BE:
+ case SND_PCM_FORMAT_U16_BE:
return 0x8000800080008000ULL;
- case SND_PCM_SFMT_U24_BE:
+ case SND_PCM_FORMAT_U24_BE:
return 0x0080000000800000ULL;
- case SND_PCM_SFMT_U32_BE:
+ case SND_PCM_FORMAT_U32_BE:
return 0x8000000080000000ULL;
#endif
- case SND_PCM_SFMT_FLOAT_LE:
+ case SND_PCM_FORMAT_FLOAT_LE:
{
union {
float f;
@@ -282,7 +282,7 @@ u_int64_t snd_pcm_format_silence_64(int format)
return bswap_32(u.i);
#endif
}
- case SND_PCM_SFMT_FLOAT64_LE:
+ case SND_PCM_FORMAT_FLOAT64_LE:
{
union {
double f;
@@ -295,7 +295,7 @@ u_int64_t snd_pcm_format_silence_64(int format)
return bswap_64(u.i);
#endif
}
- case SND_PCM_SFMT_FLOAT_BE:
+ case SND_PCM_FORMAT_FLOAT_BE:
{
union {
float f;
@@ -308,7 +308,7 @@ u_int64_t snd_pcm_format_silence_64(int format)
return u.i;
#endif
}
- case SND_PCM_SFMT_FLOAT64_BE:
+ case SND_PCM_FORMAT_FLOAT64_BE:
{
union {
double f;
@@ -321,16 +321,16 @@ u_int64_t snd_pcm_format_silence_64(int format)
return u.i;
#endif
}
- case SND_PCM_SFMT_IEC958_SUBFRAME_LE:
- case SND_PCM_SFMT_IEC958_SUBFRAME_BE:
+ case SND_PCM_FORMAT_IEC958_SUBFRAME_LE:
+ case SND_PCM_FORMAT_IEC958_SUBFRAME_BE:
return 0;
- case SND_PCM_SFMT_MU_LAW:
+ case SND_PCM_FORMAT_MU_LAW:
return 0x7f7f7f7f7f7f7f7fULL;
- case SND_PCM_SFMT_A_LAW:
+ case SND_PCM_FORMAT_A_LAW:
return 0x5555555555555555ULL;
- case SND_PCM_SFMT_IMA_ADPCM: /* special case */
- case SND_PCM_SFMT_MPEG:
- case SND_PCM_SFMT_GSM:
+ case SND_PCM_FORMAT_IMA_ADPCM: /* special case */
+ case SND_PCM_FORMAT_MPEG:
+ case SND_PCM_FORMAT_GSM:
return 0;
}
return 0;
@@ -395,22 +395,22 @@ ssize_t snd_pcm_format_set_silence(int format, void *data, size_t samples)
}
static int linear_formats[4*2*2] = {
- SND_PCM_SFMT_S8,
- SND_PCM_SFMT_U8,
- SND_PCM_SFMT_S8,
- SND_PCM_SFMT_U8,
- 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_FORMAT_S8,
+ SND_PCM_FORMAT_U8,
+ SND_PCM_FORMAT_S8,
+ SND_PCM_FORMAT_U8,
+ SND_PCM_FORMAT_S16_LE,
+ SND_PCM_FORMAT_S16_BE,
+ SND_PCM_FORMAT_U16_LE,
+ SND_PCM_FORMAT_U16_BE,
+ SND_PCM_FORMAT_S24_LE,
+ SND_PCM_FORMAT_S24_BE,
+ SND_PCM_FORMAT_U24_LE,
+ SND_PCM_FORMAT_U24_BE,
+ SND_PCM_FORMAT_S32_LE,
+ SND_PCM_FORMAT_S32_BE,
+ SND_PCM_FORMAT_U32_LE,
+ SND_PCM_FORMAT_U32_BE
};
int snd_pcm_build_linear_format(int width, int unsignd, int big_endian)
diff --git a/src/pcm/pcm_mmap.c b/src/pcm/pcm_mmap.c
index 4eb51d4f..1a754c72 100644
--- a/src/pcm/pcm_mmap.c
+++ b/src/pcm/pcm_mmap.c
@@ -23,15 +23,23 @@
#include <string.h>
#include <errno.h>
#include <sys/poll.h>
+#include <sys/mman.h>
+#include <sys/shm.h>
+#include <asm/page.h>
#include "pcm_local.h"
+
+#ifndef PAGE_ALIGN
+#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK)
+#endif
+
+
snd_pcm_channel_area_t *snd_pcm_mmap_areas(snd_pcm_t *pcm)
{
- int state = snd_pcm_state(pcm);
- if (state == SND_PCM_STATE_RUNNING)
- return pcm->running_areas;
- else
- return pcm->stopped_areas;
+ if (pcm->stopped_areas &&
+ snd_pcm_state(pcm) != SND_PCM_STATE_RUNNING)
+ return pcm->stopped_areas;
+ return pcm->running_areas;
}
size_t snd_pcm_mmap_playback_xfer(snd_pcm_t *pcm, size_t frames)
@@ -40,7 +48,7 @@ size_t snd_pcm_mmap_playback_xfer(snd_pcm_t *pcm, size_t frames)
size_t avail = snd_pcm_mmap_playback_avail(pcm);
if (avail < frames)
frames = avail;
- cont = pcm->setup.buffer_size - *pcm->appl_ptr % pcm->setup.buffer_size;
+ cont = pcm->buffer_size - *pcm->appl_ptr % pcm->buffer_size;
if (cont < frames)
frames = cont;
return frames;
@@ -52,7 +60,7 @@ size_t snd_pcm_mmap_capture_xfer(snd_pcm_t *pcm, size_t frames)
size_t avail = snd_pcm_mmap_capture_avail(pcm);
if (avail < frames)
frames = avail;
- cont = pcm->setup.buffer_size - *pcm->appl_ptr % pcm->setup.buffer_size;
+ cont = pcm->buffer_size - *pcm->appl_ptr % pcm->buffer_size;
if (cont < frames)
frames = cont;
return frames;
@@ -70,13 +78,13 @@ size_t snd_pcm_mmap_xfer(snd_pcm_t *pcm, size_t frames)
size_t snd_pcm_mmap_offset(snd_pcm_t *pcm)
{
assert(pcm);
- return *pcm->appl_ptr % pcm->setup.buffer_size;
+ return *pcm->appl_ptr % pcm->buffer_size;
}
size_t snd_pcm_mmap_hw_offset(snd_pcm_t *pcm)
{
assert(pcm);
- return *pcm->hw_ptr % pcm->setup.buffer_size;
+ return *pcm->hw_ptr % pcm->buffer_size;
}
void snd_pcm_mmap_appl_backward(snd_pcm_t *pcm, size_t frames)
@@ -84,7 +92,7 @@ void snd_pcm_mmap_appl_backward(snd_pcm_t *pcm, size_t frames)
ssize_t appl_ptr = *pcm->appl_ptr;
appl_ptr -= frames;
if (appl_ptr < 0)
- appl_ptr += pcm->setup.boundary;
+ appl_ptr += pcm->boundary;
*pcm->appl_ptr = appl_ptr;
}
@@ -92,8 +100,8 @@ void snd_pcm_mmap_appl_forward(snd_pcm_t *pcm, size_t frames)
{
size_t appl_ptr = *pcm->appl_ptr;
appl_ptr += frames;
- if (appl_ptr >= pcm->setup.boundary)
- appl_ptr -= pcm->setup.boundary;
+ if (appl_ptr >= pcm->boundary)
+ appl_ptr -= pcm->boundary;
*pcm->appl_ptr = appl_ptr;
}
@@ -102,7 +110,7 @@ void snd_pcm_mmap_hw_backward(snd_pcm_t *pcm, size_t frames)
ssize_t hw_ptr = *pcm->hw_ptr;
hw_ptr -= frames;
if (hw_ptr < 0)
- hw_ptr += pcm->setup.boundary;
+ hw_ptr += pcm->boundary;
*pcm->hw_ptr = hw_ptr;
}
@@ -110,8 +118,8 @@ void snd_pcm_mmap_hw_forward(snd_pcm_t *pcm, size_t frames)
{
size_t hw_ptr = *pcm->hw_ptr;
hw_ptr += frames;
- if (hw_ptr >= pcm->setup.boundary)
- hw_ptr -= pcm->setup.boundary;
+ if (hw_ptr >= pcm->boundary)
+ hw_ptr -= pcm->boundary;
*pcm->hw_ptr = hw_ptr;
}
@@ -127,11 +135,13 @@ ssize_t snd_pcm_mmap_write_areas(snd_pcm_t *pcm,
xfer = 0;
while (xfer < size) {
size_t frames = snd_pcm_mmap_playback_xfer(pcm, size - xfer);
+ ssize_t err;
snd_pcm_areas_copy(areas, offset,
snd_pcm_mmap_areas(pcm), snd_pcm_mmap_offset(pcm),
- pcm->setup.format.channels,
- frames, pcm->setup.format.sfmt);
- snd_pcm_mmap_forward(pcm, frames);
+ pcm->channels,
+ frames, pcm->format);
+ err = snd_pcm_mmap_forward(pcm, frames);
+ assert(err == (ssize_t)frames);
offset += frames;
xfer += frames;
}
@@ -152,11 +162,13 @@ ssize_t snd_pcm_mmap_read_areas(snd_pcm_t *pcm,
xfer = 0;
while (xfer < size) {
size_t frames = snd_pcm_mmap_capture_xfer(pcm, size - xfer);
+ ssize_t err;
snd_pcm_areas_copy(snd_pcm_mmap_areas(pcm), snd_pcm_mmap_offset(pcm),
areas, offset,
- pcm->setup.format.channels,
- frames, pcm->setup.format.sfmt);
- snd_pcm_mmap_forward(pcm, frames);
+ pcm->channels,
+ frames, pcm->format);
+ err = snd_pcm_mmap_forward(pcm, frames);
+ assert(err == (ssize_t)frames);
offset += frames;
xfer += frames;
}
@@ -167,7 +179,7 @@ ssize_t snd_pcm_mmap_read_areas(snd_pcm_t *pcm,
ssize_t snd_pcm_mmap_writei(snd_pcm_t *pcm, const void *buffer, size_t size)
{
- snd_pcm_channel_area_t areas[pcm->setup.format.channels];
+ snd_pcm_channel_area_t areas[pcm->channels];
snd_pcm_areas_from_buf(pcm, areas, (void*)buffer);
return snd_pcm_write_areas(pcm, areas, 0, size,
snd_pcm_mmap_write_areas);
@@ -175,7 +187,7 @@ ssize_t snd_pcm_mmap_writei(snd_pcm_t *pcm, const void *buffer, size_t size)
ssize_t snd_pcm_mmap_writen(snd_pcm_t *pcm, void **bufs, size_t size)
{
- snd_pcm_channel_area_t areas[pcm->setup.format.channels];
+ snd_pcm_channel_area_t areas[pcm->channels];
snd_pcm_areas_from_bufs(pcm, areas, bufs);
return snd_pcm_write_areas(pcm, areas, 0, size,
snd_pcm_mmap_write_areas);
@@ -183,7 +195,7 @@ ssize_t snd_pcm_mmap_writen(snd_pcm_t *pcm, void **bufs, size_t size)
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_channel_area_t areas[pcm->channels];
snd_pcm_areas_from_buf(pcm, areas, buffer);
return snd_pcm_read_areas(pcm, areas, 0, size,
snd_pcm_mmap_read_areas);
@@ -191,71 +203,204 @@ ssize_t snd_pcm_mmap_readi(snd_pcm_t *pcm, void *buffer, size_t size)
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_channel_area_t areas[pcm->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_get_areas(snd_pcm_t *pcm, snd_pcm_channel_area_t *stopped_areas, snd_pcm_channel_area_t *running_areas)
+int snd_pcm_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info)
{
- snd_pcm_channel_setup_t setup;
- snd_pcm_channel_area_t *r, *rp, *s, *sp;
- unsigned int channel;
- int err;
- assert(pcm);
- assert(pcm->mmap_info);
- if (!pcm->running_areas) {
- r = calloc(pcm->setup.format.channels, sizeof(*r));
- s = calloc(pcm->setup.format.channels, sizeof(*s));
- for (channel = 0, rp = r, sp = s; channel < pcm->setup.format.channels; ++channel, ++rp, ++sp) {
- setup.channel = channel;
- err = snd_pcm_channel_setup(pcm, &setup);
- if (err < 0) {
- free(r);
- free(s);
- return err;
- }
- *rp = setup.running_area;
- *sp = setup.stopped_area;
- }
- pcm->running_areas = r;
- pcm->stopped_areas = s;
+ return pcm->ops->channel_info(pcm, info);
+}
+
+int snd_pcm_channel_info_shm(snd_pcm_t *pcm, snd_pcm_channel_info_t *info,
+ int shmid)
+{
+ switch (pcm->access) {
+ case SND_PCM_ACCESS_MMAP_INTERLEAVED:
+ case SND_PCM_ACCESS_RW_INTERLEAVED:
+ info->first = info->channel * pcm->bits_per_sample;
+ info->step = pcm->bits_per_frame;
+ break;
+ case SND_PCM_ACCESS_MMAP_NONINTERLEAVED:
+ case SND_PCM_ACCESS_RW_NONINTERLEAVED:
+ info->first = 0;
+ info->step = pcm->bits_per_sample;
+ break;
+ default:
+ assert(0);
+ break;
}
- if (running_areas)
- memcpy(running_areas, pcm->running_areas, pcm->setup.format.channels * sizeof(*running_areas));
- if (stopped_areas)
- memcpy(stopped_areas, pcm->stopped_areas, pcm->setup.format.channels * sizeof(*stopped_areas));
+ info->addr = 0;
+ info->type = SND_PCM_AREA_SHM;
+ info->u.shm.shmid = shmid;
return 0;
-}
+}
int snd_pcm_mmap(snd_pcm_t *pcm)
{
int err;
+ unsigned int c;
assert(pcm);
- assert(pcm->valid_setup);
- if (pcm->mmap_info)
- return 0;
-
- if ((err = pcm->ops->mmap(pcm->op_arg)) < 0)
- return err;
- err = snd_pcm_mmap_get_areas(pcm, NULL, NULL);
+ assert(pcm->setup);
+ assert(!pcm->mmap_channels);
+ err = pcm->ops->mmap(pcm);
if (err < 0)
return err;
+ pcm->mmap_channels = calloc(pcm->channels, sizeof(pcm->mmap_channels[0]));
+ if (!pcm->mmap_channels)
+ return -ENOMEM;
+ assert(!pcm->running_areas);
+ pcm->running_areas = calloc(pcm->channels, sizeof(pcm->running_areas[0]));
+ if (!pcm->running_areas) {
+ free(pcm->mmap_channels);
+ pcm->mmap_channels = NULL;
+ return -ENOMEM;
+ }
+ for (c = 0; c < pcm->channels; ++c) {
+ snd_pcm_channel_info_t *i = &pcm->mmap_channels[c];
+ i->channel = c;
+ err = snd_pcm_channel_info(pcm, i);
+ if (err < 0)
+ return err;
+ }
+ for (c = 0; c < pcm->channels; ++c) {
+ snd_pcm_channel_info_t *i = &pcm->mmap_channels[c];
+ snd_pcm_channel_area_t *a = &pcm->running_areas[c];
+ unsigned int c1;
+ if (!i->addr) {
+ char *ptr;
+ size_t size = i->first + i->step * pcm->buffer_size;
+ for (c1 = c + 1; c1 < pcm->channels; ++c1) {
+ snd_pcm_channel_info_t *i1 = &pcm->mmap_channels[c1];
+ size_t s;
+ if (i1->type != i->type)
+ continue;
+ switch (i1->type) {
+ case SND_PCM_AREA_MMAP:
+ if (i1->u.mmap.fd != i->u.mmap.fd ||
+ i1->u.mmap.offset != i->u.mmap.offset)
+ continue;
+ break;
+ case SND_PCM_AREA_SHM:
+ if (i1->u.shm.shmid != i->u.shm.shmid)
+ continue;
+ break;
+ default:
+ assert(0);
+ }
+ s = i1->first + i1->step * pcm->buffer_size;
+ if (s > size)
+ size = s;
+ }
+ size = (size + 7) / 8;
+ size = PAGE_ALIGN(size);
+ switch (i->type) {
+ case SND_PCM_AREA_MMAP:
+ ptr = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, i->u.mmap.fd, i->u.mmap.offset);
+ if (ptr == MAP_FAILED) {
+ SYSERR("mmap failed");
+ return -errno;
+ }
+ i->addr = ptr;
+ break;
+ case SND_PCM_AREA_SHM:
+ if (i->u.shm.shmid < 0) {
+ int id;
+ id = shmget(IPC_PRIVATE, size, 0666);
+ if (id < 0) {
+ SYSERR("shmget failed");
+ return -errno;
+ }
+ i->u.shm.shmid = id;
+ }
+ ptr = shmat(i->u.shm.shmid, 0, 0);
+ if (ptr == (void*) -1) {
+ SYSERR("shmat failed");
+ return -errno;
+ }
+ i->addr = ptr;
+ break;
+ default:
+ assert(0);
+ }
+ }
+ for (c1 = c + 1; c1 < pcm->channels; ++c1) {
+ snd_pcm_channel_info_t *i1 = &pcm->mmap_channels[c1];
+ if (i1->type != i->type)
+ continue;
+ switch (i1->type) {
+ case SND_PCM_AREA_MMAP:
+ if (i1->u.mmap.fd != i->u.mmap.fd ||
+ i1->u.mmap.offset != i->u.mmap.offset)
+ continue;
+ break;
+ case SND_PCM_AREA_SHM:
+ if (i1->u.shm.shmid != i->u.shm.shmid)
+ continue;
+ break;
+ default:
+ assert(0);
+ }
+ i1->addr = i->addr;
+ }
+ a->addr = i->addr;
+ a->first = i->first;
+ a->step = i->step;
+ }
return 0;
}
int snd_pcm_munmap(snd_pcm_t *pcm)
{
int err;
+ unsigned int c;
assert(pcm);
- assert(pcm->mmap_info);
- if ((err = pcm->ops->munmap(pcm->op_arg)) < 0)
+ assert(pcm->mmap_channels);
+ for (c = 0; c < pcm->channels; ++c) {
+ snd_pcm_channel_info_t *i = &pcm->mmap_channels[c];
+ unsigned int c1;
+ size_t size = i->first + i->step * pcm->buffer_size;
+ if (!i->addr)
+ continue;
+ for (c1 = c + 1; c1 < pcm->channels; ++c1) {
+ snd_pcm_channel_info_t *i1 = &pcm->mmap_channels[c1];
+ size_t s;
+ if (i1->addr != i->addr)
+ continue;
+ i1->addr = NULL;
+ s = i1->first + i1->step * pcm->buffer_size;
+ if (s > size)
+ size = s;
+ }
+ size = (size + 7) / 8;
+ size = PAGE_ALIGN(size);
+ switch (i->type) {
+ case SND_PCM_AREA_MMAP:
+ err = munmap(i->addr, size);
+ if (err < 0) {
+ SYSERR("mmap failed");
+ return -errno;
+ }
+ break;
+ case SND_PCM_AREA_SHM:
+ err = shmdt(i->addr);
+ if (err < 0) {
+ SYSERR("shmdt failed");
+ return -errno;
+ }
+ break;
+ default:
+ assert(0);
+ }
+ i->addr = NULL;
+ }
+ err = pcm->ops->munmap(pcm);
+ if (err < 0)
return err;
- free(pcm->stopped_areas);
- free(pcm->running_areas);
- pcm->stopped_areas = 0;
- pcm->running_areas = 0;
+ free(pcm->mmap_channels);
+ pcm->mmap_channels = 0;
return 0;
}
@@ -267,25 +412,34 @@ ssize_t snd_pcm_write_mmap(snd_pcm_t *pcm, size_t size)
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;
+ size_t cont = pcm->buffer_size - offset;
if (cont < frames)
frames = cont;
- if (pcm->setup.xfer_mode == SND_PCM_XFER_INTERLEAVED) {
+ switch (pcm->access) {
+ case SND_PCM_ACCESS_MMAP_INTERLEAVED:
+ {
snd_pcm_channel_area_t *a = snd_pcm_mmap_areas(pcm);
char *buf = snd_pcm_channel_area_addr(a, offset);
- assert(pcm->setup.mmap_shape == SND_PCM_MMAP_INTERLEAVED);
err = _snd_pcm_writei(pcm, buf, size);
- } else {
- size_t channels = pcm->setup.format.channels;
+ break;
+ }
+ case SND_PCM_ACCESS_MMAP_NONINTERLEAVED:
+ {
+ size_t channels = pcm->channels;
unsigned int c;
void *bufs[channels];
snd_pcm_channel_area_t *areas = snd_pcm_mmap_areas(pcm);
- assert(pcm->setup.mmap_shape == SND_PCM_MMAP_NONINTERLEAVED);
for (c = 0; c < channels; ++c) {
snd_pcm_channel_area_t *a = &areas[c];
bufs[c] = snd_pcm_channel_area_addr(a, offset);
}
err = _snd_pcm_writen(pcm, bufs, size);
+ break;
+ }
+ default:
+ assert(0);
+ err = -EINVAL;
+ break;
}
if (err < 0)
break;
@@ -304,26 +458,34 @@ ssize_t snd_pcm_read_mmap(snd_pcm_t *pcm, size_t size)
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;
+ size_t cont = pcm->buffer_size - offset;
if (cont < frames)
frames = cont;
- if (pcm->setup.xfer_mode == SND_PCM_XFER_INTERLEAVED) {
+ switch (pcm->access) {
+ case SND_PCM_ACCESS_MMAP_INTERLEAVED:
+ {
snd_pcm_channel_area_t *a = snd_pcm_mmap_areas(pcm);
char *buf = snd_pcm_channel_area_addr(a, offset);
- assert(pcm->setup.mmap_shape == SND_PCM_MMAP_INTERLEAVED);
err = _snd_pcm_readi(pcm, buf, size);
- } else {
- size_t channels = pcm->setup.format.channels;
+ break;
+ }
+ case SND_PCM_ACCESS_MMAP_NONINTERLEAVED:
+ {
+ size_t channels = pcm->channels;
unsigned int c;
void *bufs[channels];
snd_pcm_channel_area_t *areas = snd_pcm_mmap_areas(pcm);
- assert(pcm->setup.mmap_shape == SND_PCM_MMAP_NONINTERLEAVED);
for (c = 0; c < channels; ++c) {
snd_pcm_channel_area_t *a = &areas[c];
bufs[c] = snd_pcm_channel_area_addr(a, offset);
}
err = _snd_pcm_readn(pcm->fast_op_arg, bufs, size);
}
+ default:
+ assert(0);
+ err = -EINVAL;
+ break;
+ }
if (err < 0)
break;
xfer += frames;
diff --git a/src/pcm/pcm_mulaw.c b/src/pcm/pcm_mulaw.c
index e7ed4802..01cd202c 100644
--- a/src/pcm/pcm_mulaw.c
+++ b/src/pcm/pcm_mulaw.c
@@ -35,8 +35,6 @@ typedef struct {
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)
@@ -230,96 +228,76 @@ static void mulaw_encode(snd_pcm_channel_area_t *src_areas,
}
}
-static int snd_pcm_mulaw_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t * info)
+static int snd_pcm_mulaw_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t * info)
{
snd_pcm_mulaw_t *mulaw = pcm->private;
- unsigned int req_mask = info->req_mask;
- unsigned int sfmt = info->req.format.sfmt;
+ unsigned int format_mask, access_mask;
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->access_mask &= (SND_PCM_ACCBIT_MMAP_INTERLEAVED |
+ SND_PCM_ACCBIT_RW_INTERLEAVED |
+ SND_PCM_ACCBIT_MMAP_NONINTERLEAVED |
+ SND_PCM_ACCBIT_RW_NONINTERLEAVED);
+ access_mask = info->access_mask;
+ if (access_mask == 0)
+ return -EINVAL;
+ if (mulaw->sformat == SND_PCM_FORMAT_MU_LAW)
+ info->format_mask &= SND_PCM_FMTBIT_LINEAR;
+ else
+ info->format_mask &= SND_PCM_FMTBIT_MU_LAW;
+ format_mask = info->format_mask;
+ if (format_mask == 0)
+ return -EINVAL;
+
+ info->format_mask = 1U << mulaw->sformat;
+ info->access_mask = SND_PCM_ACCBIT_MMAP;
+ err = snd_pcm_hw_info(mulaw->plug.slave, info);
+ if (info->format_mask)
+ info->format_mask = format_mask;
+ if (info->access_mask) {
+ mulaw->plug.saccess_mask = info->access_mask;
+ info->access_mask = access_mask;
}
- 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;
+ info->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
+ snd_pcm_hw_info_complete(info);
+ return 0;
}
-static int snd_pcm_mulaw_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
+static int snd_pcm_mulaw_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
{
snd_pcm_mulaw_t *mulaw = pcm->private;
snd_pcm_t *slave = mulaw->plug.slave;
+ unsigned int format, access;
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;
- }
- 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_mmap(slave, params);
- params->format.sfmt = mulaw->cformat;
- params->xfer_mode = mulaw->cxfer_mode;
- params->mmap_shape = mulaw->cmmap_shape;
- 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);
+ format = params->format;
+ access = params->access;
+ params->format = mulaw->sformat;
+ if (mulaw->plug.saccess_mask & SND_PCM_ACCBIT_MMAP_INTERLEAVED)
+ params->access = SND_PCM_ACCESS_MMAP_INTERLEAVED;
+ else if (mulaw->plug.saccess_mask & SND_PCM_ACCBIT_MMAP_NONINTERLEAVED)
+ params->access = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;
+ else
+ assert(0);
+ err = snd_pcm_hw_params(slave, params);
+ params->format = format;
+ params->access = access;
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 = get_index(mulaw->cformat, SND_PCM_SFMT_S16);
+ if (mulaw->sformat == SND_PCM_FORMAT_MU_LAW) {
+ mulaw->getput_idx = get_index(format, SND_PCM_FORMAT_S16);
mulaw->func = mulaw_encode;
} else {
- mulaw->getput_idx = put_index(SND_PCM_SFMT_S16, mulaw->sformat);
+ mulaw->getput_idx = put_index(SND_PCM_FORMAT_S16, mulaw->sformat);
mulaw->func = mulaw_decode;
}
} else {
- if (mulaw->sformat == SND_PCM_SFMT_MU_LAW) {
- mulaw->getput_idx = put_index(SND_PCM_SFMT_S16, mulaw->cformat);
+ if (mulaw->sformat == SND_PCM_FORMAT_MU_LAW) {
+ mulaw->getput_idx = put_index(SND_PCM_FORMAT_S16, format);
mulaw->func = mulaw_decode;
} else {
- mulaw->getput_idx = get_index(mulaw->sformat, SND_PCM_SFMT_S16);
+ mulaw->getput_idx = get_index(mulaw->sformat, SND_PCM_FORMAT_S16);
mulaw->func = mulaw_encode;
}
}
@@ -343,7 +321,7 @@ static ssize_t snd_pcm_mulaw_write_areas(snd_pcm_t *pcm,
size_t frames = snd_pcm_mmap_playback_xfer(slave, size - xfer);
mulaw->func(areas, offset,
snd_pcm_mmap_areas(slave), snd_pcm_mmap_offset(slave),
- frames, pcm->setup.format.channels,
+ frames, pcm->channels,
mulaw->getput_idx);
err = snd_pcm_mmap_forward(slave, frames);
if (err < 0)
@@ -378,7 +356,7 @@ static ssize_t snd_pcm_mulaw_read_areas(snd_pcm_t *pcm,
size_t frames = snd_pcm_mmap_capture_xfer(slave, size - xfer);
mulaw->func(snd_pcm_mmap_areas(slave), snd_pcm_mmap_offset(slave),
areas, offset,
- frames, pcm->setup.format.channels,
+ frames, pcm->channels,
mulaw->getput_idx);
err = snd_pcm_mmap_forward(slave, frames);
if (err < 0)
@@ -401,7 +379,7 @@ 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) {
+ if (pcm->setup) {
fprintf(fp, "Its setup is:\n");
snd_pcm_dump_setup(pcm, fp);
}
@@ -412,12 +390,12 @@ static void snd_pcm_mulaw_dump(snd_pcm_t *pcm, FILE *fp)
snd_pcm_ops_t 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,
+ hw_info: snd_pcm_mulaw_hw_info,
+ hw_params: snd_pcm_mulaw_hw_params,
+ sw_params: snd_pcm_plugin_sw_params,
+ dig_info: snd_pcm_plugin_dig_info,
+ dig_params: snd_pcm_plugin_dig_params,
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,
async: snd_pcm_plugin_async,
@@ -431,7 +409,7 @@ int snd_pcm_mulaw_open(snd_pcm_t **pcmp, char *name, int sformat, snd_pcm_t *sla
snd_pcm_mulaw_t *mulaw;
assert(pcmp && slave);
if (snd_pcm_format_linear(sformat) != 1 &&
- sformat != SND_PCM_SFMT_MU_LAW)
+ sformat != SND_PCM_FORMAT_MU_LAW)
return -EINVAL;
mulaw = calloc(1, sizeof(snd_pcm_mulaw_t));
if (!mulaw) {
@@ -498,7 +476,7 @@ int _snd_pcm_mulaw_open(snd_pcm_t **pcmp, char *name,
if (sformat < 0)
return -EINVAL;
if (snd_pcm_format_linear(sformat) != 1 &&
- sformat != SND_PCM_SFMT_MU_LAW)
+ sformat != SND_PCM_FORMAT_MU_LAW)
return -EINVAL;
continue;
}
diff --git a/src/pcm/pcm_multi.c b/src/pcm/pcm_multi.c
index 13c9f523..95f63478 100644
--- a/src/pcm/pcm_multi.c
+++ b/src/pcm/pcm_multi.c
@@ -31,6 +31,7 @@ typedef struct {
snd_pcm_t *pcm;
unsigned int channels_count;
int close_slave;
+ unsigned int access_mask;
} snd_pcm_multi_slave_t;
typedef struct {
@@ -43,7 +44,6 @@ typedef struct {
snd_pcm_multi_slave_t *slaves;
size_t channels_count;
snd_pcm_multi_channel_t *channels;
- int xfer_mode;
} snd_pcm_multi_t;
static int snd_pcm_multi_close(snd_pcm_t *pcm)
@@ -91,176 +91,104 @@ static int snd_pcm_multi_info(snd_pcm_t *pcm, snd_pcm_info_t *info)
return 0;
}
-static int snd_pcm_multi_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t *info)
+static int snd_pcm_multi_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t *info)
{
snd_pcm_multi_t *multi = pcm->private;
- unsigned int i;
- int err;
- snd_pcm_t *slave_0 = multi->slaves[0].pcm;
- unsigned int req_mask = info->req_mask;
- unsigned int channels = info->req.format.channels;
- if ((req_mask & SND_PCM_PARAMS_CHANNELS) &&
- channels != multi->channels_count) {
- info->req.fail_mask |= SND_PCM_PARAMS_CHANNELS;
- info->req.fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
+ unsigned int k;
+ snd_pcm_hw_info_t i;
+ unsigned int access_mask = ~0;
+ int err = 0;
+ if (info->channels_min < multi->channels_count)
+ info->channels_min = multi->channels_count;
+ if (info->channels_max > multi->channels_count)
+ info->channels_max = multi->channels_count;
+ if (info->channels_max > info->channels_max)
return -EINVAL;
- }
- info->req_mask |= SND_PCM_PARAMS_CHANNELS;
- info->req.format.channels = multi->slaves[0].channels_count;
- err = snd_pcm_params_info(slave_0, info);
- info->req_mask = req_mask;
- info->req.format.channels = channels;
- if (err < 0)
- return err;
- info->min_channels = multi->channels_count;
- info->max_channels = multi->channels_count;
- for (i = 1; i < multi->slaves_count; ++i) {
- snd_pcm_t *slave_i = multi->slaves[i].pcm;
- 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_count;
- err = snd_pcm_params_info(slave_i, &info_i);
+ i = *info;
+ for (k = 0; k < multi->slaves_count; ++k) {
+ snd_pcm_t *slave = multi->slaves[k].pcm;
+ i.access_mask = SND_PCM_ACCBIT_MMAP;
+ i.channels_min = i.channels_max = multi->slaves[k].channels_count;
+ err = snd_pcm_hw_info(slave, &i);
+ access_mask &= i.access_mask;
if (err < 0)
- return err;
- info->formats &= info_i.formats;
- info->rates &= info_i.rates;
- if (info_i.min_rate > info->min_rate)
- info->min_rate = info_i.min_rate;
- if (info_i.max_rate < info->max_rate)
- info->max_rate = info_i.max_rate;
- if (info_i.buffer_size < info->buffer_size)
- info->buffer_size = info_i.buffer_size;
- if (info_i.min_fragment_size > info->min_fragment_size)
- info->min_fragment_size = info_i.min_fragment_size;
- if (info_i.max_fragment_size < info->max_fragment_size)
- info->max_fragment_size = info_i.max_fragment_size;
- if (info_i.min_fragments > info->min_fragments)
- 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;
+ break;
+ multi->slaves[k].access_mask = i.access_mask;
}
- if (info->flags & SND_PCM_INFO_INTERLEAVED) {
- if (multi->slaves_count > 0) {
- info->flags &= ~SND_PCM_INFO_INTERLEAVED;
- info->flags |= SND_PCM_INFO_COMPLEX;
- }
- } else if (!(info->flags & SND_PCM_INFO_NONINTERLEAVED))
- info->flags |= SND_PCM_INFO_COMPLEX;
- info->req_mask = req_mask;
- return 0;
+ *info = i;
+ if (i.channels_min <= i.channels_max)
+ info->channels_min = info->channels_max = multi->channels_count;
+ if (i.access_mask) {
+ if (!(access_mask & SND_PCM_ACCBIT_MMAP_INTERLEAVED) ||
+ multi->slaves_count > 1)
+ info->access_mask &= ~SND_PCM_ACCBIT_MMAP_INTERLEAVED;
+ if (!(access_mask & SND_PCM_ACCBIT_MMAP_NONINTERLEAVED))
+ info->access_mask &= ~SND_PCM_ACCBIT_MMAP_NONINTERLEAVED;
+ }
+ return err;
}
-static int snd_pcm_multi_mmap(snd_pcm_t *pcm)
+static int snd_pcm_multi_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{
snd_pcm_multi_t *multi = pcm->private;
unsigned int i;
- size_t count = 0;
+ snd_pcm_hw_params_t p;
+ int err;
+ if (params->channels != multi->channels_count) {
+ params->fail_mask = SND_PCM_HW_PARBIT_CHANNELS;
+ return -EINVAL;
+ }
+ p = *params;
for (i = 0; i < multi->slaves_count; ++i) {
snd_pcm_t *slave = multi->slaves[i].pcm;
- snd_pcm_setup_t *setup;
- int err = snd_pcm_mmap(slave);
+ if (multi->slaves[i].access_mask & SND_PCM_ACCBIT_MMAP_INTERLEAVED)
+ p.access = SND_PCM_ACCESS_MMAP_INTERLEAVED;
+ else if (multi->slaves[i].access_mask & SND_PCM_ACCBIT_MMAP_NONINTERLEAVED)
+ p.access = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;
+ else
+ assert(0);
+ p.channels = multi->slaves[i].channels_count;
+ err = snd_pcm_hw_params(slave, &p);
+ if (err < 0) {
+ params->fail_mask = p.fail_mask;
+ return err;
+ }
+ err = snd_pcm_areas_silence(slave->running_areas, 0, slave->channels, slave->buffer_size, slave->format);
if (err < 0)
return err;
- count += slave->mmap_info_count;
- setup = &slave->setup;
- if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
- snd_pcm_channel_area_t r[setup->format.channels];
- snd_pcm_channel_area_t s[setup->format.channels];
- err = snd_pcm_mmap_get_areas(slave, s, r);
- if (err < 0)
- return err;
- err = snd_pcm_areas_silence(s, 0, setup->format.channels, setup->buffer_size, setup->format.sfmt);
- if (err < 0)
- return err;
- err = snd_pcm_areas_silence(r, 0, setup->format.channels, setup->buffer_size, setup->format.sfmt);
+ if (slave->stopped_areas) {
+ err = snd_pcm_areas_silence(slave->stopped_areas, 0, slave->channels, slave->buffer_size, slave->format);
if (err < 0)
return err;
}
}
- pcm->mmap_info_count = count;
- pcm->mmap_info = malloc(count * sizeof(*pcm->mmap_info));
- count = 0;
- for (i = 0; i < multi->slaves_count; ++i) {
- snd_pcm_t *slave = multi->slaves[i].pcm;
- memcpy(&pcm->mmap_info[count], slave->mmap_info, slave->mmap_info_count * sizeof(*pcm->mmap_info));
- count += slave->mmap_info_count;
- }
return 0;
}
-static int snd_pcm_multi_munmap(snd_pcm_t *pcm)
+static int snd_pcm_multi_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)
{
snd_pcm_multi_t *multi = pcm->private;
unsigned int i;
+ int err;
for (i = 0; i < multi->slaves_count; ++i) {
snd_pcm_t *slave = multi->slaves[i].pcm;
- int err = snd_pcm_munmap(slave);
+ err = snd_pcm_sw_params(slave, params);
if (err < 0)
return err;
}
- pcm->mmap_info_count = 0;
- free(pcm->mmap_info);
- pcm->mmap_info = 0;
return 0;
}
-
-static int snd_pcm_multi_params(snd_pcm_t *pcm, snd_pcm_params_t *params)
+
+static int snd_pcm_multi_dig_info(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_dig_info_t *info ATTRIBUTE_UNUSED)
{
- snd_pcm_multi_t *multi = pcm->private;
- unsigned int i;
- snd_pcm_params_t p;
- int err = 0;
- if (params->format.channels != multi->channels_count) {
- params->fail_mask = SND_PCM_PARAMS_CHANNELS;
- params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
- return -EINVAL;
- }
- p = *params;
- for (i = 0; i < multi->slaves_count; ++i) {
- snd_pcm_t *slave = multi->slaves[i].pcm;
- p.format.channels = multi->slaves[i].channels_count;
- err = snd_pcm_params_mmap(slave, &p);
- if (err < 0) {
- params->fail_mask = p.fail_mask;
- params->fail_reason = p.fail_reason;
- break;
- }
- }
- if (err == 0)
- multi->xfer_mode = params->xfer_mode;
- return err;
+ /* FIXME */
+ return -ENOSYS;
}
-static int snd_pcm_multi_setup(snd_pcm_t *pcm, snd_pcm_setup_t *setup)
+static int snd_pcm_multi_dig_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_dig_params_t *params ATTRIBUTE_UNUSED)
{
- snd_pcm_multi_t *multi = pcm->private;
- unsigned int i;
- int err;
- err = snd_pcm_setup(multi->slaves[0].pcm, setup);
- if (err < 0)
- return err;
- for (i = 1; i < multi->slaves_count; ++i) {
- snd_pcm_setup_t s;
- snd_pcm_t *sh = multi->slaves[i].pcm;
- err = snd_pcm_setup(sh, &s);
- if (err < 0)
- return err;
- if (setup->format.rate != s.format.rate)
- return -EINVAL;
- 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.channels = multi->channels_count;
- if (multi->xfer_mode == SND_PCM_XFER_UNSPECIFIED)
- setup->xfer_mode = SND_PCM_XFER_NONINTERLEAVED;
- else
- setup->xfer_mode = multi->xfer_mode;
- return 0;
+ /* FIXME */
+ return -ENOSYS;
}
static int snd_pcm_multi_status(snd_pcm_t *pcm, snd_pcm_status_t *status)
@@ -335,34 +263,6 @@ static int snd_pcm_multi_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *in
return err;
}
-static int snd_pcm_multi_channel_params(snd_pcm_t *pcm, snd_pcm_channel_params_t *params)
-{
- snd_pcm_multi_t *multi = pcm->private;
- unsigned int channel = params->channel;
- snd_pcm_multi_channel_t *c = &multi->channels[channel];
- int err;
- if (c->slave_idx < 0)
- return -ENXIO;
- params->channel = c->slave_channel;
- err = snd_pcm_channel_params(multi->slaves[c->slave_idx].pcm, params);
- params->channel = channel;
- return err;
-}
-
-static int snd_pcm_multi_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t *setup)
-{
- snd_pcm_multi_t *multi = pcm->private;
- unsigned int channel = setup->channel;
- snd_pcm_multi_channel_t *c = &multi->channels[channel];
- int err;
- if (c->slave_idx < 0)
- return -ENXIO;
- setup->channel = c->slave_channel;
- err = snd_pcm_channel_setup(multi->slaves[c->slave_idx].pcm, setup);
- setup->channel = channel;
- return err;
-}
-
static ssize_t snd_pcm_multi_rewind(snd_pcm_t *pcm, size_t frames)
{
snd_pcm_multi_t *multi = pcm->private;
@@ -413,6 +313,16 @@ static int snd_pcm_multi_set_avail_min(snd_pcm_t *pcm, size_t frames)
return snd_pcm_set_avail_min(multi->slaves[0].pcm, frames);
}
+static int snd_pcm_multi_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
+{
+ return 0;
+}
+
+static int snd_pcm_multi_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
+{
+ return 0;
+}
+
int snd_pcm_multi_poll_descriptor(snd_pcm_t *pcm)
{
snd_pcm_multi_t *multi = pcm->private;
@@ -433,7 +343,7 @@ static void snd_pcm_multi_dump(snd_pcm_t *pcm, FILE *fp)
fprintf(fp, "%d: slave %d, channel %d\n",
k, c->slave_idx, c->slave_channel);
}
- if (pcm->valid_setup) {
+ if (pcm->setup) {
fprintf(fp, "\nIts setup is:\n");
snd_pcm_dump_setup(pcm, fp);
}
@@ -446,12 +356,12 @@ static void snd_pcm_multi_dump(snd_pcm_t *pcm, FILE *fp)
snd_pcm_ops_t snd_pcm_multi_ops = {
close: snd_pcm_multi_close,
info: snd_pcm_multi_info,
- params_info: snd_pcm_multi_params_info,
- params: snd_pcm_multi_params,
- setup: snd_pcm_multi_setup,
+ hw_info: snd_pcm_multi_hw_info,
+ hw_params: snd_pcm_multi_hw_params,
+ sw_params: snd_pcm_multi_sw_params,
+ dig_info: snd_pcm_multi_dig_info,
+ dig_params: snd_pcm_multi_dig_params,
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,
async: snd_pcm_multi_async,
@@ -538,7 +448,7 @@ int snd_pcm_multi_open(snd_pcm_t **pcmp, char *name,
pcm->type = SND_PCM_TYPE_MULTI;
pcm->stream = stream;
pcm->mode = multi->slaves[0].pcm->mode;
- pcm->mmap_auto = 1;
+ pcm->mmap_rw = 1;
pcm->ops = &snd_pcm_multi_ops;
pcm->op_arg = pcm;
pcm->fast_ops = &snd_pcm_multi_fast_ops;
diff --git a/src/pcm/pcm_null.c b/src/pcm/pcm_null.c
index 625c08f9..2878a17b 100644
--- a/src/pcm/pcm_null.c
+++ b/src/pcm/pcm_null.c
@@ -21,13 +21,14 @@
#include <byteswap.h>
#include <limits.h>
+#include <sys/shm.h>
#include "pcm_local.h"
#include "pcm_plugin.h"
typedef struct {
- snd_pcm_setup_t setup;
snd_timestamp_t trigger_time;
int state;
+ int shmid;
size_t appl_ptr;
size_t hw_ptr;
int poll_fd;
@@ -58,25 +59,10 @@ static int snd_pcm_null_info(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_info_t * i
return 0;
}
-static int snd_pcm_null_channel_info(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_channel_info_t * info)
+static int snd_pcm_null_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info)
{
- int channel = info->channel;
- memset(info, 0, sizeof(*info));
- info->channel = channel;
- return 0;
-}
-
-static int snd_pcm_null_channel_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_channel_params_t * params ATTRIBUTE_UNUSED)
-{
- return 0;
-}
-
-static int snd_pcm_null_channel_setup(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_channel_setup_t * setup)
-{
- int channel = setup->channel;
- memset(setup, 0, sizeof(*setup));
- setup->channel = channel;
- return 0;
+ snd_pcm_null_t *null = pcm->private;
+ return snd_pcm_channel_info_shm(pcm, info, null->shmid);
}
static int snd_pcm_null_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
@@ -86,7 +72,7 @@ static int snd_pcm_null_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
status->state = null->state;
status->trigger_time = null->trigger_time;
gettimeofday(&status->tstamp, 0);
- status->avail = pcm->setup.buffer_size;
+ status->avail = pcm->buffer_size;
status->avail_max = status->avail;
return 0;
}
@@ -118,7 +104,7 @@ static int snd_pcm_null_start(snd_pcm_t *pcm)
assert(null->state == SND_PCM_STATE_PREPARED);
null->state = SND_PCM_STATE_RUNNING;
if (pcm->stream == SND_PCM_STREAM_CAPTURE)
- snd_pcm_mmap_appl_forward(pcm, pcm->setup.buffer_size);
+ snd_pcm_mmap_appl_forward(pcm, pcm->buffer_size);
return 0;
}
@@ -182,7 +168,7 @@ static ssize_t snd_pcm_null_writei(snd_pcm_t *pcm, const void *buffer ATTRIBUTE_
{
snd_pcm_null_t *null = pcm->private;
if (null->state == SND_PCM_STATE_PREPARED &&
- pcm->setup.start_mode != SND_PCM_START_EXPLICIT) {
+ pcm->start_mode != SND_PCM_START_EXPLICIT) {
null->state = SND_PCM_STATE_RUNNING;
}
return snd_pcm_null_fwd(pcm, size);
@@ -192,7 +178,7 @@ static ssize_t snd_pcm_null_writen(snd_pcm_t *pcm, void **bufs ATTRIBUTE_UNUSED,
{
snd_pcm_null_t *null = pcm->private;
if (null->state == SND_PCM_STATE_PREPARED &&
- pcm->setup.start_mode != SND_PCM_START_EXPLICIT) {
+ pcm->start_mode != SND_PCM_START_EXPLICIT) {
null->state = SND_PCM_STATE_RUNNING;
}
return snd_pcm_null_fwd(pcm, size);
@@ -202,9 +188,9 @@ static ssize_t snd_pcm_null_readi(snd_pcm_t *pcm, void *buffer ATTRIBUTE_UNUSED,
{
snd_pcm_null_t *null = pcm->private;
if (null->state == SND_PCM_STATE_PREPARED &&
- pcm->setup.start_mode != SND_PCM_START_EXPLICIT) {
+ pcm->start_mode != SND_PCM_START_EXPLICIT) {
null->state = SND_PCM_STATE_RUNNING;
- snd_pcm_mmap_hw_forward(pcm, pcm->setup.buffer_size);
+ snd_pcm_mmap_hw_forward(pcm, pcm->buffer_size);
}
return snd_pcm_null_fwd(pcm, size);
}
@@ -213,9 +199,9 @@ static ssize_t snd_pcm_null_readn(snd_pcm_t *pcm, void **bufs ATTRIBUTE_UNUSED,
{
snd_pcm_null_t *null = pcm->private;
if (null->state == SND_PCM_STATE_PREPARED &&
- pcm->setup.start_mode != SND_PCM_START_EXPLICIT) {
+ pcm->start_mode != SND_PCM_START_EXPLICIT) {
null->state = SND_PCM_STATE_RUNNING;
- snd_pcm_mmap_hw_forward(pcm, pcm->setup.buffer_size);
+ snd_pcm_mmap_hw_forward(pcm, pcm->buffer_size);
}
return snd_pcm_null_fwd(pcm, size);
}
@@ -227,111 +213,83 @@ static ssize_t snd_pcm_null_mmap_forward(snd_pcm_t *pcm, size_t size)
static ssize_t snd_pcm_null_avail_update(snd_pcm_t *pcm)
{
- return pcm->setup.buffer_size;
+ return pcm->buffer_size;
}
static int snd_pcm_null_set_avail_min(snd_pcm_t *pcm, size_t frames)
{
- pcm->setup.buffer_size = frames;
+ pcm->avail_min = frames;
return 0;
}
-static int snd_pcm_null_mmap(snd_pcm_t *pcm)
+static int snd_pcm_null_hw_info(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_info_t * info)
{
- snd_pcm_mmap_info_t *i;
- int err;
- i = calloc(1, sizeof(*i));
- if (!i)
- return -ENOMEM;
- err = snd_pcm_alloc_user_mmap(pcm, i);
- if (err < 0) {
- free(i);
- return err;
- }
- pcm->mmap_info = i;
- pcm->mmap_info_count = 1;
+ snd_pcm_hw_info_complete(info);
+ info->fifo_size = 0;
return 0;
}
-static int snd_pcm_null_munmap(snd_pcm_t *pcm)
+static int snd_pcm_null_hw_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t * params ATTRIBUTE_UNUSED)
{
- int err = snd_pcm_free_mmap(pcm, pcm->mmap_info);
- if (err < 0)
- return err;
- free(pcm->mmap_info);
- pcm->mmap_info_count = 0;
- pcm->mmap_info = 0;
return 0;
}
-static int snd_pcm_null_params_info(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_params_info_t * info)
-{
- int sizes = ((info->req_mask & SND_PCM_PARAMS_SFMT) &&
- (info->req_mask & SND_PCM_PARAMS_CHANNELS));
- info->flags = SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID |
- SND_PCM_INFO_INTERLEAVED | SND_PCM_INFO_NONINTERLEAVED |
- SND_PCM_INFO_PAUSE;
- info->formats = ~0;
- info->rates = SND_PCM_RATE_CONTINUOUS | SND_PCM_RATE_8000_192000;
- info->min_rate = 4000;
- info->max_rate = 192000;
- info->min_channels = 1;
- info->max_channels = 32;
- info->min_fragments = 1;
- info->max_fragments = 1024 * 1024;
- if (sizes) {
- info->buffer_size = 1024 * 1024;
- info->min_fragment_size = 1;
- info->max_fragment_size = 1024 * 1024;
- info->fragment_align = 1;
+static int snd_pcm_null_sw_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_params_t * params)
+{
+ if (params->start_mode > SND_PCM_START_LAST) {
+ params->fail_mask = SND_PCM_SW_PARBIT_START_MODE;
+ return -EINVAL;
+ }
+ if (params->ready_mode > SND_PCM_READY_LAST) {
+ params->fail_mask = SND_PCM_SW_PARBIT_READY_MODE;
+ return -EINVAL;
+ }
+ if (params->xrun_mode > SND_PCM_XRUN_LAST) {
+ params->fail_mask = SND_PCM_SW_PARBIT_XRUN_MODE;
+ return -EINVAL;
}
return 0;
}
-static int snd_pcm_null_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
+static int snd_pcm_null_dig_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_dig_params_t *params ATTRIBUTE_UNUSED)
+{
+ return 0;
+}
+
+static int snd_pcm_null_dig_info(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_dig_info_t *info ATTRIBUTE_UNUSED)
+{
+ return 0;
+}
+
+static int snd_pcm_null_mmap(snd_pcm_t *pcm)
{
snd_pcm_null_t *null = pcm->private;
- snd_pcm_setup_t *s = &null->setup;
- int w = snd_pcm_format_width(s->format.sfmt);
- if (w < 0) {
- params->fail_mask = SND_PCM_PARAMS_SFMT;
- return -EINVAL;
+ if (!(pcm->info & SND_PCM_INFO_MMAP)) {
+ size_t size = snd_pcm_frames_to_bytes(pcm, pcm->buffer_size);
+ int id = shmget(IPC_PRIVATE, size, 0666);
+ if (id < 0) {
+ SYSERR("shmget failed");
+ return -errno;
+ }
+ null->shmid = id;
}
- s->msbits = w;
- s->format = params->format;
- s->start_mode = params->start_mode;
- s->ready_mode = params->ready_mode;
- s->avail_min = params->avail_min;
- s->xfer_mode = params->xfer_mode;
- s->xfer_min = params->xfer_min;
- s->xfer_align = params->xfer_align;
- s->xrun_mode = params->xrun_mode;
- s->mmap_shape = params->mmap_shape;
- s->frag_size = params->frag_size;
- s->frags = s->buffer_size / s->frag_size;
- if (s->frags < 1)
- s->frags = 1;
- s->buffer_size = s->frag_size * s->frags;
- s->boundary = LONG_MAX - LONG_MAX % s->buffer_size;
- s->time = params->time;
- s->rate_master = s->format.rate;
- s->rate_divisor = 1;
- s->mmap_bytes = 0;
- s->fifo_size = 1;
return 0;
}
-static int snd_pcm_null_setup(snd_pcm_t *pcm, snd_pcm_setup_t * setup)
+static int snd_pcm_null_munmap(snd_pcm_t *pcm)
{
snd_pcm_null_t *null = pcm->private;
- *setup = null->setup;
+ if (shmctl(null->shmid, IPC_RMID, 0) < 0) {
+ SYSERR("shmctl IPC_RMID failed");
+ return -errno;
+ }
return 0;
}
static void snd_pcm_null_dump(snd_pcm_t *pcm, FILE *fp)
{
fprintf(fp, "Null PCM\n");
- if (pcm->valid_setup) {
+ if (pcm->setup) {
fprintf(fp, "Its setup is:\n");
snd_pcm_dump_setup(pcm, fp);
}
@@ -340,12 +298,12 @@ static void snd_pcm_null_dump(snd_pcm_t *pcm, FILE *fp)
snd_pcm_ops_t snd_pcm_null_ops = {
close: snd_pcm_null_close,
info: snd_pcm_null_info,
- params_info: snd_pcm_null_params_info,
- params: snd_pcm_null_params,
- setup: snd_pcm_null_setup,
+ hw_info: snd_pcm_null_hw_info,
+ hw_params: snd_pcm_null_hw_params,
+ sw_params: snd_pcm_null_sw_params,
+ dig_params: snd_pcm_null_dig_params,
+ dig_info: snd_pcm_null_dig_info,
channel_info: snd_pcm_null_channel_info,
- channel_params: snd_pcm_null_channel_params,
- channel_setup: snd_pcm_null_channel_setup,
dump: snd_pcm_null_dump,
nonblock: snd_pcm_null_nonblock,
async: snd_pcm_null_async,
diff --git a/src/pcm/pcm_plug.c b/src/pcm/pcm_plug.c
index d659ccb5..cafe1970 100644
--- a/src/pcm/pcm_plug.c
+++ b/src/pcm/pcm_plug.c
@@ -32,37 +32,25 @@ typedef struct {
} 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
+ SND_PCM_FORMAT_S16_LE,
+ SND_PCM_FORMAT_S16_BE,
+ SND_PCM_FORMAT_U16_LE,
+ SND_PCM_FORMAT_U16_BE,
+ SND_PCM_FORMAT_S24_LE,
+ SND_PCM_FORMAT_S24_BE,
+ SND_PCM_FORMAT_U24_LE,
+ SND_PCM_FORMAT_U24_BE,
+ SND_PCM_FORMAT_S32_LE,
+ SND_PCM_FORMAT_S32_BE,
+ SND_PCM_FORMAT_U32_LE,
+ SND_PCM_FORMAT_U32_BE,
+ SND_PCM_FORMAT_S8,
+ SND_PCM_FORMAT_U8
};
-static int snd_pcm_plug_slave_fmt(int format,
- snd_pcm_params_info_t *slave_info)
+static int snd_pcm_plug_slave_fmt(int format, unsigned int format_mask)
{
- 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);
@@ -77,8 +65,8 @@ static int snd_pcm_plug_slave_fmt(int format,
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;
+ format_mask & (1U << format1))
+ return format1;
unsignd1 = !unsignd1;
}
big1 = !big1;
@@ -89,80 +77,24 @@ static int snd_pcm_plug_slave_fmt(int format,
}
width1 += dwidth1;
}
- return -EINVAL;
- _found:
- return format1;
+ return ffs(format_mask) - 1;
} else {
unsigned int i;
switch (format) {
- case SND_PCM_SFMT_MU_LAW:
- case SND_PCM_SFMT_A_LAW:
- case SND_PCM_SFMT_IMA_ADPCM:
+ case SND_PCM_FORMAT_MU_LAW:
+ case SND_PCM_FORMAT_A_LAW:
+ case SND_PCM_FORMAT_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))
+ if (format_mask & (1U << format1))
return format1;
}
default:
- return -EINVAL;
+ return ffs(format_mask) - 1;
}
}
}
-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 }
-};
-
-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 rate;
-}
-
static int snd_pcm_plug_close(snd_pcm_t *pcm)
{
snd_pcm_plug_t *plug = pcm->private;
@@ -206,97 +138,156 @@ static int snd_pcm_plug_info(snd_pcm_t *pcm, snd_pcm_info_t *info)
return 0;
}
-static int snd_pcm_plug_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t *info)
+static int snd_pcm_plug_hw_info(snd_pcm_t *pcm, snd_pcm_hw_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 sformat, srate;
- unsigned int schannels;
- int crate;
-
- info->req.fail_reason = 0;
- info->req.fail_mask = 0;
+ snd_pcm_hw_info_t sinfo, i;
+ snd_pcm_hw_params_t sparams;
+ unsigned int rate_min, rate_max;
+ unsigned int channels_min, channels_max;
+ unsigned int format, format_mask;
+ size_t fragment_size_min, fragment_size_max;
+
+ info->access_mask &= (SND_PCM_ACCBIT_MMAP_INTERLEAVED |
+ SND_PCM_ACCBIT_RW_INTERLEAVED |
+ SND_PCM_ACCBIT_MMAP_NONINTERLEAVED |
+ SND_PCM_ACCBIT_RW_NONINTERLEAVED);
+ if (info->access_mask == 0)
+ return -EINVAL;
- if (info->req_mask & SND_PCM_PARAMS_RATE) {
- info->min_rate = info->req.format.rate;
- info->max_rate = info->req.format.rate;
- } else {
- info->min_rate = 4000;
- info->max_rate = 192000;
- }
- info->rates = SND_PCM_RATE_CONTINUOUS | SND_PCM_RATE_8000_192000;
+ info->format_mask &= (SND_PCM_FMTBIT_LINEAR | SND_PCM_FMTBIT_MU_LAW |
+ SND_PCM_FMTBIT_A_LAW | SND_PCM_FMTBIT_IMA_ADPCM);
+ if (info->format_mask == 0)
+ return -EINVAL;
- if (info->req_mask & SND_PCM_PARAMS_CHANNELS) {
- info->min_channels = info->req.format.channels;
- info->max_channels = info->req.format.channels;
- } else {
- info->min_channels = 1;
- info->max_channels = 32;
- }
+ if (info->rate_min < 4000)
+ info->rate_min = 4000;
+ if (info->rate_max > 192000)
+ info->rate_max = 192000;
+ if (info->rate_max < info->rate_min)
+ return -EINVAL;
- memset(&slave_info, 0, sizeof(slave_info));
- if ((err = snd_pcm_params_info(slave, &slave_info)) < 0)
- return err;
+ if (info->channels_min < 1)
+ info->channels_min = 1;
+ if (info->channels_max > 1024)
+ info->channels_max = 1024;
+ if (info->channels_max < info->channels_min)
+ return -EINVAL;
- info->flags = slave_info.flags;
- info->flags |= SND_PCM_INFO_INTERLEAVED | SND_PCM_INFO_NONINTERLEAVED;
+ if (info->fragment_size_max > 1024 * 1024)
+ info->fragment_size_max = 1024 * 1024;
+ if (info->fragment_size_max < info->fragment_size_min)
+ return -EINVAL;
- info->min_fragments = slave_info.min_fragments;
- info->max_fragments = slave_info.max_fragments;
-
- 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;
+ sinfo.access_mask = SND_PCM_ACCBIT_MMAP;
+ sinfo.format_mask = (SND_PCM_FMTBIT_LINEAR | SND_PCM_FMTBIT_MU_LAW |
+ SND_PCM_FMTBIT_A_LAW | SND_PCM_FMTBIT_IMA_ADPCM);
+ sinfo.subformat_mask = SND_PCM_SUBFMTBIT_STD;
+ sinfo.channels_min = 1;
+ sinfo.channels_max = 1024;
+ sinfo.rate_min = 4000;
+ sinfo.rate_max = 192000;
+ sinfo.fragments_min = 1;
+ sinfo.fragments_max = UINT_MAX;
+ sinfo.fragment_size_min = 1;
+ sinfo.fragment_size_max = ULONG_MAX;
+
+ /* Formats */
+ err = snd_pcm_hw_info(slave, &sinfo);
+ if (err < 0) {
+ *info = i;
+ return err;
}
-
- 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;
+ format_mask = 0;
+ for (format = 0; format < SND_PCM_FORMAT_LAST; ++format) {
+ if (!(info->format_mask & (1 << format)))
+ continue;
+ err = snd_pcm_plug_slave_fmt(format, sinfo.format_mask);
+ if (err < 0)
+ info->format_mask &= ~(1 << format);
+ else
+ format_mask |= (1 << err);
}
-
- if (!(info->req_mask & SND_PCM_PARAMS_RATE))
- return 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;
+ sinfo.format_mask = format_mask;
+
+ /* Rate (and fragment_size) */
+ i = sinfo;
+ sparams.rate = info->rate_min;
+ err = snd_pcm_hw_info_rulesv(slave, &i, &sparams,
+ SND_PCM_RULE_REL_NEAR | SND_PCM_HW_PARAM_RATE,
+ -1);
+ if (err < 0) {
+ *info = i;
+ return err;
}
-
- if (!(info->req_mask & SND_PCM_PARAMS_CHANNELS))
- return 0;
- 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_SFMT |
- SND_PCM_PARAMS_CHANNELS |
- SND_PCM_PARAMS_RATE);
- 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;
+ rate_min = i.rate_min;
+ if (info->rate_max != info->rate_min) {
+ i = sinfo;
+ sparams.rate = info->rate_max;
+ err = snd_pcm_hw_info_rulesv(slave, &i, &sparams,
+ SND_PCM_RULE_REL_NEAR | SND_PCM_HW_PARAM_RATE,
+ -1);
+ if (err < 0) {
+ *info = i;
+ return err;
+ }
+ rate_max = i.rate_min;
+ } else
+ rate_max = rate_min;
+ sinfo.rate_min = rate_min;
+ sinfo.rate_max = rate_max;
+
+ /* Channels */
+ i = sinfo;
+ sparams.channels = info->channels_min;
+ err = snd_pcm_hw_info_rulesv(slave, &i, &sparams,
+ SND_PCM_RULE_REL_NEAR | SND_PCM_HW_PARAM_CHANNELS,
+ -1);
+ if (err < 0) {
+ *info = i;
+ return err;
+ }
+ channels_min = i.channels_min;
+ if (info->channels_max != info->channels_min) {
+ i = sinfo;
+ sparams.channels = info->channels_max;
+ err = snd_pcm_hw_info_rulesv(slave, &i, &sparams,
+ SND_PCM_RULE_REL_NEAR | SND_PCM_HW_PARAM_CHANNELS,
+ -1);
+ if (err < 0) {
+ *info = i;
+ return err;
+ }
+ channels_max = i.channels_min;
+ } else
+ channels_max = channels_min;
+ sinfo.channels_min = channels_min;
+ sinfo.channels_max = channels_max;
+
+ sinfo.fragments_min = info->fragments_min;
+ sinfo.fragments_max = info->fragments_max;
+ sinfo.fragment_size_min = muldiv_down(info->fragment_size_min, sinfo.rate_min, info->rate_max);
+ sinfo.fragment_size_max = muldiv_up(info->fragment_size_max, sinfo.rate_max, info->rate_min);
+ err = snd_pcm_hw_info(slave, &sinfo);
+ if (err < 0) {
+ *info = sinfo;
return err;
}
- 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);
+
+ info->subformat_mask = sinfo.subformat_mask;
+ info->fragments_min = sinfo.fragments_min;
+ info->fragments_max = sinfo.fragments_max;
+
+ fragment_size_min = muldiv_down(sinfo.fragment_size_min, info->rate_min, sinfo.rate_max);
+ fragment_size_max = muldiv_up(sinfo.fragment_size_max, info->rate_max, sinfo.rate_min);
+ if (fragment_size_min > info->fragment_size_min)
+ info->fragment_size_min = fragment_size_min;
+ if (fragment_size_max < info->fragment_size_max)
+ info->fragment_size_max = fragment_size_max;
+ info->info = sinfo.info & ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
+ snd_pcm_hw_info_complete(info);
return 0;
}
@@ -313,29 +304,29 @@ static void snd_pcm_plug_clear(snd_pcm_t *pcm)
}
}
-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)
+static int snd_pcm_plug_change_rate(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_hw_params_t *clt, snd_pcm_hw_params_t *slv)
{
snd_pcm_plug_t *plug = pcm->private;
int err;
- assert(snd_pcm_format_linear(slv->sfmt));
+ assert(snd_pcm_format_linear(slv->format));
if (clt->rate == slv->rate)
return 0;
- err = snd_pcm_rate_open(new, NULL, slv->sfmt, slv->rate, plug->slave, plug->slave != plug->req_slave);
+ err = snd_pcm_rate_open(new, NULL, slv->format, slv->rate, plug->slave, plug->slave != plug->req_slave);
if (err < 0)
return err;
slv->rate = clt->rate;
- if (snd_pcm_format_linear(clt->sfmt))
- slv->sfmt = clt->sfmt;
+ if (snd_pcm_format_linear(clt->format))
+ slv->format = clt->format;
return 1;
}
-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)
+static int snd_pcm_plug_change_channels(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_hw_params_t *clt, snd_pcm_hw_params_t *slv)
{
snd_pcm_plug_t *plug = pcm->private;
unsigned int tt_ssize, tt_cused, tt_sused;
ttable_entry_t *ttable;
int err;
- assert(snd_pcm_format_linear(slv->sfmt));
+ assert(snd_pcm_format_linear(slv->format));
if (clt->channels == slv->channels)
return 0;
if (clt->rate != slv->rate &&
@@ -384,100 +375,100 @@ static int snd_pcm_plug_change_channels(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm
s = 0;
}
}
- err = snd_pcm_route_open(new, NULL, slv->sfmt, slv->channels, ttable, tt_ssize, tt_cused, tt_sused, plug->slave, plug->slave != plug->req_slave);
+ err = snd_pcm_route_open(new, NULL, slv->format, slv->channels, ttable, tt_ssize, tt_cused, tt_sused, plug->slave, plug->slave != plug->req_slave);
if (err < 0)
return err;
slv->channels = clt->channels;
- if (snd_pcm_format_linear(clt->sfmt))
- slv->sfmt = clt->sfmt;
+ if (snd_pcm_format_linear(clt->format))
+ slv->format = clt->format;
return 1;
}
-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)
+static int snd_pcm_plug_change_format(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_hw_params_t *clt, snd_pcm_hw_params_t *slv)
{
snd_pcm_plug_t *plug = pcm->private;
int err, cfmt;
int (*f)(snd_pcm_t **pcm, char *name, int sformat, snd_pcm_t *slave, int close_slave);
- if (snd_pcm_format_linear(slv->sfmt)) {
+ if (snd_pcm_format_linear(slv->format)) {
/* Conversion is done in another plugin */
- if (clt->sfmt == slv->sfmt ||
+ if (clt->format == slv->format ||
clt->rate != slv->rate ||
clt->channels != slv->channels)
return 0;
} else {
/* No conversion is needed */
- if (clt->sfmt == slv->sfmt &&
+ if (clt->format == slv->format &&
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:
+ if (snd_pcm_format_linear(slv->format)) {
+ cfmt = clt->format;
+ switch (clt->format) {
+ case SND_PCM_FORMAT_MU_LAW:
f = snd_pcm_mulaw_open;
break;
- case SND_PCM_SFMT_A_LAW:
+ case SND_PCM_FORMAT_A_LAW:
f = snd_pcm_alaw_open;
break;
- case SND_PCM_SFMT_IMA_ADPCM:
+ case SND_PCM_FORMAT_IMA_ADPCM:
f = snd_pcm_adpcm_open;
break;
default:
- assert(snd_pcm_format_linear(clt->sfmt));
+ assert(snd_pcm_format_linear(clt->format));
f = snd_pcm_linear_open;
break;
}
} else {
- switch (slv->sfmt) {
- case SND_PCM_SFMT_MU_LAW:
+ switch (slv->format) {
+ case SND_PCM_FORMAT_MU_LAW:
f = snd_pcm_mulaw_open;
break;
- case SND_PCM_SFMT_A_LAW:
+ case SND_PCM_FORMAT_A_LAW:
f = snd_pcm_alaw_open;
break;
- case SND_PCM_SFMT_IMA_ADPCM:
+ case SND_PCM_FORMAT_IMA_ADPCM:
f = snd_pcm_adpcm_open;
break;
default:
assert(0);
return -EINVAL;
}
- if (snd_pcm_format_linear(clt->sfmt))
- cfmt = clt->sfmt;
+ if (snd_pcm_format_linear(clt->format))
+ cfmt = clt->format;
else
- cfmt = SND_PCM_SFMT_S16;
+ cfmt = SND_PCM_FORMAT_S16;
}
- err = f(new, NULL, slv->sfmt, plug->slave, plug->slave != plug->req_slave);
+ err = f(new, NULL, slv->format, plug->slave, plug->slave != plug->req_slave);
if (err < 0)
return err;
- slv->sfmt = cfmt;
+ slv->format = cfmt;
return 1;
}
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_hw_params_t *client,
+ snd_pcm_hw_params_t *slave)
{
snd_pcm_plug_t *plug = pcm->private;
- int (*funcs[])(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_format_t *s, snd_pcm_format_t *d) = {
+ int (*funcs[])(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_hw_params_t *s, snd_pcm_hw_params_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;
+ snd_pcm_hw_params_t p = *slave;
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)
+ if (client->format == p.format &&
+ client->channels == p.channels &&
+ client->rate == p.rate)
return 0;
assert(k < sizeof(funcs)/sizeof(*funcs));
- err = funcs[k](pcm, &new, client_fmt, &sfmt);
+ err = funcs[k](pcm, &new, client, &p);
if (err < 0) {
snd_pcm_plug_clear(pcm);
return err;
@@ -493,134 +484,118 @@ static int snd_pcm_plug_insert_plugins(snd_pcm_t *pcm,
return 0;
}
-static int snd_pcm_plug_params(snd_pcm_t *pcm, snd_pcm_params_t *params)
+static int snd_pcm_plug_hw_params(snd_pcm_t *pcm, snd_pcm_hw_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;
+ snd_pcm_hw_info_t sinfo;
+ snd_pcm_hw_params_t sparams;
int err;
-
- memset(&slave_info, 0, sizeof(slave_info));
- err = snd_pcm_params_info(slave, &slave_info);
- assert(err >= 0);
- if (err < 0)
+ sparams = *params;
+ snd_pcm_hw_params_to_info(&sparams, &sinfo);
+ sinfo.access_mask = SND_PCM_ACCBIT_MMAP;
+ sinfo.format_mask = (SND_PCM_FMTBIT_LINEAR | SND_PCM_FMTBIT_MU_LAW |
+ SND_PCM_FMTBIT_A_LAW | SND_PCM_FMTBIT_IMA_ADPCM);
+ sinfo.subformat_mask = SND_PCM_SUBFMTBIT_STD;
+ sinfo.channels_min = 1;
+ sinfo.channels_max = 1024;
+ sinfo.rate_min = 4000;
+ sinfo.rate_max = 192000;
+ sinfo.fragment_size_min = 1;
+ sinfo.fragment_size_max = ULONG_MAX;
+ err = snd_pcm_hw_info_rulesv(slave, &sinfo, params,
+ SND_PCM_RULE_REL_NEAR | SND_PCM_HW_PARAM_RATE,
+ SND_PCM_RULE_REL_NEAR | SND_PCM_HW_PARAM_CHANNELS,
+ -1);
+ if (err < 0) {
+ snd_pcm_hw_info_to_params_fail(&sinfo, params);
return err;
-
- slave_info.req = *params;
- format = &params->format;
- slave_format = &slave_info.req.format;
-
- 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 |= SND_PCM_PARAMS_RATE;
- err = snd_pcm_params_info(slave, &slave_info);
- assert(err >= 0);
+ err = snd_pcm_plug_slave_fmt(sparams.format, sinfo.format_mask);
if (err < 0)
return err;
-
- 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;
-
- 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;
- slave_info.req_mask |= SND_PCM_PARAMS_CHANNELS;
- err = snd_pcm_params_info(slave, &slave_info);
- assert(err >= 0);
- if (err < 0)
+ sparams.format = err;
+ sinfo.format_mask = 1U << err;
+ sparams.fragment_size = muldiv_near(params->fragment_size, sparams.rate, params->rate);
+ err = snd_pcm_hw_info_rulesv(slave, &sinfo, &sparams,
+ SND_PCM_RULE_REL_NEAR | SND_PCM_HW_PARAM_FRAGMENT_SIZE,
+ -1);
+ if (err < 0) {
+ snd_pcm_hw_info_to_params_fail(&sinfo, params);
return err;
-
- 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;
- }
- slave_info.req_mask |= SND_PCM_PARAMS_SFMT;
-
- if (slave_info.formats != 1U << slave_format->sfmt) {
- err = snd_pcm_params_info(slave, &slave_info);
- assert(err >= 0);
- if (err < 0)
- return err;
}
+ if (sinfo.access_mask & SND_PCM_ACCBIT_MMAP_INTERLEAVED)
+ sparams.access = SND_PCM_ACCESS_MMAP_INTERLEAVED;
+ else if (sinfo.access_mask & SND_PCM_ACCBIT_MMAP_NONINTERLEAVED)
+ sparams.access = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;
+ else
+ assert(0);
- err = snd_pcm_plug_insert_plugins(pcm, format, slave_format);
+ err = snd_pcm_plug_insert_plugins(pcm, params, &sparams);
if (err < 0)
return err;
- err = snd_pcm_params(plug->slave, params);
+ err = snd_pcm_hw_params(plug->slave, params);
if (err < 0) {
snd_pcm_plug_clear(pcm);
return err;
}
- assert(slave->setup.format.sfmt == slave_format->sfmt);
- assert(slave->setup.format.channels == slave_format->channels);
- assert(slave->setup.format.rate == slave_format->rate);
pcm->hw_ptr = slave->hw_ptr;
pcm->appl_ptr = slave->appl_ptr;
return 0;
}
-static int snd_pcm_plug_setup(snd_pcm_t *pcm, snd_pcm_setup_t *setup)
+static int snd_pcm_plug_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params)
{
snd_pcm_plug_t *plug = pcm->private;
- return snd_pcm_setup(plug->slave, setup);
+ snd_pcm_t *slave = plug->req_slave;
+ size_t avail_min, xfer_min, xfer_align;
+ int err;
+ avail_min = params->avail_min;
+ xfer_min = params->xfer_min;
+ xfer_align = params->xfer_align;
+ params->avail_min = muldiv_near(params->avail_min, slave->rate, pcm->rate);
+ params->xfer_min = muldiv_near(params->xfer_min, slave->rate, pcm->rate);
+ params->xfer_align = muldiv_near(params->xfer_align, slave->rate, pcm->rate);
+ err = snd_pcm_sw_params(slave, params);
+ params->avail_min = avail_min;
+ params->xfer_min = xfer_min;
+ params->xfer_align = xfer_align;
+ params->boundary = LONG_MAX - pcm->buffer_size * 2 - LONG_MAX % pcm->buffer_size;
+ return err;
}
-static int snd_pcm_plug_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info)
+static int snd_pcm_plug_dig_info(snd_pcm_t *pcm, snd_pcm_dig_info_t * info)
{
snd_pcm_plug_t *plug = pcm->private;
- return snd_pcm_channel_info(plug->slave, info);
+ return snd_pcm_dig_info(plug->slave, info);
}
-static int snd_pcm_plug_channel_params(snd_pcm_t *pcm, snd_pcm_channel_params_t *params)
+static int snd_pcm_plug_dig_params(snd_pcm_t *pcm, snd_pcm_dig_params_t * params)
{
snd_pcm_plug_t *plug = pcm->private;
- return snd_pcm_channel_params(plug->slave, params);
+ return snd_pcm_dig_params(plug->slave, params);
}
-static int snd_pcm_plug_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t *setup)
+
+static int snd_pcm_plug_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info)
{
snd_pcm_plug_t *plug = pcm->private;
- return snd_pcm_channel_setup(plug->slave, setup);
+ return snd_pcm_channel_info(plug->slave, info);
}
static int snd_pcm_plug_mmap(snd_pcm_t *pcm)
{
- snd_pcm_plug_t *plug = pcm->private;
- int err = snd_pcm_mmap(plug->slave);
- if (err < 0)
- return err;
- pcm->mmap_info_count = plug->slave->mmap_info_count;
- pcm->mmap_info = plug->slave->mmap_info;
- return 0;
+ snd_pcm_plugin_t *plug = pcm->private;
+ return snd_pcm_mmap(plug->slave);
}
static int snd_pcm_plug_munmap(snd_pcm_t *pcm)
{
- snd_pcm_plug_t *plug = pcm->private;
- int err = snd_pcm_munmap(plug->slave);
- if (err < 0)
- return err;
- pcm->mmap_info_count = 0;
- pcm->mmap_info = 0;
- return 0;
+ snd_pcm_plugin_t *plug = pcm->private;
+ return snd_pcm_munmap(plug->slave);
}
-
+
static void snd_pcm_plug_dump(snd_pcm_t *pcm, FILE *fp)
{
snd_pcm_plug_t *plug = pcm->private;
@@ -631,12 +606,12 @@ static void snd_pcm_plug_dump(snd_pcm_t *pcm, FILE *fp)
snd_pcm_ops_t 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,
+ hw_info: snd_pcm_plug_hw_info,
+ hw_params: snd_pcm_plug_hw_params,
+ sw_params: snd_pcm_plug_sw_params,
+ dig_info: snd_pcm_plug_dig_info,
+ dig_params: snd_pcm_plug_dig_params,
channel_info: snd_pcm_plug_channel_info,
- channel_params: snd_pcm_plug_channel_params,
- channel_setup: snd_pcm_plug_channel_setup,
dump: snd_pcm_plug_dump,
nonblock: snd_pcm_plug_nonblock,
async: snd_pcm_plug_async,
@@ -687,19 +662,14 @@ int snd_pcm_plug_open(snd_pcm_t **pcmp,
return 0;
}
-int snd_pcm_plug_open_subdevice(snd_pcm_t **pcmp, int card, int device, int subdevice, int stream, int mode)
+int snd_pcm_plug_open_hw(snd_pcm_t **pcmp, char *name, int card, int device, int subdevice, int stream, int mode)
{
snd_pcm_t *slave;
int err;
- err = snd_pcm_hw_open_subdevice(&slave, card, device, subdevice, stream, mode);
+ err = snd_pcm_hw_open(&slave, NULL, card, device, subdevice, stream, mode);
if (err < 0)
return err;
- return snd_pcm_plug_open(pcmp, NULL, 0, 0, 0, 0, slave, 1);
-}
-
-int snd_pcm_plug_open_device(snd_pcm_t **pcmp, int card, int device, int stream, int mode)
-{
- return snd_pcm_plug_open_subdevice(pcmp, card, device, -1, stream, mode);
+ return snd_pcm_plug_open(pcmp, name, 0, 0, 0, 0, slave, 1);
}
#define MAX_CHANNELS 32
diff --git a/src/pcm/pcm_plugin.c b/src/pcm/pcm_plugin.c
index 9929558f..9dd4e612 100644
--- a/src/pcm/pcm_plugin.c
+++ b/src/pcm/pcm_plugin.c
@@ -52,38 +52,28 @@ int snd_pcm_plugin_info(snd_pcm_t *pcm, snd_pcm_info_t * info)
return snd_pcm_info(plugin->slave, info);
}
-int snd_pcm_plugin_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info)
+int snd_pcm_plugin_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)
{
snd_pcm_plugin_t *plugin = pcm->private;
- return snd_pcm_channel_info(plugin->slave, info);
+ return snd_pcm_sw_params(plugin->slave, params);
}
-int snd_pcm_plugin_channel_params(snd_pcm_t *pcm, snd_pcm_channel_params_t * params)
+int snd_pcm_plugin_dig_info(snd_pcm_t *pcm, snd_pcm_dig_info_t *info)
{
snd_pcm_plugin_t *plugin = pcm->private;
- return snd_pcm_channel_params(plugin->slave, params);
+ return snd_pcm_dig_info(plugin->slave, info);
}
-int snd_pcm_plugin_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t * setup)
+int snd_pcm_plugin_dig_params(snd_pcm_t *pcm, snd_pcm_dig_params_t *params)
{
snd_pcm_plugin_t *plugin = pcm->private;
- int err;
- err = snd_pcm_channel_setup(plugin->slave, setup);
- if (err < 0)
- return err;
- if (!pcm->mmap_info)
- return 0;
- if (pcm->setup.mmap_shape == SND_PCM_MMAP_INTERLEAVED) {
- setup->running_area.addr = pcm->mmap_info->addr;
- setup->running_area.first = setup->channel * pcm->bits_per_sample;
- setup->running_area.step = pcm->bits_per_frame;
- } else {
- setup->running_area.addr = pcm->mmap_info->addr + setup->channel * pcm->setup.buffer_size * pcm->bits_per_sample / 8;
- setup->running_area.first = 0;
- setup->running_area.step = pcm->bits_per_sample;
- }
- setup->stopped_area = setup->running_area;
- return 0;
+ return snd_pcm_dig_params(plugin->slave, params);
+}
+
+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_shm(pcm, info, plugin->shmid);
}
int snd_pcm_plugin_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
@@ -185,7 +175,7 @@ ssize_t snd_pcm_plugin_rewind(snd_pcm_t *pcm, size_t frames)
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];
+ snd_pcm_channel_area_t areas[pcm->channels];
ssize_t frames;
snd_pcm_areas_from_buf(pcm, areas, (void*)buffer);
frames = snd_pcm_write_areas(pcm, areas, 0, size, plugin->write);
@@ -197,7 +187,7 @@ 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)
{
snd_pcm_plugin_t *plugin = pcm->private;
- snd_pcm_channel_area_t areas[pcm->setup.format.channels];
+ snd_pcm_channel_area_t areas[pcm->channels];
ssize_t frames;
snd_pcm_areas_from_bufs(pcm, areas, bufs);
frames = snd_pcm_write_areas(pcm, areas, 0, size, plugin->write);
@@ -209,7 +199,7 @@ 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)
{
snd_pcm_plugin_t *plugin = pcm->private;
- snd_pcm_channel_area_t areas[pcm->setup.format.channels];
+ snd_pcm_channel_area_t areas[pcm->channels];
ssize_t frames;
snd_pcm_areas_from_buf(pcm, areas, buffer);
frames = snd_pcm_read_areas(pcm, areas, 0, size, plugin->read);
@@ -221,7 +211,7 @@ 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)
{
snd_pcm_plugin_t *plugin = pcm->private;
- snd_pcm_channel_area_t areas[pcm->setup.format.channels];
+ snd_pcm_channel_area_t areas[pcm->channels];
ssize_t frames;
snd_pcm_areas_from_bufs(pcm, areas, bufs);
frames = snd_pcm_read_areas(pcm, areas, 0, size, plugin->read);
@@ -251,7 +241,7 @@ ssize_t snd_pcm_plugin_mmap_forward(snd_pcm_t *pcm, size_t client_size)
size_t slave_frames = slave_size - slave_xfer;
size_t client_frames = client_size - client_xfer;
size_t offset = snd_pcm_mmap_hw_offset(pcm);
- size_t cont = pcm->setup.buffer_size - offset;
+ size_t cont = pcm->buffer_size - offset;
if (cont < client_frames)
client_frames = cont;
err = plugin->write(pcm, pcm->running_areas, offset,
@@ -279,17 +269,18 @@ ssize_t snd_pcm_plugin_avail_update(snd_pcm_t *pcm)
if (slave_size <= 0)
return slave_size;
if (pcm->stream == SND_PCM_STREAM_PLAYBACK ||
- !pcm->mmap_info)
+ pcm->access == SND_PCM_ACCESS_RW_INTERLEAVED ||
+ pcm->access == SND_PCM_ACCESS_RW_NONINTERLEAVED)
return plugin->client_frames ?
plugin->client_frames(pcm, slave_size) : slave_size;
client_xfer = snd_pcm_mmap_capture_avail(pcm);
- client_size = pcm->setup.buffer_size;
+ client_size = pcm->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 offset = snd_pcm_mmap_hw_offset(pcm);
- size_t cont = pcm->setup.buffer_size - offset;
+ size_t cont = pcm->buffer_size - offset;
if (cont < client_frames)
client_frames = cont;
err = plugin->read(pcm, pcm->running_areas, offset,
@@ -313,38 +304,26 @@ int snd_pcm_plugin_set_avail_min(snd_pcm_t *pcm, size_t frames)
int snd_pcm_plugin_mmap(snd_pcm_t *pcm)
{
- snd_pcm_plugin_t *plugin = pcm->private;
- snd_pcm_t *slave = plugin->slave;
- snd_pcm_mmap_info_t *i;
- int err = snd_pcm_mmap(slave);
- if (err < 0)
- return err;
- i = calloc(1, sizeof(*i));
- if (!i)
- return -ENOMEM;
- err = snd_pcm_alloc_user_mmap(pcm, i);
- if (err < 0) {
- free(i);
- return err;
+ snd_pcm_plugin_t *plug = pcm->private;
+ if (!(pcm->info & SND_PCM_INFO_MMAP)) {
+ size_t size = snd_pcm_frames_to_bytes(pcm, pcm->buffer_size);
+ int id = shmget(IPC_PRIVATE, size, 0666);
+ if (id < 0) {
+ SYSERR("shmget failed");
+ return -errno;
+ }
+ plug->shmid = id;
}
- pcm->mmap_info = i;
- pcm->mmap_info_count = 1;
return 0;
}
int snd_pcm_plugin_munmap(snd_pcm_t *pcm)
{
- snd_pcm_plugin_t *plugin = pcm->private;
- snd_pcm_t *slave = plugin->slave;
- int err = snd_pcm_munmap(slave);
- if (err < 0)
- return err;
- err = snd_pcm_free_mmap(pcm, pcm->mmap_info);
- if (err < 0)
- return err;
- free(pcm->mmap_info);
- pcm->mmap_info_count = 0;
- pcm->mmap_info = 0;
+ snd_pcm_plugin_t *plug = pcm->private;
+ if (shmctl(plug->shmid, IPC_RMID, 0) < 0) {
+ SYSERR("shmctl IPC_RMID failed");
+ return -errno;
+ }
return 0;
}
diff --git a/src/pcm/pcm_plugin.h b/src/pcm/pcm_plugin.h
index b0275fd8..4047ffb7 100644
--- a/src/pcm/pcm_plugin.h
+++ b/src/pcm/pcm_plugin.h
@@ -24,18 +24,21 @@ typedef struct {
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);
+ ssize_t (*client_frames)(snd_pcm_t *pcm, ssize_t frames);
int (*init)(snd_pcm_t *pcm);
+ int shmid;
size_t appl_ptr, hw_ptr;
+ unsigned int saccess_mask;
} 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_async(snd_pcm_t *pcm, int sig, pid_t pid);
int snd_pcm_plugin_info(snd_pcm_t *pcm, snd_pcm_info_t * info);
+int snd_pcm_plugin_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *params);
+int snd_pcm_plugin_dig_info(snd_pcm_t *pcm, snd_pcm_dig_info_t *info);
+int snd_pcm_plugin_dig_params(snd_pcm_t *pcm, snd_pcm_dig_params_t *params);
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);
@@ -58,22 +61,34 @@ 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(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 get_index(int src_format, int dst_format);
int put_index(int src_format, int dst_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)
+#define SND_PCM_FMTBIT_LINEAR (SND_PCM_FMTBIT_S8 |SND_PCM_FMTBIT_U8 | \
+ SND_PCM_FMTBIT_S16_LE|SND_PCM_FMTBIT_S16_BE | \
+ SND_PCM_FMTBIT_U16_LE|SND_PCM_FMTBIT_U16_BE | \
+ SND_PCM_FMTBIT_S24_LE|SND_PCM_FMTBIT_S24_BE | \
+ SND_PCM_FMTBIT_U24_LE|SND_PCM_FMTBIT_U24_BE | \
+ SND_PCM_FMTBIT_S32_LE|SND_PCM_FMTBIT_S32_BE | \
+ SND_PCM_FMTBIT_U32_LE|SND_PCM_FMTBIT_U32_BE)
extern snd_pcm_fast_ops_t snd_pcm_plugin_fast_ops;
-#define muldiv64(a,b,d) (((int64_t)(a) * (b) + (b) / 2) / (d))
+static inline ssize_t muldiv_down(ssize_t a, ssize_t b, ssize_t d)
+{
+ return (int64_t) (a * b) / d;
+}
+
+static inline ssize_t muldiv_up(ssize_t a, ssize_t b, ssize_t d)
+{
+ return (int64_t) (a * b + (d - 1)) / d;
+}
+
+static inline ssize_t muldiv_near(ssize_t a, ssize_t b, ssize_t d)
+{
+ return (int64_t) (a * b + (d / 2)) / d;
+}
#define ROUTE_PLUGIN_FLOAT 1
#define ROUTE_PLUGIN_RESOLUTION 16
diff --git a/src/pcm/pcm_rate.c b/src/pcm/pcm_rate.c
index 8893f268..8684ccec 100644
--- a/src/pcm/pcm_rate.c
+++ b/src/pcm/pcm_rate.c
@@ -48,13 +48,8 @@ typedef struct {
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;
@@ -93,7 +88,7 @@ static size_t resample_expand(snd_pcm_channel_area_t *src_areas,
#if 0
if (!src_area->enabled) {
if (dst_area->wanted)
- snd_pcm_area_silence(&dst_area->area, 0, dst_frames, plugin->dst_format.sfmt);
+ snd_pcm_area_silence(&dst_area->area, 0, dst_frames, plugin->dst_format);
dst_area->enabled = 0;
continue;
}
@@ -177,7 +172,7 @@ static size_t resample_shrink(snd_pcm_channel_area_t *src_areas,
#if 0
if (!src_area->enabled) {
if (dst_area->wanted)
- snd_pcm_area_silence(&dst_area->area, 0, dst_frames, plugin->dst_format.sfmt);
+ snd_pcm_area_silence(&dst_area->area, 0, dst_frames, plugin->dst_format);
dst_area->enabled = 0;
continue;
}
@@ -238,142 +233,132 @@ static int snd_pcm_rate_close(snd_pcm_t *pcm)
return 0;
}
-static int snd_pcm_rate_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t * info)
+static int snd_pcm_rate_hw_info(snd_pcm_t *pcm, snd_pcm_hw_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;
+ snd_pcm_hw_info_t sinfo;
+ unsigned int access_mask;
+ size_t fragment_size_min, fragment_size_max;
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;
+ info->access_mask &= (SND_PCM_ACCBIT_MMAP_INTERLEAVED |
+ SND_PCM_ACCBIT_RW_INTERLEAVED |
+ SND_PCM_ACCBIT_MMAP_NONINTERLEAVED |
+ SND_PCM_ACCBIT_RW_NONINTERLEAVED);
+ access_mask = info->access_mask;
+ if (access_mask == 0)
return -EINVAL;
+ info->format_mask &= SND_PCM_FMTBIT_LINEAR;
+ if (info->format_mask == 0)
+ return -EINVAL;
+ if (info->rate_min < 4000)
+ info->rate_min = 4000;
+ if (info->rate_max > 192000)
+ info->rate_max = 192000;
+ if (info->rate_max < info->rate_min)
+ return -EINVAL;
+ if (info->fragment_size_max > 1024 * 1024)
+ info->fragment_size_max = 1024 * 1024;
+ if (info->fragment_size_max < info->fragment_size_min)
+ return -EINVAL;
+ sinfo = *info;
+
+ sinfo.rate_min = rate->srate;
+ sinfo.rate_max = rate->srate;
+ if (rate->sformat >= 0)
+ sinfo.format_mask = 1U << rate->sformat;
+ sinfo.fragment_size_min = muldiv_down(info->fragment_size_min, sinfo.rate_min, info->rate_max);
+ sinfo.fragment_size_max = muldiv_up(info->fragment_size_max, sinfo.rate_max, info->rate_min);
+
+ sinfo.access_mask = SND_PCM_ACCBIT_MMAP;
+ err = snd_pcm_hw_info(rate->plug.slave, &sinfo);
+ info->subformat_mask = sinfo.subformat_mask;
+ info->channels_min = sinfo.channels_min;
+ info->channels_max = sinfo.channels_max;
+ info->fragments_min = sinfo.fragments_min;
+ info->fragments_max = sinfo.fragments_max;
+
+ if (!sinfo.access_mask) {
+ info->access_mask = 0;
}
- if (rate->req_sformat >= 0) {
- info->req_mask |= SND_PCM_PARAMS_SFMT;
- info->req.format.sfmt = rate->req_sformat;
+ if (!sinfo.format_mask) {
+ info->format_mask = 0;
+ }
+ if (sinfo.rate_min > sinfo.rate_max) {
+ info->rate_min = UINT_MAX;
+ info->rate_max = 0;
+ }
+ if (sinfo.fragment_size_min > sinfo.fragment_size_max) {
+ info->fragment_size_min = ULONG_MAX;
+ info->fragment_size_max = 0;
}
- 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;
+
+ fragment_size_min = muldiv_down(sinfo.fragment_size_min, info->rate_min, sinfo.rate_max);
+ fragment_size_max = muldiv_up(sinfo.fragment_size_max, info->rate_max, sinfo.rate_min);
+ if (fragment_size_min > info->fragment_size_min)
+ info->fragment_size_min = fragment_size_min;
+ if (fragment_size_max < info->fragment_size_max)
+ info->fragment_size_max = fragment_size_max;
+ rate->plug.saccess_mask = sinfo.access_mask;
+ info->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
+ snd_pcm_hw_info_complete(info);
return 0;
}
-static int snd_pcm_rate_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
+static int snd_pcm_rate_hw_params(snd_pcm_t *pcm, snd_pcm_hw_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;
+ snd_pcm_hw_info_t sinfo;
+ unsigned int format, access, crate;
+ unsigned int src_format, dst_format;
+ unsigned int src_rate, dst_rate;
+ size_t fragment_size;
+ int mul, div;
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_params.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 (rate->req_srate - slave_info.min_rate < slave_info.max_rate - rate->req_srate)
- srate = slave_info.min_rate;
+ crate = params->rate;
+ format = params->format;
+ fragment_size = params->fragment_size;
+ access = params->access;
+ params->rate = rate->srate;
+ if (rate->sformat >= 0)
+ params->format = rate->sformat;
+ if (rate->plug.saccess_mask & SND_PCM_ACCBIT_MMAP_INTERLEAVED)
+ params->access = SND_PCM_ACCESS_MMAP_INTERLEAVED;
+ else if (rate->plug.saccess_mask & SND_PCM_ACCBIT_MMAP_NONINTERLEAVED)
+ params->access = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;
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);
- /* FIXME: boundary? */
- slave_params.xfer_mode = SND_PCM_XFER_UNSPECIFIED;
- slave_params.mmap_shape = SND_PCM_MMAP_UNSPECIFIED;
- err = snd_pcm_params_mmap(slave, &slave_params);
- params->fail_mask = slave_params.fail_mask;
- params->fail_reason = slave_params.fail_reason;
- 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);
+ assert(0);
+ params->fragment_size = muldiv_near(params->fragment_size, params->rate, crate);
+ snd_pcm_hw_params_to_info(params, &sinfo);
+ sinfo.fragment_size_min = 0;
+ sinfo.fragment_size_max = ULONG_MAX;
+ err = snd_pcm_hw_info_rulesv(slave, &sinfo, params,
+ SND_PCM_RULE_REL_NEAR | SND_PCM_HW_PARAM_FRAGMENT_SIZE,
+ -1);
+ snd_pcm_hw_info_to_params(&sinfo, params);
+ if (err >= 0)
+ err = snd_pcm_hw_params(slave, params);
+ params->format = format;
+ params->rate = crate;
+ params->access = access;
+ params->fragment_size = fragment_size;
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;
+ src_format = format;
+ dst_format = slave->format;
+ src_rate = crate;
+ dst_rate = slave->rate;
} else {
- src_format = rate->sformat;
- dst_format = rate->cformat;
- src_rate = rate->srate;
- dst_rate = rate->crate;
+ src_format = slave->format;
+ dst_format = format;
+ src_rate = slave->rate;
+ dst_rate = crate;
}
- rate->get_idx = get_index(src_format, SND_PCM_SFMT_S16);
- rate->put_idx = put_index(SND_PCM_SFMT_S16, dst_format);
+ rate->get_idx = get_index(src_format, SND_PCM_FORMAT_S16);
+ rate->put_idx = put_index(SND_PCM_FORMAT_S16, dst_format);
if (src_rate < dst_rate) {
rate->func = resample_expand;
/* pitch is get_threshold */
@@ -389,43 +374,37 @@ static int snd_pcm_rate_setup(snd_pcm_t *pcm, snd_pcm_setup_t * setup)
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);
-
- /* 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));
+ rate->states = malloc(params->channels * sizeof(*rate->states));
return 0;
}
+static int snd_pcm_rate_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params)
+{
+ snd_pcm_rate_t *rate = pcm->private;
+ snd_pcm_t *slave = rate->plug.slave;
+ size_t avail_min, xfer_min, xfer_align;
+ int err;
+ avail_min = params->avail_min;
+ xfer_min = params->xfer_min;
+ xfer_align = params->xfer_align;
+ params->avail_min = muldiv_near(params->avail_min, slave->rate, pcm->rate);
+ params->xfer_min = muldiv_near(params->xfer_min, slave->rate, pcm->rate);
+ params->xfer_align = muldiv_near(params->xfer_align, slave->rate, pcm->rate);
+ err = snd_pcm_sw_params(slave, params);
+ params->avail_min = avail_min;
+ params->xfer_min = xfer_min;
+ params->xfer_align = xfer_align;
+ params->boundary = LONG_MAX - pcm->buffer_size * 2 - LONG_MAX % pcm->buffer_size;
+ return err;
+}
+
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) {
+ for (k = 0; k < pcm->channels; ++k) {
rate->states[k].sum = 0;
rate->states[k].sample = 0;
if (rate->func == resample_expand) {
@@ -463,7 +442,7 @@ static ssize_t snd_pcm_rate_write_areas(snd_pcm_t *pcm,
src_frames = rate->func(areas, client_offset, src_frames,
snd_pcm_mmap_areas(slave), snd_pcm_mmap_offset(slave),
&dst_frames,
- pcm->setup.format.channels,
+ pcm->channels,
rate->get_idx, rate->put_idx,
rate->pitch, rate->states);
err = snd_pcm_mmap_forward(slave, dst_frames);
@@ -509,7 +488,7 @@ static ssize_t snd_pcm_rate_read_areas(snd_pcm_t *pcm,
src_frames = rate->func(snd_pcm_mmap_areas(slave), snd_pcm_mmap_offset(slave),
src_frames,
areas, client_offset, &dst_frames,
- pcm->setup.format.channels,
+ pcm->channels,
rate->get_idx, rate->put_idx,
rate->pitch, rate->states);
err = snd_pcm_mmap_forward(slave, src_frames);
@@ -529,27 +508,27 @@ static ssize_t snd_pcm_rate_read_areas(snd_pcm_t *pcm,
return err;
}
-size_t snd_pcm_rate_client_frames(snd_pcm_t *pcm, size_t frames)
+ssize_t snd_pcm_rate_client_frames(snd_pcm_t *pcm, ssize_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;
+ return muldiv_down(frames, DIV, rate->pitch);
else
- return (int64_t)frames * rate->pitch / DIV;
+ return muldiv_down(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)
+ if (rate->sformat < 0)
fprintf(fp, "Rate conversion PCM (%d)\n",
- rate->req_srate);
+ rate->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) {
+ rate->srate,
+ snd_pcm_format_name(rate->sformat));
+ if (pcm->setup) {
fprintf(fp, "Its setup is:\n");
snd_pcm_dump_setup(pcm, fp);
}
@@ -560,12 +539,12 @@ static void snd_pcm_rate_dump(snd_pcm_t *pcm, FILE *fp)
snd_pcm_ops_t 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,
+ hw_info: snd_pcm_rate_hw_info,
+ hw_params: snd_pcm_rate_hw_params,
+ sw_params: snd_pcm_rate_sw_params,
+ dig_info: snd_pcm_plugin_dig_info,
+ dig_params: snd_pcm_plugin_dig_params,
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,
async: snd_pcm_plugin_async,
@@ -584,8 +563,8 @@ int snd_pcm_rate_open(snd_pcm_t **pcmp, char *name, int sformat, int srate, snd_
if (!rate) {
return -ENOMEM;
}
- rate->req_srate = srate;
- rate->req_sformat = sformat;
+ rate->srate = srate;
+ rate->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;
diff --git a/src/pcm/pcm_route.c b/src/pcm/pcm_route.c
index 4e841553..75a4b106 100644
--- a/src/pcm/pcm_route.c
+++ b/src/pcm/pcm_route.c
@@ -81,12 +81,8 @@ typedef union {
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;
@@ -429,110 +425,91 @@ static int snd_pcm_route_close(snd_pcm_t *pcm)
return 0;
}
-static int snd_pcm_route_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t * info)
+static int snd_pcm_route_hw_info(snd_pcm_t *pcm, snd_pcm_hw_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;
+ unsigned int format_mask, access_mask, channels_min, channels_max;
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;
+ info->access_mask &= (SND_PCM_ACCBIT_MMAP_INTERLEAVED |
+ SND_PCM_ACCBIT_RW_INTERLEAVED |
+ SND_PCM_ACCBIT_MMAP_NONINTERLEAVED |
+ SND_PCM_ACCBIT_RW_NONINTERLEAVED);
+ access_mask = info->access_mask;
+ if (access_mask == 0)
return -EINVAL;
+ info->format_mask &= SND_PCM_FMTBIT_LINEAR;
+ format_mask = info->format_mask;
+ if (format_mask == 0)
+ return -EINVAL;
+ if (info->channels_min < 1)
+ info->channels_min = 1;
+ if (info->channels_max > 1024)
+ info->channels_max = 1024;
+ if (info->channels_max < info->channels_min)
+ return -EINVAL;
+ channels_min = info->channels_min;
+ channels_max = info->channels_max;
+ if (route->sformat >= 0)
+ info->format_mask = 1U << route->sformat;
+ if (route->schannels >= 0)
+ info->channels_min = info->channels_max = route->schannels;
+
+ info->access_mask = SND_PCM_ACCBIT_MMAP;
+ err = snd_pcm_hw_info(route->plug.slave, info);
+ if (info->format_mask)
+ info->format_mask = format_mask;
+ if (info->channels_min <= info->channels_max) {
+ info->channels_min = channels_min;
+ info->channels_max = channels_max;
}
- 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;
+ if (info->access_mask) {
+ route->plug.saccess_mask = info->access_mask;
+ info->access_mask = access_mask;
}
- 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 (info->format_mask)
+ info->format_mask = format_mask;
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;
+ info->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
+ snd_pcm_hw_info_complete(info);
+ return 0;
}
-static int snd_pcm_route_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
+static int snd_pcm_route_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
{
snd_pcm_route_t *route = pcm->private;
snd_pcm_t *slave = route->plug.slave;
+ unsigned int format, access, channels;
+ unsigned int src_format, dst_format;
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;
- }
- 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_mmap(slave, params);
- params->format.sfmt = route->cformat;
- params->format.channels = route->cchannels;
- params->xfer_mode = route->cxfer_mode;
- params->mmap_shape = route->cmmap_shape;
- 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);
+ format = params->format;
+ channels = params->channels;
+ access = params->access;
+ if (route->sformat >= 0)
+ params->format = route->sformat;
+ if (route->schannels >= 0)
+ params->channels = route->schannels;
+ if (route->plug.saccess_mask & SND_PCM_ACCBIT_MMAP_INTERLEAVED)
+ params->access = SND_PCM_ACCESS_MMAP_INTERLEAVED;
+ else if (route->plug.saccess_mask & SND_PCM_ACCBIT_MMAP_NONINTERLEAVED)
+ params->access = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;
+ else
+ assert(0);
+ err = snd_pcm_hw_params(slave, params);
+ params->format = format;
+ params->channels = channels;
+ params->access = access;
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;
+ src_format = format;
+ dst_format = slave->format;
} else {
- src_format = route->sformat;
- dst_format = route->cformat;
+ src_format = slave->format;
+ dst_format = format;
}
- route->params.get_idx = get_index(src_format, SND_PCM_SFMT_U16);
- route->params.put_idx = put_index(SND_PCM_SFMT_U32, dst_format);
+ route->params.get_idx = get_index(src_format, SND_PCM_FORMAT_U16);
+ route->params.put_idx = put_index(SND_PCM_FORMAT_U32, 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;
@@ -547,30 +524,6 @@ static int snd_pcm_route_setup(snd_pcm_t *pcm, snd_pcm_setup_t * setup)
return 0;
}
-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->mmap_info)
- return 0;
- if (pcm->setup.mmap_shape == SND_PCM_MMAP_INTERLEAVED) {
- setup->running_area.addr = pcm->mmap_info->addr;
- setup->running_area.first = setup->channel * pcm->bits_per_sample;
- setup->running_area.step = pcm->bits_per_frame;
- } else {
- setup->running_area.addr = pcm->mmap_info->addr + setup->channel * pcm->setup.buffer_size * pcm->bits_per_sample / 8;
- setup->running_area.first = 0;
- setup->running_area.step = pcm->bits_per_sample;
- }
- setup->stopped_area = setup->running_area;
- return 0;
-}
-
static ssize_t snd_pcm_route_write_areas(snd_pcm_t *pcm,
snd_pcm_channel_area_t *areas,
size_t offset,
@@ -588,7 +541,7 @@ static ssize_t snd_pcm_route_write_areas(snd_pcm_t *pcm,
size_t frames = snd_pcm_mmap_playback_xfer(slave, size - xfer);
route_transfer(areas, offset,
snd_pcm_mmap_areas(slave), snd_pcm_mmap_offset(slave),
- frames, route->schannels, &route->params);
+ frames, slave->channels, &route->params);
err = snd_pcm_mmap_forward(slave, frames);
if (err < 0)
break;
@@ -622,7 +575,7 @@ static ssize_t snd_pcm_route_read_areas(snd_pcm_t *pcm,
size_t frames = snd_pcm_mmap_capture_xfer(slave, size - xfer);
route_transfer(snd_pcm_mmap_areas(slave), snd_pcm_mmap_offset(slave),
areas, offset,
- frames, route->cchannels, &route->params);
+ frames, pcm->channels, &route->params);
err = snd_pcm_mmap_forward(slave, frames);
if (err < 0)
break;
@@ -643,11 +596,11 @@ 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)
+ if (route->sformat < 0)
fprintf(fp, "Route conversion PCM\n");
else
fprintf(fp, "Route conversion PCM (sformat=%s)\n",
- snd_pcm_format_name(route->req_sformat));
+ snd_pcm_format_name(route->sformat));
fputs("Transformation table:\n", fp);
for (dst = 0; dst < route->params.ndsts; dst++) {
ttable_dst_t *d = &route->params.dsts[dst];
@@ -669,7 +622,7 @@ static void snd_pcm_route_dump(snd_pcm_t *pcm, FILE *fp)
}
putc('\n', fp);
}
- if (pcm->valid_setup) {
+ if (pcm->setup) {
fprintf(fp, "Its setup is:\n");
snd_pcm_dump_setup(pcm, fp);
}
@@ -680,12 +633,12 @@ static void snd_pcm_route_dump(snd_pcm_t *pcm, FILE *fp)
snd_pcm_ops_t 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,
+ hw_info: snd_pcm_route_hw_info,
+ hw_params: snd_pcm_route_hw_params,
+ sw_params: snd_pcm_plugin_sw_params,
+ dig_info: snd_pcm_plugin_dig_info,
+ dig_params: snd_pcm_plugin_dig_params,
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,
async: snd_pcm_plugin_async,
@@ -782,8 +735,8 @@ int snd_pcm_route_open(snd_pcm_t **pcmp, char *name,
if (!route) {
return -ENOMEM;
}
- route->req_sformat = sformat;
- route->req_schannels = schannels;
+ route->sformat = sformat;
+ route->schannels = schannels;
route->plug.read = snd_pcm_route_read_areas;
route->plug.write = snd_pcm_route_write_areas;
route->plug.slave = slave;
diff --git a/src/pcm/pcm_share.c b/src/pcm/pcm_share.c
index 85edc923..898f8647 100644
--- a/src/pcm/pcm_share.c
+++ b/src/pcm/pcm_share.c
@@ -21,6 +21,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include <limits.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
@@ -66,8 +67,8 @@ typedef struct {
struct list_head clients;
struct list_head list;
snd_pcm_t *pcm;
- int sformat;
- int srate;
+ int format;
+ int rate;
size_t channels_count;
size_t open_count;
size_t setup_count;
@@ -104,7 +105,6 @@ typedef struct {
int ready;
int client_socket;
int slave_socket;
- void *stopped_data;
} snd_pcm_share_t;
static void _snd_pcm_share_stop(snd_pcm_t *pcm, int state);
@@ -115,9 +115,9 @@ static size_t snd_pcm_share_slave_avail(snd_pcm_share_slave_t *slave)
snd_pcm_t *pcm = slave->pcm;
avail = slave->hw_ptr - *pcm->appl_ptr;
if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
- avail += pcm->setup.buffer_size;
+ avail += pcm->buffer_size;
if (avail < 0)
- avail += pcm->setup.boundary;
+ avail += pcm->boundary;
return avail;
}
@@ -133,8 +133,8 @@ static size_t _snd_pcm_share_slave_forward(snd_pcm_share_slave_t *slave)
size_t avail, slave_avail;
size_t slave_hw_avail;
slave_avail = snd_pcm_share_slave_avail(slave);
- boundary = slave->pcm->setup.boundary;
- buffer_size = slave->pcm->setup.buffer_size;
+ boundary = slave->pcm->boundary;
+ buffer_size = slave->pcm->buffer_size;
min_frames = slave_avail;
max_frames = 0;
slave_appl_ptr = *slave->pcm->appl_ptr;
@@ -191,7 +191,7 @@ static size_t _snd_pcm_share_missing(snd_pcm_t *pcm, int slave_xrun)
snd_pcm_share_t *share = pcm->private;
snd_pcm_share_slave_t *slave = share->slave;
snd_pcm_t *spcm = slave->pcm;
- size_t buffer_size = spcm->setup.buffer_size;
+ size_t buffer_size = spcm->buffer_size;
int ready = 1, running = 0;
size_t avail = 0, slave_avail;
ssize_t hw_avail;
@@ -208,7 +208,7 @@ static size_t _snd_pcm_share_missing(snd_pcm_t *pcm, int slave_xrun)
default:
return INT_MAX;
}
- if (slave_xrun && pcm->setup.xrun_mode != SND_PCM_XRUN_NONE) {
+ if (slave_xrun && pcm->xrun_mode != SND_PCM_XRUN_NONE) {
_snd_pcm_share_stop(pcm, SND_PCM_STATE_XRUN);
goto update_poll;
}
@@ -251,7 +251,7 @@ static size_t _snd_pcm_share_missing(snd_pcm_t *pcm, int slave_xrun)
}
break;
case SND_PCM_STATE_RUNNING:
- if (pcm->setup.xrun_mode != SND_PCM_XRUN_NONE) {
+ if (pcm->xrun_mode != SND_PCM_XRUN_NONE) {
if (hw_avail <= 0) {
_snd_pcm_share_stop(pcm, SND_PCM_STATE_XRUN);
break;
@@ -300,7 +300,7 @@ static size_t _snd_pcm_share_missing(snd_pcm_t *pcm, int slave_xrun)
size_t cont = buffer_size - offset;
if (cont < frames)
frames = cont;
- snd_pcm_areas_silence(pcm->running_areas, offset, pcm->setup.format.channels, frames, pcm->setup.format.sfmt);
+ snd_pcm_areas_silence(pcm->running_areas, offset, pcm->channels, frames, pcm->format);
offset += frames;
if (offset >= buffer_size)
offset = 0;
@@ -357,17 +357,17 @@ void *snd_pcm_share_slave_thread(void *data)
size_t hw_ptr;
ssize_t avail_min;
hw_ptr = slave->hw_ptr + missing;
- hw_ptr += spcm->setup.frag_size - 1;
- if (hw_ptr >= spcm->setup.boundary)
- hw_ptr -= spcm->setup.boundary;
- hw_ptr -= hw_ptr % spcm->setup.frag_size;
+ hw_ptr += spcm->fragment_size - 1;
+ if (hw_ptr >= spcm->boundary)
+ hw_ptr -= spcm->boundary;
+ hw_ptr -= hw_ptr % spcm->fragment_size;
avail_min = hw_ptr - *spcm->appl_ptr;
if (spcm->stream == SND_PCM_STREAM_PLAYBACK)
- avail_min += spcm->setup.buffer_size;
+ avail_min += spcm->buffer_size;
if (avail_min < 0)
- avail_min += spcm->setup.boundary;
+ avail_min += spcm->boundary;
// printf("avail_min=%d\n", avail_min);
- if ((size_t)avail_min != spcm->setup.avail_min)
+ if ((size_t)avail_min != spcm->avail_min)
snd_pcm_set_avail_min(spcm, avail_min);
slave->polling = 1;
Pthread_mutex_unlock(&slave->mutex);
@@ -403,16 +403,16 @@ static void _snd_pcm_share_update(snd_pcm_t *pcm)
size_t hw_ptr;
ssize_t avail_min;
hw_ptr = slave->hw_ptr + missing;
- hw_ptr += spcm->setup.frag_size - 1;
- if (hw_ptr >= spcm->setup.boundary)
- hw_ptr -= spcm->setup.boundary;
- hw_ptr -= hw_ptr % spcm->setup.frag_size;
+ hw_ptr += spcm->fragment_size - 1;
+ if (hw_ptr >= spcm->boundary)
+ hw_ptr -= spcm->boundary;
+ hw_ptr -= hw_ptr % spcm->fragment_size;
avail_min = hw_ptr - *spcm->appl_ptr;
if (spcm->stream == SND_PCM_STREAM_PLAYBACK)
- avail_min += spcm->setup.buffer_size;
+ avail_min += spcm->buffer_size;
if (avail_min < 0)
- avail_min += spcm->setup.boundary;
- if ((size_t)avail_min < spcm->setup.avail_min)
+ avail_min += spcm->boundary;
+ if ((size_t)avail_min < spcm->avail_min)
snd_pcm_set_avail_min(spcm, avail_min);
}
}
@@ -442,211 +442,128 @@ static int snd_pcm_share_info(snd_pcm_t *pcm, snd_pcm_info_t *info)
return snd_pcm_info(share->slave->pcm, info);
}
-static int snd_pcm_share_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t *info)
+static int snd_pcm_share_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t *info)
{
snd_pcm_share_t *share = pcm->private;
snd_pcm_share_slave_t *slave = share->slave;
+ unsigned int access_mask;
int err = 0;
- unsigned int req_mask = info->req_mask;
- unsigned int channels = info->req.format.channels;
- if ((req_mask & SND_PCM_PARAMS_CHANNELS) &&
- channels != share->channels_count) {
- info->req.fail_mask |= SND_PCM_PARAMS_CHANNELS;
- info->req.fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
+ info->access_mask &= (SND_PCM_ACCBIT_MMAP_INTERLEAVED |
+ SND_PCM_ACCBIT_RW_INTERLEAVED |
+ SND_PCM_ACCBIT_MMAP_NONINTERLEAVED |
+ SND_PCM_ACCBIT_RW_NONINTERLEAVED);
+ access_mask = info->access_mask;
+ if (access_mask == 0)
return -EINVAL;
- }
- if (slave->sformat >= 0) {
- if ((req_mask & SND_PCM_PARAMS_SFMT) &&
- info->req.format.sfmt != slave->sformat) {
- info->req.fail_mask |= SND_PCM_PARAMS_SFMT;
- info->req.fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
+ if (info->channels_min < share->channels_count)
+ info->channels_min = share->channels_count;
+ if (info->channels_max > share->channels_count)
+ info->channels_max = share->channels_count;
+ if (info->channels_max > info->channels_max)
+ return -EINVAL;
+ if (slave->format >= 0) {
+ info->format_mask &= 1U << slave->format;
+ if (!info->format_mask)
return -EINVAL;
- }
- info->req.format.sfmt = slave->sformat;
- info->req_mask |= SND_PCM_PARAMS_SFMT;
- }
- if (slave->srate >= 0) {
- info->req.format.rate = slave->srate;
- info->req_mask |= SND_PCM_PARAMS_RATE;
- }
-
- info->req_mask |= SND_PCM_PARAMS_CHANNELS;
- info->req.format.channels = slave->channels_count;
- err = snd_pcm_params_info(slave->pcm, info);
- info->req.format.channels = channels;
- info->req_mask = req_mask;
- Pthread_mutex_lock(&slave->mutex);
- if (slave->setup_count > 1 ||
- (slave->setup_count == 1 && !pcm->valid_setup)) {
- snd_pcm_setup_t *s = &slave->pcm->setup;
- if ((req_mask & SND_PCM_PARAMS_SFMT) &&
- info->req.format.sfmt != s->format.sfmt) {
- info->req.fail_mask |= SND_PCM_PARAMS_SFMT;
- info->req.fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
- err = -EINVAL;
- goto _end;
- }
- info->formats = 1 << s->format.sfmt;
- info->rates = SND_PCM_RATE_CONTINUOUS;
- info->min_rate = info->max_rate = s->format.rate;
- info->buffer_size = s->buffer_size;
- info->min_fragment_size = info->max_fragment_size = s->frag_size;
- info->min_fragments = info->max_fragments = s->frags;
- info->fragment_align = s->frag_size;
- info->req.fail_mask = 0;
}
-
- info->min_channels = info->max_channels = share->channels_count;
- if (info->flags & SND_PCM_INFO_INTERLEAVED) {
- info->flags &= ~SND_PCM_INFO_INTERLEAVED;
- info->flags |= SND_PCM_INFO_COMPLEX;
+ if (slave->rate >= 0) {
+ if (info->rate_min < (unsigned)slave->rate)
+ info->rate_min = slave->rate;
+ if (info->rate_max > (unsigned)slave->rate)
+ info->rate_max = slave->rate;
+ if (info->rate_max > info->rate_max)
+ return -EINVAL;
}
- _end:
- Pthread_mutex_unlock(&slave->mutex);
+ info->access_mask = SND_PCM_ACCBIT_MMAP;
+ info->channels_min = info->channels_max = slave->channels_count;
+ err = snd_pcm_hw_info(slave->pcm, info);
+ if (info->channels_min <= info->channels_max)
+ info->channels_min = info->channels_max = share->channels_count;
+ if (info->access_mask)
+ info->access_mask = access_mask;
+ info->info |= SND_PCM_INFO_DOUBLE;
return err;
}
-static int snd_pcm_share_mmap(snd_pcm_t *pcm)
+static int snd_pcm_share_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{
snd_pcm_share_t *share = pcm->private;
snd_pcm_share_slave_t *slave = share->slave;
- snd_pcm_mmap_info_t *i;
- size_t count;
+ snd_pcm_t *spcm = slave->pcm;
int err = 0;
Pthread_mutex_lock(&slave->mutex);
- if (slave->mmap_count == 0) {
- err = snd_pcm_mmap(slave->pcm);
+ if (slave->setup_count > 1 ||
+ (slave->setup_count == 1 && !pcm->setup)) {
+ if (params->access != spcm->access ||
+ params->format != spcm->format ||
+ params->subformat != spcm->subformat ||
+ params->rate != spcm->rate ||
+ params->fragments != spcm->fragments ||
+ params->fragment_size != spcm->fragment_size) {
+ ERR("slave is already running with different setup");
+ params->fail_mask |= SND_PCM_HW_PARBIT_FORMAT;
+ return -EBUSY;
+ }
+ } else {
+ snd_pcm_hw_params_t sparams = *params;
+ sparams.channels = slave->channels_count;
+ err = snd_pcm_hw_params(slave->pcm, &sparams);
if (err < 0)
goto _end;
+ /* >= 30 ms */
+ slave->safety_threshold = sparams.rate * 30 / 1000;
+ slave->safety_threshold += sparams.fragment_size - 1;
+ slave->safety_threshold -= slave->safety_threshold % sparams.fragment_size;
+ slave->silence_frames = slave->safety_threshold;
if (slave->pcm->stream == SND_PCM_STREAM_PLAYBACK)
- snd_pcm_areas_silence(slave->pcm->running_areas, 0, slave->pcm->setup.format.channels, slave->pcm->setup.buffer_size, slave->pcm->setup.format.sfmt);
+ snd_pcm_areas_silence(slave->pcm->running_areas, 0, slave->pcm->channels, slave->pcm->buffer_size, slave->pcm->format);
}
- slave->mmap_count++;
- count = slave->pcm->mmap_info_count;
- i = malloc((count + 1) * sizeof(*i));
- if (!i) {
- err = -ENOMEM;
- goto _end;
- }
- err = snd_pcm_alloc_user_mmap(pcm, i);
- if (err < 0) {
- free(i);
- return err;
- }
- share->stopped_data = i->addr;
- memcpy(i + 1, slave->pcm->mmap_info, count * sizeof(*pcm->mmap_info));
- pcm->mmap_info_count = count + 1;
- pcm->mmap_info = i;
+ share->state = SND_PCM_STATE_SETUP;
+ slave->setup_count++;
_end:
Pthread_mutex_unlock(&slave->mutex);
- return 0;
+ return err;
}
-static int snd_pcm_share_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
+static int snd_pcm_share_sw_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_params_t *params)
{
- snd_pcm_share_t *share = pcm->private;
- snd_pcm_share_slave_t *slave = share->slave;
- snd_pcm_mmap_info_t *i = pcm->mmap_info;
- int err = 0;
- Pthread_mutex_lock(&slave->mutex);
- slave->mmap_count--;
- if (slave->mmap_count == 0) {
- err = snd_pcm_munmap(slave->pcm);
- if (err < 0)
- goto _end;
+ if (params->start_mode > SND_PCM_START_LAST) {
+ params->fail_mask = SND_PCM_SW_PARBIT_START_MODE;
+ return -EINVAL;
}
- err = snd_pcm_free_mmap(pcm, i);
- if (err < 0)
- goto _end;
- free(i);
- pcm->mmap_info_count = 0;
- pcm->mmap_info = 0;
- _end:
- Pthread_mutex_unlock(&slave->mutex);
- return err;
+ if (params->ready_mode > SND_PCM_READY_LAST) {
+ params->fail_mask = SND_PCM_SW_PARBIT_READY_MODE;
+ return -EINVAL;
+ }
+ if (params->xrun_mode > SND_PCM_XRUN_LAST) {
+ params->fail_mask = SND_PCM_SW_PARBIT_XRUN_MODE;
+ return -EINVAL;
+ }
+ return 0;
}
-
-static int snd_pcm_share_params(snd_pcm_t *pcm, snd_pcm_params_t *params)
+
+static int snd_pcm_share_dig_info(snd_pcm_t *pcm, snd_pcm_dig_info_t *info)
{
snd_pcm_share_t *share = pcm->private;
snd_pcm_share_slave_t *slave = share->slave;
- unsigned int channels = params->format.channels;
- int err = 0;
- if (channels != share->channels_count) {
- params->fail_mask = SND_PCM_PARAMS_CHANNELS;
- params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
- ERR("channels requested (%d) differs from configuration (%ld)", channels, (long)share->channels_count);
- return -EINVAL;
- }
- share->xfer_mode = params->xfer_mode;
- share->xrun_mode = params->xrun_mode;
- share->avail_min = params->avail_min;
+ int err;
+ /* FIXME */
Pthread_mutex_lock(&slave->mutex);
- if (slave->setup_count > 1 ||
- (slave->setup_count == 1 && !pcm->valid_setup)) {
- snd_pcm_setup_t *s = &slave->pcm->setup;
- if (params->format.sfmt != s->format.sfmt) {
- ERR("slave is already running with different format");
- params->fail_mask |= SND_PCM_PARAMS_SFMT;
- }
- if (params->fail_mask) {
- params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
- err = -EINVAL;
- goto _end;
- }
- } else {
- snd_pcm_params_t sp = *params;
- snd_pcm_setup_t *ss;
- if (slave->sformat >= 0 &&
- params->format.sfmt != slave->sformat) {
- params->fail_mask = SND_PCM_PARAMS_SFMT;
- params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
- ERR("format requested (%d) differs from configuration (%d)", params->format.sfmt, slave->sformat);
- err = -EINVAL;
- goto _end;
- }
- if (slave->srate >= 0)
- sp.format.rate = slave->srate;
- sp.xfer_mode = SND_PCM_XFER_UNSPECIFIED;
- sp.xrun_mode = SND_PCM_XRUN_NONE;
- sp.format.channels = slave->channels_count;
- err = snd_pcm_params_mmap(slave->pcm, &sp);
- if (err < 0)
- goto _end;
- ss = &slave->pcm->setup;
- /* >= 30 ms */
- slave->safety_threshold = ss->format.rate * 30 / 1000;
- slave->safety_threshold += ss->frag_size - 1;
- slave->safety_threshold -= slave->safety_threshold % ss->frag_size;
- slave->silence_frames = slave->safety_threshold;
- }
- share->state = SND_PCM_STATE_SETUP;
- slave->setup_count++;
- _end:
+ err = snd_pcm_dig_info(slave->pcm, info);
Pthread_mutex_unlock(&slave->mutex);
return err;
}
-static int snd_pcm_share_setup(snd_pcm_t *pcm, snd_pcm_setup_t *setup)
+static int snd_pcm_share_dig_params(snd_pcm_t *pcm, snd_pcm_dig_params_t *params)
{
snd_pcm_share_t *share = pcm->private;
snd_pcm_share_slave_t *slave = share->slave;
int err;
- err = snd_pcm_setup(slave->pcm, setup);
- if (err < 0)
- return err;
- setup->xrun_mode = share->xrun_mode;
- setup->format.channels = share->channels_count;
- if (share->avail_min > setup->buffer_size)
- share->avail_min = setup->buffer_size;
- setup->avail_min = share->avail_min;
- if (share->xfer_mode == SND_PCM_XFER_UNSPECIFIED)
- setup->xfer_mode = SND_PCM_XFER_NONINTERLEAVED;
- else
- setup->xfer_mode = share->xfer_mode;
- if (setup->mmap_shape != SND_PCM_MMAP_INTERLEAVED)
- setup->mmap_shape = SND_PCM_MMAP_COMPLEX;
- return 0;
+ /* FIXME */
+ Pthread_mutex_lock(&slave->mutex);
+ err = snd_pcm_dig_params(slave->pcm, params);
+ Pthread_mutex_unlock(&slave->mutex);
+ return err;
}
static int snd_pcm_share_status(snd_pcm_t *pcm, snd_pcm_status_t *status)
@@ -661,7 +578,7 @@ static int snd_pcm_share_status(snd_pcm_t *pcm, snd_pcm_status_t *status)
if (share->state != SND_PCM_STATE_RUNNING &&
share->state != SND_PCM_STATE_DRAINING)
goto _notrunning;
- d = pcm->setup.buffer_size - status->avail;
+ d = pcm->buffer_size - status->avail;
} else {
status->avail = snd_pcm_mmap_capture_avail(pcm);
if (share->state != SND_PCM_STATE_RUNNING)
@@ -738,7 +655,7 @@ static ssize_t snd_pcm_share_avail_update(snd_pcm_t *pcm)
}
Pthread_mutex_unlock(&slave->mutex);
avail = snd_pcm_mmap_avail(pcm);
- if ((size_t)avail > pcm->setup.buffer_size)
+ if ((size_t)avail > pcm->buffer_size)
return -EPIPE;
return avail;
}
@@ -753,10 +670,10 @@ static ssize_t _snd_pcm_share_mmap_forward(snd_pcm_t *pcm, size_t size)
if (pcm->stream == SND_PCM_STREAM_PLAYBACK &&
share->state == SND_PCM_STATE_RUNNING) {
frames = *slave->pcm->appl_ptr - share->appl_ptr;
- if (frames > (ssize_t)pcm->setup.buffer_size)
- frames -= pcm->setup.boundary;
- else if (frames < -(ssize_t)pcm->setup.buffer_size)
- frames += pcm->setup.boundary;
+ if (frames > (ssize_t)pcm->buffer_size)
+ frames -= pcm->boundary;
+ else if (frames < -(ssize_t)pcm->buffer_size)
+ frames += pcm->boundary;
if (frames > 0) {
/* Latecomer PCM */
ret = snd_pcm_rewind(slave->pcm, frames);
@@ -839,13 +756,13 @@ static int snd_pcm_share_start(snd_pcm_t *pcm)
while (xfer < hw_avail) {
size_t frames = hw_avail - xfer;
size_t offset = snd_pcm_mmap_offset(pcm);
- size_t cont = pcm->setup.buffer_size - offset;
+ size_t cont = pcm->buffer_size - offset;
if (cont < frames)
frames = cont;
snd_pcm_areas_copy(pcm->stopped_areas, xfer,
pcm->running_areas, offset,
- pcm->setup.format.channels, frames,
- pcm->setup.format.sfmt);
+ pcm->channels, frames,
+ pcm->format);
xfer += frames;
}
snd_pcm_mmap_appl_forward(pcm, hw_avail);
@@ -883,51 +800,6 @@ static int snd_pcm_share_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *in
return err;
}
-static int snd_pcm_share_channel_params(snd_pcm_t *pcm, snd_pcm_channel_params_t *params)
-{
- snd_pcm_share_t *share = pcm->private;
- snd_pcm_share_slave_t *slave = share->slave;
- unsigned int channel = params->channel;
- int c = share->slave_channels[channel];
- int err;
- params->channel = c;
- err = snd_pcm_channel_params(slave->pcm, params);
- params->channel = channel;
- return err;
-}
-
-static int snd_pcm_share_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t *setup)
-{
- snd_pcm_share_t *share = pcm->private;
- snd_pcm_share_slave_t *slave = share->slave;
- unsigned int channel = setup->channel;
- int c = share->slave_channels[channel];
- int err;
- setup->channel = c;
- err = snd_pcm_channel_setup(slave->pcm, setup);
- setup->channel = channel;
- if (err < 0)
- return err;
- if (!pcm->mmap_info)
- return 0;
- switch (pcm->setup.mmap_shape) {
- case SND_PCM_MMAP_INTERLEAVED:
- case SND_PCM_MMAP_COMPLEX:
- setup->stopped_area.addr = share->stopped_data;
- setup->stopped_area.first = channel * pcm->bits_per_sample;
- setup->stopped_area.step = pcm->bits_per_frame;
- break;
- case SND_PCM_MMAP_NONINTERLEAVED:
- setup->stopped_area.addr = share->stopped_data + c * pcm->setup.buffer_size * pcm->bits_per_sample / 8;
- setup->stopped_area.first = 0;
- setup->stopped_area.step = pcm->bits_per_sample;
- break;
- default:
- assert(0);
- }
- return 0;
-}
-
static ssize_t _snd_pcm_share_rewind(snd_pcm_t *pcm, size_t frames)
{
snd_pcm_share_t *share = pcm->private;
@@ -984,7 +856,7 @@ static int snd_pcm_share_set_avail_min(snd_pcm_t *pcm, size_t frames)
snd_pcm_share_t *share = pcm->private;
snd_pcm_share_slave_t *slave = share->slave;
Pthread_mutex_lock(&slave->mutex);
- pcm->setup.avail_min = frames;
+ pcm->avail_min = frames;
share->avail_min = frames;
_snd_pcm_share_update(pcm);
Pthread_mutex_unlock(&slave->mutex);
@@ -996,7 +868,7 @@ static void _snd_pcm_share_stop(snd_pcm_t *pcm, int state)
{
snd_pcm_share_t *share = pcm->private;
snd_pcm_share_slave_t *slave = share->slave;
- if (!pcm->mmap_info) {
+ if (!pcm->mmap_channels) {
/* PCM closing already begun in the main thread */
return;
}
@@ -1004,13 +876,13 @@ static void _snd_pcm_share_stop(snd_pcm_t *pcm, int state)
if (pcm->stream == SND_PCM_STREAM_CAPTURE) {
snd_pcm_areas_copy(pcm->running_areas, 0,
pcm->stopped_areas, 0,
- pcm->setup.format.channels, pcm->setup.buffer_size,
- pcm->setup.format.sfmt);
+ pcm->channels, pcm->buffer_size,
+ pcm->format);
} else if (slave->running_count > 1) {
int err;
ssize_t delay;
- snd_pcm_areas_silence(pcm->running_areas, 0, pcm->setup.format.channels,
- pcm->setup.buffer_size, pcm->setup.format.sfmt);
+ snd_pcm_areas_silence(pcm->running_areas, 0, pcm->channels,
+ pcm->buffer_size, pcm->format);
err = snd_pcm_delay(slave->pcm, &delay);
if (err >= 0 && delay > 0)
snd_pcm_rewind(slave->pcm, delay);
@@ -1116,7 +988,7 @@ static int snd_pcm_share_close(snd_pcm_t *pcm)
int err = 0;
Pthread_mutex_lock(&slaves_mutex);
Pthread_mutex_lock(&slave->mutex);
- if (pcm->valid_setup)
+ if (pcm->setup)
slave->setup_count--;
slave->open_count--;
if (slave->open_count == 0) {
@@ -1142,6 +1014,16 @@ static int snd_pcm_share_close(snd_pcm_t *pcm)
return err;
}
+static int snd_pcm_share_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
+{
+ return 0;
+}
+
+static int snd_pcm_share_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
+{
+ return 0;
+}
+
static void snd_pcm_share_dump(snd_pcm_t *pcm, FILE *fp)
{
snd_pcm_share_t *share = pcm->private;
@@ -1151,7 +1033,7 @@ static void snd_pcm_share_dump(snd_pcm_t *pcm, FILE *fp)
fprintf(fp, "\nChannel bindings:\n");
for (k = 0; k < share->channels_count; ++k)
fprintf(fp, "%d: %d\n", k, share->slave_channels[k]);
- if (pcm->valid_setup) {
+ if (pcm->setup) {
fprintf(fp, "\nIts setup is:\n");
snd_pcm_dump_setup(pcm, fp);
}
@@ -1162,12 +1044,12 @@ static void snd_pcm_share_dump(snd_pcm_t *pcm, FILE *fp)
snd_pcm_ops_t snd_pcm_share_ops = {
close: snd_pcm_share_close,
info: snd_pcm_share_info,
- params_info: snd_pcm_share_params_info,
- params: snd_pcm_share_params,
- setup: snd_pcm_share_setup,
+ hw_info: snd_pcm_share_hw_info,
+ hw_params: snd_pcm_share_hw_params,
+ sw_params: snd_pcm_share_sw_params,
+ dig_info: snd_pcm_share_dig_info,
+ dig_params: snd_pcm_share_dig_params,
channel_info: snd_pcm_share_channel_info,
- channel_params: snd_pcm_share_channel_params,
- channel_setup: snd_pcm_share_channel_setup,
dump: snd_pcm_share_dump,
nonblock: snd_pcm_share_nonblock,
async: snd_pcm_share_async,
@@ -1311,8 +1193,8 @@ int snd_pcm_share_open(snd_pcm_t **pcmp, char *name, char *sname,
INIT_LIST_HEAD(&slave->clients);
slave->pcm = spcm;
slave->channels_count = schannels_count;
- slave->sformat = sformat;
- slave->srate = srate;
+ slave->format = sformat;
+ slave->rate = srate;
pthread_mutex_init(&slave->mutex, NULL);
pthread_cond_init(&slave->poll_cond, NULL);
list_add_tail(&slave->list, &slaves);
@@ -1353,7 +1235,7 @@ int snd_pcm_share_open(snd_pcm_t **pcmp, char *name, char *sname,
pcm->type = SND_PCM_TYPE_SHARE;
pcm->stream = stream;
pcm->mode = mode;
- pcm->mmap_auto = 1;
+ pcm->mmap_rw = 1;
pcm->ops = &snd_pcm_share_ops;
pcm->op_arg = pcm;
pcm->fast_ops = &snd_pcm_share_fast_ops;
diff --git a/src/pcm/pcm_shm.c b/src/pcm/pcm_shm.c
index 0878bc17..d609e742 100644
--- a/src/pcm/pcm_shm.c
+++ b/src/pcm/pcm_shm.c
@@ -22,6 +22,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
+#include <limits.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
@@ -40,8 +41,8 @@
typedef struct {
int socket;
+ unsigned int access_mask;
volatile snd_pcm_shm_ctrl_t *ctrl;
- snd_pcm_mmap_info_t *slave_mmap_info;
} snd_pcm_shm_t;
int receive_fd(int socket, void *data, size_t len, int *fd)
@@ -147,108 +148,147 @@ static int snd_pcm_shm_info(snd_pcm_t *pcm, snd_pcm_info_t * info)
return err;
}
-static int snd_pcm_shm_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t * info)
+static int snd_pcm_shm_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t * info)
{
snd_pcm_shm_t *shm = pcm->private;
volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
int err;
- ctrl->cmd = SND_PCM_IOCTL_PARAMS_INFO;
- ctrl->u.params_info = *info;
+ unsigned int access_mask = info->access_mask;
+ ctrl->cmd = SND_PCM_IOCTL_HW_INFO;
+ ctrl->u.hw_info = *info;
+ ctrl->u.hw_info.access_mask |= SND_PCM_ACCBIT_MMAP;
err = snd_pcm_shm_action(pcm);
+ *info = ctrl->u.hw_info;
+ if (info->access_mask) {
+ shm->access_mask = info->access_mask;
+ info->access_mask |= (SND_PCM_ACCESS_RW_INTERLEAVED |
+ SND_PCM_ACCESS_RW_NONINTERLEAVED);
+ info->access_mask &= access_mask;
+ }
if (err < 0)
return err;
- *info = ctrl->u.params_info;
return err;
}
-static int snd_pcm_shm_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
+static int snd_pcm_shm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
{
snd_pcm_shm_t *shm = pcm->private;
volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
+ unsigned int access = params->access;
int err;
- ctrl->cmd = SND_PCM_IOCTL_PARAMS;
- ctrl->u.params = *params;
+ ctrl->cmd = SND_PCM_IOCTL_HW_PARAMS;
+ ctrl->u.hw_params = *params;
+ if (shm->access_mask & SND_PCM_ACCBIT_MMAP_INTERLEAVED)
+ ctrl->u.hw_params.access = SND_PCM_ACCESS_MMAP_INTERLEAVED;
+ else if (shm->access_mask & SND_PCM_ACCBIT_MMAP_NONINTERLEAVED)
+ ctrl->u.hw_params.access = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;
+ else
+ assert(0);
err = snd_pcm_shm_action(pcm);
+ params->access = access;
+ *params = ctrl->u.hw_params;
if (err < 0)
return err;
- *params = ctrl->u.params;
return err;
}
-static int snd_pcm_shm_setup(snd_pcm_t *pcm, snd_pcm_setup_t * setup)
+static int snd_pcm_shm_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params)
{
snd_pcm_shm_t *shm = pcm->private;
volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
int err;
- ctrl->cmd = SND_PCM_IOCTL_SETUP;
- // ctrl->u.setup = *setup;
+ ctrl->cmd = SND_PCM_IOCTL_SW_PARAMS;
+ ctrl->u.sw_params = *params;
err = snd_pcm_shm_action(pcm);
+ *params = ctrl->u.sw_params;
if (err < 0)
return err;
- *setup = ctrl->u.setup;
return err;
}
-static int snd_pcm_shm_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info)
+static int snd_pcm_shm_dig_info(snd_pcm_t *pcm, snd_pcm_dig_info_t * info)
{
snd_pcm_shm_t *shm = pcm->private;
volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
int err;
- ctrl->cmd = SND_PCM_IOCTL_CHANNEL_INFO;
- ctrl->u.channel_info = *info;
+ ctrl->cmd = SND_PCM_IOCTL_DIG_INFO;
+ ctrl->u.dig_info = *info;
err = snd_pcm_shm_action(pcm);
if (err < 0)
return err;
- *info = ctrl->u.channel_info;
+ *info = ctrl->u.dig_info;
return err;
}
-static int snd_pcm_shm_channel_params(snd_pcm_t *pcm, snd_pcm_channel_params_t * params)
+static int snd_pcm_shm_dig_params(snd_pcm_t *pcm, snd_pcm_dig_params_t * params)
{
snd_pcm_shm_t *shm = pcm->private;
volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
int err;
- ctrl->cmd = SND_PCM_IOCTL_CHANNEL_PARAMS;
- ctrl->u.channel_params = *params;
+ ctrl->cmd = SND_PCM_IOCTL_DIG_PARAMS;
+ ctrl->u.dig_params = *params;
err = snd_pcm_shm_action(pcm);
+ *params = ctrl->u.dig_params;
if (err < 0)
return err;
- *params = ctrl->u.channel_params;
return err;
}
-static void *convert_addr(void *addr, size_t count, snd_pcm_mmap_info_t *old, snd_pcm_mmap_info_t *new)
+static int snd_pcm_shm_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
{
- size_t k;
- size_t mindist = ULONG_MAX;
- int idx = -1;
- for (k = 0; k < count; ++k) {
- if (addr >= old[k].addr) {
- size_t dist = addr - old[k].addr;
- if (dist < mindist) {
- mindist = dist;
- idx = k;
- }
+ return 0;
+}
+
+static int snd_pcm_shm_munmap(snd_pcm_t *pcm)
+{
+ unsigned int c;
+ for (c = 0; c < pcm->channels; ++c) {
+ snd_pcm_channel_info_t *i = &pcm->mmap_channels[c];
+ unsigned int c1;
+ int err;
+ if (i->type != SND_PCM_AREA_MMAP)
+ continue;
+ if (i->u.mmap.fd < 0)
+ continue;
+ for (c1 = c + 1; c1 < pcm->channels; ++c1) {
+ snd_pcm_channel_info_t *i1 = &pcm->mmap_channels[c1];
+ if (i1->type != SND_PCM_AREA_MMAP)
+ continue;
+ if (i1->u.mmap.fd != i->u.mmap.fd)
+ continue;
+ i1->u.mmap.fd = -1;
+ }
+ err = close(i->u.mmap.fd);
+ if (err < 0) {
+ SYSERR("close failed");
+ return -errno;
}
}
- assert(idx >= 0);
- return new[idx].addr + mindist;
+ return 0;
}
-static int snd_pcm_shm_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t * setup)
+static int snd_pcm_shm_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info)
{
snd_pcm_shm_t *shm = pcm->private;
volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
int err;
- ctrl->cmd = SND_PCM_IOCTL_CHANNEL_SETUP;
- ctrl->u.channel_setup = *setup;
- err = snd_pcm_shm_action(pcm);
+ int fd;
+ ctrl->cmd = SND_PCM_IOCTL_CHANNEL_INFO;
+ ctrl->u.channel_info = *info;
+ err = snd_pcm_shm_action_fd(pcm, &fd);
if (err < 0)
return err;
- *setup = ctrl->u.channel_setup;
- if (pcm->mmap_info) {
- setup->running_area.addr = convert_addr(setup->running_area.addr, pcm->mmap_info_count, shm->slave_mmap_info, pcm->mmap_info);
- setup->stopped_area.addr = convert_addr(setup->stopped_area.addr, pcm->mmap_info_count, shm->slave_mmap_info, pcm->mmap_info);
+ *info = ctrl->u.channel_info;
+ info->addr = 0;
+ switch (info->type) {
+ case SND_PCM_AREA_MMAP:
+ info->u.mmap.fd = fd;
+ break;
+ case SND_PCM_AREA_SHM:
+ break;
+ default:
+ assert(0);
+ break;
}
return err;
}
@@ -356,86 +396,6 @@ static ssize_t snd_pcm_shm_rewind(snd_pcm_t *pcm, size_t frames)
return snd_pcm_shm_action(pcm);
}
-static int snd_pcm_shm_mmap(snd_pcm_t *pcm)
-{
- snd_pcm_shm_t *shm = pcm->private;
- volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
- int count, k, err, fd;
- ctrl->cmd = SND_PCM_IOCTL_MMAP;
- count = snd_pcm_shm_action(pcm);
- if (count < 0)
- return count;
- pcm->mmap_info_count = count;
- pcm->mmap_info = malloc(count * sizeof(*pcm->mmap_info));
- shm->slave_mmap_info = malloc(count * sizeof(*shm->slave_mmap_info));
- for (k = 0; k < count; ++k) {
- snd_pcm_mmap_info_t *i = &pcm->mmap_info[k];
- void *ptr;
- ctrl->cmd = SND_PCM_IOCTL_MMAP_INFO;
- ctrl->u.mmap_info.index = k;
- err = snd_pcm_shm_action_fd(pcm, &fd);
- if (err < 0)
- return err;
- shm->slave_mmap_info[k] = ctrl->u.mmap_info;
- *i = ctrl->u.mmap_info;
- if (i->type == SND_PCM_MMAP_KERNEL) {
- i->u.kernel.fd = fd;
- ptr = mmap(NULL, i->size, PROT_WRITE | PROT_READ,
- MAP_FILE | MAP_SHARED,
- fd, SND_PCM_MMAP_OFFSET_DATA);
- close(fd);
- if (ptr == MAP_FAILED || ptr == NULL) {
- SYSERR("mmap failed");
- free(pcm->mmap_info);
- return -errno;
- }
- } else {
- ptr = shmat(i->u.user.shmid, 0, 0);
- if (ptr == (void*)-1) {
- SYSERR("shmat failed");
- free(pcm->mmap_info);
- return -errno;
- }
- }
- i->addr = ptr;
- }
- return 0;
-}
-
-static int snd_pcm_shm_munmap(snd_pcm_t *pcm)
-{
- snd_pcm_shm_t *shm = pcm->private;
- volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
- int err;
- unsigned int k;
- ctrl->cmd = SND_PCM_IOCTL_MUNMAP;
- err = snd_pcm_shm_action(pcm);
- if (err < 0)
- return err;
- for (k = 0; k < pcm->mmap_info_count; ++k) {
- snd_pcm_mmap_info_t *i = &pcm->mmap_info[k];
- if (i->type == SND_PCM_MMAP_KERNEL) {
- err = munmap(i->addr, i->size);
- if (err < 0) {
- SYSERR("munmap failed");
- return -errno;
- }
- } else {
- err = shmdt(i->addr);
- if (err < 0) {
- SYSERR("shmdt failed");
- return -errno;
- }
- }
- }
- pcm->mmap_info_count = 0;
- free(pcm->mmap_info);
- free(shm->slave_mmap_info);
- pcm->mmap_info = 0;
- shm->slave_mmap_info = 0;
- return ctrl->result;
-}
-
static ssize_t snd_pcm_shm_mmap_forward(snd_pcm_t *pcm, size_t size)
{
snd_pcm_shm_t *shm = pcm->private;
@@ -483,7 +443,7 @@ static int snd_pcm_shm_close(snd_pcm_t *pcm)
static void snd_pcm_shm_dump(snd_pcm_t *pcm, FILE *fp)
{
fprintf(fp, "Shm PCM\n");
- if (pcm->valid_setup) {
+ if (pcm->setup) {
fprintf(fp, "\nIts setup is:\n");
snd_pcm_dump_setup(pcm, fp);
}
@@ -492,12 +452,12 @@ static void snd_pcm_shm_dump(snd_pcm_t *pcm, FILE *fp)
snd_pcm_ops_t snd_pcm_shm_ops = {
close: snd_pcm_shm_close,
info: snd_pcm_shm_info,
- params_info: snd_pcm_shm_params_info,
- params: snd_pcm_shm_params,
- setup: snd_pcm_shm_setup,
+ hw_info: snd_pcm_shm_hw_info,
+ hw_params: snd_pcm_shm_hw_params,
+ sw_params: snd_pcm_shm_sw_params,
+ dig_info: snd_pcm_shm_dig_info,
+ dig_params: snd_pcm_shm_dig_params,
channel_info: snd_pcm_shm_channel_info,
- channel_params: snd_pcm_shm_channel_params,
- channel_setup: snd_pcm_shm_channel_setup,
dump: snd_pcm_shm_dump,
nonblock: snd_pcm_shm_nonblock,
async: snd_pcm_shm_async,
@@ -656,7 +616,7 @@ int snd_pcm_shm_open(snd_pcm_t **pcmp, char *name, char *socket, char *sname, in
pcm->type = SND_PCM_TYPE_SHM;
pcm->stream = stream;
pcm->mode = mode;
- pcm->mmap_auto = 1;
+ pcm->mmap_rw = 1;
pcm->ops = &snd_pcm_shm_ops;
pcm->op_arg = pcm;
pcm->fast_ops = &snd_pcm_shm_fast_ops;
diff --git a/src/rawmidi/Makefile.am b/src/rawmidi/Makefile.am
index 1abeadd1..7b374de4 100644
--- a/src/rawmidi/Makefile.am
+++ b/src/rawmidi/Makefile.am
@@ -1,6 +1,8 @@
EXTRA_LTLIBRARIES=librawmidi.la
-librawmidi_la_SOURCES = rawmidi.c
+librawmidi_la_SOURCES = rawmidi.c rawmidi_hw.c
+noinst_HEADERS = rawmidi_local.h
+
all: librawmidi.la
diff --git a/src/rawmidi/rawmidi.c b/src/rawmidi/rawmidi.c
index f18dc087..3bebdff9 100644
--- a/src/rawmidi/rawmidi.c
+++ b/src/rawmidi/rawmidi.c
@@ -1,7 +1,7 @@
/*
* RawMIDI Interface - main file
- * Copyright (c) 1998 by Jaroslav Kysela <perex@suse.cz>
- *
+ * Copyright (c) 2000 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
@@ -21,221 +21,214 @@
#include <stdio.h>
#include <stdlib.h>
+#include <stdarg.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
+#include <dlfcn.h>
+#include "rawmidi_local.h"
#include "asoundlib.h"
-#define SND_FILE_RAWMIDI "/dev/snd/midiC%iD%i"
-#define SND_RAWMIDI_VERSION_MAX SND_PROTOCOL_VERSION(2, 0, 0)
-
-struct snd_rawmidi {
- int card;
- int device;
- int fd;
- int mode;
-};
-
-int snd_rawmidi_open_subdevice(snd_rawmidi_t **handle, int card, int device, int subdevice, int mode)
-{
- int fd, ver, ret;
- int attempt = 0;
- char filename[32];
- snd_ctl_t *ctl;
- snd_rawmidi_t *rmidi;
- snd_rawmidi_info_t info;
-
- *handle = NULL;
-
- if (card < 0 || card >= SND_CARDS)
- return -EINVAL;
-
- if ((ret = snd_ctl_hw_open(&ctl, NULL, card)) < 0)
- return ret;
- sprintf(filename, SND_FILE_RAWMIDI, card, device);
-
- __again:
- if (attempt++ > 3) {
- snd_ctl_close(ctl);
- return -EBUSY;
- }
- ret = snd_ctl_rawmidi_prefer_subdevice(ctl, subdevice);
- if (ret < 0) {
- snd_ctl_close(ctl);
- return ret;
- }
- if ((fd = open(filename, mode)) < 0) {
- snd_card_load(card);
- if ((fd = open(filename, mode)) < 0) {
- snd_ctl_close(ctl);
- return -errno;
- }
- }
- if (ioctl(fd, SND_RAWMIDI_IOCTL_PVERSION, &ver) < 0) {
- ret = -errno;
- close(fd);
- snd_ctl_close(ctl);
- return ret;
- }
- if (SND_PROTOCOL_INCOMPATIBLE(ver, SND_RAWMIDI_VERSION_MAX)) {
- close(fd);
- snd_ctl_close(ctl);
- return -SND_ERROR_INCOMPATIBLE_VERSION;
- }
- if (subdevice >= 0) {
- memset(&info, 0, sizeof(info));
- if (ioctl(fd, SND_RAWMIDI_IOCTL_INFO, &info) < 0) {
- ret = -errno;
- close(fd);
- snd_ctl_close(ctl);
- return ret;
- }
- if (info.subdevice != subdevice) {
- close(fd);
- goto __again;
- }
- }
- rmidi = (snd_rawmidi_t *) calloc(1, sizeof(snd_rawmidi_t));
- if (rmidi == NULL) {
- close(fd);
- snd_ctl_close(ctl);
- return -ENOMEM;
- }
- rmidi->card = card;
- rmidi->device = device;
- rmidi->fd = fd;
- rmidi->mode = mode;
- *handle = rmidi;
- return 0;
-}
-
-int snd_rawmidi_open(snd_rawmidi_t **handle, int card, int device, int mode)
-{
- return snd_rawmidi_open_subdevice(handle, card, device, -1, mode);
-}
-
int snd_rawmidi_close(snd_rawmidi_t *rmidi)
{
- int res;
-
- if (!rmidi)
- return -EINVAL;
- res = close(rmidi->fd) < 0 ? -errno : 0;
+ int err;
+ assert(rmidi);
+ if ((err = rmidi->ops->close(rmidi)) < 0)
+ return err;
+ if (rmidi->name)
+ free(rmidi->name);
free(rmidi);
- return res;
+ return 0;
}
int snd_rawmidi_poll_descriptor(snd_rawmidi_t *rmidi)
{
- if (!rmidi)
- return -EINVAL;
- return rmidi->fd;
+ assert(rmidi);
+ return rmidi->poll_fd;
}
-int snd_rawmidi_block_mode(snd_rawmidi_t *rmidi, int enable)
+int snd_rawmidi_nonblock(snd_rawmidi_t *rmidi, int nonblock)
{
- long flags;
-
- if (!rmidi)
- return -EINVAL;
- if (rmidi->mode == SND_RAWMIDI_OPEN_OUTPUT_APPEND ||
- rmidi->mode == SND_RAWMIDI_OPEN_DUPLEX_APPEND)
- return -EINVAL;
- if ((flags = fcntl(rmidi->fd, F_GETFL)) < 0)
- return -errno;
- if (enable)
- flags &= ~O_NONBLOCK;
+ int err;
+ assert(rmidi);
+ assert(!(rmidi->mode & SND_RAWMIDI_APPEND));
+ if ((err = rmidi->ops->nonblock(rmidi, nonblock)) < 0)
+ return err;
+ if (nonblock)
+ rmidi->mode |= SND_RAWMIDI_NONBLOCK;
else
- flags |= O_NONBLOCK;
- if (fcntl(rmidi->fd, F_SETFL, flags) < 0)
- return -errno;
+ rmidi->mode &= ~SND_RAWMIDI_NONBLOCK;
return 0;
}
int snd_rawmidi_info(snd_rawmidi_t *rmidi, snd_rawmidi_info_t * info)
{
- if (!rmidi || !info)
- return -EINVAL;
- if (ioctl(rmidi->fd, SND_RAWMIDI_IOCTL_INFO, info) < 0)
- return -errno;
- return 0;
+ assert(rmidi && info);
+ return rmidi->ops->info(rmidi, info);
}
int snd_rawmidi_params(snd_rawmidi_t *rmidi, snd_rawmidi_params_t * params)
{
- if (!rmidi || !params)
- return -EINVAL;
- if (params->stream < 0 || params->stream > 1)
- return -EINVAL;
- if (ioctl(rmidi->fd, SND_RAWMIDI_IOCTL_PARAMS, params) < 0)
- return -errno;
- return 0;
+ assert(rmidi && params);
+ return rmidi->ops->params(rmidi, params);
}
int snd_rawmidi_status(snd_rawmidi_t *rmidi, snd_rawmidi_status_t * status)
{
- if (!rmidi || !status)
- return -EINVAL;
- if (status->stream < 0 || status->stream > 1)
- return -EINVAL;
- if (ioctl(rmidi->fd, SND_RAWMIDI_IOCTL_STATUS, status) < 0)
- return -errno;
- return 0;
+ assert(rmidi && status);
+ return rmidi->ops->status(rmidi, status);
+}
+
+int snd_rawmidi_drop(snd_rawmidi_t *rmidi, int str)
+{
+ assert(rmidi);
+ assert(str >= 0 && str <= 1);
+ assert(rmidi->streams & (1 << str));
+ return rmidi->ops->drop(rmidi, str);
}
int snd_rawmidi_output_drop(snd_rawmidi_t *rmidi)
{
- int str = SND_RAWMIDI_STREAM_OUTPUT;
- if (!rmidi)
- return -EINVAL;
- if (ioctl(rmidi->fd, SND_RAWMIDI_IOCTL_DROP, &str) < 0)
- return -errno;
- return 0;
+ return snd_rawmidi_drop(rmidi, SND_RAWMIDI_STREAM_OUTPUT);
}
-int snd_rawmidi_stream_drain(snd_rawmidi_t *rmidi, int str)
+int snd_rawmidi_drain(snd_rawmidi_t *rmidi, int str)
{
- if (!rmidi)
- return -EINVAL;
- if (str < 0 || str > 1)
- return -EINVAL;
- if (ioctl(rmidi->fd, SND_RAWMIDI_IOCTL_DRAIN, &str) < 0)
- return -errno;
- return 0;
+ assert(rmidi);
+ assert(str >= 0 && str <= 1);
+ assert(rmidi->streams & (1 << str));
+ return rmidi->ops->drain(rmidi, str);
}
int snd_rawmidi_output_drain(snd_rawmidi_t *rmidi)
{
- return snd_rawmidi_stream_drain(rmidi, SND_RAWMIDI_STREAM_OUTPUT);
+ return snd_rawmidi_drain(rmidi, SND_RAWMIDI_STREAM_OUTPUT);
}
int snd_rawmidi_input_drain(snd_rawmidi_t *rmidi)
{
- return snd_rawmidi_stream_drain(rmidi, SND_RAWMIDI_STREAM_INPUT);
+ return snd_rawmidi_drain(rmidi, SND_RAWMIDI_STREAM_INPUT);
}
ssize_t snd_rawmidi_write(snd_rawmidi_t *rmidi, const void *buffer, size_t size)
{
- ssize_t result;
-
- if (!rmidi || (!buffer && size > 0))
- return -EINVAL;
- result = write(rmidi->fd, buffer, size);
- if (result < 0)
- return -errno;
- return result;
+ assert(rmidi && (buffer || size == 0));
+ return rmidi->ops->write(rmidi, buffer, size);
}
ssize_t snd_rawmidi_read(snd_rawmidi_t *rmidi, void *buffer, size_t size)
{
- ssize_t result;
+ assert(rmidi && (buffer || size == 0));
+ return rmidi->ops->read(rmidi, buffer, size);
+}
- if (!rmidi || (!buffer && size > 0))
+int snd_rawmidi_open(snd_rawmidi_t **rawmidip, char *name,
+ int streams, int mode)
+{
+ char *str;
+ int err;
+ snd_config_t *rawmidi_conf, *conf, *type_conf;
+ snd_config_iterator_t i;
+ char *lib = NULL, *open = NULL;
+ int (*open_func)(snd_rawmidi_t **rawmidip, char *name, snd_config_t *conf,
+ int streams, int mode);
+ void *h;
+ assert(rawmidip && name);
+ err = snd_config_update();
+ if (err < 0)
+ return err;
+ err = snd_config_searchv(snd_config, &rawmidi_conf, "rawmidi", name, 0);
+ if (err < 0) {
+ int card, dev, subdev;
+ err = sscanf(name, "hw:%d,%d,%d", &card, &dev, &subdev);
+ if (err == 3)
+ return snd_rawmidi_hw_open(rawmidip, name, card, dev, subdev, streams, mode);
+ err = sscanf(name, "hw:%d,%d", &card, &dev);
+ if (err == 2)
+ return snd_rawmidi_hw_open(rawmidip, name, card, dev, -1, streams, mode);
+ ERR("Unknown RAWMIDI %s", name);
+ return -ENOENT;
+ }
+ if (snd_config_type(rawmidi_conf) != SND_CONFIG_TYPE_COMPOUND) {
+ ERR("Invalid type for RAWMIDI definition");
+ return -EINVAL;
+ }
+ err = snd_config_search(rawmidi_conf, "streams", &conf);
+ if (err >= 0) {
+ err = snd_config_string_get(conf, &str);
+ if (err < 0) {
+ ERR("Invalid type for streams");
+ return err;
+ }
+ if (strcmp(str, "output") == 0) {
+ if (streams == SND_RAWMIDI_OPEN_INPUT)
+ return -EINVAL;
+ } else if (strcmp(str, "input") == 0) {
+ if (streams == SND_RAWMIDI_OPEN_OUTPUT)
+ return -EINVAL;
+ } else if (strcmp(str, "duplex") == 0) {
+ if (streams != SND_RAWMIDI_OPEN_DUPLEX)
+ return -EINVAL;
+ } else {
+ ERR("Invalid value for streams");
+ return -EINVAL;
+ }
+ }
+ err = snd_config_search(rawmidi_conf, "type", &conf);
+ if (err < 0) {
+ ERR("type is not defined");
+ return err;
+ }
+ err = snd_config_string_get(conf, &str);
+ if (err < 0) {
+ ERR("Invalid type for type");
+ return err;
+ }
+ err = snd_config_searchv(snd_config, &type_conf, "rawmiditype", str, 0);
+ if (err < 0) {
+ ERR("Unknown RAWMIDI type %s", str);
+ 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, "lib") == 0) {
+ err = snd_config_string_get(n, &lib);
+ if (err < 0) {
+ ERR("Invalid type for lib");
+ return -EINVAL;
+ }
+ continue;
+ }
+ if (strcmp(n->id, "open") == 0) {
+ err = snd_config_string_get(n, &open);
+ if (err < 0) {
+ ERR("Invalid type for open");
+ return -EINVAL;
+ }
+ continue;
+ ERR("Unknown field: %s", n->id);
+ return -EINVAL;
+ }
+ }
+ if (!open) {
+ ERR("open is not defined");
return -EINVAL;
- result = read(rmidi->fd, buffer, size);
- if (result < 0)
- return -errno;
- return result;
+ }
+ if (!lib)
+ lib = "libasound.so";
+ h = dlopen(lib, RTLD_NOW);
+ if (!h) {
+ ERR("Cannot open shared library %s", lib);
+ return -ENOENT;
+ }
+ open_func = dlsym(h, open);
+ dlclose(h);
+ if (!open_func) {
+ ERR("symbol %s is not defined inside %s", open, lib);
+ return -ENXIO;
+ }
+ return open_func(rawmidip, name, rawmidi_conf, streams, mode);
}
+
diff --git a/src/rawmidi/rawmidi_hw.c b/src/rawmidi/rawmidi_hw.c
new file mode 100644
index 00000000..4ebe70a4
--- /dev/null
+++ b/src/rawmidi/rawmidi_hw.c
@@ -0,0 +1,320 @@
+/*
+ * RawMIDI - Hardware
+ * Copyright (c) 2000 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.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include "../control/control_local.h"
+#include "rawmidi_local.h"
+#include "asoundlib.h"
+
+#define SND_FILE_RAWMIDI "/dev/snd/midiC%iD%i"
+#define SND_RAWMIDI_VERSION_MAX SND_PROTOCOL_VERSION(2, 0, 0)
+
+typedef struct {
+ int fd;
+ int card, device, subdevice;
+} snd_rawmidi_hw_t;
+
+static int snd_rawmidi_hw_close(snd_rawmidi_t *rmidi)
+{
+ snd_rawmidi_hw_t *hw = rmidi->private;
+ if (close(hw->fd)) {
+ SYSERR("close failed\n");
+ return -errno;
+ }
+ free(hw);
+ return 0;
+}
+
+static int snd_rawmidi_hw_nonblock(snd_rawmidi_t *rmidi, int nonblock)
+{
+ snd_rawmidi_hw_t *hw = rmidi->private;
+ long flags;
+
+ if ((flags = fcntl(hw->fd, F_GETFL)) < 0) {
+ SYSERR("F_GETFL failed");
+ return -errno;
+ }
+ if (nonblock)
+ flags &= ~O_NONBLOCK;
+ else
+ flags |= O_NONBLOCK;
+ if (fcntl(hw->fd, F_SETFL, flags) < 0) {
+ SYSERR("F_SETFL for O_NONBLOCK failed");
+ return -errno;
+ }
+ return 0;
+}
+
+static int snd_rawmidi_hw_info(snd_rawmidi_t *rmidi, snd_rawmidi_info_t * info)
+{
+ snd_rawmidi_hw_t *hw = rmidi->private;
+ if (ioctl(hw->fd, SND_RAWMIDI_IOCTL_INFO, info) < 0) {
+ SYSERR("SND_RAWMIDI_IOCTL_INFO failed");
+ return -errno;
+ }
+ return 0;
+}
+
+static int snd_rawmidi_hw_params(snd_rawmidi_t *rmidi, snd_rawmidi_params_t * params)
+{
+ snd_rawmidi_hw_t *hw = rmidi->private;
+ if (ioctl(hw->fd, SND_RAWMIDI_IOCTL_PARAMS, params) < 0) {
+ SYSERR("SND_RAWMIDI_IOCTL_PARAMS failed");
+ return -errno;
+ }
+ return 0;
+}
+
+static int snd_rawmidi_hw_status(snd_rawmidi_t *rmidi, snd_rawmidi_status_t * status)
+{
+ snd_rawmidi_hw_t *hw = rmidi->private;
+ if (ioctl(hw->fd, SND_RAWMIDI_IOCTL_STATUS, status) < 0) {
+ SYSERR("SND_RAWMIDI_IOCTL_STATUS failed");
+ return -errno;
+ }
+ return 0;
+}
+
+static int snd_rawmidi_hw_drop(snd_rawmidi_t *rmidi, int stream)
+{
+ snd_rawmidi_hw_t *hw = rmidi->private;
+ if (ioctl(hw->fd, SND_RAWMIDI_IOCTL_DROP, &stream) < 0) {
+ SYSERR("SND_RAWMIDI_IOCTL_DROP failed");
+ return -errno;
+ }
+ return 0;
+}
+
+static int snd_rawmidi_hw_drain(snd_rawmidi_t *rmidi, int stream)
+{
+ snd_rawmidi_hw_t *hw = rmidi->private;
+ if (ioctl(hw->fd, SND_RAWMIDI_IOCTL_DRAIN, &stream) < 0) {
+ SYSERR("SND_RAWMIDI_IOCTL_DRAIN failed");
+ return -errno;
+ }
+ return 0;
+}
+
+static ssize_t snd_rawmidi_hw_write(snd_rawmidi_t *rmidi, const void *buffer, size_t size)
+{
+ snd_rawmidi_hw_t *hw = rmidi->private;
+ ssize_t result;
+ result = write(hw->fd, buffer, size);
+ if (result < 0)
+ return -errno;
+ return result;
+}
+
+static ssize_t snd_rawmidi_hw_read(snd_rawmidi_t *rmidi, void *buffer, size_t size)
+{
+ snd_rawmidi_hw_t *hw = rmidi->private;
+ ssize_t result;
+ result = read(hw->fd, buffer, size);
+ if (result < 0)
+ return -errno;
+ return result;
+}
+
+snd_rawmidi_ops_t snd_rawmidi_hw_ops = {
+ close: snd_rawmidi_hw_close,
+ nonblock: snd_rawmidi_hw_nonblock,
+ info: snd_rawmidi_hw_info,
+ params: snd_rawmidi_hw_params,
+ status: snd_rawmidi_hw_status,
+ drop: snd_rawmidi_hw_drop,
+ drain: snd_rawmidi_hw_drain,
+ write: snd_rawmidi_hw_write,
+ read: snd_rawmidi_hw_read,
+};
+
+
+int snd_rawmidi_hw_open(snd_rawmidi_t **handlep, char *name, int card, int device, int subdevice, int streams, int mode)
+{
+ int fd, ver, ret;
+ int attempt = 0;
+ char filename[32];
+ snd_ctl_t *ctl;
+ snd_rawmidi_t *rmidi;
+ snd_rawmidi_hw_t *hw;
+ snd_rawmidi_info_t info;
+ int fmode;
+
+ *handlep = NULL;
+
+ assert(card >= 0 && card < SND_CARDS);
+
+ if ((ret = snd_ctl_hw_open(&ctl, NULL, card)) < 0)
+ return ret;
+ sprintf(filename, SND_FILE_RAWMIDI, card, device);
+
+ __again:
+ if (attempt++ > 3) {
+ snd_ctl_close(ctl);
+ return -EBUSY;
+ }
+ ret = snd_ctl_rawmidi_prefer_subdevice(ctl, subdevice);
+ if (ret < 0) {
+ snd_ctl_close(ctl);
+ return ret;
+ }
+
+ switch (streams) {
+ case SND_RAWMIDI_OPEN_OUTPUT:
+ fmode = O_WRONLY;
+ break;
+ case SND_RAWMIDI_OPEN_INPUT:
+ fmode = O_RDONLY;
+ break;
+ case SND_RAWMIDI_OPEN_DUPLEX:
+ fmode = O_RDWR;
+ break;
+ default:
+ assert(0);
+ return -EINVAL;
+ }
+
+ if (mode & SND_RAWMIDI_APPEND) {
+ assert(streams & SND_RAWMIDI_OPEN_OUTPUT);
+ fmode |= O_APPEND;
+ }
+
+ if (mode & SND_RAWMIDI_NONBLOCK) {
+ fmode |= O_NONBLOCK;
+ }
+
+ assert(!(mode & ~(SND_RAWMIDI_APPEND|SND_RAWMIDI_NONBLOCK)));
+
+ if ((fd = open(filename, fmode)) < 0) {
+ snd_card_load(card);
+ if ((fd = open(filename, fmode)) < 0) {
+ snd_ctl_close(ctl);
+ SYSERR("open %s failed", filename);
+ return -errno;
+ }
+ }
+ if (ioctl(fd, SND_RAWMIDI_IOCTL_PVERSION, &ver) < 0) {
+ ret = -errno;
+ SYSERR("SND_RAWMIDI_IOCTL_PVERSION failed");
+ close(fd);
+ snd_ctl_close(ctl);
+ return ret;
+ }
+ if (SND_PROTOCOL_INCOMPATIBLE(ver, SND_RAWMIDI_VERSION_MAX)) {
+ close(fd);
+ snd_ctl_close(ctl);
+ return -SND_ERROR_INCOMPATIBLE_VERSION;
+ }
+ if (subdevice >= 0) {
+ memset(&info, 0, sizeof(info));
+ if (ioctl(fd, SND_RAWMIDI_IOCTL_INFO, &info) < 0) {
+ SYSERR("SND_RAWMIDI_IOCTL_INFO failed");
+ ret = -errno;
+ close(fd);
+ snd_ctl_close(ctl);
+ return ret;
+ }
+ if (info.subdevice != subdevice) {
+ close(fd);
+ goto __again;
+ }
+ }
+ hw = calloc(1, sizeof(snd_rawmidi_hw_t));
+ if (hw == NULL) {
+ close(fd);
+ snd_ctl_close(ctl);
+ return -ENOMEM;
+ }
+ rmidi = calloc(1, sizeof(snd_rawmidi_t));
+ if (rmidi == NULL) {
+ free(hw);
+ close(fd);
+ snd_ctl_close(ctl);
+ return -ENOMEM;
+ }
+ hw->card = card;
+ hw->device = device;
+ hw->subdevice = subdevice;
+ hw->fd = fd;
+ if (name)
+ rmidi->name = strdup(name);
+ rmidi->type = SND_RAWMIDI_TYPE_HW;
+ rmidi->streams = streams;
+ rmidi->mode = mode;
+ rmidi->poll_fd = fd;
+ rmidi->ops = &snd_rawmidi_hw_ops;
+ rmidi->private = hw;
+ *handlep = rmidi;
+ return 0;
+}
+
+int _snd_rawmidi_hw_open(snd_rawmidi_t **handlep, char *name, snd_config_t *conf,
+ int streams, 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, "streams") == 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_rawmidi_hw_open(handlep, name, card, device, subdevice, streams, mode);
+}
+
diff --git a/src/rawmidi/rawmidi_local.h b/src/rawmidi/rawmidi_local.h
new file mode 100644
index 00000000..81b303de
--- /dev/null
+++ b/src/rawmidi/rawmidi_local.h
@@ -0,0 +1,60 @@
+/*
+ * Rawmidi interface - local header file
+ * 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 <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <errno.h>
+#include "asoundlib.h"
+
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)
+#define ERR(...) snd_lib_error(__FILE__, __LINE__, __FUNCTION__, 0, __VA_ARGS__)
+#define SYSERR(...) snd_lib_error(__FILE__, __LINE__, __FUNCTION__, errno, __VA_ARGS__)
+#else
+#define ERR(args...) snd_lib_error(__FILE__, __LINE__, __FUNCTION__, 0, ##args)
+#define SYSERR(args...) snd_lib_error(__FILE__, __LINE__, __FUNCTION__, errno, ##args)
+#endif
+
+typedef struct {
+ int (*close)(snd_rawmidi_t *rawmidi);
+ int (*nonblock)(snd_rawmidi_t *rawmidi, int nonblock);
+ int (*info)(snd_rawmidi_t *rawmidi, snd_rawmidi_info_t *info);
+ int (*params)(snd_rawmidi_t *rawmidi, snd_rawmidi_params_t *params);
+ int (*status)(snd_rawmidi_t *rawmidi, snd_rawmidi_status_t *status);
+ int (*drop)(snd_rawmidi_t *rawmidi, int stream);
+ int (*drain)(snd_rawmidi_t *rawmidi, int stream);
+ ssize_t (*write)(snd_rawmidi_t *rawmidi, const void *buffer, size_t size);
+ ssize_t (*read)(snd_rawmidi_t *rawmidi, void *buffer, size_t size);
+} snd_rawmidi_ops_t;
+
+struct _snd_rawmidi {
+ char *name;
+ snd_rawmidi_type_t type;
+ int streams;
+ int mode;
+ int poll_fd;
+ snd_rawmidi_ops_t *ops;
+ void *private;
+};
+
+int snd_rawmidi_hw_open(snd_rawmidi_t **handle, char *name, int card, int device, int subdevice, int streams, int mode);
+
diff --git a/src/seq/Makefile.am b/src/seq/Makefile.am
index 637dfec8..530820e0 100644
--- a/src/seq/Makefile.am
+++ b/src/seq/Makefile.am
@@ -1,7 +1,7 @@
EXTRA_LTLIBRARIES=libseq.la
-libseq_la_SOURCES = seq.c seqmid.c
-noinst_HEADERS = seq_priv.h
+libseq_la_SOURCES = seq_hw.c seq.c seqmid.c
+noinst_HEADERS = seq_local.h
all: libseq.la
diff --git a/src/seq/seq.c b/src/seq/seq.c
index c0774d21..ab4f269f 100644
--- a/src/seq/seq.c
+++ b/src/seq/seq.c
@@ -1,6 +1,7 @@
/*
* Sequencer Interface - main file
- * Copyright (c) 1998 by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) 2000 by Jaroslav Kysela <perex@suse.cz>
+ * Abramo Bagnara <abramo@alsa-project.org>
*
*
* This library is free software; you can redistribute it and/or modify
@@ -19,81 +20,114 @@
*
*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <sys/time.h>
+#include <sys/poll.h>
+#include <dlfcn.h>
+#include "seq_local.h"
#include "asoundlib.h"
-#include "seq_priv.h"
-#define SND_FILE_SEQ "/dev/snd/seq"
-#define SND_FILE_ALOADSEQ "/dev/aloadSEQ"
-#define SND_SEQ_VERSION_MAX SND_PROTOCOL_VERSION(1, 0, 0)
-#define SND_SEQ_OBUF_SIZE (16*1024) /* default size */
-#define SND_SEQ_IBUF_SIZE 500 /* in event_size aligned */
-#define DEFAULT_TMPBUF_SIZE 20
-
-/*
- * open a sequencer device so that it creates a user-client.
- */
-int snd_seq_open(snd_seq_t **handle, int mode)
+int snd_seq_open(snd_seq_t **seqp, char *name,
+ int streams, int mode)
{
- int fd, ver, client, flg;
- char filename[32];
- snd_seq_t *seq;
-
- *handle = NULL;
-
- sprintf(filename, SND_FILE_SEQ);
- if ((fd = open(filename, mode)) < 0) {
- close(open(SND_FILE_ALOADSEQ, O_RDWR));
- if ((fd = open(filename, mode)) < 0)
- return -errno;
+ char *str;
+ int err;
+ snd_config_t *seq_conf, *conf, *type_conf;
+ snd_config_iterator_t i;
+ char *lib = NULL, *open = NULL;
+ int (*open_func)(snd_seq_t **seqp, char *name, snd_config_t *conf,
+ int streams, int mode);
+ void *h;
+ assert(seqp && name);
+ err = snd_config_update();
+ if (err < 0)
+ return err;
+ err = snd_config_searchv(snd_config, &seq_conf, "seq", name, 0);
+ if (err < 0) {
+ if (strcmp(name, "hw") == 0)
+ return snd_seq_hw_open(seqp, name, streams, mode);
+ ERR("Unknown SEQ %s", name);
+ return -ENOENT;
}
- if (ioctl(fd, SND_SEQ_IOCTL_PVERSION, &ver) < 0) {
- close(fd);
- return -errno;
+ if (snd_config_type(seq_conf) != SND_CONFIG_TYPE_COMPOUND) {
+ ERR("Invalid type for SEQ definition");
+ return -EINVAL;
+ }
+ err = snd_config_search(seq_conf, "streams", &conf);
+ if (err >= 0) {
+ err = snd_config_string_get(conf, &str);
+ if (err < 0) {
+ ERR("Invalid type for streams");
+ return err;
+ }
+ if (strcmp(str, "output") == 0) {
+ if (streams == SND_SEQ_OPEN_INPUT)
+ return -EINVAL;
+ } else if (strcmp(str, "input") == 0) {
+ if (streams == SND_SEQ_OPEN_OUTPUT)
+ return -EINVAL;
+ } else if (strcmp(str, "duplex") == 0) {
+ if (streams != SND_SEQ_OPEN_DUPLEX)
+ return -EINVAL;
+ } else {
+ ERR("Invalid value for streams");
+ return -EINVAL;
+ }
}
- if (SND_PROTOCOL_INCOMPATIBLE(ver, SND_SEQ_VERSION_MAX)) {
- close(fd);
- return -SND_ERROR_INCOMPATIBLE_VERSION;
+ err = snd_config_search(seq_conf, "type", &conf);
+ if (err < 0) {
+ ERR("type is not defined");
+ return err;
}
- if (ioctl(fd, SND_SEQ_IOCTL_CLIENT_ID, &client) < 0) {
- close(fd);
- return -errno;
+ err = snd_config_string_get(conf, &str);
+ if (err < 0) {
+ ERR("Invalid type for type");
+ return err;
}
- seq = (snd_seq_t *) calloc(1, sizeof(snd_seq_t));
- if (seq == NULL) {
- close(fd);
- return -ENOMEM;
+ err = snd_config_searchv(snd_config, &type_conf, "seqtype", str, 0);
+ if (err < 0) {
+ ERR("Unknown SEQ type %s", str);
+ return err;
}
- seq->client = client;
- seq->fd = fd;
- flg = 3;
- if (mode == SND_SEQ_OPEN_OUT || mode == SND_SEQ_OPEN)
- seq->obuf = (char *) malloc(seq->obufsize = SND_SEQ_OBUF_SIZE);
- else
- flg &= ~1;
- if (mode == SND_SEQ_OPEN_IN || mode == SND_SEQ_OPEN)
- seq->ibuf = (snd_seq_event_t *) calloc(sizeof(snd_seq_event_t), seq->ibufsize = SND_SEQ_IBUF_SIZE);
- else
- flg &= ~2;
- if ((!seq->obuf && (flg & 1)) || (!seq->ibuf && (flg & 2))) {
- if (seq->obuf)
- free(seq->obuf);
- if (seq->ibuf)
- free(seq->ibuf);
- free(seq);
- return -ENOMEM;
+ 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, "lib") == 0) {
+ err = snd_config_string_get(n, &lib);
+ if (err < 0) {
+ ERR("Invalid type for lib");
+ return -EINVAL;
+ }
+ continue;
+ }
+ if (strcmp(n->id, "open") == 0) {
+ err = snd_config_string_get(n, &open);
+ if (err < 0) {
+ ERR("Invalid type for open");
+ return -EINVAL;
+ }
+ continue;
+ ERR("Unknown field: %s", n->id);
+ return -EINVAL;
+ }
}
- seq->tmpbuf = NULL;
- seq->tmpbufsize = 0;
- *handle = seq;
- return 0;
+ if (!open) {
+ ERR("open is not defined");
+ return -EINVAL;
+ }
+ if (!lib)
+ lib = "libasound.so";
+ h = dlopen(lib, RTLD_NOW);
+ if (!h) {
+ ERR("Cannot open shared library %s", lib);
+ return -ENOENT;
+ }
+ open_func = dlsym(h, open);
+ dlclose(h);
+ if (!open_func) {
+ ERR("symbol %s is not defined inside %s", open, lib);
+ return -ENXIO;
+ }
+ return open_func(seqp, name, seq_conf, streams, mode);
}
/*
@@ -101,19 +135,21 @@ int snd_seq_open(snd_seq_t **handle, int mode)
*/
int snd_seq_close(snd_seq_t *seq)
{
- int res;
-
- if (!seq)
- return -EINVAL;
- res = close(seq->fd) < 0 ? -errno : 0;
+ int err;
+ assert(seq);
+ err = seq->ops->close(seq);
+ if (err < 0)
+ return err;
if (seq->obuf)
free(seq->obuf);
if (seq->ibuf)
free(seq->ibuf);
if (seq->tmpbuf)
free(seq->tmpbuf);
+ if (seq->name)
+ free(seq->name);
free(seq);
- return res;
+ return 0;
}
/*
@@ -121,28 +157,24 @@ int snd_seq_close(snd_seq_t *seq)
*/
int snd_seq_poll_descriptor(snd_seq_t *seq)
{
- if (!seq)
- return -EINVAL;
- return seq->fd;
+ assert(seq);
+ return seq->poll_fd;
}
/*
* set blocking behavior
*/
-int snd_seq_block_mode(snd_seq_t *seq, int enable)
+int snd_seq_nonblock(snd_seq_t *seq, int nonblock)
{
- long flags;
-
- if (!seq)
- return -EINVAL;
- if ((flags = fcntl(seq->fd, F_GETFL)) < 0)
- return -errno;
- if (enable)
- flags &= ~O_NONBLOCK;
+ int err;
+ assert(seq);
+ err = seq->ops->nonblock(seq, nonblock);
+ if (err < 0)
+ return err;
+ if (nonblock)
+ seq->mode |= SND_SEQ_NONBLOCK;
else
- flags |= O_NONBLOCK;
- if (fcntl(seq->fd, F_SETFL, flags) < 0)
- return -errno;
+ seq->mode &= ~SND_SEQ_NONBLOCK;
return 0;
}
@@ -151,8 +183,7 @@ int snd_seq_block_mode(snd_seq_t *seq, int enable)
*/
int snd_seq_client_id(snd_seq_t *seq)
{
- if (!seq)
- return -EINVAL;
+ assert(seq);
return seq->client;
}
@@ -161,8 +192,7 @@ int snd_seq_client_id(snd_seq_t *seq)
*/
int snd_seq_output_buffer_size(snd_seq_t *seq)
{
- if (!seq)
- return -EINVAL;
+ assert(seq);
if (!seq->obuf)
return 0;
return seq->obufsize;
@@ -173,8 +203,7 @@ int snd_seq_output_buffer_size(snd_seq_t *seq)
*/
int snd_seq_input_buffer_size(snd_seq_t *seq)
{
- if (!seq)
- return -EINVAL;
+ assert(seq);
if (!seq->ibuf)
return 0;
return seq->ibufsize * sizeof(snd_seq_event_t);
@@ -185,10 +214,8 @@ int snd_seq_input_buffer_size(snd_seq_t *seq)
*/
int snd_seq_resize_output_buffer(snd_seq_t *seq, size_t size)
{
- if (!seq || !seq->obuf)
- return -EINVAL;
- if (size < sizeof(snd_seq_event_t))
- return -EINVAL;
+ assert(seq && seq->obuf);
+ assert(size >= sizeof(snd_seq_event_t));
snd_seq_drop_output(seq);
if (size != seq->obufsize) {
char *newbuf;
@@ -207,10 +234,8 @@ int snd_seq_resize_output_buffer(snd_seq_t *seq, size_t size)
*/
int snd_seq_resize_input_buffer(snd_seq_t *seq, size_t size)
{
- if (!seq || !seq->ibuf)
- return -EINVAL;
- if (size < sizeof(snd_seq_event_t))
- return -EINVAL;
+ assert(seq && seq->ibuf);
+ assert(size >= sizeof(snd_seq_event_t));
snd_seq_drop_input(seq);
size = (size + sizeof(snd_seq_event_t) - 1) / sizeof(snd_seq_event_t);
if (size != seq->ibufsize) {
@@ -230,35 +255,27 @@ int snd_seq_resize_input_buffer(snd_seq_t *seq, size_t size)
*/
int snd_seq_system_info(snd_seq_t *seq, snd_seq_system_info_t * info)
{
- if (!seq || !info)
- return -EINVAL;
- if (ioctl(seq->fd, SND_SEQ_IOCTL_SYSTEM_INFO, info) < 0)
- return -errno;
- return 0;
+ assert(seq && info);
+ return seq->ops->system_info(seq, info);
}
/*
- * obtain the current client information
+ * obtain the information of given client
*/
-int snd_seq_get_client_info(snd_seq_t *seq, snd_seq_client_info_t * info)
+int snd_seq_get_any_client_info(snd_seq_t *seq, int client, snd_seq_client_info_t * info)
{
- if (!seq || !info)
- return -EINVAL;
- return snd_seq_get_any_client_info(seq, seq->client, info);
+ assert(seq && info && client >= 0);
+ memset(info, 0, sizeof(snd_seq_client_info_t));
+ info->client = client;
+ return seq->ops->get_client_info(seq, info);
}
/*
- * obtain the information of given client
+ * obtain the current client information
*/
-int snd_seq_get_any_client_info(snd_seq_t *seq, int client, snd_seq_client_info_t * info)
+int snd_seq_get_client_info(snd_seq_t *seq, snd_seq_client_info_t * info)
{
- if (!seq || !info || client < 0)
- return -EINVAL;
- bzero(info, sizeof(snd_seq_client_info_t));
- info->client = client;
- if (ioctl(seq->fd, SND_SEQ_IOCTL_GET_CLIENT_INFO, info) < 0)
- return -errno;
- return 0;
+ return snd_seq_get_any_client_info(seq, seq->client, info);
}
/*
@@ -266,13 +283,10 @@ int snd_seq_get_any_client_info(snd_seq_t *seq, int client, snd_seq_client_info_
*/
int snd_seq_set_client_info(snd_seq_t *seq, snd_seq_client_info_t * info)
{
- if (!seq || !info)
- return -EINVAL;
+ assert(seq && info);
info->client = seq->client;
info->type = USER_CLIENT;
- if (ioctl(seq->fd, SND_SEQ_IOCTL_SET_CLIENT_INFO, info) < 0)
- return -errno;
- return 0;
+ return seq->ops->set_client_info(seq, info);
}
/*----------------------------------------------------------------*/
@@ -283,51 +297,37 @@ int snd_seq_set_client_info(snd_seq_t *seq, snd_seq_client_info_t * info)
int snd_seq_create_port(snd_seq_t *seq, snd_seq_port_info_t * port)
{
- if (!seq || !port)
- return -EINVAL;
+ assert(seq && port);
port->client = seq->client;
- if (ioctl(seq->fd, SND_SEQ_IOCTL_CREATE_PORT, port) < 0)
- return -errno;
- return 0;
+ return seq->ops->create_port(seq, port);
}
int snd_seq_delete_port(snd_seq_t *seq, snd_seq_port_info_t * port)
{
- if (!seq || !port)
- return -EINVAL;
+ assert(seq && port);
port->client = seq->client;
- if (ioctl(seq->fd, SND_SEQ_IOCTL_DELETE_PORT, port) < 0)
- return -errno;
- return 0;
-}
-
-int snd_seq_get_port_info(snd_seq_t *seq, int port, snd_seq_port_info_t * info)
-{
- if (!seq || !info || port < 0)
- return -EINVAL;
- return snd_seq_get_any_port_info(seq, seq->client, port, info);
+ return seq->ops->delete_port(seq, port);
}
int snd_seq_get_any_port_info(snd_seq_t *seq, int client, int port, snd_seq_port_info_t * info)
{
- if (!seq || !info || client < 0 || port < 0)
- return -EINVAL;
- bzero(info, sizeof(snd_seq_port_info_t));
+ assert(seq && info && client >= 0 && port >= 0);
+ memset(info, 0, sizeof(snd_seq_port_info_t));
info->client = client;
info->port = port;
- if (ioctl(seq->fd, SND_SEQ_IOCTL_GET_PORT_INFO, info) < 0)
- return -errno;
- return 0;
+ return seq->ops->get_port_info(seq, info);
+}
+
+int snd_seq_get_port_info(snd_seq_t *seq, int port, snd_seq_port_info_t * info)
+{
+ return snd_seq_get_any_port_info(seq, seq->client, port, info);
}
int snd_seq_set_port_info(snd_seq_t *seq, int port, snd_seq_port_info_t * info)
{
- if (!seq || !info || port < 0)
- return -EINVAL;
+ assert(seq && info && port >= 0);
info->port = port;
- if (ioctl(seq->fd, SND_SEQ_IOCTL_SET_PORT_INFO, info) < 0)
- return -errno;
- return 0;
+ return seq->ops->set_port_info(seq, info);
}
/*----------------------------------------------------------------*/
@@ -338,38 +338,26 @@ int snd_seq_set_port_info(snd_seq_t *seq, int port, snd_seq_port_info_t * info)
int snd_seq_get_port_subscription(snd_seq_t *seq, snd_seq_port_subscribe_t * sub)
{
- if (!seq || !sub)
- return -EINVAL;
- if (ioctl(seq->fd, SND_SEQ_IOCTL_GET_SUBSCRIPTION, sub) < 0)
- return -errno;
- return 0;
+ assert(seq && sub);
+ return seq->ops->get_port_subscription(seq, sub);
}
int snd_seq_subscribe_port(snd_seq_t *seq, snd_seq_port_subscribe_t * sub)
{
- if (!seq || !sub)
- return -EINVAL;
- if (ioctl(seq->fd, SND_SEQ_IOCTL_SUBSCRIBE_PORT, sub) < 0)
- return -errno;
- return 0;
+ assert(seq && sub);
+ return seq->ops->subscribe_port(seq, sub);
}
int snd_seq_unsubscribe_port(snd_seq_t *seq, snd_seq_port_subscribe_t * sub)
{
- if (!seq || !sub)
- return -EINVAL;
- if (ioctl(seq->fd, SND_SEQ_IOCTL_UNSUBSCRIBE_PORT, sub) < 0)
- return -errno;
- return 0;
+ assert(seq && sub);
+ return seq->ops->unsubscribe_port(seq, sub);
}
int snd_seq_query_port_subscribers(snd_seq_t *seq, snd_seq_query_subs_t * subs)
{
- if (!seq || !subs)
- return -EINVAL;
- if (ioctl(seq->fd, SND_SEQ_IOCTL_QUERY_SUBS, subs) < 0)
- return -errno;
- return 0;
+ assert(seq && subs);
+ return seq->ops->query_port_subscribers(seq, subs);
}
/*----------------------------------------------------------------*/
@@ -380,118 +368,88 @@ int snd_seq_query_port_subscribers(snd_seq_t *seq, snd_seq_query_subs_t * subs)
int snd_seq_get_queue_status(snd_seq_t *seq, int q, snd_seq_queue_status_t * status)
{
- if (!seq || !status)
- return -EINVAL;
- bzero(status, sizeof(snd_seq_queue_status_t));
+ assert(seq && status);
+ memset(status, 0, sizeof(snd_seq_queue_status_t));
status->queue = q;
- if (ioctl(seq->fd, SND_SEQ_IOCTL_GET_QUEUE_STATUS, status) < 0)
- return -errno;
- return 0;
+ return seq->ops->get_queue_status(seq, status);
}
int snd_seq_get_queue_tempo(snd_seq_t *seq, int q, snd_seq_queue_tempo_t * tempo)
{
- if (!seq || !tempo)
- return -EINVAL;
- bzero(tempo, sizeof(snd_seq_queue_tempo_t));
+ assert(seq && tempo);
+ memset(tempo, 0, sizeof(snd_seq_queue_tempo_t));
tempo->queue = q;
- if (ioctl(seq->fd, SND_SEQ_IOCTL_GET_QUEUE_TEMPO, tempo) < 0)
- return -errno;
- return 0;
+ return seq->ops->get_queue_tempo(seq, tempo);
}
int snd_seq_set_queue_tempo(snd_seq_t *seq, int q, snd_seq_queue_tempo_t * tempo)
{
- if (!seq || !tempo)
- return -EINVAL;
+ assert(seq && tempo);
tempo->queue = q;
- if (ioctl(seq->fd, SND_SEQ_IOCTL_SET_QUEUE_TEMPO, tempo) < 0)
- return -errno;
- return 0;
+ return seq->ops->set_queue_tempo(seq, tempo);
}
int snd_seq_get_queue_owner(snd_seq_t *seq, int q, snd_seq_queue_owner_t * owner)
{
- if (!seq || !owner)
- return -EINVAL;
- bzero(owner, sizeof(snd_seq_queue_owner_t));
+ assert(seq && owner);
+ memset(owner, 0, sizeof(snd_seq_queue_owner_t));
owner->queue = q;
- if (ioctl(seq->fd, SND_SEQ_IOCTL_GET_QUEUE_OWNER, owner) < 0)
- return -errno;
- return 0;
+ return seq->ops->get_queue_owner(seq, owner);
}
int snd_seq_set_queue_owner(snd_seq_t *seq, int q, snd_seq_queue_owner_t * owner)
{
- if (!seq || !owner)
- return -EINVAL;
+ assert(seq && owner);
owner->queue = q;
- if (ioctl(seq->fd, SND_SEQ_IOCTL_SET_QUEUE_OWNER, owner) < 0)
- return -errno;
- return 0;
+ return seq->ops->set_queue_owner(seq, owner);
}
int snd_seq_get_queue_timer(snd_seq_t *seq, int q, snd_seq_queue_timer_t * timer)
{
- if (!seq || !timer)
- return -EINVAL;
- bzero(timer, sizeof(snd_seq_queue_timer_t));
+ assert(seq && timer);
+ memset(timer, 0, sizeof(snd_seq_queue_timer_t));
timer->queue = q;
- if (ioctl(seq->fd, SND_SEQ_IOCTL_GET_QUEUE_TIMER, timer) < 0)
- return -errno;
- return 0;
+ return seq->ops->get_queue_timer(seq, timer);
}
int snd_seq_set_queue_timer(snd_seq_t *seq, int q, snd_seq_queue_timer_t * timer)
{
- if (!seq || !timer)
- return -EINVAL;
+ assert(seq && timer);
timer->queue = q;
- if (ioctl(seq->fd, SND_SEQ_IOCTL_SET_QUEUE_TIMER, timer) < 0)
- return -errno;
- return 0;
+ return seq->ops->set_queue_timer(seq, timer);
}
int snd_seq_get_queue_client(snd_seq_t *seq, int q, snd_seq_queue_client_t * info)
{
- if (!seq || !info)
- return -EINVAL;
- bzero(info, sizeof(snd_seq_queue_client_t));
+ assert(seq && info);
+ memset(info, 0, sizeof(snd_seq_queue_client_t));
info->queue = q;
info->client = seq->client;
- if (ioctl(seq->fd, SND_SEQ_IOCTL_GET_QUEUE_CLIENT, info) < 0)
- return -errno;
- return 0;
+ return seq->ops->get_queue_client(seq, info);
}
int snd_seq_set_queue_client(snd_seq_t *seq, int q, snd_seq_queue_client_t * info)
{
- if (!seq || !info)
- return -EINVAL;
+ assert(seq && info);
info->queue = q;
info->client = seq->client;
- if (ioctl(seq->fd, SND_SEQ_IOCTL_SET_QUEUE_CLIENT, info) < 0)
- return -errno;
- return 0;
+ return seq->ops->set_queue_client(seq, info);
}
int snd_seq_create_queue(snd_seq_t *seq, snd_seq_queue_info_t *info)
{
- if (!seq)
- return -EINVAL;
+ int err;
+ assert(seq && info);
info->owner = seq->client;
- if (ioctl(seq->fd, SND_SEQ_IOCTL_CREATE_QUEUE, info) < 0)
- return -errno;
+ err = seq->ops->create_queue(seq, info);
+ if (err < 0)
+ return err;
return info->queue;
}
int snd_seq_alloc_named_queue(snd_seq_t *seq, char *name)
{
snd_seq_queue_info_t info;
-
- if (!seq)
- return -EINVAL;
-
memset(&info, 0, sizeof(info));
info.locked = 1;
if (name)
@@ -508,10 +466,6 @@ int snd_seq_alloc_queue(snd_seq_t *seq)
int snd_seq_alloc_sync_queue(snd_seq_t *seq, char *name)
{
snd_seq_queue_info_t info;
-
- if (!seq)
- return -EINVAL;
-
memset(&info, 0, sizeof(info));
info.locked = 1;
if (name)
@@ -524,47 +478,35 @@ int snd_seq_alloc_sync_queue(snd_seq_t *seq, char *name)
int snd_seq_free_queue(snd_seq_t *seq, int q)
{
snd_seq_queue_info_t info;
-
- if (!seq)
- return -EINVAL;
-
+ assert(seq);
memset(&info, 0, sizeof(info));
info.queue = q;
- if (ioctl(seq->fd, SND_SEQ_IOCTL_DELETE_QUEUE, &info) < 0)
- return -errno;
-
- return 0;
+ return seq->ops->delete_queue(seq, &info);
}
int snd_seq_get_queue_info(snd_seq_t *seq, int q, snd_seq_queue_info_t *info)
{
- if (!seq || !info)
- return -EINVAL;
+ assert(seq && info);
info->queue = q;
- if (ioctl(seq->fd, SND_SEQ_IOCTL_GET_QUEUE_INFO, info) < 0)
- return -errno;
- return 0;
+ return seq->ops->get_queue_info(seq, info);
}
int snd_seq_set_queue_info(snd_seq_t *seq, int q, snd_seq_queue_info_t *info)
{
- if (!seq || !info)
- return -EINVAL;
+ assert(seq && info);
info->queue = q;
- if (ioctl(seq->fd, SND_SEQ_IOCTL_SET_QUEUE_INFO, info) < 0)
- return -errno;
- return 0;
+ return seq->ops->set_queue_info(seq, info);
}
int snd_seq_get_named_queue(snd_seq_t *seq, char *name)
{
+ int err;
snd_seq_queue_info_t info;
-
- if (!seq)
- return -EINVAL;
+ assert(seq && name);
strncpy(info.name, name, sizeof(info.name));
- if (ioctl(seq->fd, SND_SEQ_IOCTL_GET_NAMED_QUEUE, &info) < 0)
- return -errno;
+ err = seq->ops->get_named_queue(seq, &info);
+ if (err < 0)
+ return err;
return info.queue;
}
@@ -687,9 +629,7 @@ int snd_seq_free_event(snd_seq_event_t *ev ATTRIBUTE_UNUSED)
ssize_t snd_seq_event_length(snd_seq_event_t *ev)
{
ssize_t len = sizeof(snd_seq_event_t);
-
- if (!ev)
- return -EINVAL;
+ assert(ev);
if (snd_seq_ev_is_variable(ev))
len += ev->data.ext.len;
return len;
@@ -726,9 +666,7 @@ int snd_seq_event_output(snd_seq_t *seq, snd_seq_event_t *ev)
int snd_seq_event_output_buffer(snd_seq_t *seq, snd_seq_event_t *ev)
{
int len;
-
- if (!seq || !ev)
- return -EINVAL;
+ assert(seq && ev);
len = snd_seq_event_length(ev);
if (len < 0)
return -EINVAL;
@@ -773,7 +711,7 @@ static int alloc_tmpbuf(snd_seq_t *seq, size_t len)
*/
int snd_seq_event_output_direct(snd_seq_t *seq, snd_seq_event_t *ev)
{
- ssize_t len, result;
+ ssize_t len;
void *buf;
len = snd_seq_event_length(ev);
@@ -789,9 +727,7 @@ int snd_seq_event_output_direct(snd_seq_t *seq, snd_seq_event_t *ev)
buf = seq->tmpbuf;
}
- result = write(seq->fd, buf, len);
-
- return (result < 0) ? -errno : (int)result;
+ return seq->ops->write(seq, buf, len);
}
/*
@@ -799,8 +735,7 @@ int snd_seq_event_output_direct(snd_seq_t *seq, snd_seq_event_t *ev)
*/
int snd_seq_event_output_pending(snd_seq_t *seq)
{
- if (!seq)
- return -EINVAL;
+ assert(seq);
return seq->obufused;
}
@@ -809,14 +744,12 @@ int snd_seq_event_output_pending(snd_seq_t *seq)
*/
int snd_seq_drain_output(snd_seq_t *seq)
{
- int result;
-
- if (!seq)
- return -EINVAL;
+ ssize_t result;
+ assert(seq);
while (seq->obufused > 0) {
- result = write(seq->fd, seq->obuf, seq->obufused);
+ result = seq->ops->write(seq, seq->obuf, seq->obufused);
if (result < 0)
- return -errno;
+ return -result;
if ((size_t)result < seq->obufused)
memmove(seq->obuf, seq->obuf + result, seq->obufused - result);
seq->obufused -= result;
@@ -832,9 +765,7 @@ int snd_seq_extract_output(snd_seq_t *seq, snd_seq_event_t **ev_res)
{
size_t len, olen;
snd_seq_event_t ev;
-
- if (!seq)
- return -EINVAL;
+ assert(seq);
if (ev_res)
*ev_res = NULL;
if ((olen = seq->obufused) < sizeof(snd_seq_event_t))
@@ -865,9 +796,9 @@ int snd_seq_extract_output(snd_seq_t *seq, snd_seq_event_t **ev_res)
static ssize_t snd_seq_event_read_buffer(snd_seq_t *seq)
{
ssize_t len;
- len = read(seq->fd, seq->ibuf, seq->ibufsize * sizeof(snd_seq_event_t));
+ len = seq->ops->read(seq, seq->ibuf, seq->ibufsize * sizeof(snd_seq_event_t));
if (len < 0)
- return -errno;
+ return len;
seq->ibuflen = len / sizeof(snd_seq_event_t);
seq->ibufptr = 0;
return seq->ibuflen;
@@ -901,11 +832,8 @@ static int snd_seq_event_retrieve_buffer(snd_seq_t *seq, snd_seq_event_t **retp)
int snd_seq_event_input(snd_seq_t *seq, snd_seq_event_t **ev)
{
int err;
-
+ assert(seq);
*ev = NULL;
- if (!seq)
- return -EINVAL;
-
if (seq->ibuflen <= 0) {
if ((err = snd_seq_event_read_buffer(seq)) < 0)
return err;
@@ -917,15 +845,18 @@ int snd_seq_event_input(snd_seq_t *seq, snd_seq_event_t **ev)
/*
* read input data from sequencer if available
*/
-static int snd_seq_event_input_feed(snd_seq_t *seq, struct timeval *timeout)
+static int snd_seq_event_input_feed(snd_seq_t *seq, int timeout)
{
- fd_set rfds;
-
- FD_ZERO(&rfds);
- FD_SET(seq->fd, &rfds);
- if (select(seq->fd + 1, &rfds, NULL, NULL, timeout) < 0)
+ struct pollfd pfd;
+ int err;
+ pfd.fd = seq->poll_fd;
+ pfd.events = POLLIN;
+ err = poll(&pfd, 1, timeout);
+ if (err < 0) {
+ SYSERR("poll");
return -errno;
- if (FD_ISSET(seq->fd, &rfds))
+ }
+ if (pfd.revents & POLLIN)
return snd_seq_event_read_buffer(seq);
return seq->ibuflen;
}
@@ -936,10 +867,7 @@ static int snd_seq_event_input_feed(snd_seq_t *seq, struct timeval *timeout)
int snd_seq_event_input_pending(snd_seq_t *seq, int fetch_sequencer)
{
if (seq->ibuflen == 0 && fetch_sequencer) {
- struct timeval tv;
- tv.tv_sec = 0;
- tv.tv_usec = 0;
- return snd_seq_event_input_feed(seq, &tv);
+ return snd_seq_event_input_feed(seq, 0);
}
return seq->ibuflen;
}
@@ -955,8 +883,7 @@ int snd_seq_event_input_pending(snd_seq_t *seq, int fetch_sequencer)
*/
int snd_seq_drop_output_buffer(snd_seq_t *seq)
{
- if (!seq)
- return -EINVAL;
+ assert(seq);
seq->obufused = 0;
return 0;
}
@@ -966,8 +893,7 @@ int snd_seq_drop_output_buffer(snd_seq_t *seq)
*/
int snd_seq_drop_input_buffer(snd_seq_t *seq)
{
- if (!seq)
- return -EINVAL;
+ assert(seq);
seq->ibufptr = 0;
seq->ibuflen = 0;
return 0;
@@ -979,10 +905,7 @@ int snd_seq_drop_input_buffer(snd_seq_t *seq)
int snd_seq_drop_output(snd_seq_t *seq)
{
snd_seq_remove_events_t rminfo;
-
- if (!seq)
- return -EINVAL;
-
+ assert(seq);
seq->obufused = 0; /* drain output buffer */
memset(&rminfo, 0, sizeof(rminfo));
@@ -997,9 +920,7 @@ int snd_seq_drop_output(snd_seq_t *seq)
int snd_seq_drop_input(snd_seq_t *seq)
{
snd_seq_remove_events_t rminfo;
-
- if (!seq)
- return -EINVAL;
+ assert(seq);
seq->ibufptr = 0; /* drain input buffer */
seq->ibuflen = 0;
@@ -1131,10 +1052,7 @@ int snd_seq_remove_events(snd_seq_t *seq, snd_seq_remove_events_t *rmp)
}
}
- if (ioctl(seq->fd, SND_SEQ_IOCTL_REMOVE_EVENTS, rmp) < 0)
- return -errno;
-
- return 0;
+ return seq->ops->remove_events(seq, rmp);
}
/*----------------------------------------------------------------*/
@@ -1145,22 +1063,16 @@ int snd_seq_remove_events(snd_seq_t *seq, snd_seq_remove_events_t *rmp)
int snd_seq_get_client_pool(snd_seq_t *seq, snd_seq_client_pool_t *info)
{
- if (!seq || !info)
- return -EINVAL;
+ assert(seq && info);
info->client = seq->client;
- if (ioctl(seq->fd, SND_SEQ_IOCTL_GET_CLIENT_POOL, info) < 0)
- return -errno;
- return 0;
+ return seq->ops->get_client_pool(seq, info);
}
int snd_seq_set_client_pool(snd_seq_t *seq, snd_seq_client_pool_t *info)
{
- if (!seq || !info)
- return -EINVAL;
+ assert(seq && info);
info->client = seq->client;
- if (ioctl(seq->fd, SND_SEQ_IOCTL_SET_CLIENT_POOL, info) < 0)
- return -errno;
- return 0;
+ return seq->ops->set_client_pool(seq, info);
}
/*----------------------------------------------------------------*/
@@ -1171,20 +1083,14 @@ int snd_seq_set_client_pool(snd_seq_t *seq, snd_seq_client_pool_t *info)
int snd_seq_query_next_client(snd_seq_t *seq, snd_seq_client_info_t *info)
{
- if (!seq || !info)
- return -EINVAL;
- if (ioctl(seq->fd, SND_SEQ_IOCTL_QUERY_NEXT_CLIENT, info) < 0)
- return -errno;
- return 0;
+ assert(seq && info);
+ return seq->ops->query_next_client(seq, info);
}
int snd_seq_query_next_port(snd_seq_t *seq, snd_seq_port_info_t *info)
{
- if (!seq || !info)
- return -EINVAL;
- if (ioctl(seq->fd, SND_SEQ_IOCTL_QUERY_NEXT_PORT, info) < 0)
- return -errno;
- return 0;
+ assert(seq && info);
+ return seq->ops->query_next_port(seq, info);
}
/*----------------------------------------------------------------*/
diff --git a/src/seq/seq_hw.c b/src/seq/seq_hw.c
new file mode 100644
index 00000000..4f7e243c
--- /dev/null
+++ b/src/seq/seq_hw.c
@@ -0,0 +1,545 @@
+/*
+ * Sequencer Interface - main file
+ * Copyright (c) 2000 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.
+ *
+ */
+
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include "seq_local.h"
+#include "asoundlib.h"
+
+#define SND_FILE_SEQ "/dev/snd/seq"
+#define SND_FILE_ALOADSEQ "/dev/aloadSEQ"
+#define SND_SEQ_VERSION_MAX SND_PROTOCOL_VERSION(1, 0, 0)
+
+typedef struct {
+ int fd;
+} snd_seq_hw_t;
+
+static int snd_seq_hw_close(snd_seq_t *seq)
+{
+ snd_seq_hw_t *hw = seq->private;
+ if (close(hw->fd)) {
+ SYSERR("close failed\n");
+ return -errno;
+ }
+ free(hw);
+ return 0;
+}
+
+static int snd_seq_hw_nonblock(snd_seq_t *seq, int nonblock)
+{
+ snd_seq_hw_t *hw = seq->private;
+ long flags;
+
+ if ((flags = fcntl(hw->fd, F_GETFL)) < 0) {
+ SYSERR("F_GETFL failed");
+ return -errno;
+ }
+ if (nonblock)
+ flags &= ~O_NONBLOCK;
+ else
+ flags |= O_NONBLOCK;
+ if (fcntl(hw->fd, F_SETFL, flags) < 0) {
+ SYSERR("F_SETFL for O_NONBLOCK failed");
+ return -errno;
+ }
+ return 0;
+}
+
+static int snd_seq_hw_client_id(snd_seq_t *seq)
+{
+ snd_seq_hw_t *hw = seq->private;
+ int client;
+ if (ioctl(hw->fd, SND_SEQ_IOCTL_CLIENT_ID, &client) < 0) {
+ SYSERR("SND_SEQ_IOCTL_CLIENT_ID failed");
+ return -errno;
+ }
+ return client;
+}
+
+static int snd_seq_hw_system_info(snd_seq_t *seq, snd_seq_system_info_t * info)
+{
+ snd_seq_hw_t *hw = seq->private;
+ if (ioctl(hw->fd, SND_SEQ_IOCTL_SYSTEM_INFO, info) < 0) {
+ SYSERR("SND_SEQ_IOCTL_SYSTEM_INFO failed");
+ return -errno;
+ }
+ return 0;
+}
+
+static int snd_seq_hw_get_client_info(snd_seq_t *seq, snd_seq_client_info_t * info)
+{
+ snd_seq_hw_t *hw = seq->private;
+ if (ioctl(hw->fd, SND_SEQ_IOCTL_GET_CLIENT_INFO, info) < 0) {
+ SYSERR("SND_SEQ_IOCTL_GET_CLIENT_INFO failed");
+ return -errno;
+ }
+ return 0;
+}
+
+static int snd_seq_hw_set_client_info(snd_seq_t *seq, snd_seq_client_info_t * info)
+{
+ snd_seq_hw_t *hw = seq->private;
+ if (ioctl(hw->fd, SND_SEQ_IOCTL_SET_CLIENT_INFO, info) < 0) {
+ SYSERR("SND_SEQ_IOCTL_SET_CLIENT_INFO failed");
+ return -errno;
+ }
+ return 0;
+}
+
+static int snd_seq_hw_create_port(snd_seq_t *seq, snd_seq_port_info_t * port)
+{
+ snd_seq_hw_t *hw = seq->private;
+ if (ioctl(hw->fd, SND_SEQ_IOCTL_CREATE_PORT, port) < 0) {
+ SYSERR("SND_SEQ_IOCTL_CREATE_PORT failed");
+ return -errno;
+ }
+ return 0;
+}
+
+static int snd_seq_hw_delete_port(snd_seq_t *seq, snd_seq_port_info_t * port)
+{
+ snd_seq_hw_t *hw = seq->private;
+ if (ioctl(hw->fd, SND_SEQ_IOCTL_DELETE_PORT, port) < 0) {
+ SYSERR("SND_SEQ_IOCTL_DELETE_PORT failed");
+ return -errno;
+ }
+ return 0;
+}
+
+static int snd_seq_hw_get_port_info(snd_seq_t *seq, snd_seq_port_info_t * info)
+{
+ snd_seq_hw_t *hw = seq->private;
+ if (ioctl(hw->fd, SND_SEQ_IOCTL_GET_PORT_INFO, info) < 0) {
+ SYSERR("SND_SEQ_IOCTL_GET_PORT_INFO failed");
+ return -errno;
+ }
+ return 0;
+}
+
+static int snd_seq_hw_set_port_info(snd_seq_t *seq, snd_seq_port_info_t * info)
+{
+ snd_seq_hw_t *hw = seq->private;
+ if (ioctl(hw->fd, SND_SEQ_IOCTL_SET_PORT_INFO, info) < 0) {
+ SYSERR("SND_SEQ_IOCTL_SET_PORT_INFO failed");
+ return -errno;
+ }
+ return 0;
+}
+
+static int snd_seq_hw_get_port_subscription(snd_seq_t *seq, snd_seq_port_subscribe_t * sub)
+{
+ snd_seq_hw_t *hw = seq->private;
+ if (ioctl(hw->fd, SND_SEQ_IOCTL_GET_SUBSCRIPTION, sub) < 0) {
+ SYSERR("SND_SEQ_IOCTL_GET_SUBSCRIPTION failed");
+ return -errno;
+ }
+ return 0;
+}
+
+static int snd_seq_hw_subscribe_port(snd_seq_t *seq, snd_seq_port_subscribe_t * sub)
+{
+ snd_seq_hw_t *hw = seq->private;
+ if (ioctl(hw->fd, SND_SEQ_IOCTL_SUBSCRIBE_PORT, sub) < 0) {
+ SYSERR("SND_SEQ_IOCTL_SUBSCRIBE_PORT failed");
+ return -errno;
+ }
+ return 0;
+}
+
+static int snd_seq_hw_unsubscribe_port(snd_seq_t *seq, snd_seq_port_subscribe_t * sub)
+{
+ snd_seq_hw_t *hw = seq->private;
+ if (ioctl(hw->fd, SND_SEQ_IOCTL_UNSUBSCRIBE_PORT, sub) < 0) {
+ SYSERR("SND_SEQ_IOCTL_UNSUBSCRIBE_PORT failed");
+ return -errno;
+ }
+ return 0;
+}
+
+static int snd_seq_hw_query_port_subscribers(snd_seq_t *seq, snd_seq_query_subs_t * subs)
+{
+ snd_seq_hw_t *hw = seq->private;
+ if (ioctl(hw->fd, SND_SEQ_IOCTL_QUERY_SUBS, subs) < 0) {
+ SYSERR("SND_SEQ_IOCTL_QUERY_SUBS failed");
+ return -errno;
+ }
+ return 0;
+}
+
+static int snd_seq_hw_get_queue_status(snd_seq_t *seq, snd_seq_queue_status_t * status)
+{
+ snd_seq_hw_t *hw = seq->private;
+ if (ioctl(hw->fd, SND_SEQ_IOCTL_GET_QUEUE_STATUS, status) < 0) {
+ SYSERR("SND_SEQ_IOCTL_GET_QUEUE_STATUS failed");
+ return -errno;
+ }
+ return 0;
+}
+
+static int snd_seq_hw_get_queue_tempo(snd_seq_t *seq, snd_seq_queue_tempo_t * tempo)
+{
+ snd_seq_hw_t *hw = seq->private;
+ if (ioctl(hw->fd, SND_SEQ_IOCTL_GET_QUEUE_TEMPO, tempo) < 0) {
+ SYSERR("SND_SEQ_IOCTL_GET_QUEUE_TEMPO failed");
+ return -errno;
+ }
+ return 0;
+}
+
+static int snd_seq_hw_set_queue_tempo(snd_seq_t *seq, snd_seq_queue_tempo_t * tempo)
+{
+ snd_seq_hw_t *hw = seq->private;
+ if (ioctl(hw->fd, SND_SEQ_IOCTL_SET_QUEUE_TEMPO, tempo) < 0) {
+ SYSERR("SND_SEQ_IOCTL_SET_QUEUE_TEMPO failed");
+ return -errno;
+ }
+ return 0;
+}
+
+static int snd_seq_hw_get_queue_owner(snd_seq_t *seq, snd_seq_queue_owner_t * owner)
+{
+ snd_seq_hw_t *hw = seq->private;
+ if (ioctl(hw->fd, SND_SEQ_IOCTL_GET_QUEUE_OWNER, owner) < 0) {
+ SYSERR("SND_SEQ_IOCTL_GET_QUEUE_OWNER failed");
+ return -errno;
+ }
+ return 0;
+}
+
+static int snd_seq_hw_set_queue_owner(snd_seq_t *seq, snd_seq_queue_owner_t * owner)
+{
+ snd_seq_hw_t *hw = seq->private;
+ if (ioctl(hw->fd, SND_SEQ_IOCTL_SET_QUEUE_OWNER, owner) < 0) {
+ SYSERR("SND_SEQ_IOCTL_SET_QUEUE_OWNER failed");
+ return -errno;
+ }
+ return 0;
+}
+
+static int snd_seq_hw_get_queue_timer(snd_seq_t *seq, snd_seq_queue_timer_t * timer)
+{
+ snd_seq_hw_t *hw = seq->private;
+ if (ioctl(hw->fd, SND_SEQ_IOCTL_GET_QUEUE_TIMER, timer) < 0) {
+ SYSERR("SND_SEQ_IOCTL_GET_QUEUE_TIMER failed");
+ return -errno;
+ }
+ return 0;
+}
+
+static int snd_seq_hw_set_queue_timer(snd_seq_t *seq, snd_seq_queue_timer_t * timer)
+{
+ snd_seq_hw_t *hw = seq->private;
+ if (ioctl(hw->fd, SND_SEQ_IOCTL_SET_QUEUE_TIMER, timer) < 0) {
+ SYSERR("SND_SEQ_IOCTL_SET_QUEUE_TIMER failed");
+ return -errno;
+ }
+ return 0;
+}
+
+static int snd_seq_hw_get_queue_client(snd_seq_t *seq, snd_seq_queue_client_t * info)
+{
+ snd_seq_hw_t *hw = seq->private;
+ if (ioctl(hw->fd, SND_SEQ_IOCTL_GET_QUEUE_CLIENT, info) < 0) {
+ SYSERR("SND_SEQ_IOCTL_GET_QUEUE_CLIENT failed");
+ return -errno;
+ }
+ return 0;
+}
+
+static int snd_seq_hw_set_queue_client(snd_seq_t *seq, snd_seq_queue_client_t * info)
+{
+ snd_seq_hw_t *hw = seq->private;
+ if (ioctl(hw->fd, SND_SEQ_IOCTL_SET_QUEUE_CLIENT, info) < 0) {
+ SYSERR("SND_SEQ_IOCTL_SET_QUEUE_CLIENT failed");
+ return -errno;
+ }
+ return 0;
+}
+
+static int snd_seq_hw_create_queue(snd_seq_t *seq, snd_seq_queue_info_t *info)
+{
+ snd_seq_hw_t *hw = seq->private;
+ if (ioctl(hw->fd, SND_SEQ_IOCTL_CREATE_QUEUE, info) < 0) {
+ SYSERR("SND_SEQ_IOCTL_CREATE_QUEUE failed");
+ return -errno;
+ }
+ return 0;
+}
+
+static int snd_seq_hw_delete_queue(snd_seq_t *seq, snd_seq_queue_info_t *info)
+{
+ snd_seq_hw_t *hw = seq->private;
+ if (ioctl(hw->fd, SND_SEQ_IOCTL_DELETE_QUEUE, info) < 0) {
+ SYSERR("SND_SEQ_IOCTL_DELETE_QUEUE failed");
+ return -errno;
+ }
+ return 0;
+}
+
+static int snd_seq_hw_get_queue_info(snd_seq_t *seq, snd_seq_queue_info_t *info)
+{
+ snd_seq_hw_t *hw = seq->private;
+ if (ioctl(hw->fd, SND_SEQ_IOCTL_GET_QUEUE_INFO, info) < 0) {
+ SYSERR("SND_SEQ_IOCTL_GET_QUEUE_INFO failed");
+ return -errno;
+ }
+ return 0;
+}
+
+static int snd_seq_hw_set_queue_info(snd_seq_t *seq, snd_seq_queue_info_t *info)
+{
+ snd_seq_hw_t *hw = seq->private;
+ if (ioctl(hw->fd, SND_SEQ_IOCTL_SET_QUEUE_INFO, info) < 0) {
+ SYSERR("SND_SEQ_IOCTL_SET_QUEUE_INFO failed");
+ return -errno;
+ }
+ return 0;
+}
+
+static int snd_seq_hw_get_named_queue(snd_seq_t *seq, snd_seq_queue_info_t *info)
+{
+ snd_seq_hw_t *hw = seq->private;
+ if (ioctl(hw->fd, SND_SEQ_IOCTL_GET_NAMED_QUEUE, info) < 0) {
+ SYSERR("SND_SEQ_IOCTL_GET_NAMED_QUEUE failed");
+ return -errno;
+ }
+ return 0;
+}
+
+static ssize_t snd_seq_hw_write(snd_seq_t *seq, void *buf, size_t len)
+{
+ snd_seq_hw_t *hw = seq->private;
+ ssize_t result = write(hw->fd, buf, len);
+ if (result < 0)
+ return -errno;
+ return result;
+}
+
+static ssize_t snd_seq_hw_read(snd_seq_t *seq, void *buf, size_t len)
+{
+ snd_seq_hw_t *hw = seq->private;
+ ssize_t result = read(hw->fd, buf, len);
+ if (result < 0)
+ return -errno;
+ return result;
+}
+
+static int snd_seq_hw_remove_events(snd_seq_t *seq, snd_seq_remove_events_t *rmp)
+{
+ snd_seq_hw_t *hw = seq->private;
+ if (ioctl(hw->fd, SND_SEQ_IOCTL_REMOVE_EVENTS, rmp) < 0) {
+ SYSERR("SND_SEQ_IOCTL_REMOVE_EVENTS failed");
+ return -errno;
+ }
+ return 0;
+}
+
+static int snd_seq_hw_get_client_pool(snd_seq_t *seq, snd_seq_client_pool_t *info)
+{
+ snd_seq_hw_t *hw = seq->private;
+ if (ioctl(hw->fd, SND_SEQ_IOCTL_GET_CLIENT_POOL, info) < 0) {
+ SYSERR("SND_SEQ_IOCTL_GET_CLIENT_POOL failed");
+ return -errno;
+ }
+ return 0;
+}
+
+static int snd_seq_hw_set_client_pool(snd_seq_t *seq, snd_seq_client_pool_t *info)
+{
+ snd_seq_hw_t *hw = seq->private;
+ if (ioctl(hw->fd, SND_SEQ_IOCTL_SET_CLIENT_POOL, info) < 0) {
+ SYSERR("SND_SEQ_IOCTL_SET_CLIENT_POOL failed");
+ return -errno;
+ }
+ return 0;
+}
+
+static int snd_seq_hw_query_next_client(snd_seq_t *seq, snd_seq_client_info_t *info)
+{
+ snd_seq_hw_t *hw = seq->private;
+ if (ioctl(hw->fd, SND_SEQ_IOCTL_QUERY_NEXT_CLIENT, info) < 0) {
+ SYSERR("SND_SEQ_IOCTL_QUERY_NEXT_CLIENT failed");
+ return -errno;
+ }
+ return 0;
+}
+
+static int snd_seq_hw_query_next_port(snd_seq_t *seq, snd_seq_port_info_t *info)
+{
+ snd_seq_hw_t *hw = seq->private;
+ if (ioctl(hw->fd, SND_SEQ_IOCTL_QUERY_NEXT_PORT, info) < 0) {
+ SYSERR("SND_SEQ_IOCTL_QUERY_NEXT_PORT failed");
+ return -errno;
+ }
+ return 0;
+}
+
+snd_seq_ops_t snd_seq_hw_ops = {
+ close: snd_seq_hw_close,
+ nonblock: snd_seq_hw_nonblock,
+ system_info: snd_seq_hw_system_info,
+ get_client_info: snd_seq_hw_get_client_info,
+ set_client_info: snd_seq_hw_set_client_info,
+ create_port: snd_seq_hw_create_port,
+ delete_port: snd_seq_hw_delete_port,
+ get_port_info: snd_seq_hw_get_port_info,
+ set_port_info: snd_seq_hw_set_port_info,
+ get_port_subscription: snd_seq_hw_get_port_subscription,
+ subscribe_port: snd_seq_hw_subscribe_port,
+ unsubscribe_port: snd_seq_hw_unsubscribe_port,
+ query_port_subscribers: snd_seq_hw_query_port_subscribers,
+ get_queue_status: snd_seq_hw_get_queue_status,
+ get_queue_tempo: snd_seq_hw_get_queue_tempo,
+ set_queue_tempo: snd_seq_hw_set_queue_tempo,
+ get_queue_owner: snd_seq_hw_get_queue_owner,
+ set_queue_owner: snd_seq_hw_set_queue_owner,
+ get_queue_timer: snd_seq_hw_get_queue_timer,
+ set_queue_timer: snd_seq_hw_set_queue_timer,
+ get_queue_client: snd_seq_hw_get_queue_client,
+ set_queue_client: snd_seq_hw_set_queue_client,
+ create_queue: snd_seq_hw_create_queue,
+ delete_queue: snd_seq_hw_delete_queue,
+ get_queue_info: snd_seq_hw_get_queue_info,
+ set_queue_info: snd_seq_hw_set_queue_info,
+ get_named_queue: snd_seq_hw_get_named_queue,
+ write: snd_seq_hw_write,
+ read: snd_seq_hw_read,
+ remove_events: snd_seq_hw_remove_events,
+ get_client_pool: snd_seq_hw_get_client_pool,
+ set_client_pool: snd_seq_hw_set_client_pool,
+ query_next_client: snd_seq_hw_query_next_client,
+ query_next_port: snd_seq_hw_query_next_port,
+};
+
+int snd_seq_hw_open(snd_seq_t **handle, char *name, int streams, int mode)
+{
+ int fd, ver, client, fmode;
+ char filename[32];
+ snd_seq_t *seq;
+ snd_seq_hw_t *hw;
+
+ *handle = NULL;
+
+ switch (streams) {
+ case SND_SEQ_OPEN_OUTPUT:
+ fmode = O_WRONLY;
+ break;
+ case SND_SEQ_OPEN_INPUT:
+ fmode = O_RDONLY;
+ break;
+ case SND_SEQ_OPEN_DUPLEX:
+ fmode = O_RDWR;
+ break;
+ default:
+ assert(0);
+ return -EINVAL;
+ }
+
+ if (mode & SND_SEQ_NONBLOCK)
+ fmode |= O_NONBLOCK;
+
+ sprintf(filename, SND_FILE_SEQ);
+ if ((fd = open(filename, fmode)) < 0) {
+ close(open(SND_FILE_ALOADSEQ, O_RDWR));
+ if ((fd = open(filename, fmode)) < 0) {
+ SYSERR("open %s failed", filename);
+ return -errno;
+ }
+ }
+ if (ioctl(fd, SND_SEQ_IOCTL_PVERSION, &ver) < 0) {
+ SYSERR("SND_SEQ_IOCTL_PVERSION failed");
+ close(fd);
+ return -errno;
+ }
+ if (SND_PROTOCOL_INCOMPATIBLE(ver, SND_SEQ_VERSION_MAX)) {
+ close(fd);
+ return -SND_ERROR_INCOMPATIBLE_VERSION;
+ }
+ hw = calloc(1, sizeof(snd_seq_hw_t));
+ if (hw == NULL) {
+ close(fd);
+ return -ENOMEM;
+ }
+
+ seq = calloc(1, sizeof(snd_seq_t));
+ if (seq == NULL) {
+ free(hw);
+ close(fd);
+ return -ENOMEM;
+ }
+ hw->fd = fd;
+ if (streams & SND_SEQ_OPEN_OUTPUT) {
+ seq->obuf = (char *) malloc(seq->obufsize = SND_SEQ_OBUF_SIZE);
+ if (!seq->obuf) {
+ free(hw);
+ free(seq);
+ close(fd);
+ return -ENOMEM;
+ }
+ }
+ if (streams & SND_SEQ_OPEN_INPUT) {
+ seq->ibuf = (snd_seq_event_t *) calloc(sizeof(snd_seq_event_t), seq->ibufsize = SND_SEQ_IBUF_SIZE);
+ if (!seq->ibuf) {
+ free(seq->ibuf);
+ free(hw);
+ free(seq);
+ close(fd);
+ return -ENOMEM;
+ }
+ }
+ if (name)
+ seq->name = strdup(name);
+ seq->type = SND_SEQ_TYPE_HW;
+ seq->streams = streams;
+ seq->mode = mode;
+ seq->tmpbuf = NULL;
+ seq->tmpbufsize = 0;
+ seq->poll_fd = fd;
+ seq->ops = &snd_seq_hw_ops;
+ seq->private = hw;
+ client = snd_seq_hw_client_id(seq);
+ if (client < 0) {
+ snd_seq_close(seq);
+ return client;
+ } else
+ seq->client = client;
+ *handle = seq;
+ return 0;
+}
+
+int _snd_seq_hw_open(snd_seq_t **handlep, char *name, snd_config_t *conf,
+ int streams, int mode)
+{
+ snd_config_iterator_t i;
+ 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, "streams") == 0)
+ continue;
+ return -EINVAL;
+ }
+ return snd_seq_hw_open(handlep, name, streams, mode);
+}
+
diff --git a/src/seq/seq_local.h b/src/seq/seq_local.h
new file mode 100644
index 00000000..24b815c7
--- /dev/null
+++ b/src/seq/seq_local.h
@@ -0,0 +1,105 @@
+/*
+ * Sequencer Interface - definition of sequencer event handler
+ * Copyright (c) 2000 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.
+ *
+ */
+
+#ifndef __SEQ_LOCAL_H
+#define __SEQ_LOCAL_H
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <errno.h>
+#include "asoundlib.h"
+
+#define SND_SEQ_OBUF_SIZE (16*1024) /* default size */
+#define SND_SEQ_IBUF_SIZE 500 /* in event_size aligned */
+#define DEFAULT_TMPBUF_SIZE 20
+
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)
+#define ERR(...) snd_lib_error(__FILE__, __LINE__, __FUNCTION__, 0, __VA_ARGS__)
+#define SYSERR(...) snd_lib_error(__FILE__, __LINE__, __FUNCTION__, errno, __VA_ARGS__)
+#else
+#define ERR(args...) snd_lib_error(__FILE__, __LINE__, __FUNCTION__, 0, ##args)
+#define SYSERR(args...) snd_lib_error(__FILE__, __LINE__, __FUNCTION__, errno, ##args)
+#endif
+
+typedef struct {
+ int (*close)(snd_seq_t *seq);
+ int (*nonblock)(snd_seq_t *seq, int nonblock);
+ int (*system_info)(snd_seq_t *seq, snd_seq_system_info_t * info);
+ int (*get_client_info)(snd_seq_t *seq, snd_seq_client_info_t * info);
+ int (*set_client_info)(snd_seq_t *seq, snd_seq_client_info_t * info);
+ int (*create_port)(snd_seq_t *seq, snd_seq_port_info_t * port);
+ int (*delete_port)(snd_seq_t *seq, snd_seq_port_info_t * port);
+ int (*get_port_info)(snd_seq_t *seq, snd_seq_port_info_t * info);
+ int (*set_port_info)(snd_seq_t *seq, snd_seq_port_info_t * info);
+ int (*get_port_subscription)(snd_seq_t *seq, snd_seq_port_subscribe_t * sub);
+ int (*subscribe_port)(snd_seq_t *seq, snd_seq_port_subscribe_t * sub);
+ int (*unsubscribe_port)(snd_seq_t *seq, snd_seq_port_subscribe_t * sub);
+ int (*query_port_subscribers)(snd_seq_t *seq, snd_seq_query_subs_t * subs);
+ int (*get_queue_status)(snd_seq_t *seq, snd_seq_queue_status_t * status);
+ int (*get_queue_tempo)(snd_seq_t *seq, snd_seq_queue_tempo_t * tempo);
+ int (*set_queue_tempo)(snd_seq_t *seq, snd_seq_queue_tempo_t * tempo);
+ int (*get_queue_owner)(snd_seq_t *seq, snd_seq_queue_owner_t * owner);
+ int (*set_queue_owner)(snd_seq_t *seq, snd_seq_queue_owner_t * owner);
+ int (*get_queue_timer)(snd_seq_t *seq, snd_seq_queue_timer_t * timer);
+ int (*set_queue_timer)(snd_seq_t *seq, snd_seq_queue_timer_t * timer);
+ int (*get_queue_client)(snd_seq_t *seq, snd_seq_queue_client_t * client);
+ int (*set_queue_client)(snd_seq_t *seq, snd_seq_queue_client_t * client);
+ int (*create_queue)(snd_seq_t *seq, snd_seq_queue_info_t *info);
+ int (*delete_queue)(snd_seq_t *seq, snd_seq_queue_info_t *info);
+ int (*get_queue_info)(snd_seq_t *seq, snd_seq_queue_info_t *info);
+ int (*set_queue_info)(snd_seq_t *seq, snd_seq_queue_info_t *info);
+ int (*get_named_queue)(snd_seq_t *seq, snd_seq_queue_info_t *info);
+ ssize_t (*write)(snd_seq_t *seq, void *buf, size_t len);
+ ssize_t (*read)(snd_seq_t *seq, void *buf, size_t len);
+ int (*remove_events)(snd_seq_t *seq, snd_seq_remove_events_t *rmp);
+ int (*get_client_pool)(snd_seq_t *seq, snd_seq_client_pool_t *info);
+ int (*set_client_pool)(snd_seq_t *seq, snd_seq_client_pool_t *info);
+ int (*query_next_client)(snd_seq_t *seq, snd_seq_client_info_t *info);
+ int (*query_next_port)(snd_seq_t *seq, snd_seq_port_info_t *info);
+} snd_seq_ops_t;
+
+struct _snd_seq {
+ char *name;
+ int type;
+ int streams;
+ int mode;
+ int poll_fd;
+ snd_seq_ops_t *ops;
+ void *private;
+ int client; /* client number */
+ /* buffers */
+ char *obuf; /* output buffer */
+ size_t obufsize; /* output buffer size */
+ size_t obufused; /* output buffer used size */
+ snd_seq_event_t *ibuf; /* input buffer */
+ size_t ibufptr; /* current pointer of input buffer */
+ size_t ibuflen; /* queued length */
+ size_t ibufsize; /* input buffer size */
+ snd_seq_event_t *tmpbuf; /* temporary event for extracted event */
+ size_t tmpbufsize; /* size of errbuf */
+};
+
+int snd_seq_hw_open(snd_seq_t **handle, char *name, int streams, int mode);
+
+#endif
diff --git a/src/seq/seq_priv.h b/src/seq/seq_priv.h
deleted file mode 100644
index 7dbb1b3e..00000000
--- a/src/seq/seq_priv.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Sequencer Interface - definition of sequencer event handler
- * Copyright (c) 1998 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.
- *
- */
-
-#ifndef __SEQ_PRIV_H
-#define __SEQ_PRIV_H
-
-struct snd_seq {
- int client; /* client number */
- int fd;
- /* buffers */
- char *obuf; /* output buffer */
- size_t obufsize; /* output buffer size */
- size_t obufused; /* output buffer used size */
- snd_seq_event_t *ibuf; /* input buffer */
- size_t ibufptr; /* current pointer of input buffer */
- size_t ibuflen; /* queued length */
- size_t ibufsize; /* input buffer size */
- snd_seq_event_t *tmpbuf; /* temporary event for extracted event */
- size_t tmpbufsize; /* size of errbuf */
-};
-
-#endif
diff --git a/src/seq/seqmid.c b/src/seq/seqmid.c
index dcef2223..9b9ff89b 100644
--- a/src/seq/seqmid.c
+++ b/src/seq/seqmid.c
@@ -28,7 +28,7 @@
#include <fcntl.h>
#include <sys/ioctl.h>
#include "asoundlib.h"
-#include "seq_priv.h"
+#include "seq_local.h"
/* direct passing (without queued) */
void snd_seq_ev_set_direct(snd_seq_event_t *ev)
diff --git a/src/timer/timer.c b/src/timer/timer.c
index 7201b0cf..535e79d5 100644
--- a/src/timer/timer.c
+++ b/src/timer/timer.c
@@ -31,7 +31,7 @@
#define SND_FILE_TIMER "/dev/snd/timer"
#define SND_TIMER_VERSION_MAX SND_PROTOCOL_VERSION(2, 0, 0)
-struct snd_timer {
+struct _snd_timer {
int fd;
};
@@ -136,18 +136,6 @@ int snd_timer_params(snd_timer_t *handle, snd_timer_params_t * params)
return 0;
}
-int snd_timer_setup(snd_timer_t *handle, snd_timer_setup_t * setup)
-{
- snd_timer_t *tmr;
-
- tmr = handle;
- if (!tmr || !setup)
- return -EINVAL;
- if (ioctl(tmr->fd, SND_TIMER_IOCTL_SETUP, setup) < 0)
- return -errno;
- return 0;
-}
-
int snd_timer_status(snd_timer_t *handle, snd_timer_status_t * status)
{
snd_timer_t *tmr;
diff --git a/test/latency.c b/test/latency.c
index 7d9071c6..ed6382d0 100644
--- a/test/latency.c
+++ b/test/latency.c
@@ -47,7 +47,7 @@ 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.sfmt = SND_PCM_SFMT_S16_LE;
+ params.format.sfmt = SND_PCM_FORMAT_S16_LE;
params.format.channels = 2;
params.format.rate = USED_RATE;
params.start_mode = SND_PCM_START_EXPLICIT;
@@ -216,7 +216,7 @@ int main(void)
frames_in = frames_out = 0;
if (setparams(phandle, chandle, &latency) < 0)
break;
- if (snd_pcm_format_set_silence(SND_PCM_SFMT_S16_LE, buffer, latency*2) < 0) {
+ if (snd_pcm_format_set_silence(SND_PCM_FORMAT_S16_LE, buffer, latency*2) < 0) {
fprintf(stderr, "silence error\n");
break;
}
diff --git a/test/pause.c b/test/pause.c
index 0da03421..4d7e26df 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.sfmt = SND_PCM_SFMT_MU_LAW;
+ format.sfmt = SND_PCM_FORMAT_MU_LAW;
format.rate = 8000;
format.channels = 1;
if ((err = snd_pcm_playback_format(handle, &format)) < 0) {
diff --git a/test/pcm.c b/test/pcm.c
index 9b750ee7..23262253 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.sfmt = SND_PCM_SFMT_S16_LE;
+ format.sfmt = SND_PCM_FORMAT_S16_LE;
format.channels = 2;
format.rate = 22050;
if ((err = snd_pcm_playback_format(phandle, &format)) < 0) {
diff --git a/test/pcmtest.c b/test/pcmtest.c
index 6f50a85c..c32d5af7 100644
--- a/test/pcmtest.c
+++ b/test/pcmtest.c
@@ -52,53 +52,53 @@ void info_channel(snd_pcm_t *handle, int channel, char *id)
printf(" overrange");
printf("\n");
printf(" formats :");
- if (stream_info.formats & SND_PCM_FMT_MU_LAW)
+ if (stream_info.formats & SND_PCM_FMTBIT_MU_LAW)
printf(" mu-Law");
- if (stream_info.formats & SND_PCM_FMT_A_LAW)
+ if (stream_info.formats & SND_PCM_FMTBIT_A_LAW)
printf(" a-Law");
- if (stream_info.formats & SND_PCM_FMT_IMA_ADPCM)
+ if (stream_info.formats & SND_PCM_FMTBIT_IMA_ADPCM)
printf(" IMA-ADPCM");
- if (stream_info.formats & SND_PCM_FMT_U8)
+ if (stream_info.formats & SND_PCM_FMTBIT_U8)
printf(" U8");
- if (stream_info.formats & SND_PCM_FMT_S16_LE)
+ if (stream_info.formats & SND_PCM_FMTBIT_S16_LE)
printf(" S16-LE");
- if (stream_info.formats & SND_PCM_FMT_S16_BE)
+ if (stream_info.formats & SND_PCM_FMTBIT_S16_BE)
printf(" S16-BE");
- if (stream_info.formats & SND_PCM_FMT_S8)
+ if (stream_info.formats & SND_PCM_FMTBIT_S8)
printf(" S8");
- if (stream_info.formats & SND_PCM_FMT_U16_LE)
+ if (stream_info.formats & SND_PCM_FMTBIT_U16_LE)
printf(" U16-LE");
- if (stream_info.formats & SND_PCM_FMT_U16_BE)
+ if (stream_info.formats & SND_PCM_FMTBIT_U16_BE)
printf(" U16-BE");
- if (stream_info.formats & SND_PCM_FMT_MPEG)
+ if (stream_info.formats & SND_PCM_FMTBIT_MPEG)
printf(" MPEG");
- if (stream_info.formats & SND_PCM_FMT_GSM)
+ if (stream_info.formats & SND_PCM_FMTBIT_GSM)
printf(" GSM");
- if (stream_info.formats & SND_PCM_FMT_S24_LE)
+ if (stream_info.formats & SND_PCM_FMTBIT_S24_LE)
printf(" S24-LE");
- if (stream_info.formats & SND_PCM_FMT_S24_BE)
+ if (stream_info.formats & SND_PCM_FMTBIT_S24_BE)
printf(" S24-BE");
- if (stream_info.formats & SND_PCM_FMT_U24_LE)
+ if (stream_info.formats & SND_PCM_FMTBIT_U24_LE)
printf(" U24-LE");
- if (stream_info.formats & SND_PCM_FMT_U24_BE)
+ if (stream_info.formats & SND_PCM_FMTBIT_U24_BE)
printf(" U24-BE");
- if (stream_info.formats & SND_PCM_FMT_S32_LE)
+ if (stream_info.formats & SND_PCM_FMTBIT_S32_LE)
printf(" S32-LE");
- if (stream_info.formats & SND_PCM_FMT_S32_BE)
+ if (stream_info.formats & SND_PCM_FMTBIT_S32_BE)
printf(" S32-BE");
- if (stream_info.formats & SND_PCM_FMT_U32_LE)
+ if (stream_info.formats & SND_PCM_FMTBIT_U32_LE)
printf(" U32-LE");
- if (stream_info.formats & SND_PCM_FMT_U32_BE)
+ if (stream_info.formats & SND_PCM_FMTBIT_U32_BE)
printf(" U32-BE");
- if (stream_info.formats & SND_PCM_FMT_FLOAT)
+ if (stream_info.formats & SND_PCM_FMTBIT_FLOAT)
printf(" Float");
- if (stream_info.formats & SND_PCM_FMT_FLOAT64)
+ if (stream_info.formats & SND_PCM_FMTBIT_FLOAT64)
printf(" Float64");
- if (stream_info.formats & SND_PCM_FMT_IEC958_SUBFRAME_LE)
+ if (stream_info.formats & SND_PCM_FMTBIT_IEC958_SUBFRAME_LE)
printf(" IEC958-LE");
- if (stream_info.formats & SND_PCM_FMT_IEC958_SUBFRAME_BE)
+ if (stream_info.formats & SND_PCM_FMTBIT_IEC958_SUBFRAME_BE)
printf(" IEC958-BE");
- if (stream_info.formats & SND_PCM_FMT_SPECIAL)
+ if (stream_info.formats & SND_PCM_FMTBIT_SPECIAL)
printf(" Special");
printf("\n");
printf(" rates :");
diff --git a/test/seq-sender.c b/test/seq-sender.c
index b7c1f6c8..546f0a91 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.sfmt = SND_PCM_SFMT_S16_LE;
+ format.sfmt = SND_PCM_FORMAT_S16_LE;
format.channels = 2;
format.rate = 44100;
if ((err = snd_pcm_playback_format(phandle, &format)) < 0) {