mirror of
https://gitee.com/openharmony/third_party_alsa-lib
synced 2024-11-23 07:30:32 +00:00
Merged pcmfinal branch.
This commit is contained in:
parent
3cc2b957fb
commit
41bb7068f2
2
TODO
2
TODO
@ -1,3 +1,3 @@
|
||||
M think about xrun recovery helpers
|
||||
M add abstraction layer to timer, rawmidi, hwdep, seq
|
||||
M add abstraction layer to timer, hwdep
|
||||
L move OSS emulation to user space? (pseudo device driver and daemon)
|
||||
|
@ -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:
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
@ -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 */
|
||||
|
@ -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)));
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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" {
|
||||
|
@ -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);
|
||||
|
144
include/pcm.h
144
include/pcm.h
@ -12,94 +12,9 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef unsigned int bitset_t;
|
||||
typedef struct _snd_pcm snd_pcm_t;
|
||||
|
||||
static inline size_t bitset_size(size_t nbits)
|
||||
{
|
||||
return (nbits + sizeof(bitset_t) * 8 - 1) / (sizeof(bitset_t) * 8);
|
||||
}
|
||||
|
||||
static inline bitset_t *bitset_alloc(size_t nbits)
|
||||
{
|
||||
return (bitset_t*) calloc(bitset_size(nbits), sizeof(bitset_t));
|
||||
}
|
||||
|
||||
static inline void bitset_set(bitset_t *bitmap, unsigned int pos)
|
||||
{
|
||||
size_t bits = sizeof(*bitmap) * 8;
|
||||
bitmap[pos / bits] |= 1U << (pos % bits);
|
||||
}
|
||||
|
||||
static inline void bitset_reset(bitset_t *bitmap, unsigned int pos)
|
||||
{
|
||||
size_t bits = sizeof(*bitmap) * 8;
|
||||
bitmap[pos / bits] &= ~(1U << (pos % bits));
|
||||
}
|
||||
|
||||
static inline int bitset_get(bitset_t *bitmap, unsigned int pos)
|
||||
{
|
||||
size_t bits = sizeof(*bitmap) * 8;
|
||||
return !!(bitmap[pos / bits] & (1U << (pos % bits)));
|
||||
}
|
||||
|
||||
static inline void bitset_copy(bitset_t *dst, bitset_t *src, size_t nbits)
|
||||
{
|
||||
memcpy(dst, src, bitset_size(nbits) * sizeof(bitset_t));
|
||||
}
|
||||
|
||||
static inline void bitset_and(bitset_t *dst, bitset_t *bs, size_t nbits)
|
||||
{
|
||||
bitset_t *end = dst + bitset_size(nbits);
|
||||
while (dst < end)
|
||||
*dst++ &= *bs++;
|
||||
}
|
||||
|
||||
static inline void bitset_or(bitset_t *dst, bitset_t *bs, size_t nbits)
|
||||
{
|
||||
bitset_t *end = dst + bitset_size(nbits);
|
||||
while (dst < end)
|
||||
*dst++ |= *bs++;
|
||||
}
|
||||
|
||||
static inline void bitset_zero(bitset_t *dst, size_t nbits)
|
||||
{
|
||||
bitset_t *end = dst + bitset_size(nbits);
|
||||
while (dst < end)
|
||||
*dst++ = 0;
|
||||
}
|
||||
|
||||
static inline void bitset_one(bitset_t *dst, size_t nbits)
|
||||
{
|
||||
bitset_t *end = dst + bitset_size(nbits);
|
||||
while (dst < end)
|
||||
*dst++ = ~(bitset_t)0;
|
||||
}
|
||||
|
||||
static inline size_t hweight32(bitset_t v)
|
||||
{
|
||||
v = (v & 0x55555555) + ((v >> 1) & 0x55555555);
|
||||
v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
|
||||
v = (v & 0x0F0F0F0F) + ((v >> 4) & 0x0F0F0F0F);
|
||||
v = (v & 0x00FF00FF) + ((v >> 8) & 0x00FF00FF);
|
||||
return (v & 0x0000FFFF) + ((v >> 16) & 0x0000FFFF);
|
||||
}
|
||||
|
||||
/* Count bits set */
|
||||
static inline size_t bitset_count(bitset_t *bitset, size_t nbits)
|
||||
{
|
||||
bitset_t *end = bitset + bitset_size(nbits) - 1;
|
||||
size_t bits = sizeof(*bitset) * 8;
|
||||
size_t count = 0;
|
||||
while (bitset < end)
|
||||
count += hweight32(*bitset++);
|
||||
count += hweight32(*bitset & ((1U << (nbits % bits)) - 1));
|
||||
return count;
|
||||
}
|
||||
|
||||
typedef struct snd_pcm snd_pcm_t;
|
||||
typedef struct snd_pcm_loopback snd_pcm_loopback_t;
|
||||
|
||||
typedef enum {
|
||||
typedef enum _snd_pcm_type {
|
||||
SND_PCM_TYPE_HW,
|
||||
SND_PCM_TYPE_MULTI,
|
||||
SND_PCM_TYPE_FILE,
|
||||
@ -119,16 +34,28 @@ typedef enum {
|
||||
SND_PCM_TYPE_LBSERVER,
|
||||
} snd_pcm_type_t;
|
||||
|
||||
extern void snd_pcm_error(const char *file, int line, const char *function, int err, const char *fmt, ...) __attribute__ ((weak, format (printf, 5, 6)));
|
||||
enum {
|
||||
SND_PCM_RULE_PAR_MASK = 0x00ff,
|
||||
SND_PCM_RULE_REL_LT = 0x100,
|
||||
SND_PCM_RULE_REL_GT = 0x200,
|
||||
SND_PCM_RULE_REL_EQ = 0x300,
|
||||
SND_PCM_RULE_REL_LE = 0x400,
|
||||
SND_PCM_RULE_REL_GE = 0x500,
|
||||
SND_PCM_RULE_REL_NEAR = 0x600,
|
||||
SND_PCM_RULE_REL_BITS = 0x700,
|
||||
SND_PCM_RULE_REL_MASK = 0xff00
|
||||
};
|
||||
|
||||
typedef struct _snd_pcm_channel_area {
|
||||
void *addr; /* base address of channel samples */
|
||||
unsigned int first; /* offset to first sample in bits */
|
||||
unsigned int step; /* samples distance in bits */
|
||||
} snd_pcm_channel_area_t;
|
||||
|
||||
int snd_pcm_open(snd_pcm_t **pcm, char *name,
|
||||
int stream, int mode);
|
||||
|
||||
/* Obsolete functions */
|
||||
int snd_pcm_hw_open_subdevice(snd_pcm_t **pcm, int card, int device, int subdevice, int stream, int mode);
|
||||
int snd_pcm_hw_open_device(snd_pcm_t **pcm, int card, int device, int stream, int mode);
|
||||
int snd_pcm_plug_open_subdevice(snd_pcm_t **pcm, int card, int device, int subdevice, int stream, int mode);
|
||||
int snd_pcm_plug_open_device(snd_pcm_t **pcm, int card, int device, int stream, int mode);
|
||||
#define snd_pcm_write snd_pcm_writei
|
||||
#define snd_pcm_read snd_pcm_readi
|
||||
ssize_t snd_pcm_writev(snd_pcm_t *pcm, const struct iovec *vector, int count);
|
||||
@ -141,12 +68,11 @@ int snd_pcm_poll_descriptor(snd_pcm_t *pcm);
|
||||
int snd_pcm_nonblock(snd_pcm_t *pcm, int nonblock);
|
||||
int snd_pcm_async(snd_pcm_t *pcm, int sig, pid_t pid);
|
||||
int snd_pcm_info(snd_pcm_t *pcm, snd_pcm_info_t *info);
|
||||
int snd_pcm_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t *info);
|
||||
int snd_pcm_params(snd_pcm_t *pcm, snd_pcm_params_t *params);
|
||||
int snd_pcm_setup(snd_pcm_t *pcm, snd_pcm_setup_t *setup);
|
||||
int snd_pcm_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info);
|
||||
int snd_pcm_channel_params(snd_pcm_t *pcm, snd_pcm_channel_params_t *params);
|
||||
int snd_pcm_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t *setup);
|
||||
int snd_pcm_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t *info);
|
||||
int snd_pcm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params);
|
||||
int snd_pcm_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *params);
|
||||
int snd_pcm_dig_info(snd_pcm_t *pcm, snd_pcm_dig_info_t *info);
|
||||
int snd_pcm_dig_params(snd_pcm_t *pcm, snd_pcm_dig_params_t *params);
|
||||
int snd_pcm_status(snd_pcm_t *pcm, snd_pcm_status_t *status);
|
||||
int snd_pcm_prepare(snd_pcm_t *pcm);
|
||||
int snd_pcm_start(snd_pcm_t *pcm);
|
||||
@ -160,23 +86,35 @@ ssize_t snd_pcm_writei(snd_pcm_t *pcm, const void *buffer, size_t size);
|
||||
ssize_t snd_pcm_readi(snd_pcm_t *pcm, void *buffer, size_t size);
|
||||
ssize_t snd_pcm_writen(snd_pcm_t *pcm, void **bufs, size_t size);
|
||||
ssize_t snd_pcm_readn(snd_pcm_t *pcm, void **bufs, size_t size);
|
||||
|
||||
int snd_pcm_dump_hw_setup(snd_pcm_t *pcm, FILE *fp);
|
||||
int snd_pcm_dump_sw_setup(snd_pcm_t *pcm, FILE *fp);
|
||||
int snd_pcm_dump_setup(snd_pcm_t *pcm, FILE *fp);
|
||||
int snd_pcm_dump_hw_params_fail(snd_pcm_hw_params_t *params, FILE *fp);
|
||||
int snd_pcm_dump_sw_params_fail(snd_pcm_sw_params_t *params, FILE *fp);
|
||||
int snd_pcm_dump(snd_pcm_t *pcm, FILE *fp);
|
||||
int snd_pcm_dump_status(snd_pcm_status_t *status, FILE *fp);
|
||||
int snd_pcm_link(snd_pcm_t *pcm1, snd_pcm_t *pcm2);
|
||||
int snd_pcm_unlink(snd_pcm_t *pcm);
|
||||
|
||||
int snd_pcm_channels_mask(snd_pcm_t *pcm, bitset_t *cmask);
|
||||
int snd_pcm_wait(snd_pcm_t *pcm, int timeout);
|
||||
ssize_t snd_pcm_avail_update(snd_pcm_t *pcm);
|
||||
int snd_pcm_set_avail_min(snd_pcm_t *pcm, size_t size);
|
||||
|
||||
int snd_pcm_hw_params_rules(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
|
||||
unsigned int count, int *rules);
|
||||
int snd_pcm_hw_params_rulesv(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, ...);
|
||||
int snd_pcm_hw_info_rules(snd_pcm_t *pcm,
|
||||
snd_pcm_hw_info_t *info,
|
||||
snd_pcm_hw_params_t *params,
|
||||
unsigned int count, int *rules);
|
||||
int snd_pcm_hw_info_rulesv(snd_pcm_t *pcm,
|
||||
snd_pcm_hw_info_t *info,
|
||||
snd_pcm_hw_params_t *params, ...);
|
||||
|
||||
/* mmap */
|
||||
int snd_pcm_mmap(snd_pcm_t *pcm);
|
||||
int snd_pcm_munmap(snd_pcm_t *pcm);
|
||||
snd_pcm_channel_area_t *snd_pcm_mmap_areas(snd_pcm_t *pcm);
|
||||
int snd_pcm_mmap_get_areas(snd_pcm_t *pcm, snd_pcm_channel_area_t *stopped_areas, snd_pcm_channel_area_t *running_areas);
|
||||
snd_pcm_channel_area_t *snd_pcm_mmap_running_areas(snd_pcm_t *pcm);
|
||||
snd_pcm_channel_area_t *snd_pcm_mmap_stopped_areas(snd_pcm_t *pcm);
|
||||
ssize_t snd_pcm_mmap_forward(snd_pcm_t *pcm, size_t size);
|
||||
size_t snd_pcm_mmap_offset(snd_pcm_t *pcm);
|
||||
size_t snd_pcm_mmap_xfer(snd_pcm_t *pcm, size_t size);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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"
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
14
src/error.c
14
src/error.c
@ -23,6 +23,7 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include "asoundlib.h"
|
||||
|
||||
@ -42,3 +43,16 @@ const char *snd_strerror(int errnum)
|
||||
return "Unknown error";
|
||||
return snd_error_codes[errnum];
|
||||
}
|
||||
|
||||
void snd_lib_error(const char *file, int line, const char *function, int err, const char *fmt, ...)
|
||||
{
|
||||
va_list arg;
|
||||
va_start(arg, fmt);
|
||||
fprintf(stderr, "ALSA lib %s:%i:(%s) ", file, line, function);
|
||||
vfprintf(stderr, fmt, arg);
|
||||
if (err)
|
||||
fprintf(stderr, ": %s", snd_strerror(err));
|
||||
putc('\n', stderr);
|
||||
va_end(arg);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
1895
src/pcm/pcm.c
1895
src/pcm/pcm.c
File diff suppressed because it is too large
Load Diff
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
196
src/pcm/pcm_hw.c
196
src/pcm/pcm_hw.c
@ -29,17 +29,24 @@
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/shm.h>
|
||||
#include <asm/page.h>
|
||||
#include "pcm_local.h"
|
||||
#include "../control/control_local.h"
|
||||
|
||||
#ifndef F_SETSIG
|
||||
#define F_SETSIG 10
|
||||
#endif
|
||||
|
||||
#ifndef PAGE_ALIGN
|
||||
#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK)
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
int fd;
|
||||
int card, device, subdevice;
|
||||
volatile snd_pcm_mmap_status_t *mmap_status;
|
||||
snd_pcm_mmap_control_t *mmap_control;
|
||||
int shmid;
|
||||
} snd_pcm_hw_t;
|
||||
|
||||
#define SND_FILE_PCM_STREAM_PLAYBACK "/dev/snd/pcmC%iD%ip"
|
||||
@ -102,7 +109,7 @@ static int snd_pcm_hw_async(snd_pcm_t *pcm, int sig, pid_t pid)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_pcm_hw_info(snd_pcm_t *pcm, snd_pcm_info_t * info)
|
||||
static int _snd_pcm_hw_info(snd_pcm_t *pcm, snd_pcm_info_t * info)
|
||||
{
|
||||
snd_pcm_hw_t *hw = pcm->private;
|
||||
int fd = hw->fd;
|
||||
@ -113,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,
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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 = ¶ms->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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -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
320
src/rawmidi/rawmidi_hw.c
Normal 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);
|
||||
}
|
||||
|
60
src/rawmidi/rawmidi_local.h
Normal file
60
src/rawmidi/rawmidi_local.h
Normal 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);
|
||||
|
@ -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
|
||||
|
||||
|
574
src/seq/seq.c
574
src/seq/seq.c
@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Sequencer Interface - main file
|
||||
* Copyright (c) 1998 by Jaroslav Kysela <perex@suse.cz>
|
||||
* Copyright (c) 2000 by Jaroslav Kysela <perex@suse.cz>
|
||||
* Abramo Bagnara <abramo@alsa-project.org>
|
||||
*
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
@ -19,81 +20,114 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/poll.h>
|
||||
#include <dlfcn.h>
|
||||
#include "seq_local.h"
|
||||
#include "asoundlib.h"
|
||||
#include "seq_priv.h"
|
||||
|
||||
#define SND_FILE_SEQ "/dev/snd/seq"
|
||||
#define SND_FILE_ALOADSEQ "/dev/aloadSEQ"
|
||||
#define SND_SEQ_VERSION_MAX SND_PROTOCOL_VERSION(1, 0, 0)
|
||||
#define SND_SEQ_OBUF_SIZE (16*1024) /* default size */
|
||||
#define SND_SEQ_IBUF_SIZE 500 /* in event_size aligned */
|
||||
#define DEFAULT_TMPBUF_SIZE 20
|
||||
|
||||
/*
|
||||
* open a sequencer device so that it creates a user-client.
|
||||
*/
|
||||
int snd_seq_open(snd_seq_t **handle, int mode)
|
||||
int snd_seq_open(snd_seq_t **seqp, char *name,
|
||||
int streams, int mode)
|
||||
{
|
||||
int fd, ver, client, flg;
|
||||
char filename[32];
|
||||
snd_seq_t *seq;
|
||||
|
||||
*handle = NULL;
|
||||
|
||||
sprintf(filename, SND_FILE_SEQ);
|
||||
if ((fd = open(filename, mode)) < 0) {
|
||||
close(open(SND_FILE_ALOADSEQ, O_RDWR));
|
||||
if ((fd = open(filename, mode)) < 0)
|
||||
return -errno;
|
||||
char *str;
|
||||
int err;
|
||||
snd_config_t *seq_conf, *conf, *type_conf;
|
||||
snd_config_iterator_t i;
|
||||
char *lib = NULL, *open = NULL;
|
||||
int (*open_func)(snd_seq_t **seqp, char *name, snd_config_t *conf,
|
||||
int streams, int mode);
|
||||
void *h;
|
||||
assert(seqp && name);
|
||||
err = snd_config_update();
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = snd_config_searchv(snd_config, &seq_conf, "seq", name, 0);
|
||||
if (err < 0) {
|
||||
if (strcmp(name, "hw") == 0)
|
||||
return snd_seq_hw_open(seqp, name, streams, mode);
|
||||
ERR("Unknown SEQ %s", name);
|
||||
return -ENOENT;
|
||||
}
|
||||
if (ioctl(fd, SND_SEQ_IOCTL_PVERSION, &ver) < 0) {
|
||||
close(fd);
|
||||
return -errno;
|
||||
if (snd_config_type(seq_conf) != SND_CONFIG_TYPE_COMPOUND) {
|
||||
ERR("Invalid type for SEQ definition");
|
||||
return -EINVAL;
|
||||
}
|
||||
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
545
src/seq/seq_hw.c
Normal 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
105
src/seq/seq_local.h
Normal 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
|
@ -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
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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 :");
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user