[Freeciv-Dev] Re: (PR#8509) ALSA sound plugin for freeciv
[Top] [All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: |
undisclosed-recipients: ; |
Subject: |
[Freeciv-Dev] Re: (PR#8509) ALSA sound plugin for freeciv |
From: |
"Javier Pello" <jpello@xxxxxxxxxxxxx> |
Date: |
Wed, 14 Apr 2004 07:49:44 -0700 |
Reply-to: |
rt@xxxxxxxxxxx |
<URL: http://rt.freeciv.org/Ticket/Display.html?id=8509 >
Hi again:
Sorry I did not attach the patch in the previous message.
--- freeciv-1.14.1/m4/alsa.m4 1970-01-01 01:00:00.000000000 +0100
+++ freeciv-alsa/m4/alsa.m4 2004-03-15 11:53:16.000000000 +0100
@@ -0,0 +1,37 @@
+dnl AM_ALSA_SUPPORT([ACTION-IF-SUPPORTS [, ACTION-IF-NOT-SUPPORTS]])
+dnl Partially stolen from alsaplayer
+dnl
+AC_DEFUN(AM_ALSA_SUPPORT,
+[dnl
+ AC_MSG_CHECKING(for ALSA version)
+ AC_EGREP_CPP([AP_maGiC_VALUE],
+ [
+#include <sys/asoundlib.h>
+#if defined(SND_LIB_MAJOR) && defined(SND_LIB_MINOR)
+#if SND_LIB_MAJOR>0 || (SND_LIB_MAJOR==0 && SND_LIB_MINOR>=6)
+AP_maGiC_VALUE
+#endif
+#endif
+ ],
+ AC_MSG_RESULT([>= 0.6])
+ AC_MSG_CHECKING(for Audio File Library version)
+ AC_EGREP_CPP([AP_maGiC_VALUE],
+ [
+#include <audiofile.h>
+#if defined(LIBAUDIOFILE_MAJOR_VERSION) && defined(LIBAUDIOFILE_MINOR_VERSION)
+#if LIBAUDIOFILE_MAJOR_VERSION>0 || (LIBAUDIOFILE_MAJOR_VERSION==0 &&
LIBAUDIOFILE_MINOR_VERSION>=2)
+AP_maGiC_VALUE
+#endif
+#endif
+ ],
+ AC_MSG_RESULT([>= 0.2])
+ ALSA_CFLAGS=""
+ ALSA_LIB="-laudiofile -lasound"
+ ifelse([$1], , :, [$1]),
+ AC_MSG_RESULT([no])
+ ifelse([$2], , :, [$2])
+ ),
+ AC_MSG_RESULT([no])
+ ifelse([$2], , :, [$2])
+ )
+])
--- freeciv-1.14.1/m4/sound.m4 2003-12-02 19:57:25.000000000 +0100
+++ freeciv-alsa/m4/sound.m4 2004-03-10 15:57:30.000000000 +0100
@@ -7,6 +7,10 @@
[ --disable-sdl-mixer Do not try to use the SDL mixer],
USE_SOUND=no, USE_SOUND_SDL=yes)
+ AC_ARG_ENABLE(alsa,
+ [ --disable-alsa Do not try to use ALSA],
+ USE_SOUND=no, USE_SOUND_ALSA=yes)
+
AC_ARG_ENABLE(winmm,
[ --disable-winmm Do not try to use WinMM for sound],
USE_SOUND=no, USE_SOUND_WINMM=yes)
@@ -48,6 +52,18 @@
fi
fi
+ if test "x$USE_SOUND_ALSA" = "xyes"; then
+ dnl Add ALSA support to client
+ AM_ALSA_SUPPORT(ALSA=yes, ALSA=no)
+ if test "x$ALSA" != "xno"; then
+ SOUND_CFLAGS="$SOUND_CFLAGS $ALSA_CFLAGS"
+ SOUND_LIBS="$SOUND_LIBS $ALSA_LIBS"
+ AC_DEFINE(ALSA, 1, [ALSA support])
+ AC_MSG_CHECKING(building ALSA support)
+ AC_MSG_RESULT(yes)
+ fi
+ fi
+
if test "x$USE_SOUND_WINMM" = "xyes"; then
dnl Add WinMM sound support to client
if test x"$MINGW32" = "xyes"; then
--- freeciv-1.14.1/configure.ac 2003-12-02 19:56:54.000000000 +0100
+++ freeciv-alsa/configure.ac 2004-03-10 14:04:06.000000000 +0100
@@ -507,6 +507,7 @@
AC_SUBST(SOUND_LIBS)
AM_CONDITIONAL(ESD, test "x$ESD" = "xyes")
AM_CONDITIONAL(SDL, test "x$SDL_mixer" = "xyes")
+AM_CONDITIONAL(ALSA, test "x$ALSA" = "xyes")
AM_CONDITIONAL(WINMM, test "x$WINMM" = "xyes")
AM_CONDITIONAL(CLIENT_GUI_GTK, test "$gui_sources" = "gui-gtk")
AM_CONDITIONAL(CLIENT_GUI_GTK_2_0, test "$gui_sources" = "gui-gtk-2.0")
--- freeciv-1.14.1/client/Makefile.am 2003-12-02 19:56:55.000000000 +0100
+++ freeciv-alsa/client/Makefile.am 2004-03-10 13:07:27.000000000 +0100
@@ -25,6 +25,7 @@
ALL_ESD_FILES=audio_esd.c audio_esd.h
ALL_SDL_FILES=audio_sdl.c audio_sdl.h
+ALL_ALSA_FILES=audio_alsa.c audio_alsa.h
ALL_WINMM_FILES=audio_winmm.c audio_winmm.h
ALL_AMIGA_FILES=audio_amiga.c audio_amiga.h
@@ -34,6 +35,9 @@
if SDL
SDL_FILES=$(ALL_SDL_FILES)
endif
+if ALSA
+ALSA_FILES=$(ALL_ALSA_FILES)
+endif
if WINMM
WINMM_FILES=$(ALL_WINMM_FILES)
endif
@@ -104,6 +108,7 @@
\
$(ALL_ESD_FILES) \
$(ALL_SDL_FILES) \
+ $(ALL_ALSA_FILES) \
$(ALL_WINMM_FILES) \
$(ALL_AMIGA_FILES)
@@ -126,7 +131,7 @@
## Above, note -I../intl instead of -I$(top_srdir/intl) is deliberate.
-civclient_SOURCES = $(ESD_FILES) $(SDL_FILES) $(WINMM_FILES) \
+civclient_SOURCES = $(ESD_FILES) $(SDL_FILES) $(ALSA_FILES) $(WINMM_FILES) \
attribute.h \
attribute.c \
citydlg_common.c \
--- freeciv-1.14.1/client/audio.c 2003-12-02 19:56:55.000000000 +0100
+++ freeciv-alsa/client/audio.c 2004-03-10 13:08:56.000000000 +0100
@@ -38,6 +38,10 @@
#include "audio_sdl.h"
#endif
+#ifdef ALSA
+#include "audio_alsa.h"
+#endif
+
#ifdef WINMM
#include "audio_winmm.h"
#endif
@@ -48,7 +52,7 @@
#include "audio.h"
-#define MAX_NUM_PLUGINS 3
+#define MAX_NUM_PLUGINS 4
#define SNDSPEC_SUFFIX ".soundspec"
/* keep it open throughout */
@@ -161,6 +165,9 @@
#ifdef SDL
audio_sdl_init();
#endif
+#ifdef ALSA
+ audio_alsa_init();
+#endif
#ifdef WINMM
audio_winmm_init();
#endif
@@ -280,6 +287,9 @@
#ifdef SDL
if (audio_select_plugin("sdl")) return;
#endif
+#ifdef ALSA
+ if (audio_select_plugin("alsa")) return;
+#endif
#ifdef WINMM
if (audio_select_plugin("winmm")) return;
#endif
--- freeciv-1.14.1/client/audio_alsa.h 1970-01-01 01:00:00.000000000 +0100
+++ freeciv-alsa/client/audio_alsa.h 2004-03-10 11:35:45.000000000 +0100
@@ -0,0 +1,19 @@
+/**********************************************************************
+ Freeciv - Copyright (C) 2004 - J. Pello
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program 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 General Public License for more details.
+***********************************************************************/
+
+#ifndef FC__AUDIO_ALSA_H
+#define FC__AUDIO_ALSA_H
+
+void audio_alsa_init (void);
+
+#endif /* FC__AUDIO_ALSA_H */
--- freeciv-1.14.1/client/audio_alsa.c 1970-01-01 01:00:00.000000000 +0100
+++ freeciv-alsa/client/audio_alsa.c 2004-03-15 11:42:06.000000000 +0100
@@ -0,0 +1,358 @@
+/**********************************************************************
+ Freeciv - Copyright (C) 2004 - J. Pello
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program 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 General Public License for more details.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <unistd.h>
+
+#include <audiofile.h>
+#include <alsa/asoundlib.h>
+
+#include "support.h"
+#include "log.h"
+#include "audio.h"
+
+#include "audio_alsa.h"
+
+static snd_pcm_t *sound_handle = NULL;
+static snd_async_handler_t *ah;
+static snd_pcm_sframes_t period_size;
+
+static AFfilehandle file_handle = AF_NULL_FILEHANDLE;
+static double file_rate;
+static AFframecount file_fcount, left_fcount;
+static bool file_repeat;
+
+/*****************
+ Drain if running
+*****************/
+static inline void snd_pcm_drain_if (snd_pcm_t *h)
+{
+ switch ( snd_pcm_state(h) ) {
+ case SND_PCM_STATE_RUNNING:
+ case SND_PCM_STATE_XRUN:
+ case SND_PCM_STATE_PAUSED:
+ snd_pcm_drain (h);
+ default: ;
+ }
+}
+
+/********************
+ Reset as appropiate
+********************/
+static inline void snd_pcm_drop_free (snd_pcm_t *h)
+{
+ file_repeat = FALSE;
+ switch ( snd_pcm_state(h) ) {
+ case SND_PCM_STATE_RUNNING:
+ case SND_PCM_STATE_XRUN:
+ case SND_PCM_STATE_DRAINING:
+ case SND_PCM_STATE_PAUSED:
+ snd_pcm_drop (h); /* fall through */
+ case SND_PCM_STATE_PREPARED:
+ case SND_PCM_STATE_SETUP:
+ snd_pcm_hw_free (h);
+ default: ;
+ }
+}
+
+/**********
+ Shut down
+**********/
+static void my_shutdown (void)
+{
+ snd_pcm_close (sound_handle);
+ sound_handle = NULL;
+}
+
+/*****
+ Stop
+*****/
+static void my_stop (void)
+{
+ file_repeat = FALSE;
+ snd_pcm_drop_free (sound_handle);
+}
+
+/*****
+ Wait
+*****/
+static void my_wait (void)
+{
+ file_repeat = FALSE;
+ snd_pcm_drain_if (sound_handle);
+ while ( snd_pcm_state (sound_handle) == SND_PCM_STATE_DRAINING ) {
+ usleep (100000);
+ }
+}
+
+/******************
+ Set HW parameters
+******************/
+static int set_hw_params (void)
+{
+ snd_pcm_hw_params_t *hwparams;
+ unsigned rrate;
+ unsigned period_time = 100000;
+
+ snd_pcm_hw_params_alloca (&hwparams);
+
+ if ( snd_pcm_hw_params_any (sound_handle, hwparams) < 0 ) {
+ return -1;
+ }
+ if ( snd_pcm_hw_params_set_access (sound_handle, hwparams,
+ SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0 ) {
+ return -1;
+ }
+ if ( snd_pcm_hw_params_set_format (sound_handle, hwparams,
+ SND_PCM_FORMAT_S16) < 0 ) {
+ return -1;
+ }
+ if ( snd_pcm_hw_params_set_channels (sound_handle, hwparams, 2) < 0 ) {
+ return -1;
+ }
+ rrate = file_rate;
+ if ( snd_pcm_hw_params_set_rate_near (sound_handle, hwparams, &rrate, 0)
+ < 0 ) {
+ return -1;
+ }
+ if ( rrate != (unsigned) file_rate ) {
+ freelog (LOG_VERBOSE, "ALSA: asked for rate %u, got %u",
+ (unsigned) file_rate, rrate);
+ }
+ snd_pcm_hw_params_set_period_time_near (sound_handle, hwparams,
+ &period_time, &rrate);
+ if ( snd_pcm_hw_params_get_period_size (hwparams, &period_size, &rrate)
+ < 0 ) {
+ return -1;
+ }
+ return snd_pcm_hw_params (sound_handle, hwparams);
+}
+
+/******************
+ Underrun recovery
+******************/
+static int xrun_recovery (const char *s, int e)
+{
+ if ( e == -EPIPE ) {
+ e = snd_pcm_prepare (sound_handle);
+ if (e < 0) {
+ freelog (LOG_ERROR, "ALSA: Cannot recover from underrun: %s",
+ snd_strerror(e));
+ } else {
+ return 0;
+ }
+ } else if ( e < 0 ) {
+ freelog (LOG_ERROR, "ALSA: %s: %s", s, snd_strerror(e));
+ }
+ return e;
+}
+
+/************************
+ Send a burst of samples
+************************/
+static int snd_mmap_run (void)
+{
+ snd_pcm_uframes_t left, frames, offset;
+ snd_pcm_sframes_t commit;
+ const snd_pcm_channel_area_t *area;
+
+ left = period_size;
+ if ( left > left_fcount ) {
+ left = left_fcount;
+ }
+
+ while ( left > 0 ) {
+ frames = left;
+ if ( xrun_recovery ("MMAP begin",
+ snd_pcm_mmap_begin (sound_handle, &area, &offset, &frames)) < 0 ) {
+ return -1;
+ }
+
+ /* Confirm that our parameters match what we expect for
+ * SND_PCM_ACCESS_MMAP_INTERLEAVED and SND_PCM_FORMAT_S16.
+ * Of course, we could adapt the code below, but it is easier to leave it
+ * this way as long as ALSA's input format matches audiofile's output.
+ */
+ if ( area[0].step != 32 || area[1].step != 32
+ || area[0].addr != area[1].addr ) {
+ snd_pcm_mmap_commit (sound_handle, offset, 0);
+ freelog (LOG_ERROR, "ALSA: unexpected area parameters");
+ return -1;
+ }
+
+ if ( afReadFrames (file_handle, AF_DEFAULT_TRACK,
+ area->addr + 4*offset, frames) < 0 ) {
+ snd_pcm_mmap_commit (sound_handle, offset, 0);
+ freelog (LOG_ERROR, "ALSA: cannot read frames");
+ break;
+ }
+
+ commit = snd_pcm_mmap_commit (sound_handle, offset, frames);
+ if ( commit < 0 || commit != frames ) {
+ if ( xrun_recovery ("MMAP commit", commit<0 ? commit : -EPIPE) < 0 ) {
+ return -1;
+ }
+ }
+ left_fcount -= frames;
+ left -= frames;
+ }
+
+ return 0;
+}
+
+/**************
+ Play callback
+**************/
+static void play_callback (snd_async_handler_t *ah)
+{
+ snd_pcm_state_t state;
+ snd_pcm_sframes_t avail;
+ int restart = 0;
+
+ while (1) {
+ if ( !left_fcount ) {
+ if ( file_repeat == FALSE ) {
+ return;
+ }
+ /* rewind */
+ if ( afSeekFrame (file_handle, AF_DEFAULT_TRACK, 0) < 0 ) {
+ break;
+ }
+ left_fcount = file_fcount;
+ }
+
+ state = snd_pcm_state (sound_handle);
+ if ( state == SND_PCM_STATE_XRUN ) {
+ if ( xrun_recovery(NULL,-EPIPE) < 0 ) {
+ break;
+ }
+ }
+
+ avail =
+ xrun_recovery ("avail update", snd_pcm_avail_update (sound_handle));
+ if ( avail < 0 ) {
+ restart = 1;
+ continue;
+ }
+ if ( avail < period_size ) {
+ if ( !restart ) {
+ return;
+ }
+ restart = 0;
+ if ( xrun_recovery ("start", snd_pcm_start (sound_handle)) < 0 ) {
+ break;
+ }
+ }
+
+ if ( snd_mmap_run() < 0 ) {
+ break;
+ }
+ }
+
+ /* error path */
+ snd_pcm_drop_free (sound_handle);
+}
+
+/*****
+ Play
+*****/
+static bool my_play (const char *tag, const char *fullpath, bool repeat)
+{
+ AFfilehandle new_handle;
+ double new_rate;
+ AFframecount new_fcount;
+
+ if (fullpath == NULL) {
+ return FALSE;
+ }
+
+ new_handle = afOpenFile (fullpath, "r", 0);
+ if ( new_handle == AF_NULL_FILEHANDLE ) {
+ freelog (LOG_ERROR, "ALSA: cannot open %s", fullpath);
+ return FALSE;
+ }
+
+ afSetVirtualSampleFormat (new_handle, AF_DEFAULT_TRACK,
+ AF_SAMPFMT_TWOSCOMP, 16);
+ afSetVirtualChannels (new_handle, AF_DEFAULT_TRACK, 2);
+ new_rate = afGetRate (new_handle, AF_DEFAULT_TRACK);
+ new_fcount = afGetFrameCount (new_handle, AF_DEFAULT_TRACK);
+ freelog (LOG_VERBOSE, "ALSA: %s: rate %f, %d frames", fullpath,
+ new_rate, (int) new_fcount);
+
+ snd_pcm_drop_free (sound_handle);
+ if ( file_handle != AF_NULL_FILEHANDLE ) {
+ afCloseFile (file_handle);
+ }
+
+ file_handle = new_handle;
+ file_rate = new_rate;
+ left_fcount = file_fcount = new_fcount;
+ file_repeat = repeat;
+
+ if ( set_hw_params() < 0 ) {
+ freelog (LOG_ERROR, "ALSA: bad format in %s", fullpath);
+ return FALSE;
+ }
+
+ if ( snd_mmap_run() < 0 || snd_mmap_run() < 0 ) {
+ return FALSE;
+ }
+
+ if ( xrun_recovery ("ALSA: start error", snd_pcm_start(sound_handle) )
+ < 0 ) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/***********
+ Initialize
+***********/
+static bool my_init (void)
+{
+ if (snd_pcm_open (&sound_handle, "default", SND_PCM_STREAM_PLAYBACK, 0)
+ < 0) {
+ return FALSE;
+ }
+
+ if ( snd_async_add_pcm_handler (&ah, sound_handle, play_callback, &ah)
+ < 0 ) {
+ freelog (LOG_ERROR, "ALSA: cannot set callback handler");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**************************************************
+ Initialize
+ Called early during startup--no logging available
+**************************************************/
+void audio_alsa_init (void)
+{
+ struct audio_plugin self;
+
+ sz_strlcpy (self.name, "alsa");
+ sz_strlcpy (self.descr, "ALSA plugin");
+ self.init = my_init;
+ self.shutdown = my_shutdown;
+ self.stop = my_stop;
+ self.wait = my_wait;
+ self.play = my_play;
+ audio_add_plugin (&self);
+}
- [Freeciv-Dev] Re: (PR#8509) ALSA sound plugin for freeciv,
Javier Pello <=
|
|