*
*/
+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:
int snd_pcm_direct_semaphore_create_or_connect(snd_pcm_direct_t *dmix)
{
+ union semun s;
struct semid_ds buf;
int i;
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;
}
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");
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) {
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;
}
#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,
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