Fix endianess with dmix plugin

Allow different endianess with the generic dmix code, mainly for
big-endian architectures.
This commit is contained in:
Takashi Iwai 2005-09-19 12:37:08 +00:00
parent 148c2b8e7c
commit 5bf3b31cf1
5 changed files with 177 additions and 12 deletions

View file

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

View file

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

View file

@ -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 <byteswap.h>
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

View file

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

View file

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