Benjamin Otte
2007-Jan-29 13:37 UTC
[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
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@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@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@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@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@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@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 $@
Maybe Matching Threads
- Branch 'interpreter' - 20 commits - autogen.sh configure.ac libswfdec/js libswfdec/swfdec_debug.h libswfdec/swfdec_js.c libswfdec/swfdec_js_color.c libswfdec/swfdec_js_movie.c libswfdec/swfdec_movie.c libswfdec/swfdec_movie.h libswfdec/swfdec_script.c
- 15 commits - configure.ac doc/Makefile.am doc/swfdec-docs.sgml doc/swfdec-sections.txt doc/swfdec.types libswfdec-gtk/.gitignore libswfdec-gtk/Makefile.am libswfdec-gtk/swfdec-gtk.h libswfdec-gtk/swfdec_gtk_player.c libswfdec-gtk/swfdec_gtk_player.h
- configure.ac libswfdec-gtk/Makefile.am libswfdec-gtk/swfdec_playback_oss.c
- configure.ac libswfdec-gtk/Makefile.am libswfdec-gtk/swfdec_playback_pa.c
- 2 commits - doc/Makefile.am libswfdec-gtk/Makefile.am Makefile.am player/Makefile.am test/Makefile.am