]> git.alsa-project.org Git - alsa-lib.git/commitdiff
Fix endianess with dmix plugin
authorTakashi Iwai <tiwai@suse.de>
Mon, 19 Sep 2005 12:37:08 +0000 (12:37 +0000)
committerTakashi Iwai <tiwai@suse.de>
Mon, 19 Sep 2005 12:37:08 +0000 (12:37 +0000)
Allow different endianess with the generic dmix code, mainly for
big-endian architectures.

src/pcm/pcm_direct.c
src/pcm/pcm_dmix.c
src/pcm/pcm_dmix_generic.c
src/pcm/pcm_dmix_i386.c
src/pcm/pcm_dmix_x86_64.c

index 1d2252a7d871e56c158a50f79482ca6d5c965770..8d1f05c77f51fb0443b133cba9e8299a905cb40b 100644 (file)
  *
  */
  
+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");
index 40d072dd1fac32c8cbb09661262eb2aab127caca..1d27c09eec6363507536be8eb41e71ea58ba82ac 100644 (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;
        }
index f8c023e593033b6ad50c34fc7662f406b5e0117b..ed6ebe6f1d409e7b58fb2cad7fbc9936a3dbb24f 100644 (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
index 758a58265750761e353f46255a465e9fa8af31c4..7cbf723dcd7165664ddb1f27720588f2d280ea69 100644 (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;
index 2e9a521280265fdc0fd2c1c85495cf8b5e2c71ab..a64888f26fdad6f1e9857d677da608f01d34b942 100644 (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;