[Swfdec] configure.ac libswfdec-gtk/Makefile.am libswfdec-gtk/swfdec_playback_oss.c
Eric Anholt
anholt at kemper.freedesktop.org
Mon Jul 16 00:43:17 PDT 2007
configure.ac | 14 +
libswfdec-gtk/Makefile.am | 1
libswfdec-gtk/swfdec_playback_oss.c | 265 ++++++++++++++++++++++++++++++++++++
3 files changed, 277 insertions(+), 3 deletions(-)
New commits:
diff-tree 6e644576c0bac40f193b31935946738a143c3c7a (from c45ceb30a4a9c438c89423e277d8684b2e66c65c)
Author: Eric Anholt <eric at anholt.net>
Date: Sun Jul 15 16:52:29 2007 -0700
Add an OSS audio backend so I can hear Strindberg and Helium. (Heeeelium!)
diff --git a/configure.ac b/configure.ac
index 881a73b..8e83776 100644
--- a/configure.ac
+++ b/configure.ac
@@ -125,7 +125,7 @@ dnl
dnl audio backend
dnl
AC_ARG_WITH(audio,
- [AC_HELP_STRING([--with-audio=@<:@auto/alsa/none@:>@],
+ [AC_HELP_STRING([--with-audio=@<:@auto/alsa/oss/none@:>@],
[audio backend to use])],,
[with_audio=auto])
@@ -134,6 +134,8 @@ if test "$with_audio" = "auto" -o "$with
PKG_CHECK_MODULES(ALSA, alsa >= 1.0, AUDIO_TYPE=alsa)
if test "$AUDIO_TYPE" = "alsa"; then
with_audio=alsa
+ AUDIO_CFLAGS=$ALSA_CFLAGS
+ AUDIO_LIBS=$ALSA_LIBS
else
if test "$with_audio" = "alsa"; then
AC_MSG_ERROR([no alsa audio support])
@@ -141,8 +143,14 @@ if test "$with_audio" = "auto" -o "$with
AC_MSG_WARN([no alsa audio support])
fi
fi
- AUDIO_CFLAGS=$ALSA_CFLAGS
- AUDIO_LIBS=$ALSA_LIBS
+fi
+
+dnl Assume OSS is available if ALSA wasn't found and we're "auto".
+if test "$with_audio" = "auto" -o "$with_audio" = "oss"; then
+ with_audio="oss"
+ AUDIO_CFLAGS=
+ AUDIO_LIBS=
+ AUDIO_TYPE=oss
fi
if test "$with_audio" = "auto" -o "$with_audio" = "none"; then
diff --git a/libswfdec-gtk/Makefile.am b/libswfdec-gtk/Makefile.am
index 97efc67..ac8e912 100644
--- a/libswfdec-gtk/Makefile.am
+++ b/libswfdec-gtk/Makefile.am
@@ -38,4 +38,5 @@ libswfdec_ at SWFDEC_MAJORMINOR@include_HEA
EXTRA_DIST = \
swfdec_playback_alsa.c \
+ swfdec_playback_oss.c \
swfdec_playback_none.c
diff --git a/libswfdec-gtk/swfdec_playback_oss.c b/libswfdec-gtk/swfdec_playback_oss.c
new file mode 100644
index 0000000..9c94252
--- /dev/null
+++ b/libswfdec-gtk/swfdec_playback_oss.c
@@ -0,0 +1,265 @@
+/* Swfdec
+ * Copyright © 2006 Benjamin Otte <otte at gnome.org>
+ * Copyright © 2007 Eric Anholt <eric at anholt.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/soundcard.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "swfdec_playback.h"
+
+/** @file Implements swfdec audio playback by opening /dev/dsp per stream
+ * and playing out through that.
+ *
+ * Allowing multiple access to /dev/dsp is not required by the OSS API spec,
+ * but FreeBSD's sound system lets you, which is what this file was written
+ * for.
+ */
+
+/*** DEFINITIONS ***/
+
+struct _SwfdecPlayback {
+ SwfdecPlayer * player;
+ GList * streams; /* all Stream objects */
+ GMainContext * context; /* context we work in */
+};
+
+typedef struct {
+ SwfdecPlayback * sound; /* reference to sound object */
+ SwfdecAudio * audio; /* the audio we play back */
+ int dsp_fd;
+ int fragsize; /* Audio fragment size */
+ GSource * source; /* source for writing data */
+ guint offset; /* offset into sound */
+} Stream;
+
+/* Size of one of our audio samples, in bytes */
+#define SAMPLESIZE 2
+#define CHANNELS 2
+
+/*** STREAMS ***/
+
+static gboolean
+handle_stream (GIOChannel *source, GIOCondition cond, gpointer data)
+{
+ Stream *stream = data;
+ char *frag = malloc(stream->fragsize);
+
+ if (frag == NULL) {
+ g_printerr ("Failed to allocate fragment of size %d\n",
+ stream->fragsize);
+ return FALSE;
+ }
+
+ while (TRUE) {
+ int ret;
+ audio_buf_info spaceinfo;
+
+ ret = ioctl(stream->dsp_fd, SNDCTL_DSP_GETOSPACE, &spaceinfo);
+ if (ret == -1) {
+ g_printerr ("Failed to get output buffer availability\n");
+ free(frag);
+ return FALSE;
+ }
+ g_assert(spaceinfo.fragsize == stream->fragsize);
+
+ if (spaceinfo.fragments == 0)
+ break;
+
+ memset (frag, 0, stream->fragsize);
+ swfdec_audio_render (stream->audio, (gint16 *)frag, stream->offset,
+ stream->fragsize / SAMPLESIZE / CHANNELS);
+
+ ret = write (stream->dsp_fd, frag, stream->fragsize);
+ if (ret != stream->fragsize) {
+ g_printerr ("Failed to write fragment\n");
+ free(frag);
+ return FALSE;
+ }
+
+ stream->offset += stream->fragsize / SAMPLESIZE / CHANNELS;
+ }
+
+ free(frag);
+
+ return TRUE;
+}
+
+static void
+swfdec_stream_open (SwfdecPlayback *sound, SwfdecAudio *audio)
+{
+ GIOChannel *channel;
+ Stream *stream;
+ guint rate;
+ int dsp_fd, ret, format, channels, fragsize;
+
+ dsp_fd = open("/dev/dsp", O_WRONLY);
+ if (dsp_fd == -1) {
+ g_printerr ("Failed to open /dev/dsp\n");
+ return;
+ }
+
+ format = AFMT_S16_LE;
+ ret = ioctl(dsp_fd, SNDCTL_DSP_SETFMT, &format);
+ if (ret == -1) {
+ g_printerr ("Failed to set sound format\n");
+ close(dsp_fd);
+ return;
+ }
+
+ channels = 2;
+ ret = ioctl(dsp_fd, SNDCTL_DSP_CHANNELS, &channels);
+ if (ret == -1) {
+ g_printerr ("Failed to set stereo\n");
+ close(dsp_fd);
+ return;
+ }
+
+ rate = 44100;
+ ret = ioctl(dsp_fd, SNDCTL_DSP_SPEED, &rate);
+ if (ret == -1) {
+ g_printerr ("Failed to set rate\n");
+ close(dsp_fd);
+ return;
+ }
+
+ ret = ioctl(dsp_fd, SNDCTL_DSP_GETBLKSIZE, &fragsize);
+ if (ret == -1) {
+ g_printerr ("Failed to get fragment size\n");
+ close(dsp_fd);
+ return;
+ }
+
+ stream = g_new0 (Stream, 1);
+ stream->sound = sound;
+ stream->audio = g_object_ref (audio);
+ stream->dsp_fd = dsp_fd;
+ stream->fragsize = fragsize;
+ sound->streams = g_list_prepend (sound->streams, stream);
+
+ channel = g_io_channel_unix_new (stream->dsp_fd);
+ stream->source = g_io_create_watch (channel, G_IO_OUT);
+ g_source_set_priority (stream->source, G_PRIORITY_HIGH);
+ g_source_set_callback (stream->source, (GSourceFunc) handle_stream, stream,
+ NULL);
+ g_io_channel_unref (channel);
+ g_source_attach (stream->source, stream->sound->context);
+
+ return;
+}
+
+static void
+swfdec_stream_close (Stream *stream)
+{
+ close (stream->dsp_fd);
+ g_source_destroy (stream->source);
+ g_source_unref (stream->source);
+ stream->sound->streams = g_list_remove (stream->sound->streams, stream);
+ g_object_unref (stream->audio);
+ g_free (stream);
+}
+
+/*** SOUND ***/
+
+static void
+advance_before (SwfdecPlayer *player, guint msecs, guint audio_samples, gpointer data)
+{
+ SwfdecPlayback *sound = data;
+ GList *walk;
+
+ for (walk = sound->streams; walk; walk = walk->next) {
+ Stream *stream = walk->data;
+ if (audio_samples >= stream->offset) {
+ stream->offset = 0;
+ } else {
+ stream->offset -= audio_samples;
+ }
+ }
+}
+
+static void
+audio_added (SwfdecPlayer *player, SwfdecAudio *audio, SwfdecPlayback *sound)
+{
+ swfdec_stream_open (sound, audio);
+}
+
+static void
+audio_removed (SwfdecPlayer *player, SwfdecAudio *audio, SwfdecPlayback *sound)
+{
+ GList *walk;
+
+ for (walk = sound->streams; walk; walk = walk->next) {
+ Stream *stream = walk->data;
+ if (stream->audio == audio) {
+ swfdec_stream_close (stream);
+ return;
+ }
+ }
+ g_assert_not_reached ();
+}
+
+SwfdecPlayback *
+swfdec_playback_open (SwfdecPlayer *player, GMainContext *context)
+{
+ SwfdecPlayback *sound;
+ const GList *walk;
+
+ g_return_val_if_fail (SWFDEC_IS_PLAYER (player), NULL);
+ g_return_val_if_fail (context != NULL, NULL);
+
+ sound = g_new0 (SwfdecPlayback, 1);
+ sound->player = player;
+ g_signal_connect (player, "advance", G_CALLBACK (advance_before), sound);
+ g_signal_connect (player, "audio-added", G_CALLBACK (audio_added), sound);
+ g_signal_connect (player, "audio-removed", G_CALLBACK (audio_removed), sound);
+ for (walk = swfdec_player_get_audio (player); walk; walk = walk->next) {
+ swfdec_stream_open (sound, walk->data);
+ }
+ g_main_context_ref (context);
+ sound->context = context;
+ return sound;
+}
+
+void
+swfdec_playback_close (SwfdecPlayback *sound)
+{
+#define REMOVE_HANDLER_FULL(obj,func,data,count) G_STMT_START {\
+ if (g_signal_handlers_disconnect_by_func ((obj), \
+ G_CALLBACK (func), (data)) != (count)) { \
+ g_assert_not_reached (); \
+ } \
+} G_STMT_END
+#define REMOVE_HANDLER(obj,func,data) REMOVE_HANDLER_FULL (obj, func, data, 1)
+
+ while (sound->streams)
+ swfdec_stream_close (sound->streams->data);
+ REMOVE_HANDLER (sound->player, advance_before, sound);
+ REMOVE_HANDLER (sound->player, audio_added, sound);
+ REMOVE_HANDLER (sound->player, audio_removed, sound);
+ g_main_context_unref (sound->context);
+ g_free (sound);
+}
+
+
More information about the Swfdec
mailing list