Eric Anholt
2007-Jul-16 07:43 UTC
[Swfdec] configure.ac libswfdec-gtk/Makefile.am libswfdec-gtk/swfdec_playback_oss.c
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); +} + +
Apparently Analagous Threads
- configure.ac libswfdec-gtk/Makefile.am libswfdec-gtk/swfdec_playback_pa.c
- 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
- 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
- 2 commits - libswfdec-gtk/swfdec_playback_pa.c