[Swfdec] 3 commits - autogen.sh configure.ac player/.gitignore player/Makefile.am player/swfdec_playback_alsa.c player/swfdec_playback.c player/swfdec_playback_none.c

Benjamin Otte company at kemper.freedesktop.org
Mon Jan 29 13:37:22 PST 2007


 autogen.sh                    |    2 +-
 configure.ac                  |   39 +++++++++++++++++++++++++++++++++------
 player/.gitignore             |    1 +
 player/Makefile.am            |   28 +++++++++++++++++++---------
 player/swfdec_playback_none.c |   38 ++++++++++++++++++++++++++++++++++++++
 5 files changed, 92 insertions(+), 16 deletions(-)

New commits:
diff-tree 133819a86a6435cce34751911118b74dd51f9bfc (from parents)
Merge: d3add5d691f7832d56e3126003ce242822bfe11d 4e7806e7020535920cbb2009ed8b039fd64c046c
Author: Benjamin Otte <otte at gnome.org>
Date:   Mon Jan 29 22:34:49 2007 +0100

    Merge branch 'master' of ssh://company@git.freedesktop.org/git/swfdec

diff-tree d3add5d691f7832d56e3126003ce242822bfe11d (from f9f53b7a60b641e2ba5c846430f2fb48ac013eb0)
Author: Benjamin Otte <otte at gnome.org>
Date:   Mon Jan 29 22:33:27 2007 +0100

    rework audio configuration subsystem
    
    - make it easier to plug new backends
    - add a "none" backend when alsa isn't available

diff --git a/configure.ac b/configure.ac
index eb69535..e02adfd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -86,13 +86,40 @@ if test "$HAVE_GTK" = "no"; then
 fi
 AM_CONDITIONAL(WITH_GTK,[test "$HAVE_GTK" != "no"])
 
-PKG_CHECK_MODULES(ALSA, alsa >= 1.0, HAVE_ALSA=yes, HAVE_ALSA=no)
-AC_SUBST(ALSA_LIBS)
-AC_SUBST(ALSA_CFLAGS)
-if test "$HAVE_ALSA" = "no"; then
-  AC_MSG_WARN([cannot find alsa, player will be disabled])
+dnl
+dnl audio backend
+dnl
+AC_ARG_WITH(audio,
+            [AC_HELP_STRING([--with-audio=@<:@auto/alsa/none@:>@],
+                            [audio backend to use])],,
+	    [with_audio=auto])
+
+AUDIO_TYPE=
+if test "$with_audio" = "auto" -o "$with_audio" = "alsa"; then
+  PKG_CHECK_MODULES(ALSA, alsa >= 1.0, AUDIO_TYPE=alsa)
+  if test "$AUDIO_TYPE" = "alsa"; then
+    with_audio=alsa
+  else
+    AC_MSG_WARN([no alsa audio support])
+  fi
+  AUDIO_CFLAGS=$ALSA_CFLAGS
+  AUDIO_LIBS=$ALSA_LIBS
+fi
+
+if test "$with_audio" = "auto" -o "$with_audio" = "none"; then
+  AUDIO_CFLAGS=
+  AUDIO_LIBS=
+  AUDIO_TYPE=none
 fi
-AM_CONDITIONAL(WITH_ALSA,[test "$HAVE_ALSA" != "no"])
+
+if test "x$AUDIO_TYPE" = "x"; then
+  AC_MSG_ERROR([desired audio support could not be used])
+else
+  AC_MSG_NOTICE([audio backend: $AUDIO_TYPE])
+fi
+AC_SUBST(AUDIO_LIBS)
+AC_SUBST(AUDIO_CFLAGS)
+AC_SUBST(AUDIO_TYPE)
 
 PKG_CHECK_MODULES(LIBOIL, liboil-0.3 >= 0.3.1.1, HAVE_LIBOIL=yes, HAVE_LIBOIL=no)
 AC_SUBST(LIBOIL_LIBS)
diff --git a/player/.gitignore b/player/.gitignore
index 3e3d43c..f2dfbf1 100644
--- a/player/.gitignore
+++ b/player/.gitignore
@@ -9,6 +9,7 @@ Makefile.in
 *.o
 *.lo
 *.loT
+swfdec_playback.c
 
 libswfdecui.la
 swfdebug
diff --git a/player/Makefile.am b/player/Makefile.am
index 0a29cc5..c56ee91 100644
--- a/player/Makefile.am
+++ b/player/Makefile.am
@@ -1,5 +1,13 @@
 if WITH_GTK
-if WITH_ALSA
+
+# this workaround is needed or autotools don't generate the .deps/*.Plo files correctly
+swfdec_playback.c: swfdec_playback_$(AUDIO_TYPE).c Makefile
+	cmp -s $(srcdir)/swfdec_playback_$(AUDIO_TYPE).c swfdec_playback.c \
+	|| cp $(srcdir)/swfdec_playback_$(AUDIO_TYPE).c swfdec_playback.c
+
+BUILT_SOURCES = swfdec_playback.c
+CLEANFILES = swfdec_playback.c
+
 noinst_LTLIBRARIES = libswfdecui.la
 noinst_PROGRAMS = swfplay swfdebug
 
@@ -31,15 +39,17 @@ noinst_HEADERS = \
 	swfdec_slow_loader.h \
 	swfdec_widget.h 
 
-libswfdecui_la_CFLAGS = $(GLOBAL_CFLAGS) $(GTK_CFLAGS) $(SWF_CFLAGS) $(ALSA_CFLAGS)
-libswfdecui_la_LDFLAGS = $(GTK_LIBS) $(SWF_LIBS) $(ALSA_LIBS)
-swfplay_CFLAGS = $(GLOBAL_CFLAGS) $(GTK_CFLAGS) $(SWF_CFLAGS) $(ALSA_CFLAGS)
-swfplay_LDFLAGS = $(GTK_LIBS) $(SWF_LIBS) $(ALSA_LIBS)
+libswfdecui_la_CFLAGS = $(GLOBAL_CFLAGS) $(GTK_CFLAGS) $(SWF_CFLAGS) $(AUDIO_CFLAGS)
+libswfdecui_la_LDFLAGS = $(GTK_LIBS) $(SWF_LIBS) $(AUDIO_LIBS)
+swfplay_CFLAGS = $(GLOBAL_CFLAGS) $(GTK_CFLAGS) $(SWF_CFLAGS)
+swfplay_LDFLAGS = $(GTK_LIBS) $(SWF_LIBS)
 swfplay_LDADD = libswfdecui.la
-swfdebug_CFLAGS = $(GLOBAL_CFLAGS) $(GTK_CFLAGS) $(SWF_CFLAGS) $(ALSA_CFLAGS) -DXP_UNIX -I$(top_builddir)/libswfdec/js
-swfdebug_LDFLAGS = $(GTK_LIBS) $(SWF_LIBS) $(ALSA_LIBS)
+swfdebug_CFLAGS = $(GLOBAL_CFLAGS) $(GTK_CFLAGS) $(SWF_CFLAGS) -DXP_UNIX -I$(top_builddir)/libswfdec/js
+swfdebug_LDFLAGS = $(GTK_LIBS) $(SWF_LIBS)
 swfdebug_LDADD = libswfdecui.la $(top_builddir)/libswfdec/js/libjs.la
 endif
-endif
 
-EXTRA_DIST = swfdebug.c swfplay.c swfdec_widget.c swfdec_widget.h swfdec_playback.c swfdec_playback.h
+EXTRA_DIST = \
+	swfdec_playback_alsa.c \
+	swfdec_playback_none.c
+
diff --git a/player/swfdec_playback.c b/player/swfdec_playback.c
deleted file mode 100644
index ea47099..0000000
--- a/player/swfdec_playback.c
+++ /dev/null
@@ -1,355 +0,0 @@
-/* Swfdec
- * Copyright (C) 2006 Benjamin Otte <otte at gnome.org>
- *
- * 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 <alsa/asoundlib.h>
-#include "swfdec_source.h"
-
-/* Why ALSA sucks for beginners:
- * - snd_pcm_delay is not sample-exact, but period-exact most of the time.
- *   Yay for getting told the time every 512 samples when a human notices
- *   a delay of 100 samples (oooops)
- * - lots of functions are simply not implemented. So the super-smart idea
- *   of using snd_pcm_rewind to avoid XRUNS and still get low latency has
- *   some issues when dmix just returns -EIO all of the time. That wouldn't
- *   be so bad if there was actually a way to query if it's supported.
- * - But to make up for all this, you have 10 hardware parameters, 10 
- *   software parameters and 10 configuration parameters. All of this is
- *   naturally supported on 10 driver APIs depending on kernel. So if your
- *   sound card seems to do weird stuff, that is not my fault.
- * Welcome to Linux sound in the 21st century.
- */
-
-/*** DEFINITIONS ***/
-
-typedef struct {
-  SwfdecPlayer *	player;
-  GList *		streams;	/* all Stream objects */
-  GMainContext *	context;	/* context we work in */
-} Sound;
-
-typedef struct {
-  Sound *		sound;		/* reference to sound object */
-  SwfdecAudio *		audio;		/* the audio we play back */
-  snd_pcm_t *		pcm;		/* the pcm we play back to */
-  GSource **		sources;	/* sources for writing data */
-  guint			n_sources;	/* number of sources */
-  guint			offset;		/* offset into sound */
-} Stream;
-
-#define ALSA_TRY(func,msg) G_STMT_START{ \
-  int err = func; \
-  if (err < 0) \
-    g_printerr (msg ": %s\n", snd_strerror (err)); \
-}G_STMT_END
-
-#define ALSA_ERROR(func,msg,retval) G_STMT_START { \
-  int err = func; \
-  if (err < 0) { \
-    g_printerr (msg ": %s\n", snd_strerror (err)); \
-    return retval; \
-  } \
-}G_STMT_END
-
-/*** STREAMS ***/
-
-static snd_pcm_uframes_t
-write_player (Stream *stream, const snd_pcm_channel_area_t *dst, 
-    snd_pcm_uframes_t offset, snd_pcm_uframes_t avail)
-{
-  /* FIXME: do a long path if this doesn't hold */
-  g_assert (dst[1].first - dst[0].first == 16);
-  g_assert (dst[0].addr == dst[1].addr);
-  g_assert (dst[0].step == dst[1].step);
-  g_assert (dst[0].step == 32);
-
-  memset (dst[0].addr + offset * dst[0].step / 8, 0, avail * 4);
-  swfdec_audio_render (stream->audio, dst[0].addr + offset * dst[0].step / 8, 
-      stream->offset, avail);
-  //g_print ("rendering %u %u\n", stream->offset, (guint) avail);
-  return avail;
-}
-
-static gboolean
-try_write (Stream *stream)
-{
-  snd_pcm_sframes_t avail_result;
-  snd_pcm_uframes_t offset, avail;
-  const snd_pcm_channel_area_t *dst;
-
-  while (TRUE) {
-    avail_result = snd_pcm_avail_update (stream->pcm);
-    ALSA_ERROR (avail_result, "snd_pcm_avail_update failed", FALSE);
-    if (avail_result == 0)
-      return TRUE;
-    avail = avail_result;
-    ALSA_ERROR (snd_pcm_mmap_begin (stream->pcm, &dst, &offset, &avail),
-	"snd_pcm_mmap_begin failed", FALSE);
-    //g_print ("  avail = %u\n", (guint) avail);
-
-    avail = write_player (stream, dst, offset, avail);
-    if (snd_pcm_mmap_commit (stream->pcm, offset, avail) < 0) {
-      g_printerr ("snd_pcm_mmap_commit failed\n");
-      return FALSE;
-    }
-    stream->offset += avail;
-    //g_print ("offset: %u (+%u)\n", stream->offset, (guint) avail);
-  }
-  return TRUE;
-}
-
-static void
-swfdec_stream_remove_handlers (Stream *stream)
-{
-  unsigned int i;
-
-  for (i = 0; i < stream->n_sources; i++) {
-    if (stream->sources[i]) {
-      g_source_destroy (stream->sources[i]);
-      g_source_unref (stream->sources[i]);
-      stream->sources[i] = NULL;
-    }
-  }
-}
-
-static void swfdec_stream_start (Stream *stream);
-static gboolean
-handle_stream (GIOChannel *source, GIOCondition cond, gpointer data)
-{
-  Stream *stream = data;
-  snd_pcm_state_t state;
-
-  state = snd_pcm_state (stream->pcm);
-  if (state != SND_PCM_STATE_RUNNING) {
-    swfdec_stream_start (stream);
-  } else {
-    try_write (stream);
-  }
-  return TRUE;
-}
-
-static void
-swfdec_stream_install_handlers (Stream *stream)
-{
-  if (stream->n_sources > 0) {
-    struct pollfd polls[stream->n_sources];
-    unsigned int i, count;
-    if (stream->n_sources > 1)
-      g_printerr ("attention: more than one fd!\n");
-    count = snd_pcm_poll_descriptors (stream->pcm, polls, stream->n_sources);
-    for (i = 0; i < count; i++) {
-      if (stream->sources[i] != NULL)
-	continue;
-      GIOChannel *channel = g_io_channel_unix_new (polls[i].fd);
-      stream->sources[i] = g_io_create_watch (channel, polls[i].events);
-      g_source_set_priority (stream->sources[i], G_PRIORITY_HIGH);
-      g_source_set_callback (stream->sources[i], (GSourceFunc) handle_stream, stream, NULL);
-      g_io_channel_unref (channel);
-      g_source_attach (stream->sources[i], stream->sound->context);
-    }
-  }
-}
-
-static void
-swfdec_stream_start (Stream *stream)
-{
-  snd_pcm_state_t state = snd_pcm_state (stream->pcm);
-  switch (state) {
-    case SND_PCM_STATE_XRUN:
-      ALSA_ERROR (snd_pcm_prepare (stream->pcm), "no prepare",);
-      //g_print ("XRUN!\n");
-      /* fall through */
-    case SND_PCM_STATE_SUSPENDED:
-    case SND_PCM_STATE_PREPARED:
-      stream->offset = 0;
-      //g_print ("offset: %u (delay: %ld)\n", sound->offset, delay);
-      if (try_write (stream)) {
-	ALSA_ERROR (snd_pcm_start (stream->pcm), "error starting",);
-	swfdec_stream_install_handlers (stream);
-      }
-      break;
-    default:
-      break;
-  }
-}
-
-static void
-swfdec_stream_open (Sound *sound, SwfdecAudio *audio)
-{
-  Stream *stream;
-  snd_pcm_t *ret;
-  snd_pcm_hw_params_t *hw_params;
-  unsigned int rate;
-  snd_pcm_uframes_t uframes;
-
-  /* "default" uses dmix, and dmix ticks way slow, so this thingy here stutters */
-  ALSA_ERROR (snd_pcm_open (&ret, "default", SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK),
-      "Failed to open sound device", );
-
-  snd_pcm_hw_params_alloca (&hw_params);
-  if (snd_pcm_hw_params_any (ret, hw_params) < 0) {
-    g_printerr ("No sound format available\n");
-    return;
-  }
-  if (snd_pcm_hw_params_set_access (ret, hw_params, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0) {
-    g_printerr ("Failed setting access\n");
-    goto fail;
-  }
-  if (snd_pcm_hw_params_set_format (ret, hw_params, SND_PCM_FORMAT_S16) < 0) {
-    g_printerr ("Failed setting format\n");
-    goto fail;
-  }
-  if (snd_pcm_hw_params_set_channels (ret, hw_params, 2) < 0) {
-    g_printerr ("Failed setting channels\n");
-    goto fail;
-  }
-  rate = 44100;
-  if (snd_pcm_hw_params_set_rate_near (ret, hw_params, &rate, 0) < 0) {
-    g_printerr ("Failed setting rate\n");
-    goto fail;
-  }
-  uframes = 16384;
-  if (snd_pcm_hw_params_set_buffer_size_near (ret, hw_params, &uframes) < 0) {
-    g_printerr ("Failed setting buffer size\n");
-    goto fail;
-  }
-  if (snd_pcm_hw_params (ret, hw_params) < 0) {
-    g_printerr ("Could not set hardware parameters\n");
-    goto fail;
-  }
-#if 0
-  {
-    snd_output_t *log;
-    snd_output_stdio_attach (&log, stderr, 0);
-    snd_pcm_hw_params_dump (hw_params, log);
-  }
-#endif
-  stream = g_new0 (Stream, 1);
-  stream->sound = sound;
-  stream->audio = g_object_ref (audio);
-  stream->pcm = ret;
-  stream->n_sources = snd_pcm_poll_descriptors_count (ret);
-  if (stream->n_sources > 0)
-    stream->sources = g_new0 (GSource *, stream->n_sources);
-  sound->streams = g_list_prepend (sound->streams, stream);
-  swfdec_stream_start (stream);
-  return;
-
-fail:
-  snd_pcm_close (ret);
-}
-
-static void
-swfdec_stream_close (Stream *stream)
-{
-  ALSA_TRY (snd_pcm_close (stream->pcm), "failed closing");
-  swfdec_stream_remove_handlers (stream);
-  g_free (stream->sources);
-  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)
-{
-  Sound *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, Sound *sound)
-{
-  swfdec_stream_open (sound, audio);
-}
-
-static void
-audio_removed (SwfdecPlayer *player, SwfdecAudio *audio, Sound *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 ();
-}
-
-gpointer
-swfdec_playback_open (SwfdecPlayer *player, GMainContext *context)
-{
-  Sound *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 (Sound, 1);
-  sound->player = g_object_ref (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 (gpointer data)
-{
-  Sound *sound = data;
-#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_object_unref (sound->player);
-  g_main_context_unref (sound->context);
-  g_free (sound);
-}
-
-
diff --git a/player/swfdec_playback_alsa.c b/player/swfdec_playback_alsa.c
new file mode 100644
index 0000000..ea47099
--- /dev/null
+++ b/player/swfdec_playback_alsa.c
@@ -0,0 +1,355 @@
+/* Swfdec
+ * Copyright (C) 2006 Benjamin Otte <otte at gnome.org>
+ *
+ * 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 <alsa/asoundlib.h>
+#include "swfdec_source.h"
+
+/* Why ALSA sucks for beginners:
+ * - snd_pcm_delay is not sample-exact, but period-exact most of the time.
+ *   Yay for getting told the time every 512 samples when a human notices
+ *   a delay of 100 samples (oooops)
+ * - lots of functions are simply not implemented. So the super-smart idea
+ *   of using snd_pcm_rewind to avoid XRUNS and still get low latency has
+ *   some issues when dmix just returns -EIO all of the time. That wouldn't
+ *   be so bad if there was actually a way to query if it's supported.
+ * - But to make up for all this, you have 10 hardware parameters, 10 
+ *   software parameters and 10 configuration parameters. All of this is
+ *   naturally supported on 10 driver APIs depending on kernel. So if your
+ *   sound card seems to do weird stuff, that is not my fault.
+ * Welcome to Linux sound in the 21st century.
+ */
+
+/*** DEFINITIONS ***/
+
+typedef struct {
+  SwfdecPlayer *	player;
+  GList *		streams;	/* all Stream objects */
+  GMainContext *	context;	/* context we work in */
+} Sound;
+
+typedef struct {
+  Sound *		sound;		/* reference to sound object */
+  SwfdecAudio *		audio;		/* the audio we play back */
+  snd_pcm_t *		pcm;		/* the pcm we play back to */
+  GSource **		sources;	/* sources for writing data */
+  guint			n_sources;	/* number of sources */
+  guint			offset;		/* offset into sound */
+} Stream;
+
+#define ALSA_TRY(func,msg) G_STMT_START{ \
+  int err = func; \
+  if (err < 0) \
+    g_printerr (msg ": %s\n", snd_strerror (err)); \
+}G_STMT_END
+
+#define ALSA_ERROR(func,msg,retval) G_STMT_START { \
+  int err = func; \
+  if (err < 0) { \
+    g_printerr (msg ": %s\n", snd_strerror (err)); \
+    return retval; \
+  } \
+}G_STMT_END
+
+/*** STREAMS ***/
+
+static snd_pcm_uframes_t
+write_player (Stream *stream, const snd_pcm_channel_area_t *dst, 
+    snd_pcm_uframes_t offset, snd_pcm_uframes_t avail)
+{
+  /* FIXME: do a long path if this doesn't hold */
+  g_assert (dst[1].first - dst[0].first == 16);
+  g_assert (dst[0].addr == dst[1].addr);
+  g_assert (dst[0].step == dst[1].step);
+  g_assert (dst[0].step == 32);
+
+  memset (dst[0].addr + offset * dst[0].step / 8, 0, avail * 4);
+  swfdec_audio_render (stream->audio, dst[0].addr + offset * dst[0].step / 8, 
+      stream->offset, avail);
+  //g_print ("rendering %u %u\n", stream->offset, (guint) avail);
+  return avail;
+}
+
+static gboolean
+try_write (Stream *stream)
+{
+  snd_pcm_sframes_t avail_result;
+  snd_pcm_uframes_t offset, avail;
+  const snd_pcm_channel_area_t *dst;
+
+  while (TRUE) {
+    avail_result = snd_pcm_avail_update (stream->pcm);
+    ALSA_ERROR (avail_result, "snd_pcm_avail_update failed", FALSE);
+    if (avail_result == 0)
+      return TRUE;
+    avail = avail_result;
+    ALSA_ERROR (snd_pcm_mmap_begin (stream->pcm, &dst, &offset, &avail),
+	"snd_pcm_mmap_begin failed", FALSE);
+    //g_print ("  avail = %u\n", (guint) avail);
+
+    avail = write_player (stream, dst, offset, avail);
+    if (snd_pcm_mmap_commit (stream->pcm, offset, avail) < 0) {
+      g_printerr ("snd_pcm_mmap_commit failed\n");
+      return FALSE;
+    }
+    stream->offset += avail;
+    //g_print ("offset: %u (+%u)\n", stream->offset, (guint) avail);
+  }
+  return TRUE;
+}
+
+static void
+swfdec_stream_remove_handlers (Stream *stream)
+{
+  unsigned int i;
+
+  for (i = 0; i < stream->n_sources; i++) {
+    if (stream->sources[i]) {
+      g_source_destroy (stream->sources[i]);
+      g_source_unref (stream->sources[i]);
+      stream->sources[i] = NULL;
+    }
+  }
+}
+
+static void swfdec_stream_start (Stream *stream);
+static gboolean
+handle_stream (GIOChannel *source, GIOCondition cond, gpointer data)
+{
+  Stream *stream = data;
+  snd_pcm_state_t state;
+
+  state = snd_pcm_state (stream->pcm);
+  if (state != SND_PCM_STATE_RUNNING) {
+    swfdec_stream_start (stream);
+  } else {
+    try_write (stream);
+  }
+  return TRUE;
+}
+
+static void
+swfdec_stream_install_handlers (Stream *stream)
+{
+  if (stream->n_sources > 0) {
+    struct pollfd polls[stream->n_sources];
+    unsigned int i, count;
+    if (stream->n_sources > 1)
+      g_printerr ("attention: more than one fd!\n");
+    count = snd_pcm_poll_descriptors (stream->pcm, polls, stream->n_sources);
+    for (i = 0; i < count; i++) {
+      if (stream->sources[i] != NULL)
+	continue;
+      GIOChannel *channel = g_io_channel_unix_new (polls[i].fd);
+      stream->sources[i] = g_io_create_watch (channel, polls[i].events);
+      g_source_set_priority (stream->sources[i], G_PRIORITY_HIGH);
+      g_source_set_callback (stream->sources[i], (GSourceFunc) handle_stream, stream, NULL);
+      g_io_channel_unref (channel);
+      g_source_attach (stream->sources[i], stream->sound->context);
+    }
+  }
+}
+
+static void
+swfdec_stream_start (Stream *stream)
+{
+  snd_pcm_state_t state = snd_pcm_state (stream->pcm);
+  switch (state) {
+    case SND_PCM_STATE_XRUN:
+      ALSA_ERROR (snd_pcm_prepare (stream->pcm), "no prepare",);
+      //g_print ("XRUN!\n");
+      /* fall through */
+    case SND_PCM_STATE_SUSPENDED:
+    case SND_PCM_STATE_PREPARED:
+      stream->offset = 0;
+      //g_print ("offset: %u (delay: %ld)\n", sound->offset, delay);
+      if (try_write (stream)) {
+	ALSA_ERROR (snd_pcm_start (stream->pcm), "error starting",);
+	swfdec_stream_install_handlers (stream);
+      }
+      break;
+    default:
+      break;
+  }
+}
+
+static void
+swfdec_stream_open (Sound *sound, SwfdecAudio *audio)
+{
+  Stream *stream;
+  snd_pcm_t *ret;
+  snd_pcm_hw_params_t *hw_params;
+  unsigned int rate;
+  snd_pcm_uframes_t uframes;
+
+  /* "default" uses dmix, and dmix ticks way slow, so this thingy here stutters */
+  ALSA_ERROR (snd_pcm_open (&ret, "default", SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK),
+      "Failed to open sound device", );
+
+  snd_pcm_hw_params_alloca (&hw_params);
+  if (snd_pcm_hw_params_any (ret, hw_params) < 0) {
+    g_printerr ("No sound format available\n");
+    return;
+  }
+  if (snd_pcm_hw_params_set_access (ret, hw_params, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0) {
+    g_printerr ("Failed setting access\n");
+    goto fail;
+  }
+  if (snd_pcm_hw_params_set_format (ret, hw_params, SND_PCM_FORMAT_S16) < 0) {
+    g_printerr ("Failed setting format\n");
+    goto fail;
+  }
+  if (snd_pcm_hw_params_set_channels (ret, hw_params, 2) < 0) {
+    g_printerr ("Failed setting channels\n");
+    goto fail;
+  }
+  rate = 44100;
+  if (snd_pcm_hw_params_set_rate_near (ret, hw_params, &rate, 0) < 0) {
+    g_printerr ("Failed setting rate\n");
+    goto fail;
+  }
+  uframes = 16384;
+  if (snd_pcm_hw_params_set_buffer_size_near (ret, hw_params, &uframes) < 0) {
+    g_printerr ("Failed setting buffer size\n");
+    goto fail;
+  }
+  if (snd_pcm_hw_params (ret, hw_params) < 0) {
+    g_printerr ("Could not set hardware parameters\n");
+    goto fail;
+  }
+#if 0
+  {
+    snd_output_t *log;
+    snd_output_stdio_attach (&log, stderr, 0);
+    snd_pcm_hw_params_dump (hw_params, log);
+  }
+#endif
+  stream = g_new0 (Stream, 1);
+  stream->sound = sound;
+  stream->audio = g_object_ref (audio);
+  stream->pcm = ret;
+  stream->n_sources = snd_pcm_poll_descriptors_count (ret);
+  if (stream->n_sources > 0)
+    stream->sources = g_new0 (GSource *, stream->n_sources);
+  sound->streams = g_list_prepend (sound->streams, stream);
+  swfdec_stream_start (stream);
+  return;
+
+fail:
+  snd_pcm_close (ret);
+}
+
+static void
+swfdec_stream_close (Stream *stream)
+{
+  ALSA_TRY (snd_pcm_close (stream->pcm), "failed closing");
+  swfdec_stream_remove_handlers (stream);
+  g_free (stream->sources);
+  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)
+{
+  Sound *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, Sound *sound)
+{
+  swfdec_stream_open (sound, audio);
+}
+
+static void
+audio_removed (SwfdecPlayer *player, SwfdecAudio *audio, Sound *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 ();
+}
+
+gpointer
+swfdec_playback_open (SwfdecPlayer *player, GMainContext *context)
+{
+  Sound *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 (Sound, 1);
+  sound->player = g_object_ref (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 (gpointer data)
+{
+  Sound *sound = data;
+#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_object_unref (sound->player);
+  g_main_context_unref (sound->context);
+  g_free (sound);
+}
+
+
diff --git a/player/swfdec_playback_none.c b/player/swfdec_playback_none.c
new file mode 100644
index 0000000..6464a4a
--- /dev/null
+++ b/player/swfdec_playback_none.c
@@ -0,0 +1,38 @@
+/* Swfdec
+ * Copyright (C) 2007 Benjamin Otte <otte at gnome.org>
+ *
+ * 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 "swfdec_playback.h"
+
+/* STUBS ONLY - audio is disabled */
+
+gpointer
+swfdec_playback_open (SwfdecPlayer *player, GMainContext *context)
+{
+  return GINT_TO_POINTER (-1);
+}
+
+void
+swfdec_playback_close (gpointer sound)
+{
+  g_assert (sound == GINT_TO_POINTER (-1));
+}
diff-tree f9f53b7a60b641e2ba5c846430f2fb48ac013eb0 (from 2cb8680a8577ff5d018b50e7da55c233e8eaa4af)
Author: Benjamin Otte <otte at gnome.org>
Date:   Mon Jan 29 22:31:13 2007 +0100

    enable gtk-doc in autogen.sh
    
    developers are supposed to ensure that docs build and make dist requires it

diff --git a/autogen.sh b/autogen.sh
index 13824b4..fee343b 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -1,3 +1,3 @@
 #!/bin/sh
 autoreconf -i -f &&
-./configure --enable-maintainer-mode --disable-static $@
+./configure --enable-maintainer-mode --disable-static --enable-gtk-doc $@


More information about the Swfdec mailing list