mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-11-02 09:01:48 -05:00
Fix endianess with dmix plugin
Allow different endianess with the generic dmix code, mainly for big-endian architectures.
This commit is contained in:
parent
148c2b8e7c
commit
5bf3b31cf1
5 changed files with 177 additions and 12 deletions
|
|
@ -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:
|
* FIXME:
|
||||||
|
|
@ -50,6 +56,7 @@
|
||||||
|
|
||||||
int snd_pcm_direct_semaphore_create_or_connect(snd_pcm_direct_t *dmix)
|
int snd_pcm_direct_semaphore_create_or_connect(snd_pcm_direct_t *dmix)
|
||||||
{
|
{
|
||||||
|
union semun s;
|
||||||
struct semid_ds buf;
|
struct semid_ds buf;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
|
@ -60,13 +67,15 @@ int snd_pcm_direct_semaphore_create_or_connect(snd_pcm_direct_t *dmix)
|
||||||
if (dmix->ipc_gid < 0)
|
if (dmix->ipc_gid < 0)
|
||||||
return 0;
|
return 0;
|
||||||
for (i = 0; i < DIRECT_IPC_SEMS; i++) {
|
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;
|
int err = -errno;
|
||||||
snd_pcm_direct_semaphore_discard(dmix);
|
snd_pcm_direct_semaphore_discard(dmix);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
buf.sem_perm.gid = dmix->ipc_gid;
|
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;
|
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);
|
ret = snd_pcm_hw_params_set_format(spcm, hw_params, params->format);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
snd_pcm_format_t format;
|
snd_pcm_format_t format;
|
||||||
|
if (dmix->type == SND_PCM_TYPE_DMIX) {
|
||||||
switch (params->format) {
|
switch (params->format) {
|
||||||
case SND_PCM_FORMAT_S32: format = SND_PCM_FORMAT_S16; break;
|
case SND_PCM_FORMAT_S32_LE:
|
||||||
case SND_PCM_FORMAT_S16: format = SND_PCM_FORMAT_S32; break;
|
case SND_PCM_FORMAT_S32_BE:
|
||||||
|
case SND_PCM_FORMAT_S16_LE:
|
||||||
|
case SND_PCM_FORMAT_S16_BE:
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
SNDERR("invalid format");
|
SNDERR("invalid format");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
format = params->format;
|
||||||
ret = snd_pcm_hw_params_set_format(spcm, hw_params, format);
|
ret = snd_pcm_hw_params_set_format(spcm, hw_params, format);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
SNDERR("requested or auto-format is not available");
|
SNDERR("requested or auto-format is not available");
|
||||||
|
|
|
||||||
|
|
@ -159,7 +159,8 @@ static void mix_areas(snd_pcm_direct_t *dmix,
|
||||||
unsigned int chn, dchn, channels;
|
unsigned int chn, dchn, channels;
|
||||||
|
|
||||||
channels = dmix->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;
|
signed short *src;
|
||||||
volatile signed short *dst;
|
volatile signed short *dst;
|
||||||
if (dmix->interleaved) {
|
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 */
|
params.period_time = 125000; /* 0.125 seconds */
|
||||||
|
|
||||||
/* sorry, limited features */
|
/* sorry, limited features */
|
||||||
if (params.format != SND_PCM_FORMAT_S16 &&
|
if (! (dmix_supported_format & (1ULL << params.format))) {
|
||||||
params.format != SND_PCM_FORMAT_S32) {
|
SNDERR("Unsupported format");
|
||||||
SNDERR("invalid format, specify s16 or s32");
|
|
||||||
snd_config_delete(sconf);
|
snd_config_delete(sconf);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,7 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
|
||||||
#define IS_CONCURRENT 0 /* no race check */
|
#define IS_CONCURRENT 0 /* no race check */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if IS_CONCURRENT
|
||||||
static void mix_areas1(unsigned int size,
|
static void mix_areas1(unsigned int size,
|
||||||
volatile signed short *dst, signed short *src,
|
volatile signed short *dst, signed short *src,
|
||||||
volatile signed int *sum, size_t dst_step,
|
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_areas1 = mix_areas1;
|
||||||
dmix->u.dmix.mix_areas2 = mix_areas2;
|
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
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,9 @@
|
||||||
#undef MIX_AREAS2
|
#undef MIX_AREAS2
|
||||||
#undef LOCK_PREFIX
|
#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)
|
static void mix_select_callbacks(snd_pcm_direct_t *dmix)
|
||||||
{
|
{
|
||||||
FILE *in;
|
FILE *in;
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,9 @@
|
||||||
#undef MIX_AREAS2
|
#undef MIX_AREAS2
|
||||||
#undef LOCK_PREFIX
|
#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)
|
static void mix_select_callbacks(snd_pcm_direct_t *dmix)
|
||||||
{
|
{
|
||||||
FILE *in;
|
FILE *in;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue