diff options
author | Yves Combe <ycombe@src.gnome.org> | 2006-12-08 12:17:50 (GMT) |
---|---|---|
committer | Yves Combe <ycombe@src.gnome.org> | 2006-12-08 12:17:50 (GMT) |
commit | 59a68ac4a498251f80b4cce4306078492c37f781 (patch) | |
tree | 6e200a7b2fc816bd308e567d394b3525255d594a | |
parent | 3029281726ef0767af37b5e4922a8edb54013d14 (diff) |
gc_sound: Work on destroy recursive on mixer-SDL/channel/item
-rw-r--r-- | ChangeLog | 46 | ||||
-rw-r--r-- | src/gc_sound/ChangeLog | 43 | ||||
-rw-r--r-- | src/gc_sound/src/gc-sound-channel.c | 93 | ||||
-rw-r--r-- | src/gc_sound/src/gc-sound-channel.h | 6 | ||||
-rw-r--r-- | src/gc_sound/src/gc-sound-item.c | 50 | ||||
-rw-r--r-- | src/gc_sound/src/gc-sound-item.h | 3 | ||||
-rw-r--r-- | src/gc_sound/src/gc-sound-mixer-SDL.c | 148 | ||||
-rw-r--r-- | src/gc_sound/src/gc-sound-mixer-SDL.h | 8 | ||||
-rw-r--r-- | src/gc_sound/src/gc-sound-object.c | 42 | ||||
-rw-r--r-- | src/gc_sound/src/gc-sound-object.h | 9 | ||||
-rw-r--r-- | src/gc_sound/src/test_gc_sound.c | 92 |
11 files changed, 335 insertions, 205 deletions
@@ -1,3 +1,49 @@ +2006-12-08 Yves Combe <yves@ycombe.net> + + GC_SOUND + Work on destroy recursive on mixer-SDL/channel/item + TODO: + - fix if channel is destroyed before mixer, + an error occurs when mixer is destroyed? + - python bindings + + * src/gc_sound/ChangeLog: + * src/gc_sound/src/gc-sound-channel.c: + (gc_sound_channel_play_item), (gc_sound_channel_pause), + (gc_sound_channel_resume), (gc_sound_channel_halt), + (gc_sound_channel_play), (root_destroyed), + (gc_sound_channel_destroy), (gc_sound_channel_init), + (gc_sound_channel_get_property), (gc_sound_channel_set_property), + (gc_sound_channel_signal_chunk_end), (gc_sound_channel_signal_run), + (gc_sound_channel_class_init): + * src/gc_sound/src/gc-sound-channel.h: + * src/gc_sound/src/gc-sound-item.c: (gc_sound_item_run_next), + (gc_sound_item_child_destroyed), (gc_sound_item_append_child), + (gc_sound_item_signal_real_play), (gc_sound_item_signal_play_end), + (gc_sound_item_signal_play_start), + (gc_sound_item_signal_chunk_end), + (gc_sound_item_signal_chunk_start), (gc_sound_item_init), + (gc_sound_item_get_property), (gc_sound_item_set_property), + (gc_sound_item_class_init): + * src/gc_sound/src/gc-sound-item.h: + * src/gc_sound/src/gc-sound-mixer-SDL.c: + (gc_sound_mixer_SDL_open_audio), (reset_channel_number), + (channel_destroyed), (gc_sound_mixer_SDL_new_channel), + (gc_sound_mixer_SDL_pause_channel), + (gc_sound_mixer_SDL_resume_channel), + (gc_sound_mixer_SDL_halt_channel), (gc_sound_mixer_SDL_play_item), + (channel_finished_cb), (gc_sound_mixer_SDL_channel_finished), + (gc_sound_mixer_SDL_init), (gc_sound_mixer_SDL_finalize), + (gc_sound_mixer_SDL_destroy), (gc_sound_mixer_SDL_class_init), + (gc_init_sound_mixer): + * src/gc_sound/src/gc-sound-mixer-SDL.h: + * src/gc_sound/src/gc-sound-object.c: (gc_sound_object_class_init), + (gc_sound_object_init), (gc_sound_object_destroy), + (parent_destroyed), (gc_sound_object_set_property), + (gc_sound_object_get_property): + * src/gc_sound/src/gc-sound-object.h: + * src/gc_sound/src/test_gc_sound.c: (finish), (start), (main): + 2006-12-01 Yves Combe <yves@ycombe.net> GCSound: diff --git a/src/gc_sound/ChangeLog b/src/gc_sound/ChangeLog index f6b9f90..3389b8a 100644 --- a/src/gc_sound/ChangeLog +++ b/src/gc_sound/ChangeLog @@ -1,3 +1,46 @@ +2006-12-08 Yves Combe <yves@ycombe.net> + + Work on destroy recursive on mixer-SDL/channel/item + TODO: + - fix if channel is destroyed before mixer, + an error occurs when mixer is destroyed? + - python bindings + + * src/gc-sound-channel.c: (gc_sound_channel_play_item), + (gc_sound_channel_pause), (gc_sound_channel_resume), + (gc_sound_channel_halt), (gc_sound_channel_play), (root_destroyed), + (gc_sound_channel_destroy), (gc_sound_channel_init), + (gc_sound_channel_get_property), (gc_sound_channel_set_property), + (gc_sound_channel_signal_chunk_end), (gc_sound_channel_signal_run), + (gc_sound_channel_class_init): + * src/gc-sound-channel.h: + * src/gc-sound-item.c: (gc_sound_item_run_next), + (gc_sound_item_child_destroyed), (gc_sound_item_append_child), + (gc_sound_item_signal_real_play), (gc_sound_item_signal_play_end), + (gc_sound_item_signal_play_start), + (gc_sound_item_signal_chunk_end), + (gc_sound_item_signal_chunk_start), (gc_sound_item_init), + (gc_sound_item_get_property), (gc_sound_item_set_property), + (gc_sound_item_class_init): + * src/gc-sound-item.h: + * src/gc-sound-mixer-SDL.c: (gc_sound_mixer_SDL_open_audio), + (reset_channel_number), (channel_destroyed), + (gc_sound_mixer_SDL_new_channel), + (gc_sound_mixer_SDL_pause_channel), + (gc_sound_mixer_SDL_resume_channel), + (gc_sound_mixer_SDL_halt_channel), (gc_sound_mixer_SDL_play_item), + (channel_finished_cb), (gc_sound_mixer_SDL_channel_finished), + (gc_sound_mixer_SDL_init), (gc_sound_mixer_SDL_finalize), + (gc_sound_mixer_SDL_destroy), (gc_sound_mixer_SDL_class_init), + (gc_init_sound_mixer): + * src/gc-sound-mixer-SDL.h: + * src/gc-sound-object.c: (gc_sound_object_class_init), + (gc_sound_object_init), (gc_sound_object_destroy), + (parent_destroyed), (gc_sound_object_set_property), + (gc_sound_object_get_property): + * src/gc-sound-object.h: + * src/test_gc_sound.c: (finish), (start), (main): + 2006-12-01 Yves Combe <yves@ycombe.net> Add GCSoundObject to have a base class with destroy signal/functions. diff --git a/src/gc_sound/src/gc-sound-channel.c b/src/gc_sound/src/gc-sound-channel.c index 15592a8..8f03d3e 100644 --- a/src/gc_sound/src/gc-sound-channel.c +++ b/src/gc_sound/src/gc-sound-channel.c @@ -38,12 +38,10 @@ guint gc_sound_channel_signals[N_SIGNALS] = {0}; gboolean gc_sound_channel_play_item (GCSoundChannel * self, GCSoundItem *item) { - g_warning("gc_sound_channel_play_item %s %s", self->nick, item->nick); - self->running_sample = item; self->stopped = FALSE; - return gc_sound_mixer_play_item (self->mixer, self, item); + return gc_sound_mixer_play_item (GC_SOUND_MIXER(GC_SOUND_OBJECT(self)->parent), self, item); } GCSoundItem * gc_sound_channel_get_root (GCSoundChannel * self) @@ -53,17 +51,17 @@ GCSoundItem * gc_sound_channel_get_root (GCSoundChannel * self) gboolean gc_sound_channel_pause (GCSoundChannel * self) { - return gc_sound_mixer_pause_channel( self->mixer, self); + return gc_sound_mixer_pause_channel( GC_SOUND_MIXER(GC_SOUND_OBJECT(self)->parent), self); } gboolean gc_sound_channel_resume (GCSoundChannel * self) { - return gc_sound_mixer_resume_channel( self->mixer, self); + return gc_sound_mixer_resume_channel( GC_SOUND_MIXER(GC_SOUND_OBJECT(self)->parent), self); } gboolean gc_sound_channel_halt (GCSoundChannel * self) { - return gc_sound_mixer_halt_channel( self->mixer, self); + return gc_sound_mixer_halt_channel(GC_SOUND_MIXER(GC_SOUND_OBJECT(self)->parent), self); } GCSoundPolicy gc_sound_channel_get_policy (GCSoundChannel * self) @@ -88,8 +86,6 @@ gboolean gc_sound_channel_play (GCSoundChannel *self, else policy = gc_sound_item_get_policy(item); - //g_warning ("play_item %s with policy %d", item->nick, policy); - switch (policy) { case GC_SOUND_PLAY_ONLY_IF_IDLE: if (self->running_sample || g_list_length (self->playlist)>0) @@ -99,26 +95,22 @@ gboolean gc_sound_channel_play (GCSoundChannel *self, g_signal_emit(self, gc_sound_channel_signals[RUN], 0); break; - case GC_SOUND_INTERRUPT_AND_PLAY: - g_list_free (self->playlist); - self->playlist = NULL; - self->playlist = g_list_append (self->playlist, item); - if (self->running_sample){ - self->stopped = TRUE; - //g_warning("halting channel %d %d", self->_priv->channel, g_list_length(self->_priv->play_list)); - // send a signal to halt. - gc_sound_channel_halt(self); - } - // TODO send a signal to run !!! + case GC_SOUND_INTERRUPT_AND_PLAY: + g_list_free (self->playlist); + self->playlist = NULL; + self->playlist = g_list_append (self->playlist, item); + if (self->running_sample){ + self->stopped = TRUE; + gc_sound_channel_halt(self); + } + g_signal_emit(self, gc_sound_channel_signals[RUN], 0); + break; + + default: + self->playlist = g_list_append (self->playlist, item); + if (!self->running_sample) g_signal_emit(self, gc_sound_channel_signals[RUN], 0); - break; - - default: - self->playlist = g_list_append (self->playlist, item); - if (!self->running_sample) - // TODO send a signal to run !!! - g_signal_emit(self, gc_sound_channel_signals[RUN], 0); - break; + break; } } @@ -131,7 +123,23 @@ enum { /* GType */ -G_DEFINE_TYPE(GCSoundChannel, gc_sound_channel, G_TYPE_OBJECT); +G_DEFINE_TYPE(GCSoundChannel, gc_sound_channel, GC_TYPE_SOUND_OBJECT); + +static void root_destroyed (GCSoundObject *root, gpointer data) +{ + // direct call claas destroy because root is already destroyed. + + GC_SOUND_OBJECT_GET_CLASS(data)->destroy (GC_SOUND_OBJECT(data)); +} + +static void +gc_sound_channel_destroy (GCSoundChannel *self){ + g_signal_handlers_disconnect_by_func(self->root, root_destroyed, self); + gc_sound_object_destroy(GC_SOUND_OBJECT(self->root)); + g_object_unref(self->root); + + GC_SOUND_OBJECT_GET_CLASS(self)->destroy (GC_SOUND_OBJECT(self)); +} static void gc_sound_channel_init(GCSoundChannel* self) @@ -144,9 +152,13 @@ gc_sound_channel_init(GCSoundChannel* self) self->stopped = FALSE; - self->mixer = NULL; + GC_SOUND_OBJECT(self)->parent = NULL; self->root = GC_SOUND_ITEM(g_object_new(GC_TYPE_SOUND_ITEM, "channel", self, NULL)); + g_object_ref_sink(G_OBJECT(self->root)); + + g_signal_connect(G_OBJECT(self->root), "destroy", (GCallback) root_destroyed, self); + self->playlist = NULL; //this one is the item with the file @@ -154,9 +166,6 @@ gc_sound_channel_init(GCSoundChannel* self) // this one is the group playing self->running_root = NULL; - //debug. will be removed. - gchar *nick; - } static void @@ -164,9 +173,6 @@ gc_sound_channel_get_property(GObject* object, guint prop_id, GValue* value, GPa { GCSoundChannel *self = GC_SOUND_CHANNEL(object); switch(prop_id) { - case PROP_MIXER: - g_value_set_object(value, self->mixer); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; @@ -179,9 +185,6 @@ gc_sound_channel_set_property(GObject* object, guint prop_id, GValue const* valu GCSoundChannel *self = GC_SOUND_CHANNEL(object); switch(prop_id) { - case PROP_MIXER: - self->mixer = g_value_get_object(value); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; @@ -198,8 +201,6 @@ gc_sound_channel_signal_chunk_end (GCSoundChannel *self) g_return_if_fail(GC_IS_SOUND_ITEM(chunk)); - g_warning ("%s received chunk_end self->stopped %s", self->nick, self->stopped ? "TRUE" : "FALSE"); - g_signal_emit_by_name (chunk, "chunk_end", 0, self->stopped); } @@ -209,8 +210,6 @@ gc_sound_channel_signal_run (GCSoundChannel *self) GList *item_root; gboolean ret; - g_warning("Channel %s received run !", self->nick); - while (g_list_length(self->playlist)>0) { self->running_root = g_list_first (self->playlist); @@ -236,15 +235,6 @@ gc_sound_channel_class_init(GCSoundChannelClass* self_class) go_class->get_property = gc_sound_channel_get_property; go_class->set_property = gc_sound_channel_set_property; - g_object_class_install_property(go_class, - PROP_MIXER, - g_param_spec_object ("mixer", - "GCompris mixer", - "The mixer where this channel stand", - GC_TYPE_SOUND_MIXER, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - - /* signals */ /* enum { */ /* RUN, /\* internal: launch recursive playing of playlist *\/ */ @@ -261,6 +251,7 @@ gc_sound_channel_class_init(GCSoundChannelClass* self_class) self_class->run = gc_sound_channel_signal_run; self_class->chunk_end = gc_sound_channel_signal_chunk_end; + self_class->destroy = gc_sound_channel_destroy; gc_sound_channel_signals[RUN] = g_signal_new("run", /* name */ diff --git a/src/gc_sound/src/gc-sound-channel.h b/src/gc_sound/src/gc-sound-channel.h index 855d5b4..ab6b487 100644 --- a/src/gc_sound/src/gc-sound-channel.h +++ b/src/gc_sound/src/gc-sound-channel.h @@ -71,17 +71,15 @@ struct _GCSoundChannel { GList* running_root; gint channel_number; - - //debug. will be removed. - gchar *nick; }; struct _GCSoundChannelClass { GCSoundObjectClass __parentClass__; /* signal handlers */ - void (* run) (GCSoundChannel * self); + void (* run) (GCSoundChannel * self); void (* chunk_end) (GCSoundChannel * self); + void (* destroy) (GCSoundChannel *self); }; GCSoundItem * gc_sound_channel_get_root (GCSoundChannel * self); diff --git a/src/gc_sound/src/gc-sound-item.c b/src/gc_sound/src/gc-sound-item.c index 9820be5..c6b0e15 100644 --- a/src/gc_sound/src/gc-sound-item.c +++ b/src/gc_sound/src/gc-sound-item.c @@ -45,8 +45,6 @@ gboolean gc_sound_item_run_next (GCSoundItem *self, { gboolean ret; - g_warning("run_next %s %d", self->nick, stopped); - /* if we are stopped, we don't continue */ if (stopped) { g_signal_emit(self, gc_sound_item_signals[PLAY_END], 0, stopped); @@ -69,7 +67,6 @@ gboolean gc_sound_item_run_next (GCSoundItem *self, self->playing = g_list_next (self->playing ); if ((self->playing == NULL) && (self->loop)) { - g_warning ("looping on %s", self->nick); self->playing = g_list_first (self->children ); } @@ -133,20 +130,32 @@ void gc_sound_item_child_end( GCSoundItem *child, gboolean stopped, gpointer dat gc_sound_item_run_next(self, stopped); } +void gc_sound_item_child_destroyed( GCSoundItem *child, gpointer data) +{ + GCSoundItem *self = GC_SOUND_ITEM(data); + + self->children = g_list_remove ( self->children, child); + g_object_unref (G_OBJECT(child)); +} + GCSoundItem * gc_sound_item_append_child (GCSoundItem *self) { GCSoundItem *child; - child = GC_SOUND_ITEM(g_object_new(gc_sound_item_get_type(), "parent", self, "channel", self->channel, NULL)); + child = GC_SOUND_ITEM(g_object_new(GC_TYPE_SOUND_ITEM, + "parent", self, + "channel", self->channel, + NULL)); /* Child is added to our lists */ self->children = g_list_append (self->children, child); /* we get a ref */ - g_object_ref (G_OBJECT(child)); + g_object_ref_sink (G_OBJECT(child)); g_signal_connect( child, "play-end", (GCallback) gc_sound_item_child_end, self); g_signal_connect( child, "play-start", (GCallback) gc_sound_item_child_start, self); + g_signal_connect( child, "destroy", (GCallback) gc_sound_item_child_destroyed, self); return child; } @@ -177,8 +186,6 @@ gchar * gc_sound_item_get_filename (GCSoundItem *self) static void gc_sound_item_signal_real_play (GCSoundItem *self) { - g_warning("item %s received real_play", self->nick); - g_signal_emit(self, gc_sound_item_signals[CHUNK_START], 0); gc_sound_channel_play_item (self->channel, self); } @@ -186,8 +193,6 @@ gc_sound_item_signal_real_play (GCSoundItem *self) static void gc_sound_item_signal_play_end (GCSoundItem *self, gboolean stopped) { - g_warning("item %s received play_end", self->nick); - if (self->has_played || stopped) { self->started = FALSE; self->has_played = FALSE; @@ -198,16 +203,12 @@ gc_sound_item_signal_play_end (GCSoundItem *self, gboolean stopped) static void gc_sound_item_signal_play_start (GCSoundItem *self) { - g_warning("item %s received play_start", self->nick); - self->started = TRUE; } static void gc_sound_item_signal_chunk_end (GCSoundItem *self, gboolean stopped) { - g_warning("item %s received chunk_end", self->nick); - /* We receive this signal from channel when play of chunk if finished. We have to continue play in our group. @@ -219,8 +220,6 @@ gc_sound_item_signal_chunk_end (GCSoundItem *self, gboolean stopped) static void gc_sound_item_signal_chunk_start (GCSoundItem *self) { - g_warning("item %s received chunk_start", self->nick); - self->started = TRUE; } @@ -228,19 +227,16 @@ gc_sound_item_signal_chunk_start (GCSoundItem *self) enum { PROP_0, PROP_CHANNEL, - PROP_PARENT, PROP_FILENAME }; /* GType */ -G_DEFINE_TYPE(GCSoundItem, gc_sound_item, G_TYPE_OBJECT); +G_DEFINE_TYPE(GCSoundItem, gc_sound_item, GC_TYPE_SOUND_OBJECT); static void gc_sound_item_init(GCSoundItem* self) { // initialisation des variables. - g_warning("gc_sound_item_init"); - self->volume = -1.0; self->mute = FALSE; @@ -276,9 +272,6 @@ gc_sound_item_get_property(GObject* object, guint prop_id, GValue* value, GParam case PROP_CHANNEL: g_value_set_object(value, self->channel); break; - case PROP_PARENT: - g_value_set_object(value, self->parent); - break; case PROP_FILENAME: g_value_set_string(value, self->filename); break; @@ -297,9 +290,6 @@ gc_sound_item_set_property(GObject* object, guint prop_id, GValue const* value, case PROP_CHANNEL: self->channel = g_value_get_object(value); break; - case PROP_PARENT: - self->parent = g_value_get_object(value); - break; case PROP_FILENAME: gc_sound_item_set_filename( self, (gchar *)g_value_get_string(value)); break; @@ -314,8 +304,6 @@ static void gc_sound_item_class_init(GCSoundItemClass* self_class) { // c'est ici qu'il faut passer les properties et les signals. - g_warning("gc_sound_item_class_init"); - GObjectClass* go_class; /* GObjectClass */ @@ -332,14 +320,6 @@ gc_sound_item_class_init(GCSoundItemClass* self_class) GC_TYPE_SOUND_CHANNEL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - g_object_class_install_property(go_class, - PROP_PARENT, - g_param_spec_object ("parent", - "GCompris parent", - "The parent where this channel stand", - GC_TYPE_SOUND_ITEM, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - /* signals */ /* enum { */ /* RUN, /\* internal: launch recursive playing of playlist *\/ */ diff --git a/src/gc_sound/src/gc-sound-item.h b/src/gc_sound/src/gc-sound-item.h index ee1d037..967eb77 100644 --- a/src/gc_sound/src/gc-sound-item.h +++ b/src/gc_sound/src/gc-sound-item.h @@ -60,9 +60,6 @@ struct _GCSoundItem { GCSoundItem* parent; GList* children; - //debug. will be removed - gchar * nick; - //internal use // TRUE if we are in running play tree. gboolean has_played; diff --git a/src/gc_sound/src/gc-sound-mixer-SDL.c b/src/gc_sound/src/gc-sound-mixer-SDL.c index e800c97..ae1aa17 100644 --- a/src/gc_sound/src/gc-sound-mixer-SDL.c +++ b/src/gc_sound/src/gc-sound-mixer-SDL.c @@ -75,13 +75,13 @@ gc_sound_mixer_SDL_open_audio (GCSoundMixer* mixer) // print out some info on the audio device and stream Mix_QuerySpec(&audio_rate, &audio_format, &audio_channels); bits=audio_format&0xFF; - Mix_AllocateChannels(g_hash_table_size(self->channels_from_pointer)); + Mix_AllocateChannels(self->channels->len); g_warning("Opened audio at %d Hz %d bit %s, %d bytes audio buffer number of channels %d", audio_rate, bits, audio_channels>1?"stereo":"mono", audio_buffers, - g_hash_table_size(self->channels_from_pointer)); + self->channels->len); return TRUE; } @@ -105,39 +105,67 @@ gc_sound_mixer_SDL_close_audio (GCSoundMixer * mixer) return TRUE; } +static void reset_channel_number(GCSoundChannel *channel, gboolean stopped, gpointer data) +{ + channel->channel_number = GPOINTER_TO_INT(data); +} + +static void channel_destroyed(GCSoundChannel *channel, gpointer data) +{ + GCSoundMixerSDL *self = GC_SOUND_MIXER_SDL (data); + int i; + + //check if channel is playing + if (channel->running_sample) { + // Correct. As channel take a ref on itself when it's playing, it will + // not be finalized before it get this signal. + gc_sound_mixer_halt_channel (GC_SOUND_MIXER(self), channel); + } + + g_ptr_array_remove_index (self->channels, channel->channel_number); + g_object_unref (channel); + + /* channel reorganisation */ + for (i = 0; i < self->channels->len; i++) { + GCSoundChannel *i_channel = g_ptr_array_index (self->channels, i); + + if (i!=i_channel->channel_number) { + if (i_channel->running_sample) + g_signal_connect(i_channel, "chunk_end", (GCallback) reset_channel_number, GINT_TO_POINTER(i)); + else + reset_channel_number ( i_channel, FALSE, GINT_TO_POINTER(i)); + } + } +} + static GCSoundChannel *gc_sound_mixer_SDL_new_channel (GCSoundMixer * mixer) - { +{ GCSoundMixerSDL* self; g_return_val_if_fail(GC_IS_SOUND_MIXER_SDL(mixer), FALSE); self = GC_SOUND_MIXER_SDL(mixer); - g_warning ("gc_sound_mixer_SDL_new_channel"); - GCSoundChannel *channel = GC_SOUND_CHANNEL(g_object_new(GC_TYPE_SOUND_CHANNEL, - "mixer", self, NULL)); + "parent", self, NULL)); g_assert (channel != 0); - channel->channel_number = g_hash_table_size(self->channels_from_pointer); - - g_warning ("inserting channel %d into tables", channel->channel_number); - g_hash_table_insert (self->channels_from_pointer, - channel, - GINT_TO_POINTER(channel->channel_number)); + channel->channel_number = self->channels->len; - g_hash_table_insert (self->channels_to_pointer, - &(channel->channel_number), - channel); + g_ptr_array_add (self->channels, + channel); Mix_AllocateChannels(channel->channel_number + 1); - g_warning ("Numbers of channels allocated %d", Mix_AllocateChannels(-1)); + g_warning ("Numbers of channels allocated is now %d", Mix_AllocateChannels(-1)); - return channel; - } + g_object_ref_sink(G_OBJECT(channel)); + + g_signal_connect(G_OBJECT(channel), "destroy", (GCallback) channel_destroyed, self); + return channel; +} gboolean gc_sound_mixer_SDL_pause (GCSoundMixer * mixer) { @@ -193,11 +221,7 @@ gc_sound_mixer_SDL_pause_channel (GCSoundMixer * mixer, GCSoundChannel * cha g_return_val_if_fail(GC_IS_SOUND_MIXER_SDL(mixer), FALSE); g_return_val_if_fail(GC_IS_SOUND_CHANNEL(channel), FALSE); - self = GC_SOUND_MIXER_SDL(mixer); - int channel_number = (int) g_hash_table_lookup (self->channels_from_pointer, - channel); - - Mix_Pause (channel_number); + Mix_Pause (channel->channel_number); } gboolean @@ -208,12 +232,7 @@ gc_sound_mixer_SDL_resume_channel (GCSoundMixer * mixer, GCSoundChannel * cha g_return_val_if_fail(GC_IS_SOUND_MIXER_SDL(mixer), FALSE); g_return_val_if_fail(GC_IS_SOUND_CHANNEL(channel), FALSE); - self = GC_SOUND_MIXER_SDL(mixer); - - int channel_number = (int) g_hash_table_lookup (self->channels_from_pointer, - channel); - - Mix_Resume (channel_number); + Mix_Resume (channel->channel_number); return TRUE; } @@ -226,12 +245,7 @@ gc_sound_mixer_SDL_halt_channel (GCSoundMixer * mixer, GCSoundChannel * cha g_return_val_if_fail(GC_IS_SOUND_MIXER_SDL(mixer), FALSE); g_return_val_if_fail(GC_IS_SOUND_CHANNEL(channel), FALSE); - self = GC_SOUND_MIXER_SDL(mixer); - - int channel_number = (int) g_hash_table_lookup (self->channels_from_pointer, - channel); - - Mix_HaltChannel (channel_number); + Mix_HaltChannel (channel->channel_number); return TRUE; } @@ -249,10 +263,7 @@ gc_sound_mixer_SDL_play_item (GCSoundMixer * mixer, GCSoundChannel * channel, G self = GC_SOUND_MIXER_SDL(mixer); - int channel_number = (int) g_hash_table_lookup (self->channels_from_pointer, - channel); - - if (Mix_Playing(channel_number)){ + if (Mix_Playing(channel->channel_number)){ g_warning("Channel busy ? no play!"); return FALSE; } @@ -273,7 +284,7 @@ gc_sound_mixer_SDL_play_item (GCSoundMixer * mixer, GCSoundChannel * channel, G else Mix_VolumeChunk(sample, (int) item->volume * MIX_MAX_VOLUME); - if (Mix_PlayChannel(channel_number, sample, 0)==-1) { + if (Mix_PlayChannel(channel->channel_number, sample, 0)==-1) { g_warning("Channel cannot play music %s", item->filename); Mix_FreeChunk (sample); return FALSE; @@ -281,7 +292,7 @@ gc_sound_mixer_SDL_play_item (GCSoundMixer * mixer, GCSoundChannel * channel, G g_hash_table_insert( self->samples, channel, sample); - g_warning("Playing %s on channel #%d", item->filename, channel_number); + g_warning("Playing %s on channel #%d", item->filename, channel->channel_number); return TRUE; } @@ -290,14 +301,7 @@ void channel_finished_cb (int channel_number) { GCSoundMixerSDL* self = running_mixer; - g_warning("Channel number %d size %d", - channel_number, - g_hash_table_size(self->channels_to_pointer)); - - int cn = channel_number; - - GCSoundChannel *channel = GC_SOUND_CHANNEL(g_hash_table_lookup (self->channels_to_pointer, - &cn)); + GCSoundChannel *channel = g_ptr_array_index(self->channels, channel_number); g_return_if_fail(channel != NULL); g_return_if_fail(GC_IS_SOUND_MIXER_SDL(self)); @@ -316,6 +320,7 @@ void gc_sound_mixer_SDL_channel_finished (GCSoundMixerSDL* self, sample = g_hash_table_lookup (self->samples, channel); Mix_FreeChunk (sample); + g_hash_table_remove (self->samples, channel); g_signal_emit_by_name (channel, "chunk_end", 0, channel->stopped); } @@ -328,10 +333,8 @@ gc_sound_mixer_SDL_init (GCSoundMixerSDL* self) g_error("Sorry, i can't allocate more than one mixer !!!"); running_mixer = self; - self->channels_from_pointer = g_hash_table_new (g_direct_hash, - g_direct_equal); - self->channels_to_pointer = g_hash_table_new (g_int_hash, - g_int_equal); + self->channels = g_ptr_array_new (); + self->samples = g_hash_table_new (g_direct_hash, g_direct_equal); self->paused = FALSE; @@ -357,6 +360,7 @@ enum { PROP_0, PROP_DEVICE, }; +static GObjectClass *parent_class; static void @@ -366,16 +370,39 @@ gc_sound_mixer_SDL_finalize (GObject* object) running_mixer = NULL; - g_hash_table_destroy (self->channels_from_pointer); - g_hash_table_destroy (self->channels_to_pointer); + g_ptr_array_free (self->channels, TRUE); + g_hash_table_destroy (self->samples); if (self->audio_opened) Mix_CloseAudio(); SDL_Quit(); + + parent_class->finalize (object); } +static void +gc_sound_mixer_SDL_destroy (GCSoundMixerSDL *self) +{ + gint i; + + if (self->has_user_ref_count) + { + self->has_user_ref_count = FALSE; + g_object_unref (self); + } + + for (i = 0; i < self->channels->len; i++) + { + g_signal_handlers_disconnect_by_func(GC_SOUND_OBJECT(g_ptr_array_index(self->channels,i)), channel_destroyed, self); + gc_sound_object_destroy (GC_SOUND_OBJECT(g_ptr_array_index(self->channels,i))); + g_object_unref(G_OBJECT(g_ptr_array_index(self->channels,i))); + } + + GC_SOUND_OBJECT_GET_CLASS(self)->destroy (GC_SOUND_OBJECT(self)); + +} static void gc_sound_mixer_SDL_get_property() {} @@ -386,16 +413,17 @@ gc_sound_mixer_SDL_set_property() {} static void gc_sound_mixer_SDL_class_init (GCSoundMixerSDLClass* self_class) { - g_warning("gc_sound_mixer_SDL_class_init"); - GObjectClass* go_class; + parent_class = g_type_class_peek_parent (G_OBJECT_CLASS(self_class)); + /* GObjectClass */ go_class = G_OBJECT_CLASS(self_class); go_class->finalize = gc_sound_mixer_SDL_finalize; go_class->get_property = gc_sound_mixer_SDL_get_property; go_class->set_property = gc_sound_mixer_SDL_set_property; - + + self_class->destroy = gc_sound_mixer_SDL_destroy; _gc_sound_mixer_install_property( go_class, PROP_DEVICE); /* signals */ @@ -432,12 +460,12 @@ gc_sound_mixer_SDL_class_init (GCSoundMixerSDLClass* self_class) static void gc_init_sound_mixer (GCSoundMixerIface* iface); -G_DEFINE_TYPE_WITH_CODE(GCSoundMixerSDL, gc_sound_mixer_SDL, G_TYPE_OBJECT, +G_DEFINE_TYPE_WITH_CODE(GCSoundMixerSDL, gc_sound_mixer_SDL, GC_TYPE_SOUND_OBJECT, G_IMPLEMENT_INTERFACE(GC_TYPE_SOUND_MIXER, gc_init_sound_mixer)); void gc_init_sound_mixer (GCSoundMixerIface* iface) { - g_warning("Sound Mixer is initalized from SDL! "); + g_warning("Sound Mixer is initalized by SDL mixer! "); /* vtable */ iface->open_audio = gc_sound_mixer_SDL_open_audio; diff --git a/src/gc_sound/src/gc-sound-mixer-SDL.h b/src/gc_sound/src/gc-sound-mixer-SDL.h index 533496e..16bcb2c 100644 --- a/src/gc_sound/src/gc-sound-mixer-SDL.h +++ b/src/gc_sound/src/gc-sound-mixer-SDL.h @@ -66,15 +66,11 @@ struct _GCSoundMixerSDL { gboolean paused; /* List of channels */ - GHashTable *channels_from_pointer; - GHashTable *channels_to_pointer; + GPtrArray *channels; GHashTable *samples; gboolean stopped; - // debug only. will be removed. - gchar* nick; - gboolean has_user_ref_count; }; @@ -106,6 +102,8 @@ struct _GCSoundMixerSDLClass { void (* channel_finished) (GCSoundMixerSDL * self, GCSoundChannel * channel); + + void (* destroy) (GCSoundMixerSDL *self); }; G_END_DECLS diff --git a/src/gc_sound/src/gc-sound-object.c b/src/gc_sound/src/gc-sound-object.c index 3bc36b8..b217a70 100644 --- a/src/gc_sound/src/gc-sound-object.c +++ b/src/gc_sound/src/gc-sound-object.c @@ -43,6 +43,7 @@ enum { }; enum { PROP_0, + PROP_PARENT, PROP_USER_DATA }; @@ -99,6 +100,9 @@ gc_sound_object_class_init (GCSoundObjectClass *class) parent_class = g_type_class_ref (G_TYPE_OBJECT); + gobject_class->get_property = gc_sound_object_get_property; + gobject_class->set_property = gc_sound_object_set_property; + gobject_class->dispose = gc_sound_object_dispose; gobject_class->finalize = gc_sound_object_finalize; @@ -110,6 +114,13 @@ gc_sound_object_class_init (GCSoundObjectClass *class) "User Data", "Anonymous User Data Pointer", G_PARAM_READWRITE)); + g_object_class_install_property (gobject_class, + PROP_PARENT, + g_param_spec_object ("parent", + "Parent Object", + "GCSoundObject parent", + GC_TYPE_SOUND_OBJECT, + G_PARAM_READWRITE)); gc_sound_object_signals[DESTROY] = g_signal_new ("destroy", @@ -125,6 +136,8 @@ static void gc_sound_object_init (GCSoundObject *object, GCSoundObjectClass *klass) { + // TRUE is default; + object->destroy_with_parent = TRUE; } /******************************************** @@ -136,9 +149,10 @@ gc_sound_object_destroy (GCSoundObject *object) { g_return_if_fail (object != NULL); g_return_if_fail (GC_IS_SOUND_OBJECT (object)); - - if (!(GC_SOUND_OBJECT_FLAGS (object) & GC_SOUND_IN_DESTRUCTION)) + + if (!(GC_SOUND_OBJECT_FLAGS (object) & GC_SOUND_IN_DESTRUCTION)){ g_object_run_dispose (G_OBJECT (object)); + } } static void @@ -188,6 +202,15 @@ gc_sound_object_finalize (GObject *gobject) * comes directly from GtkObject * *****************************************/ +static void +parent_destroyed (GCSoundObject *object, gpointer data) +{ + if (GC_SOUND_OBJECT(object)->parent) { + g_signal_handlers_disconnect_by_func(GC_SOUND_OBJECT(object)->parent, parent_destroyed, object); + g_object_unref (GC_SOUND_OBJECT(object)->parent); + } + gc_sound_object_destroy(GC_SOUND_OBJECT(data)); +} static void gc_sound_object_set_property (GObject *object, @@ -200,6 +223,18 @@ gc_sound_object_set_property (GObject *object, case PROP_USER_DATA: g_object_set_data (G_OBJECT (object), "user_data", g_value_get_pointer (value)); break; + case PROP_PARENT: + if (GC_SOUND_OBJECT(object)->parent) { + g_signal_handlers_disconnect_by_func(GC_SOUND_OBJECT(object)->parent, parent_destroyed, object); + g_object_unref (GC_SOUND_OBJECT(object)->parent); + } + GC_SOUND_OBJECT(object)->parent = g_value_get_object (value); + if (GC_SOUND_OBJECT(object)->parent){ + g_object_ref (GC_SOUND_OBJECT(object)->parent); + g_signal_connect ( G_OBJECT(GC_SOUND_OBJECT(object)->parent), "destroy", (GCallback) parent_destroyed, object ); + } + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; @@ -217,6 +252,9 @@ gc_sound_object_get_property (GObject *object, case PROP_USER_DATA: g_value_set_pointer (value, g_object_get_data (G_OBJECT (object), "user_data")); break; + case PROP_PARENT: + g_value_set_object (value, G_OBJECT (GC_SOUND_OBJECT(object)->parent)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; diff --git a/src/gc_sound/src/gc-sound-object.h b/src/gc_sound/src/gc-sound-object.h index d3f651c..0b73bbd 100644 --- a/src/gc_sound/src/gc-sound-object.h +++ b/src/gc_sound/src/gc-sound-object.h @@ -52,6 +52,13 @@ struct _GCSoundObject { GInitiallyUnowned __parent__; guint32 flags; + + // NULL on mixer; mixer on channel,; prent item on item + GCSoundObject *parent; + gboolean destroy_with_parent; + + //debug + gchar *nick; }; struct _GCSoundObjectClass { @@ -60,6 +67,8 @@ struct _GCSoundObjectClass { void (*destroy) (GCSoundObject *object); }; +void gc_sound_object_destroy (GCSoundObject *object); + G_END_DECLS diff --git a/src/gc_sound/src/test_gc_sound.c b/src/gc_sound/src/test_gc_sound.c index 6ae45d0..8e8722d 100644 --- a/src/gc_sound/src/test_gc_sound.c +++ b/src/gc_sound/src/test_gc_sound.c @@ -4,12 +4,12 @@ void finish(GCSoundItem *item, gboolean stopped, gpointer data) { - g_warning("Return of finish callback %s %s", item->nick, stopped ? "STOPPED" : "normal"); + g_warning("Return of finish callback %s %s", GC_SOUND_OBJECT(item)->nick, stopped ? "STOPPED" : "normal"); } void start(GCSoundItem *item, gpointer data) { - g_warning("Return of start callback %s", item->nick); + g_warning("Return of start callback %s", GC_SOUND_OBJECT(item)->nick); } main (int argc, char *argv) @@ -21,71 +21,62 @@ main (int argc, char *argv) /* Sound mixer opens SDL and audio device */ gcmix = gc_sound_mixer_SDL_new(); - GC_SOUND_MIXER_SDL(gcmix)->nick = "gcmix"; + GC_SOUND_OBJECT(gcmix)->nick = "gcmix"; /* We open two chans to play simultaneously */ gcchan1 = gc_sound_mixer_new_channel(gcmix); gcchan2 = gc_sound_mixer_new_channel(gcmix); - gcchan1->nick = "gcchan1"; - gcchan2->nick = "gcchan2"; - - //g_warning ("nick of mixer %s %s", GC_SOUND_MIXER_SDL(gcchan1->mixer)->nick, - // GC_SOUND_MIXER_SDL(gcchan2->mixer)->nick); + GC_SOUND_OBJECT(gcchan1)->nick = "gcchan1"; + GC_SOUND_OBJECT(gcchan2)->nick = "gcchan2"; GCSoundMixer *gcmix2; - g_object_get(G_OBJECT(gcchan2), "mixer", &gcmix2, NULL); + g_object_get(G_OBJECT(gcchan2), "parent", &gcmix2, NULL); - g_warning ("g_object_get return mixer %s", GC_SOUND_MIXER_SDL(gcmix2)->nick); /* Each chan has a root item, where we group the sounds to play in that channel*/ root1 = GC_SOUND_ITEM(gc_sound_channel_get_root(gcchan1)); root2 = GC_SOUND_ITEM(gc_sound_channel_get_root(gcchan2)); - root1->nick="root1"; - root2->nick="root2"; + GC_SOUND_OBJECT(root1)->nick="root1"; + GC_SOUND_OBJECT(root2)->nick="root2"; /* create new item for our sounds */ - item1 = gc_sound_item_append_child (root1); - item2 = gc_sound_item_append_child (root2); - item3 = gc_sound_item_append_child (root2); - item1_1 = gc_sound_item_append_child (item1); - - item1_2 = gc_sound_item_append_child (item1); - - GCSoundChannel *gcc2; - g_object_get(G_OBJECT(item2), "channel", &gcc2, NULL); - - g_warning ("g_object_get return channel %s", GC_SOUND_CHANNEL(gcc2)->nick); - - - item1->nick = "item1"; - item2->nick = "item2"; - item3->nick = "item3"; - item1_1->nick = "item1_1"; - item1_2->nick = "item1_2"; + item1 = gc_sound_item_append_child (root1); + item2 = gc_sound_item_append_child (root2); + item3 = gc_sound_item_append_child (root2); + item1_1 = gc_sound_item_append_child (item1); + + item1_2 = gc_sound_item_append_child (item1); + + GC_SOUND_OBJECT(item1)->nick = "item1"; + GC_SOUND_OBJECT(item2)->nick = "item2"; + GC_SOUND_OBJECT(item3)->nick = "item3"; + GC_SOUND_OBJECT(item1_1)->nick = "item1_1"; + GC_SOUND_OBJECT(item1_2)->nick = "item1_2"; /* set file sound name */ - gc_sound_item_set_filename(item1_1, "../../../boards/sounds/wahoo.ogg"); - gc_sound_item_set_filename(item1_2, "../../../boards/sounds/wahoo.ogg"); - gc_sound_item_set_filename(item2, "../../../boards/music/background/LRLaPause.ogg"); - gc_sound_item_set_filename(item3, "../../../boards/sounds/bonus.ogg"); + gc_sound_item_set_filename(item1_1, "../../../../../gcompris_main/gcompris/boards/sounds/wahoo.ogg"); + gc_sound_item_set_filename(item1_2, "../../../../../gcompris_main/gcompris/boards/sounds/wahoo.ogg"); + gc_sound_item_set_filename(item2, "../../../../../gcompris_main/gcompris/boards/music/background/LRLaPause.ogg"); + gc_sound_item_set_filename(item3, "../../../../../gcompris_main/gcompris/boards/sounds/bonus.ogg"); // test gc_sound_item_set_filename(item1_1, NULL); - gc_sound_item_set_filename(item1_1, "../../../boards/sounds/train.ogg"); + gc_sound_item_set_filename(item1_1, "../../../../../gcompris_main/gcompris/boards/sounds/train.ogg"); //policy test: works on channel and on item. //gc_sound_channel_set_policy(gcchan2, GC_SOUND_INTERRUPT_AND_PLAY); gc_sound_item_set_policy(item3, GC_SOUND_INTERRUPT_AND_PLAY); // callback connection - //gc_sound_item_connect__play_finished(item2, finish, NULL); - //gc_sound_item_connect__play_finished(item3, finish, NULL); - //gc_sound_item_connect__play_started(item1_1, start, NULL); - //gc_sound_item_connect__play_started(item1_2, start, NULL); - g_signal_connect( item2, "play_end", finish, NULL); - g_signal_connect( item2, "play_end", finish, NULL); - g_signal_connect( item1_1, "play_start", start, NULL); - g_signal_connect( item1_2, "play_start", start, NULL); + //gc_sound_item_connect__play_finished(item2, (GCallback) finish, NULL); + //gc_sound_item_connect__play_finished(item3, (GCallback) finish, NULL); + //gc_sound_item_connect__play_started(item1_1, (GCallback) start, NULL); + //gc_sound_item_connect__play_started(item1_2, (GCallback) start, NULL); + g_signal_connect( item2, "play_end", (GCallback) finish, NULL); + g_signal_connect( item2, "play_end", (GCallback) finish, NULL); + g_signal_connect( item1_1, "play_start", (GCallback) start, NULL); + g_signal_connect( item1_2, "play_start", (GCallback) start, NULL); + g_signal_connect( item1_2, "play_end", (GCallback) finish, NULL); /* // test mute */ @@ -108,9 +99,20 @@ main (int argc, char *argv) g_usleep(3000000); //this will stop item2 because of policy - gc_sound_item_play(item3); + //gc_sound_item_play(item3); + //gc_sound_object_destroy(GC_SOUND_OBJECT(gcchan2)); + gc_sound_object_destroy(GC_SOUND_OBJECT(item1)); + g_usleep(3000000); + //gc_sound_object_destroy(GC_SOUND_OBJECT(root2)); + + g_usleep(3000000); + + gc_sound_object_destroy(GC_SOUND_OBJECT(gcmix)); + gc_sound_object_destroy(GC_SOUND_OBJECT(gcmix2)); + + g_usleep(3000000); /* infinite loop */ - g_main_loop_run(g_main_loop_new (NULL, FALSE)); + //g_main_loop_run(g_main_loop_new (NULL, FALSE)); } |