mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-10-28 05:40:23 -04:00
Merged pcm2 branch.
This commit is contained in:
parent
986c1500d2
commit
1cd6778173
40 changed files with 5053 additions and 3045 deletions
|
|
@ -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"
|
||||
])
|
||||
|
|
|
|||
|
|
@ -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 $@
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
#define UNUSED __attribute__ ((unused))
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
269
include/pcm.h
269
include/pcm.h
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
800
src/pcm/pcm.c
800
src/pcm/pcm.c
|
|
@ -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
471
src/pcm/pcm_hw.c
Normal 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);
|
||||
}
|
||||
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
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
824
src/pcm/pcm_plug.c
Normal 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(¶ms1, params, sizeof(*params));
|
||||
if ((err = snd_pcm_plug_format(pcm, ¶ms1, &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);
|
||||
}
|
||||
|
||||
|
||||
1192
src/pcm/pcm_plugin.c
1192
src/pcm/pcm_plugin.c
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
156
src/pcm/plugin/copy.c
Normal 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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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] = {
|
||||
&©_xxx1_xxx1, /* 8h -> 8h */
|
||||
&©_xxx1_xxx1, /* 8h -> 8s */
|
||||
&©_xxx1_xx10, /* 8h -> 16h */
|
||||
&©_xxx1_xx01, /* 8h -> 16s */
|
||||
&©_xxx1_x100, /* 8h -> 24h */
|
||||
&©_xxx1_001x, /* 8h -> 24s */
|
||||
&©_xxx1_1000, /* 8h -> 32h */
|
||||
&©_xxx1_0001, /* 8h -> 32s */
|
||||
&©_xxx1_xxx9, /* 8h ^> 8h */
|
||||
&©_xxx1_xxx9, /* 8h ^> 8s */
|
||||
&©_xxx1_xx90, /* 8h ^> 16h */
|
||||
&©_xxx1_xx09, /* 8h ^> 16s */
|
||||
&©_xxx1_x900, /* 8h ^> 24h */
|
||||
&©_xxx1_009x, /* 8h ^> 24s */
|
||||
&©_xxx1_9000, /* 8h ^> 32h */
|
||||
&©_xxx1_0009, /* 8h ^> 32s */
|
||||
&©_xxx1_xxx1, /* 8s -> 8h */
|
||||
&©_xxx1_xxx1, /* 8s -> 8s */
|
||||
&©_xxx1_xx10, /* 8s -> 16h */
|
||||
&©_xxx1_xx01, /* 8s -> 16s */
|
||||
&©_xxx1_x100, /* 8s -> 24h */
|
||||
&©_xxx1_001x, /* 8s -> 24s */
|
||||
&©_xxx1_1000, /* 8s -> 32h */
|
||||
&©_xxx1_0001, /* 8s -> 32s */
|
||||
&©_xxx1_xxx9, /* 8s ^> 8h */
|
||||
&©_xxx1_xxx9, /* 8s ^> 8s */
|
||||
&©_xxx1_xx90, /* 8s ^> 16h */
|
||||
&©_xxx1_xx09, /* 8s ^> 16s */
|
||||
&©_xxx1_x900, /* 8s ^> 24h */
|
||||
&©_xxx1_009x, /* 8s ^> 24s */
|
||||
&©_xxx1_9000, /* 8s ^> 32h */
|
||||
&©_xxx1_0009, /* 8s ^> 32s */
|
||||
&©_xx12_xxx1, /* 16h -> 8h */
|
||||
&©_xx12_xxx1, /* 16h -> 8s */
|
||||
&©_xx12_xx12, /* 16h -> 16h */
|
||||
&©_xx12_xx21, /* 16h -> 16s */
|
||||
&©_xx12_x120, /* 16h -> 24h */
|
||||
&©_xx12_021x, /* 16h -> 24s */
|
||||
&©_xx12_1200, /* 16h -> 32h */
|
||||
&©_xx12_0021, /* 16h -> 32s */
|
||||
&©_xx12_xxx9, /* 16h ^> 8h */
|
||||
&©_xx12_xxx9, /* 16h ^> 8s */
|
||||
&©_xx12_xx92, /* 16h ^> 16h */
|
||||
&©_xx12_xx29, /* 16h ^> 16s */
|
||||
&©_xx12_x920, /* 16h ^> 24h */
|
||||
&©_xx12_029x, /* 16h ^> 24s */
|
||||
&©_xx12_9200, /* 16h ^> 32h */
|
||||
&©_xx12_0029, /* 16h ^> 32s */
|
||||
&©_xx12_xxx2, /* 16s -> 8h */
|
||||
&©_xx12_xxx2, /* 16s -> 8s */
|
||||
&©_xx12_xx21, /* 16s -> 16h */
|
||||
&©_xx12_xx12, /* 16s -> 16s */
|
||||
&©_xx12_x210, /* 16s -> 24h */
|
||||
&©_xx12_012x, /* 16s -> 24s */
|
||||
&©_xx12_2100, /* 16s -> 32h */
|
||||
&©_xx12_0012, /* 16s -> 32s */
|
||||
&©_xx12_xxxA, /* 16s ^> 8h */
|
||||
&©_xx12_xxxA, /* 16s ^> 8s */
|
||||
&©_xx12_xxA1, /* 16s ^> 16h */
|
||||
&©_xx12_xx1A, /* 16s ^> 16s */
|
||||
&©_xx12_xA10, /* 16s ^> 24h */
|
||||
&©_xx12_01Ax, /* 16s ^> 24s */
|
||||
&©_xx12_A100, /* 16s ^> 32h */
|
||||
&©_xx12_001A, /* 16s ^> 32s */
|
||||
&©_x123_xxx1, /* 24h -> 8h */
|
||||
&©_x123_xxx1, /* 24h -> 8s */
|
||||
&©_x123_xx12, /* 24h -> 16h */
|
||||
&©_x123_xx21, /* 24h -> 16s */
|
||||
&©_x123_x123, /* 24h -> 24h */
|
||||
&©_x123_321x, /* 24h -> 24s */
|
||||
&©_x123_1230, /* 24h -> 32h */
|
||||
&©_x123_0321, /* 24h -> 32s */
|
||||
&©_x123_xxx9, /* 24h ^> 8h */
|
||||
&©_x123_xxx9, /* 24h ^> 8s */
|
||||
&©_x123_xx92, /* 24h ^> 16h */
|
||||
&©_x123_xx29, /* 24h ^> 16s */
|
||||
&©_x123_x923, /* 24h ^> 24h */
|
||||
&©_x123_329x, /* 24h ^> 24s */
|
||||
&©_x123_9230, /* 24h ^> 32h */
|
||||
&©_x123_0329, /* 24h ^> 32s */
|
||||
&©_123x_xxx3, /* 24s -> 8h */
|
||||
&©_123x_xxx3, /* 24s -> 8s */
|
||||
&©_123x_xx32, /* 24s -> 16h */
|
||||
&©_123x_xx23, /* 24s -> 16s */
|
||||
&©_123x_x321, /* 24s -> 24h */
|
||||
&©_123x_123x, /* 24s -> 24s */
|
||||
&©_123x_3210, /* 24s -> 32h */
|
||||
&©_123x_0123, /* 24s -> 32s */
|
||||
&©_123x_xxxB, /* 24s ^> 8h */
|
||||
&©_123x_xxxB, /* 24s ^> 8s */
|
||||
&©_123x_xxB2, /* 24s ^> 16h */
|
||||
&©_123x_xx2B, /* 24s ^> 16s */
|
||||
&©_123x_xB21, /* 24s ^> 24h */
|
||||
&©_123x_12Bx, /* 24s ^> 24s */
|
||||
&©_123x_B210, /* 24s ^> 32h */
|
||||
&©_123x_012B, /* 24s ^> 32s */
|
||||
&©_1234_xxx1, /* 32h -> 8h */
|
||||
&©_1234_xxx1, /* 32h -> 8s */
|
||||
&©_1234_xx12, /* 32h -> 16h */
|
||||
&©_1234_xx21, /* 32h -> 16s */
|
||||
&©_1234_x123, /* 32h -> 24h */
|
||||
&©_1234_321x, /* 32h -> 24s */
|
||||
&©_1234_1234, /* 32h -> 32h */
|
||||
&©_1234_4321, /* 32h -> 32s */
|
||||
&©_1234_xxx9, /* 32h ^> 8h */
|
||||
&©_1234_xxx9, /* 32h ^> 8s */
|
||||
&©_1234_xx92, /* 32h ^> 16h */
|
||||
&©_1234_xx29, /* 32h ^> 16s */
|
||||
&©_1234_x923, /* 32h ^> 24h */
|
||||
&©_1234_329x, /* 32h ^> 24s */
|
||||
&©_1234_9234, /* 32h ^> 32h */
|
||||
&©_1234_4329, /* 32h ^> 32s */
|
||||
&©_1234_xxx4, /* 32s -> 8h */
|
||||
&©_1234_xxx4, /* 32s -> 8s */
|
||||
&©_1234_xx43, /* 32s -> 16h */
|
||||
&©_1234_xx34, /* 32s -> 16s */
|
||||
&©_1234_x432, /* 32s -> 24h */
|
||||
&©_1234_234x, /* 32s -> 24s */
|
||||
&©_1234_4321, /* 32s -> 32h */
|
||||
&©_1234_1234, /* 32s -> 32s */
|
||||
&©_1234_xxxC, /* 32s ^> 8h */
|
||||
&©_1234_xxxC, /* 32s ^> 8s */
|
||||
&©_1234_xxC3, /* 32s ^> 16h */
|
||||
&©_1234_xx3C, /* 32s ^> 16s */
|
||||
&©_1234_xC32, /* 32s ^> 24h */
|
||||
&©_1234_23Cx, /* 32s ^> 24s */
|
||||
&©_1234_C321, /* 32s ^> 32h */
|
||||
&©_1234_123C, /* 32s ^> 32s */
|
||||
static void *copy_labels[4] = {
|
||||
&©_8,
|
||||
&©_16,
|
||||
&©_32,
|
||||
&©_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
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
104
test/latency.c
104
test/latency.c
|
|
@ -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(¶ms.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, ¶ms)) < 0) {
|
||||
if ((err = snd_pcm_channel_params(phandle, ¶ms)) < 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, ¶ms)) < 0) {
|
||||
if ((err = snd_pcm_channel_params(chandle, ¶ms)) < 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) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue