r2631 - trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src

abraxa at sita.openmoko.org abraxa at sita.openmoko.org
Sat Aug 4 14:50:37 CEST 2007


Author: abraxa
Date: 2007-08-04 14:50:34 +0200 (Sat, 04 Aug 2007)
New Revision: 2631

Modified:
   trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/Makefile.am
   trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/main.c
   trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/main.h
   trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/mainwin.c
   trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/mainwin.h
   trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/playback.c
   trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/playback.h
   trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/playlist.c
   trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/playlist.h
Log:
Continued work on UI<->backend communication and gstreamer wrapping



Modified: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/Makefile.am
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/Makefile.am	2007-08-04 10:36:33 UTC (rev 2630)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/Makefile.am	2007-08-04 12:50:34 UTC (rev 2631)
@@ -17,7 +17,8 @@
         $(OPENMOKO_CFLAGS) \
 	$(OMP_DEFINES) \
         -I$(top_srcdir) \
-        -I$(top_srcdir)/intl
+        -I$(top_srcdir)/intl\
+	-g -DDEBUG
 
 INCLUDES = $(openmoko_mediaplayer_CFLAGS)
 

Modified: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/main.c
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/main.c	2007-08-04 10:36:33 UTC (rev 2630)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/main.c	2007-08-04 12:50:34 UTC (rev 2631)
@@ -140,6 +140,10 @@
 void
 omp_config_restore_state()
 {
+	#ifdef DEBUG
+		g_print("Loading playlist and restoring playback state\n");
+	#endif
+
 	// This mustn't be called more than once
 	g_assert(omp_config == NULL);
 
@@ -158,10 +162,11 @@
 	// Check whether playlist_position is valid
 	if (!omp_playlist_set_current_track(omp_config->playlist_position))
 	{
-		// Reset playlist state as it must have been modified since it was last loaded
+		// Reset playlist state as playlist must have been modified since it was last loaded
 		omp_config->playlist_position = 0;
 		omp_config->track_position = 0;
-	} 
+		omp_playlist_set_current_track(0);
+	}
 
 	// Feed the track entity to the playback engine to obtain track information
 	omp_playlist_load_current_track();
@@ -362,15 +367,12 @@
 	signal(SIGSEGV, handler_sigsegfault);
 	signal(SIGUSR1, handler_sigusr1);
 
-	// Load config and restore playback state
-	omp_config_restore_state();
-
 	// Initialize playback, playlist and UI handling
 	omp_main_window_create();
 	omp_playback_init();
 	omp_playlist_init();
 	omp_main_connect_signals();
-	omp_main_update_track_info();
+	omp_config_restore_state();
 	omp_main_window_show();
 
 	gtk_main();
@@ -384,6 +386,7 @@
 	omp_playback_free();
 	omp_playlist_free();
 	gst_deinit();
+	g_free(ui_image_path);
 
 #ifdef DEBUG_MEM_PROFILE
 	g_mem_profile();

Modified: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/main.h
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/main.h	2007-08-04 10:36:33 UTC (rev 2630)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/main.h	2007-08-04 12:50:34 UTC (rev 2631)
@@ -52,7 +52,7 @@
 //	gchar *playlist_path;						///< Last path used for the playlist selection dialog
 	gchar playlist_file[256];				///< Path and file name of current (=last used) playlist
 	gint playlist_position;					///< Position within the playlist
-	gint track_position;						///< Position to resume playback from within the last played track
+	glong track_position;						///< Position to resume playback from within the last played track
 };
 
 extern struct _omp_config *omp_config;

Modified: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/mainwin.c
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/mainwin.c	2007-08-04 10:36:33 UTC (rev 2630)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/mainwin.c	2007-08-04 12:50:34 UTC (rev 2631)
@@ -59,6 +59,8 @@
 
 GtkWidget *omp_main_window = NULL;
 
+gboolean omp_main_time_slider_can_update = TRUE;
+gboolean omp_main_time_slider_was_dragged = FALSE;
 
 
 /**
@@ -67,9 +69,6 @@
 void
 omp_application_terminate()
 {
-	// Free resources
-	g_free(ui_image_path);
-
 	// Tell GTK to leave the message loop
 	gtk_main_quit();
 }
@@ -190,7 +189,52 @@
 	gtk_label_set_text(GTK_LABEL(main_widgets.title_label), title);
 }
 
+/**
+ * Gets called when the time slider's value got changed (yes, that means it gets called every second, too)
+ */
 void
+omp_main_time_slider_changed(GtkRange *range, gpointer data)
+{
+	if (omp_main_time_slider_was_dragged)
+	{
+		omp_main_time_slider_was_dragged = FALSE;
+
+		// Set new position and resume playback that was paused when dragging started
+		omp_playback_set_track_position(gtk_range_get_value(GTK_RANGE(range)));
+
+		// Update UI right away
+		gtk_range_set_value(GTK_RANGE(main_widgets.time_hscale), omp_playback_get_track_position());
+	}
+}
+
+/**
+ * Gets called when the user starts dragging the time slider
+ */
+gboolean
+omp_main_time_slider_drag_start(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
+{
+	while (gtk_events_pending()) gtk_main_iteration();
+
+	// Prevent UI callbacks from messing with the slider position
+	omp_main_time_slider_can_update = FALSE;
+}
+
+/**
+ * Gets called when the user stops dragging the time slider
+ */
+gboolean
+omp_main_time_slider_drag_stop(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
+{
+	while (gtk_events_pending()) gtk_main_iteration();
+
+	// Allow UI callbacks to alter the the slider position again
+	omp_main_time_slider_can_update = TRUE;
+
+	// Notify the slider change callback that this time we indeed want to change position
+	omp_main_time_slider_was_dragged = TRUE;
+}
+
+void
 omp_shuffle_button_callback(GtkWidget* widget, gpointer data)
 {
 /*    if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
@@ -225,13 +269,46 @@
 }
 
 /**
+ * Event handler for the Fast Forward button
+ */
+void
+omp_main_button_fast_forward_callback()
+{
+	// Set new position and resume playback that was paused when dragging started
+	omp_playback_set_track_position(omp_playback_get_track_position()+BUTTON_SEEK_DISTANCE);
+
+	// Update UI right away
+	gtk_range_set_value(GTK_RANGE(main_widgets.time_hscale), omp_playback_get_track_position());
+}
+
+/**
+ * Event handler for the Rewind button
+ */
+void
+omp_main_button_rewind_callback()
+{
+	// Set new position and resume playback that was paused when dragging started
+	omp_playback_set_track_position(omp_playback_get_track_position()-BUTTON_SEEK_DISTANCE);
+
+	// Update UI right away
+	gtk_range_set_value(GTK_RANGE(main_widgets.time_hscale), omp_playback_get_track_position());
+}
+
+/**
  * Event handler for the Play/Pause button
- * @todo State change, etc
+ * @todo Pixmap change
  */
 void
 omp_main_button_play_pause_callback()
 {
-	omp_playback_play();
+	if (omp_playback_get_state() != OMP_PLAYBACK_STATE_PLAYING)
+	{
+		omp_playback_play();
+
+	} else {
+
+		omp_playback_pause();
+	}
 }
 
 /**
@@ -282,7 +359,6 @@
 
 	image = gtk_image_new_from_icon_name(image_name, 36);
 	gtk_container_add(GTK_CONTAINER(button), GTK_WIDGET(image));
-	g_object_unref(image);
 
 	return button;
 }
@@ -388,9 +464,11 @@
 	gtk_scale_set_draw_value(GTK_SCALE(main_widgets.time_hscale), FALSE);
 	GTK_WIDGET_UNSET_FLAGS(GTK_WIDGET(main_widgets.time_hscale), GTK_CAN_FOCUS);
 	gtk_widget_set_size_request(GTK_WIDGET(main_widgets.time_hscale), 338, 35);
+	gtk_range_set_update_policy(GTK_RANGE(main_widgets.time_hscale), GTK_UPDATE_DISCONTINUOUS);
 	gtk_range_set_value(GTK_RANGE(main_widgets.time_hscale), 0.0);
-//    g_signal_connect(G_OBJECT(time_hscale), "change_value",
-//		    G_CALLBACK(omp_main_set_time), NULL);
+	g_signal_connect(G_OBJECT(main_widgets.time_hscale), "value_changed",					G_CALLBACK(omp_main_time_slider_changed), NULL);
+	g_signal_connect(G_OBJECT(main_widgets.time_hscale), "button-press-event",		G_CALLBACK(omp_main_time_slider_drag_start), NULL);
+	g_signal_connect(G_OBJECT(main_widgets.time_hscale), "button-release-event",	G_CALLBACK(omp_main_time_slider_drag_stop), NULL);
 	gtk_container_add(GTK_CONTAINER(alignment), GTK_WIDGET(main_widgets.time_hscale));
 
 	// --- --- --- --- --- Middle hbox --- --- --- --- ---
@@ -483,7 +561,7 @@
 	gtk_box_set_child_packing(GTK_BOX(controls_hbox), GTK_WIDGET(button), FALSE, FALSE, 0, GTK_PACK_START);
 
 	// Rewind button
-	button = omp_button_create("gtk-media-rewind-ltr", NULL);
+	button = omp_button_create("gtk-media-rewind-ltr", G_CALLBACK(omp_main_button_rewind_callback));
 	gtk_box_pack_start(GTK_BOX(controls_hbox), button, TRUE, TRUE, 0);
 	gtk_box_set_child_packing(GTK_BOX(controls_hbox), GTK_WIDGET(button), FALSE, FALSE, 0, GTK_PACK_START);
 
@@ -493,7 +571,7 @@
 	gtk_box_set_child_packing(GTK_BOX(controls_hbox), GTK_WIDGET(button), FALSE, FALSE, 0, GTK_PACK_START);
 
 	// Fast Forward button
-	button = omp_button_create("gtk-media-forward-ltr", NULL);
+	button = omp_button_create("gtk-media-forward-ltr", G_CALLBACK(omp_main_button_fast_forward_callback));
 	gtk_box_pack_start(GTK_BOX(controls_hbox), button, TRUE, TRUE, 0);
 	gtk_box_set_child_packing(GTK_BOX(controls_hbox), GTK_WIDGET(button), FALSE, FALSE, 0, GTK_PACK_START);
 
@@ -536,6 +614,7 @@
 	// Show everything but the window itself
 	gtk_widget_show_all(GTK_WIDGET(bg_muxer));
 
+
 	return;
 }
 
@@ -547,20 +626,23 @@
 void
 omp_main_connect_signals()
 {
-	g_signal_connect(G_OBJECT(omp_main_window), OMP_EVENT_PREV_TRACK, G_CALLBACK(omp_main_update_track_info), NULL);
-	g_signal_connect(G_OBJECT(omp_main_window), OMP_EVENT_NEXT_TRACK, G_CALLBACK(omp_main_update_track_info), NULL);
+	g_signal_connect(G_OBJECT(omp_main_window), OMP_EVENT_PLAYLIST_TRACK_CHANGED,			G_CALLBACK(omp_main_update_track_change), NULL);
+	g_signal_connect(G_OBJECT(omp_main_window), OMP_EVENT_PLAYBACK_STATUS_CHANGED,		G_CALLBACK(omp_main_update_track_change), NULL);
+	g_signal_connect(G_OBJECT(omp_main_window), OMP_EVENT_PLAYBACK_POSITION_CHANGED,	G_CALLBACK(omp_main_update_track_position), NULL);
 }
 
-
 /**
  * Evaluates current track information and updates the config/UI if necessary
+ * @note This function only checks elements that don't change too often - for the rest we have specialized functions below
  */
 void
-omp_main_update_track_info()
+omp_main_update_track_change()
 {
 	static gint old_track_count = 0;
 	static gint old_track_id = 0;
+	static gulong old_track_length = 0;
 
+	gulong track_length, track_position;
 	gchar *text;
 
 	// Track id/track count changed?
@@ -572,12 +654,68 @@
 		// Update config
 		omp_config_update();
 
-		// Update UI
+		// Update label
 		text = g_strdup_printf(WIDGET_CAPTION_TRACK_NUM, omp_playlist_current_track_id+1, omp_playlist_track_count);
 		gtk_label_set_text(GTK_LABEL(main_widgets.track_number_label), text);
 		g_free(text);
 	}
 
+	// Got a track length change?
+	track_length = omp_playback_get_track_length();
 
+	if (track_length != old_track_length)
+	{
+		old_track_length = track_length;
+		track_position = omp_playback_get_track_position();
+
+		// Set new time slider increments
+		gtk_range_set_increments(GTK_RANGE(main_widgets.time_hscale), track_length/10, track_length/10);
+
+		// Update label and slider
+		text = g_strdup_printf(WIDGET_CAPTION_TRACK_TIME,
+			track_position / 60, track_position % 60,
+			track_length / 60, track_length % 60);
+		gtk_label_set_text(GTK_LABEL(main_widgets.time_label), text);
+		g_free(text);
+
+		if (omp_main_time_slider_can_update)
+		{
+			gtk_range_set_range(GTK_RANGE(main_widgets.time_hscale), 0, track_length ? track_length : 1);
+			gtk_range_set_value(GTK_RANGE(main_widgets.time_hscale), track_position);
+		}
+	}
 }
 
+/**
+ * Updates the UI if the playback position changed
+ */
+void
+omp_main_update_track_position()
+{
+	static gulong old_track_position = 0;
+
+	gulong track_position, track_length;
+	gchar *text;
+
+	// Got a track length change?
+	track_position = omp_playback_get_track_position();
+	{
+		old_track_position = track_position;
+		track_length = omp_playback_get_track_length();
+
+		// Update UI
+		text = g_strdup_printf(WIDGET_CAPTION_TRACK_TIME,
+			track_position / 60, track_position % 60,
+			track_length / 60, track_length % 60);
+		gtk_label_set_text(GTK_LABEL(main_widgets.time_label), text);
+		g_free(text);
+
+		if (omp_main_time_slider_can_update)
+		{
+			gtk_range_set_range(GTK_RANGE(main_widgets.time_hscale), 0, track_length ? track_length : 1);
+			gtk_range_set_value(GTK_RANGE(main_widgets.time_hscale), track_position);
+		}
+	}
+
+}
+

Modified: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/mainwin.h
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/mainwin.h	2007-08-04 10:36:33 UTC (rev 2630)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/mainwin.h	2007-08-04 12:50:34 UTC (rev 2631)
@@ -33,6 +33,9 @@
 #define WIDGET_CAPTION_TRACK_NUM "%.3d / %.3d"
 #define WIDGET_CAPTION_VOLUME "%d%%"
 
+// Determines how many seconds the engine will seek if the FFWD/REW buttons are clicked
+#define BUTTON_SEEK_DISTANCE 10
+
 extern GtkWidget *omp_main_window;
 
 void omp_application_terminate();
@@ -42,6 +45,7 @@
 void omp_main_window_create();
 void omp_main_connect_signals();
 
-void omp_main_update_track_info();
+void omp_main_update_track_change();
+void omp_main_update_track_position();
 
 #endif

Modified: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/playback.c
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/playback.c	2007-08-04 10:36:33 UTC (rev 2630)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/playback.c	2007-08-04 12:50:34 UTC (rev 2631)
@@ -30,9 +30,9 @@
 #include "mainwin.h"
 
 GstElement *omp_gst_playbin = NULL;
+guint omp_playback_ui_timeout = 0;
+gboolean omp_playback_ui_timeout_halted;
 
-
-
 /**
  * Initializes gstreamer by setting up pipe, message hooks and bins
  */
@@ -48,7 +48,9 @@
 	}
 
 	// Create the signals we'll emit
-	g_signal_new(OMP_EVENT_PLAYBACK_EOS, G_TYPE_OBJECT, 0, 0, 0, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, NULL);
+	g_signal_new(OMP_EVENT_PLAYBACK_EOS,								G_TYPE_OBJECT, 0, 0, 0, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, NULL);
+	g_signal_new(OMP_EVENT_PLAYBACK_STATUS_CHANGED,			G_TYPE_OBJECT, 0, 0, 0, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, NULL);
+	g_signal_new(OMP_EVENT_PLAYBACK_POSITION_CHANGED,		G_TYPE_OBJECT, 0, 0, 0, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, NULL);
 
 	// Set up gstreamer pipe and bins
 	omp_gst_playbin = gst_element_factory_make("playbin", "play");
@@ -81,6 +83,7 @@
 
 /**
  * Attempts to load a track from an URI
+ * @return TRUE if successful, FALSE if failed
  */
 gboolean
 omp_playback_load_track_from_uri(gchar *uri)
@@ -91,59 +94,171 @@
 		omp_playback_init();
 	}
 
-	// DEBUG
-	g_printf("Loading %s\n", uri);
+	#ifdef DEBUG
+		g_printf("Loading track: %s\n", uri);
+	#endif
 
 	gst_element_set_state(omp_gst_playbin, GST_STATE_NULL);
 	g_object_set(G_OBJECT(omp_gst_playbin), "uri", uri, NULL);
 	gst_element_set_state(omp_gst_playbin, GST_STATE_PAUSED);
+
+	return (gst_element_set_state(omp_gst_playbin, GST_STATE_PAUSED) != GST_STATE_CHANGE_FAILURE);
 }
 
 /**
+ * This callback gets called at least once per second if a track is playing
+ */
+static gboolean
+omp_playback_ui_timeout_callback(gpointer data)
+{
+	g_signal_emit_by_name(G_OBJECT(omp_main_window), OMP_EVENT_PLAYBACK_POSITION_CHANGED);
+	
+	if (omp_playback_ui_timeout_halted)
+	{
+		// Reset the timeout ID so we can prevent race conditions
+		omp_playback_ui_timeout = 0;
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+/**
  * Starts playback of the current stream
  */
 void
 omp_playback_play()
 {
-	// DEBUG
-	g_print("Starting playback\n");
+	#ifdef DEBUG
+		g_print("Starting playback\n");
+	#endif
 
+	// Set state
 	gst_element_set_state(omp_gst_playbin, GST_STATE_PLAYING);
+	g_signal_emit_by_name(G_OBJECT(omp_main_window), OMP_EVENT_PLAYBACK_STATUS_CHANGED);
+
+	// Add timer to update UI if necessary
+	// If the halt flag was set but the callback didn't run yet then we
+	// don't want to add another callback since we would have two then
+	omp_playback_ui_timeout_halted = FALSE;
+
+	if (!omp_playback_ui_timeout)
+	{
+		omp_playback_ui_timeout = g_timeout_add(PLAYBACK_UI_UPDATE_INTERVAL, omp_playback_ui_timeout_callback, NULL);
+	}
 }
 
 /**
+ * Suspends playback of the current stream
+ */
+void
+omp_playback_pause()
+{
+	#ifdef DEBUG
+		g_print("Suspending playback\n");
+	#endif
+
+	// Set state
+	gst_element_set_state(omp_gst_playbin, GST_STATE_PAUSED);
+	g_signal_emit_by_name(G_OBJECT(omp_main_window), OMP_EVENT_PLAYBACK_STATUS_CHANGED);
+
+	// Stop timer
+	omp_playback_ui_timeout_halted = TRUE;
+}
+
+/**
  * Returns the current state the playback engine is in
+ * @todo Don't use system clock, might be out-of-sync with playbin clock?
  */
 gint
 omp_playback_get_state()
 {
 	GstState state;
-	GstSystemClock *system_clock;
+	GstClock *clock;
 
 	// Poll state with an immediate timeout
-	system_clock = gst_system_clock_obtain();
-	gst_element_get_state(GST_OBJECT(omp_gst_playbin), &state, NULL, gst_clock_get_time(system_clock));
-	gst_object_unref(system_clock);
+	clock = gst_system_clock_obtain();
+	gst_element_get_state(GST_ELEMENT(omp_gst_playbin), &state, NULL, gst_clock_get_time(clock));
+	gst_object_unref(clock);
 
-	// The NULL element state is no different from READY for more abstract layers
-	if (state == GST_STATE_NULL)
+	// The NULL and READY element states are no different from PAUSED for more abstract layers
+	if ( (state == GST_STATE_NULL) || (state == GST_STATE_READY) )
 	{
-		state = GST_STATE_READY;
+		state = GST_STATE_PAUSED;
 	}
 
 	return (gint)state;
 }
 
 /**
+ * Returns the number of seconds that the track has been playing so far
+ */
+gulong
+omp_playback_get_track_position()
+{
+	GstFormat format = GST_FORMAT_TIME;
+	gint64 position;
+
+	if (!omp_gst_playbin)
+	{
+		return 0;
+	}
+
+	// Return 0 if function returns FALSE, position otherwise
+	return (gst_element_query_position(omp_gst_playbin, &format, &position)) ? (position/GST_SECOND) : 0;
+}
+
+/**
+ * Sets the playback position of the currently loaded track
+ */
+void
+omp_playback_set_track_position(glong position)
+{
+	if (!omp_gst_playbin)
+	{
+		return;
+	}
+
+	gst_element_seek_simple(GST_ELEMENT(omp_gst_playbin),
+		GST_FORMAT_TIME,
+		GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE,
+		position*GST_SECOND);
+
+	g_signal_emit_by_name(G_OBJECT(omp_main_window), OMP_EVENT_PLAYBACK_POSITION_CHANGED);
+}
+
+/**
+ * Returns the current track's playing length
+ */
+gulong
+omp_playback_get_track_length()
+{
+	GstFormat format = GST_FORMAT_TIME;
+	gint64 length;
+
+	if (!omp_gst_playbin)
+	{
+		return 0;
+	}
+
+	// Return 0 if function returns FALSE, track length otherwise
+	return (gst_element_query_duration(omp_gst_playbin, &format, &length)) ? (length/GST_SECOND) : 0;
+}
+
+/**
  * Handles gstreamer's end-of-stream notification
  */
 static gboolean
 omp_gst_message_eos(GstBus *bus, GstMessage *message, gpointer data)
 {
-	// DEBUG
-	g_printf("End of stream reached.\n");
+	#ifdef DEBUG
+		g_printf("End of stream reached.\n");
+	#endif
 
-	gst_element_set_state(omp_gst_playbin, GST_STATE_NULL);
+	// Reset playback engine
+	gst_element_set_state(omp_gst_playbin, GST_STATE_READY);
+	omp_playback_set_track_position(0);
+
 	g_signal_emit_by_name(G_OBJECT(omp_main_window), OMP_EVENT_PLAYBACK_EOS);
 
 	return TRUE;
@@ -157,9 +272,12 @@
 {
 	GError *error;
 
-	gst_message_parse_error(message, &error, NULL);
-	g_printerr("gstreamer error: %s\n", error->message);
-	g_error_free(error);
+	#ifdef DEBUG
+		gst_message_parse_error(message, &error, NULL);
+		g_printerr("gstreamer error: %s\n", error->message);
+		gst_message_unref(error);
+		g_error_free(error);
+	#endif
 
 	return TRUE;
 }
@@ -172,10 +290,12 @@
 {
 	GError *error;
 
-	gst_message_parse_error(message, &error, NULL);
-	g_printerr("gstreamer warning: %s\n", error->message);
-	g_error_free(error);
+	#ifdef DEBUG
+		gst_message_parse_warning(message, &error, NULL);
+		g_printerr("gstreamer warning: %s\n", error->message);
+		gst_message_unref(error);
+		g_error_free(error);
+	#endif
 
 	return TRUE;
 }
-

Modified: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/playback.h
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/playback.h	2007-08-04 10:36:33 UTC (rev 2630)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/playback.h	2007-08-04 12:50:34 UTC (rev 2631)
@@ -30,12 +30,15 @@
 #include <gst/gst.h>
 
 #define OMP_EVENT_PLAYBACK_EOS "playback_end_of_stream"
+#define OMP_EVENT_PLAYBACK_STATUS_CHANGED "playback_status_change"
+#define OMP_EVENT_PLAYBACK_POSITION_CHANGED "playback_position_change"
 
 // Player states masking the gstreamer states so we can be more abstract
-#define OMP_PLAYBACK_STATE_READY GST_STATE_READY
 #define OMP_PLAYBACK_STATE_PAUSED GST_STATE_PAUSED
 #define OMP_PLAYBACK_STATE_PLAYING GST_STATE_PLAYING
 
+// The UI will be updated at this interval when a track is playing (in ms)
+#define PLAYBACK_UI_UPDATE_INTERVAL 1000
 
 void omp_playback_init();
 void omp_playback_free();
@@ -43,7 +46,11 @@
 gboolean omp_playback_load_track_from_uri(gchar *uri);
 
 void omp_playback_play();
+void omp_playback_pause();
 gint omp_playback_get_state();
+gulong omp_playback_get_track_position();
+void omp_playback_set_track_position(glong position);
+gulong omp_playback_get_track_length();
 
 static gboolean omp_gst_message_eos(GstBus *bus, GstMessage *message, gpointer data);
 static gboolean omp_gst_message_error(GstBus *bus, GstMessage *message, gpointer data);

Modified: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/playlist.c
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/playlist.c	2007-08-04 10:36:33 UTC (rev 2630)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/playlist.c	2007-08-04 12:50:34 UTC (rev 2631)
@@ -62,8 +62,7 @@
 	g_signal_connect(G_OBJECT(omp_main_window), OMP_EVENT_PLAYBACK_EOS, G_CALLBACK(omp_playlist_process_eos_event), NULL);
 
 	// Create the signals we emit: no params, no return value
-	g_signal_new(OMP_EVENT_PREV_TRACK, G_TYPE_OBJECT, 0, 0, 0, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, NULL);
-	g_signal_new(OMP_EVENT_NEXT_TRACK, G_TYPE_OBJECT, 0, 0, 0, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, NULL);
+	g_signal_new(OMP_EVENT_PLAYLIST_TRACK_CHANGED, G_TYPE_OBJECT, 0, 0, 0, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, NULL);
 }
 
 /**
@@ -93,6 +92,14 @@
 void
 omp_playlist_load(gchar *playlist_file)
 {
+	// Free the track history's memory by deleting the first element until the list is empty
+	while (omp_track_history)
+	{
+		g_free(omp_track_history->data);
+		omp_track_history = g_slist_delete_link(omp_track_history, omp_track_history);
+	}
+
+	// Let XSPF clean up, too
 	if (omp_playlist)
 	{
 		spiff_free(omp_playlist);
@@ -124,8 +131,9 @@
 	struct spiff_track *track;
 	gint track_num = 0;
 
-	// DEBUG
-	g_printf("Setting current track to #%d\n", playlist_pos);
+	#ifdef DEBUG
+		g_printf("Setting current track to #%d\n", playlist_pos);
+	#endif
 
 	if (!omp_playlist)
 	{
@@ -146,6 +154,9 @@
 	if (position_valid)
 	{
 		omp_playlist_track_count = track_num;
+
+		// Emit signal to update UI and the like
+		g_signal_emit_by_name(G_OBJECT(omp_main_window), OMP_EVENT_PLAYLIST_TRACK_CHANGED);
 	}
 
 	return position_valid;
@@ -161,6 +172,7 @@
 {
 	struct omp_track_history_entry *history_entry;
 	struct spiff_track *track;
+	gboolean was_playing;
 	gboolean is_new_track = FALSE;
 
 	if (!omp_playlist_current_track)
@@ -168,6 +180,34 @@
 		return;
 	}
 
+	// If track playing time is >= 10 seconds we just jump back to the beginning of the track
+	if (omp_playback_get_track_position() >= 10)
+	{
+		omp_playback_set_track_position(0);
+		return TRUE;
+	}
+
+	// Get player state so we can continue playback if necessary
+	was_playing = (omp_playback_get_state() == OMP_PLAYBACK_STATE_PLAYING);
+
+try_again:
+
+	#ifdef DEBUG
+		if (omp_track_history)
+		{
+			GSList *list;
+			g_printf("--- Track History:\n");
+			list = omp_track_history;
+			while (list)
+			{
+				history_entry = list->data;
+				g_printf("- %s\n", history_entry->track->locations->value);
+				list = g_slist_next(list);
+			}
+			g_printf("---\n");
+		}
+	#endif
+
 	// Do we have tracks in the history to go back to?
 	if (omp_track_history)
 	{
@@ -197,7 +237,7 @@
 			// We only found the previous track if we're not at the end of the list
 			if (track->next)
 			{
-				omp_playlist_current_track		= track;
+				omp_playlist_current_track = track;
 				omp_playlist_current_track_id--;
 			}
 		}
@@ -206,7 +246,19 @@
 	if (is_new_track)
 	{
 		// Emit signal to update UI and the like
-		g_signal_emit_by_name(G_OBJECT(omp_main_window), OMP_EVENT_PREV_TRACK);
+		g_signal_emit_by_name(G_OBJECT(omp_main_window), OMP_EVENT_PLAYLIST_TRACK_CHANGED);
+
+		// Load track and start playing if needed
+		if (omp_playlist_load_current_track())
+		{
+			if (was_playing) omp_playback_play();
+
+		} else {
+
+			// Uh-oh, track failed to load - let's find another one, shall we?
+			is_new_track = FALSE;
+			goto try_again;
+		}
 	}
 
 	return is_new_track;
@@ -237,8 +289,8 @@
 
 	// Prepare the history entry - if we don't need it we'll just free it again
 	history_entry = g_new(struct omp_track_history_entry, 1);
-	history_entry->track = omp_playlist_current_track;
-	history_entry->track_id = omp_playlist_current_track_id;
+	history_entry->track		= omp_playlist_current_track;
+	history_entry->track_id	= omp_playlist_current_track_id;
 
 	// Do we have a track to play?
 	if (omp_playlist_current_track->next)
@@ -256,7 +308,7 @@
 		omp_track_history = g_slist_prepend(omp_track_history, (gpointer)history_entry);
 
 		// Emit signal to update UI and the like
-		g_signal_emit_by_name(G_OBJECT(omp_main_window), OMP_EVENT_NEXT_TRACK);
+		g_signal_emit_by_name(G_OBJECT(omp_main_window), OMP_EVENT_PLAYLIST_TRACK_CHANGED);
 
 		// Load track and start playing if needed
 		if (omp_playlist_load_current_track())

Modified: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/playlist.h
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/playlist.h	2007-08-04 10:36:33 UTC (rev 2630)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer/src/playlist.h	2007-08-04 12:50:34 UTC (rev 2631)
@@ -29,13 +29,8 @@
 
 #include <spiff/spiff_c.h>
 
-#define OMP_EVENT_PREV_TRACK "prev_track"
-#define OMP_EVENT_NEXT_TRACK "next_track"
+#define OMP_EVENT_PLAYLIST_TRACK_CHANGED "playlist_track_changed"
 
-
-extern struct _omp_playlist_events omp_playlist_events;
-
-
 extern struct spiff_list *omp_playlist;
 extern guint omp_playlist_track_count;
 





More information about the commitlog mailing list