support multiple sound drivers, add sdl
authorGrazvydas Ignotas <notasas@gmail.com>
Sun, 23 Jun 2013 19:23:57 +0000 (22:23 +0300)
committerGrazvydas Ignotas <notasas@gmail.com>
Sun, 23 Jun 2013 19:23:57 +0000 (22:23 +0300)
linux/sndout_oss.c
linux/sndout_oss.h
sndout.c [new file with mode: 0644]
sndout.h [new file with mode: 0644]
sndout_sdl.c [new file with mode: 0644]
sndout_sdl.h [new file with mode: 0644]

index 0df17b2..c0b775a 100644 (file)
@@ -20,6 +20,8 @@
 
 #include "sndout_oss.h"
 
+int sndout_oss_frag_frames = 1;
+
 static int sounddev = -1, mixerdev = -1;
 static int can_write_safe;
 
@@ -47,7 +49,7 @@ void sndout_oss_stop(void)
        sounddev = -1;
 }
 
-int sndout_oss_start(int rate, int stereo, int frames_in_frag)
+int sndout_oss_start(int rate, int stereo)
 {
        static int s_oldrate = 0, s_oldstereo = 0;
        int frag, bsize, bits, ret;
@@ -69,10 +71,11 @@ int sndout_oss_start(int rate, int stereo, int frames_in_frag)
                }
        }
 
-       // try to fit frames_in_frag frames worth of data in fragment
+       // try to fit sndout_oss_frag_frames (video) frames
+       // worth of sound data in OSS fragment
        // ignore mono because it's unlikely to be used and
        // both GP2X and Wiz mixes mono to stereo anyway.
-       bsize = (frames_in_frag * rate / 50) * 4;
+       bsize = (sndout_oss_frag_frames * rate / 50) * 4;
 
        for (frag = 0; bsize; bsize >>= 1, frag++)
                ;
@@ -164,8 +167,9 @@ int sndout_oss_can_write(int bytes)
        return bi.bytes - bi.fragsize >= bytes ? 1 : 0;
 }
 
-void sndout_oss_sync(void)
+void sndout_oss_wait(void)
 {
+       // FIXME?
        ioctl(sounddev, SOUND_PCM_SYNC, 0);
 }
 
index 0b3fe6c..fde9ff6 100644 (file)
@@ -1,9 +1,12 @@
 int  sndout_oss_init(void);
-int  sndout_oss_start(int rate, int stereo, int frames_in_frag);
+int  sndout_oss_start(int rate, int stereo);
 void sndout_oss_stop(void);
 int  sndout_oss_write(const void *buff, int len);
 int  sndout_oss_write_nb(const void *buff, int len);
 int  sndout_oss_can_write(int bytes);
-void sndout_oss_sync(void);
+void sndout_oss_wait(void);
 void sndout_oss_setvol(int l, int r);
 void sndout_oss_exit(void);
+
+/* make oss fragment size to fit this much video frames */
+extern int sndout_oss_frag_frames;
diff --git a/sndout.c b/sndout.c
new file mode 100644 (file)
index 0000000..ba34f3c
--- /dev/null
+++ b/sndout.c
@@ -0,0 +1,80 @@
+/*
+ * (C) notaz, 2013
+ *
+ * This work is licensed under the terms of any of these licenses
+ * (at your option):
+ *  - GNU GPL, version 2 or later.
+ *  - GNU LGPL, version 2.1 or later.
+ *  - MAME license.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "linux/sndout_oss.h"
+#include "sndout_sdl.h"
+#include "sndout.h"
+
+static int sndout_null_init(void)
+{
+       return 0;
+}
+
+static void sndout_null_exit(void)
+{
+}
+
+static int sndout_null_start(int rate, int stereo)
+{
+       return 0;
+}
+
+static void sndout_null_stop(void)
+{
+}
+
+static void sndout_null_wait(void)
+{
+}
+
+static int sndout_null_write_nb(const void *data, int bytes)
+{
+       return bytes;
+}
+
+#define SNDOUT_DRIVER(name) { \
+       #name, \
+       sndout_##name##_init, \
+       sndout_##name##_exit, \
+       sndout_##name##_start, \
+       sndout_##name##_stop, \
+       sndout_##name##_wait, \
+       sndout_##name##_write_nb, \
+}
+
+static struct sndout_driver sndout_avail[] =
+{
+#ifdef HAVE_SDL
+       SNDOUT_DRIVER(sdl),
+#endif
+#ifdef HAVE_OSS
+       SNDOUT_DRIVER(oss),
+#endif
+       SNDOUT_DRIVER(null)
+};
+
+struct sndout_driver sndout_current;
+
+void sndout_init(void)
+{
+       int i;
+
+       for (i = 0; i < sizeof(sndout_avail) / sizeof(sndout_avail[0]); i++) {
+               if (sndout_avail[i].init() == 0)
+                       break;
+       }
+
+       memcpy(&sndout_current, &sndout_avail[i], sizeof(sndout_current));
+       printf("using %s audio output driver\n", sndout_current.name);
+}
diff --git a/sndout.h b/sndout.h
new file mode 100644 (file)
index 0000000..cd416c5
--- /dev/null
+++ b/sndout.h
@@ -0,0 +1,43 @@
+#ifndef LIBPICOFE_SNDOUT_H
+#define LIBPICOFE_SNDOUT_H
+
+struct sndout_driver {
+       const char *name;
+       int  (*init)(void);
+       void (*exit)(void);
+       int  (*start)(int rate, int stereo);
+       void (*stop)(void);
+       void (*wait)(void);
+       int  (*write_nb)(const void *data, int bytes);
+};
+
+extern struct sndout_driver sndout_current;
+
+void sndout_init(void);
+
+static inline void sndout_exit(void)
+{
+       sndout_current.exit();
+}
+
+static inline int sndout_start(int rate, int stereo)
+{
+       return sndout_current.start(rate, stereo);
+}
+
+static inline void sndout_stop(void)
+{
+       sndout_current.stop();
+}
+
+static inline void sndout_wait(void)
+{
+       sndout_current.wait();
+}
+
+static inline int sndout_write_nb(const void *data, int bytes)
+{
+       return sndout_current.write_nb(data, bytes);
+}
+
+#endif // LIBPICOFE_SNDOUT_H
diff --git a/sndout_sdl.c b/sndout_sdl.c
new file mode 100644 (file)
index 0000000..83b3ea2
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * (C) notaz, 2013
+ *
+ * This work is licensed under the terms of any of these licenses
+ * (at your option):
+ *  - GNU GPL, version 2 or later.
+ *  - GNU LGPL, version 2.1 or later.
+ *  - MAME license.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <SDL.h>
+#include "sndout_sdl.h"
+
+// ~1/3s at 44kHz
+// set this to power of 2
+#define BUF_LEN 32768
+#define BUF_MASK (BUF_LEN - 1)
+
+static short buf[BUF_LEN];
+static int buf_w, buf_r;
+static int started;
+
+static void callback(void *userdata, Uint8 *stream, int len)
+{
+       int have = (buf_w - buf_r) & BUF_MASK;
+       int buf_left = BUF_LEN - buf_r;
+
+       len /= 2;
+       if (have > len)
+               have = len;
+       if (have > 0) {
+               if (have > buf_left) {
+                       memcpy(stream, buf + buf_r, buf_left * 2);
+                       stream += buf_left * 2;
+                       buf_r = 0;
+                       have -= buf_left;
+                       len -= buf_left;
+               }
+               memcpy(stream, buf + buf_r, have * 2);
+               stream += have * 2;
+               buf_r = (buf_r + have) & BUF_MASK;
+               len -= have;
+       }
+
+       if (len > 0) {
+               // put in some silence..
+               memset(stream, 0, len * 2);
+       }
+}
+
+int sndout_sdl_init(void)
+{
+       int ret;
+
+       ret = SDL_InitSubSystem(SDL_INIT_AUDIO);
+       if (ret != 0)
+               return -1;
+
+       return 0;
+}
+
+int sndout_sdl_start(int rate, int stereo)
+{
+       SDL_AudioSpec desired;
+       int samples, shift;
+       int ret;
+
+       if (started)
+               sndout_sdl_stop();
+
+       desired.freq = rate;
+       desired.format = AUDIO_S16LSB;
+       desired.channels = stereo ? 2 : 1;
+       desired.callback = callback;
+       desired.userdata = NULL;
+
+       samples = rate * 4 * 16 / 1000;
+       for (shift = 8; (1 << shift) < samples; shift++)
+               ;
+       desired.samples = 1 << shift;
+
+       ret = SDL_OpenAudio(&desired, NULL);
+       if (ret != 0) {
+               fprintf(stderr, "SDL_OpenAudio: %s\n", SDL_GetError());
+               return -1;
+       }
+
+       buf_w = buf_r = 0;
+
+       SDL_PauseAudio(0);
+       started = 1;
+
+       return 0;
+}
+
+void sndout_sdl_stop(void)
+{
+       SDL_PauseAudio(1);
+       SDL_CloseAudio();
+       started = 0;
+}
+
+void sndout_sdl_wait(void)
+{
+       int left;
+
+       while (1)
+       {
+               left = (buf_r - buf_w - 2) & BUF_MASK;
+               if (left >= BUF_LEN / 2)
+                       break;
+
+               SDL_Delay(4);
+       }
+}
+
+int sndout_sdl_write_nb(const void *samples, int len)
+{
+       int maxlen = (buf_r - buf_w - 2) & BUF_MASK;
+       int buf_left = BUF_LEN - buf_w;
+       int retval;
+
+       len /= 2;
+       if (len > maxlen)
+               // not enough space
+               len = maxlen;
+       if (len == 0)
+               // totally full
+               return 0;
+
+       retval = len;
+
+       if (len > buf_left) {
+               memcpy(buf + buf_w, samples, buf_left * 2);
+               samples = (const short *)samples + buf_left;
+               len -= buf_left;
+               buf_w = 0;
+       }
+       memcpy(buf + buf_w, samples, len * 2);
+       buf_w = (buf_w + len) & BUF_MASK;
+
+       return retval;
+}
+
+void sndout_sdl_exit(void)
+{
+       if (started)
+               sndout_sdl_stop();
+       SDL_QuitSubSystem(SDL_INIT_AUDIO);
+}
diff --git a/sndout_sdl.h b/sndout_sdl.h
new file mode 100644 (file)
index 0000000..3310f27
--- /dev/null
@@ -0,0 +1,7 @@
+int  sndout_sdl_init(void);
+int  sndout_sdl_start(int rate, int stereo);
+void sndout_sdl_stop(void);
+void sndout_sdl_wait(void);
+int  sndout_sdl_write_nb(const void *buff, int len);
+void sndout_sdl_exit(void);
+