Merged pcmfinal branch.

This commit is contained in:
Jaroslav Kysela 2000-11-20 20:10:46 +00:00
parent 3cc2b957fb
commit 41bb7068f2
57 changed files with 5189 additions and 3088 deletions

2
TODO
View File

@ -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)

View File

@ -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:
{

View File

@ -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;

View File

@ -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 {

View File

@ -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 */

View File

@ -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)));

View File

@ -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);

View File

@ -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" {

View File

@ -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);

View File

@ -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);

View File

@ -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;
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);
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(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);

View File

@ -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;
int snd_seq_open(snd_seq_t **handle, int mode);
typedef struct _snd_seq snd_seq_t;
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);

View File

@ -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);

View File

@ -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"

View File

@ -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);
}

View File

@ -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,

View File

@ -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);

View File

@ -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,

View File

@ -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);
}

View File

@ -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;

View File

@ -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;

View File

@ -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 */

File diff suppressed because it is too large Load Diff

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t * info)
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_params_info(file->slave, info);
return snd_pcm_sw_params(file->slave, params);
}
static int snd_pcm_file_params(snd_pcm_t *pcm, snd_pcm_params_t * 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_params(file->slave, params);
return snd_pcm_dig_info(file->slave, info);
}
static int snd_pcm_file_setup(snd_pcm_t *pcm, snd_pcm_setup_t * setup)
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_setup(file->slave, setup);
return snd_pcm_dig_params(file->slave, params);
}
static int snd_pcm_file_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
{
snd_pcm_file_t *file = pcm->private;
return snd_pcm_mmap(file->slave);
}
static int snd_pcm_file_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
{
snd_pcm_file_t *file = pcm->private;
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;

View File

@ -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,41 +120,57 @@ 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_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_DIG_INFO, info) < 0) {
SYSERR("SND_PCM_IOCTL_DIG_INFO failed");
return -errno;
}
return 0;
}
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_DIG_PARAMS, params) < 0) {
SYSERR("SND_PCM_IOCTL_DIG_PARAMS failed");
return -errno;
}
return 0;
}
@ -155,51 +178,24 @@ static int snd_pcm_hw_setup(snd_pcm_t *pcm, snd_pcm_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_INFO, info) < 0) {
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;
}
return 0;
}
static int snd_pcm_hw_channel_params(snd_pcm_t *pcm, snd_pcm_channel_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");
return -errno;
}
return 0;
}
static int snd_pcm_hw_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t * setup)
{
snd_pcm_hw_t *hw = pcm->private;
int fd = hw->fd;
if (ioctl(fd, SND_PCM_IOCTL_CHANNEL_SETUP, setup) < 0) {
SYSERR("SND_PCM_IOCTL_CHANNEL_SETUP 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,

View File

@ -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,

View File

@ -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

View File

@ -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)

View File

@ -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;
}
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));
return 0;
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;
}
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;

View File

@ -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;
}

View File

@ -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,178 +91,106 @@ 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;
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);
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;
}
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;
}
static int snd_pcm_multi_mmap(snd_pcm_t *pcm)
{
snd_pcm_multi_t *multi = pcm->private;
unsigned int i;
size_t count = 0;
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 (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 (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)
{
snd_pcm_multi_t *multi = pcm->private;
unsigned int i;
for (i = 0; i < multi->slaves_count; ++i) {
snd_pcm_t *slave = multi->slaves[i].pcm;
int err = snd_pcm_munmap(slave);
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)
{
snd_pcm_multi_t *multi = pcm->private;
unsigned int i;
snd_pcm_params_t p;
unsigned int k;
snd_pcm_hw_info_t i;
unsigned int access_mask = ~0;
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;
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;
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)
break;
multi->slaves[k].access_mask = i.access_mask;
}
*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_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{
snd_pcm_multi_t *multi = pcm->private;
unsigned int i;
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;
p.format.channels = multi->slaves[i].channels_count;
err = snd_pcm_params_mmap(slave, &p);
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;
params->fail_reason = p.fail_reason;
break;
return err;
}
err = snd_pcm_areas_silence(slave->running_areas, 0, slave->channels, slave->buffer_size, slave->format);
if (err < 0)
return err;
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;
}
}
if (err == 0)
multi->xfer_mode = params->xfer_mode;
return err;
return 0;
}
static int snd_pcm_multi_setup(snd_pcm_t *pcm, snd_pcm_setup_t *setup)
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;
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);
for (i = 0; i < multi->slaves_count; ++i) {
snd_pcm_t *slave = multi->slaves[i].pcm;
err = snd_pcm_sw_params(slave, params);
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;
}
static int snd_pcm_multi_dig_info(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_dig_info_t *info ATTRIBUTE_UNUSED)
{
/* FIXME */
return -ENOSYS;
}
static int snd_pcm_multi_dig_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_dig_params_t *params ATTRIBUTE_UNUSED)
{
/* FIXME */
return -ENOSYS;
}
static int snd_pcm_multi_status(snd_pcm_t *pcm, snd_pcm_status_t *status)
{
snd_pcm_multi_t *multi = pcm->private;
@ -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;

View File

@ -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_hw_info(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_info_t * info)
{
snd_pcm_hw_info_complete(info);
info->fifo_size = 0;
return 0;
}
static int snd_pcm_null_hw_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t * params ATTRIBUTE_UNUSED)
{
return 0;
}
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_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_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;
snd_pcm_null_t *null = 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;
}
null->shmid = id;
}
pcm->mmap_info = i;
pcm->mmap_info_count = 1;
return 0;
}
static int snd_pcm_null_munmap(snd_pcm_t *pcm)
{
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;
}
return 0;
}
static int snd_pcm_null_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
{
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 (shmctl(null->shmid, IPC_RMID, 0) < 0) {
SYSERR("shmctl IPC_RMID failed");
return -errno;
}
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)
{
snd_pcm_null_t *null = pcm->private;
*setup = null->setup;
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,

View File

@ -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;
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;
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;
}
memset(&slave_info, 0, sizeof(slave_info));
if ((err = snd_pcm_params_info(slave, &slave_info)) < 0)
return err;
info->flags = slave_info.flags;
info->flags |= SND_PCM_INFO_INTERLEAVED | SND_PCM_INFO_NONINTERLEAVED;
info->min_fragments = slave_info.min_fragments;
info->max_fragments = slave_info.max_fragments;
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;
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;
}
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;
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))
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;
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))
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;
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;
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;
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;
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.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;
}
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);
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);
}
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;
}
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->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;
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 (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
slave_format->rate = slave_info.max_rate;
assert(0);
if (format->channels < slave_info.min_channels)
slave_format->channels = slave_info.min_channels;
else if (format->channels > slave_info.max_channels)
slave_format->channels = slave_info.max_channels;
slave_info.req_mask |= SND_PCM_PARAMS_CHANNELS;
err = snd_pcm_params_info(slave, &slave_info);
assert(err >= 0);
err = snd_pcm_plug_insert_plugins(pcm, params, &sparams);
if (err < 0)
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;
}
err = snd_pcm_plug_insert_plugins(pcm, format, slave_format);
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_dig_info(snd_pcm_t *pcm, snd_pcm_dig_info_t * info)
{
snd_pcm_plug_t *plug = pcm->private;
return snd_pcm_dig_info(plug->slave, info);
}
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_dig_params(plug->slave, params);
}
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_info(plug->slave, info);
}
static int snd_pcm_plug_channel_params(snd_pcm_t *pcm, snd_pcm_channel_params_t *params)
{
snd_pcm_plug_t *plug = pcm->private;
return snd_pcm_channel_params(plug->slave, params);
}
static int snd_pcm_plug_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t *setup)
{
snd_pcm_plug_t *plug = pcm->private;
return snd_pcm_channel_setup(plug->slave, setup);
}
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

View File

@ -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;
}

View File

@ -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

View File

@ -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;
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;
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;
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 = snd_pcm_setup(rate->plug.slave, setup);
int err;
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
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;

View File

@ -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 (info->access_mask) {
route->plug.saccess_mask = info->access_mask;
info->access_mask = access_mask;
}
if (route->req_schannels >= 0) {
info->req_mask |= SND_PCM_PARAMS_CHANNELS;
info->req.format.channels = route->req_schannels;
}
info->req_mask &= ~(SND_PCM_PARAMS_MMAP_SHAPE |
SND_PCM_PARAMS_XFER_MODE);
err = snd_pcm_params_info(route->plug.slave, info);
info->req_mask = req_mask;
info->req.format.sfmt = sfmt;
info->req.format.channels = channels;
if (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;

View File

@ -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,183 +442,81 @@ 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;
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;
}
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;
}
_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 (err < 0)
goto _end;
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);
}
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;
_end:
Pthread_mutex_unlock(&slave->mutex);
return 0;
}
static int snd_pcm_share_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
{
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;
}
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;
}
static int snd_pcm_share_params(snd_pcm_t *pcm, snd_pcm_params_t *params)
{
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;
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;
(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_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);
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;
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->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->channels, slave->pcm->buffer_size, slave->pcm->format);
}
share->state = SND_PCM_STATE_SETUP;
slave->setup_count++;
@ -627,26 +525,45 @@ static int snd_pcm_share_params(snd_pcm_t *pcm, snd_pcm_params_t *params)
return err;
}
static int snd_pcm_share_setup(snd_pcm_t *pcm, snd_pcm_setup_t *setup)
static int snd_pcm_share_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_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;
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_info(slave->pcm, info);
Pthread_mutex_unlock(&slave->mutex);
return err;
}
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;
/* 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;

View File

@ -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;
return err;
}
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_DIG_INFO;
ctrl->u.dig_info = *info;
err = snd_pcm_shm_action(pcm);
if (err < 0)
return err;
*setup = ctrl->u.setup;
*info = ctrl->u.dig_info;
return err;
}
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_DIG_PARAMS;
ctrl->u.dig_params = *params;
err = snd_pcm_shm_action(pcm);
*params = ctrl->u.dig_params;
if (err < 0)
return err;
return err;
}
static int snd_pcm_shm_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
{
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;
}
}
return 0;
}
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;
int fd;
ctrl->cmd = SND_PCM_IOCTL_CHANNEL_INFO;
ctrl->u.channel_info = *info;
err = snd_pcm_shm_action(pcm);
err = snd_pcm_shm_action_fd(pcm, &fd);
if (err < 0)
return err;
*info = ctrl->u.channel_info;
return err;
}
static int snd_pcm_shm_channel_params(snd_pcm_t *pcm, snd_pcm_channel_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;
err = snd_pcm_shm_action(pcm);
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)
{
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;
}
}
}
assert(idx >= 0);
return new[idx].addr + mindist;
}
static int snd_pcm_shm_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t * setup)
{
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);
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->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;

View File

@ -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

View File

@ -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;
if (!rmidi || (!buffer && size > 0))
return -EINVAL;
result = read(rmidi->fd, buffer, size);
if (result < 0)
return -errno;
return result;
assert(rmidi && (buffer || size == 0));
return rmidi->ops->read(rmidi, buffer, size);
}
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;
}
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);
}

320
src/rawmidi/rawmidi_hw.c Normal file
View File

@ -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);
}

View File

@ -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);

View File

@ -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

View File

@ -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;
}
if (SND_PROTOCOL_INCOMPATIBLE(ver, SND_SEQ_VERSION_MAX)) {
close(fd);
return -SND_ERROR_INCOMPATIBLE_VERSION;
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 (ioctl(fd, SND_SEQ_IOCTL_CLIENT_ID, &client) < 0) {
close(fd);
return -errno;
err = snd_config_search(seq_conf, "type", &conf);
if (err < 0) {
ERR("type is not defined");
return err;
}
seq = (snd_seq_t *) calloc(1, sizeof(snd_seq_t));
if (seq == NULL) {
close(fd);
return -ENOMEM;
err = snd_config_string_get(conf, &str);
if (err < 0) {
ERR("Invalid type for type");
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;
err = snd_config_searchv(snd_config, &type_conf, "seqtype", str, 0);
if (err < 0) {
ERR("Unknown SEQ type %s", str);
return err;
}
seq->tmpbuf = NULL;
seq->tmpbufsize = 0;
*handle = seq;
return 0;
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;
}
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,21 +255,8 @@ 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;
}
/*
* obtain the current client information
*/
int snd_seq_get_client_info(snd_seq_t *seq, 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);
return seq->ops->system_info(seq, info);
}
/*
@ -252,13 +264,18 @@ 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 || client < 0)
return -EINVAL;
bzero(info, sizeof(snd_seq_client_info_t));
assert(seq && info && client >= 0);
memset(info, 0, 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 seq->ops->get_client_info(seq, info);
}
/*
* obtain the current client information
*/
int snd_seq_get_client_info(snd_seq_t *seq, snd_seq_client_info_t * info)
{
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);
}
/*----------------------------------------------------------------*/

545
src/seq/seq_hw.c Normal file
View File

@ -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);
}

105
src/seq/seq_local.h Normal file
View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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;

View File

@ -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;
}

View File

@ -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) {

View File

@ -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) {

View File

@ -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 :");

View File

@ -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) {