Merged pcm2 branch.

This commit is contained in:
Jaroslav Kysela 2000-05-08 18:53:38 +00:00
parent 986c1500d2
commit 1cd6778173
40 changed files with 5053 additions and 3045 deletions

View file

@ -16,7 +16,7 @@ void main(void)
#if !defined(SND_PROTOCOL_VERSION) || !defined(SND_PROTOCOL_INCOMPATIBLE)
#error not found
#else
#if !defined(SND_MIXER_IOCTL_ELEMENTS)
#if !defined(SND_PCM_IOCTL_CHANNEL_UPDATE)
#error wrong version
#endif
exit(0);
@ -25,7 +25,7 @@ void main(void)
],
AC_MSG_RESULT(present),
[AC_MSG_RESULT(not found or wrong version);
AC_MSG_ERROR([Install alsa-driver v0.3.0pre5+ package first...])]
AC_MSG_ERROR([Install alsa-driver v0.6.0 package first...])]
)
CFLAGS="$OLD_CFLAGS"
])

View file

@ -3,7 +3,7 @@
aclocal $ACLOCAL_FLAGS
automake --foreign
autoconf
export CFLAGS='-O2 -Wall -pipe -g'
export CFLAGS='-O2 -Wall -W -pipe -g'
echo "CFLAGS=$CFLAGS"
echo "./configure $@"
./configure $@

View file

@ -1,3 +1,5 @@
#define UNUSED __attribute__ ((unused))
/*
*
*/

View file

@ -13,8 +13,8 @@ typedef void snd_instr_simple_t;
extern "C" {
#endif
int snd_instr_simple_convert_to_stream(snd_instr_simple_t *simple, const char *name, snd_seq_instr_put_t **put, long *size);
int snd_instr_simple_convert_from_stream(snd_seq_instr_get_t *data, long size, snd_instr_simple_t **simple);
int snd_instr_simple_convert_to_stream(snd_instr_simple_t *simple, const char *name, snd_seq_instr_put_t **put, size_t *size);
int snd_instr_simple_convert_from_stream(snd_seq_instr_get_t *data, size_t size, snd_instr_simple_t **simple);
int snd_instr_simple_free(snd_instr_simple_t *simple);
#ifdef __cplusplus
@ -35,8 +35,8 @@ int snd_instr_iwffff_open_rom(snd_iwffff_handle_t **handle, int card, int bank,
int snd_instr_iwffff_open_rom_file(snd_iwffff_handle_t **handle, const char *name, int bank, int file);
int snd_instr_iwffff_close(snd_iwffff_handle_t *handle);
int snd_instr_iwffff_load(snd_iwffff_handle_t *handle, int bank, int prg, snd_instr_iwffff_t **iwffff);
int snd_instr_iwffff_convert_to_stream(snd_instr_iwffff_t *iwffff, const char *name, snd_seq_instr_put_t **data, long *size);
int snd_instr_iwffff_convert_from_stream(snd_seq_instr_get_t *data, long size, snd_instr_iwffff_t **iwffff);
int snd_instr_iwffff_convert_to_stream(snd_instr_iwffff_t *iwffff, const char *name, snd_seq_instr_put_t **data, size_t *size);
int snd_instr_iwffff_convert_from_stream(snd_seq_instr_get_t *data, size_t size, snd_instr_iwffff_t **iwffff);
int snd_instr_iwffff_free(snd_instr_iwffff_t *iwffff);
#ifdef __cplusplus

View file

@ -8,26 +8,97 @@
#define SND_PCM_OPEN_PLAYBACK 0x0001
#define SND_PCM_OPEN_CAPTURE 0x0002
#define SND_PCM_OPEN_DUPLEX 0x0003
#define SND_PCM_OPEN_NONBLOCK 0x1000
#define SND_PCM_NONBLOCK_PLAYBACK 0x1000
#define SND_PCM_NONBLOCK_CAPTURE 0x2000
#define SND_PCM_NONBLOCK 0x3000
#ifdef __cplusplus
extern "C" {
#endif
typedef unsigned int bitset_t;
static inline size_t bitset_size(int nbits)
{
return (nbits + sizeof(bitset_t) * 8 - 1) / (sizeof(bitset_t) * 8);
}
static inline bitset_t *bitset_alloc(int nbits)
{
return calloc(bitset_size(nbits), sizeof(bitset_t));
}
static inline void bitset_set(bitset_t *bitmap, unsigned int pos)
{
int bits = sizeof(*bitmap) * 8;
bitmap[pos / bits] |= 1 << (pos % bits);
}
static inline void bitset_reset(bitset_t *bitmap, unsigned int pos)
{
int bits = sizeof(*bitmap) * 8;
bitmap[pos / bits] &= ~(1 << (pos % bits));
}
static inline int bitset_get(bitset_t *bitmap, unsigned int pos)
{
int bits = sizeof(*bitmap) * 8;
return !!(bitmap[pos / bits] & (1 << (pos % bits)));
}
static inline void bitset_copy(bitset_t *dst, bitset_t *src, unsigned int nbits)
{
memcpy(dst, src, bitset_size(nbits) * sizeof(bitset_t));
}
static inline void bitset_and(bitset_t *dst, bitset_t *bs, unsigned int nbits)
{
bitset_t *end = dst + bitset_size(nbits);
while (dst < end)
*dst++ &= *bs++;
}
static inline void bitset_or(bitset_t *dst, bitset_t *bs, unsigned int nbits)
{
bitset_t *end = dst + bitset_size(nbits);
while (dst < end)
*dst++ |= *bs++;
}
static inline void bitset_zero(bitset_t *dst, unsigned int nbits)
{
bitset_t *end = dst + bitset_size(nbits);
while (dst < end)
*dst++ = 0;
}
static inline void bitset_one(bitset_t *dst, unsigned int nbits)
{
bitset_t *end = dst + bitset_size(nbits);
while (dst < end)
*dst++ = -1;
}
typedef struct snd_pcm snd_pcm_t;
typedef struct snd_pcm_loopback snd_pcm_loopback_t;
typedef enum { SND_PCM_TYPE_HW, SND_PCM_TYPE_PLUG } snd_pcm_type_t;
int snd_pcm_open(snd_pcm_t **handle, int card, int device, int mode);
int snd_pcm_open_subdevice(snd_pcm_t **handle, int card, int device, int subdevice, int mode);
snd_pcm_type_t snd_pcm_type(snd_pcm_t *handle);
int snd_pcm_close(snd_pcm_t *handle);
int snd_pcm_channel_close(snd_pcm_t *handle, int channel);
int snd_pcm_file_descriptor(snd_pcm_t *handle, int channel);
int snd_pcm_nonblock_mode(snd_pcm_t *handle, int nonblock);
int snd_pcm_info(snd_pcm_t *handle, snd_pcm_info_t * info);
int snd_pcm_channel_info(snd_pcm_t *handle, snd_pcm_channel_info_t * info);
int snd_pcm_channel_params(snd_pcm_t *handle, snd_pcm_channel_params_t * params);
int snd_pcm_channel_setup(snd_pcm_t *handle, snd_pcm_channel_setup_t * setup);
int snd_pcm_voice_setup(snd_pcm_t *handle, int channel, snd_pcm_voice_setup_t * setup);
int snd_pcm_channel_status(snd_pcm_t *handle, snd_pcm_channel_status_t * status);
int snd_pcm_channel_nonblock(snd_pcm_t *handle, int channel, int nonblock);
int snd_pcm_info(snd_pcm_t *handle, snd_pcm_info_t *info);
int snd_pcm_channel_info(snd_pcm_t *handle, snd_pcm_channel_info_t *info);
int snd_pcm_channel_params(snd_pcm_t *handle, snd_pcm_channel_params_t *params);
int snd_pcm_channel_setup(snd_pcm_t *handle, snd_pcm_channel_setup_t *setup);
int snd_pcm_voice_setup(snd_pcm_t *handle, int channel, snd_pcm_voice_setup_t *setup);
int snd_pcm_all_voices_setup(snd_pcm_t *handle, int channel, snd_pcm_voice_setup_t *setup);
int snd_pcm_channel_status(snd_pcm_t *handle, snd_pcm_channel_status_t *status);
int snd_pcm_playback_prepare(snd_pcm_t *handle);
int snd_pcm_capture_prepare(snd_pcm_t *handle);
int snd_pcm_channel_prepare(snd_pcm_t *handle, int channel);
@ -36,17 +107,34 @@ int snd_pcm_capture_go(snd_pcm_t *handle);
int snd_pcm_channel_go(snd_pcm_t *handle, int channel);
int snd_pcm_sync_go(snd_pcm_t *handle, snd_pcm_sync_t *sync);
int snd_pcm_playback_drain(snd_pcm_t *handle);
int snd_pcm_channel_drain(snd_pcm_t *handle, int channel);
int snd_pcm_playback_flush(snd_pcm_t *handle);
int snd_pcm_capture_flush(snd_pcm_t *handle);
int snd_pcm_channel_flush(snd_pcm_t *handle, int channel);
int snd_pcm_playback_pause(snd_pcm_t *handle, int enable);
int snd_pcm_channel_pause(snd_pcm_t *handle, int channel, int enable);
ssize_t snd_pcm_transfer_size(snd_pcm_t *handle, int channel);
ssize_t snd_pcm_write(snd_pcm_t *handle, const void *buffer, size_t size);
ssize_t snd_pcm_read(snd_pcm_t *handle, void *buffer, size_t size);
ssize_t snd_pcm_writev(snd_pcm_t *pcm, const struct iovec *vector, int count);
ssize_t snd_pcm_readv(snd_pcm_t *pcm, const struct iovec *vector, int count);
ssize_t snd_pcm_writev(snd_pcm_t *pcm, const struct iovec *vector, unsigned long count);
ssize_t snd_pcm_readv(snd_pcm_t *pcm, const struct iovec *vector, unsigned long count);
int snd_pcm_mmap(snd_pcm_t *handle, int channel, snd_pcm_mmap_control_t **control, void **buffer);
int snd_pcm_munmap(snd_pcm_t *handle, int channel);
int snd_pcm_mmap_control(snd_pcm_t *handle, int channel, snd_pcm_mmap_control_t **control);
int snd_pcm_mmap_data(snd_pcm_t *handle, int channel, void **buffer);
int snd_pcm_munmap_control(snd_pcm_t *handle, int channel);
int snd_pcm_munmap_data(snd_pcm_t *handle, int channel);
int snd_pcm_voices_mask(snd_pcm_t *pcm, int channel, bitset_t *client_vmask);
int snd_pcm_mmap_frags_used(snd_pcm_t *pcm, int channel, ssize_t *frags);
int snd_pcm_mmap_frags_free(snd_pcm_t *pcm, int channel, ssize_t *frags);
int snd_pcm_mmap_bytes_used(snd_pcm_t *pcm, int channel, ssize_t *bytes);
int snd_pcm_mmap_bytes_free(snd_pcm_t *pcm, int channel, ssize_t *bytes);
int snd_pcm_mmap_ready(snd_pcm_t *pcm, int channel);
ssize_t snd_pcm_mmap_write(snd_pcm_t *handle, const void *buffer, size_t size);
ssize_t snd_pcm_mmap_read(snd_pcm_t *handle, void *buffer, size_t size);
ssize_t snd_pcm_mmap_writev(snd_pcm_t *pcm, const struct iovec *vector, unsigned long count);
ssize_t snd_pcm_mmap_readv(snd_pcm_t *pcm, const struct iovec *vector, unsigned long count);
ssize_t snd_pcm_bytes_per_second(snd_pcm_t *pcm, int channel);
/* misc */
@ -59,7 +147,12 @@ int snd_pcm_format_width(int format); /* in bits */
int snd_pcm_format_physical_width(int format); /* in bits */
int snd_pcm_build_linear_format(int width, int unsignd, int big_endian);
ssize_t snd_pcm_format_size(int format, size_t samples);
unsigned char snd_pcm_format_silence(int format);
ssize_t snd_pcm_format_bytes_per_second(snd_pcm_format_t *format);
u_int8_t snd_pcm_format_silence(int format);
u_int16_t snd_pcm_format_silence_16(int format);
u_int32_t snd_pcm_format_silence_32(int format);
u_int64_t snd_pcm_format_silence_64(int format);
ssize_t snd_pcm_format_set_silence(int format, void *buf, size_t count);
const char *snd_pcm_get_format_name(int format);
#ifdef __cplusplus
@ -82,6 +175,7 @@ typedef enum {
PREPARE = 1,
DRAIN = 2,
FLUSH = 3,
PAUSE = 4,
} snd_pcm_plugin_action_t;
typedef struct snd_stru_pcm_plugin_voice {
@ -89,25 +183,31 @@ typedef struct snd_stru_pcm_plugin_voice {
void *addr; /* address to voice samples */
unsigned int first; /* offset to first sample in bits */
unsigned int step; /* samples distance in bits */
unsigned int enabled:1; /* voice need to be processed */
unsigned int wanted:1; /* voice is wanted */
} snd_pcm_plugin_voice_t;
struct snd_stru_pcm_plugin {
char *name; /* plug-in name */
int channel;
snd_pcm_format_t src_format; /* source format */
snd_pcm_format_t dst_format; /* destination format */
int src_width; /* sample width in bits */
int dst_width; /* sample width in bits */
ssize_t (*src_samples)(snd_pcm_plugin_t *plugin, size_t dst_samples);
ssize_t (*dst_samples)(snd_pcm_plugin_t *plugin, size_t src_samples);
int (*src_voices)(snd_pcm_plugin_t *plugin,
snd_pcm_plugin_voice_t **voices,
size_t samples);
int (*dst_voices)(snd_pcm_plugin_t *plugin,
snd_pcm_plugin_voice_t **voices,
size_t samples);
int (*client_voices)(snd_pcm_plugin_t *plugin,
size_t samples,
snd_pcm_plugin_voice_t **voices);
int (*src_voices_mask)(snd_pcm_plugin_t *plugin,
bitset_t *dst_vmask,
bitset_t **src_vmask);
int (*dst_voices_mask)(snd_pcm_plugin_t *plugin,
bitset_t *src_vmask,
bitset_t **dst_vmask);
ssize_t (*transfer)(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
const snd_pcm_plugin_voice_t *dst_voices,
snd_pcm_plugin_voice_t *dst_voices,
size_t samples);
int (*action)(snd_pcm_plugin_t *plugin,
snd_pcm_plugin_action_t action,
@ -123,49 +223,32 @@ struct snd_stru_pcm_plugin {
snd_pcm_plugin_handle_t *handle;
void *private_data;
void (*private_free)(snd_pcm_plugin_t *plugin, void *private_data);
snd_pcm_plugin_voice_t *voices;
void *extra_data;
snd_pcm_plugin_voice_t *src_voices;
snd_pcm_plugin_voice_t *dst_voices;
bitset_t *src_vmask;
bitset_t *dst_vmask;
char extra_data[0];
};
snd_pcm_plugin_t *snd_pcm_plugin_build(snd_pcm_plugin_handle_t *handle,
const char *name,
snd_pcm_format_t *src_format,
snd_pcm_format_t *dst_format,
int extra);
int snd_pcm_plug_connect(snd_pcm_t **handle, snd_pcm_t *slave, int mode, int close_slave);
int snd_pcm_plug_open_subdevice(snd_pcm_t **handle, int card, int device, int subdevice, int mode);
int snd_pcm_plug_open(snd_pcm_t **handle, int card, int device, int mode);
int snd_pcm_plugin_free(snd_pcm_plugin_t *plugin);
int snd_pcm_plugin_clear(snd_pcm_t *handle, int channel);
int snd_pcm_plugin_insert(snd_pcm_t *handle, int channel, snd_pcm_plugin_t *plugin);
int snd_pcm_plugin_append(snd_pcm_t *handle, int channel, snd_pcm_plugin_t *plugin);
int snd_pcm_plugin_remove_to(snd_pcm_t *handle, int channel, snd_pcm_plugin_t *plugin);
int snd_pcm_plugin_remove_first(snd_pcm_t *handle, int channel);
snd_pcm_plugin_t *snd_pcm_plugin_first(snd_pcm_t *handle, int channel);
snd_pcm_plugin_t *snd_pcm_plugin_last(snd_pcm_t *handle, int channel);
ssize_t snd_pcm_plugin_client_samples(snd_pcm_t *handle, int channel, size_t drv_samples);
ssize_t snd_pcm_plugin_hardware_samples(snd_pcm_t *handle, int channel, size_t clt_samples);
ssize_t snd_pcm_plugin_client_size(snd_pcm_t *handle, int channel, size_t drv_size);
ssize_t snd_pcm_plugin_hardware_size(snd_pcm_t *handle, int channel, size_t clt_size);
int snd_pcm_plugin_info(snd_pcm_t *handle, snd_pcm_channel_info_t *info);
int snd_pcm_plugin_params(snd_pcm_t *handle, snd_pcm_channel_params_t *params);
int snd_pcm_plugin_setup(snd_pcm_t *handle, snd_pcm_channel_setup_t *setup);
int snd_pcm_plugin_voice_setup(snd_pcm_t *handle, int channel, snd_pcm_voice_setup_t * setup);
int snd_pcm_plugin_status(snd_pcm_t *handle, snd_pcm_channel_status_t *status);
int snd_pcm_plugin_prepare(snd_pcm_t *handle, int channel);
int snd_pcm_plugin_playback_drain(snd_pcm_t *handle);
int snd_pcm_plugin_flush(snd_pcm_t *handle, int channel);
ssize_t snd_pcm_plugin_transfer_size(snd_pcm_t *handle, int channel);
int snd_pcm_plugin_pointer(snd_pcm_t *pcm, int channel, void **ptr, size_t *size);
ssize_t snd_pcm_plugin_write(snd_pcm_t *handle, const void *buffer, size_t size);
ssize_t snd_pcm_plugin_read(snd_pcm_t *handle, void *bufer, size_t size);
int snd_pcm_plugin_pointerv(snd_pcm_t *pcm, int channel, struct iovec **vector, int *count);
ssize_t snd_pcm_plugin_writev(snd_pcm_t *pcm, const struct iovec *vector, int count);
ssize_t snd_pcm_plugin_readv(snd_pcm_t *pcm, const struct iovec *vector, int count);
ssize_t snd_pcm_plugin_write_continue(snd_pcm_t *pcm);
int snd_pcm_plugin_mmap(snd_pcm_t *handle, int channel, snd_pcm_mmap_control_t **control, void **buffer);
int snd_pcm_plugin_munmap(snd_pcm_t *handle, int channel);
int snd_pcm_plugin_go(snd_pcm_t *handle, int channel);
int snd_pcm_plugin_sync_go(snd_pcm_t *handle, snd_pcm_sync_t *sync);
int snd_pcm_plugin_pause(snd_pcm_t *pcm, int enable);
int snd_pcm_plugin_voice_setup(snd_pcm_t *pcm, int channel, snd_pcm_voice_setup_t *setup);
int snd_pcm_plug_clear(snd_pcm_t *handle, int channel);
int snd_pcm_plugin_insert(snd_pcm_plugin_t *plugin);
int snd_pcm_plugin_append(snd_pcm_plugin_t *plugin);
#if 0
int snd_pcm_plugin_remove_to(snd_pcm_plugin_t *plugin);
int snd_pcm_plug_remove_first(snd_pcm_t *handle, int channel);
#endif
snd_pcm_plugin_t *snd_pcm_plug_first(snd_pcm_t *handle, int channel);
snd_pcm_plugin_t *snd_pcm_plug_last(snd_pcm_t *handle, int channel);
int snd_pcm_plug_direct(snd_pcm_t *pcm, int channel);
ssize_t snd_pcm_plug_client_samples(snd_pcm_t *handle, int channel, size_t drv_samples);
ssize_t snd_pcm_plug_slave_samples(snd_pcm_t *handle, int channel, size_t clt_samples);
ssize_t snd_pcm_plug_client_size(snd_pcm_t *handle, int channel, size_t drv_size);
ssize_t snd_pcm_plug_slave_size(snd_pcm_t *handle, int channel, size_t clt_size);
/*
* Plug-In helpers
@ -175,91 +258,75 @@ ssize_t snd_pcm_plugin_src_samples_to_size(snd_pcm_plugin_t *plugin, size_t samp
ssize_t snd_pcm_plugin_dst_samples_to_size(snd_pcm_plugin_t *plugin, size_t samples);
ssize_t snd_pcm_plugin_src_size_to_samples(snd_pcm_plugin_t *plugin, size_t size);
ssize_t snd_pcm_plugin_dst_size_to_samples(snd_pcm_plugin_t *plugin, size_t size);
int snd_pcm_plugin_src_voices(snd_pcm_plugin_t *plugin,
snd_pcm_plugin_voice_t **voices,
size_t samples);
int snd_pcm_plugin_dst_voices(snd_pcm_plugin_t *plugin,
snd_pcm_plugin_voice_t **voices,
size_t samples);
/*
* Plug-In constructors
*/
int snd_pcm_plugin_build(snd_pcm_plugin_handle_t *handle,
int channel,
const char *name,
snd_pcm_format_t *src_format,
snd_pcm_format_t *dst_format,
int extra,
snd_pcm_plugin_t **ret);
/* basic I/O */
int snd_pcm_plugin_build_stream(snd_pcm_plugin_handle_t *handle, int channel,
int snd_pcm_plugin_build_stream(snd_pcm_plugin_handle_t *handle,
int channel,
snd_pcm_t *slave,
snd_pcm_format_t *format,
snd_pcm_plugin_t **r_plugin);
int snd_pcm_plugin_build_block(snd_pcm_plugin_handle_t *handle, int channel,
int snd_pcm_plugin_build_block(snd_pcm_plugin_handle_t *handle,
int channel,
snd_pcm_t *slave,
snd_pcm_format_t *format,
snd_pcm_plugin_t **r_plugin);
int snd_pcm_plugin_build_mmap(snd_pcm_plugin_handle_t *handle, int channel,
int snd_pcm_plugin_build_mmap(snd_pcm_plugin_handle_t *handle,
int channel,
snd_pcm_t *slave,
snd_pcm_format_t *format,
snd_pcm_plugin_t **r_plugin);
/* conversion plugins */
int snd_pcm_plugin_build_interleave(snd_pcm_plugin_handle_t *handle,
int channel,
snd_pcm_format_t *src_format,
snd_pcm_format_t *dst_format,
snd_pcm_plugin_t **r_plugin);
int snd_pcm_plugin_build_linear(snd_pcm_plugin_handle_t *handle,
int channel,
snd_pcm_format_t *src_format,
snd_pcm_format_t *dst_format,
snd_pcm_plugin_t **r_plugin);
int snd_pcm_plugin_build_mulaw(snd_pcm_plugin_handle_t *handle,
int channel,
snd_pcm_format_t *src_format,
snd_pcm_format_t *dst_format,
snd_pcm_plugin_t **r_plugin);
int snd_pcm_plugin_build_alaw(snd_pcm_plugin_handle_t *handle,
int channel,
snd_pcm_format_t *src_format,
snd_pcm_format_t *dst_format,
snd_pcm_plugin_t **r_plugin);
int snd_pcm_plugin_build_adpcm(snd_pcm_plugin_handle_t *handle,
int channel,
snd_pcm_format_t *src_format,
snd_pcm_format_t *dst_format,
snd_pcm_plugin_t **r_plugin);
int snd_pcm_plugin_build_rate(snd_pcm_plugin_handle_t *handle,
int channel,
snd_pcm_format_t *src_format,
snd_pcm_format_t *dst_format,
snd_pcm_plugin_t **r_plugin);
int snd_pcm_plugin_build_route(snd_pcm_plugin_handle_t *handle,
int channel,
snd_pcm_format_t *src_format,
snd_pcm_format_t *dst_format,
float *ttable,
snd_pcm_plugin_t **r_plugin);
#ifdef __cplusplus
}
#endif
/*
* Loopback interface
*/
#define SND_PCM_LB_OPEN_PLAYBACK 0
#define SND_PCM_LB_OPEN_CAPTURE 1
#ifdef __cplusplus
extern "C" {
#endif
typedef struct snd_pcm_loopback_callbacks {
void *private_data; /* should be used with an application */
size_t max_buffer_size; /* zero = default (64kB) */
void (*data) (void *private_data, char *buffer, size_t count);
void (*position_change) (void *private_data, unsigned int pos);
void (*format_change) (void *private_data, snd_pcm_format_t *format);
void (*silence) (void *private_data, size_t count);
void *reserved[31]; /* reserved for the future use - must be NULL!!! */
} snd_pcm_loopback_callbacks_t;
int snd_pcm_loopback_open(snd_pcm_loopback_t **handle, int card, int device, int subdev, int mode);
int snd_pcm_loopback_close(snd_pcm_loopback_t *handle);
int snd_pcm_loopback_file_descriptor(snd_pcm_loopback_t *handle);
int snd_pcm_loopback_block_mode(snd_pcm_loopback_t *handle, int enable);
int snd_pcm_loopback_stream_mode(snd_pcm_loopback_t *handle, int mode);
int snd_pcm_loopback_format(snd_pcm_loopback_t *handle, snd_pcm_format_t * format);
int snd_pcm_loopback_status(snd_pcm_loopback_t *handle, snd_pcm_loopback_status_t * status);
ssize_t snd_pcm_loopback_read(snd_pcm_loopback_t *handle, snd_pcm_loopback_callbacks_t * callbacks);
int snd_pcm_plugin_build_copy(snd_pcm_plugin_handle_t *handle,
int channel,
snd_pcm_format_t *format,
snd_pcm_plugin_t **r_plugin);
#ifdef __cplusplus
}

View file

@ -22,8 +22,8 @@ int snd_seq_block_mode(snd_seq_t *handle, int enable);
int snd_seq_client_id(snd_seq_t *handle);
int snd_seq_output_buffer_size(snd_seq_t *handle);
int snd_seq_input_buffer_size(snd_seq_t *handle);
int snd_seq_resize_output_buffer(snd_seq_t *handle, int size);
int snd_seq_resize_input_buffer(snd_seq_t *handle, int size);
int snd_seq_resize_output_buffer(snd_seq_t *handle, size_t size);
int snd_seq_resize_input_buffer(snd_seq_t *handle, size_t size);
int snd_seq_system_info(snd_seq_t *handle, snd_seq_system_info_t *info);
int snd_seq_get_client_info(snd_seq_t *handle, snd_seq_client_info_t *info);
int snd_seq_get_any_client_info(snd_seq_t *handle, int client, snd_seq_client_info_t *info);
@ -64,7 +64,7 @@ int snd_seq_query_next_port(snd_seq_t *handle, snd_seq_port_info_t * info);
/* event routines */
snd_seq_event_t *snd_seq_create_event(void);
int snd_seq_free_event(snd_seq_event_t *ev);
int snd_seq_event_length(snd_seq_event_t *ev);
ssize_t snd_seq_event_length(snd_seq_event_t *ev);
int snd_seq_event_output(snd_seq_t *handle, snd_seq_event_t *ev);
int snd_seq_event_output(snd_seq_t *handle, snd_seq_event_t *ev);
int snd_seq_event_output_buffer(snd_seq_t *handle, snd_seq_event_t *ev);

View file

@ -2,7 +2,7 @@ SUBDIRS=control mixer pcm rawmidi timer hwdep seq instr
COMPATNUM=@LIBTOOL_VERSION_INFO@
lib_LTLIBRARIES = libasound.la
libasound_la_SOURCES = error.c
libasound_la_SOURCES = error.c
libasound_la_LIBADD = control/libcontrol.la mixer/libmixer.la pcm/libpcm.la \
rawmidi/librawmidi.la timer/libtimer.la hwdep/libhwdep.la \
seq/libseq.la instr/libinstr.la

View file

@ -38,7 +38,7 @@ const char *snd_strerror(int errnum)
if (errnum < SND_ERROR_BEGIN)
return (const char *) strerror(errnum);
errnum -= SND_ERROR_BEGIN;
if (errnum >= sizeof(snd_error_codes) / sizeof(const char *))
if ((unsigned int) errnum >= sizeof(snd_error_codes) / sizeof(const char *))
return "Unknown error";
return snd_error_codes[errnum];
}

View file

@ -132,7 +132,7 @@ ssize_t snd_hwdep_write(snd_hwdep_t *hwdep, const void *buffer, size_t size)
{
ssize_t result;
if (!hwdep || (!buffer && size > 0) || size < 0)
if (!hwdep || (!buffer && size > 0))
return -EINVAL;
result = write(hwdep->fd, buffer, size);
if (result < 0)
@ -144,7 +144,7 @@ ssize_t snd_hwdep_read(snd_hwdep_t *hwdep, void *buffer, size_t size)
{
ssize_t result;
if (!hwdep || (!buffer && size > 0) || size < 0)
if (!hwdep || (!buffer && size > 0))
return -EINVAL;
result = read(hwdep->fd, buffer, size);
if (result < 0)

View file

@ -174,7 +174,7 @@ struct envelope_record {
struct snd_iwffff_handle {
int rom;
unsigned char *fff_data;
unsigned int fff_size;
size_t fff_size;
char *fff_filename;
char *dat_filename;
unsigned int start_addr;
@ -237,7 +237,7 @@ int snd_instr_iwffff_open(snd_iwffff_handle_t **handle, const char *name_fff, co
close(fd);
return -ENOMEM;
}
if (read(fd, iwf->fff_data, iwf->fff_size) != iwf->fff_size) {
if (read(fd, iwf->fff_data, iwf->fff_size) != (ssize_t) iwf->fff_size) {
free(iwf->fff_data);
free(iwf);
close(fd);
@ -292,7 +292,7 @@ int snd_instr_iwffff_open_rom(snd_iwffff_handle_t **handle, int card, int bank,
close(fd);
return -ENOMEM;
}
if (read(fd, iwf->fff_data, ffff.length) != ffff.length) {
if (read(fd, iwf->fff_data, ffff.length) != (ssize_t) ffff.length) {
free(iwf->fff_data);
free(iwf);
close(fd);
@ -386,7 +386,7 @@ int snd_instr_iwffff_free(snd_instr_iwffff_t *__instr)
return 0;
}
static char *look_for_id(snd_iwffff_handle_t *iwf, unsigned char *start,
static char *look_for_id(snd_iwffff_handle_t *iwf UNUSED, unsigned char *start,
unsigned char *end, ID id)
{
if (!start)
@ -485,7 +485,7 @@ static int load_iw_wave(snd_iwffff_handle_t *file,
close(fd);
return -ENOMEM;
}
if (read(fd, result, size) != size) {
if (read(fd, result, size) != (ssize_t) size) {
free(*result);
*result = NULL;
close(fd);
@ -832,9 +832,9 @@ int snd_instr_iwffff_conv_to_stream(snd_instr_iwffff_t *iwffff,
return 0;
}
int snd_instr_iwffff_convert_from_stream(snd_seq_instr_get_t *data,
long size,
snd_instr_iwffff_t **iwffff)
int snd_instr_iwffff_convert_from_stream(snd_seq_instr_get_t *data UNUSED,
size_t size UNUSED,
snd_instr_iwffff_t **iwffff UNUSED)
{
/* TODO */
return -ENXIO;

View file

@ -43,7 +43,7 @@ static long simple_size(simple_instrument_t *instr)
int snd_instr_simple_convert_to_stream(snd_instr_simple_t *simple,
const char *name,
snd_seq_instr_put_t **__data,
long *__size)
size_t *__size)
{
snd_seq_instr_put_t *put;
snd_seq_instr_data_t *data;
@ -93,9 +93,9 @@ int snd_instr_simple_convert_to_stream(snd_instr_simple_t *simple,
return 0;
}
int snd_instr_simple_convert_from_stream(snd_seq_instr_get_t *__data,
long size,
snd_instr_simple_t **simple)
int snd_instr_simple_convert_from_stream(snd_seq_instr_get_t *__data UNUSED,
size_t size UNUSED,
snd_instr_simple_t **simple UNUSED)
{
/* TODO */
return -ENXIO;

View file

@ -91,15 +91,6 @@ int snd_mixer_element_info_build(snd_mixer_t *handle, snd_mixer_element_info_t *
if ((err = snd_mixer_element_info(handle, element)) < 0)
return err;
break;
case SND_MIXER_ETYPE_SWITCH3:
element->data.switch3.voices_size = element->data.switch3.voices_over;
element->data.switch3.voices = element->data.switch3.voices_over = 0;
element->data.switch3.pvoices = (snd_mixer_voice_t *)malloc(element->data.switch3.voices_size * sizeof(snd_mixer_voice_t));
if (!element->data.switch3.pvoices)
return -ENOMEM;
if ((err = snd_mixer_element_info(handle, element)) < 0)
return err;
break;
case SND_MIXER_ETYPE_VOLUME1:
element->data.volume1.range_size = element->data.volume1.range_over;
element->data.volume1.range = element->data.volume1.range_over = 0;
@ -176,9 +167,6 @@ int snd_mixer_element_info_free(snd_mixer_element_info_t *element)
case SND_MIXER_ETYPE_PLAYBACK1:
safe_free((void **)&element->data.pcm1.pdevices);
break;
case SND_MIXER_ETYPE_SWITCH3:
safe_free((void **)&element->data.switch3.pvoices);
break;
case SND_MIXER_ETYPE_VOLUME1:
safe_free((void **)&element->data.volume1.prange);
break;

View file

@ -32,7 +32,7 @@
#include <search.h>
#define SND_FILE_MIXER "/dev/snd/mixerC%iD%i"
#define SND_MIXER_VERSION_MAX SND_PROTOCOL_VERSION(1, 0, 1)
#define SND_MIXER_VERSION_MAX SND_PROTOCOL_VERSION(2, 0, 0)
struct snd_mixer {
int card;
@ -335,7 +335,7 @@ void snd_mixer_sort_gid(snd_mixer_gid_t *list, int count,
/* Compare using name and index */
int snd_mixer_compare_gid_name_index(const snd_mixer_gid_t *a,
const snd_mixer_gid_t *b,
void* ignored)
void *ignored UNUSED)
{
int r = strcmp(a->name, b->name);
if (r != 0)
@ -426,7 +426,7 @@ void snd_mixer_sort_eid(snd_mixer_eid_t *list, int count,
/* Compare using name and index */
int snd_mixer_compare_eid_name_index(const snd_mixer_eid_t *a,
const snd_mixer_eid_t *b,
void* ignored)
void *ignored UNUSED)
{
int r = strcmp(a->name, b->name);
if (r != 0)

View file

@ -2,8 +2,8 @@ SUBDIRS = plugin
EXTRA_LTLIBRARIES = libpcm.la
libpcm_la_SOURCES = pcm.c pcm_plugin.c pcm_plugin_build.c pcm_misc.c \
pcm_loopback.c
libpcm_la_SOURCES = pcm.c pcm_hw.c pcm_plug.c pcm_plugin_build.c pcm_misc.c \
pcm_mmap.c
libpcm_la_LIBADD = plugin/libpcmplugin.la
noinst_HEADERS = pcm_local.h

View file

@ -1,7 +1,7 @@
/*
* PCM Interface - main file
* Copyright (c) 1998 by Jaroslav Kysela <perex@suse.cz>
*
* Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
@ -20,567 +20,521 @@
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <malloc.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/poll.h>
#include <sys/uio.h>
#include "pcm_local.h"
#define SND_FILE_PCM_PLAYBACK "/dev/snd/pcmC%iD%ip"
#define SND_FILE_PCM_CAPTURE "/dev/snd/pcmC%iD%ic"
#define SND_PCM_VERSION_MAX SND_PROTOCOL_VERSION(2, 0, 0)
int snd_pcm_open(snd_pcm_t **handle, int card, int device, int mode)
int snd_pcm_abstract_open(snd_pcm_t **handle, int mode,
snd_pcm_type_t type, size_t extra)
{
return snd_pcm_open_subdevice(handle, card, device, -1, mode);
}
static int snd_pcm_open_channel(int card, int device, int channel, int subdevice, int fmode, snd_ctl_t *ctl, int *ver)
{
char filename[32];
char *filefmt;
int err, fd;
int attempt = 0;
snd_pcm_channel_info_t info;
switch (channel) {
case SND_PCM_CHANNEL_PLAYBACK:
filefmt = SND_FILE_PCM_PLAYBACK;
break;
case SND_PCM_CHANNEL_CAPTURE:
filefmt = SND_FILE_PCM_CAPTURE;
break;
default:
return -EINVAL;
}
if ((err = snd_ctl_pcm_channel_prefer_subdevice(ctl, device, channel, subdevice)) < 0)
return err;
sprintf(filename, filefmt, card, device);
__again:
if (attempt++ > 3) {
snd_ctl_close(ctl);
return -EBUSY;
}
if ((fd = open(filename, fmode)) < 0) {
err = -errno;
return err;
}
if (ioctl(fd, SND_PCM_IOCTL_PVERSION, ver) < 0) {
err = -errno;
close(fd);
return err;
}
if (SND_PROTOCOL_INCOMPATIBLE(*ver, SND_PCM_VERSION_MAX)) {
close(fd);
return -SND_ERROR_INCOMPATIBLE_VERSION;
}
if (subdevice >= 0) {
memset(&info, 0, sizeof(info));
if (ioctl(fd, SND_PCM_IOCTL_CHANNEL_INFO, &info) < 0) {
err = -errno;
close(fd);
return err;
}
if (info.subdevice != subdevice) {
close(fd);
goto __again;
}
}
return fd;
}
int snd_pcm_open_subdevice(snd_pcm_t **handle, int card, int device, int subdevice, int mode)
{
int fmode, ver, err;
snd_pcm_t *pcm;
snd_ctl_t *ctl;
int pfd = -1, cfd = -1;
if (!handle)
return -EFAULT;
*handle = NULL;
if (card < 0 || card >= SND_CARDS)
return -EINVAL;
if ((err = snd_ctl_open(&ctl, card)) < 0)
return err;
fmode = O_RDWR;
if (mode & SND_PCM_OPEN_NONBLOCK)
fmode |= O_NONBLOCK;
pcm = (snd_pcm_t *) calloc(1, sizeof(snd_pcm_t) + extra);
if (pcm == NULL)
return -ENOMEM;
if (mode & SND_PCM_OPEN_PLAYBACK) {
pfd = snd_pcm_open_channel(card, device, SND_PCM_CHANNEL_PLAYBACK,
subdevice, fmode, ctl, &ver);
if (pfd < 0) {
snd_ctl_close(ctl);
return pfd;
}
struct snd_pcm_chan *chan = &pcm->chan[SND_PCM_CHANNEL_PLAYBACK];
chan->open = 1;
chan->mode = (mode & SND_PCM_NONBLOCK_PLAYBACK) ? SND_PCM_NONBLOCK : 0;
}
if (mode & SND_PCM_OPEN_CAPTURE) {
cfd = snd_pcm_open_channel(card, device, SND_PCM_CHANNEL_CAPTURE,
subdevice, fmode, ctl, &ver);
if (cfd < 0) {
if (pfd >= 0)
close(pfd);
snd_ctl_close(ctl);
return cfd;
}
struct snd_pcm_chan *chan = &pcm->chan[SND_PCM_CHANNEL_CAPTURE];
chan->open = 1;
chan->mode = (mode & SND_PCM_NONBLOCK_CAPTURE) ? SND_PCM_NONBLOCK : 0;
}
snd_ctl_close(ctl);
if (pfd < 0 && cfd < 0)
return -EINVAL;
pcm = (snd_pcm_t *) calloc(1, sizeof(snd_pcm_t));
if (pcm == NULL) {
if (pfd >= 0)
close(pfd);
if (cfd >= 0)
close(cfd);
return -ENOMEM;
}
pcm->card = card;
pcm->device = device;
pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd = pfd;
pcm->chan[SND_PCM_CHANNEL_CAPTURE].fd = cfd;
pcm->mode = mode;
pcm->ver = ver;
pcm->type = type;
pcm->mode = mode & SND_PCM_OPEN_DUPLEX;
*handle = pcm;
return 0;
}
snd_pcm_type_t snd_pcm_type(snd_pcm_t *handle)
{
return handle->type;
}
int snd_pcm_channel_close(snd_pcm_t *pcm, int channel)
{
int ret = 0;
int err;
struct snd_pcm_chan *chan;
if (!pcm)
return -EFAULT;
if (channel < 0 || channel > 1)
return -EINVAL;
chan = &pcm->chan[channel];
if (!chan->open)
return -EBADFD;
if (chan->mmap_control) {
if ((err = snd_pcm_munmap_control(pcm, channel)) < 0)
ret = err;
}
if (chan->mmap_data) {
if ((err = snd_pcm_munmap_data(pcm, channel)) < 0)
ret = err;
}
if ((err = pcm->ops->channel_close(pcm, channel)) < 0)
ret = err;
chan->open = 0;
chan->valid_setup = 0;
if (chan->valid_voices_setup) {
chan->valid_voices_setup = 0;
free(chan->voices_setup);
}
return ret;
}
int snd_pcm_close(snd_pcm_t *pcm)
{
int res = 0;
int err, ret = 0;
int channel;
if (!pcm)
return -EINVAL;
return -EFAULT;
for (channel = 0; channel < 2; ++channel) {
snd_pcm_plugin_munmap(pcm, channel);
snd_pcm_plugin_clear(pcm, channel);
snd_pcm_munmap(pcm, channel);
if (pcm->chan[channel].fd >= 0)
if (close(pcm->chan[channel].fd))
res = -errno;
if (pcm->chan[channel].open) {
if ((err = snd_pcm_channel_close(pcm, channel)) < 0)
ret = err;
}
}
free(pcm);
return res;
return ret;
}
int snd_pcm_file_descriptor(snd_pcm_t *pcm, int channel)
{
if (!pcm)
return -EINVAL;
if (channel < 0 || channel > 1)
return -EINVAL;
return pcm->chan[channel].fd;
}
int snd_pcm_nonblock_mode(snd_pcm_t *pcm, int nonblock)
{
long flags;
int fd, channel;
if (!pcm)
return -EINVAL;
for (channel = 0; channel < 2; ++channel) {
fd = pcm->chan[channel].fd;
if (fd < 0)
continue;
if ((flags = fcntl(fd, F_GETFL)) < 0)
return -errno;
if (nonblock)
flags |= O_NONBLOCK;
else
flags &= ~O_NONBLOCK;
if (fcntl(fd, F_SETFL, flags) < 0)
return -errno;
if (nonblock)
pcm->mode |= SND_PCM_OPEN_NONBLOCK;
else
pcm->mode &= ~SND_PCM_OPEN_NONBLOCK;
}
return 0;
}
int snd_pcm_info(snd_pcm_t *pcm, snd_pcm_info_t * info)
{
int fd, channel;
if (!pcm || !info)
return -EINVAL;
for (channel = 0; channel < 2; ++channel) {
fd = pcm->chan[channel].fd;
if (fd >= 0)
break;
}
if (ioctl(fd, SND_PCM_IOCTL_INFO, info) < 0)
return -errno;
return 0;
}
int snd_pcm_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info)
{
int fd;
if (!pcm || !info)
return -EINVAL;
if (info->channel < 0 || info->channel > 1)
return -EINVAL;
fd = pcm->chan[info->channel].fd;
if (fd < 0)
return -EINVAL;
if (ioctl(fd, SND_PCM_IOCTL_CHANNEL_INFO, info) < 0)
return -errno;
return 0;
}
int snd_pcm_channel_params(snd_pcm_t *pcm, snd_pcm_channel_params_t * params)
int snd_pcm_channel_nonblock(snd_pcm_t *pcm, int channel, int nonblock)
{
int err;
int fd;
struct snd_pcm_chan *chan;
if (!pcm || !params)
if (!pcm)
return -EFAULT;
if (channel < 0 || channel > 1)
return -EINVAL;
if (!pcm->chan[channel].open)
return -EBADFD;
if ((err = pcm->ops->channel_nonblock(pcm, channel, nonblock)) < 0)
return err;
if (nonblock)
pcm->chan[channel].mode |= SND_PCM_NONBLOCK;
else
pcm->chan[channel].mode &= ~SND_PCM_NONBLOCK;
return 0;
}
int snd_pcm_info(snd_pcm_t *pcm, snd_pcm_info_t *info)
{
if (!pcm || !info)
return -EFAULT;
return pcm->ops->info(pcm, info);
}
int snd_pcm_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info)
{
if (!pcm || !info)
return -EFAULT;
if (info->channel < 0 || info->channel > 1)
return -EINVAL;
if (!pcm->chan[info->channel].open)
return -EBADFD;
return pcm->ops->channel_info(pcm, info);
}
int snd_pcm_channel_params(snd_pcm_t *pcm, snd_pcm_channel_params_t *params)
{
int err;
snd_pcm_channel_setup_t setup;
struct snd_pcm_chan *chan;
if (!pcm || !params)
return -EFAULT;
if (params->channel < 0 || params->channel > 1)
return -EINVAL;
chan = &pcm->chan[params->channel];
fd = chan->fd;
if (fd < 0)
return -EINVAL;
if (ioctl(fd, SND_PCM_IOCTL_CHANNEL_PARAMS, params) < 0)
return -errno;
chan->setup_is_valid = 0;
memset(&chan->setup, 0, sizeof(snd_pcm_channel_setup_t));
chan->setup.channel = params->channel;
if ((err = snd_pcm_channel_setup(pcm, &chan->setup))<0)
if (!chan->open)
return -EBADFD;
if (chan->mmap_control)
return -EBADFD;
if ((err = pcm->ops->channel_params(pcm, params)) < 0)
return err;
return 0;
chan->valid_setup = 0;
setup.channel = params->channel;
return snd_pcm_channel_setup(pcm, &setup);
}
int snd_pcm_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t * setup)
int snd_pcm_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t *setup)
{
int fd;
int err;
struct snd_pcm_chan *chan;
if (!pcm || !setup)
return -EINVAL;
return -EFAULT;
if (setup->channel < 0 || setup->channel > 1)
return -EINVAL;
chan = &pcm->chan[setup->channel];
fd = chan->fd;
if (fd < 0)
return -EINVAL;
if (chan->setup_is_valid) {
if (!chan->open)
return -EBADFD;
if (chan->valid_setup) {
memcpy(setup, &chan->setup, sizeof(*setup));
return 0;
}
if (ioctl(fd, SND_PCM_IOCTL_CHANNEL_SETUP, setup) < 0)
return -errno;
if ((err = pcm->ops->channel_setup(pcm, setup)) < 0)
return err;
memcpy(&chan->setup, setup, sizeof(*setup));
chan->setup_is_valid = 1;
chan->valid_setup = 1;
return 0;
}
int snd_pcm_voice_setup(snd_pcm_t *pcm, int channel, snd_pcm_voice_setup_t * setup)
const snd_pcm_channel_setup_t* snd_pcm_channel_cached_setup(snd_pcm_t *pcm, int channel)
{
int fd;
struct snd_pcm_chan *chan;
if (!pcm)
return 0;
if (channel < 0 || channel > 1)
return 0;
chan = &pcm->chan[channel];
if (!chan->open || !chan->valid_setup)
return 0;
return &chan->setup;
}
int snd_pcm_voice_setup(snd_pcm_t *pcm, int channel, snd_pcm_voice_setup_t *setup)
{
struct snd_pcm_chan *chan;
if (!pcm || !setup)
return -EINVAL;
return -EFAULT;
if (channel < 0 || channel > 1)
return -EINVAL;
fd = pcm->chan[channel].fd;
if (fd < 0)
chan = &pcm->chan[channel];
if (!chan->open || !chan->valid_setup)
return -EBADFD;
if (chan->valid_voices_setup) {
if (setup->voice >= chan->setup.format.voices)
return -EINVAL;
memcpy(setup, &chan->voices_setup[setup->voice], sizeof(*setup));
return 0;
}
return pcm->ops->voice_setup(pcm, channel, setup);
}
const snd_pcm_voice_setup_t* snd_pcm_channel_cached_voice_setup(snd_pcm_t *pcm, int channel, unsigned int voice)
{
struct snd_pcm_chan *chan;
if (!pcm)
return 0;
if (channel < 0 || channel > 1)
return 0;
chan = &pcm->chan[channel];
if (!chan->open || !chan->valid_setup)
return 0;
if (voice >= chan->setup.format.voices)
return 0;
return &chan->voices_setup[voice];
}
int snd_pcm_all_voices_setup(snd_pcm_t *pcm, int channel, snd_pcm_voice_setup_t *setup)
{
struct snd_pcm_chan *chan;
snd_pcm_voice_setup_t *vs, *v;
unsigned int voice;
int err;
if (!pcm)
return -EFAULT;
if (channel < 0 || channel > 1)
return -EINVAL;
if (ioctl(fd, SND_PCM_IOCTL_VOICE_SETUP, setup) < 0)
return -errno;
chan = &pcm->chan[channel];
if (!chan->open || !chan->valid_setup)
return -EBADFD;
vs = calloc(chan->setup.format.voices, sizeof(*setup));
for (voice = 0, v = vs; voice < chan->setup.format.voices; ++voice, ++v) {
v->voice = voice;
err = snd_pcm_voice_setup(pcm, channel, v);
if (err < 0) {
free(vs);
return err;
}
if (setup) {
memcpy(setup, v, sizeof(*setup));
setup++;
}
}
chan->voices_setup = vs;
chan->valid_voices_setup = 1;
return 0;
}
int snd_pcm_channel_status(snd_pcm_t *pcm, snd_pcm_channel_status_t * status)
int snd_pcm_channel_status(snd_pcm_t *pcm, snd_pcm_channel_status_t *status)
{
int fd;
if (!pcm || !status)
return -EFAULT;
if (status->channel < 0 || status->channel > 1)
return -EINVAL;
fd = pcm->chan[status->channel].fd;
if (fd < 0)
if (!pcm->chan[status->channel].open)
return -EBADFD;
return pcm->ops->channel_status(pcm, status);
}
int snd_pcm_channel_prepare(snd_pcm_t *pcm, int channel)
{
int err;
if (!pcm)
return -EFAULT;
if (channel < 0 || channel > 1)
return -EINVAL;
if (ioctl(fd, SND_PCM_IOCTL_CHANNEL_STATUS, status) < 0)
return -errno;
if (!pcm->chan[channel].open)
return -EBADFD;
err = pcm->ops->channel_prepare(pcm, channel);
if (err < 0)
return err;
snd_pcm_mmap_status_change(pcm, channel, SND_PCM_STATUS_PREPARED);
return 0;
}
int snd_pcm_playback_prepare(snd_pcm_t *pcm)
{
if (!pcm)
return -EINVAL;
if (pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd < 0)
return -EINVAL;
if (ioctl(pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd, SND_PCM_IOCTL_CHANNEL_PREPARE) < 0)
return -errno;
return 0;
return snd_pcm_channel_prepare(pcm, SND_PCM_CHANNEL_PLAYBACK);
}
int snd_pcm_capture_prepare(snd_pcm_t *pcm)
{
if (!pcm)
return -EINVAL;
if (pcm->chan[SND_PCM_CHANNEL_CAPTURE].fd < 0)
return -EINVAL;
if (ioctl(pcm->chan[SND_PCM_CHANNEL_CAPTURE].fd, SND_PCM_IOCTL_CHANNEL_PREPARE) < 0)
return -errno;
return 0;
return snd_pcm_channel_prepare(pcm, SND_PCM_CHANNEL_CAPTURE);
}
int snd_pcm_channel_prepare(snd_pcm_t *pcm, int channel)
static int mmap_playback_go(snd_pcm_t *pcm, int channel)
{
switch (channel) {
case SND_PCM_CHANNEL_PLAYBACK:
return snd_pcm_playback_prepare(pcm);
case SND_PCM_CHANNEL_CAPTURE:
return snd_pcm_capture_prepare(pcm);
default:
struct snd_pcm_chan *chan = &pcm->chan[channel];
if (chan->mmap_control->status != SND_PCM_STATUS_PREPARED)
return -EBADFD;
if (chan->mmap_control->frag_data == 0)
return -EIO;
}
}
int snd_pcm_playback_go(snd_pcm_t *pcm)
{
if (!pcm)
return -EINVAL;
if (pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd < 0)
return -EINVAL;
if (ioctl(pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd, SND_PCM_IOCTL_CHANNEL_GO) < 0)
return -errno;
return 0;
}
int snd_pcm_capture_go(snd_pcm_t *pcm)
{
if (!pcm)
return -EINVAL;
if (pcm->chan[SND_PCM_CHANNEL_CAPTURE].fd < 0)
return -EINVAL;
if (ioctl(pcm->chan[SND_PCM_CHANNEL_CAPTURE].fd, SND_PCM_IOCTL_CHANNEL_GO) < 0)
return -errno;
chan->mmap_control->status = SND_PCM_STATUS_RUNNING;
pthread_mutex_lock(&chan->mutex);
pthread_cond_signal(&chan->status_cond);
pthread_cond_wait(&chan->ready_cond, &chan->mutex);
pthread_mutex_unlock(&chan->mutex);
return 0;
}
int snd_pcm_channel_go(snd_pcm_t *pcm, int channel)
{
switch (channel) {
case SND_PCM_CHANNEL_PLAYBACK:
return snd_pcm_playback_go(pcm);
case SND_PCM_CHANNEL_CAPTURE:
return snd_pcm_capture_go(pcm);
default:
return -EIO;
int err;
struct snd_pcm_chan *chan;
if (!pcm)
return -EFAULT;
if (channel < 0 || channel > 1)
return -EINVAL;
chan = &pcm->chan[channel];
if (!chan->open)
return -EBADFD;
if (channel == SND_PCM_CHANNEL_PLAYBACK &&
chan->mmap_data_emulation) {
err = mmap_playback_go(pcm, channel);
if (err < 0)
return err;
}
err = pcm->ops->channel_go(pcm, channel);
if (err < 0)
return err;
if (channel == SND_PCM_CHANNEL_CAPTURE)
snd_pcm_mmap_status_change(pcm, channel, SND_PCM_STATUS_RUNNING);
return 0;
}
int snd_pcm_playback_go(snd_pcm_t *pcm)
{
return snd_pcm_channel_go(pcm, SND_PCM_CHANNEL_PLAYBACK);
}
int snd_pcm_capture_go(snd_pcm_t *pcm)
{
return snd_pcm_channel_go(pcm, SND_PCM_CHANNEL_CAPTURE);
}
int snd_pcm_sync_go(snd_pcm_t *pcm, snd_pcm_sync_t *sync)
{
int err;
if (!pcm || !sync)
return -EFAULT;
if (!pcm->chan[SND_PCM_CHANNEL_PLAYBACK].open &&
!pcm->chan[SND_PCM_CHANNEL_CAPTURE].open)
return -EBADFD;
err = pcm->ops->sync_go(pcm, sync);
if (err < 0)
return err;
/* NYI: mmap emulation */
return 0;
}
int snd_pcm_channel_drain(snd_pcm_t *pcm, int channel)
{
int err;
if (!pcm)
return -EFAULT;
if (channel < 0 || channel > 1)
return -EINVAL;
if (pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd < 0)
return -EINVAL;
if (ioctl(pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd, SND_PCM_IOCTL_SYNC_GO, sync) < 0)
return -errno;
if (!pcm->chan[channel].open)
return -EBADFD;
if (channel != SND_PCM_CHANNEL_PLAYBACK)
return -EBADFD;
err = pcm->ops->channel_drain(pcm, channel);
if (err < 0)
return err;
snd_pcm_mmap_status_change(pcm, channel, SND_PCM_STATUS_READY);
return 0;
}
int snd_pcm_playback_drain(snd_pcm_t *pcm)
{
return snd_pcm_channel_drain(pcm, SND_PCM_CHANNEL_PLAYBACK);
}
int snd_pcm_channel_flush(snd_pcm_t *pcm, int channel)
{
int err;
if (!pcm)
return -EFAULT;
if (channel < 0 || channel > 1)
return -EINVAL;
if (pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd < 0)
return -EINVAL;
if (ioctl(pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd, SND_PCM_IOCTL_CHANNEL_DRAIN) < 0)
return -errno;
if (!pcm->chan[channel].open)
return -EBADFD;
err = pcm->ops->channel_flush(pcm, channel);
if (err < 0)
return err;
snd_pcm_mmap_status_change(pcm, channel, SND_PCM_STATUS_READY);
return 0;
}
int snd_pcm_playback_flush(snd_pcm_t *pcm)
{
if (!pcm)
return -EINVAL;
if (pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd < 0)
return -EINVAL;
if (ioctl(pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd, SND_PCM_IOCTL_CHANNEL_FLUSH) < 0)
return -errno;
return 0;
return snd_pcm_channel_flush(pcm, SND_PCM_CHANNEL_PLAYBACK);
}
int snd_pcm_capture_flush(snd_pcm_t *pcm)
{
if (!pcm)
return -EINVAL;
if (pcm->chan[SND_PCM_CHANNEL_CAPTURE].fd < 0)
return -EINVAL;
if (ioctl(pcm->chan[SND_PCM_CHANNEL_CAPTURE].fd, SND_PCM_IOCTL_CHANNEL_FLUSH) < 0)
return -errno;
return 0;
return snd_pcm_channel_flush(pcm, SND_PCM_CHANNEL_CAPTURE);
}
int snd_pcm_channel_flush(snd_pcm_t *pcm, int channel)
int snd_pcm_channel_pause(snd_pcm_t *pcm, int channel, int enable)
{
switch (channel) {
case SND_PCM_CHANNEL_PLAYBACK:
return snd_pcm_playback_flush(pcm);
case SND_PCM_CHANNEL_CAPTURE:
return snd_pcm_capture_flush(pcm);
default:
return -EIO;
}
int err;
if (!pcm)
return -EFAULT;
if (channel < 0 || channel > 1)
return -EINVAL;
if (!pcm->chan[channel].open)
return -EBADFD;
if (channel != SND_PCM_CHANNEL_PLAYBACK)
return -EBADFD;
err = pcm->ops->channel_pause(pcm, channel, enable);
if (err < 0)
return err;
snd_pcm_mmap_status_change(pcm, channel, SND_PCM_STATUS_PAUSED);
return 0;
}
int snd_pcm_playback_pause(snd_pcm_t *pcm, int enable)
{
if (!pcm)
return -EINVAL;
if (pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd < 0)
return -EINVAL;
if (ioctl(pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd, SND_PCM_IOCTL_CHANNEL_PAUSE, &enable) < 0)
return -errno;
return 0;
return snd_pcm_channel_pause(pcm, SND_PCM_CHANNEL_PLAYBACK, enable);
}
ssize_t snd_pcm_transfer_size(snd_pcm_t *pcm, int channel)
{
struct snd_pcm_chan *chan;
if (!pcm || channel < 0 || channel > 1)
if (!pcm)
return -EFAULT;
if (channel < 0 || channel > 1)
return -EINVAL;
chan = &pcm->chan[channel];
if (!chan->setup_is_valid)
if (!chan->open)
return -EBADFD;
if (!chan->valid_setup)
return -EBADFD;
if (chan->setup.mode != SND_PCM_MODE_BLOCK)
return -EBADFD;
return chan->setup.buf.block.frag_size;
return chan->setup.frag_size;
}
ssize_t snd_pcm_write(snd_pcm_t *pcm, const void *buffer, size_t size)
{
ssize_t result;
if (!pcm || (!buffer && size > 0) || size < 0)
return -EINVAL;
if (pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd < 0)
return -EINVAL;
result = write(pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd, buffer, size);
if (result < 0)
return -errno;
return result;
if (!pcm)
return -EFAULT;
if (!pcm->chan[SND_PCM_CHANNEL_PLAYBACK].open ||
!pcm->chan[SND_PCM_CHANNEL_PLAYBACK].valid_setup)
return -EBADFD;
if (size > 0 && !buffer)
return -EFAULT;
return pcm->ops->write(pcm, buffer, size);
}
ssize_t snd_pcm_writev(snd_pcm_t *pcm, const struct iovec *vector, int count)
ssize_t snd_pcm_writev(snd_pcm_t *pcm, const struct iovec *vector, unsigned long count)
{
ssize_t result;
if (!pcm || (!vector && count > 0) || count < 0)
return -EINVAL;
if (pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd < 0)
return -EINVAL;
#if 0
result = writev(pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd, vector, count);
#else
{
snd_v_args_t args;
args.vector = vector;
args.count = count;
result = ioctl(pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd, SND_IOCTL_WRITEV, &args);
}
#endif
if (result < 0)
return -errno;
return result;
if (!pcm)
return -EFAULT;
if (!pcm->chan[SND_PCM_CHANNEL_PLAYBACK].open ||
!pcm->chan[SND_PCM_CHANNEL_PLAYBACK].valid_setup)
return -EBADFD;
if (count > 0 && !vector)
return -EFAULT;
return pcm->ops->writev(pcm, vector, count);
}
ssize_t snd_pcm_read(snd_pcm_t *pcm, void *buffer, size_t size)
{
ssize_t result;
if (!pcm || (!buffer && size > 0) || size < 0)
return -EINVAL;
if (pcm->chan[SND_PCM_CHANNEL_CAPTURE].fd < 0)
return -EINVAL;
result = read(pcm->chan[SND_PCM_CHANNEL_CAPTURE].fd, buffer, size);
if (result < 0)
return -errno;
return result;
if (!pcm)
return -EFAULT;
if (!pcm->chan[SND_PCM_CHANNEL_CAPTURE].open ||
!pcm->chan[SND_PCM_CHANNEL_CAPTURE].valid_setup)
return -EBADFD;
if (size > 0 && !buffer)
return -EFAULT;
return pcm->ops->read(pcm, buffer, size);
}
ssize_t snd_pcm_readv(snd_pcm_t *pcm, const struct iovec *vector, int count)
ssize_t snd_pcm_readv(snd_pcm_t *pcm, const struct iovec *vector, unsigned long count)
{
ssize_t result;
if (!pcm || (!vector && count > 0) || count < 0)
return -EINVAL;
if (pcm->chan[SND_PCM_CHANNEL_CAPTURE].fd < 0)
return -EINVAL;
#if 0
result = readv(pcm->chan[SND_PCM_CHANNEL_CAPTURE].fd, vector, count);
#else
{
snd_v_args_t args;
args.vector = vector;
args.count = count;
result = ioctl(pcm->chan[SND_PCM_CHANNEL_CAPTURE].fd, SND_IOCTL_READV, &args);
}
#endif
if (result < 0)
return -errno;
return result;
if (!pcm)
return -EFAULT;
if (!pcm->chan[SND_PCM_CHANNEL_CAPTURE].open ||
!pcm->chan[SND_PCM_CHANNEL_CAPTURE].valid_setup)
return -EBADFD;
if (count > 0 && !vector)
return -EFAULT;
return pcm->ops->readv(pcm, vector, count);
}
int snd_pcm_mmap(snd_pcm_t *pcm, int channel, snd_pcm_mmap_control_t **control, void **buffer)
int snd_pcm_file_descriptor(snd_pcm_t* pcm, int channel)
{
snd_pcm_channel_info_t info;
int err, fd, prot;
void *caddr, *daddr;
struct snd_pcm_chan *chan;
if (control)
*control = NULL;
if (buffer)
*buffer = NULL;
if (!pcm || channel < 0 || channel > 1 || !control || !buffer)
if (!pcm)
return -EFAULT;
if (channel < 0 || channel > 1)
return -EINVAL;
chan = &pcm->chan[channel];
fd = chan->fd;
if (fd < 0)
return -EINVAL;
memset(&info, 0, sizeof(info));
info.channel = channel;
if ((err = snd_pcm_channel_info(pcm, &info))<0)
return err;
caddr = mmap(NULL, sizeof(snd_pcm_mmap_control_t), PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, fd, SND_PCM_MMAP_OFFSET_CONTROL);
if (caddr == (caddr_t)-1 || caddr == NULL)
return -errno;
prot = channel == SND_PCM_CHANNEL_PLAYBACK ? PROT_WRITE : PROT_READ;
daddr = mmap(NULL, info.mmap_size, prot, MAP_FILE|MAP_SHARED, fd, SND_PCM_MMAP_OFFSET_DATA);
if (daddr == (caddr_t)-1 || daddr == NULL) {
err = -errno;
munmap(caddr, sizeof(snd_pcm_mmap_control_t));
return err;
}
*control = chan->mmap_control = caddr;
*buffer = chan->mmap_data = daddr;
chan->mmap_size = info.mmap_size;
return 0;
if (!pcm->chan[channel].open)
return -EBADFD;
return pcm->ops->file_descriptor(pcm, channel);
}
int snd_pcm_munmap(snd_pcm_t *pcm, int channel)
int snd_pcm_voices_mask(snd_pcm_t *pcm, int channel, bitset_t *client_vmask)
{
if (!pcm)
return -EFAULT;
if (channel < 0 || channel > 1)
return -EINVAL;
if (!pcm->chan[channel].open)
return -EBADFD;
return pcm->ops->voices_mask(pcm, channel, client_vmask);
}
int snd_pcm_bytes_per_second(snd_pcm_t *pcm, int channel)
{
struct snd_pcm_chan *chan;
if (!pcm || channel < 0 || channel > 1)
if (!pcm)
return -EFAULT;
if (channel < 0 || channel > 1)
return -EINVAL;
chan = &pcm->chan[channel];
if (chan->mmap_control) {
munmap(chan->mmap_control, sizeof(snd_pcm_mmap_control_t));
chan->mmap_control = NULL;
}
if (chan->mmap_data) {
munmap(chan->mmap_data, chan->mmap_size);
chan->mmap_data = NULL;
chan->mmap_size = 0;
}
return 0;
if (!chan->open || !chan->valid_setup)
return -EBADFD;
return snd_pcm_format_bytes_per_second(&chan->setup.format);
}

471
src/pcm/pcm_hw.c Normal file
View file

@ -0,0 +1,471 @@
/*
* PCM - Hardware
* 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 <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include "pcm_local.h"
#define SND_FILE_PCM_PLAYBACK "/dev/snd/pcmC%iD%ip"
#define SND_FILE_PCM_CAPTURE "/dev/snd/pcmC%iD%ic"
#define SND_PCM_VERSION_MAX SND_PROTOCOL_VERSION(2, 0, 0)
static int snd_pcm_hw_channel_close(snd_pcm_t *pcm, int channel)
{
snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private;
if (hw->chan[channel].fd >= 0)
if (close(hw->chan[channel].fd))
return -errno;
return 0;
}
int snd_pcm_hw_channel_fd(snd_pcm_t *pcm, int channel)
{
snd_pcm_hw_t *hw;
if (!pcm)
return -EINVAL;
if (channel < 0 || channel > 1)
return -EINVAL;
hw = (snd_pcm_hw_t*) &pcm->private;
return hw->chan[channel].fd;
}
static int snd_pcm_hw_channel_nonblock(snd_pcm_t *pcm, int channel, int nonblock)
{
long flags;
int fd;
snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private;
fd = hw->chan[channel].fd;
if ((flags = fcntl(fd, F_GETFL)) < 0)
return -errno;
if (nonblock)
flags |= O_NONBLOCK;
else
flags &= ~O_NONBLOCK;
if (fcntl(fd, F_SETFL, flags) < 0)
return -errno;
return 0;
}
static int snd_pcm_hw_info(snd_pcm_t *pcm, snd_pcm_info_t * info)
{
int fd, channel;
snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private;
for (channel = 0; channel < 2; ++channel) {
fd = hw->chan[channel].fd;
if (fd >= 0)
break;
}
if (fd < 0)
return -EBADFD;
if (ioctl(fd, SND_PCM_IOCTL_INFO, info) < 0)
return -errno;
return 0;
}
static int snd_pcm_hw_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info)
{
int fd;
snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private;
fd = hw->chan[info->channel].fd;
if (fd < 0)
return -EINVAL;
if (ioctl(fd, SND_PCM_IOCTL_CHANNEL_INFO, info) < 0)
return -errno;
return 0;
}
static int snd_pcm_hw_channel_params(snd_pcm_t *pcm, snd_pcm_channel_params_t * params)
{
int fd;
snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private;
fd = hw->chan[params->channel].fd;
if (ioctl(fd, SND_PCM_IOCTL_CHANNEL_PARAMS, params) < 0)
return -errno;
return 0;
}
static int snd_pcm_hw_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t * setup)
{
int fd;
snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private;
fd = hw->chan[setup->channel].fd;
if (ioctl(fd, SND_PCM_IOCTL_CHANNEL_SETUP, setup) < 0)
return -errno;
return 0;
}
static int snd_pcm_hw_voice_setup(snd_pcm_t *pcm, int channel, snd_pcm_voice_setup_t * setup)
{
int fd;
snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private;
fd = hw->chan[channel].fd;
if (ioctl(fd, SND_PCM_IOCTL_VOICE_SETUP, setup) < 0)
return -errno;
return 0;
}
static int snd_pcm_hw_channel_status(snd_pcm_t *pcm, snd_pcm_channel_status_t * status)
{
int fd;
snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private;
fd = hw->chan[status->channel].fd;
if (ioctl(fd, SND_PCM_IOCTL_CHANNEL_STATUS, status) < 0)
return -errno;
return 0;
}
static int snd_pcm_hw_channel_prepare(snd_pcm_t *pcm, int channel)
{
int fd;
snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private;
fd = hw->chan[channel].fd;
if (ioctl(fd, SND_PCM_IOCTL_CHANNEL_PREPARE) < 0)
return -errno;
return 0;
}
static int snd_pcm_hw_channel_go(snd_pcm_t *pcm, int channel)
{
int fd;
snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private;
fd = hw->chan[channel].fd;
if (ioctl(fd, SND_PCM_IOCTL_CHANNEL_GO) < 0)
return -errno;
return 0;
}
static int snd_pcm_hw_sync_go(snd_pcm_t *pcm, snd_pcm_sync_t *sync)
{
int fd;
snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private;
if (pcm->chan[SND_PCM_CHANNEL_PLAYBACK].open)
fd = hw->chan[SND_PCM_CHANNEL_PLAYBACK].fd;
else
fd = hw->chan[SND_PCM_CHANNEL_CAPTURE].fd;
if (ioctl(fd, SND_PCM_IOCTL_SYNC_GO, sync) < 0)
return -errno;
return 0;
}
static int snd_pcm_hw_channel_drain(snd_pcm_t *pcm, int channel)
{
int fd;
snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private;
fd = hw->chan[channel].fd;
if (ioctl(fd, SND_PCM_IOCTL_CHANNEL_DRAIN) < 0)
return -errno;
return 0;
}
static int snd_pcm_hw_channel_flush(snd_pcm_t *pcm, int channel)
{
int fd;
snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private;
fd = hw->chan[channel].fd;
if (ioctl(fd, SND_PCM_IOCTL_CHANNEL_FLUSH) < 0)
return -errno;
return 0;
}
static int snd_pcm_hw_channel_pause(snd_pcm_t *pcm, int channel, int enable)
{
int fd;
snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private;
fd = hw->chan[channel].fd;
if (ioctl(fd, SND_PCM_IOCTL_CHANNEL_PAUSE, &enable) < 0)
return -errno;
return 0;
}
static ssize_t snd_pcm_hw_write(snd_pcm_t *pcm, const void *buffer, size_t size)
{
ssize_t result;
int fd;
snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private;
fd = hw->chan[SND_PCM_CHANNEL_PLAYBACK].fd;
result = write(fd, buffer, size);
if (result < 0)
return -errno;
return result;
}
static ssize_t snd_pcm_hw_writev(snd_pcm_t *pcm, const struct iovec *vector, unsigned long count)
{
ssize_t result;
int fd;
snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private;
fd = hw->chan[SND_PCM_CHANNEL_PLAYBACK].fd;
#if 0
result = writev(fd, vector, count);
#else
{
snd_v_args_t args;
args.vector = vector;
args.count = count;
result = ioctl(fd, SND_IOCTL_WRITEV, &args);
}
#endif
if (result < 0)
return -errno;
return result;
}
static ssize_t snd_pcm_hw_read(snd_pcm_t *pcm, void *buffer, size_t size)
{
ssize_t result;
int fd;
snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private;
fd = hw->chan[SND_PCM_CHANNEL_CAPTURE].fd;
result = read(fd, buffer, size);
if (result < 0)
return -errno;
return result;
}
ssize_t snd_pcm_hw_readv(snd_pcm_t *pcm, const struct iovec *vector, unsigned long count)
{
ssize_t result;
int fd;
snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private;
fd = hw->chan[SND_PCM_CHANNEL_CAPTURE].fd;
#if 0
result = readv(fd, vector, count);
#else
{
snd_v_args_t args;
args.vector = vector;
args.count = count;
result = ioctl(fd, SND_IOCTL_READV, &args);
}
#endif
if (result < 0)
return -errno;
return result;
}
static int snd_pcm_hw_mmap_control(snd_pcm_t *pcm, int channel, snd_pcm_mmap_control_t **control, size_t csize)
{
void *caddr;
snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private;
caddr = mmap(NULL, csize, PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED,
hw->chan[channel].fd, SND_PCM_MMAP_OFFSET_CONTROL);
if (caddr == MAP_FAILED || caddr == NULL)
return -errno;
*control = caddr;
return 0;
}
static int snd_pcm_hw_mmap_data(snd_pcm_t *pcm, int channel, void **buffer, size_t bsize)
{
int prot;
void *daddr;
snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private;
prot = channel == SND_PCM_CHANNEL_PLAYBACK ? PROT_WRITE : PROT_READ;
daddr = mmap(NULL, bsize, prot, MAP_FILE|MAP_SHARED,
hw->chan[channel].fd, SND_PCM_MMAP_OFFSET_DATA);
if (daddr == MAP_FAILED || daddr == NULL)
return -errno;
*buffer = daddr;
return 0;
}
static int snd_pcm_hw_munmap_control(snd_pcm_t *pcm UNUSED, int channel UNUSED, snd_pcm_mmap_control_t *control, size_t csize)
{
if (munmap(control, csize) < 0)
return -errno;
return 0;
}
static int snd_pcm_hw_munmap_data(snd_pcm_t *pcm UNUSED, int channel UNUSED, void *buffer, size_t bsize)
{
if (munmap(buffer, bsize) < 0)
return -errno;
return 0;
}
static int snd_pcm_hw_file_descriptor(snd_pcm_t *pcm, int channel)
{
snd_pcm_hw_t *hw = (snd_pcm_hw_t*) &pcm->private;
return hw->chan[channel].fd;
}
static int snd_pcm_hw_voices_mask(snd_pcm_t *pcm UNUSED, int channel UNUSED,
bitset_t *client_vmask UNUSED)
{
return 0;
}
struct snd_pcm_ops snd_pcm_hw_ops = {
channel_close: snd_pcm_hw_channel_close,
channel_nonblock: snd_pcm_hw_channel_nonblock,
info: snd_pcm_hw_info,
channel_info: snd_pcm_hw_channel_info,
channel_params: snd_pcm_hw_channel_params,
channel_setup: snd_pcm_hw_channel_setup,
voice_setup: snd_pcm_hw_voice_setup,
channel_status: snd_pcm_hw_channel_status,
channel_prepare: snd_pcm_hw_channel_prepare,
channel_go: snd_pcm_hw_channel_go,
sync_go: snd_pcm_hw_sync_go,
channel_drain: snd_pcm_hw_channel_drain,
channel_flush: snd_pcm_hw_channel_flush,
channel_pause: snd_pcm_hw_channel_pause,
write: snd_pcm_hw_write,
writev: snd_pcm_hw_writev,
read: snd_pcm_hw_read,
readv: snd_pcm_hw_readv,
mmap_control: snd_pcm_hw_mmap_control,
mmap_data: snd_pcm_hw_mmap_data,
munmap_control: snd_pcm_hw_munmap_control,
munmap_data: snd_pcm_hw_munmap_data,
file_descriptor: snd_pcm_hw_file_descriptor,
voices_mask: snd_pcm_hw_voices_mask,
};
static int snd_pcm_hw_open_channel(int card, int device, int channel, int subdevice, int fmode, snd_ctl_t *ctl, int *ver)
{
char filename[32];
char *filefmt;
int err, fd;
int attempt = 0;
snd_pcm_channel_info_t info;
switch (channel) {
case SND_PCM_CHANNEL_PLAYBACK:
filefmt = SND_FILE_PCM_PLAYBACK;
break;
case SND_PCM_CHANNEL_CAPTURE:
filefmt = SND_FILE_PCM_CAPTURE;
break;
default:
return -EINVAL;
}
if ((err = snd_ctl_pcm_channel_prefer_subdevice(ctl, device, channel, subdevice)) < 0)
return err;
sprintf(filename, filefmt, card, device);
__again:
if (attempt++ > 3) {
snd_ctl_close(ctl);
return -EBUSY;
}
if ((fd = open(filename, fmode)) < 0) {
err = -errno;
return err;
}
if (ioctl(fd, SND_PCM_IOCTL_PVERSION, ver) < 0) {
err = -errno;
close(fd);
return err;
}
if (SND_PROTOCOL_INCOMPATIBLE(*ver, SND_PCM_VERSION_MAX)) {
close(fd);
return -SND_ERROR_INCOMPATIBLE_VERSION;
}
if (subdevice >= 0) {
memset(&info, 0, sizeof(info));
if (ioctl(fd, SND_PCM_IOCTL_CHANNEL_INFO, &info) < 0) {
err = -errno;
close(fd);
return err;
}
if (info.subdevice != subdevice) {
close(fd);
goto __again;
}
}
return fd;
}
int snd_pcm_open_subdevice(snd_pcm_t **handle, int card, int device, int subdevice, int mode)
{
int fmode, ver, err;
snd_pcm_t *pcm;
snd_pcm_hw_t *hw;
snd_ctl_t *ctl;
int pfd = -1, cfd = -1;
if (!handle)
return -EFAULT;
*handle = NULL;
if (card < 0 || card >= SND_CARDS)
return -EINVAL;
if ((err = snd_ctl_open(&ctl, card)) < 0)
return err;
if (mode & SND_PCM_OPEN_PLAYBACK) {
fmode = O_RDWR;
if (mode & SND_PCM_NONBLOCK_PLAYBACK)
fmode |= O_NONBLOCK;
pfd = snd_pcm_hw_open_channel(card, device, SND_PCM_CHANNEL_PLAYBACK,
subdevice, fmode, ctl, &ver);
if (pfd < 0) {
snd_ctl_close(ctl);
return pfd;
}
}
if (mode & SND_PCM_OPEN_CAPTURE) {
fmode = O_RDWR;
if (mode & SND_PCM_NONBLOCK_CAPTURE)
fmode |= O_NONBLOCK;
cfd = snd_pcm_hw_open_channel(card, device, SND_PCM_CHANNEL_CAPTURE,
subdevice, fmode, ctl, &ver);
if (cfd < 0) {
if (pfd >= 0)
close(pfd);
snd_ctl_close(ctl);
return cfd;
}
}
snd_ctl_close(ctl);
if (pfd < 0 && cfd < 0)
return -EINVAL;
err = snd_pcm_abstract_open(handle, mode, SND_PCM_TYPE_HW, sizeof(snd_pcm_hw_t));
if (err < 0) {
if (pfd >= 0)
close(pfd);
if (cfd >= 0)
close(cfd);
return err;
}
pcm = *handle;
pcm->ops = &snd_pcm_hw_ops;
hw = (snd_pcm_hw_t*) &pcm->private;
hw->card = card;
hw->device = device;
hw->ver = ver;
hw->chan[SND_PCM_CHANNEL_PLAYBACK].fd = pfd;
hw->chan[SND_PCM_CHANNEL_CAPTURE].fd = cfd;
return 0;
}
int snd_pcm_open(snd_pcm_t **handle, int card, int device, int mode)
{
return snd_pcm_open_subdevice(handle, card, device, -1, mode);
}

View file

@ -22,60 +22,133 @@
#include <pthread.h>
#include "asoundlib.h"
struct snd_pcm_plug {
struct snd_pcm_ops {
int (*channel_close)(snd_pcm_t *pcm, int channel);
int (*channel_nonblock)(snd_pcm_t *pcm, int channel, int nonblock);
int (*info)(snd_pcm_t *pcm, snd_pcm_info_t *info);
int (*channel_info)(snd_pcm_t *pcm, snd_pcm_channel_info_t *info);
int (*channel_params)(snd_pcm_t *pcm, snd_pcm_channel_params_t *params);
int (*channel_setup)(snd_pcm_t *pcm, snd_pcm_channel_setup_t *setup);
int (*voice_setup)(snd_pcm_t *pcm, int channel, snd_pcm_voice_setup_t *setup);
int (*channel_status)(snd_pcm_t *pcm, snd_pcm_channel_status_t *status);
int (*channel_prepare)(snd_pcm_t *pcm, int channel);
int (*channel_go)(snd_pcm_t *pcm, int channel);
int (*sync_go)(snd_pcm_t *pcm, snd_pcm_sync_t *sync);
int (*channel_drain)(snd_pcm_t *pcm, int channel);
int (*channel_flush)(snd_pcm_t *pcm, int channel);
int (*channel_pause)(snd_pcm_t *pcm, int channel, int enable);
ssize_t (*write)(snd_pcm_t *pcm, const void *buffer, size_t size);
ssize_t (*writev)(snd_pcm_t *pcm, const struct iovec *vector, unsigned long count);
ssize_t (*read)(snd_pcm_t *pcm, void *buffer, size_t size);
ssize_t (*readv)(snd_pcm_t *pcm, const struct iovec *vector, unsigned long count);
int (*mmap_control)(snd_pcm_t *pcm, int channel, snd_pcm_mmap_control_t **control, size_t csize);
int (*mmap_data)(snd_pcm_t *pcm, int channel, void **buffer, size_t bsize);
int (*munmap_control)(snd_pcm_t *pcm, int channel, snd_pcm_mmap_control_t *control, size_t csize);
int (*munmap_data)(snd_pcm_t *pcm, int channel, void *buffer, size_t bsize);
int (*file_descriptor)(snd_pcm_t* pcm, int channel);
int (*voices_mask)(snd_pcm_t *pcm, int channel, bitset_t *client_vmask);
};
struct snd_pcm_plug_chan {
snd_pcm_plugin_t *first;
snd_pcm_plugin_t *last;
void *alloc_ptr[2];
long alloc_size[2];
size_t alloc_size[2];
int alloc_lock[2];
snd_pcm_mmap_control_t *mmap_control;
char *mmap_data;
long mmap_size;
pthread_t thread;
int thread_stop;
int setup_is_valid;
snd_pcm_channel_setup_t setup;
int hwstatus;
};
struct snd_pcm_chan {
typedef struct snd_pcm_plug {
int close_slave;
snd_pcm_t *slave;
struct snd_pcm_plug_chan chan[2];
} snd_pcm_plug_t;
struct snd_pcm_hw_chan {
int fd;
int setup_is_valid;
};
typedef struct snd_pcm_hw {
int card;
int device;
int ver;
struct snd_pcm_hw_chan chan[2];
} snd_pcm_hw_t;
struct snd_pcm_chan {
int open;
int mode;
int valid_setup;
snd_pcm_channel_setup_t setup;
int valid_voices_setup;
snd_pcm_voice_setup_t *voices_setup;
snd_pcm_mmap_control_t *mmap_control;
size_t mmap_control_size;
int mmap_control_emulation;
char *mmap_data;
long mmap_size;
struct snd_pcm_plug plug;
size_t mmap_data_size;
int mmap_data_emulation;
pthread_t mmap_thread;
int mmap_thread_stop;
pthread_mutex_t mutex;
pthread_cond_t status_cond;
pthread_cond_t ready_cond;
};
struct snd_pcm {
int card;
int device;
snd_pcm_type_t type;
int mode;
int ver;
struct snd_pcm_ops *ops;
struct snd_pcm_chan chan[2];
int private[0];
};
unsigned int snd_pcm_plugin_formats(unsigned int formats);
int snd_pcm_plugin_hwparams(snd_pcm_channel_params_t *params,
snd_pcm_channel_info_t *hwinfo,
snd_pcm_channel_params_t *hwparams);
int snd_pcm_plugin_format(snd_pcm_t *pcm,
snd_pcm_channel_params_t *params,
snd_pcm_channel_params_t *hwparams,
snd_pcm_channel_info_t *hwinfo);
void snd_pcm_mmap_status_change(snd_pcm_t *pcm, int channel, int newstatus);
int snd_pcm_abstract_open(snd_pcm_t **handle, int mode, snd_pcm_type_t type, size_t extra);
unsigned int snd_pcm_plug_formats(unsigned int formats);
int snd_pcm_plug_slave_params(snd_pcm_channel_params_t *params,
snd_pcm_channel_info_t *slave_info,
snd_pcm_channel_params_t *slave_params);
int snd_pcm_plug_format(snd_pcm_plugin_handle_t *pcm,
snd_pcm_channel_params_t *params,
snd_pcm_channel_params_t *slave_params);
ssize_t snd_pcm_plug_write_transfer(snd_pcm_plugin_handle_t *handle, snd_pcm_plugin_voice_t *src_voices, size_t size);
ssize_t snd_pcm_plug_read_transfer(snd_pcm_plugin_handle_t *handle, snd_pcm_plugin_voice_t *dst_voices_final, size_t size);
ssize_t snd_pcm_plug_client_voices_iovec(snd_pcm_plugin_handle_t *handle, int channel,
const struct iovec *vector, unsigned long count,
snd_pcm_plugin_voice_t **voices);
ssize_t snd_pcm_plug_client_voices_buf(snd_pcm_plugin_handle_t *handle, int channel,
char *buf, size_t count,
snd_pcm_plugin_voice_t **voices);
int snd_pcm_plug_playback_voices_mask(snd_pcm_plugin_handle_t *handle,
bitset_t *client_vmask);
int snd_pcm_plug_capture_voices_mask(snd_pcm_plugin_handle_t *handle,
bitset_t *client_vmask);
int snd_pcm_plugin_client_voices(snd_pcm_plugin_t *plugin,
size_t samples,
snd_pcm_plugin_voice_t **voices);
void *snd_pcm_plug_buf_alloc(snd_pcm_t *pcm, int channel, size_t size);
void snd_pcm_plug_buf_unlock(snd_pcm_t *pcm, int channel, void *ptr);
#define ROUTE_PLUGIN_RESOLUTION 16
int getput_index(int format);
int copy_index(int src_format, int dst_format);
int copy_index(int format);
int conv_index(int src_format, int dst_format);
void zero_voice(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *dst_voice,
size_t samples);
void snd_pcm_plugin_silence_voice(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *dst_voice,
size_t samples);
#ifdef PLUGIN_DEBUG
#define pdprintf( args... ) printf( "plugin: " ##args)
#define pdprintf( args... ) fprintf(stderr, "plugin: " ##args)
#else
#define pdprintf( args... ) { ; }
#endif

View file

@ -1,239 +0,0 @@
/*
* PCM LoopBack Interface - main file
* 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.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include "asoundlib.h"
#define SND_FILE_PCM_LB "/proc/asound/%i/pcmloopD%iS%i%s"
#define SND_PCM_LB_VERSION_MAX SND_PROTOCOL_VERSION(1, 0, 0)
struct snd_pcm_loopback {
int card;
int device;
int fd;
long mode;
size_t buffer_size;
char *buffer;
};
int snd_pcm_loopback_open(snd_pcm_loopback_t **handle, int card, int device, int subchn, int mode)
{
int fd, ver;
char filename[32];
snd_pcm_loopback_t *lb;
*handle = NULL;
if (card < 0 || card >= SND_CARDS)
return -EINVAL;
sprintf(filename, SND_FILE_PCM_LB, card, device, subchn,
mode == SND_PCM_LB_OPEN_CAPTURE ? "c" : "p");
if ((fd = open(filename, mode)) < 0) {
snd_card_load(card);
if ((fd = open(filename, mode)) < 0)
return -errno;
}
if (ioctl(fd, SND_PCM_LB_IOCTL_PVERSION, &ver) < 0) {
close(fd);
return -errno;
}
if (SND_PROTOCOL_INCOMPATIBLE(ver, SND_PCM_LB_VERSION_MAX)) {
close(fd);
return -SND_ERROR_INCOMPATIBLE_VERSION;
}
lb = (snd_pcm_loopback_t *) calloc(1, sizeof(snd_pcm_loopback_t));
if (lb == NULL) {
close(fd);
return -ENOMEM;
}
lb->card = card;
lb->device = device;
lb->fd = fd;
lb->mode = SND_PCM_LB_STREAM_MODE_RAW;
*handle = lb;
return 0;
}
int snd_pcm_loopback_close(snd_pcm_loopback_t *lb)
{
int res;
if (!lb)
return -EINVAL;
if (lb->buffer)
free(lb->buffer);
res = close(lb->fd) < 0 ? -errno : 0;
free(lb);
return res;
}
int snd_pcm_loopback_file_descriptor(snd_pcm_loopback_t *lb)
{
if (!lb)
return -EINVAL;
return lb->fd;
}
int snd_pcm_loopback_block_mode(snd_pcm_loopback_t *lb, int enable)
{
long flags;
if (!lb)
return -EINVAL;
if ((flags = fcntl(lb->fd, F_GETFL)) < 0)
return -errno;
if (enable)
flags &= ~O_NONBLOCK;
else
flags |= O_NONBLOCK;
if (fcntl(lb->fd, F_SETFL, flags) < 0)
return -errno;
return 0;
}
int snd_pcm_loopback_stream_mode(snd_pcm_loopback_t *lb, int mode)
{
if (!lb || (mode != SND_PCM_LB_STREAM_MODE_RAW &&
mode != SND_PCM_LB_STREAM_MODE_PACKET))
return -EINVAL;
lb->mode = mode;
if (ioctl(lb->fd, SND_PCM_LB_IOCTL_STREAM_MODE, &lb->mode) < 0)
return -errno;
return 0;
}
int snd_pcm_loopback_format(snd_pcm_loopback_t *lb, snd_pcm_format_t * format)
{
if (!lb)
return -EINVAL;
if (ioctl(lb->fd, SND_PCM_LB_IOCTL_FORMAT, format) < 0)
return -errno;
return 0;
}
int snd_pcm_loopback_status(snd_pcm_loopback_t *lb, snd_pcm_loopback_status_t * status)
{
if (!lb)
return -EINVAL;
if (ioctl(lb->fd, SND_PCM_LB_IOCTL_FORMAT, status) < 0)
return -errno;
return 0;
}
ssize_t snd_pcm_loopback_read(snd_pcm_loopback_t *lb, snd_pcm_loopback_callbacks_t *callbacks)
{
ssize_t result = 0, res, count;
size_t size;
char *buf;
snd_pcm_loopback_header_t header;
if (!lb || !callbacks)
return -EINVAL;
if (callbacks->max_buffer_size == 0)
size = 64 * 1024;
else
size = callbacks->max_buffer_size < 16 ? 16 : callbacks->max_buffer_size;
while (1) {
if (lb->mode == SND_PCM_LB_STREAM_MODE_RAW) {
header.size = size;
header.type = SND_PCM_LB_TYPE_DATA;
} else {
res = read(lb->fd, &header, sizeof(header));
if (res < 0)
return -errno;
if (res == 0)
break;
if (res != sizeof(header))
return -EBADFD;
result += res;
}
switch (header.type) {
case SND_PCM_LB_TYPE_DATA:
if (lb->buffer_size < size) {
buf = (char *) realloc(lb->buffer, size);
if (buf == NULL)
return -ENOMEM;
lb->buffer = buf;
lb->buffer_size = size;
} else {
buf = lb->buffer;
}
while (header.size > 0) {
count = header.size;
if (count > size)
count = size;
res = read(lb->fd, buf, count);
if (res < 0)
return -errno;
result += res;
if (lb->mode == SND_PCM_LB_STREAM_MODE_PACKET && res != count)
return -EBADFD;
if (res == 0)
break;
if (callbacks->data)
callbacks->data(callbacks->private_data, buf, res);
if (res < count && lb->mode == SND_PCM_LB_STREAM_MODE_RAW)
break;
header.size -= res;
}
break;
case SND_PCM_LB_TYPE_FORMAT:
{
snd_pcm_format_t format;
res = read(lb->fd, &format, sizeof(format));
if (res < 0)
return -errno;
result += res;
if (res != sizeof(format))
return -EBADFD;
if (callbacks->format_change)
callbacks->format_change(callbacks->private_data, &format);
}
break;
case SND_PCM_LB_TYPE_POSITION:
{
unsigned int pos;
res = read(lb->fd, &pos, sizeof(pos));
if (res < 0)
return -errno;
result += res;
if (res != sizeof(pos))
return -EBADFD;
if (callbacks->position_change)
callbacks->position_change(callbacks->private_data, pos);
}
break;
case SND_PCM_LB_TYPE_SILENCE:
if (callbacks->silence)
callbacks->silence(callbacks->private_data, header.size);
break;
}
}
return result;
}

View file

@ -21,11 +21,14 @@
#ifdef __KERNEL__
#include "../include/driver.h"
#include "../include/pcm.h"
#include "../include/pcm_plugin.h"
#else
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <byteswap.h>
#include <errno.h>
#include <endian.h>
#include <byteswap.h>
@ -187,10 +190,6 @@ int snd_pcm_format_physical_width(int format)
ssize_t snd_pcm_format_size(int format, size_t samples)
{
if (samples < 0)
return -EINVAL;
if (samples == 0)
return samples;
switch (format) {
case SND_PCM_SFMT_S8:
case SND_PCM_SFMT_U8:
@ -229,6 +228,11 @@ ssize_t snd_pcm_format_size(int format, size_t samples)
}
}
ssize_t snd_pcm_format_bytes_per_second(snd_pcm_format_t *format)
{
return snd_pcm_format_size(format->format, format->voices * format->rate);
}
const char *snd_pcm_get_format_name(int format)
{
static char *formats[] = {
@ -265,23 +269,9 @@ const char *snd_pcm_get_format_name(int format)
return formats[format];
}
unsigned char snd_pcm_format_silence(int format)
u_int64_t snd_pcm_format_silence_64(int format)
{
switch (format) {
case SND_PCM_SFMT_IMA_ADPCM: /* special case */
case SND_PCM_SFMT_MPEG:
case SND_PCM_SFMT_GSM:
case SND_PCM_SFMT_MU_LAW:
case SND_PCM_SFMT_A_LAW:
return 0;
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:
return 0x80;
case SND_PCM_SFMT_S8:
case SND_PCM_SFMT_S16_LE:
case SND_PCM_SFMT_S16_BE:
@ -290,15 +280,135 @@ unsigned char snd_pcm_format_silence(int format)
case SND_PCM_SFMT_S32_LE:
case SND_PCM_SFMT_S32_BE:
return 0;
case SND_PCM_SFMT_FLOAT:
case SND_PCM_SFMT_FLOAT64:
case SND_PCM_SFMT_U8:
return 0x8080808080808080UL;
case SND_PCM_SFMT_U16_LE:
case SND_PCM_SFMT_U24_LE:
case SND_PCM_SFMT_U32_LE:
#if defined(LITTLE_ENDIAN)
return 0x8000800080008000UL;
#elif defined(BIG_ENDIAN)
return 0x0080008000800080UL;
#else
#error "endian"
#endif
case SND_PCM_SFMT_U16_BE:
case SND_PCM_SFMT_U24_BE:
case SND_PCM_SFMT_U32_BE:
#if defined(LITTLE_ENDIAN)
return 0x0000008000000080UL;
#elif defined(BIG_ENDIAN)
return 0x8000000080000000UL;
#else
#error "endian"
#endif
case SND_PCM_SFMT_FLOAT_LE:
#if defined(LITTLE_ENDIAN)
return (float)0.0;
#elif defined(BIG_ENDIAN)
return bswap_32((u_int32_t)((float)0.0));
#else
#error "endian"
#endif
case SND_PCM_SFMT_FLOAT64_LE:
#if defined(LITTLE_ENDIAN)
return (double)0.0;
#elif defined(BIG_ENDIAN)
return bswap_64((u_int64_t)((double)0.0));
#else
#error "endian"
#endif
case SND_PCM_SFMT_FLOAT_BE:
#if defined(LITTLE_ENDIAN)
return bswap_32((u_int32_t)((float)0.0));
#elif defined(BIG_ENDIAN)
return (float)0.0;
#else
#error "endian"
#endif
case SND_PCM_SFMT_FLOAT64_BE:
#if defined(LITTLE_ENDIAN)
return bswap_64((u_int64_t)((double)0.0));
#elif defined(BIG_ENDIAN)
return (double)0.0;
#else
#error "endian"
#endif
case SND_PCM_SFMT_IEC958_SUBFRAME_LE:
case SND_PCM_SFMT_IEC958_SUBFRAME_BE:
return 0;
case SND_PCM_SFMT_MU_LAW:
return 0x7f7f7f7f7f7f7f7fUL;
case SND_PCM_SFMT_A_LAW:
return 0x5555555555555555UL;
case SND_PCM_SFMT_IMA_ADPCM: /* special case */
case SND_PCM_SFMT_MPEG:
case SND_PCM_SFMT_GSM:
return 0;
}
return 0;
}
u_int32_t snd_pcm_format_silence_32(int format)
{
return (u_int32_t)snd_pcm_format_silence_64(format);
}
u_int16_t snd_pcm_format_silence_16(int format)
{
return (u_int16_t)snd_pcm_format_silence_64(format);
}
u_int8_t snd_pcm_format_silence(int format)
{
return (u_int8_t)snd_pcm_format_silence_64(format);
}
ssize_t snd_pcm_format_set_silence(int format, void *data, size_t count)
{
size_t count1;
if (count == 0)
return 0;
switch (snd_pcm_format_width(format)) {
case 4:
case 8: {
u_int8_t silence = snd_pcm_format_silence_64(format);
memset(data, silence, count);
break;
}
case 16: {
u_int16_t silence = snd_pcm_format_silence_64(format);
if (count % 2)
return -EINVAL;
count1 = count / 2;
while (count1-- > 0)
*((u_int16_t *)data)++ = silence;
break;
}
case 32: {
u_int32_t silence = snd_pcm_format_silence_64(format);
if (count % 4)
return -EINVAL;
count1 = count / 4;
while (count1-- > 0)
*((u_int32_t *)data)++ = silence;
break;
}
case 64: {
u_int64_t silence = snd_pcm_format_silence_64(format);
if (count % 8)
return -EINVAL;
count1 = count / 8;
while (count1-- > 0)
*((u_int64_t *)data)++ = silence;
}
default:
return -EINVAL;
}
return count;
}
static int linear_formats[4*2*2] = {
SND_PCM_SFMT_S8,
SND_PCM_SFMT_U8,

1139
src/pcm/pcm_mmap.c Normal file

File diff suppressed because it is too large Load diff

824
src/pcm/pcm_plug.c Normal file
View file

@ -0,0 +1,824 @@
/*
* PCM - Plug
* 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 <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <math.h>
#include <sys/uio.h>
#include "pcm_local.h"
/* snd_pcm_plug helpers */
void *snd_pcm_plug_buf_alloc(snd_pcm_t *pcm, int channel, size_t size)
{
int idx;
snd_pcm_plug_t *plug = (snd_pcm_plug_t*) &pcm->private;
struct snd_pcm_plug_chan *plugchan = &plug->chan[channel];
for (idx = 0; idx < 2; idx++) {
if (plugchan->alloc_lock[idx])
continue;
if (plugchan->alloc_size[idx] >= size) {
plugchan->alloc_lock[idx] = 1;
return plugchan->alloc_ptr[idx];
}
}
for (idx = 0; idx < 2; idx++) {
if (plugchan->alloc_lock[idx])
continue;
if (plugchan->alloc_ptr[idx] != NULL)
free(plugchan->alloc_ptr[idx]);
plugchan->alloc_ptr[idx] = malloc(size);
if (plugchan->alloc_ptr[idx] == NULL)
return NULL;
plugchan->alloc_size[idx] = size;
plugchan->alloc_lock[idx] = 1;
return plugchan->alloc_ptr[idx];
}
return NULL;
}
void snd_pcm_plug_buf_unlock(snd_pcm_t *pcm, int channel, void *ptr)
{
int idx;
snd_pcm_plug_t *plug;
struct snd_pcm_plug_chan *plugchan;
if (!ptr)
return;
plug = (snd_pcm_plug_t*) &pcm->private;
plugchan = &plug->chan[channel];
for (idx = 0; idx < 2; idx++) {
if (plugchan->alloc_ptr[idx] == ptr) {
plugchan->alloc_lock[idx] = 0;
return;
}
}
}
/* snd_pcm_plugin externs */
int snd_pcm_plugin_insert(snd_pcm_plugin_t *plugin)
{
snd_pcm_plug_t *plug;
struct snd_pcm_plug_chan *plugchan;
snd_pcm_t *pcm;
if (!plugin)
return -EFAULT;
pcm = plugin->handle;
plug = (snd_pcm_plug_t*) &pcm->private;
plugchan = &plug->chan[plugin->channel];
plugin->next = plugchan->first;
plugin->prev = NULL;
if (plugchan->first) {
plugchan->first->prev = plugin;
plugchan->first = plugin;
} else {
plugchan->last =
plugchan->first = plugin;
}
return 0;
}
int snd_pcm_plugin_append(snd_pcm_plugin_t *plugin)
{
snd_pcm_plug_t *plug;
struct snd_pcm_plug_chan *plugchan;
snd_pcm_t *pcm;
if (!plugin)
return -EFAULT;
pcm = plugin->handle;
plug = (snd_pcm_plug_t*) &pcm->private;
plugchan = &plug->chan[plugin->channel];
plugin->next = NULL;
plugin->prev = plugchan->last;
if (plugchan->last) {
plugchan->last->next = plugin;
plugchan->last = plugin;
} else {
plugchan->last =
plugchan->first = plugin;
}
return 0;
}
#if 0
int snd_pcm_plugin_remove_to(snd_pcm_plugin_t *plugin)
{
snd_pcm_plugin_t *plugin1, *plugin1_prev;
snd_pcm_plug_t *plug;
snd_pcm_t *pcm;
struct snd_pcm_plug_chan *plugchan;
if (!plugin)
return -EFAULT;
pcm = plugin->handle;
plug = (snd_pcm_plug_t*) &pcm->private;
plugchan = &plug->chan[plugin->channel];
plugin1 = plugin;
while (plugin1->prev)
plugin1 = plugin1->prev;
if (plugchan->first != plugin1)
return -EINVAL;
plugchan->first = plugin;
plugin1 = plugin->prev;
plugin->prev = NULL;
while (plugin1) {
plugin1_prev = plugin1->prev;
snd_pcm_plugin_free(plugin1);
plugin1 = plugin1_prev;
}
return 0;
}
int snd_pcm_plug_remove_first(snd_pcm_t *pcm, int channel)
{
snd_pcm_plugin_t *plugin;
snd_pcm_plug_t *plug;
struct snd_pcm_plug_chan *plugchan;
if (!pcm)
return -EFAULT;
if (channel < 0 || channel > 1)
return -EINVAL;
if (!pcm->chan[channel].open)
return -EBADFD;
plug = (snd_pcm_plug_t*) &pcm->private;
plugchan = &plug->chan[channel];
plugin = plugchan->first;
if (plugin->next) {
plugin = plugin->next;
} else {
return snd_pcm_plug_clear(pcm, channel);
}
return snd_pcm_plugin_remove_to(plugin);
}
#endif
/* snd_pcm_plug externs */
int snd_pcm_plug_clear(snd_pcm_t *pcm, int channel)
{
snd_pcm_plugin_t *plugin, *plugin_next;
snd_pcm_plug_t *plug;
struct snd_pcm_plug_chan *plugchan;
int idx;
if (!pcm)
return -EINVAL;
if (channel < 0 || channel > 1)
return -EINVAL;
if (!pcm->chan[channel].open)
return -EBADFD;
plug = (snd_pcm_plug_t*) &pcm->private;
plugchan = &plug->chan[channel];
plugin = plugchan->first;
plugchan->first = NULL;
plugchan->last = NULL;
while (plugin) {
plugin_next = plugin->next;
snd_pcm_plugin_free(plugin);
plugin = plugin_next;
}
for (idx = 0; idx < 2; idx++) {
if (plugchan->alloc_ptr[idx]) {
free(plugchan->alloc_ptr[idx]);
plugchan->alloc_ptr[idx] = 0;
}
plugchan->alloc_size[idx] = 0;
plugchan->alloc_lock[idx] = 0;
}
return 0;
}
snd_pcm_plugin_t *snd_pcm_plug_first(snd_pcm_t *pcm, int channel)
{
snd_pcm_plug_t *plug;
struct snd_pcm_plug_chan *plugchan;
if (!pcm)
return NULL;
if (channel < 0 || channel > 1)
return NULL;
if (!pcm->chan[channel].open)
return NULL;
plug = (snd_pcm_plug_t*) &pcm->private;
plugchan = &plug->chan[channel];
return plugchan->first;
}
snd_pcm_plugin_t *snd_pcm_plug_last(snd_pcm_t *pcm, int channel)
{
snd_pcm_plug_t *plug;
struct snd_pcm_plug_chan *plugchan;
if (!pcm)
return NULL;
if (channel < 0 || channel > 1)
return NULL;
if (!pcm->chan[channel].open)
return NULL;
plug = (snd_pcm_plug_t*) &pcm->private;
plugchan = &plug->chan[channel];
return plugchan->last;
}
int snd_pcm_plug_direct(snd_pcm_t *pcm, int channel)
{
return snd_pcm_plug_first(pcm, channel) == NULL;
}
#if 0
double snd_pcm_plug_client_ratio(snd_pcm_t *pcm, int channel)
{
ssize_t client;
if (!pcm)
return -EFAULT;
if (channel < 0 || channel > 1)
return -EINVAL;
if (!pcm->chan[channel].open)
return -EBADFD;
client = snd_pcm_plug_client_size(pcm, channel, 1000000);
if (client < 0)
return 0;
return (double)client / (double)1000000;
}
double snd_pcm_plug_slave_ratio(snd_pcm_t *pcm, int channel)
{
ssize_t slave;
if (!pcm)
return -EFAULT;
if (channel < 0 || channel > 1)
return -EINVAL;
if (!pcm->chan[channel].open)
return -EBADFD;
slave = snd_pcm_plug_slave_size(pcm, channel, 1000000);
if (slave < 0)
return 0;
return (double)slave / (double)1000000;
}
#endif
/*
*
*/
static int snd_pcm_plug_channel_close(snd_pcm_t *pcm, int channel)
{
snd_pcm_plug_t *plug = (snd_pcm_plug_t*) &pcm->private;
snd_pcm_plug_clear(pcm, channel);
if (plug->close_slave)
return snd_pcm_channel_close(plug->slave, channel);
return 0;
}
static int snd_pcm_plug_channel_nonblock(snd_pcm_t *pcm, int channel, int nonblock)
{
snd_pcm_plug_t *plug = (snd_pcm_plug_t*) &pcm->private;
return snd_pcm_channel_nonblock(plug->slave, channel, nonblock);
}
static int snd_pcm_plug_info(snd_pcm_t *pcm, snd_pcm_info_t * info)
{
snd_pcm_plug_t *plug = (snd_pcm_plug_t*) &pcm->private;
return snd_pcm_info(plug->slave, info);
}
static int snd_pcm_plug_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info)
{
int err;
snd_pcm_plug_t *plug = (snd_pcm_plug_t*) &pcm->private;
struct snd_pcm_chan *chan;
if ((err = snd_pcm_channel_info(plug->slave, info)) < 0)
return err;
info->formats = snd_pcm_plug_formats(info->formats);
info->min_rate = 4000;
info->max_rate = 192000;
info->min_voices = 1;
info->max_voices = 32;
info->rates = SND_PCM_RATE_CONTINUOUS | SND_PCM_RATE_8000_192000;
info->flags |= SND_PCM_CHNINFO_INTERLEAVE | SND_PCM_CHNINFO_NONINTERLEAVE;
chan = &pcm->chan[info->channel];
if (pcm->chan[info->channel].valid_setup) {
info->buffer_size = snd_pcm_plug_client_size(pcm, info->channel, info->buffer_size);
info->min_fragment_size = snd_pcm_plug_client_size(pcm, info->channel, info->min_fragment_size);
info->max_fragment_size = snd_pcm_plug_client_size(pcm, info->channel, info->max_fragment_size);
info->fragment_align = snd_pcm_plug_client_size(pcm, info->channel, info->fragment_align);
info->fifo_size = snd_pcm_plug_client_size(pcm, info->channel, info->fifo_size);
info->transfer_block_size = snd_pcm_plug_client_size(pcm, info->channel, info->transfer_block_size);
if (chan->setup.mode == SND_PCM_MODE_BLOCK)
info->mmap_size = chan->setup.buffer_size;
else
info->mmap_size = snd_pcm_plug_client_size(pcm, info->channel, info->mmap_size);
}
if (!snd_pcm_plug_direct(pcm, info->channel))
info->flags &= ~(SND_PCM_CHNINFO_MMAP | SND_PCM_CHNINFO_MMAP_VALID);
return 0;
}
static int snd_pcm_plug_action(snd_pcm_t *pcm, int channel, int action,
unsigned long data)
{
snd_pcm_plugin_t *plugin;
int err;
snd_pcm_plug_t *plug;
struct snd_pcm_plug_chan *plugchan;
plug = (snd_pcm_plug_t*) &pcm->private;
plugchan = &plug->chan[channel];
plugin = plugchan->first;
while (plugin) {
if (plugin->action) {
if ((err = plugin->action(plugin, action, data))<0)
return err;
}
plugin = plugin->next;
}
return 0;
}
static int snd_pcm_plug_channel_params(snd_pcm_t *pcm, snd_pcm_channel_params_t *params)
{
snd_pcm_channel_params_t slave_params, params1;
snd_pcm_channel_info_t slave_info;
snd_pcm_plugin_t *plugin;
snd_pcm_plug_t *plug;
int err;
int channel = params->channel;
plug = (snd_pcm_plug_t*) &pcm->private;
/*
* try to decide, if a conversion is required
*/
memset(&slave_info, 0, sizeof(slave_info));
slave_info.channel = channel;
if ((err = snd_pcm_channel_info(plug->slave, &slave_info)) < 0) {
snd_pcm_plug_clear(pcm, channel);
return err;
}
if ((err = snd_pcm_plug_slave_params(params, &slave_info, &slave_params)) < 0)
return err;
snd_pcm_plug_clear(pcm, channel);
/* add necessary plugins */
memcpy(&params1, params, sizeof(*params));
if ((err = snd_pcm_plug_format(pcm, &params1, &slave_params)) < 0)
return err;
if (snd_pcm_plug_direct(pcm, channel))
return snd_pcm_channel_params(plug->slave, params);
/*
* I/O plugins
*/
if (params->mode == SND_PCM_MODE_STREAM) {
pdprintf("params stream plugin\n");
err = snd_pcm_plugin_build_stream(pcm, channel, plug->slave, &slave_params.format, &plugin);
} else if (params->mode == SND_PCM_MODE_BLOCK) {
if (slave_info.flags & SND_PCM_CHNINFO_MMAP) {
pdprintf("params mmap plugin\n");
err = snd_pcm_plugin_build_mmap(pcm, channel, plug->slave, &slave_params.format, &plugin);
} else {
pdprintf("params block plugin\n");
err = snd_pcm_plugin_build_block(pcm, channel, plug->slave, &slave_params.format, &plugin);
}
} else {
return -EINVAL;
}
if (err < 0)
return err;
if (channel == SND_PCM_CHANNEL_PLAYBACK) {
err = snd_pcm_plugin_append(plugin);
} else {
err = snd_pcm_plugin_insert(plugin);
}
if (err < 0) {
snd_pcm_plugin_free(plugin);
return err;
}
/* compute right sizes */
slave_params.frag_size = snd_pcm_plug_slave_size(pcm, channel, slave_params.frag_size);
if (params->mode == SND_PCM_MODE_STREAM) {
slave_params.buf.stream.bytes_fill_max = snd_pcm_plug_slave_size(pcm, channel, slave_params.buf.stream.bytes_fill_max);
slave_params.buf.stream.bytes_min = snd_pcm_plug_slave_size(pcm, channel, slave_params.buf.stream.bytes_min);
slave_params.buf.stream.bytes_xrun_max = snd_pcm_plug_slave_size(pcm, channel, slave_params.buf.stream.bytes_xrun_max);
slave_params.buf.stream.bytes_align = snd_pcm_plug_slave_size(pcm, channel, slave_params.buf.stream.bytes_align);
} else if (params->mode != SND_PCM_MODE_BLOCK)
return -EINVAL;
pdprintf("params requested params: format = %i, rate = %i, voices = %i\n", slave_params.format.format, slave_params.format.rate, slave_params.format.voices);
err = snd_pcm_channel_params(plug->slave, &slave_params);
if (err < 0)
return err;
err = snd_pcm_plug_action(pcm, channel, INIT, 0);
if (err < 0)
return err;
return 0;
}
static int snd_pcm_plug_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t *setup)
{
int err;
snd_pcm_plug_t *plug = (snd_pcm_plug_t*) &pcm->private;
struct snd_pcm_plug_chan *plugchan;
err = snd_pcm_channel_setup(plug->slave, setup);
if (err < 0)
return err;
if (snd_pcm_plug_direct(pcm, setup->channel))
return 0;
setup->buffer_size = snd_pcm_plug_client_size(pcm, setup->channel, setup->buffer_size);
setup->frag_size = snd_pcm_plug_client_size(pcm, setup->channel, setup->frag_size);
/* FIXME: it may overflow */
setup->pos_boundary = snd_pcm_plug_client_size(pcm, setup->channel, setup->pos_boundary);
if (setup->mode == SND_PCM_MODE_STREAM) {
setup->buf.stream.bytes_min = snd_pcm_plug_client_size(pcm, setup->channel, setup->buf.stream.bytes_min);
setup->buf.stream.bytes_align = snd_pcm_plug_client_size(pcm, setup->channel, setup->buf.stream.bytes_align);
setup->buf.stream.bytes_xrun_max = snd_pcm_plug_client_size(pcm, setup->channel, setup->buf.stream.bytes_xrun_max);
} else if (setup->mode != SND_PCM_MODE_BLOCK) {
return -EINVAL;
}
plugchan = &plug->chan[setup->channel];
if (setup->channel == SND_PCM_CHANNEL_PLAYBACK)
setup->format = plugchan->first->src_format;
else
setup->format = plugchan->last->dst_format;
return 0;
}
static int snd_pcm_plug_channel_status(snd_pcm_t *pcm, snd_pcm_channel_status_t *status)
{
int err;
snd_pcm_plug_t *plug = (snd_pcm_plug_t*) &pcm->private;
err = snd_pcm_channel_status(plug->slave, status);
if (err < 0)
return err;
if (snd_pcm_plug_direct(pcm, status->channel))
return 0;
/* FIXME: may overflow */
status->pos_io = snd_pcm_plug_client_size(pcm, status->channel, status->pos_io);
status->pos_data = snd_pcm_plug_client_size(pcm, status->channel, status->pos_data);
status->bytes_used = snd_pcm_plug_client_size(pcm, status->channel, status->bytes_used);
status->bytes_free = snd_pcm_plug_client_size(pcm, status->channel, status->bytes_free);
return 0;
}
static int snd_pcm_plug_channel_prepare(snd_pcm_t *pcm, int channel)
{
snd_pcm_plug_t *plug = (snd_pcm_plug_t*) &pcm->private;
int err;
err = snd_pcm_channel_prepare(plug->slave, channel);
if (err < 0)
return err;
if (snd_pcm_plug_direct(pcm, channel))
return 0;
if ((err = snd_pcm_plug_action(pcm, channel, PREPARE, 0))<0)
return err;
return 0;
}
static int snd_pcm_plug_channel_go(snd_pcm_t *pcm, int channel)
{
snd_pcm_plug_t *plug = (snd_pcm_plug_t*) &pcm->private;
return snd_pcm_channel_go(plug->slave, channel);
}
static int snd_pcm_plug_sync_go(snd_pcm_t *pcm, snd_pcm_sync_t *sync)
{
snd_pcm_plug_t *plug = (snd_pcm_plug_t*) &pcm->private;
return snd_pcm_sync_go(plug->slave, sync);
}
static int snd_pcm_plug_channel_drain(snd_pcm_t *pcm, int channel)
{
snd_pcm_plug_t *plug = (snd_pcm_plug_t*) &pcm->private;
int err;
if ((err = snd_pcm_channel_drain(plug->slave, channel)) < 0)
return err;
if (snd_pcm_plug_direct(pcm, channel))
return 0;
if ((err = snd_pcm_plug_action(pcm, channel, DRAIN, 0))<0)
return err;
return 0;
}
static int snd_pcm_plug_channel_flush(snd_pcm_t *pcm, int channel)
{
snd_pcm_plug_t *plug = (snd_pcm_plug_t*) &pcm->private;
int err;
if ((err = snd_pcm_channel_flush(plug->slave, channel)) < 0)
return err;
if (snd_pcm_plug_direct(pcm, channel))
return 0;
if ((err = snd_pcm_plug_action(pcm, channel, FLUSH, 0))<0)
return err;
return 0;
}
static int snd_pcm_plug_channel_pause(snd_pcm_t *pcm, int channel, int enable)
{
snd_pcm_plug_t *plug = (snd_pcm_plug_t*) &pcm->private;
int err;
if ((err = snd_pcm_channel_pause(plug->slave, channel, enable)) < 0)
return err;
if ((err = snd_pcm_plug_action(pcm, channel, PAUSE, 0))<0)
return err;
return 0;
}
static int snd_pcm_plug_voice_setup(snd_pcm_t *pcm, int channel, snd_pcm_voice_setup_t *setup)
{
snd_pcm_plug_t *plug = (snd_pcm_plug_t*) &pcm->private;
struct snd_pcm_chan *chan;
unsigned int voice;
int width;
size_t size;
if (snd_pcm_plug_direct(pcm, channel))
return snd_pcm_voice_setup(plug->slave, channel, setup);
voice = setup->voice;
memset(setup, 0, sizeof(*setup));
setup->voice = voice;
chan = &pcm->chan[channel];
if (!chan->mmap_control) {
setup->addr = -1;
return 0;
}
if (voice >= chan->setup.format.voices)
return -EINVAL;
width = snd_pcm_format_physical_width(chan->setup.format.format);
if (width < 0)
return width;
size = chan->mmap_data_size;
if (chan->setup.format.interleave) {
setup->addr = 0;
setup->first = voice * width;
setup->step = chan->setup.format.voices * width;
} else {
size /= chan->setup.format.voices;
setup->addr = setup->voice * size;
setup->first = 0;
setup->step = width;
}
return 0;
}
ssize_t snd_pcm_plug_writev(snd_pcm_t *pcm, const struct iovec *vector, unsigned long count)
{
snd_pcm_plug_t *plug = (snd_pcm_plug_t*) &pcm->private;
struct snd_pcm_chan *chan = &pcm->chan[SND_PCM_CHANNEL_PLAYBACK];
unsigned int k, step, voices;
int size = 0;
if (snd_pcm_plug_direct(pcm, SND_PCM_CHANNEL_PLAYBACK))
return snd_pcm_writev(plug->slave, vector, count);
voices = chan->setup.format.voices;
if (chan->setup.format.interleave)
step = 1;
else {
step = voices;
if (count % voices != 0)
return -EINVAL;
}
for (k = 0; k < count; k += step, vector += step) {
snd_pcm_plugin_voice_t *voices;
int expected, ret;
expected = snd_pcm_plug_client_voices_iovec(pcm, SND_PCM_CHANNEL_PLAYBACK, vector, count, &voices);
if (expected < 0)
return expected;
ret = snd_pcm_plug_write_transfer(pcm, voices, expected);
if (ret < 0) {
if (size > 0)
return size;
return ret;
}
size += ret;
if (ret != expected)
return size;
}
return size;
}
ssize_t snd_pcm_plug_readv(snd_pcm_t *pcm, const struct iovec *vector, unsigned long count)
{
snd_pcm_plug_t *plug = (snd_pcm_plug_t*) &pcm->private;
struct snd_pcm_chan *chan = &pcm->chan[SND_PCM_CHANNEL_CAPTURE];
unsigned int k, step, voices;
int size = 0;
if (snd_pcm_plug_direct(pcm, SND_PCM_CHANNEL_CAPTURE))
return snd_pcm_readv(plug->slave, vector, count);
voices = chan->setup.format.voices;
if (chan->setup.format.interleave)
step = 1;
else {
step = voices;
if (count % voices != 0)
return -EINVAL;
}
for (k = 0; k < count; k += step) {
snd_pcm_plugin_voice_t *voices;
int expected, ret;
expected = snd_pcm_plug_client_voices_iovec(pcm, SND_PCM_CHANNEL_CAPTURE, vector, count, &voices);
if (expected < 0)
return expected;
ret = snd_pcm_plug_read_transfer(pcm, voices, expected);
if (ret < 0) {
if (size > 0)
return size;
return ret;
}
size += ret;
if (ret != expected)
return size;
}
return size;
}
ssize_t snd_pcm_plug_write(snd_pcm_t *pcm, const void *buf, size_t count)
{
snd_pcm_plug_t *plug = (snd_pcm_plug_t*) &pcm->private;
int expected;
snd_pcm_plugin_voice_t *voices;
if (snd_pcm_plug_direct(pcm, SND_PCM_CHANNEL_PLAYBACK))
return snd_pcm_write(plug->slave, buf, count);
expected = snd_pcm_plug_client_voices_buf(pcm, SND_PCM_CHANNEL_PLAYBACK, (char *)buf, count, &voices);
if (expected < 0)
return expected;
return snd_pcm_plug_write_transfer(pcm, voices, expected);
}
ssize_t snd_pcm_plug_read(snd_pcm_t *pcm, void *buf, size_t count)
{
snd_pcm_plug_t *plug = (snd_pcm_plug_t*) &pcm->private;
int expected;
snd_pcm_plugin_voice_t *voices;
if (snd_pcm_plug_direct(pcm, SND_PCM_CHANNEL_CAPTURE))
return snd_pcm_read(plug->slave, buf, count);
expected = snd_pcm_plug_client_voices_buf(pcm, SND_PCM_CHANNEL_CAPTURE, buf, count, &voices);
if (expected < 0)
return expected;
return snd_pcm_plug_read_transfer(pcm, voices, expected);
}
static int snd_pcm_plug_mmap_control(snd_pcm_t *pcm, int channel, snd_pcm_mmap_control_t **control, size_t csize UNUSED)
{
snd_pcm_plug_t *plug = (snd_pcm_plug_t*) &pcm->private;
if (snd_pcm_plug_direct(pcm, channel))
return snd_pcm_mmap_control(plug->slave, channel, control);
return -EBADFD;
}
static int snd_pcm_plug_mmap_data(snd_pcm_t *pcm, int channel, void **buffer, size_t bsize UNUSED)
{
snd_pcm_plug_t *plug = (snd_pcm_plug_t*) &pcm->private;
if (snd_pcm_plug_direct(pcm, channel))
return snd_pcm_mmap_data(plug->slave, channel, buffer);
return -EBADFD;
}
static int snd_pcm_plug_munmap_control(snd_pcm_t *pcm, int channel, snd_pcm_mmap_control_t *control UNUSED, size_t csize UNUSED)
{
snd_pcm_plug_t *plug = (snd_pcm_plug_t*) &pcm->private;
if (snd_pcm_plug_direct(pcm, channel))
return snd_pcm_munmap_control(plug->slave, channel);
return -EBADFD;
}
static int snd_pcm_plug_munmap_data(snd_pcm_t *pcm, int channel, void *buffer UNUSED, size_t size UNUSED)
{
snd_pcm_plug_t *plug = (snd_pcm_plug_t*) &pcm->private;
if (snd_pcm_plug_direct(pcm, channel))
return snd_pcm_munmap_data(plug->slave, channel);
return -EBADFD;
}
static int snd_pcm_plug_voices_mask(snd_pcm_t *pcm, int channel,
bitset_t *client_vmask)
{
snd_pcm_plug_t *plug = (snd_pcm_plug_t*) &pcm->private;
if (snd_pcm_plug_direct(pcm, channel))
return snd_pcm_voices_mask(plug->slave, channel, client_vmask);
if (channel == SND_PCM_CHANNEL_PLAYBACK)
return snd_pcm_plug_playback_voices_mask(pcm, client_vmask);
else
return snd_pcm_plug_capture_voices_mask(pcm, client_vmask);
}
int snd_pcm_plug_file_descriptor(snd_pcm_t* pcm, int channel)
{
snd_pcm_plug_t *plug = (snd_pcm_plug_t*) &pcm->private;
return snd_pcm_file_descriptor(plug->slave, channel);
}
struct snd_pcm_ops snd_pcm_plug_ops = {
channel_close: snd_pcm_plug_channel_close,
channel_nonblock: snd_pcm_plug_channel_nonblock,
info: snd_pcm_plug_info,
channel_info: snd_pcm_plug_channel_info,
channel_params: snd_pcm_plug_channel_params,
channel_setup: snd_pcm_plug_channel_setup,
voice_setup: snd_pcm_plug_voice_setup,
channel_status: snd_pcm_plug_channel_status,
channel_prepare: snd_pcm_plug_channel_prepare,
channel_go: snd_pcm_plug_channel_go,
sync_go: snd_pcm_plug_sync_go,
channel_drain: snd_pcm_plug_channel_drain,
channel_flush: snd_pcm_plug_channel_flush,
channel_pause: snd_pcm_plug_channel_pause,
write: snd_pcm_plug_write,
writev: snd_pcm_plug_writev,
read: snd_pcm_plug_read,
readv: snd_pcm_plug_readv,
mmap_control: snd_pcm_plug_mmap_control,
mmap_data: snd_pcm_plug_mmap_data,
munmap_control: snd_pcm_plug_munmap_control,
munmap_data: snd_pcm_plug_munmap_data,
file_descriptor: snd_pcm_plug_file_descriptor,
voices_mask: snd_pcm_plug_voices_mask,
};
int snd_pcm_plug_connect(snd_pcm_t **handle, snd_pcm_t *slave, int mode, int close_slave)
{
snd_pcm_t *pcm;
snd_pcm_plug_t *plug;
int err;
err = snd_pcm_abstract_open(handle, mode, SND_PCM_TYPE_PLUG, sizeof(snd_pcm_plug_t));
if (err < 0) {
if (close_slave)
snd_pcm_close(slave);
return err;
}
pcm = *handle;
pcm->ops = &snd_pcm_plug_ops;
plug = (snd_pcm_plug_t*) &pcm->private;
plug->slave = slave;
plug->close_slave = close_slave;
return 0;
}
int snd_pcm_plug_open_subdevice(snd_pcm_t **handle, int card, int device, int subdevice, int mode)
{
snd_pcm_t *slave;
int err;
err = snd_pcm_open_subdevice(&slave, card, device, subdevice, mode);
if (err < 0)
return err;
return snd_pcm_plug_connect(handle, slave, mode, 1);
}
int snd_pcm_plug_open(snd_pcm_t **handle, int card, int device, int mode)
{
return snd_pcm_plug_open_subdevice(handle, card, device, -1, mode);
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
EXTRA_LTLIBRARIES = libpcmplugin.la
libpcmplugin_la_SOURCES = block.c mmap.c stream.c linear.c \
libpcmplugin_la_SOURCES = block.c mmap.c stream.c copy.c linear.c \
mulaw.c alaw.c adpcm.c rate.c route.c
all: libpcmplugin.la

View file

@ -78,7 +78,7 @@ typedef struct {
typedef void (*adpcm_f)(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
const snd_pcm_plugin_voice_t *dst_voices,
snd_pcm_plugin_voice_t *dst_voices,
size_t samples);
typedef struct adpcm_private_data {
@ -90,7 +90,7 @@ typedef struct adpcm_private_data {
static void adpcm_init(snd_pcm_plugin_t *plugin)
{
int voice;
unsigned int voice;
adpcm_t *data = (adpcm_t *)plugin->extra_data;
for (voice = 0; voice < plugin->src_format.voices; voice++) {
adpcm_voice_t *v = &data->voices[voice];
@ -212,7 +212,7 @@ static int adpcm_decoder(unsigned char code, adpcm_voice_t * state)
static void adpcm_decode(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
const snd_pcm_plugin_voice_t *dst_voices,
snd_pcm_plugin_voice_t *dst_voices,
size_t samples)
{
#define PUT16_LABELS
@ -229,13 +229,13 @@ static void adpcm_decode(snd_pcm_plugin_t *plugin,
int src_step, srcbit_step, dst_step;
size_t samples1;
adpcm_voice_t *state;
if (src_voices[voice].addr == NULL) {
if (dst_voices[voice].addr != NULL) {
// null_voice(&dst_voices[voice]);
zero_voice(plugin, &dst_voices[voice], samples);
}
if (!src_voices[voice].enabled) {
if (dst_voices[voice].wanted)
snd_pcm_plugin_silence_voice(plugin, &dst_voices[voice], samples);
dst_voices[voice].enabled = 0;
continue;
}
dst_voices[voice].enabled = 1;
src = src_voices[voice].addr + src_voices[voice].first / 8;
srcbit = src_voices[voice].first % 8;
dst = dst_voices[voice].addr + dst_voices[voice].first / 8;
@ -270,7 +270,7 @@ static void adpcm_decode(snd_pcm_plugin_t *plugin,
static void adpcm_encode(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
const snd_pcm_plugin_voice_t *dst_voices,
snd_pcm_plugin_voice_t *dst_voices,
size_t samples)
{
#define GET16_LABELS
@ -288,13 +288,13 @@ static void adpcm_encode(snd_pcm_plugin_t *plugin,
int src_step, dst_step, dstbit_step;
size_t samples1;
adpcm_voice_t *state;
if (src_voices[voice].addr == NULL) {
if (dst_voices[voice].addr != NULL) {
// null_voice(&dst_voices[voice]);
zero_voice(plugin, &dst_voices[voice], samples);
}
if (!src_voices[voice].enabled) {
if (dst_voices[voice].wanted)
snd_pcm_plugin_silence_voice(plugin, &dst_voices[voice], samples);
dst_voices[voice].enabled = 0;
continue;
}
dst_voices[voice].enabled = 1;
src = src_voices[voice].addr + src_voices[voice].first / 8;
dst = dst_voices[voice].addr + dst_voices[voice].first / 8;
dstbit = dst_voices[voice].first % 8;
@ -328,22 +328,17 @@ static void adpcm_encode(snd_pcm_plugin_t *plugin,
static ssize_t adpcm_transfer(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
const snd_pcm_plugin_voice_t *dst_voices,
snd_pcm_plugin_voice_t *dst_voices,
size_t samples)
{
adpcm_t *data;
int voice;
unsigned int voice;
if (plugin == NULL || src_voices == NULL || dst_voices == NULL)
return -EFAULT;
if (samples < 0)
return -EINVAL;
if (samples == 0)
return 0;
for (voice = 0; voice < plugin->src_format.voices; voice++) {
if (src_voices[voice].addr != NULL &&
dst_voices[voice].addr == NULL)
return -EFAULT;
if (plugin->src_format.format == SND_PCM_SFMT_IMA_ADPCM) {
if (src_voices[voice].first % 4 != 0 ||
src_voices[voice].step % 4 != 0 ||
@ -365,7 +360,7 @@ static ssize_t adpcm_transfer(snd_pcm_plugin_t *plugin,
static int adpcm_action(snd_pcm_plugin_t * plugin,
snd_pcm_plugin_action_t action,
unsigned long udata)
unsigned long udata UNUSED)
{
if (plugin == NULL)
return -EINVAL;
@ -376,15 +371,19 @@ static int adpcm_action(snd_pcm_plugin_t * plugin,
case FLUSH:
adpcm_init(plugin);
break;
default:
break;
}
return 0; /* silenty ignore other actions */
}
int snd_pcm_plugin_build_adpcm(snd_pcm_plugin_handle_t *handle,
int channel,
snd_pcm_format_t *src_format,
snd_pcm_format_t *dst_format,
snd_pcm_plugin_t **r_plugin)
{
int err;
struct adpcm_private_data *data;
snd_pcm_plugin_t *plugin;
snd_pcm_format_t *format;
@ -412,13 +411,14 @@ int snd_pcm_plugin_build_adpcm(snd_pcm_plugin_handle_t *handle,
if (!snd_pcm_format_linear(format->format))
return -EINVAL;
plugin = snd_pcm_plugin_build(handle,
"Ima-ADPCM<->linear conversion",
src_format,
dst_format,
sizeof(adpcm_t) + src_format->voices * sizeof(adpcm_voice_t));
if (plugin == NULL)
return -ENOMEM;
err = snd_pcm_plugin_build(handle, channel,
"Ima-ADPCM<->linear conversion",
src_format,
dst_format,
sizeof(adpcm_t) + src_format->voices * sizeof(adpcm_voice_t),
&plugin);
if (err < 0)
return err;
data = (adpcm_t *)plugin->extra_data;
data->func = func;
data->conv = getput_index(format->format);

View file

@ -134,7 +134,7 @@ static int alaw2linear(unsigned char a_val)
typedef void (*alaw_f)(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
const snd_pcm_plugin_voice_t *dst_voices,
snd_pcm_plugin_voice_t *dst_voices,
size_t samples);
typedef struct alaw_private_data {
@ -144,7 +144,7 @@ typedef struct alaw_private_data {
static void alaw_decode(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
const snd_pcm_plugin_voice_t *dst_voices,
snd_pcm_plugin_voice_t *dst_voices,
size_t samples)
{
#define PUT16_LABELS
@ -159,13 +159,13 @@ static void alaw_decode(snd_pcm_plugin_t *plugin,
char *dst;
int src_step, dst_step;
size_t samples1;
if (src_voices[voice].addr == NULL) {
if (dst_voices[voice].addr != NULL) {
// null_voice(&dst_voices[voice]);
zero_voice(plugin, &dst_voices[voice], samples);
}
if (!src_voices[voice].enabled) {
if (dst_voices[voice].wanted)
snd_pcm_plugin_silence_voice(plugin, &dst_voices[voice], samples);
dst_voices[voice].enabled = 0;
continue;
}
dst_voices[voice].enabled = 1;
src = src_voices[voice].addr + src_voices[voice].first / 8;
dst = dst_voices[voice].addr + dst_voices[voice].first / 8;
src_step = src_voices[voice].step / 8;
@ -186,7 +186,7 @@ static void alaw_decode(snd_pcm_plugin_t *plugin,
static void alaw_encode(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
const snd_pcm_plugin_voice_t *dst_voices,
snd_pcm_plugin_voice_t *dst_voices,
size_t samples)
{
#define GET16_LABELS
@ -202,13 +202,13 @@ static void alaw_encode(snd_pcm_plugin_t *plugin,
char *dst;
int src_step, dst_step;
size_t samples1;
if (src_voices[voice].addr == NULL) {
if (dst_voices[voice].addr != NULL) {
// null_voice(&dst_voices[voice]);
zero_voice(plugin, &dst_voices[voice], samples);
}
if (!src_voices[voice].enabled) {
if (dst_voices[voice].wanted)
snd_pcm_plugin_silence_voice(plugin, &dst_voices[voice], samples);
dst_voices[voice].enabled = 0;
continue;
}
dst_voices[voice].enabled = 1;
src = src_voices[voice].addr + src_voices[voice].first / 8;
dst = dst_voices[voice].addr + dst_voices[voice].first / 8;
src_step = src_voices[voice].step / 8;
@ -229,22 +229,17 @@ static void alaw_encode(snd_pcm_plugin_t *plugin,
static ssize_t alaw_transfer(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
const snd_pcm_plugin_voice_t *dst_voices,
snd_pcm_plugin_voice_t *dst_voices,
size_t samples)
{
alaw_t *data;
int voice;
unsigned int voice;
if (plugin == NULL || src_voices == NULL || dst_voices == NULL)
return -EFAULT;
if (samples < 0)
return -EINVAL;
if (samples == 0)
return 0;
for (voice = 0; voice < plugin->src_format.voices; voice++) {
if (src_voices[voice].addr != NULL &&
dst_voices[voice].addr == NULL)
return -EFAULT;
if (src_voices[voice].first % 8 != 0 ||
src_voices[voice].step % 8 != 0)
return -EINVAL;
@ -258,10 +253,12 @@ static ssize_t alaw_transfer(snd_pcm_plugin_t *plugin,
}
int snd_pcm_plugin_build_alaw(snd_pcm_plugin_handle_t *handle,
int channel,
snd_pcm_format_t *src_format,
snd_pcm_format_t *dst_format,
snd_pcm_plugin_t **r_plugin)
{
int err;
alaw_t *data;
snd_pcm_plugin_t *plugin;
snd_pcm_format_t *format;
@ -289,13 +286,14 @@ int snd_pcm_plugin_build_alaw(snd_pcm_plugin_handle_t *handle,
if (!snd_pcm_format_linear(format->format))
return -EINVAL;
plugin = snd_pcm_plugin_build(handle,
"A-Law<->linear conversion",
src_format,
dst_format,
sizeof(alaw_t));
if (plugin == NULL)
return -ENOMEM;
err = snd_pcm_plugin_build(handle, channel,
"A-Law<->linear conversion",
src_format,
dst_format,
sizeof(alaw_t),
&plugin);
if (err < 0)
return err;
data = (alaw_t*)plugin->extra_data;
data->func = func;
data->conv = getput_index(format->format);

View file

@ -19,6 +19,15 @@
*
*/
#ifdef __KERNEL__
#include "../../include/driver.h"
#include "../../include/pcm.h"
#include "../../include/pcm_plugin.h"
#define snd_pcm_write(handle,buf,count) snd_pcm_oss_write3(handle,buf,count,1)
#define snd_pcm_writev(handle,vec,count) snd_pcm_oss_writev3(handle,vec,count,1)
#define snd_pcm_read(handle,buf,count) snd_pcm_oss_read3(handle,buf,count,1)
#define snd_pcm_readv(handle,vec,count) snd_pcm_oss_readv3(handle,vec,count,1)
#else
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
@ -26,18 +35,19 @@
#include <errno.h>
#include <sys/uio.h>
#include "../pcm_local.h"
#endif
/*
* Basic block plugin
*/
typedef struct block_private_data {
int channel;
snd_pcm_plugin_handle_t *slave;
} block_t;
static ssize_t block_transfer(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
const snd_pcm_plugin_voice_t *dst_voices,
snd_pcm_plugin_voice_t *dst_voices,
size_t samples)
{
block_t *data;
@ -51,40 +61,50 @@ static ssize_t block_transfer(snd_pcm_plugin_t *plugin,
if (data == NULL)
return -EINVAL;
vec = (struct iovec *)((char *)data + sizeof(*data));
if (data->channel == SND_PCM_CHANNEL_PLAYBACK) {
if (plugin->channel == SND_PCM_CHANNEL_PLAYBACK) {
if (src_voices == NULL)
return -EINVAL;
if ((result = snd_pcm_plugin_src_samples_to_size(plugin, samples)) < 0)
return result;
count = plugin->src_format.voices;
if (plugin->src_format.interleave) {
result = snd_pcm_write(plugin->handle, src_voices->addr, result);
result = snd_pcm_write(data->slave, src_voices->addr, result);
} else {
count = plugin->src_format.voices;
result /= count;
for (voice = 0; voice < count; voice++) {
vec[voice].iov_base = src_voices[voice].addr;
if (src_voices[voice].enabled)
vec[voice].iov_base = src_voices[voice].addr;
else
vec[voice].iov_base = 0;
vec[voice].iov_len = result;
}
result = snd_pcm_writev(plugin->handle, vec, count);
result = snd_pcm_writev(data->slave, vec, count);
}
if (result < 0)
return result;
return snd_pcm_plugin_src_size_to_samples(plugin, result);
} else if (data->channel == SND_PCM_CHANNEL_CAPTURE) {
} else if (plugin->channel == SND_PCM_CHANNEL_CAPTURE) {
if (dst_voices == NULL)
return -EINVAL;
if ((result = snd_pcm_plugin_dst_samples_to_size(plugin, samples)) < 0)
return result;
count = plugin->dst_format.voices;
if (plugin->dst_format.interleave) {
result = snd_pcm_read(plugin->handle, dst_voices->addr, result);
result = snd_pcm_read(data->slave, dst_voices->addr, result);
for (voice = 0; voice < count; voice++) {
dst_voices[voice].enabled = src_voices[voice].enabled;
}
} else {
count = plugin->dst_format.voices;
result /= count;
for (voice = 0; voice < count; voice++) {
vec[voice].iov_base = dst_voices[voice].addr;
dst_voices[voice].enabled = src_voices[voice].enabled;
if (dst_voices[voice].enabled)
vec[voice].iov_base = dst_voices[voice].addr;
else
vec[voice].iov_base = 0;
vec[voice].iov_len = result;
}
result = snd_pcm_readv(plugin->handle, vec, count);
result = snd_pcm_readv(data->slave, vec, count);
}
if (result < 0)
return result;
@ -94,29 +114,49 @@ static ssize_t block_transfer(snd_pcm_plugin_t *plugin,
}
}
int snd_pcm_plugin_build_block(snd_pcm_t *pcm, int channel,
static int block_src_voices(snd_pcm_plugin_t *plugin,
size_t samples,
snd_pcm_plugin_voice_t **voices)
{
int err;
unsigned int voice;
snd_pcm_plugin_voice_t *v;
err = snd_pcm_plugin_client_voices(plugin, samples, &v);
if (err < 0)
return err;
*voices = v;
for (voice = 0; voice < plugin->src_format.voices; ++voice, ++v)
v->wanted = 1;
return 0;
}
int snd_pcm_plugin_build_block(snd_pcm_plugin_handle_t *pcm,
int channel,
snd_pcm_plugin_handle_t *slave,
snd_pcm_format_t *format,
snd_pcm_plugin_t **r_plugin)
{
int err;
block_t *data;
snd_pcm_plugin_t *plugin;
if (r_plugin == NULL)
return -EINVAL;
*r_plugin = NULL;
if (pcm == NULL || channel < 0 || channel > 1 || format == NULL)
if (pcm == NULL || format == NULL)
return -EINVAL;
plugin = snd_pcm_plugin_build(pcm,
channel == SND_PCM_CHANNEL_PLAYBACK ?
"I/O block playback" :
"I/O block capture",
format, format,
sizeof(block_t) + sizeof(struct iovec) * format->voices);
if (plugin == NULL)
return -ENOMEM;
err = snd_pcm_plugin_build(pcm, channel,
"I/O block",
format, format,
sizeof(block_t) + sizeof(struct iovec) * format->voices,
&plugin);
if (err < 0)
return err;
data = (block_t *)plugin->extra_data;
data->channel = channel;
data->slave = slave;
plugin->transfer = block_transfer;
if (format->interleave && channel == SND_PCM_CHANNEL_PLAYBACK)
plugin->client_voices = block_src_voices;
*r_plugin = plugin;
return 0;
}

156
src/pcm/plugin/copy.c Normal file
View file

@ -0,0 +1,156 @@
/*
* Linear conversion Plug-In
* Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
*
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#ifdef __KERNEL__
#include "../../include/driver.h"
#include "../../include/pcm.h"
#include "../../include/pcm_plugin.h"
#else
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <endian.h>
#include <byteswap.h>
#include <sys/uio.h>
#include "../pcm_local.h"
#endif
typedef struct copy_private_data {
int copy;
} copy_t;
static void copy(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
snd_pcm_plugin_voice_t *dst_voices,
size_t samples)
{
#define COPY_LABELS
#include "plugin_ops.h"
#undef COPY_LABELS
copy_t *data = (copy_t *)plugin->extra_data;
void *copy = copy_labels[data->copy];
int voice;
int nvoices = plugin->src_format.voices;
for (voice = 0; voice < nvoices; ++voice) {
char *src;
char *dst;
int src_step, dst_step;
size_t samples1;
if (!src_voices[voice].enabled) {
if (dst_voices[voice].wanted)
snd_pcm_plugin_silence_voice(plugin, &dst_voices[voice], samples);
dst_voices[voice].enabled = 0;
continue;
}
dst_voices[voice].enabled = 1;
src = src_voices[voice].addr + src_voices[voice].first / 8;
dst = dst_voices[voice].addr + dst_voices[voice].first / 8;
src_step = src_voices[voice].step / 8;
dst_step = dst_voices[voice].step / 8;
samples1 = samples;
while (samples1-- > 0) {
goto *copy;
#define COPY_END after
#include "plugin_ops.h"
#undef COPY_END
after:
src += src_step;
dst += dst_step;
}
}
}
static ssize_t copy_transfer(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
snd_pcm_plugin_voice_t *dst_voices,
size_t samples)
{
copy_t *data;
unsigned int voice;
if (plugin == NULL || src_voices == NULL || dst_voices == NULL)
return -EFAULT;
data = (copy_t *)plugin->extra_data;
if (samples == 0)
return 0;
for (voice = 0; voice < plugin->src_format.voices; voice++) {
if (src_voices[voice].first % 8 != 0 ||
src_voices[voice].step % 8 != 0)
return -EINVAL;
if (dst_voices[voice].first % 8 != 0 ||
dst_voices[voice].step % 8 != 0)
return -EINVAL;
}
copy(plugin, src_voices, dst_voices, samples);
return samples;
}
int copy_index(int format)
{
int size = snd_pcm_format_physical_width(format);
switch (size) {
case 8:
return 0;
case 16:
return 1;
case 32:
return 2;
case 64:
return 3;
default:
return -EINVAL;
}
}
int snd_pcm_plugin_build_copy(snd_pcm_plugin_handle_t *handle,
int channel,
snd_pcm_format_t *format,
snd_pcm_plugin_t **r_plugin)
{
int err;
struct copy_private_data *data;
snd_pcm_plugin_t *plugin;
int copy;
if (r_plugin == NULL)
return -EFAULT;
*r_plugin = NULL;
copy = copy_index(format->format);
if (copy < 0)
return -EINVAL;
err = snd_pcm_plugin_build(handle, channel,
"copy",
format,
format,
sizeof(copy_t),
&plugin);
if (err < 0)
return err;
data = (copy_t *)plugin->extra_data;
data->copy = copy;
plugin->transfer = copy_transfer;
*r_plugin = plugin;
return 0;
}

View file

@ -41,19 +41,19 @@
*/
typedef struct linear_private_data {
int copy;
int conv;
} linear_t;
static void convert(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
const snd_pcm_plugin_voice_t *dst_voices,
snd_pcm_plugin_voice_t *dst_voices,
size_t samples)
{
#define COPY_LABELS
#define CONV_LABELS
#include "plugin_ops.h"
#undef COPY_LABELS
#undef CONV_LABELS
linear_t *data = (linear_t *)plugin->extra_data;
void *copy = copy_labels[data->copy];
void *conv = conv_labels[data->conv];
int voice;
int nvoices = plugin->src_format.voices;
for (voice = 0; voice < nvoices; ++voice) {
@ -61,23 +61,23 @@ static void convert(snd_pcm_plugin_t *plugin,
char *dst;
int src_step, dst_step;
size_t samples1;
if (src_voices[voice].addr == NULL) {
if (dst_voices[voice].addr != NULL) {
// null_voice(&dst_voices[voice]);
zero_voice(plugin, &dst_voices[voice], samples);
}
if (!src_voices[voice].enabled) {
if (dst_voices[voice].wanted)
snd_pcm_plugin_silence_voice(plugin, &dst_voices[voice], samples);
dst_voices[voice].enabled = 0;
continue;
}
dst_voices[voice].enabled = 1;
src = src_voices[voice].addr + src_voices[voice].first / 8;
dst = dst_voices[voice].addr + dst_voices[voice].first / 8;
src_step = src_voices[voice].step / 8;
dst_step = dst_voices[voice].step / 8;
samples1 = samples;
while (samples1-- > 0) {
goto *copy;
#define COPY_END after
goto *conv;
#define CONV_END after
#include "plugin_ops.h"
#undef COPY_END
#undef CONV_END
after:
src += src_step;
dst += dst_step;
@ -87,23 +87,18 @@ static void convert(snd_pcm_plugin_t *plugin,
static ssize_t linear_transfer(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
const snd_pcm_plugin_voice_t *dst_voices,
snd_pcm_plugin_voice_t *dst_voices,
size_t samples)
{
linear_t *data;
int voice;
unsigned int voice;
if (plugin == NULL || src_voices == NULL || dst_voices == NULL)
return -EFAULT;
data = (linear_t *)plugin->extra_data;
if (samples < 0)
return -EINVAL;
if (samples == 0)
return 0;
for (voice = 0; voice < plugin->src_format.voices; voice++) {
if (src_voices[voice].addr != NULL &&
dst_voices[voice].addr == NULL)
return -EFAULT;
if (src_voices[voice].first % 8 != 0 ||
src_voices[voice].step % 8 != 0)
return -EINVAL;
@ -115,7 +110,7 @@ static ssize_t linear_transfer(snd_pcm_plugin_t *plugin,
return samples;
}
int copy_index(int src_format, int dst_format)
int conv_index(int src_format, int dst_format)
{
int src_endian, dst_endian, sign, src_width, dst_width;
@ -143,10 +138,12 @@ int copy_index(int src_format, int dst_format)
}
int snd_pcm_plugin_build_linear(snd_pcm_plugin_handle_t *handle,
int channel,
snd_pcm_format_t *src_format,
snd_pcm_format_t *dst_format,
snd_pcm_plugin_t **r_plugin)
{
int err;
struct linear_private_data *data;
snd_pcm_plugin_t *plugin;
@ -162,15 +159,16 @@ int snd_pcm_plugin_build_linear(snd_pcm_plugin_handle_t *handle,
snd_pcm_format_linear(dst_format->format)))
return -EINVAL;
plugin = snd_pcm_plugin_build(handle,
"linear format conversion",
src_format,
dst_format,
sizeof(linear_t));
if (plugin == NULL)
return -ENOMEM;
err = snd_pcm_plugin_build(handle, channel,
"linear format conversion",
src_format,
dst_format,
sizeof(linear_t),
&plugin);
if (err < 0)
return err;
data = (linear_t *)plugin->extra_data;
data->copy = copy_index(src_format->format, dst_format->format);
data->conv = conv_index(src_format->format, dst_format->format);
plugin->transfer = linear_transfer;
*r_plugin = plugin;
return 0;

View file

@ -24,6 +24,7 @@
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <sys/poll.h>
#include <sys/uio.h>
#include "../pcm_local.h"
@ -33,310 +34,248 @@
*/
typedef struct mmap_private_data {
int channel;
snd_pcm_t *slave;
snd_pcm_mmap_control_t *control;
char *buffer;
int frag;
int frag_size, samples_frag_size;
int start_mode, stop_mode;
int frags, frags_used;
int frags_min, frags_max;
unsigned int lastblock;
void *buffer;
unsigned int frag;
size_t samples_frag_size;
char *silence;
snd_pcm_plugin_voice_t voices[0];
} mmap_t;
static int playback_ok(snd_pcm_plugin_t *plugin)
{
mmap_t *data = (mmap_t *)plugin->extra_data;
snd_pcm_mmap_control_t *control = data->control;
int delta = control->status.block;
if (delta < data->lastblock) {
delta += (~0 - data->lastblock) + 1;
} else {
delta -= data->lastblock;
}
data->frags_used -= delta;
if (data->frags_used < 0) {
/* correction for rollover */
data->frag += -data->frags_used;
data->frag %= data->frags;
data->frags_used = 0;
}
data->lastblock += delta;
return data->frags_used <= data->frags_max &&
(data->frags - data->frags_used) >= data->frags_min;
}
static int poll_playback(snd_pcm_t *pcm)
{
int err;
struct pollfd pfd;
if (pcm->mode & SND_PCM_OPEN_NONBLOCK)
return -EAGAIN;
pfd.fd = pcm->chan[SND_PCM_CHANNEL_PLAYBACK].fd;
pfd.events = POLLOUT;
pfd.revents = 0;
err = poll(&pfd, 1, 1000);
return err < 0 ? err : 0;
}
static int query_playback(snd_pcm_plugin_t *plugin, int not_use_poll)
{
mmap_t *data = (mmap_t *)plugin->extra_data;
snd_pcm_mmap_control_t *control = data->control;
int err;
switch (control->status.status) {
case SND_PCM_STATUS_PREPARED:
if (data->start_mode == SND_PCM_START_GO)
return -EAGAIN;
if ((data->start_mode == SND_PCM_START_DATA &&
playback_ok(plugin)) ||
(data->start_mode == SND_PCM_START_FULL &&
data->frags_used == data->frags)) {
err = snd_pcm_channel_go(plugin->handle, data->channel);
if (err < 0)
return err;
}
break;
case SND_PCM_STATUS_RUNNING:
if (!not_use_poll) {
control->status.expblock = control->status.block + 1;
err = poll_playback(plugin->handle);
if (err < 0)
return err;
}
break;
case SND_PCM_STATUS_UNDERRUN:
return -EPIPE;
default:
return -EIO;
}
return 0;
}
static int capture_ok(snd_pcm_plugin_t *plugin)
{
mmap_t *data = (mmap_t *)plugin->extra_data;
snd_pcm_mmap_control_t *control = data->control;
int delta = control->status.block;
if (delta < data->lastblock) {
delta += (~0 - data->lastblock) + 1;
} else {
delta -= data->lastblock;
}
data->frags_used += delta;
if (data->frags_used > data->frags) {
/* correction for rollover */
data->frag += data->frags_used - data->frags;
data->frag %= data->frags;
data->frags_used = data->frags;
}
data->lastblock += delta;
return data->frags_used >= data->frags_min;
}
static int poll_capture(snd_pcm_t *pcm)
{
int err;
struct pollfd pfd;
if (pcm->mode & SND_PCM_OPEN_NONBLOCK)
return -EAGAIN;
pfd.fd = pcm->chan[SND_PCM_CHANNEL_CAPTURE].fd;
pfd.events = POLLIN;
pfd.revents = 0;
err = poll(&pfd, 1, 1000);
return err < 0 ? err : 0;
}
static int query_capture(snd_pcm_plugin_t *plugin, int not_use_poll)
{
mmap_t *data = (mmap_t *)plugin->extra_data;
snd_pcm_mmap_control_t *control = data->control;
int err;
switch (control->status.status) {
case SND_PCM_STATUS_PREPARED:
if (data->start_mode != SND_PCM_START_DATA)
return -EAGAIN;
err = snd_pcm_channel_go(plugin->handle, data->channel);
if (err < 0)
return err;
break;
case SND_PCM_STATUS_RUNNING:
if (!not_use_poll) {
control->status.expblock = control->status.block + data->frags_min;
err = poll_capture(plugin->handle);
if (err < 0)
return err;
}
break;
case SND_PCM_STATUS_OVERRUN:
return -EPIPE;
default:
return -EIO;
}
return 0;
}
static int mmap_src_voices(snd_pcm_plugin_t *plugin,
snd_pcm_plugin_voice_t **voices,
size_t samples)
size_t samples,
snd_pcm_plugin_voice_t **voices)
{
mmap_t *data;
int err;
int voice;
unsigned int voice;
snd_pcm_plugin_voice_t *dv, *sv;
struct snd_pcm_chan *chan;
snd_pcm_channel_setup_t *setup;
snd_pcm_mmap_control_t *ctrl;
int frag, f;
struct pollfd pfd;
int ready;
if (plugin == NULL || voices == NULL)
return -EINVAL;
data = (mmap_t *)plugin->extra_data;
if (data->channel != SND_PCM_CHANNEL_PLAYBACK)
if (samples != data->samples_frag_size)
return -EINVAL;
if (snd_pcm_plugin_dst_samples_to_size(plugin, samples) != data->frag_size)
return -EINVAL;
/* wait until the block is not free */
while (!playback_ok(plugin)) {
err = query_playback(plugin, 0);
if (err < 0)
return err;
}
sv = data->voices;
dv = plugin->voices;
ctrl = data->control;
chan = &plugin->handle->chan[plugin->channel];
setup = &chan->setup;
if (ctrl->status < SND_PCM_STATUS_PREPARED)
return -EBADFD;
ready = snd_pcm_mmap_ready(data->slave, plugin->channel);
if (ready < 0)
return ready;
if (!ready) {
if (ctrl->status != SND_PCM_STATUS_RUNNING)
return -EPIPE;
if (chan->mode & SND_PCM_NONBLOCK)
return -EAGAIN;
pfd.fd = snd_pcm_file_descriptor(plugin->handle, plugin->channel);
pfd.events = POLLOUT | POLLERR;
ready = poll(&pfd, 1, 10000);
if (ready < 0)
return ready;
if (ready && pfd.revents & POLLERR)
return -EPIPE;
assert(snd_pcm_mmap_ready(data->slave, plugin->channel));
}
frag = ctrl->frag_data;
f = frag % setup->frags;
dv = data->voices;
sv = plugin->src_voices;
*voices = sv;
for (voice = 0; voice < plugin->src_format.voices; ++voice) {
dv->addr = sv->addr + (sv->step * data->samples_frag_size * data->frag) / 8;
dv->first = sv->first;
dv->step = sv->step;
sv->enabled = 1;
sv->wanted = !data->silence[voice * setup->frags + f];
sv->aptr = 0;
sv->addr = dv->addr + (dv->step * data->samples_frag_size * f) / 8;
sv->first = dv->first;
sv->step = dv->step;
++sv;
++dv;
}
*voices = plugin->voices;
data->frag = frag;
return 0;
}
static int mmap_dst_voices(snd_pcm_plugin_t *plugin,
snd_pcm_plugin_voice_t **voices,
size_t samples)
size_t samples,
snd_pcm_plugin_voice_t **voices)
{
mmap_t *data;
int voice;
int err;
unsigned int voice;
snd_pcm_plugin_voice_t *dv, *sv;
struct snd_pcm_chan *chan;
snd_pcm_channel_setup_t *setup;
snd_pcm_mmap_control_t *ctrl;
int frag, f;
struct pollfd pfd;
int ready;
if (plugin == NULL || voices == NULL)
return -EINVAL;
data = (mmap_t *)plugin->extra_data;
if (data->channel != SND_PCM_CHANNEL_CAPTURE)
return -EINVAL;
if (snd_pcm_plugin_src_samples_to_size(plugin, samples) != data->frag_size)
if (samples != data->samples_frag_size)
return -EINVAL;
chan = &plugin->handle->chan[plugin->channel];
setup = &chan->setup;
ctrl = data->control;
if (ctrl->status < SND_PCM_STATUS_PREPARED)
return -EBADFD;
if (ctrl->status == SND_PCM_STATUS_PREPARED &&
chan->setup.start_mode == SND_PCM_START_DATA) {
err = snd_pcm_channel_go(data->slave, plugin->channel);
if (err < 0)
return err;
}
ready = snd_pcm_mmap_ready(data->slave, plugin->channel);
if (ready < 0)
return ready;
if (!ready) {
if (ctrl->status == SND_PCM_STATUS_PREPARED &&
chan->setup.start_mode == SND_PCM_START_FULL) {
err = snd_pcm_channel_go(data->slave, plugin->channel);
if (err < 0)
return err;
}
if (ctrl->status != SND_PCM_STATUS_RUNNING)
return -EPIPE;
if (chan->mode & SND_PCM_NONBLOCK)
return -EAGAIN;
pfd.fd = snd_pcm_file_descriptor(plugin->handle, plugin->channel);
pfd.events = POLLIN | POLLERR;
ready = poll(&pfd, 1, 10000);
if (ready < 0)
return ready;
if (ready && pfd.revents & POLLERR)
return -EPIPE;
assert(snd_pcm_mmap_ready(data->slave, plugin->channel));
}
frag = ctrl->frag_data;
f = frag % setup->frags;
sv = data->voices;
dv = plugin->voices;
for (voice = 0; voice < plugin->src_format.voices; ++voice) {
dv->addr = sv->addr + (sv->step * data->samples_frag_size * data->frag) / 8;
dv = plugin->dst_voices;
*voices = dv;
for (voice = 0; voice < plugin->dst_format.voices; ++voice) {
dv->enabled = 1;
dv->wanted = 0;
dv->aptr = 0;
dv->addr = sv->addr + (sv->step * data->samples_frag_size * f) / 8;
dv->first = sv->first;
dv->step = sv->step;
++sv;
++dv;
}
*voices = plugin->voices;
data->frag = frag;
return 0;
}
static ssize_t mmap_transfer(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
const snd_pcm_plugin_voice_t *dst_voices,
size_t samples)
static ssize_t mmap_playback_transfer(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
snd_pcm_plugin_voice_t *dst_voices UNUSED,
size_t samples)
{
mmap_t *data;
snd_pcm_mmap_control_t *control;
ssize_t size;
unsigned int voice;
snd_pcm_channel_setup_t *setup;
snd_pcm_mmap_control_t *ctrl;
struct snd_pcm_chan *chan;
unsigned int frag, f;
int err;
if (plugin == NULL)
return -EINVAL;
data = (mmap_t *)plugin->extra_data;
control = data->control;
if (control == NULL)
if (src_voices == NULL)
return -EINVAL;
if (data->channel == SND_PCM_CHANNEL_PLAYBACK) {
if (src_voices == NULL)
return -EINVAL;
while (!playback_ok(plugin)) {
err = query_playback(plugin, 0);
if (err < 0)
return err;
}
size = snd_pcm_plugin_src_samples_to_size(plugin, samples);
if (size != data->frag_size)
return -EINVAL;
if (plugin->prev == NULL) {
if (plugin->src_format.interleave) {
void *dst = data->voices[0].addr + data->frag * data->frag_size;
/* Paranoia: add check for src_voices */
memcpy(dst, src_voices[0].addr, size);
} else {
int voice;
size /= plugin->src_format.voices;
for (voice = 0; voice < plugin->src_format.voices; ++voice) {
void *dst = data->voices[voice].addr + (data->voices[voice].step * data->samples_frag_size * data->frag) / 8;
/* Paranoia: add check for src_voices */
memcpy(dst, src_voices[voice].addr, size);
}
}
}
control->fragments[data->frag].data = 1;
data->frag++;
data->frag %= data->frags;
data->frags_used++;
return samples;
} else if (data->channel == SND_PCM_CHANNEL_CAPTURE) {
if (dst_voices == NULL)
return -EINVAL;
while (!capture_ok(plugin)) {
err = query_capture(plugin, 0);
if (err < 0)
return err;
}
size = snd_pcm_plugin_dst_samples_to_size(plugin, samples);
if (size != data->frag_size)
return -EINVAL;
if (plugin->next == NULL) {
if (plugin->dst_format.interleave) {
void *src = data->voices[0].addr + data->frag * data->frag_size;
/* Paranoia: add check for dst_voices */
memcpy(dst_voices[0].addr, src, size);
} else {
int voice;
size /= plugin->src_format.voices;
for (voice = 0; voice < plugin->src_format.voices; ++voice) {
void *src = data->voices[voice].addr + (data->voices[voice].step * data->samples_frag_size * data->frag) / 8;
/* Paranoia: add check for dst_voices */
memcpy(dst_voices[voice].addr, src, size);
}
}
control->fragments[data->frag].data = 0;
} else {
int prev_frag = data->frag - 1;
if (prev_frag < 0)
prev_frag = data->frags - 1;
control->fragments[prev_frag].data = 0;
}
data->frag++;
data->frag %= data->frags;
data->frags_used--;
return samples;
} else {
if (plugin->prev == NULL)
return -EINVAL;
ctrl = data->control;
if (ctrl == NULL)
return -EINVAL;
chan = &data->slave->chan[SND_PCM_CHANNEL_PLAYBACK];
setup = &chan->setup;
frag = ctrl->frag_data;
if (frag != data->frag)
return -EIO;
f = frag % setup->frags;
for (voice = 0; voice < plugin->src_format.voices; voice++) {
if (src_voices[voice].enabled)
data->silence[voice * setup->frags + f] = 0;
}
frag++;
if (frag == setup->frag_boundary) {
ctrl->frag_data = 0;
ctrl->pos_data = 0;
} else {
ctrl->frag_data = frag;
ctrl->pos_data += setup->frag_size;
}
if (ctrl->status == SND_PCM_STATUS_PREPARED &&
(chan->setup.start_mode == SND_PCM_START_DATA ||
(chan->setup.start_mode == SND_PCM_START_FULL &&
!snd_pcm_mmap_ready(data->slave, plugin->channel)))) {
err = snd_pcm_channel_go(data->slave, plugin->channel);
if (err < 0)
return err;
}
return samples;
}
static ssize_t mmap_capture_transfer(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices UNUSED,
snd_pcm_plugin_voice_t *dst_voices UNUSED,
size_t samples)
{
mmap_t *data;
snd_pcm_channel_setup_t *setup;
snd_pcm_mmap_control_t *ctrl;
unsigned int frag;
if (plugin == NULL)
return -EINVAL;
data = (mmap_t *)plugin->extra_data;
if (plugin->next == NULL)
return -EINVAL;
ctrl = data->control;
if (ctrl == NULL)
return -EINVAL;
frag = ctrl->frag_data;
if (frag != data->frag)
return -EIO;
setup = &data->slave->chan[SND_PCM_CHANNEL_CAPTURE].setup;
/* FIXME: not here the increment */
frag++;
if (frag == setup->frag_boundary) {
ctrl->frag_data = 0;
ctrl->pos_data = 0;
} else {
ctrl->frag_data = frag;
ctrl->pos_data += setup->frag_size;
}
return samples;
}
static int mmap_action(snd_pcm_plugin_t *plugin,
snd_pcm_plugin_action_t action,
unsigned long udata)
unsigned long udata UNUSED)
{
struct mmap_private_data *data;
@ -344,48 +283,25 @@ static int mmap_action(snd_pcm_plugin_t *plugin,
return -EINVAL;
data = (mmap_t *)plugin->extra_data;
if (action == INIT) {
snd_pcm_channel_params_t *params;
snd_pcm_channel_setup_t setup;
snd_pcm_channel_setup_t *setup;
int result;
int voice;
unsigned int voice;
snd_pcm_plugin_voice_t *v;
if (data->control)
snd_pcm_munmap(plugin->handle, data->channel);
result = snd_pcm_mmap(plugin->handle, data->channel, &data->control, (void **)&data->buffer);
snd_pcm_munmap(data->slave, plugin->channel);
result = snd_pcm_mmap(data->slave, plugin->channel, &data->control, (void **)&data->buffer);
if (result < 0)
return result;
params = (snd_pcm_channel_params_t *)udata;
data->start_mode = params->start_mode;
data->stop_mode = params->stop_mode;
memset(&setup, 0, sizeof(setup));
setup.channel = data->channel;
if ((result = snd_pcm_channel_setup(plugin->handle, &setup)) < 0)
return result;
data->frags = setup.buf.block.frags;
data->frag_size = setup.buf.block.frag_size;
data->samples_frag_size = data->frag_size / snd_pcm_format_size(plugin->src_format.format, plugin->src_format.voices);
data->frags_min = setup.buf.block.frags_min;
data->frags_max = setup.buf.block.frags_max;
if (data->frags_min < 0)
data->frags_min = 0;
if (data->frags_min >= setup.buf.block.frags)
data->frags_min = setup.buf.block.frags - 1;
if (data->frags_max < 0)
data->frags_max = setup.buf.block.frags + data->frags_max;
if (data->frags_max < data->frags_min)
data->frags_max = data->frags_min;
if (data->frags_max < 1)
data->frags_max = 1;
if (data->frags_max > setup.buf.block.frags)
data->frags_max = setup.buf.block.frags;
setup = &data->slave->chan[plugin->channel].setup;
data->samples_frag_size = setup->frag_size / snd_pcm_format_size(setup->format.format, setup->format.voices);
v = data->voices;
for (voice = 0; voice < plugin->src_format.voices; ++voice) {
for (voice = 0; voice < setup->format.voices; ++voice) {
snd_pcm_voice_setup_t vsetup;
vsetup.voice = voice;
if ((result = snd_pcm_voice_setup(plugin->handle, data->channel, &vsetup)) < 0)
if ((result = snd_pcm_voice_setup(data->slave, plugin->channel, &vsetup)) < 0)
return result;
if (vsetup.addr < 0)
return -EBADFD;
@ -394,56 +310,60 @@ static int mmap_action(snd_pcm_plugin_t *plugin,
v->step = vsetup.step;
v++;
}
if (plugin->channel == SND_PCM_CHANNEL_PLAYBACK) {
data->silence = malloc(setup->frags * setup->format.voices);
memset(data->silence, 0, setup->frags * setup->format.voices);
} else
data->silence = 0;
return 0;
} else if (action == PREPARE) {
data->frag = 0;
data->lastblock = 0;
} else if (action == DRAIN && data->channel == SND_PCM_CHANNEL_PLAYBACK) {
data->frag = 0;
data->lastblock = 0;
} else if (action == FLUSH) {
data->frag = 0;
data->lastblock = 0;
}
return 0; /* silenty ignore other actions */
}
static void mmap_free(snd_pcm_plugin_t *plugin, void *private_data)
static void mmap_free(snd_pcm_plugin_t *plugin, void *private_data UNUSED)
{
struct mmap_private_data *data;
if (plugin == NULL)
return;
data = (mmap_t *)plugin->extra_data;
if (data->silence)
free(data->silence);
if (data->control)
snd_pcm_munmap(plugin->handle, data->channel);
snd_pcm_munmap(data->slave, plugin->channel);
}
int snd_pcm_plugin_build_mmap(snd_pcm_t *pcm, int channel,
int snd_pcm_plugin_build_mmap(snd_pcm_plugin_handle_t *pcm,
int channel,
snd_pcm_t *slave,
snd_pcm_format_t *format,
snd_pcm_plugin_t **r_plugin)
{
int err;
mmap_t *data;
snd_pcm_plugin_t *plugin;
if (r_plugin == NULL)
return -EINVAL;
*r_plugin = NULL;
if (!pcm || channel < 0 || channel > 1)
if (!pcm)
return -EINVAL;
plugin = snd_pcm_plugin_build(pcm,
channel == SND_PCM_CHANNEL_PLAYBACK ?
"I/O mmap playback" :
"I/O mmap capture",
format, format,
sizeof(mmap_t) + sizeof(snd_pcm_plugin_voice_t) * format->voices);
if (plugin == NULL)
return -ENOMEM;
err = snd_pcm_plugin_build(pcm, channel,
"I/O mmap",
format, format,
sizeof(mmap_t) + sizeof(snd_pcm_plugin_voice_t) * format->voices,
&plugin);
if (err < 0)
return err;
data = (mmap_t *)plugin->extra_data;
data->channel = channel;
plugin->src_voices = mmap_src_voices;
plugin->dst_voices = mmap_dst_voices;
plugin->transfer = mmap_transfer;
data->slave = slave;
if (channel == SND_PCM_CHANNEL_PLAYBACK) {
plugin->client_voices = mmap_src_voices;
plugin->transfer = mmap_playback_transfer;
} else {
plugin->client_voices = mmap_dst_voices;
plugin->transfer = mmap_capture_transfer;
}
plugin->action = mmap_action;
plugin->private_free = mmap_free;
*r_plugin = plugin;

View file

@ -150,7 +150,7 @@ static int ulaw2linear(unsigned char u_val)
typedef void (*mulaw_f)(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
const snd_pcm_plugin_voice_t *dst_voices,
snd_pcm_plugin_voice_t *dst_voices,
size_t samples);
typedef struct mulaw_private_data {
@ -160,7 +160,7 @@ typedef struct mulaw_private_data {
static void mulaw_decode(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
const snd_pcm_plugin_voice_t *dst_voices,
snd_pcm_plugin_voice_t *dst_voices,
size_t samples)
{
#define PUT16_LABELS
@ -175,13 +175,13 @@ static void mulaw_decode(snd_pcm_plugin_t *plugin,
char *dst;
int src_step, dst_step;
size_t samples1;
if (src_voices[voice].addr == NULL) {
if (dst_voices[voice].addr != NULL) {
// null_voice(&dst_voices[voice]);
zero_voice(plugin, &dst_voices[voice], samples);
}
if (!src_voices[voice].enabled) {
if (dst_voices[voice].wanted)
snd_pcm_plugin_silence_voice(plugin, &dst_voices[voice], samples);
dst_voices[voice].enabled = 0;
continue;
}
dst_voices[voice].enabled = 1;
src = src_voices[voice].addr + src_voices[voice].first / 8;
dst = dst_voices[voice].addr + dst_voices[voice].first / 8;
src_step = src_voices[voice].step / 8;
@ -202,7 +202,7 @@ static void mulaw_decode(snd_pcm_plugin_t *plugin,
static void mulaw_encode(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
const snd_pcm_plugin_voice_t *dst_voices,
snd_pcm_plugin_voice_t *dst_voices,
size_t samples)
{
#define GET16_LABELS
@ -218,13 +218,13 @@ static void mulaw_encode(snd_pcm_plugin_t *plugin,
char *dst;
int src_step, dst_step;
size_t samples1;
if (src_voices[voice].addr == NULL) {
if (dst_voices[voice].addr != NULL) {
// null_voice(&dst_voices[voice]);
zero_voice(plugin, &dst_voices[voice], samples);
}
if (!src_voices[voice].enabled) {
if (dst_voices[voice].wanted)
snd_pcm_plugin_silence_voice(plugin, &dst_voices[voice], samples);
dst_voices[voice].enabled = 0;
continue;
}
dst_voices[voice].enabled = 1;
src = src_voices[voice].addr + src_voices[voice].first / 8;
dst = dst_voices[voice].addr + dst_voices[voice].first / 8;
src_step = src_voices[voice].step / 8;
@ -245,22 +245,17 @@ static void mulaw_encode(snd_pcm_plugin_t *plugin,
static ssize_t mulaw_transfer(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
const snd_pcm_plugin_voice_t *dst_voices,
snd_pcm_plugin_voice_t *dst_voices,
size_t samples)
{
mulaw_t *data;
int voice;
unsigned int voice;
if (plugin == NULL || src_voices == NULL || dst_voices == NULL)
return -EFAULT;
if (samples < 0)
return -EINVAL;
if (samples == 0)
return 0;
for (voice = 0; voice < plugin->src_format.voices; voice++) {
if (src_voices[voice].addr != NULL &&
dst_voices[voice].addr == NULL)
return -EFAULT;
if (src_voices[voice].first % 8 != 0 ||
src_voices[voice].step % 8 != 0)
return -EINVAL;
@ -274,10 +269,12 @@ static ssize_t mulaw_transfer(snd_pcm_plugin_t *plugin,
}
int snd_pcm_plugin_build_mulaw(snd_pcm_plugin_handle_t *handle,
int channel,
snd_pcm_format_t *src_format,
snd_pcm_format_t *dst_format,
snd_pcm_plugin_t **r_plugin)
{
int err;
mulaw_t *data;
snd_pcm_plugin_t *plugin;
snd_pcm_format_t *format;
@ -305,13 +302,14 @@ int snd_pcm_plugin_build_mulaw(snd_pcm_plugin_handle_t *handle,
if (!snd_pcm_format_linear(format->format))
return -EINVAL;
plugin = snd_pcm_plugin_build(handle,
"Mu-Law<->linear conversion",
src_format,
dst_format,
sizeof(mulaw_t));
if (plugin == NULL)
return -ENOMEM;
err = snd_pcm_plugin_build(handle, channel,
"Mu-Law<->linear conversion",
src_format,
dst_format,
sizeof(mulaw_t),
&plugin);
if (err < 0)
return err;
data = (mulaw_t*)plugin->extra_data;
data->func = func;
data->conv = getput_index(format->format);

View file

@ -23,241 +23,260 @@
#define as_u8(ptr) (*(u_int8_t*)(ptr))
#define as_u16(ptr) (*(u_int16_t*)(ptr))
#define as_u32(ptr) (*(u_int32_t*)(ptr))
#define as_u64(ptr) (*(u_int64_t*)(ptr))
#define as_s8(ptr) (*(int8_t*)(ptr))
#define as_s16(ptr) (*(int16_t*)(ptr))
#define as_s32(ptr) (*(int32_t*)(ptr))
#define as_s64(ptr) (*(int64_t*)(ptr))
#ifdef COPY_LABELS
/* src_wid src_endswap sign_toggle dst_wid dst_endswap */
static void *copy_labels[4 * 2 * 2 * 4 * 2] = {
&&copy_xxx1_xxx1, /* 8h -> 8h */
&&copy_xxx1_xxx1, /* 8h -> 8s */
&&copy_xxx1_xx10, /* 8h -> 16h */
&&copy_xxx1_xx01, /* 8h -> 16s */
&&copy_xxx1_x100, /* 8h -> 24h */
&&copy_xxx1_001x, /* 8h -> 24s */
&&copy_xxx1_1000, /* 8h -> 32h */
&&copy_xxx1_0001, /* 8h -> 32s */
&&copy_xxx1_xxx9, /* 8h ^> 8h */
&&copy_xxx1_xxx9, /* 8h ^> 8s */
&&copy_xxx1_xx90, /* 8h ^> 16h */
&&copy_xxx1_xx09, /* 8h ^> 16s */
&&copy_xxx1_x900, /* 8h ^> 24h */
&&copy_xxx1_009x, /* 8h ^> 24s */
&&copy_xxx1_9000, /* 8h ^> 32h */
&&copy_xxx1_0009, /* 8h ^> 32s */
&&copy_xxx1_xxx1, /* 8s -> 8h */
&&copy_xxx1_xxx1, /* 8s -> 8s */
&&copy_xxx1_xx10, /* 8s -> 16h */
&&copy_xxx1_xx01, /* 8s -> 16s */
&&copy_xxx1_x100, /* 8s -> 24h */
&&copy_xxx1_001x, /* 8s -> 24s */
&&copy_xxx1_1000, /* 8s -> 32h */
&&copy_xxx1_0001, /* 8s -> 32s */
&&copy_xxx1_xxx9, /* 8s ^> 8h */
&&copy_xxx1_xxx9, /* 8s ^> 8s */
&&copy_xxx1_xx90, /* 8s ^> 16h */
&&copy_xxx1_xx09, /* 8s ^> 16s */
&&copy_xxx1_x900, /* 8s ^> 24h */
&&copy_xxx1_009x, /* 8s ^> 24s */
&&copy_xxx1_9000, /* 8s ^> 32h */
&&copy_xxx1_0009, /* 8s ^> 32s */
&&copy_xx12_xxx1, /* 16h -> 8h */
&&copy_xx12_xxx1, /* 16h -> 8s */
&&copy_xx12_xx12, /* 16h -> 16h */
&&copy_xx12_xx21, /* 16h -> 16s */
&&copy_xx12_x120, /* 16h -> 24h */
&&copy_xx12_021x, /* 16h -> 24s */
&&copy_xx12_1200, /* 16h -> 32h */
&&copy_xx12_0021, /* 16h -> 32s */
&&copy_xx12_xxx9, /* 16h ^> 8h */
&&copy_xx12_xxx9, /* 16h ^> 8s */
&&copy_xx12_xx92, /* 16h ^> 16h */
&&copy_xx12_xx29, /* 16h ^> 16s */
&&copy_xx12_x920, /* 16h ^> 24h */
&&copy_xx12_029x, /* 16h ^> 24s */
&&copy_xx12_9200, /* 16h ^> 32h */
&&copy_xx12_0029, /* 16h ^> 32s */
&&copy_xx12_xxx2, /* 16s -> 8h */
&&copy_xx12_xxx2, /* 16s -> 8s */
&&copy_xx12_xx21, /* 16s -> 16h */
&&copy_xx12_xx12, /* 16s -> 16s */
&&copy_xx12_x210, /* 16s -> 24h */
&&copy_xx12_012x, /* 16s -> 24s */
&&copy_xx12_2100, /* 16s -> 32h */
&&copy_xx12_0012, /* 16s -> 32s */
&&copy_xx12_xxxA, /* 16s ^> 8h */
&&copy_xx12_xxxA, /* 16s ^> 8s */
&&copy_xx12_xxA1, /* 16s ^> 16h */
&&copy_xx12_xx1A, /* 16s ^> 16s */
&&copy_xx12_xA10, /* 16s ^> 24h */
&&copy_xx12_01Ax, /* 16s ^> 24s */
&&copy_xx12_A100, /* 16s ^> 32h */
&&copy_xx12_001A, /* 16s ^> 32s */
&&copy_x123_xxx1, /* 24h -> 8h */
&&copy_x123_xxx1, /* 24h -> 8s */
&&copy_x123_xx12, /* 24h -> 16h */
&&copy_x123_xx21, /* 24h -> 16s */
&&copy_x123_x123, /* 24h -> 24h */
&&copy_x123_321x, /* 24h -> 24s */
&&copy_x123_1230, /* 24h -> 32h */
&&copy_x123_0321, /* 24h -> 32s */
&&copy_x123_xxx9, /* 24h ^> 8h */
&&copy_x123_xxx9, /* 24h ^> 8s */
&&copy_x123_xx92, /* 24h ^> 16h */
&&copy_x123_xx29, /* 24h ^> 16s */
&&copy_x123_x923, /* 24h ^> 24h */
&&copy_x123_329x, /* 24h ^> 24s */
&&copy_x123_9230, /* 24h ^> 32h */
&&copy_x123_0329, /* 24h ^> 32s */
&&copy_123x_xxx3, /* 24s -> 8h */
&&copy_123x_xxx3, /* 24s -> 8s */
&&copy_123x_xx32, /* 24s -> 16h */
&&copy_123x_xx23, /* 24s -> 16s */
&&copy_123x_x321, /* 24s -> 24h */
&&copy_123x_123x, /* 24s -> 24s */
&&copy_123x_3210, /* 24s -> 32h */
&&copy_123x_0123, /* 24s -> 32s */
&&copy_123x_xxxB, /* 24s ^> 8h */
&&copy_123x_xxxB, /* 24s ^> 8s */
&&copy_123x_xxB2, /* 24s ^> 16h */
&&copy_123x_xx2B, /* 24s ^> 16s */
&&copy_123x_xB21, /* 24s ^> 24h */
&&copy_123x_12Bx, /* 24s ^> 24s */
&&copy_123x_B210, /* 24s ^> 32h */
&&copy_123x_012B, /* 24s ^> 32s */
&&copy_1234_xxx1, /* 32h -> 8h */
&&copy_1234_xxx1, /* 32h -> 8s */
&&copy_1234_xx12, /* 32h -> 16h */
&&copy_1234_xx21, /* 32h -> 16s */
&&copy_1234_x123, /* 32h -> 24h */
&&copy_1234_321x, /* 32h -> 24s */
&&copy_1234_1234, /* 32h -> 32h */
&&copy_1234_4321, /* 32h -> 32s */
&&copy_1234_xxx9, /* 32h ^> 8h */
&&copy_1234_xxx9, /* 32h ^> 8s */
&&copy_1234_xx92, /* 32h ^> 16h */
&&copy_1234_xx29, /* 32h ^> 16s */
&&copy_1234_x923, /* 32h ^> 24h */
&&copy_1234_329x, /* 32h ^> 24s */
&&copy_1234_9234, /* 32h ^> 32h */
&&copy_1234_4329, /* 32h ^> 32s */
&&copy_1234_xxx4, /* 32s -> 8h */
&&copy_1234_xxx4, /* 32s -> 8s */
&&copy_1234_xx43, /* 32s -> 16h */
&&copy_1234_xx34, /* 32s -> 16s */
&&copy_1234_x432, /* 32s -> 24h */
&&copy_1234_234x, /* 32s -> 24s */
&&copy_1234_4321, /* 32s -> 32h */
&&copy_1234_1234, /* 32s -> 32s */
&&copy_1234_xxxC, /* 32s ^> 8h */
&&copy_1234_xxxC, /* 32s ^> 8s */
&&copy_1234_xxC3, /* 32s ^> 16h */
&&copy_1234_xx3C, /* 32s ^> 16s */
&&copy_1234_xC32, /* 32s ^> 24h */
&&copy_1234_23Cx, /* 32s ^> 24s */
&&copy_1234_C321, /* 32s ^> 32h */
&&copy_1234_123C, /* 32s ^> 32s */
static void *copy_labels[4] = {
&&copy_8,
&&copy_16,
&&copy_32,
&&copy_64
};
#endif
#ifdef COPY_END
while(0) {
copy_xxx1_xxx1: as_u8(dst) = as_u8(src); goto COPY_END;
copy_xxx1_xx10: as_u16(dst) = (u_int16_t)as_u8(src) << 8; goto COPY_END;
copy_xxx1_xx01: as_u16(dst) = (u_int16_t)as_u8(src); goto COPY_END;
copy_xxx1_x100: as_u32(dst) = (u_int32_t)as_u8(src) << 16; goto COPY_END;
copy_xxx1_001x: as_u32(dst) = (u_int32_t)as_u8(src) << 8; goto COPY_END;
copy_xxx1_1000: as_u32(dst) = (u_int32_t)as_u8(src) << 24; goto COPY_END;
copy_xxx1_0001: as_u32(dst) = (u_int32_t)as_u8(src); goto COPY_END;
copy_xxx1_xxx9: as_u8(dst) = as_u8(src) ^ 0x80; goto COPY_END;
copy_xxx1_xx90: as_u16(dst) = (u_int16_t)(as_u8(src) ^ 0x80) << 8; goto COPY_END;
copy_xxx1_xx09: as_u16(dst) = (u_int16_t)(as_u8(src) ^ 0x80); goto COPY_END;
copy_xxx1_x900: as_u32(dst) = (u_int32_t)(as_u8(src) ^ 0x80) << 16; goto COPY_END;
copy_xxx1_009x: as_u32(dst) = (u_int32_t)(as_u8(src) ^ 0x80) << 8; goto COPY_END;
copy_xxx1_9000: as_u32(dst) = (u_int32_t)(as_u8(src) ^ 0x80) << 24; goto COPY_END;
copy_xxx1_0009: as_u32(dst) = (u_int32_t)(as_u8(src) ^ 0x80); goto COPY_END;
copy_xx12_xxx1: as_u8(dst) = as_u16(src) >> 8; goto COPY_END;
copy_xx12_xx12: as_u16(dst) = as_u16(src); goto COPY_END;
copy_xx12_xx21: as_u16(dst) = bswap_16(as_u16(src)); goto COPY_END;
copy_xx12_x120: as_u32(dst) = (u_int32_t)as_u16(src) << 8; goto COPY_END;
copy_xx12_021x: as_u32(dst) = (u_int32_t)bswap_16(as_u16(src)) << 8; goto COPY_END;
copy_xx12_1200: as_u32(dst) = (u_int32_t)as_u16(src) << 16; goto COPY_END;
copy_xx12_0021: as_u32(dst) = (u_int32_t)bswap_16(as_u16(src)); goto COPY_END;
copy_xx12_xxx9: as_u8(dst) = (as_u16(src) >> 8) ^ 0x80; goto COPY_END;
copy_xx12_xx92: as_u16(dst) = as_u16(src) ^ 0x8000; goto COPY_END;
copy_xx12_xx29: as_u16(dst) = bswap_16(as_u16(src)) ^ 0x80; goto COPY_END;
copy_xx12_x920: as_u32(dst) = (u_int32_t)(as_u16(src) ^ 0x8000) << 8; goto COPY_END;
copy_xx12_029x: as_u32(dst) = (u_int32_t)(bswap_16(as_u16(src)) ^ 0x80) << 8; goto COPY_END;
copy_xx12_9200: as_u32(dst) = (u_int32_t)(as_u16(src) ^ 0x8000) << 16; goto COPY_END;
copy_xx12_0029: as_u32(dst) = (u_int32_t)(bswap_16(as_u16(src)) ^ 0x80); goto COPY_END;
copy_xx12_xxx2: as_u8(dst) = as_u16(src) & 0xff; goto COPY_END;
copy_xx12_x210: as_u32(dst) = (u_int32_t)bswap_16(as_u16(src)) << 8; goto COPY_END;
copy_xx12_012x: as_u32(dst) = (u_int32_t)as_u16(src) << 8; goto COPY_END;
copy_xx12_2100: as_u32(dst) = (u_int32_t)bswap_16(as_u16(src)) << 16; goto COPY_END;
copy_xx12_0012: as_u32(dst) = (u_int32_t)as_u16(src); goto COPY_END;
copy_xx12_xxxA: as_u8(dst) = (as_u16(src) ^ 0x80) & 0xff; goto COPY_END;
copy_xx12_xxA1: as_u16(dst) = bswap_16(as_u16(src) ^ 0x80); goto COPY_END;
copy_xx12_xx1A: as_u16(dst) = as_u16(src) ^ 0x80; goto COPY_END;
copy_xx12_xA10: as_u32(dst) = (u_int32_t)bswap_16(as_u16(src) ^ 0x80) << 8; goto COPY_END;
copy_xx12_01Ax: as_u32(dst) = (u_int32_t)(as_u16(src) ^ 0x80) << 8; goto COPY_END;
copy_xx12_A100: as_u32(dst) = (u_int32_t)bswap_16(as_u16(src) ^ 0x80) << 16; goto COPY_END;
copy_xx12_001A: as_u32(dst) = (u_int32_t)(as_u16(src) ^ 0x80); goto COPY_END;
copy_x123_xxx1: as_u8(dst) = as_u32(src) >> 16; goto COPY_END;
copy_x123_xx12: as_u16(dst) = as_u32(src) >> 8; goto COPY_END;
copy_x123_xx21: as_u16(dst) = bswap_16(as_u32(src) >> 8); goto COPY_END;
copy_x123_x123: as_u32(dst) = as_u32(src); goto COPY_END;
copy_x123_321x: as_u32(dst) = bswap_32(as_u32(src)); goto COPY_END;
copy_x123_1230: as_u32(dst) = as_u32(src) << 8; goto COPY_END;
copy_x123_0321: as_u32(dst) = bswap_32(as_u32(src)) >> 8; goto COPY_END;
copy_x123_xxx9: as_u8(dst) = (as_u32(src) >> 16) ^ 0x80; goto COPY_END;
copy_x123_xx92: as_u16(dst) = (as_u32(src) >> 8) ^ 0x8000; goto COPY_END;
copy_x123_xx29: as_u16(dst) = bswap_16(as_u32(src) >> 8) ^ 0x80; goto COPY_END;
copy_x123_x923: as_u32(dst) = as_u32(src) ^ 0x800000; goto COPY_END;
copy_x123_329x: as_u32(dst) = bswap_32(as_u32(src)) ^ 0x8000; goto COPY_END;
copy_x123_9230: as_u32(dst) = (as_u32(src) ^ 0x800000) << 8; goto COPY_END;
copy_x123_0329: as_u32(dst) = (bswap_32(as_u32(src)) >> 8) ^ 0x80; goto COPY_END;
copy_123x_xxx3: as_u8(dst) = (as_u32(src) >> 8) & 0xff; goto COPY_END;
copy_123x_xx32: as_u16(dst) = bswap_16(as_u32(src) >> 8); goto COPY_END;
copy_123x_xx23: as_u16(dst) = (as_u32(src) >> 8) & 0xffff; goto COPY_END;
copy_123x_x321: as_u32(dst) = bswap_32(as_u32(src)); goto COPY_END;
copy_123x_123x: as_u32(dst) = as_u32(src); goto COPY_END;
copy_123x_3210: as_u32(dst) = bswap_32(as_u32(src)) << 8; goto COPY_END;
copy_123x_0123: as_u32(dst) = as_u32(src) >> 8; goto COPY_END;
copy_123x_xxxB: as_u8(dst) = ((as_u32(src) >> 8) & 0xff) ^ 0x80; goto COPY_END;
copy_123x_xxB2: as_u16(dst) = bswap_16((as_u32(src) >> 8) ^ 0x80); goto COPY_END;
copy_123x_xx2B: as_u16(dst) = ((as_u32(src) >> 8) & 0xffff) ^ 0x80; goto COPY_END;
copy_123x_xB21: as_u32(dst) = bswap_32(as_u32(src)) ^ 0x800000; goto COPY_END;
copy_123x_12Bx: as_u32(dst) = as_u32(src) ^ 0x8000; goto COPY_END;
copy_123x_B210: as_u32(dst) = bswap_32(as_u32(src) ^ 0x8000) << 8; goto COPY_END;
copy_123x_012B: as_u32(dst) = (as_u32(src) >> 8) ^ 0x80; goto COPY_END;
copy_1234_xxx1: as_u8(dst) = as_u32(src) >> 24; goto COPY_END;
copy_1234_xx12: as_u16(dst) = as_u32(src) >> 16; goto COPY_END;
copy_1234_xx21: as_u16(dst) = bswap_16(as_u32(src) >> 16); goto COPY_END;
copy_1234_x123: as_u32(dst) = as_u32(src) >> 8; goto COPY_END;
copy_1234_321x: as_u32(dst) = bswap_32(as_u32(src)) << 8; goto COPY_END;
copy_1234_1234: as_u32(dst) = as_u32(src); goto COPY_END;
copy_1234_4321: as_u32(dst) = bswap_32(as_u32(src)); goto COPY_END;
copy_1234_xxx9: as_u8(dst) = (as_u32(src) >> 24) ^ 0x80; goto COPY_END;
copy_1234_xx92: as_u16(dst) = (as_u32(src) >> 16) ^ 0x8000; goto COPY_END;
copy_1234_xx29: as_u16(dst) = bswap_16(as_u32(src) >> 16) ^ 0x80; goto COPY_END;
copy_1234_x923: as_u32(dst) = (as_u32(src) >> 8) ^ 0x800000; goto COPY_END;
copy_1234_329x: as_u32(dst) = (bswap_32(as_u32(src)) ^ 0x80) << 8; goto COPY_END;
copy_1234_9234: as_u32(dst) = as_u32(src) ^ 0x80000000; goto COPY_END;
copy_1234_4329: as_u32(dst) = bswap_32(as_u32(src)) ^ 0x80; goto COPY_END;
copy_1234_xxx4: as_u8(dst) = as_u32(src) & 0xff; goto COPY_END;
copy_1234_xx43: as_u16(dst) = bswap_16(as_u32(src)); goto COPY_END;
copy_1234_xx34: as_u16(dst) = as_u32(src) & 0xffff; goto COPY_END;
copy_1234_x432: as_u32(dst) = bswap_32(as_u32(src)) >> 8; goto COPY_END;
copy_1234_234x: as_u32(dst) = as_u32(src) << 8; goto COPY_END;
copy_1234_xxxC: as_u8(dst) = (as_u32(src) & 0xff) ^ 0x80; goto COPY_END;
copy_1234_xxC3: as_u16(dst) = bswap_16(as_u32(src) ^ 0x80); goto COPY_END;
copy_1234_xx3C: as_u16(dst) = (as_u32(src) & 0xffff) ^ 0x80; goto COPY_END;
copy_1234_xC32: as_u32(dst) = (bswap_32(as_u32(src)) >> 8) ^ 0x800000; goto COPY_END;
copy_1234_23Cx: as_u32(dst) = (as_u32(src) ^ 0x80) << 8; goto COPY_END;
copy_1234_C321: as_u32(dst) = bswap_32(as_u32(src) ^ 0x80); goto COPY_END;
copy_1234_123C: as_u32(dst) = as_u32(src) ^ 0x80; goto COPY_END;
copy_8: as_s8(dst) = as_s8(src); goto COPY_END;
copy_16: as_s16(dst) = as_s16(src); goto COPY_END;
copy_32: as_s32(dst) = as_s32(src); goto COPY_END;
copy_64: as_s64(dst) = as_s64(src); goto COPY_END;
}
#endif
#ifdef CONV_LABELS
/* src_wid src_endswap sign_toggle dst_wid dst_endswap */
static void *conv_labels[4 * 2 * 2 * 4 * 2] = {
&&conv_xxx1_xxx1, /* 8h -> 8h */
&&conv_xxx1_xxx1, /* 8h -> 8s */
&&conv_xxx1_xx10, /* 8h -> 16h */
&&conv_xxx1_xx01, /* 8h -> 16s */
&&conv_xxx1_x100, /* 8h -> 24h */
&&conv_xxx1_001x, /* 8h -> 24s */
&&conv_xxx1_1000, /* 8h -> 32h */
&&conv_xxx1_0001, /* 8h -> 32s */
&&conv_xxx1_xxx9, /* 8h ^> 8h */
&&conv_xxx1_xxx9, /* 8h ^> 8s */
&&conv_xxx1_xx90, /* 8h ^> 16h */
&&conv_xxx1_xx09, /* 8h ^> 16s */
&&conv_xxx1_x900, /* 8h ^> 24h */
&&conv_xxx1_009x, /* 8h ^> 24s */
&&conv_xxx1_9000, /* 8h ^> 32h */
&&conv_xxx1_0009, /* 8h ^> 32s */
&&conv_xxx1_xxx1, /* 8s -> 8h */
&&conv_xxx1_xxx1, /* 8s -> 8s */
&&conv_xxx1_xx10, /* 8s -> 16h */
&&conv_xxx1_xx01, /* 8s -> 16s */
&&conv_xxx1_x100, /* 8s -> 24h */
&&conv_xxx1_001x, /* 8s -> 24s */
&&conv_xxx1_1000, /* 8s -> 32h */
&&conv_xxx1_0001, /* 8s -> 32s */
&&conv_xxx1_xxx9, /* 8s ^> 8h */
&&conv_xxx1_xxx9, /* 8s ^> 8s */
&&conv_xxx1_xx90, /* 8s ^> 16h */
&&conv_xxx1_xx09, /* 8s ^> 16s */
&&conv_xxx1_x900, /* 8s ^> 24h */
&&conv_xxx1_009x, /* 8s ^> 24s */
&&conv_xxx1_9000, /* 8s ^> 32h */
&&conv_xxx1_0009, /* 8s ^> 32s */
&&conv_xx12_xxx1, /* 16h -> 8h */
&&conv_xx12_xxx1, /* 16h -> 8s */
&&conv_xx12_xx12, /* 16h -> 16h */
&&conv_xx12_xx21, /* 16h -> 16s */
&&conv_xx12_x120, /* 16h -> 24h */
&&conv_xx12_021x, /* 16h -> 24s */
&&conv_xx12_1200, /* 16h -> 32h */
&&conv_xx12_0021, /* 16h -> 32s */
&&conv_xx12_xxx9, /* 16h ^> 8h */
&&conv_xx12_xxx9, /* 16h ^> 8s */
&&conv_xx12_xx92, /* 16h ^> 16h */
&&conv_xx12_xx29, /* 16h ^> 16s */
&&conv_xx12_x920, /* 16h ^> 24h */
&&conv_xx12_029x, /* 16h ^> 24s */
&&conv_xx12_9200, /* 16h ^> 32h */
&&conv_xx12_0029, /* 16h ^> 32s */
&&conv_xx12_xxx2, /* 16s -> 8h */
&&conv_xx12_xxx2, /* 16s -> 8s */
&&conv_xx12_xx21, /* 16s -> 16h */
&&conv_xx12_xx12, /* 16s -> 16s */
&&conv_xx12_x210, /* 16s -> 24h */
&&conv_xx12_012x, /* 16s -> 24s */
&&conv_xx12_2100, /* 16s -> 32h */
&&conv_xx12_0012, /* 16s -> 32s */
&&conv_xx12_xxxA, /* 16s ^> 8h */
&&conv_xx12_xxxA, /* 16s ^> 8s */
&&conv_xx12_xxA1, /* 16s ^> 16h */
&&conv_xx12_xx1A, /* 16s ^> 16s */
&&conv_xx12_xA10, /* 16s ^> 24h */
&&conv_xx12_01Ax, /* 16s ^> 24s */
&&conv_xx12_A100, /* 16s ^> 32h */
&&conv_xx12_001A, /* 16s ^> 32s */
&&conv_x123_xxx1, /* 24h -> 8h */
&&conv_x123_xxx1, /* 24h -> 8s */
&&conv_x123_xx12, /* 24h -> 16h */
&&conv_x123_xx21, /* 24h -> 16s */
&&conv_x123_x123, /* 24h -> 24h */
&&conv_x123_321x, /* 24h -> 24s */
&&conv_x123_1230, /* 24h -> 32h */
&&conv_x123_0321, /* 24h -> 32s */
&&conv_x123_xxx9, /* 24h ^> 8h */
&&conv_x123_xxx9, /* 24h ^> 8s */
&&conv_x123_xx92, /* 24h ^> 16h */
&&conv_x123_xx29, /* 24h ^> 16s */
&&conv_x123_x923, /* 24h ^> 24h */
&&conv_x123_329x, /* 24h ^> 24s */
&&conv_x123_9230, /* 24h ^> 32h */
&&conv_x123_0329, /* 24h ^> 32s */
&&conv_123x_xxx3, /* 24s -> 8h */
&&conv_123x_xxx3, /* 24s -> 8s */
&&conv_123x_xx32, /* 24s -> 16h */
&&conv_123x_xx23, /* 24s -> 16s */
&&conv_123x_x321, /* 24s -> 24h */
&&conv_123x_123x, /* 24s -> 24s */
&&conv_123x_3210, /* 24s -> 32h */
&&conv_123x_0123, /* 24s -> 32s */
&&conv_123x_xxxB, /* 24s ^> 8h */
&&conv_123x_xxxB, /* 24s ^> 8s */
&&conv_123x_xxB2, /* 24s ^> 16h */
&&conv_123x_xx2B, /* 24s ^> 16s */
&&conv_123x_xB21, /* 24s ^> 24h */
&&conv_123x_12Bx, /* 24s ^> 24s */
&&conv_123x_B210, /* 24s ^> 32h */
&&conv_123x_012B, /* 24s ^> 32s */
&&conv_1234_xxx1, /* 32h -> 8h */
&&conv_1234_xxx1, /* 32h -> 8s */
&&conv_1234_xx12, /* 32h -> 16h */
&&conv_1234_xx21, /* 32h -> 16s */
&&conv_1234_x123, /* 32h -> 24h */
&&conv_1234_321x, /* 32h -> 24s */
&&conv_1234_1234, /* 32h -> 32h */
&&conv_1234_4321, /* 32h -> 32s */
&&conv_1234_xxx9, /* 32h ^> 8h */
&&conv_1234_xxx9, /* 32h ^> 8s */
&&conv_1234_xx92, /* 32h ^> 16h */
&&conv_1234_xx29, /* 32h ^> 16s */
&&conv_1234_x923, /* 32h ^> 24h */
&&conv_1234_329x, /* 32h ^> 24s */
&&conv_1234_9234, /* 32h ^> 32h */
&&conv_1234_4329, /* 32h ^> 32s */
&&conv_1234_xxx4, /* 32s -> 8h */
&&conv_1234_xxx4, /* 32s -> 8s */
&&conv_1234_xx43, /* 32s -> 16h */
&&conv_1234_xx34, /* 32s -> 16s */
&&conv_1234_x432, /* 32s -> 24h */
&&conv_1234_234x, /* 32s -> 24s */
&&conv_1234_4321, /* 32s -> 32h */
&&conv_1234_1234, /* 32s -> 32s */
&&conv_1234_xxxC, /* 32s ^> 8h */
&&conv_1234_xxxC, /* 32s ^> 8s */
&&conv_1234_xxC3, /* 32s ^> 16h */
&&conv_1234_xx3C, /* 32s ^> 16s */
&&conv_1234_xC32, /* 32s ^> 24h */
&&conv_1234_23Cx, /* 32s ^> 24s */
&&conv_1234_C321, /* 32s ^> 32h */
&&conv_1234_123C, /* 32s ^> 32s */
};
#endif
#ifdef CONV_END
while(0) {
conv_xxx1_xxx1: as_u8(dst) = as_u8(src); goto CONV_END;
conv_xxx1_xx10: as_u16(dst) = (u_int16_t)as_u8(src) << 8; goto CONV_END;
conv_xxx1_xx01: as_u16(dst) = (u_int16_t)as_u8(src); goto CONV_END;
conv_xxx1_x100: as_u32(dst) = (u_int32_t)as_u8(src) << 16; goto CONV_END;
conv_xxx1_001x: as_u32(dst) = (u_int32_t)as_u8(src) << 8; goto CONV_END;
conv_xxx1_1000: as_u32(dst) = (u_int32_t)as_u8(src) << 24; goto CONV_END;
conv_xxx1_0001: as_u32(dst) = (u_int32_t)as_u8(src); goto CONV_END;
conv_xxx1_xxx9: as_u8(dst) = as_u8(src) ^ 0x80; goto CONV_END;
conv_xxx1_xx90: as_u16(dst) = (u_int16_t)(as_u8(src) ^ 0x80) << 8; goto CONV_END;
conv_xxx1_xx09: as_u16(dst) = (u_int16_t)(as_u8(src) ^ 0x80); goto CONV_END;
conv_xxx1_x900: as_u32(dst) = (u_int32_t)(as_u8(src) ^ 0x80) << 16; goto CONV_END;
conv_xxx1_009x: as_u32(dst) = (u_int32_t)(as_u8(src) ^ 0x80) << 8; goto CONV_END;
conv_xxx1_9000: as_u32(dst) = (u_int32_t)(as_u8(src) ^ 0x80) << 24; goto CONV_END;
conv_xxx1_0009: as_u32(dst) = (u_int32_t)(as_u8(src) ^ 0x80); goto CONV_END;
conv_xx12_xxx1: as_u8(dst) = as_u16(src) >> 8; goto CONV_END;
conv_xx12_xx12: as_u16(dst) = as_u16(src); goto CONV_END;
conv_xx12_xx21: as_u16(dst) = bswap_16(as_u16(src)); goto CONV_END;
conv_xx12_x120: as_u32(dst) = (u_int32_t)as_u16(src) << 8; goto CONV_END;
conv_xx12_021x: as_u32(dst) = (u_int32_t)bswap_16(as_u16(src)) << 8; goto CONV_END;
conv_xx12_1200: as_u32(dst) = (u_int32_t)as_u16(src) << 16; goto CONV_END;
conv_xx12_0021: as_u32(dst) = (u_int32_t)bswap_16(as_u16(src)); goto CONV_END;
conv_xx12_xxx9: as_u8(dst) = (as_u16(src) >> 8) ^ 0x80; goto CONV_END;
conv_xx12_xx92: as_u16(dst) = as_u16(src) ^ 0x8000; goto CONV_END;
conv_xx12_xx29: as_u16(dst) = bswap_16(as_u16(src)) ^ 0x80; goto CONV_END;
conv_xx12_x920: as_u32(dst) = (u_int32_t)(as_u16(src) ^ 0x8000) << 8; goto CONV_END;
conv_xx12_029x: as_u32(dst) = (u_int32_t)(bswap_16(as_u16(src)) ^ 0x80) << 8; goto CONV_END;
conv_xx12_9200: as_u32(dst) = (u_int32_t)(as_u16(src) ^ 0x8000) << 16; goto CONV_END;
conv_xx12_0029: as_u32(dst) = (u_int32_t)(bswap_16(as_u16(src)) ^ 0x80); goto CONV_END;
conv_xx12_xxx2: as_u8(dst) = as_u16(src) & 0xff; goto CONV_END;
conv_xx12_x210: as_u32(dst) = (u_int32_t)bswap_16(as_u16(src)) << 8; goto CONV_END;
conv_xx12_012x: as_u32(dst) = (u_int32_t)as_u16(src) << 8; goto CONV_END;
conv_xx12_2100: as_u32(dst) = (u_int32_t)bswap_16(as_u16(src)) << 16; goto CONV_END;
conv_xx12_0012: as_u32(dst) = (u_int32_t)as_u16(src); goto CONV_END;
conv_xx12_xxxA: as_u8(dst) = (as_u16(src) ^ 0x80) & 0xff; goto CONV_END;
conv_xx12_xxA1: as_u16(dst) = bswap_16(as_u16(src) ^ 0x80); goto CONV_END;
conv_xx12_xx1A: as_u16(dst) = as_u16(src) ^ 0x80; goto CONV_END;
conv_xx12_xA10: as_u32(dst) = (u_int32_t)bswap_16(as_u16(src) ^ 0x80) << 8; goto CONV_END;
conv_xx12_01Ax: as_u32(dst) = (u_int32_t)(as_u16(src) ^ 0x80) << 8; goto CONV_END;
conv_xx12_A100: as_u32(dst) = (u_int32_t)bswap_16(as_u16(src) ^ 0x80) << 16; goto CONV_END;
conv_xx12_001A: as_u32(dst) = (u_int32_t)(as_u16(src) ^ 0x80); goto CONV_END;
conv_x123_xxx1: as_u8(dst) = as_u32(src) >> 16; goto CONV_END;
conv_x123_xx12: as_u16(dst) = as_u32(src) >> 8; goto CONV_END;
conv_x123_xx21: as_u16(dst) = bswap_16(as_u32(src) >> 8); goto CONV_END;
conv_x123_x123: as_u32(dst) = as_u32(src); goto CONV_END;
conv_x123_321x: as_u32(dst) = bswap_32(as_u32(src)); goto CONV_END;
conv_x123_1230: as_u32(dst) = as_u32(src) << 8; goto CONV_END;
conv_x123_0321: as_u32(dst) = bswap_32(as_u32(src)) >> 8; goto CONV_END;
conv_x123_xxx9: as_u8(dst) = (as_u32(src) >> 16) ^ 0x80; goto CONV_END;
conv_x123_xx92: as_u16(dst) = (as_u32(src) >> 8) ^ 0x8000; goto CONV_END;
conv_x123_xx29: as_u16(dst) = bswap_16(as_u32(src) >> 8) ^ 0x80; goto CONV_END;
conv_x123_x923: as_u32(dst) = as_u32(src) ^ 0x800000; goto CONV_END;
conv_x123_329x: as_u32(dst) = bswap_32(as_u32(src)) ^ 0x8000; goto CONV_END;
conv_x123_9230: as_u32(dst) = (as_u32(src) ^ 0x800000) << 8; goto CONV_END;
conv_x123_0329: as_u32(dst) = (bswap_32(as_u32(src)) >> 8) ^ 0x80; goto CONV_END;
conv_123x_xxx3: as_u8(dst) = (as_u32(src) >> 8) & 0xff; goto CONV_END;
conv_123x_xx32: as_u16(dst) = bswap_16(as_u32(src) >> 8); goto CONV_END;
conv_123x_xx23: as_u16(dst) = (as_u32(src) >> 8) & 0xffff; goto CONV_END;
conv_123x_x321: as_u32(dst) = bswap_32(as_u32(src)); goto CONV_END;
conv_123x_123x: as_u32(dst) = as_u32(src); goto CONV_END;
conv_123x_3210: as_u32(dst) = bswap_32(as_u32(src)) << 8; goto CONV_END;
conv_123x_0123: as_u32(dst) = as_u32(src) >> 8; goto CONV_END;
conv_123x_xxxB: as_u8(dst) = ((as_u32(src) >> 8) & 0xff) ^ 0x80; goto CONV_END;
conv_123x_xxB2: as_u16(dst) = bswap_16((as_u32(src) >> 8) ^ 0x80); goto CONV_END;
conv_123x_xx2B: as_u16(dst) = ((as_u32(src) >> 8) & 0xffff) ^ 0x80; goto CONV_END;
conv_123x_xB21: as_u32(dst) = bswap_32(as_u32(src)) ^ 0x800000; goto CONV_END;
conv_123x_12Bx: as_u32(dst) = as_u32(src) ^ 0x8000; goto CONV_END;
conv_123x_B210: as_u32(dst) = bswap_32(as_u32(src) ^ 0x8000) << 8; goto CONV_END;
conv_123x_012B: as_u32(dst) = (as_u32(src) >> 8) ^ 0x80; goto CONV_END;
conv_1234_xxx1: as_u8(dst) = as_u32(src) >> 24; goto CONV_END;
conv_1234_xx12: as_u16(dst) = as_u32(src) >> 16; goto CONV_END;
conv_1234_xx21: as_u16(dst) = bswap_16(as_u32(src) >> 16); goto CONV_END;
conv_1234_x123: as_u32(dst) = as_u32(src) >> 8; goto CONV_END;
conv_1234_321x: as_u32(dst) = bswap_32(as_u32(src)) << 8; goto CONV_END;
conv_1234_1234: as_u32(dst) = as_u32(src); goto CONV_END;
conv_1234_4321: as_u32(dst) = bswap_32(as_u32(src)); goto CONV_END;
conv_1234_xxx9: as_u8(dst) = (as_u32(src) >> 24) ^ 0x80; goto CONV_END;
conv_1234_xx92: as_u16(dst) = (as_u32(src) >> 16) ^ 0x8000; goto CONV_END;
conv_1234_xx29: as_u16(dst) = bswap_16(as_u32(src) >> 16) ^ 0x80; goto CONV_END;
conv_1234_x923: as_u32(dst) = (as_u32(src) >> 8) ^ 0x800000; goto CONV_END;
conv_1234_329x: as_u32(dst) = (bswap_32(as_u32(src)) ^ 0x80) << 8; goto CONV_END;
conv_1234_9234: as_u32(dst) = as_u32(src) ^ 0x80000000; goto CONV_END;
conv_1234_4329: as_u32(dst) = bswap_32(as_u32(src)) ^ 0x80; goto CONV_END;
conv_1234_xxx4: as_u8(dst) = as_u32(src) & 0xff; goto CONV_END;
conv_1234_xx43: as_u16(dst) = bswap_16(as_u32(src)); goto CONV_END;
conv_1234_xx34: as_u16(dst) = as_u32(src) & 0xffff; goto CONV_END;
conv_1234_x432: as_u32(dst) = bswap_32(as_u32(src)) >> 8; goto CONV_END;
conv_1234_234x: as_u32(dst) = as_u32(src) << 8; goto CONV_END;
conv_1234_xxxC: as_u8(dst) = (as_u32(src) & 0xff) ^ 0x80; goto CONV_END;
conv_1234_xxC3: as_u16(dst) = bswap_16(as_u32(src) ^ 0x80); goto CONV_END;
conv_1234_xx3C: as_u16(dst) = (as_u32(src) & 0xffff) ^ 0x80; goto CONV_END;
conv_1234_xC32: as_u32(dst) = (bswap_32(as_u32(src)) >> 8) ^ 0x800000; goto CONV_END;
conv_1234_23Cx: as_u32(dst) = (as_u32(src) ^ 0x80) << 8; goto CONV_END;
conv_1234_C321: as_u32(dst) = bswap_32(as_u32(src) ^ 0x80); goto CONV_END;
conv_1234_123C: as_u32(dst) = as_u32(src) ^ 0x80; goto CONV_END;
}
#endif

View file

@ -49,7 +49,7 @@ typedef struct {
typedef void (*rate_f)(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
const snd_pcm_plugin_voice_t *dst_voices,
snd_pcm_plugin_voice_t *dst_voices,
int src_samples, int dst_samples);
typedef struct rate_private_data {
@ -63,7 +63,7 @@ typedef struct rate_private_data {
static void rate_init(snd_pcm_plugin_t *plugin)
{
int voice;
unsigned int voice;
rate_t *data = (rate_t *)plugin->extra_data;
data->pos = 0;
for (voice = 0; voice < plugin->src_format.voices; voice++) {
@ -74,14 +74,14 @@ static void rate_init(snd_pcm_plugin_t *plugin)
static void resample_expand(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
const snd_pcm_plugin_voice_t *dst_voices,
snd_pcm_plugin_voice_t *dst_voices,
int src_samples, int dst_samples)
{
unsigned int pos = 0;
signed int val;
signed short S1, S2;
char *src, *dst;
int voice;
unsigned int voice;
int src_step, dst_step;
int src_samples1, dst_samples1;
rate_t *data = (rate_t *)plugin->extra_data;
@ -104,13 +104,13 @@ static void resample_expand(snd_pcm_plugin_t *plugin,
pos = data->pos;
S1 = rvoices->last_S1;
S2 = rvoices->last_S2;
if (src_voices[voice].addr == NULL) {
if (dst_voices[voice].addr != NULL) {
// null_voice(&dst_voices[voice]);
zero_voice(plugin, &dst_voices[voice], dst_samples);
}
if (!src_voices[voice].enabled) {
if (dst_voices[voice].wanted)
snd_pcm_plugin_silence_voice(plugin, &dst_voices[voice], dst_samples);
dst_voices[voice].enabled = 0;
continue;
}
dst_voices[voice].enabled = 1;
src = (char *)src_voices[voice].addr + src_voices[voice].first / 8;
dst = (char *)dst_voices[voice].addr + dst_voices[voice].first / 8;
src_step = src_voices[voice].step / 8;
@ -162,14 +162,14 @@ static void resample_expand(snd_pcm_plugin_t *plugin,
static void resample_shrink(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
const snd_pcm_plugin_voice_t *dst_voices,
snd_pcm_plugin_voice_t *dst_voices,
int src_samples, int dst_samples)
{
unsigned int pos = 0;
signed int val;
signed short S1, S2;
char *src, *dst;
int voice;
unsigned int voice;
int src_step, dst_step;
int src_samples1, dst_samples1;
rate_t *data = (rate_t *)plugin->extra_data;
@ -188,13 +188,13 @@ static void resample_shrink(snd_pcm_plugin_t *plugin,
pos = data->pos;
S1 = rvoices->last_S1;
S2 = rvoices->last_S2;
if (src_voices[voice].addr == NULL) {
if (dst_voices[voice].addr != NULL) {
// null_voice(&dst_voices[voice]);
zero_voice(plugin, &dst_voices[voice], dst_samples);
}
if (!src_voices[voice].enabled) {
if (dst_voices[voice].wanted)
snd_pcm_plugin_silence_voice(plugin, &dst_voices[voice], dst_samples);
dst_voices[voice].enabled = 0;
continue;
}
dst_voices[voice].enabled = 1;
src = (char *)src_voices[voice].addr + src_voices[voice].first / 8;
dst = (char *)dst_voices[voice].addr + dst_voices[voice].first / 8;
src_step = src_voices[voice].step / 8;
@ -301,23 +301,18 @@ static ssize_t rate_dst_samples(snd_pcm_plugin_t *plugin, size_t samples)
static ssize_t rate_transfer(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
const snd_pcm_plugin_voice_t *dst_voices,
snd_pcm_plugin_voice_t *dst_voices,
size_t samples)
{
size_t dst_samples;
int voice;
unsigned int voice;
rate_t *data;
if (plugin == NULL || src_voices == NULL || dst_voices == NULL)
return -EFAULT;
if (samples < 0)
return -EINVAL;
if (samples == 0)
return 0;
for (voice = 0; voice < plugin->src_format.voices; voice++) {
if (src_voices[voice].addr != NULL &&
dst_voices[voice].addr == NULL)
return -EFAULT;
if (src_voices[voice].first % 8 != 0 ||
src_voices[voice].step % 8 != 0)
return -EINVAL;
@ -334,7 +329,7 @@ static ssize_t rate_transfer(snd_pcm_plugin_t *plugin,
static int rate_action(snd_pcm_plugin_t *plugin,
snd_pcm_plugin_action_t action,
unsigned long udata)
unsigned long udata UNUSED)
{
if (plugin == NULL)
return -EINVAL;
@ -345,15 +340,19 @@ static int rate_action(snd_pcm_plugin_t *plugin,
case FLUSH:
rate_init(plugin);
break;
default:
break;
}
return 0; /* silenty ignore other actions */
}
int snd_pcm_plugin_build_rate(snd_pcm_plugin_handle_t *handle,
int channel,
snd_pcm_format_t *src_format,
snd_pcm_format_t *dst_format,
snd_pcm_plugin_t **r_plugin)
{
int err;
rate_t *data;
snd_pcm_plugin_t *plugin;
@ -372,13 +371,14 @@ int snd_pcm_plugin_build_rate(snd_pcm_plugin_handle_t *handle,
if (src_format->rate == dst_format->rate)
return -EINVAL;
plugin = snd_pcm_plugin_build(handle,
"rate conversion",
src_format,
dst_format,
sizeof(rate_t) + src_format->voices * sizeof(rate_voice_t));
if (plugin == NULL)
return -ENOMEM;
err = snd_pcm_plugin_build(handle, channel,
"rate conversion",
src_format,
dst_format,
sizeof(rate_t) + src_format->voices * sizeof(rate_voice_t),
&plugin);
if (err < 0)
return err;
data = (rate_t *)plugin->extra_data;
data->get = getput_index(src_format->format);
data->put = getput_index(dst_format->format);

View file

@ -1,6 +1,6 @@
/*
* Attenuated route Plug-In
* Copyright (c) 2000 by Abramo Bagnara <abbagnara@racine.ra.it>
* Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
*
*
* This library is free software; you can redistribute it and/or modify
@ -23,8 +23,6 @@
#include "../../include/driver.h"
#include "../../include/pcm.h"
#include "../../include/pcm_plugin.h"
#define my_calloc(size) snd_kmalloc(size, GFP_KERNEL)
#define my_free(ptr) snd_kfree(ptr)
#else
#include <stdio.h>
#include <stdlib.h>
@ -35,8 +33,6 @@
#include <byteswap.h>
#include <math.h>
#include "../pcm_local.h"
#define my_calloc(size) calloc(1, size)
#define my_free(ptr) free(ptr)
#endif
typedef struct ttable_dst ttable_dst_t;
@ -44,7 +40,7 @@ typedef struct route_private_data route_t;
typedef void (*route_voice_f)(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
const snd_pcm_plugin_voice_t *dst_voice,
snd_pcm_plugin_voice_t *dst_voice,
ttable_dst_t* ttable, size_t samples);
typedef struct {
@ -65,7 +61,7 @@ struct ttable_dst {
struct route_private_data {
enum {INT32=0, INT64=1, FLOAT=2} sum_type;
int get, put;
int copy;
int conv;
int src_sample_size;
ttable_dst_t ttable[0];
};
@ -79,77 +75,26 @@ typedef union {
} sum_t;
void zero_voice(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *dst_voice,
size_t samples)
{
char *dst = dst_voice->addr + dst_voice->first / 8;
int dst_step = dst_voice->step / 8;
switch (plugin->dst_width) {
case 4: {
int dstbit = dst_voice->first % 8;
int dstbit_step = dst_voice->step % 8;
while (samples-- > 0) {
if (dstbit)
*dst &= 0x0f;
else
*dst &= 0xf0;
dst += dst_step;
dstbit += dstbit_step;
if (dstbit == 8) {
dst++;
dstbit = 0;
}
}
break;
}
case 8:
while (samples-- > 0) {
*dst = 0;
dst += dst_step;
}
break;
case 16:
while (samples-- > 0) {
*(int16_t*)dst = 0;
dst += dst_step;
}
break;
case 32:
while (samples-- > 0) {
*(int32_t*)dst = 0;
dst += dst_step;
}
break;
case 64:
while (samples-- > 0) {
*(int64_t*)dst = 0;
dst += dst_step;
}
break;
}
}
static void route_to_voice_zero(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
const snd_pcm_plugin_voice_t *dst_voice,
ttable_dst_t* ttable, size_t samples)
const snd_pcm_plugin_voice_t *src_voices UNUSED,
snd_pcm_plugin_voice_t *dst_voice,
ttable_dst_t* ttable UNUSED, size_t samples)
{
// null_voice(&dst_voices[voice]);
zero_voice(plugin, dst_voice, samples);
if (dst_voice->wanted)
snd_pcm_plugin_silence_voice(plugin, dst_voice, samples);
dst_voice->enabled = 0;
}
static void route_to_voice_one(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
const snd_pcm_plugin_voice_t *dst_voice,
snd_pcm_plugin_voice_t *dst_voice,
ttable_dst_t* ttable, size_t samples)
{
#define COPY_LABELS
#define CONV_LABELS
#include "plugin_ops.h"
#undef COPY_LABELS
#undef CONV_LABELS
route_t *data = (route_t *)plugin->extra_data;
void *copy;
void *conv;
const snd_pcm_plugin_voice_t *src_voice = 0;
int srcidx;
char *src, *dst;
@ -164,16 +109,17 @@ static void route_to_voice_one(snd_pcm_plugin_t *plugin,
return;
}
copy = copy_labels[data->copy];
dst_voice->enabled = 1;
conv = conv_labels[data->conv];
src = src_voice->addr + src_voice->first / 8;
src_step = src_voice->step / 8;
dst = dst_voice->addr + dst_voice->first / 8;
dst_step = dst_voice->step / 8;
while (samples-- > 0) {
goto *copy;
#define COPY_END after
goto *conv;
#define CONV_END after
#include "plugin_ops.h"
#undef COPY_END
#undef CONV_END
after:
src += src_step;
dst += dst_step;
@ -182,7 +128,7 @@ static void route_to_voice_one(snd_pcm_plugin_t *plugin,
static void route_to_voice(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
const snd_pcm_plugin_voice_t *dst_voice,
snd_pcm_plugin_voice_t *dst_voice,
ttable_dst_t* ttable, size_t samples)
{
#define GET_LABELS
@ -242,7 +188,7 @@ static void route_to_voice(snd_pcm_plugin_t *plugin,
int srcidx, srcidx1 = 0;
for (srcidx = 0; srcidx < nsrcs; ++srcidx) {
const snd_pcm_plugin_voice_t *src_voice = &src_voices[ttable->srcs[srcidx].voice];
if (src_voice->addr == NULL)
if (!src_voice->enabled)
continue;
srcs[srcidx1] = src_voice->addr + src_voices->first / 8;
src_steps[srcidx1] = src_voice->step / 8;
@ -258,6 +204,7 @@ static void route_to_voice(snd_pcm_plugin_t *plugin,
return;
}
dst_voice->enabled = 1;
zero = zero_labels[data->sum_type];
get = get_labels[data->get];
add = add_labels[data->sum_type * 2 + ttable->att];
@ -416,6 +363,55 @@ static void route_to_voice(snd_pcm_plugin_t *plugin,
}
}
int route_src_voices_mask(snd_pcm_plugin_t *plugin,
bitset_t *dst_vmask,
bitset_t **src_vmask)
{
route_t *data = (route_t *)plugin->extra_data;
int svoices = plugin->src_format.voices;
int dvoices = plugin->dst_format.voices;
bitset_t *vmask = plugin->src_vmask;
int voice;
ttable_dst_t *dp = data->ttable;
bitset_zero(vmask, svoices);
for (voice = 0; voice < dvoices; voice++, dp++) {
int src;
ttable_src_t *sp;
if (!bitset_get(dst_vmask, voice))
continue;
sp = dp->srcs;
for (src = 0; src < dp->nsrcs; src++, sp++)
bitset_set(vmask, sp->voice);
}
*src_vmask = vmask;
return 0;
}
int route_dst_voices_mask(snd_pcm_plugin_t *plugin,
bitset_t *src_vmask,
bitset_t **dst_vmask)
{
route_t *data = (route_t *)plugin->extra_data;
int dvoices = plugin->dst_format.voices;
bitset_t *vmask = plugin->dst_vmask;
int voice;
ttable_dst_t *dp = data->ttable;
bitset_zero(vmask, dvoices);
for (voice = 0; voice < dvoices; voice++, dp++) {
int src;
ttable_src_t *sp;
sp = dp->srcs;
for (src = 0; src < dp->nsrcs; src++, sp++) {
if (bitset_get(src_vmask, sp->voice)) {
bitset_set(vmask, voice);
break;
}
}
}
*dst_vmask = vmask;
return 0;
}
#ifdef __KERNEL__
#define FULL ROUTE_PLUGIN_RESOLUTION
typedef int src_ttable_entry_t;
@ -424,13 +420,13 @@ typedef int src_ttable_entry_t;
typedef float src_ttable_entry_t;
#endif
static void route_free(snd_pcm_plugin_t *plugin, void* private_data)
static void route_free(snd_pcm_plugin_t *plugin, void* private_data UNUSED)
{
route_t *data = (route_t *)plugin->extra_data;
int dst_voice;
unsigned int dst_voice;
for (dst_voice = 0; dst_voice < plugin->dst_format.voices; ++dst_voice) {
if (data->ttable[dst_voice].srcs != NULL)
my_free(data->ttable[dst_voice].srcs);
free(data->ttable[dst_voice].srcs);
}
}
@ -438,7 +434,7 @@ static int route_load_ttable(snd_pcm_plugin_t *plugin,
const src_ttable_entry_t* src_ttable)
{
route_t *data;
int src_voice, dst_voice;
unsigned int src_voice, dst_voice;
const src_ttable_entry_t *sptr;
ttable_dst_t *dptr;
if (src_ttable == NULL)
@ -488,8 +484,11 @@ static int route_load_ttable(snd_pcm_plugin_t *plugin,
dptr->func = route_to_voice;
break;
}
dptr->srcs = my_calloc(sizeof(*srcs) * nsrcs);
memcpy(dptr->srcs, srcs, sizeof(*srcs) * nsrcs);
if (nsrcs > 0) {
dptr->srcs = calloc(nsrcs, sizeof(*srcs));
memcpy(dptr->srcs, srcs, sizeof(*srcs) * nsrcs);
} else
dptr->srcs = 0;
dptr++;
}
return 0;
@ -497,19 +496,17 @@ static int route_load_ttable(snd_pcm_plugin_t *plugin,
static ssize_t route_transfer(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
const snd_pcm_plugin_voice_t *dst_voices,
snd_pcm_plugin_voice_t *dst_voices,
size_t samples)
{
route_t *data;
int src_nvoices, dst_nvoices;
int src_voice, dst_voice;
ttable_dst_t *ttp;
const snd_pcm_plugin_voice_t *dvp;
snd_pcm_plugin_voice_t *dvp;
if (plugin == NULL || src_voices == NULL || dst_voices == NULL)
return -EFAULT;
if (samples < 0)
return -EINVAL;
if (samples == 0)
return 0;
data = (route_t *)plugin->extra_data;
@ -556,6 +553,7 @@ int getput_index(int format)
}
int snd_pcm_plugin_build_route(snd_pcm_plugin_handle_t *handle,
int channel,
snd_pcm_format_t *src_format,
snd_pcm_format_t *dst_format,
src_ttable_entry_t *ttable,
@ -574,19 +572,20 @@ int snd_pcm_plugin_build_route(snd_pcm_plugin_handle_t *handle,
snd_pcm_format_linear(dst_format->format)))
return -EINVAL;
plugin = snd_pcm_plugin_build(handle,
"attenuated route conversion",
src_format,
dst_format,
sizeof(route_t) + sizeof(data->ttable[0]) * dst_format->voices);
if (plugin == NULL)
return -ENOMEM;
err = snd_pcm_plugin_build(handle, channel,
"attenuated route conversion",
src_format,
dst_format,
sizeof(route_t) + sizeof(data->ttable[0]) * dst_format->voices,
&plugin);
if (err < 0)
return err;
data = (route_t *) plugin->extra_data;
data->get = getput_index(src_format->format);
data->put = getput_index(dst_format->format);
data->copy = copy_index(src_format->format, dst_format->format);
data->conv = conv_index(src_format->format, dst_format->format);
#ifdef __KERNEL__
if (snd_pcm_format_width(src_format->format) == 32)
@ -603,6 +602,8 @@ int snd_pcm_plugin_build_route(snd_pcm_plugin_handle_t *handle,
return err;
}
plugin->transfer = route_transfer;
plugin->src_voices_mask = route_src_voices_mask;
plugin->dst_voices_mask = route_dst_voices_mask;
*r_plugin = plugin;
return 0;
}

View file

@ -32,12 +32,12 @@
*/
typedef struct stream_private_data {
int channel;
snd_pcm_t *slave;
} stream_t;
static ssize_t stream_transfer(snd_pcm_plugin_t *plugin,
const snd_pcm_plugin_voice_t *src_voices,
const snd_pcm_plugin_voice_t *dst_voices,
snd_pcm_plugin_voice_t *dst_voices,
size_t samples)
{
stream_t *data;
@ -51,41 +51,49 @@ static ssize_t stream_transfer(snd_pcm_plugin_t *plugin,
if (data == NULL)
return -EINVAL;
vec = (struct iovec *)((char *)data + sizeof(*data));
if (data->channel == SND_PCM_CHANNEL_PLAYBACK) {
if (plugin->channel == SND_PCM_CHANNEL_PLAYBACK) {
if (src_voices == NULL)
return -EINVAL;
if ((result = snd_pcm_plugin_src_samples_to_size(plugin, samples)) < 0)
return result;
count = plugin->src_format.voices;
if (plugin->src_format.interleave) {
result = snd_pcm_write(plugin->handle, src_voices->addr, result);
result = snd_pcm_write(data->slave, src_voices->addr, result);
} else {
count = plugin->src_format.voices;
result /= count;
for (voice = 0; voice < count; voice++) {
vec[voice].iov_base = src_voices[voice].addr;
if (src_voices[voice].enabled)
vec[voice].iov_base = src_voices[voice].addr;
else
vec[voice].iov_base = 0;
vec[voice].iov_len = result;
}
result = snd_pcm_writev(plugin->handle, vec, count);
result = snd_pcm_writev(data->slave, vec, count);
}
if (result < 0)
return result;
return snd_pcm_plugin_src_size_to_samples(plugin, result);
} else if (data->channel == SND_PCM_CHANNEL_CAPTURE) {
} else if (plugin->channel == SND_PCM_CHANNEL_CAPTURE) {
if (dst_voices == NULL)
return -EINVAL;
if ((result = snd_pcm_plugin_dst_samples_to_size(plugin, samples)) < 0)
return result;
count = plugin->dst_format.voices;
if (plugin->dst_format.interleave) {
result = snd_pcm_read(plugin->handle, dst_voices->addr, result);
result = snd_pcm_read(data->slave, dst_voices->addr, result);
for (voice = 0; voice < count; voice++)
dst_voices[voice].enabled = src_voices[voice].enabled;
} else {
count = plugin->dst_format.voices;
result /= count;
for (voice = 0; voice < count; voice++) {
vec[voice].iov_base = dst_voices[voice].addr;
dst_voices[voice].enabled = src_voices[voice].enabled;
if (dst_voices[voice].enabled)
vec[voice].iov_base = dst_voices[voice].addr;
else
vec[voice].iov_base = 0;
vec[voice].iov_len = result;
}
result = snd_pcm_readv(plugin->handle, vec, count);
result = snd_pcm_readv(data->slave, vec, count);
}
if (result < 0)
return result;
@ -95,10 +103,29 @@ static ssize_t stream_transfer(snd_pcm_plugin_t *plugin,
}
}
int snd_pcm_plugin_build_stream(snd_pcm_t *pcm, int channel,
static int stream_src_voices(snd_pcm_plugin_t *plugin,
size_t samples,
snd_pcm_plugin_voice_t **voices)
{
int err;
unsigned int voice;
snd_pcm_plugin_voice_t *v;
err = snd_pcm_plugin_client_voices(plugin, samples, &v);
if (err < 0)
return err;
*voices = v;
for (voice = 0; voice < plugin->src_format.voices; ++voice, ++v)
v->wanted = 1;
return 0;
}
int snd_pcm_plugin_build_stream(snd_pcm_plugin_handle_t *pcm,
int channel,
snd_pcm_t *slave,
snd_pcm_format_t *format,
snd_pcm_plugin_t **r_plugin)
{
int err;
stream_t *data;
snd_pcm_plugin_t *plugin;
@ -107,17 +134,18 @@ int snd_pcm_plugin_build_stream(snd_pcm_t *pcm, int channel,
*r_plugin = NULL;
if (!pcm || channel < 0 || channel > 1)
return -EINVAL;
plugin = snd_pcm_plugin_build(pcm,
channel == SND_PCM_CHANNEL_PLAYBACK ?
"I/O stream playback" :
"I/O stream capture",
format, format,
sizeof(stream_t) + sizeof(struct iovec) * format->voices);
if (plugin == NULL)
return -ENOMEM;
err = snd_pcm_plugin_build(pcm, channel,
"I/O stream",
format, format,
sizeof(stream_t) + sizeof(struct iovec) * format->voices,
&plugin);
if (err < 0)
return err;
data = (stream_t *)plugin->extra_data;
data->channel = channel;
data->slave = slave;
plugin->transfer = stream_transfer;
if (format->interleave && channel == SND_PCM_CHANNEL_PLAYBACK)
plugin->client_voices = stream_src_voices;
*r_plugin = plugin;
return 0;
}

View file

@ -190,7 +190,7 @@ ssize_t snd_rawmidi_write(snd_rawmidi_t *rmidi, const void *buffer, size_t size)
{
ssize_t result;
if (!rmidi || (!buffer && size > 0) || size < 0)
if (!rmidi || (!buffer && size > 0))
return -EINVAL;
result = write(rmidi->fd, buffer, size);
if (result < 0)
@ -202,7 +202,7 @@ ssize_t snd_rawmidi_read(snd_rawmidi_t *rmidi, void *buffer, size_t size)
{
ssize_t result;
if (!rmidi || (!buffer && size > 0) || size < 0)
if (!rmidi || (!buffer && size > 0))
return -EINVAL;
result = read(rmidi->fd, buffer, size);
if (result < 0)

View file

@ -39,7 +39,7 @@
* prototypes
*/
static int snd_seq_free_event_static(snd_seq_event_t *ev);
static int snd_seq_decode_event(char **buf, int *len, snd_seq_event_t *ev);
static int snd_seq_decode_event(char **buf, size_t *len, snd_seq_event_t *ev);
/*
@ -184,7 +184,7 @@ int snd_seq_input_buffer_size(snd_seq_t *seq)
/*
* resize output buffer
*/
int snd_seq_resize_output_buffer(snd_seq_t *seq, int size)
int snd_seq_resize_output_buffer(snd_seq_t *seq, size_t size)
{
if (!seq || !seq->obuf)
return -EINVAL;
@ -206,7 +206,7 @@ int snd_seq_resize_output_buffer(snd_seq_t *seq, int size)
/*
* resize input buffer
*/
int snd_seq_resize_input_buffer(snd_seq_t *seq, int size)
int snd_seq_resize_input_buffer(snd_seq_t *seq, size_t size)
{
if (!seq || !seq->ibuf)
return -EINVAL;
@ -608,17 +608,14 @@ int snd_seq_free_event(snd_seq_event_t *ev)
/*
* calculates the (encoded) byte-stream size of the event
*/
int snd_seq_event_length(snd_seq_event_t *ev)
ssize_t snd_seq_event_length(snd_seq_event_t *ev)
{
int len = sizeof(snd_seq_event_t);
ssize_t len = sizeof(snd_seq_event_t);
if (!ev)
return -EINVAL;
if (snd_seq_ev_is_variable(ev)) {
if (ev->data.ext.len < 0)
return -EINVAL;
if (snd_seq_ev_is_variable(ev))
len += ev->data.ext.len;
}
return len;
}
@ -659,7 +656,7 @@ int snd_seq_event_output_buffer(snd_seq_t *seq, snd_seq_event_t *ev)
len = snd_seq_event_length(ev);
if (len < 0)
return -EINVAL;
if ((seq->obufsize - seq->obufused) < len)
if ((seq->obufsize - seq->obufused) < (size_t) len)
return -EAGAIN;
memcpy(seq->obuf + seq->obufused, ev, sizeof(snd_seq_event_t));
seq->obufused += sizeof(snd_seq_event_t);
@ -722,7 +719,7 @@ int snd_seq_flush_output(snd_seq_t *seq)
result = write(seq->fd, seq->obuf, seq->obufused);
if (result < 0)
return -errno;
if (result < seq->obufused)
if ((size_t)result < seq->obufused)
memmove(seq->obuf, seq->obuf + result, seq->obufused - result);
seq->obufused -= result;
}
@ -853,7 +850,7 @@ static int snd_seq_input_cell_available(snd_seq_t *seq)
/*
* decode from byte-stream to an event record
*/
static int snd_seq_decode_event(char **buf, int *len, snd_seq_event_t *ev)
static int snd_seq_decode_event(char **buf, size_t *len, snd_seq_event_t *ev)
{
if (!ev || !buf || !*buf || !len )
return -EINVAL;
@ -1213,11 +1210,11 @@ int snd_seq_remove_events(snd_seq_t *seq, snd_seq_remove_events_t *rmp)
snd_seq_drain_output_buffer(seq);
} else {
char *ep;
int len;
size_t len;
snd_seq_event_t *ev;
ep = seq->obuf;
while (ep - seq->obuf < seq->obufused) {
while (ep - seq->obuf < (ssize_t)seq->obufused) {
ev = (snd_seq_event_t *) ep;
len = snd_seq_event_length(ev);

View file

@ -32,10 +32,10 @@ struct snd_seq {
int fd;
/* buffers */
char *obuf; /* output buffer */
int obufsize; /* output buffer size */
int obufused; /* output buffer used size */
size_t obufsize; /* output buffer size */
size_t obufused; /* output buffer used size */
char *ibuf; /* input buffer */
int ibufsize; /* input buffer size */
size_t ibufsize; /* input buffer size */
/* input queue */
int cells;
snd_seq_cell_t *head;

View file

@ -202,7 +202,7 @@ ssize_t snd_timer_read(snd_timer_t *handle, void *buffer, size_t size)
ssize_t result;
tmr = handle;
if (!tmr || (!buffer && size > 0) || size < 0)
if (!tmr || (!buffer && size > 0))
return -EINVAL;
result = read(tmr->fd, buffer, size);
if (result < 0)

View file

@ -10,8 +10,11 @@
#endif
#define USED_RATE 48000
#define LATENCY_LIMIT 8192 /* in bytes */
#define LOOP_LIMIT (30 * 176400) /* 30 seconds */
//#define LATENCY_MIN 8192
#define LATENCY_MIN 32
#define LATENCY_MAX 8192 /* in bytes */
//#define LOOP_LIMIT (8192UL * 2)
#define LOOP_LIMIT (30 * 176400UL) /* 30 seconds */
#if 0
static char *xitoa(int aaa)
@ -32,7 +35,6 @@ static int syncro(snd_pcm_t *phandle, snd_pcm_t *chandle)
bzero(&cinfo, sizeof(cinfo));
pinfo.channel = SND_PCM_CHANNEL_PLAYBACK;
cinfo.channel = SND_PCM_CHANNEL_CAPTURE;
pinfo.mode = cinfo.mode = SND_PCM_MODE_STREAM;
if ((err = snd_pcm_channel_info(phandle, &pinfo)) < 0) {
printf("Playback info error: %s\n", snd_strerror(err));
exit(0);
@ -83,7 +85,7 @@ int setparams(snd_pcm_t *phandle, snd_pcm_t *chandle, int sync, int *queue)
params.format.voices = 2;
params.format.rate = USED_RATE;
params.start_mode = SND_PCM_START_GO;
params.stop_mode = SND_PCM_STOP_STOP;
params.xrun_mode = SND_PCM_XRUN_DRAIN;
params.time = 1;
*queue += 16;
#if 0
@ -95,46 +97,50 @@ int setparams(snd_pcm_t *phandle, snd_pcm_t *chandle, int sync, int *queue)
if (sync)
syncro_id(&params.sync);
__again:
if (*queue > LATENCY_LIMIT)
if (*queue > LATENCY_MAX)
return -1;
again = 0;
params.channel = SND_PCM_CHANNEL_PLAYBACK;
params.frag_size = *queue;
#ifdef USE_BLOCK_MODE
params.buf.block.frag_size = *queue;
params.buffer_size = *queue * 2;
params.buf.block.frags_min = 1;
params.buf.block.frags_max = -1;
#else
params.buf.stream.queue_size = *queue;
params.buffer_size = *queue;
params.buf.stream.bytes_min = 2;
#endif
if ((err = snd_pcm_plugin_params(phandle, &params)) < 0) {
if ((err = snd_pcm_channel_params(phandle, &params)) < 0) {
printf("Playback params error: %s\n", snd_strerror(err));
exit(0);
}
params.channel = SND_PCM_CHANNEL_CAPTURE;
if ((err = snd_pcm_plugin_params(chandle, &params)) < 0) {
if ((err = snd_pcm_channel_params(chandle, &params)) < 0) {
printf("Capture params error: %s\n", snd_strerror(err));
exit(0);
}
bzero(&psetup, sizeof(psetup));
psetup.channel = SND_PCM_CHANNEL_PLAYBACK;
if ((err = snd_pcm_plugin_setup(phandle, &psetup)) < 0) {
if ((err = snd_pcm_channel_setup(phandle, &psetup)) < 0) {
printf("Playback setup error: %s\n", snd_strerror(err));
exit(0);
}
bzero(&csetup, sizeof(csetup));
csetup.channel = SND_PCM_CHANNEL_CAPTURE;
if ((err = snd_pcm_plugin_setup(chandle, &csetup)) < 0) {
if ((err = snd_pcm_channel_setup(chandle, &csetup)) < 0) {
printf("Capture setup error: %s\n", snd_strerror(err));
exit(0);
}
if (psetup.buf.stream.queue_size > *queue) {
*queue = psetup.buf.stream.queue_size;
#ifdef USE_BLOCK_MODE
if (psetup.buffer_size / 2 > *queue) {
*queue = psetup.buffer_size / 2;
again++;
}
if (csetup.buf.stream.queue_size > *queue) {
*queue = csetup.buf.stream.queue_size;
#else
if (psetup.buffer_size > *queue) {
*queue = psetup.buffer_size;
again++;
}
#endif
if (again)
goto __again;
if ((err = snd_pcm_playback_prepare(phandle)) < 0) {
@ -152,11 +158,13 @@ int setparams(snd_pcm_t *phandle, snd_pcm_t *chandle, int sync, int *queue)
*queue,
#endif
psetup.format.rate, csetup.format.rate);
printf("Fragment boundary = %li/%li, Position boundary = %li/%li\n", (long)psetup.frag_boundary, (long)csetup.frag_boundary, (long)psetup.pos_boundary, (long)psetup.pos_boundary);
printf("Frags = %li/%li, Buffer size = %li/%li\n", (long)psetup.frags, (long)csetup.frags, (long)psetup.buffer_size, (long)csetup.buffer_size);
fflush(stdout);
return 0;
}
void showstat(snd_pcm_t *handle, int channel, snd_pcm_channel_status_t *rstatus)
void showstat(snd_pcm_t *handle, int channel, snd_pcm_channel_status_t *rstatus, size_t bytes)
{
int err;
snd_pcm_channel_status_t status;
@ -165,16 +173,21 @@ void showstat(snd_pcm_t *handle, int channel, snd_pcm_channel_status_t *rstatus)
str = channel == SND_PCM_CHANNEL_CAPTURE ? "Capture" : "Playback";
bzero(&status, sizeof(status));
status.channel = channel;
status.mode = SND_PCM_MODE_STREAM;
if ((err = snd_pcm_plugin_status(handle, &status)) < 0) {
if ((err = snd_pcm_channel_status(handle, &status)) < 0) {
printf("Channel %s status error: %s\n", str, snd_strerror(err));
exit(0);
}
printf("%s:\n", str);
printf(" status = %i\n", status.status);
printf(" position = %u\n", status.scount);
printf(" free = %i\n", status.free);
printf(" count = %i\n", status.count);
printf(" bytes = %i\n", bytes);
printf(" frag_io = %li\n", (long)status.frag_io);
printf(" frag_data = %li\n", (long)status.frag_data);
printf(" frag_used = %li\n", (long)status.frags_used);
printf(" frag_free = %li\n", (long)status.frags_free);
printf(" pos_io = %li\n", (long)status.pos_io);
printf(" pos_data = %li\n", (long)status.pos_data);
printf(" bytes_used = %li\n", (long)status.bytes_used);
printf(" bytes_free = %li\n", (long)status.bytes_free);
if (rstatus)
*rstatus = status;
}
@ -210,24 +223,26 @@ long timediff(struct timeval t1, struct timeval t2)
return (t1.tv_sec * 1000000) + l;
}
long readbuf(snd_pcm_t *handle, char *buf, long len)
long readbuf(snd_pcm_t *handle, char *buf, long len, size_t *bytes)
{
long r;
do {
r = snd_pcm_plugin_read(handle, buf, len);
r = snd_pcm_read(handle, buf, len);
} while (r == -EAGAIN);
if (r > 0)
*bytes += r;
// printf("read = %li\n", r);
// showstat(handle, SND_PCM_CHANNEL_CAPTURE, NULL);
return r;
}
long writebuf(snd_pcm_t *handle, char *buf, long len)
long writebuf(snd_pcm_t *handle, char *buf, long len, size_t *bytes)
{
long r;
while (len > 0) {
r = snd_pcm_plugin_write(handle, buf, len);
r = snd_pcm_write(handle, buf, len);
#ifndef USE_BLOCK_MODE
if (r == -EAGAIN)
continue;
@ -238,6 +253,7 @@ long writebuf(snd_pcm_t *handle, char *buf, long len)
// showstat(handle, SND_PCM_CHANNEL_PLAYBACK, NULL);
buf += r;
len -= r;
*bytes += r;
}
return 0;
}
@ -245,23 +261,23 @@ long writebuf(snd_pcm_t *handle, char *buf, long len)
int main(void)
{
snd_pcm_t *phandle, *chandle;
char buffer[4096 * 2]; /* max two fragments by 4096 bytes */
char buffer[LATENCY_MAX]; /* max two fragments by 4096 bytes */
int pcard = 0, pdevice = 0;
int ccard = 0, cdevice = 0;
int err, latency = 16;
int err, latency = LATENCY_MIN - 16;
int size, ok;
int sync;
snd_pcm_sync_t ssync;
snd_pcm_channel_status_t pstatus, cstatus;
long r;
ssize_t r;
size_t bytes_in, bytes_out;
// latency = 4096 - 16;
setscheduler();
if ((err = snd_pcm_open(&phandle, pcard, pdevice, SND_PCM_OPEN_PLAYBACK)) < 0) {
if ((err = snd_pcm_plug_open(&phandle, pcard, pdevice, SND_PCM_OPEN_PLAYBACK|SND_PCM_NONBLOCK_PLAYBACK)) < 0) {
printf("Playback open error: %s\n", snd_strerror(err));
return 0;
}
if ((err = snd_pcm_open(&chandle, ccard, cdevice, SND_PCM_OPEN_CAPTURE)) < 0) {
if ((err = snd_pcm_plug_open(&chandle, ccard, cdevice, SND_PCM_OPEN_CAPTURE|SND_PCM_NONBLOCK_CAPTURE)) < 0) {
printf("Record open error: %s\n", snd_strerror(err));
return 0;
}
@ -273,14 +289,21 @@ int main(void)
sync = syncro(phandle, chandle);
if (sync)
printf("Using hardware synchronization mode\n");
printf("Loop limit is %li bytes\n", LOOP_LIMIT);
while (1) {
bytes_in = bytes_out = 0;
if (setparams(phandle, chandle, sync, &latency) < 0)
break;
memset(buffer, 0, latency);
if (writebuf(phandle, buffer, latency) < 0)
if (snd_pcm_format_set_silence(SND_PCM_SFMT_S16_LE, buffer, latency) < 0) {
fprintf(stderr, "silence error\n");
break;
}
if (writebuf(phandle, buffer, latency, &bytes_out) < 0) {
fprintf(stderr, "write error\n");
break;
}
#ifdef USE_BLOCK_MODE /* at least two fragments MUST BE filled !!! */
if (writebuf(phandle, buffer, latency) < 0)
if (writebuf(phandle, buffer, latency, &bytes_out) < 0)
break;
#endif
if (sync) {
@ -301,15 +324,14 @@ int main(void)
}
ok = 1;
size = 0;
while (ok && size < LOOP_LIMIT) {
if ((r = readbuf(chandle, buffer, latency)) < 0)
while (ok && bytes_in < LOOP_LIMIT) {
if ((r = readbuf(chandle, buffer, latency, &bytes_in)) < 0)
ok = 0;
if (writebuf(phandle, buffer, r) < 0)
if (r > 0 && writebuf(phandle, buffer, r, &bytes_out) < 0)
ok = 0;
size += r;
}
showstat(phandle, SND_PCM_CHANNEL_PLAYBACK, &pstatus);
showstat(chandle, SND_PCM_CHANNEL_CAPTURE, &cstatus);
showstat(phandle, SND_PCM_CHANNEL_PLAYBACK, &pstatus, bytes_out);
showstat(chandle, SND_PCM_CHANNEL_CAPTURE, &cstatus, bytes_in);
snd_pcm_capture_flush(chandle);
snd_pcm_playback_flush(phandle);
if (ok) {