Commit 6ab1f613 authored by Bruno Coudoin's avatar Bruno Coudoin

Reorganisation of the sound playing in GCompris to split the

high level audio file management and the low level audio player
(gstreamer based for instance).
The goal behind this is to make room for an integration of
the GCOMPRIS 8.3 branch SDL Mixer player. This way we will
be able to resync the windows and master branch.
parent d6b37daa
......@@ -361,6 +361,26 @@ if test x$TETEX = xno; then
fi
dnl SDLMixer support
AC_MSG_CHECKING([wether we build with SDLMixer (will replace gstreamer by sdl mixer if enabled)])
AC_ARG_ENABLE(sdlmixer,
AC_HELP_STRING(
[--enable-sdlmixer],
[Turn on sdl mixer (will replace gstreamer by sdl mixer)]),
with_sdlmixer="$enableval", with_sdlmixer="no")
AC_MSG_RESULT($with_sdlmixer)
if test x$with_sdlmixer = xyes; then
PKG_CHECK_MODULES(AUDIO, sdl,, AC_MSG_ERROR([*** SDL Mixer not found!]))
AC_DEFINE([USE_SDLMIXER], 1,[sdl mixer is enabled])
else
dnl Default is gstreamer
PKG_CHECK_MODULES(AUDIO, gstreamer-0.10,, AC_MSG_ERROR([*** GSTREAMER not found!]))
AC_DEFINE([USE_GSTREAMER], 1,[gstreamer is enabled])
fi
AC_SUBST(AUDIO_CFLAGS)
AC_SUBST(AUDIO_LIBS)
dnl GNET support
AC_MSG_CHECKING([wether we build with GNET (if not, networking will be disabled)])
AC_ARG_ENABLE(gnet,
......@@ -825,6 +845,7 @@ echo "DBUS Support (OLPC XO Sugar) = $with_dbus"
echo "GNET Networking (--enable-gnet) = $with_gnet (networking depends on this)"
echo "BINRELOC (--enable-binreloc) = $br_cv_binreloc"
echo "NSBundle (--enable-nsbundle) = $nsbundle"
echo "SDL Mixer (--enable-sdlmixer) = $with_sdlmixer (default is gstreamer)"
echo
......
......@@ -46,6 +46,7 @@ INCLUDES = \
$(GNET_CFLAGS) \
$(DBUS_CFLAGS) \
$(cairo_cflags) \
$(AUDIO_CFLAGS) \
$(NSBUNDLE_CPPFLAGS)
gcompris_SOURCES = \
......@@ -106,6 +107,7 @@ gcompris_SOURCES = \
skin.h \
soundutil.c \
soundutil.h \
gstreamer.c \
timer.c \
timer.h \
wordlist.c \
......@@ -119,6 +121,7 @@ gcompris_LDADD = \
$(top_builddir)/src/goocanvas/src/libgoocanvas.la \
$(GCOMPRIS_LIBS) $(sqlite_ldadd) $(XML_LIBS) $(GNET_LIBS) \
$(DBUS_LIBS) \
$(AUDIO_LIBS) \
$(INTLLIBS) $(NSBUNDLE_LDFLAGS)
marshal_sources = \
......@@ -134,7 +137,6 @@ gc-marshal.c: gc-marshal.list
gc-marshal.h: gc-marshal.list
$(GLIB_GENMARSHAL) --prefix=gc_marshal $< --header > $@
EXTRA_DIST = \
Makefile.mingw gcomprisrc.rc \
gc-marshal.list
......
......@@ -1792,6 +1792,8 @@ main (int argc, char *argv[])
gc_skin_load(properties->skin);
gc_sound_build_music_list();
if(properties->music || properties->fx)
gc_sound_init();
......
/* gcompris - gstreamer.c
*
* Copyright (C) 2009 Bruno Coudoin
*
* 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 3 of the License, 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "string.h"
#include "gcompris.h"
#include <signal.h>
#include <glib.h>
#include <gst/gst.h>
static GstElement *bg_pipeline = NULL;
static GstElement *fx_pipeline = NULL;
static gboolean fx_paused = FALSE;
static gboolean bg_paused = FALSE;
/* Singleton */
static guint sound_init = 0;
/* =====================================================================
*
* =====================================================================*/
void
gc_sound_init()
{
/* Check to run the init only once */
if(sound_init == 1)
return;
sound_init = 1;
/* gstreamer init */
gst_init(NULL, NULL);
gc_sound_policy_set(PLAY_AFTER_CURRENT);
}
static gboolean
fx_bus(GstBus* bus, GstMessage* msg, gpointer data)
{
switch( GST_MESSAGE_TYPE( msg ) )
{
case GST_MESSAGE_EOS:
g_warning("fx_bus: EOS START");
gc_sound_fx_close();
gc_sound_callback((gchar *)data);
fx_play();
g_warning("fx_bus: EOS END");
break;
default:
return TRUE;
}
return FALSE;
}
static gboolean
bg_bus(GstBus* bus, GstMessage* msg, gpointer data)
{
switch( GST_MESSAGE_TYPE( msg ) ) {
case GST_MESSAGE_EOS:
g_warning("bg_bus: EOS");
gc_sound_bg_close();
bg_play(NULL);
break;
default:
return TRUE;
}
return FALSE;
}
void
gc_sound_close()
{
gc_sound_bg_close();
gc_sound_fx_close();
}
void
gc_sound_bg_close()
{
if (bg_pipeline)
{
gst_element_set_state(bg_pipeline, GST_STATE_NULL);
gst_object_unref(GST_OBJECT(bg_pipeline));
bg_pipeline = NULL;
}
}
void
gc_sound_fx_close()
{
g_warning("gc_sound_fx_close");
if (fx_pipeline)
{
gst_element_set_state(fx_pipeline, GST_STATE_NULL);
gst_object_unref(GST_OBJECT(fx_pipeline));
fx_pipeline = NULL;
}
g_warning("gc_sound_fx_close done");
}
void
gc_sound_bg_reopen()
{
if(gc_prop_get()->music)
bg_play(NULL);
}
void
gc_sound_fx_reopen()
{
}
void
gc_sound_reopen()
{
gc_sound_bg_reopen();
gc_sound_fx_reopen();
}
void
gc_sound_bg_pause()
{
if (bg_pipeline)
{
gst_element_set_state(bg_pipeline, GST_STATE_PAUSED);
}
bg_paused = TRUE;
}
void
gc_sound_bg_resume()
{
if(bg_pipeline)
gst_element_set_state(bg_pipeline, GST_STATE_PLAYING);
else
{
bg_paused = FALSE;
gc_sound_bg_reopen();
}
bg_paused = FALSE;
}
void
gc_sound_fx_pause()
{
if (fx_pipeline)
{
gst_element_set_state(fx_pipeline, GST_STATE_PAUSED);
}
fx_paused = TRUE;
}
void
gc_sound_fx_resume()
{
if(fx_pipeline)
{
gst_element_set_state(fx_pipeline, GST_STATE_PLAYING);
}
fx_paused = FALSE;
}
/* background play
*
*/
gpointer
bg_play(gpointer dummy)
{
gchar *absolute_file = gc_sound_get_next_music();
if (!absolute_file)
return NULL;
bg_pipeline = gst_element_factory_make ("playbin", "play");
if(!bg_pipeline)
{
g_warning("Failed to build the gstreamer pipeline (for background music)");
gc_prop_get()->music = 0;
return NULL;
}
gst_bus_add_watch (gst_pipeline_get_bus (GST_PIPELINE (bg_pipeline)),
bg_bus, bg_pipeline);
gchar *uri = g_strconcat("file://", absolute_file, NULL);
g_free(absolute_file);
g_warning(" bg_play %s", uri);
g_object_set (G_OBJECT (bg_pipeline), "uri", uri, NULL);
gst_element_set_state (bg_pipeline, GST_STATE_PLAYING);
g_free(uri);
return(NULL);
}
/* playing a single file
*
*/
void
fx_play()
{
gchar *file;
gchar *absolute_file;
GcomprisProperties *properties = gc_prop_get();
if(fx_pipeline)
return;
file = get_next_sound_to_play();
if(!file)
return;
g_warning(" fx_play %s", file);
absolute_file = gc_file_find_absolute(file);
if (!absolute_file ||
!properties->fx)
return;
fx_pipeline = gst_element_factory_make ("playbin", "play");
if (!fx_pipeline)
{
g_warning("Failed to build the gstreamer pipeline");
gc_prop_get()->fx = 0;
return;
}
gchar *uri = g_strconcat("file://", absolute_file, NULL);
g_free(absolute_file);
g_warning(" uri '%s'", uri);
g_object_set (G_OBJECT (fx_pipeline), "uri", uri, NULL);
gst_bus_add_watch (gst_pipeline_get_bus (GST_PIPELINE (fx_pipeline)),
fx_bus, file);
gst_element_set_state (fx_pipeline, GST_STATE_PLAYING);
g_free(uri);
return;
}
......@@ -18,93 +18,40 @@
#include "string.h"
#ifdef __APPLE__
# include <sys/types.h>
#endif
#include "gcompris.h"
#include <signal.h>
#include <glib.h>
#include <gst/gst.h>
#include <soundutil.h>
static GList *pending_queue = NULL;
static int sound_policy;
static gboolean fx_paused = FALSE;
static gboolean bg_paused = FALSE;
static GstElement *bg_pipeline = NULL;
static GstElement *fx_pipeline = NULL;
static guint bg_music_index;
GSList *music_list;
/* Singleton */
static guint sound_init = 0;
/* Forward function declarations */
static void fx_play ();
static char *get_next_sound_to_play( );
static GSList *music_list = NULL;
static gpointer bg_play (gpointer dummy);
static GSList *bg_build_music_list();
/* sound control */
void gc_sound_callback(gchar *file);
GHashTable *sound_callbacks = NULL;
/* =====================================================================
*
* =====================================================================*/
void
gc_sound_init()
{
/* Check to run the init only once */
if(sound_init == 1)
return;
sound_init = 1;
/* gstreamer init */
gst_init(NULL, NULL);
sound_policy = PLAY_AFTER_CURRENT;
music_list = bg_build_music_list();
}
static gboolean
fx_bus(GstBus* bus, GstMessage* msg, gpointer data)
gc_sound_policy_set(int policy)
{
switch( GST_MESSAGE_TYPE( msg ) )
switch (policy)
{
case GST_MESSAGE_EOS:
g_message("fx_bus: EOS START");
gc_sound_fx_close();
gc_sound_callback((gchar *)data);
fx_play();
g_message("fx_bus: EOS END");
break;
default:
break;
case PLAY_ONLY_IF_IDLE : sound_policy = PLAY_ONLY_IF_IDLE; break;
case PLAY_AFTER_CURRENT : sound_policy = PLAY_AFTER_CURRENT; break;
case PLAY_AND_INTERRUPT : sound_policy = PLAY_AND_INTERRUPT; break;
default : sound_policy = PLAY_AFTER_CURRENT;
}
return TRUE;
}
static gboolean
bg_bus(GstBus* bus, GstMessage* msg, gpointer data)
/* =====================================================================
*
* =====================================================================*/
int
gc_sound_policy_get()
{
switch( GST_MESSAGE_TYPE( msg ) ) {
case GST_MESSAGE_EOS:
g_message("bg_bus: EOS");
gc_sound_bg_close();
bg_play(NULL);
break;
default:
break;
}
return TRUE;
return sound_policy;
}
void
......@@ -114,42 +61,6 @@ gc_sound_close()
gc_sound_fx_close();
}
void
gc_sound_bg_close()
{
if (bg_pipeline)
{
gst_element_set_state(bg_pipeline, GST_STATE_NULL);
gst_element_get_state(bg_pipeline, NULL, NULL, 1000*GST_MSECOND);
gst_object_unref(GST_OBJECT(bg_pipeline));
bg_pipeline = NULL;
}
}
void
gc_sound_fx_close()
{
g_message("gc_sound_fx_close");
if (fx_pipeline)
{
gst_element_set_state(fx_pipeline, GST_STATE_NULL);
gst_element_get_state(fx_pipeline, NULL, NULL, 1000*GST_MSECOND);
gst_object_unref(GST_OBJECT(fx_pipeline));
fx_pipeline = NULL;
}
}
void
gc_sound_bg_reopen()
{
if(gc_prop_get()->music)
bg_play(NULL);
}
void
gc_sound_fx_reopen()
{
}
void
gc_sound_reopen()
......@@ -158,83 +69,33 @@ gc_sound_reopen()
gc_sound_fx_reopen();
}
void
gc_sound_bg_pause()
GSList *
gc_sound_get_music_list()
{
if (bg_pipeline)
{
gst_element_set_state(bg_pipeline, GST_STATE_PAUSED);
}
bg_paused = TRUE;
return music_list;
}
void
gc_sound_bg_resume()
char *gc_sound_get_next_music()
{
if(bg_pipeline)
{
gst_element_set_state(bg_pipeline, GST_STATE_PLAYING);
gst_element_get_state(bg_pipeline, NULL, NULL, 1000*GST_MSECOND);
}
bg_paused = FALSE;
}
static guint bg_music_index = 0;
void
gc_sound_fx_pause()
{
if (fx_pipeline)
{
gst_element_set_state(fx_pipeline, GST_STATE_PAUSED);
}
fx_paused = TRUE;
}
/* Music wrapping */
if(bg_music_index++ >= g_slist_length(gc_sound_get_music_list()))
bg_music_index = 0;
void
gc_sound_fx_resume()
{
if(fx_pipeline)
{
gst_element_set_state(fx_pipeline, GST_STATE_PLAYING);
gst_element_get_state(fx_pipeline, NULL, NULL, 1000*GST_MSECOND);
}
fx_paused = FALSE;
return gc_file_find_absolute(g_slist_nth_data(gc_sound_get_music_list(),
bg_music_index));
}
/* =====================================================================
*
* =====================================================================*/
void
gc_sound_policy_set(int policy)
{
switch (policy)
{
case PLAY_ONLY_IF_IDLE : sound_policy = PLAY_ONLY_IF_IDLE; break;
case PLAY_AFTER_CURRENT : sound_policy = PLAY_AFTER_CURRENT; break;
case PLAY_AND_INTERRUPT : sound_policy = PLAY_AND_INTERRUPT; break;
default : sound_policy = PLAY_AFTER_CURRENT;
}
}
/* =====================================================================
*
* =====================================================================*/
int
gc_sound_policy_get()
{
return sound_policy;
}
static GSList *
bg_build_music_list()
gc_sound_build_music_list()
{
GcomprisProperties *properties = gc_prop_get();
gchar *str;
gchar *music_dir;
GSList *musiclist = NULL;
GDir *dir;
const gchar *one_dirent;
bg_music_index = 0;
/* Load the Music directory file names */
music_dir = g_strconcat(properties->package_data_dir, "/music/background",
NULL);
......@@ -242,9 +103,9 @@ bg_build_music_list()
dir = g_dir_open(music_dir, 0, NULL);
if (!dir) {
g_message ("Couldn't open music dir: %s", music_dir);
g_warning ("Couldn't open music dir: %s", music_dir);
g_free(music_dir);
return NULL;
return;
}
/* Fill up the music list */
......@@ -253,132 +114,26 @@ bg_build_music_list()
if (g_str_has_suffix(one_dirent, ".ogg"))
{
str = g_strdup_printf("%s/%s", music_dir, one_dirent);
musiclist = g_slist_insert (musiclist, str,
RAND(0, g_slist_length(musiclist)));
music_list = g_slist_insert (music_list, str,
RAND(0, g_slist_length(music_list)));
}
}
g_dir_close(dir);
/* No music no play */
if(g_slist_length(musiclist)==0)
if(g_slist_length(music_list)==0)
{
g_free(music_dir);
return NULL;
}
return(musiclist);
}
/* =====================================================================
* Thread scheduler background :
* - launches a single thread for playing and play any file found
* in the gcompris music directory
======================================================================*/
static gpointer
bg_play(gpointer dummy)
{
gchar *absolute_file;
/* Music wrapping */
if(bg_music_index >= g_slist_length(music_list))
bg_music_index = 0;
absolute_file = gc_file_find_absolute(g_slist_nth_data(music_list,
bg_music_index));
if (!absolute_file)
return NULL;
bg_pipeline = gst_element_factory_make ("playbin", "play");
if(!bg_pipeline)
{
g_message("Failed to build the gstreamer pipeline (for background music)");
gc_prop_get()->music = 0;
return NULL;
}
gst_bus_add_watch (gst_pipeline_get_bus (GST_PIPELINE (bg_pipeline)),
bg_bus, bg_pipeline);
gchar *uri = g_strconcat("file://", absolute_file, NULL);
g_free(absolute_file);
g_message(" bg_play %s", uri);
g_object_set (G_OBJECT (bg_pipeline), "uri", uri, NULL);
GstStateChangeReturn statechanged = gst_element_set_state (bg_pipeline,
GST_STATE_PLAYING);
gst_element_get_state(bg_pipeline, NULL, NULL, 1000*GST_MSECOND);
if( statechanged == GST_STATE_CHANGE_SUCCESS) {
g_message("%s : bg_playing\n",__FUNCTION__);
}
g_free(uri);
return(NULL);
}
/* =====================================================================
* Thread function for playing a single file
======================================================================*/
static void
fx_play()
{
gchar *file;
gchar *absolute_file;
GcomprisProperties *properties = gc_prop_get();
if(fx_pipeline)
return;
file = get_next_sound_to_play();
if(!file)
return;
g_message(" fx_play %s", file);
absolute_file = gc_file_find_absolute(file);
if (!absolute_file ||
!properties->fx)
return;
fx_pipeline = gst_element_factory_make ("playbin", "play");
if (!fx_pipeline)
{
g_message("Failed to build the gstreamer pipeline");
gc_prop_get()->fx = 0;
return;
}
gchar *uri = g_strconcat("file://", absolute_file, NULL);
g_free(absolute_file);
g_message(" uri '%s'", uri);
g_object_set (G_OBJECT (fx_pipeline), "uri", uri, NULL);
gst_bus_add_watch (gst_pipeline_get_bus (GST_PIPELINE (fx_pipeline)),
fx_bus, file);
GstStateChangeReturn statechanged = gst_element_set_state (fx_pipeline,
GST_STATE_PLAYING);
gst_element_get_state(fx_pipeline, NULL, NULL, 1000*GST_MSECOND);
if( statechanged == GST_STATE_CHANGE_SUCCESS) {
g_message("%s : fx_playing\n",__FUNCTION__);
}
g_free(uri);
return;
}
/* =====================================================================
* Returns the next sound play, or NULL if there is no
======================================================================*/
static char*
char*
get_next_sound_to_play( )
{
char* tmpSound = NULL;
......@@ -387,7 +142,7 @@ get_next_sound_to_play( )
{
tmpSound = g_list_nth_data( pending_queue, 0 );
pending_queue = g_list_remove( pending_queue, tmpSound );
g_message( "... get_next_sound_to_play : %s\n", tmpSound );
g_warning( "... get_next_sound_to_play : %s\n", tmpSound );
}
return tmpSound;
......@@ -438,7 +193,7 @@ gc_sound_play_ogg(const gchar *sound, ...)
list = g_list_append(list, (gpointer)sound);
g_message("Adding %s in the play list queue\n", sound);
g_warning("Adding %s in the play list queue\n", sound);
va_start( ap, sound);
while( (tmp = va_arg (ap, char *)))
......@@ -463,24 +218,24 @@ void
gc_sound_play_ogg_list( GList* files )
{
GList* list;
char* tmpSound = NULL;
gchar* tmpSound = NULL;