/* gcompris - soundutil.c
*
* Copyright (C) 2002 Pascal Georges
*
* 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 .
*/
#include
#ifdef USE_SDLMIXER
#include "string.h"
#ifdef __APPLE__
# include
#endif
#include "gcompris.h"
#include "soundutil_sdl.h"
#include
#include
static int sound_policy;
static gboolean music_paused = FALSE;
static gboolean sound_closed = FALSE;
/* mutex */
GMutex *lock = NULL;
GMutex *lock_music = NULL;
GMutex *lock_fx = NULL;
GCond *cond = NULL;
/* Singleton */
static guint sound_init = 0;
/* Forward function declarations */
GThread *thread_scheduler_fx, *thread_scheduler_music;
static void *thread_play_ogg (gchar *file);
static gpointer scheduler_fx (gpointer user_data);
static gpointer scheduler_music (gpointer user_data);
/* sound control */
GObject *gc_sound_controller = NULL;
void gc_sound_callback_sdl(GcomprisSound *ctl,
gchar *file, gpointer user_data);
/* =====================================================================
*
* =====================================================================*/
void
gc_sound_init()
{
/* Check to run the init once only */
if(sound_init == 1)
{
if(sound_closed == TRUE)
gc_sound_reopen();
return;
}
sound_init = 1;
gc_sound_controller = g_object_new (GCOMPRIS_SOUND_TYPE, NULL);
g_signal_connect( gc_sound_controller,
"sound-played",
(GCallback) gc_sound_callback_sdl,
NULL);
g_assert( gc_sound_controller != NULL );
/* Initialize the thread system */
if (!g_thread_supported ()) g_thread_init (NULL);
lock = g_mutex_new ();
lock_music = g_mutex_new ();
lock_fx = g_mutex_new ();
cond = g_cond_new ();
sound_policy = PLAY_AFTER_CURRENT;
if(sdlplayer_init()!=0) {
/* Sound init failed. Desactivate the sound */
gc_prop_get()->music = 0;
gc_prop_get()->fx = 0;
return;
}
thread_scheduler_fx = g_thread_create((GThreadFunc)scheduler_fx, NULL, FALSE, NULL);
if (thread_scheduler_fx == NULL)
perror("create failed for fx scheduler");
thread_scheduler_music = g_thread_create((GThreadFunc)scheduler_music, NULL, FALSE, NULL);
if (thread_scheduler_music == NULL)
perror("create failed for music scheduler");
}
void
gc_sound_bg_close()
{
if ( !sound_closed )
{
sound_closed = TRUE;
if ( music_paused ) {
music_paused = FALSE;
gc_sound_bg_resume();
}
g_mutex_lock(lock_fx);
sdlplayer_halt_music();
sdlplayer_halt_fx();
g_mutex_lock(lock_music);
sdlplayer_close();
}
}
void
gc_sound_fx_close()
{
}
void
gc_sound_fx_reopen()
{
if (gc_prop_get()->fx || gc_prop_get()->music) {
if (sound_closed)
{
sdlplayer_reopen();
g_mutex_unlock(lock_fx);
g_mutex_unlock(lock_music);
sound_closed = FALSE;
music_paused = FALSE;
}
}
}
void
gc_sound_bg_reopen()
{
}
void
gc_sound_bg_pause()
{
sdlplayer_pause_music();
music_paused = TRUE;
}
void
gc_sound_bg_resume()
{
sdlplayer_resume_music();
music_paused = FALSE;
}
void
gc_sound_fx_pause()
{
}
void
gc_sound_fx_resume()
{
}
/* =====================================================================
* Thread scheduler background :
* - launches a single thread for playing and play any file found
* in the gcompris music directory
======================================================================*/
static gpointer
scheduler_music (gpointer user_data)
{
GcomprisProperties *properties = gc_prop_get();
gint i;
gchar *str;
gchar *music_dir;
GSList *musiclist = NULL;
GDir *dir;
const gchar *one_dirent;
/* Sleep to let gcompris intialisation and intro music to complete */
g_usleep(25000000);
/* Load the Music directory file names */
music_dir = g_strconcat(properties->package_data_dir, "/music/background", NULL);
dir = g_dir_open(music_dir, 0, NULL);
if (!dir) {
g_warning ("Couldn't open music dir: %s", music_dir);
g_free(music_dir);
return NULL;
}
/* Fill up the music list */
while((one_dirent = g_dir_read_name(dir)) != NULL)
{
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)));
}
}
g_dir_close(dir);
/* No music no play */
if(g_slist_length(musiclist)==0)
{
g_free(music_dir);
return NULL;
}
/* Now loop over all our music files */
while (TRUE)
{
for(i=0; imusic || music_paused || sound_closed)
g_usleep(1000000);
/* WARNING Displaying stuff in a thread seems to make gcompris unstable */
/* display_ogg_file_credits((char *)g_list_nth_data(musiclist, i)); */
// if(decode_ogg_file((char *)g_list_nth_data(musiclist, i))!=0)
g_mutex_lock(lock_music);
if(sdlplayer_music((char *)g_slist_nth_data(musiclist, i), 128)!=0){
g_warning("sdlplayer_music failed, try again in 5 seconds");
g_usleep(5000000);
}
g_mutex_unlock(lock_music);
}
}
/* Never happen */
g_slist_free(musiclist);
g_warning( "The background thread music is stopped now. "\
"The files in %s are not ogg vorbis OR the sound output failed",
music_dir);
g_free(music_dir);
return NULL;
}
/* =====================================================================
* Thread scheduler :
* - launches a single thread for playing a file
* - joins the previous thread at its end
* - then launches another thread if some sounds are pending
* - the thread never ends
======================================================================*/
static gpointer
scheduler_fx (gpointer user_data)
{
char *sound = NULL;
while (TRUE)
{
if ( ( sound = get_next_sound_to_play( ) ) != NULL )
{
thread_play_ogg(sound);
g_free(sound);
}
else
{
g_mutex_lock (lock);
g_cond_wait (cond, lock);
g_mutex_unlock (lock);
}
}
return NULL;
}
/* =====================================================================
* Thread function for playing a single file
======================================================================*/
static void*
thread_play_ogg (gchar *file)
{
gchar *absolute_file;
g_warning(" Thread_play_ogg %s", file);
absolute_file = gc_file_find_absolute(file);
if (!absolute_file)
return NULL;
g_warning(" Calling gcompris internal sdlplayer_file (%s)", absolute_file);
g_mutex_lock(lock_fx);
sdlplayer_fx(absolute_file, 128);
g_mutex_unlock(lock_fx);
g_signal_emit (gc_sound_controller,
GCOMPRIS_SOUND_GET_CLASS (gc_sound_controller)->sound_played_signal_id,
0 /* details */,
g_strdup(file));
g_warning(" sdlplayer_fx(%s) ended.", absolute_file);
g_free(absolute_file);
return NULL;
}
void
fx_play()
{
// Tell the scheduler to check for new sounds to play
g_warning("Tell the scheduler to check for new sounds to play\n");
g_cond_signal (cond);
}
void gc_sound_callback_sdl(GcomprisSound *ctl,
gchar *file, gpointer user_data)
{
gc_sound_callback(file);
}
/*************************************/
/* GObject control sound */
struct _GcomprisSoundPrivate
{
};
/* "gcompris-marshal.h" */
#include
/* VOID:POINTER (gcompris-marshal.list:3) */
#define gnome_canvas_marshal_VOID__POINTER g_cclosure_marshal_VOID__POINTER
static void
gc_sound_instance_init (GTypeInstance *instance,
gpointer g_class)
{
GcomprisSound *self = (GcomprisSound *)instance;
self->private = g_new (GcomprisSoundPrivate, 1);
}
static void
default_sound_played_signal_handler (GcomprisSound *obj, gchar *file, gpointer user_data)
{
/* Here, we trigger the real file write. */
g_warning ("sound_played: %s\n", file);
}
static void
gc_sound_class_init (gpointer g_class,
gpointer g_class_data)
{
GcomprisSoundClass *klass = GCOMPRIS_SOUND_CLASS (g_class);
klass->sound_played = default_sound_played_signal_handler;
klass->sound_played_signal_id =
g_signal_new ("sound-played",
G_TYPE_FROM_CLASS (g_class),
G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
G_STRUCT_OFFSET (GcomprisSoundClass, sound_played),
NULL /* accumulator */,
NULL /* accu_data */,
gnome_canvas_marshal_VOID__POINTER,
G_TYPE_NONE /* return_type */,
1 /* n_params */,
G_TYPE_POINTER /* param_types */);
}
GType gc_sound_get_type (void)
{
static GType type = 0;
if (type == 0) {
static const GTypeInfo info = {
sizeof (GcomprisSoundClass),
NULL, /* base_init */
NULL, /* base_finalize */
gc_sound_class_init, /* class_init */
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (GcomprisSound),
0, /* n_preallocs */
gc_sound_instance_init /* instance_init */
};
type = g_type_register_static (G_TYPE_OBJECT,
"GcomprisSoundType",
&info, 0);
}
return type;
}
#endif