From: Takashi Iwai Date: Mon, 19 Sep 2005 12:37:08 +0000 (+0000) Subject: Fix endianess with dmix plugin X-Git-Tag: v1.0.10rc2~9 X-Git-Url: https://git.alsa-project.org/?a=commitdiff_plain;h=5bf3b31cf18f73151c1f90d6ac9c087f18b9c0d2;p=alsa-lib.git Fix endianess with dmix plugin Allow different endianess with the generic dmix code, mainly for big-endian architectures. --- diff --git a/src/pcm/pcm_direct.c b/src/pcm/pcm_direct.c index 1d2252a7..8d1f05c7 100644 --- a/src/pcm/pcm_direct.c +++ b/src/pcm/pcm_direct.c @@ -42,6 +42,12 @@ * */ +union semun { + int val; /* Value for SETVAL */ + struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */ + unsigned short *array; /* Array for GETALL, SETALL */ + struct seminfo *__buf; /* Buffer for IPC_INFO (Linux specific) */ +}; /* * FIXME: @@ -50,6 +56,7 @@ int snd_pcm_direct_semaphore_create_or_connect(snd_pcm_direct_t *dmix) { + union semun s; struct semid_ds buf; int i; @@ -60,13 +67,15 @@ int snd_pcm_direct_semaphore_create_or_connect(snd_pcm_direct_t *dmix) if (dmix->ipc_gid < 0) return 0; for (i = 0; i < DIRECT_IPC_SEMS; i++) { - if (semctl(dmix->semid, i, IPC_STAT, &buf) < 0) { + s.buf = &buf; + if (semctl(dmix->semid, i, IPC_STAT, s) < 0) { int err = -errno; snd_pcm_direct_semaphore_discard(dmix); return err; } buf.sem_perm.gid = dmix->ipc_gid; - semctl(dmix->semid, i, IPC_SET, &buf); + s.buf = &buf; + semctl(dmix->semid, i, IPC_SET, s); } return 0; } @@ -785,13 +794,19 @@ int snd_pcm_direct_initialize_slave(snd_pcm_direct_t *dmix, snd_pcm_t *spcm, str ret = snd_pcm_hw_params_set_format(spcm, hw_params, params->format); if (ret < 0) { snd_pcm_format_t format; - switch (params->format) { - case SND_PCM_FORMAT_S32: format = SND_PCM_FORMAT_S16; break; - case SND_PCM_FORMAT_S16: format = SND_PCM_FORMAT_S32; break; - default: - SNDERR("invalid format"); - return -EINVAL; + if (dmix->type == SND_PCM_TYPE_DMIX) { + switch (params->format) { + case SND_PCM_FORMAT_S32_LE: + case SND_PCM_FORMAT_S32_BE: + case SND_PCM_FORMAT_S16_LE: + case SND_PCM_FORMAT_S16_BE: + break; + default: + SNDERR("invalid format"); + return -EINVAL; + } } + format = params->format; ret = snd_pcm_hw_params_set_format(spcm, hw_params, format); if (ret < 0) { SNDERR("requested or auto-format is not available"); diff --git a/src/pcm/pcm_dmix.c b/src/pcm/pcm_dmix.c index 40d072dd..1d27c09e 100644 --- a/src/pcm/pcm_dmix.c +++ b/src/pcm/pcm_dmix.c @@ -159,7 +159,8 @@ static void mix_areas(snd_pcm_direct_t *dmix, unsigned int chn, dchn, channels; channels = dmix->channels; - if (dmix->shmptr->s.format == SND_PCM_FORMAT_S16) { + if (dmix->shmptr->s.format == SND_PCM_FORMAT_S16_LE || + dmix->shmptr->s.format == SND_PCM_FORMAT_S16_BE) { signed short *src; volatile signed short *dst; if (dmix->interleaved) { @@ -1171,9 +1172,8 @@ int _snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name, params.period_time = 125000; /* 0.125 seconds */ /* sorry, limited features */ - if (params.format != SND_PCM_FORMAT_S16 && - params.format != SND_PCM_FORMAT_S32) { - SNDERR("invalid format, specify s16 or s32"); + if (! (dmix_supported_format & (1ULL << params.format))) { + SNDERR("Unsupported format"); snd_config_delete(sconf); return -EINVAL; } diff --git a/src/pcm/pcm_dmix_generic.c b/src/pcm/pcm_dmix_generic.c index f8c023e5..ed6ebe6f 100644 --- a/src/pcm/pcm_dmix_generic.c +++ b/src/pcm/pcm_dmix_generic.c @@ -47,6 +47,7 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old, #define IS_CONCURRENT 0 /* no race check */ #endif +#if IS_CONCURRENT static void mix_areas1(unsigned int size, volatile signed short *dst, signed short *src, volatile signed int *sum, size_t dst_step, @@ -114,3 +115,146 @@ static void mix_select_callbacks(snd_pcm_direct_t *dmix) dmix->u.dmix.mix_areas1 = mix_areas1; dmix->u.dmix.mix_areas2 = mix_areas2; } + +#else + +/* non-concurrent version, supporting both endians */ +static unsigned long long dmix_supported_format = + (1ULL << SND_PCM_FORMAT_S16_LE) | (1ULL << SND_PCM_FORMAT_S32_LE) | + (1ULL << SND_PCM_FORMAT_S16_BE) | (1ULL << SND_PCM_FORMAT_S32_BE); + +#include + +static void mix_areas1_native(unsigned int size, + volatile signed short *dst, signed short *src, + volatile signed int *sum, size_t dst_step, + size_t src_step, size_t sum_step) +{ + register signed int sample; + + for (;;) { + sample = *src; + if (! *dst) { + *sum = sample; + *dst = *src; + } else { + sample += *sum; + *sum = sample; + if (sample > 0x7fff) + sample = 0x7fff; + else if (sample < -0x8000) + sample = -0x8000; + *dst = sample; + } + if (!--size) + return; + src = (signed short *) ((char *)src + src_step); + dst = (signed short *) ((char *)dst + dst_step); + sum = (signed int *) ((char *)sum + sum_step); + } +} + +static void mix_areas2_native(unsigned int size, + volatile signed int *dst, signed int *src, + volatile signed int *sum, size_t dst_step, + size_t src_step, size_t sum_step) +{ + register signed int sample; + + for (;;) { + sample = *src / 256; + if (! *dst) { + *sum = sample; + *dst = *src; + } else { + sample += *sum; + *sum = sample; + if (sample > 0x7fffff) + sample = 0x7fffffff; + else if (sample < -0x800000) + sample = -0x80000000; + else + sample *= 256; + *dst = sample; + } + if (!--size) + return; + src = (signed int *) ((char *)src + src_step); + dst = (signed int *) ((char *)dst + dst_step); + sum = (signed int *) ((char *)sum + sum_step); + } +} + +static void mix_areas1_swap(unsigned int size, + volatile signed short *dst, signed short *src, + volatile signed int *sum, size_t dst_step, + size_t src_step, size_t sum_step) +{ + register signed int sample; + + for (;;) { + sample = bswap_16(*src); + if (! *dst) { + *sum = sample; + *dst = *src; + } else { + sample += *sum; + *sum = sample; + if (sample > 0x7fff) + sample = 0x7fff; + else if (sample < -0x8000) + sample = -0x8000; + *dst = bswap_16((signed short)sample); + } + if (!--size) + return; + src = (signed short *) ((char *)src + src_step); + dst = (signed short *) ((char *)dst + dst_step); + sum = (signed int *) ((char *)sum + sum_step); + } +} + +static void mix_areas2_swap(unsigned int size, + volatile signed int *dst, signed int *src, + volatile signed int *sum, size_t dst_step, + size_t src_step, size_t sum_step) +{ + register signed int sample; + + for (;;) { + sample = bswap_32(*src) / 256; + if (! *dst) { + *sum = sample; + *dst = *src; + } else { + sample += *sum; + *sum = sample; + if (sample > 0x7fffff) + sample = 0x7fffffff; + else if (sample < -0x800000) + sample = -0x80000000; + else + sample *= 256; + *dst = bswap_32(sample); + } + if (!--size) + return; + src = (signed int *) ((char *)src + src_step); + dst = (signed int *) ((char *)dst + dst_step); + sum = (signed int *) ((char *)sum + sum_step); + } +} + + +static void mix_select_callbacks(snd_pcm_direct_t *dmix) +{ + if (snd_pcm_format_cpu_endian(dmix->shmptr->s.format)) { + dmix->u.dmix.mix_areas1 = mix_areas1_native; + dmix->u.dmix.mix_areas2 = mix_areas2_native; + } else { + dmix->u.dmix.mix_areas1 = mix_areas1_swap; + dmix->u.dmix.mix_areas2 = mix_areas2_swap; + } +} + +#endif diff --git a/src/pcm/pcm_dmix_i386.c b/src/pcm/pcm_dmix_i386.c index 758a5826..7cbf723d 100644 --- a/src/pcm/pcm_dmix_i386.c +++ b/src/pcm/pcm_dmix_i386.c @@ -22,6 +22,9 @@ #undef MIX_AREAS2 #undef LOCK_PREFIX +static unsigned long long dmix_supported_format = + (1ULL << SND_PCM_FORMAT_S16_LE) | (1ULL << SND_PCM_FORMAT_S32_LE); + static void mix_select_callbacks(snd_pcm_direct_t *dmix) { FILE *in; diff --git a/src/pcm/pcm_dmix_x86_64.c b/src/pcm/pcm_dmix_x86_64.c index 2e9a5212..a64888f2 100644 --- a/src/pcm/pcm_dmix_x86_64.c +++ b/src/pcm/pcm_dmix_x86_64.c @@ -18,6 +18,9 @@ #undef MIX_AREAS2 #undef LOCK_PREFIX +static unsigned long long dmix_supported_format = + (1ULL << SND_PCM_FORMAT_S16_LE) | (1ULL << SND_PCM_FORMAT_S32_LE); + static void mix_select_callbacks(snd_pcm_direct_t *dmix) { FILE *in;