r2643 - in trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2: . src

abraxa at sita.openmoko.org abraxa at sita.openmoko.org
Mon Aug 6 12:51:22 CEST 2007


Author: abraxa
Date: 2007-08-06 12:51:19 +0200 (Mon, 06 Aug 2007)
New Revision: 2643

Added:
   trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/persistent.c
   trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/persistent.h
Modified:
   trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/TODO
   trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/Makefile.am
   trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/main.c
   trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/main.h
   trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/mainwin.c
   trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/mainwin.h
   trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/playback.c
   trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/playback.h
   trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/playlist.c
   trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/playlist.h
Log:
Session save/restore now implemented
More main window<->playback/playlist interfacing
Some cleaning up, some bugfixing :)



Modified: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/TODO
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/TODO	2007-08-05 22:50:00 UTC (rev 2642)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/TODO	2007-08-06 10:51:19 UTC (rev 2643)
@@ -1,6 +1,7 @@
 
 UI:
 	Add repeat mode indicator (different button pixmaps)
+	Make FFWD/REW buttons trigger repeatedly
 	
 Backend:
 	Use GConf
@@ -12,7 +13,7 @@
 	How to adjust equalizer?
 
 Build process:
-	Add libspiff/libexpat/uriparser dependencies to Makefile.am
+	Bitbake recipe and its integration into OE
 
 Documentation:
-	Dependencies: libspiff->libexpat/uriparser
+	-/-

Modified: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/Makefile.am
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/Makefile.am	2007-08-05 22:50:00 UTC (rev 2642)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/Makefile.am	2007-08-06 10:51:19 UTC (rev 2643)
@@ -27,4 +27,5 @@
 	mainwin.c mainwin.h \
 	playlist.c playlist.h \
 	playback.c playback.h \
-	guitools.c guitools.h
+	guitools.c guitools.h \
+	persistent.c persistent.h

Modified: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/main.c
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/main.c	2007-08-05 22:50:00 UTC (rev 2642)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/main.c	2007-08-06 10:51:19 UTC (rev 2643)
@@ -34,7 +34,6 @@
 #include <gdk/gdk.h>
 
 #include <stdlib.h>
-#include <string.h>
 
 #include <errno.h>
 #include <fcntl.h>
@@ -45,11 +44,12 @@
 #include <dbus/dbus-glib.h>
 #include <dbus/dbus-glib-lowlevel.h>
 
-#include <spiff/spiff_c.h>
-
 #include "main.h"
+#include "mainwin.h"
 #include "guitools.h"
 #include "playlist.h"
+#include "playback.h"
+#include "persistent.h"
 
 /// Determines how the segfault handler terminates the program
 //define HANDLE_SIGSEGV
@@ -58,28 +58,6 @@
 //define DEBUG_MEM_PROFILE
 
 
-/// The default configuration
-struct _omp_config omp_default_config =
-{
-	FALSE,
-	TRUE,
-	OMP_REPEAT_OFF,
-//	FALSE,
-	FALSE,
-	"%f",
-	0.0,
-	{0,0,0,0,0,0,0,0,0,0,0},
-	TRUE,
-	"",
-	"../../test.xspf",
-	0,
-	0
-};
-
-struct _omp_config *omp_config = NULL;			///< Global and persistent configuration data
-
-
-
 /*
 void
 init_dbus()
@@ -135,81 +113,6 @@
 }
 
 /**
- * Load configuration and restore player state from last session
- */
-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);
-
-	// Set default config
-	omp_config = g_new(struct _omp_config, 1);
-	g_memmove(omp_config, &omp_default_config, sizeof(struct _omp_config));
-
-	// Load config and last used playlist if set
-	omp_config_load();
-
-	if (omp_config->playlist_file[0])
-	{
-		omp_playlist_load(omp_config->playlist_file);
-	}
-
-	// Check whether playlist_position is valid
-	if (!omp_playlist_set_current_track(omp_config->playlist_position))
-	{
-		// 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();
-}
-
-/**
- * Releases resources allocated for configuration data
- */
-void
-omp_config_free()
-{
-	g_free(omp_config);
-}
-
-/**
- * Saves the current configuration data to persistent storate
- */
-void
-omp_config_save()
-{
-}
-
-/**
- * Reads the configuration data from persistent storage
- */
-void
-omp_config_load()
-{
-}
-
-/**
- * Updates config with current player data and saves it to disk 
- */
-void
-omp_config_update()
-{
-	omp_config->playlist_position = omp_playlist_current_track_id;
-
-	omp_config_save();
-}
-
-
-/**
  * Tests for a lock file and returns the pid of any process already running
  */
 pid_t
@@ -256,7 +159,7 @@
 	gint fd;
 	struct flock fl;
 
-	fd = open(file_name, O_WRONLY|O_CREAT,  S_IWUSR);
+	fd = open(file_name, O_WRONLY|O_CREAT, S_IWUSR);
 	if (fd < 0)
 	{
 		g_printerr("Failed opening lock file\n");
@@ -302,6 +205,8 @@
 gint
 main(int argc, char *argv[])
 {
+	GError *error;
+
 #ifdef DEBUG_MEM_PROFILE
 	g_mem_set_vtable(glib_mem_profiler_table);
 #endif
@@ -348,12 +253,10 @@
 	handle_locking();
 
 	// Initialize gstreamer, must be last in the chain of command line parameter processors
-
-	if (!gst_init_check(&argc, &argv))
+	if (!gst_init_check(&argc, &argv, &error))
 	{
-		g_printerr(_("Unable to initialize gstreamer, exiting.\n"
-			"As gstreamer also fails to initialize when encountering unknown "
-			"command line parameters you should check those as well.\n"));
+		g_printerr(_("Exiting due to gstreamer error: %s\n"), error->message);
+		g_error_free(error);
 		exit(EXIT_FAILURE);
 	}
 
@@ -368,26 +271,27 @@
 	signal(SIGUSR1, handler_sigusr1);
 
 	// Initialize playback, playlist and UI handling
+	omp_config_init();
 	omp_main_window_create();
 	omp_playback_init();
 	omp_playlist_init();
 	omp_main_connect_signals();
-	omp_config_restore_state();
+	omp_session_restore_state();
 	omp_main_window_show();
 
 	gtk_main();
 	gdk_threads_leave();
 
-	// Store and free configuration resources
-	omp_config_save();
-	omp_config_free();
-
-	// Free remaining resources
+	// Clean up
+	omp_playback_save_state();
 	omp_playback_free();
 	omp_playlist_free();
 	gst_deinit();
 	g_free(ui_image_path);
 
+	omp_session_free();
+	omp_config_free();
+
 #ifdef DEBUG_MEM_PROFILE
 	g_mem_profile();
 #endif

Modified: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/main.h
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/main.h	2007-08-05 22:50:00 UTC (rev 2642)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/main.h	2007-08-06 10:51:19 UTC (rev 2643)
@@ -27,39 +27,5 @@
 #ifndef _MAIN_H
 #define _MAIN_H
 
-/// Modes available for repetitive track playback
-enum omp_repeat_modes
-{
-	OMP_REPEAT_OFF,									///< Repeat off
-	OMP_REPEAT_CURRENT_ONCE,				///< Repeat current track once, then proceed with next track
-	OMP_REPEAT_CURRENT,							///< Repeat current track forever
-	OMP_REPEAT_PLAYLIST							///< Repeat playlist
-};
 
-/// Session-persistent configuration data
-struct _omp_config
-{
-	gboolean shuffle;								///< Shuffle on/off
-	gboolean resume_playback;				///< Resume playback on startup where it left off?
-	gint repeat_mode;								///< Repeat mode @see omp_repeat_modes
-//	gboolean auto_scroll;						///< Scroll title if it's too long?
-	gboolean convert_underscore;		///< Convert '_' to ' '?
-	gchar title_format[32];					///< Format string used for title display
-	gdouble equalizer_gain;					///< Pre-amplification value before audio stream is fed to equalizer [0.0..1.0]
-	gdouble equalizer_bands[11];		///< The gains for each of the equalizer bands [-1.0..1.0]
-	gboolean show_numbers_in_pl;		///< Show numbers in playlist?
-	gchar filesel_path[256];				///< Last path used in the file selection dialog
-//	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
-	glong track_position;						///< Position to resume playback from within the last played track
-};
-
-extern struct _omp_config *omp_config;
-extern struct _omp_config omp_default_config;
-
-void omp_config_save();
-void omp_config_load();
-void omp_config_update();
-
 #endif

Modified: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/mainwin.c
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/mainwin.c	2007-08-05 22:50:00 UTC (rev 2642)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/mainwin.c	2007-08-06 10:51:19 UTC (rev 2643)
@@ -39,6 +39,8 @@
 #include "playlist.h"
 #include "playback.h"
 
+#define OMP_BUTTON_PIXMAP_SIZE 36
+
 /// Contains all main window widgets that need to be changeable
 struct _main_widgets
 {
@@ -51,7 +53,7 @@
 	GtkWidget *volume_image;
 	GtkWidget *volume_label;
 	GtkWidget *balance_image;
-	GtkWidget *play_pause_button;
+	GtkWidget *play_pause_button_image;
 	GtkWidget *shuffle_button;
 	GtkWidget *repeat_button;
 	GtkWidget *playlist_button;
@@ -93,6 +95,9 @@
 	if ( (vol < 0) || (vol > 100) )
 		g_printerr("Warning: volume passed to omp_change_vol_img() out of bounds\n");
 
+	if (vol < 0) vol = 0;
+	if (vol > 100) vol = 100;
+
 	gchar *image_file_name = g_strdup_printf("%s/ind-music-volume-%02d.png", ui_image_path, vol/10);
 	gtk_image_set_from_file(GTK_IMAGE(main_widgets.volume_image), image_file_name);
 
@@ -313,6 +318,8 @@
 
 /**
  * Creates a toggle button framed by a GtkAlignment
+ * @param image_name Path and file name of the image to use as pixmap
+ * @return A GtkAlignment containing the button
  */
 GtkWidget*
 omp_toggle_button_create(gchar *image_name, gint pad_left, GCallback callback, GtkWidget **button)
@@ -325,7 +332,6 @@
 
 	*button = gtk_toggle_button_new();
 	gtk_widget_set_size_request(GTK_WIDGET(*button), 66, 66);
-	gtk_widget_set_name(GTK_WIDGET(*button), "mokofingerbutton-white");
 	g_signal_connect(G_OBJECT(*button), "clicked", G_CALLBACK(callback), NULL);
 	GTK_WIDGET_UNSET_FLAGS(GTK_WIDGET(*button), GTK_CAN_FOCUS);
 	gtk_container_add(GTK_CONTAINER(alignment), GTK_WIDGET(*button));
@@ -341,24 +347,24 @@
 }
 
 /**
- * Creates a button and returns it
+ * Creates a button with a stock pixmap and returns it
  * @param image_name The name of the image resource to use, not a file name
+ * @return The button
  */
 GtkWidget*
-omp_button_create(gchar *image_name, GCallback callback)
+omp_stock_button_create(gchar *image_name, GtkWidget **image, GCallback callback)
 {
-	GtkWidget *image, *button;
+	GtkWidget *button;
 
 	button = gtk_button_new();
 	gtk_widget_set_size_request(GTK_WIDGET(button), 66, 66);
-	gtk_widget_set_name(GTK_WIDGET(button), "mokofingerbutton-white");
 	g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(callback), NULL);
 	GTK_WIDGET_UNSET_FLAGS(GTK_WIDGET(button), GTK_CAN_FOCUS);
 
 	g_object_set(G_OBJECT(button), "xalign", (gfloat)0.37, "yalign", (gfloat)0.37, NULL);
 
-	image = gtk_image_new_from_icon_name(image_name, 36);
-	gtk_container_add(GTK_CONTAINER(button), GTK_WIDGET(image));
+	*image = gtk_image_new_from_icon_name(image_name, OMP_BUTTON_PIXMAP_SIZE);
+	gtk_container_add(GTK_CONTAINER(button), GTK_WIDGET(*image));
 
 	return button;
 }
@@ -556,27 +562,27 @@
 	gtk_box_set_homogeneous(GTK_BOX(controls_hbox), TRUE);
 
 	// Previous Track button
-	button = omp_button_create("gtk-media-previous-ltr", G_CALLBACK(omp_playlist_set_prev_track));
+	button = omp_stock_button_create("gtk-media-previous-ltr", &image, G_CALLBACK(omp_playlist_set_prev_track));
 	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);
 
 	// Rewind button
-	button = omp_button_create("gtk-media-rewind-ltr", G_CALLBACK(omp_main_button_rewind_callback));
+	button = omp_stock_button_create("gtk-media-rewind-ltr", &image, 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);
 
 	// Play/Pause button
-	button = omp_button_create("gtk-media-play-ltr", G_CALLBACK(omp_main_button_play_pause_callback));
+	button = omp_stock_button_create("gtk-media-play-ltr", &main_widgets.play_pause_button_image, G_CALLBACK(omp_main_button_play_pause_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);
 
 	// Fast Forward button
-	button = omp_button_create("gtk-media-forward-ltr", G_CALLBACK(omp_main_button_fast_forward_callback));
+	button = omp_stock_button_create("gtk-media-forward-ltr", &image, 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);
 
 	// Next Track button
-	button = omp_button_create("gtk-media-next-ltr", G_CALLBACK(omp_playlist_set_next_track));
+	button = omp_stock_button_create("gtk-media-next-ltr", &image, G_CALLBACK(omp_playlist_set_next_track));
 	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);
 }
@@ -614,7 +620,6 @@
 	// Show everything but the window itself
 	gtk_widget_show_all(GTK_WIDGET(bg_muxer));
 
-
 	return;
 }
 
@@ -627,7 +632,7 @@
 omp_main_connect_signals()
 {
 	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_STATUS_CHANGED,		G_CALLBACK(omp_main_update_status_change), NULL);
 	g_signal_connect(G_OBJECT(omp_main_window), OMP_EVENT_PLAYBACK_POSITION_CHANGED,	G_CALLBACK(omp_main_update_track_position), NULL);
 }
 
@@ -651,8 +656,8 @@
 		old_track_count = omp_playlist_track_count;
 		old_track_id = omp_playlist_current_track_id;
 
-		// Update config
-		omp_config_update();
+		// Update session
+		omp_session_set_track_id(omp_playlist_current_track_id);
 
 		// Update label
 		text = g_strdup_printf(WIDGET_CAPTION_TRACK_NUM, omp_playlist_current_track_id+1, omp_playlist_track_count);
@@ -668,7 +673,7 @@
 		old_track_length = track_length;
 		track_position = omp_playback_get_track_position();
 
-		// Set new time slider increments
+		// Set new time slider increments: one tap is 10% of the track's playing time
 		gtk_range_set_increments(GTK_RANGE(main_widgets.time_hscale), track_length/10, track_length/10);
 
 		// Update label and slider
@@ -680,6 +685,7 @@
 
 		if (omp_main_time_slider_can_update)
 		{
+			// We don't want to set both min/max to 0 as this triggers a critial GTK warning, so we set 0/1 instead in that case
 			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);
 		}
@@ -687,6 +693,21 @@
 }
 
 /**
+ * Updates the UI if playback engine switched between paused and playing modes
+ */
+void
+omp_main_update_status_change()
+{
+	// Update Play/Pause button pixmap
+	if (omp_playback_get_state() == OMP_PLAYBACK_STATE_PAUSED)
+	{
+		gtk_image_set_from_icon_name(GTK_IMAGE(main_widgets.play_pause_button_image), "gtk-media-play-ltr", OMP_BUTTON_PIXMAP_SIZE);
+	} else {
+		gtk_image_set_from_icon_name(GTK_IMAGE(main_widgets.play_pause_button_image), "gtk-media-pause", OMP_BUTTON_PIXMAP_SIZE);
+	}
+}
+
+/**
  * Updates the UI if the playback position changed
  */
 void
@@ -712,6 +733,7 @@
 
 		if (omp_main_time_slider_can_update)
 		{
+			// We don't want to set both min/max to 0 as this triggers a critial GTK warning, so we set 0/1 instead in that case
 			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-mediaplayer2/src/mainwin.h
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/mainwin.h	2007-08-05 22:50:00 UTC (rev 2642)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/mainwin.h	2007-08-06 10:51:19 UTC (rev 2643)
@@ -36,6 +36,7 @@
 // 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();
@@ -46,6 +47,7 @@
 void omp_main_connect_signals();
 
 void omp_main_update_track_change();
+void omp_main_update_status_change();
 void omp_main_update_track_position();
 
 #endif

Added: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/persistent.c
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/persistent.c	2007-08-05 22:50:00 UTC (rev 2642)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/persistent.c	2007-08-06 10:51:19 UTC (rev 2643)
@@ -0,0 +1,245 @@
+/*
+ *  OpenMoko Media Player
+ *   http://openmoko.org/
+ *
+ *  Copyright (C) 2007 by the OpenMoko team
+ *
+ *  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 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, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * @file persistent.c
+ * Manages application configuration and session data
+ */
+
+#include <glib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "persistent.h"
+
+/// The default configuration
+struct _omp_config omp_default_config =
+{
+	FALSE,
+	TRUE,
+	OMP_REPEAT_OFF,
+//	FALSE,
+	FALSE,
+	"%f",
+	0.0,
+	{0,0,0,0,0,0,0,0,0,0,0},
+	TRUE
+};
+
+struct _omp_config *omp_config = NULL;			///< Global and persistent configuration data
+struct _omp_session *omp_session = NULL;		///< Global and persistent session data
+
+
+/**
+ * Load application configuration data
+ */
+void
+omp_config_init()
+{
+	#ifdef DEBUG
+		g_print("Loading application configuration\n");
+	#endif
+
+	// This mustn't be called more than once
+	g_assert(omp_config == NULL);
+
+	// Set default config
+	omp_config = g_new(struct _omp_config, 1);
+	g_memmove(omp_config, &omp_default_config, sizeof(struct _omp_config));
+
+	/// @todo GConf
+}
+
+/**
+ * Releases resources allocated for configuration data
+ */
+void
+omp_config_free()
+{
+	g_free(omp_config);
+}
+
+/**
+ * Saves the current application configuration data to persistent storate
+ */
+void
+omp_config_save()
+{
+}
+
+/**
+ * Restores program state from last session
+ */
+void
+omp_session_restore_state()
+{
+	#ifdef DEBUG
+		g_print("Loading session data\n");
+	#endif
+
+	// This mustn't be called more than once
+	g_assert(omp_session == NULL);
+
+	omp_session = g_new0(struct _omp_session, 1);
+
+	// Load config and last used playlist if set
+	omp_session_load();
+
+	if (omp_session->playlist_file[0])
+	{
+		omp_playlist_load(omp_session->playlist_file);
+	}
+
+	// Check whether playlist_position is valid
+	if (!omp_playlist_set_current_track(omp_session->playlist_position))
+	{
+		// Reset playlist state as playlist must have been modified since it was last loaded
+		omp_session->playlist_position = 0;
+		omp_session->track_position = 0;
+		omp_playlist_set_current_track(0);
+	}
+
+	// Try to load the track, set the playback position and resume playback if needed
+	if (omp_playlist_load_current_track())
+	{
+		if (omp_session->was_playing)
+		{
+			omp_playback_play();
+		}
+
+		omp_playback_set_track_position(omp_session->track_position);
+	}
+}
+
+/**
+ * Free resources used for session data
+ */
+void
+omp_session_free()
+{
+	g_free(omp_session);
+}
+
+/**
+ * Save session data to persistent storage
+ */
+void
+omp_session_save()
+{
+	gint session_file, result;
+	gchar *file_name;
+
+	// OMP_SESSION_FILE_NAME is relative to user's home dir
+	file_name = g_build_filename(g_get_home_dir(), OMP_SESSION_FILE_NAME, NULL);
+
+	// Permissions for created session file are 0600
+	session_file = creat(file_name, S_IRUSR | S_IWUSR);
+	if (session_file == -1) goto io_error;
+
+	result = write(session_file, omp_session, sizeof(struct _omp_session));
+	if (result != sizeof(struct _omp_session)) goto io_error;
+
+	result = close(session_file);
+	if (result == -1) goto io_error;
+
+	g_free(file_name);
+	return;
+
+	// We use a label to avoid duplicating code and improve readability
+io_error:
+	#ifdef DEBUG
+		g_printerr("Failed trying to save session data to %s: %s\n", file_name, strerror(errno));
+	#endif
+
+	g_free(file_name);
+}
+
+/**
+ * Load session data from persistent storage
+ */
+void
+omp_session_load()
+{
+	gint session_file, result;
+	gchar *file_name;
+
+	// OMP_SESSION_FILE_NAME is relative to user's home dir
+	file_name = g_build_filename(g_get_home_dir(), OMP_SESSION_FILE_NAME, NULL);
+
+	session_file = open(file_name, O_RDONLY);
+	if (session_file == -1) goto io_error;
+
+	result = read(session_file, omp_session, sizeof(struct _omp_session));
+	if (result != sizeof(struct _omp_session)) goto io_error;
+
+	result = close(session_file);
+	if (result == -1) goto io_error;
+
+	g_free(file_name);
+	return;
+
+	// We use a label to avoid duplicating code and improve readability
+io_error:
+	#ifdef DEBUG
+		g_printerr("Failed trying to load session data from %s: %s\n", file_name, strerror(errno));
+	#endif
+
+	g_free(file_name);
+
+	// Clear session data on error - just to be safe
+	memset(omp_session, 0, sizeof(struct _omp_session));
+}
+
+/**
+ * Saves values the playback engine needs to resume operation next time the player is started
+ */
+void
+omp_session_set_playback_state(glong track_position, gboolean is_playing)
+{
+	omp_session->track_position = track_position;
+	omp_session->was_playing = is_playing;
+
+	omp_session_save();
+}
+
+/**
+ * Set playlist to be loaded next session
+ */
+void
+omp_session_set_playlist(gchar *playlist_file)
+{
+	g_snprintf(omp_session->playlist_file, sizeof(omp_session->playlist_file), "%s", playlist_file);
+	omp_session_save();
+}
+
+/**
+ * Set track to be loaded next session
+ */
+void
+omp_session_set_track_id(guint track_id)
+{
+	omp_session->playlist_position = track_id;
+	omp_session_save();
+}
+

Added: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/persistent.h
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/persistent.h	2007-08-05 22:50:00 UTC (rev 2642)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/persistent.h	2007-08-06 10:51:19 UTC (rev 2643)
@@ -0,0 +1,76 @@
+/*
+ *  OpenMoko Media Player
+ *   http://openmoko.org/
+ *
+ *  Copyright (C) 2007 by the OpenMoko team
+ *
+ *  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 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, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * @file persistent.h
+ * Manages application configuration and session data
+ */
+
+#ifndef _PERSISTENT_H
+#define _PERSISTENT_H
+
+#include "playlist.h"
+
+// File name is relative to ~
+#define OMP_SESSION_FILE_NAME "/.openmoko-mediaplayer"
+
+
+/// Application configuration data
+struct _omp_config
+{
+	gboolean shuffle;									///< Shuffle on/off
+	gboolean resume_playback;					///< Resume playback on startup where it left off?
+	gint repeat_mode;									///< Repeat mode @see omp_repeat_modes
+//	gboolean auto_scroll;						///< Scroll title if it's too long?
+	gboolean convert_underscore;			///< Convert '_' to ' '?
+	gchar title_format[32];						///< Format string used for title display
+	gdouble equalizer_gain;						///< Pre-amplification value before audio stream is fed to equalizer [0.0..1.0]
+	gdouble equalizer_bands[11];			///< The gains for each of the equalizer bands [-1.0..1.0]
+	gboolean show_numbers_in_pl;			///< Show numbers in playlist?
+};
+
+/// Session-persistent data
+/// @note Default values should be 0/FALSE as session data will be zeroed on error
+struct _omp_session
+{
+	guint playlist_position;					///< Position within the playlist
+	glong track_position;							///< Position to resume playback from within the last played track
+	gboolean was_playing;							///< Set to TRUE of track was being played as the player was closed
+	gchar filesel_path[256];					///< Last path used in the file selection dialog
+	gchar playlist_file[256];					///< Path and file name of current (=last used) playlist
+};
+
+extern struct _omp_config *omp_config;
+extern struct _omp_session *omp_session;
+
+void omp_config_init();
+void omp_config_free();
+void omp_config_save();
+
+void omp_session_restore_state();
+void omp_session_free();
+void omp_session_save();
+void omp_session_load();
+
+void omp_session_set_playlist(gchar *playlist_file);
+void omp_session_set_track_id(guint track_id);
+
+#endif

Modified: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/playback.c
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/playback.c	2007-08-05 22:50:00 UTC (rev 2642)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/playback.c	2007-08-06 10:51:19 UTC (rev 2643)
@@ -29,10 +29,12 @@
 #include "playback.h"
 #include "mainwin.h"
 
-GstElement *omp_gst_playbin = NULL;
-guint omp_playback_ui_timeout = 0;
-gboolean omp_playback_ui_timeout_halted;
+GstElement *omp_gst_playbin = NULL;						///< Our ticket to the gstreamer world
+guint omp_playback_ui_timeout = 0;						///< Handle of the UI-updating timeout
+gboolean omp_playback_ui_timeout_halted;			///< Flag that tells the UI-updating timeout to exit if set
+gulong omp_playback_pending_position = 0;			///< Since we can't set a new position if element is not paused or playing we store the position here and set it when it reached either state
 
+
 /**
  * Initializes gstreamer by setting up pipe, message hooks and bins
  */
@@ -59,9 +61,10 @@
 	bus = gst_pipeline_get_bus(GST_PIPELINE(omp_gst_playbin));
 
 	gst_bus_add_signal_watch(bus);
-	g_signal_connect(bus, "message::eos", 		G_CALLBACK(omp_gst_message_eos), NULL);
-	g_signal_connect(bus, "message::error", 	G_CALLBACK(omp_gst_message_error), NULL);
-	g_signal_connect(bus, "message::warning", G_CALLBACK(omp_gst_message_warning), NULL); 
+	g_signal_connect(bus, "message::eos", 					G_CALLBACK(omp_gst_message_eos), NULL);
+	g_signal_connect(bus, "message::error", 				G_CALLBACK(omp_gst_message_error), NULL);
+	g_signal_connect(bus, "message::warning", 			G_CALLBACK(omp_gst_message_warning), NULL);
+	g_signal_connect(bus, "message::state-changed",	G_CALLBACK(omp_gst_message_state_changed), NULL);
 
 	gst_object_unref(bus);
 }
@@ -72,16 +75,33 @@
 void
 omp_playback_free()
 {
+	GstBus *bus;
+
 	if (!omp_gst_playbin)
 	{
 		return;
 	}
 
+	bus = gst_pipeline_get_bus(GST_PIPELINE(omp_gst_playbin));
+	gst_bus_remove_signal_watch(bus);
+	gst_object_unref(bus);
+
 	gst_element_set_state(omp_gst_playbin, GST_STATE_NULL);
 	gst_object_unref(GST_OBJECT(omp_gst_playbin));
 }
 
 /**
+ * Saves current state to session data
+ */
+void
+omp_playback_save_state()
+{
+	omp_session_set_playback_state(
+		omp_playback_get_track_position(),
+		(omp_playback_get_state() == OMP_PLAYBACK_STATE_PLAYING) );
+}
+
+/**
  * Attempts to load a track from an URI
  * @return TRUE if successful, FALSE if failed
  */
@@ -129,13 +149,24 @@
 void
 omp_playback_play()
 {
+	gchar *track_uri;
+
 	#ifdef DEBUG
 		g_print("Starting playback\n");
 	#endif
 
+	g_object_get(G_OBJECT(omp_gst_playbin), "uri", &track_uri, NULL);
+	if (!track_uri)
+	{
+		#ifdef DEBUG
+			g_print("No track to play.\n");
+		#endif
+		return;
+	}
+	g_free(track_uri);
+
 	// 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
@@ -144,7 +175,7 @@
 
 	if (!omp_playback_ui_timeout)
 	{
-		omp_playback_ui_timeout = g_timeout_add(PLAYBACK_UI_UPDATE_INTERVAL, omp_playback_ui_timeout_callback, NULL);
+		omp_playback_ui_timeout = g_timeout_add(OMP_PLAYBACK_UI_UPDATE_INTERVAL, omp_playback_ui_timeout_callback, NULL);
 	}
 }
 
@@ -160,26 +191,21 @@
 
 	// 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?
+ * Returns the current state the playback engine is in, simplifying it a bit to hide internal states
  */
 gint
 omp_playback_get_state()
 {
 	GstState state;
-	GstClock *clock;
 
 	// Poll state with an immediate timeout
-	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);
+	state = GST_STATE(omp_gst_playbin);
 
 	// The NULL and READY element states are no different from PAUSED for more abstract layers
 	if ( (state == GST_STATE_NULL) || (state == GST_STATE_READY) )
@@ -214,16 +240,40 @@
 void
 omp_playback_set_track_position(glong position)
 {
+	GstState pipe_state;
+
 	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);
+	// If we don't clamp it to values >= 0 we trigger EOS messages which make the playlist mess up
+	if (position < 0) position = 0;
 
+	// Check if the pipe is even ready to seek
+	pipe_state = GST_STATE(omp_gst_playbin);
+
+	if ( (pipe_state != GST_STATE_PAUSED) && (pipe_state != GST_STATE_PLAYING) )
+	{
+		// It's not, so make the position change pending
+		omp_playback_pending_position = position;
+
+		#ifdef DEBUG
+			g_printf("Pended track position change to %d:%.2ds\n", position / 60, position % 60);
+		#endif
+		return;
+	}
+	omp_playback_pending_position = 0;
+
+	#ifdef DEBUG
+		g_printf("Setting track position to %d:%.2ds\n", position / 60, position % 60);
+	#endif
+
+	gst_element_seek(GST_ELEMENT(omp_gst_playbin), 1.0,
+		GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
+		GST_SEEK_TYPE_SET, position*GST_SECOND,
+		GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
+
 	g_signal_emit_by_name(G_OBJECT(omp_main_window), OMP_EVENT_PLAYBACK_POSITION_CHANGED);
 }
 
@@ -265,6 +315,31 @@
 }
 
 /**
+ * Handles gstreamer's state change notification
+ */
+static gboolean
+omp_gst_message_state_changed(GstBus *bus, GstMessage *message, gpointer data)
+{
+	static gint previous_state = GST_STATE_VOID_PENDING;
+	gint new_state;
+
+	// Do we have a pending playback position change that we can apply?
+	if ( ( (GST_STATE(omp_gst_playbin) == GST_STATE_PLAYING) || (GST_STATE(omp_gst_playbin) == GST_STATE_PAUSED) )
+ 		&& omp_playback_pending_position)
+	{
+		omp_playback_set_track_position(omp_playback_pending_position);
+	}
+
+	// Only propagate this event if it's of interest for higher-level routines
+	new_state = omp_playback_get_state();
+	if (new_state != previous_state)
+	{
+		previous_state = new_state;
+		g_signal_emit_by_name(G_OBJECT(omp_main_window), OMP_EVENT_PLAYBACK_STATUS_CHANGED);
+	}
+}
+
+/**
  * Handles gstreamer's error messages
  */
 static gboolean
@@ -275,7 +350,6 @@
 	#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
 
@@ -293,7 +367,6 @@
 	#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
 

Modified: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/playback.h
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/playback.h	2007-08-05 22:50:00 UTC (rev 2642)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/playback.h	2007-08-06 10:51:19 UTC (rev 2643)
@@ -38,10 +38,11 @@
 #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
+#define OMP_PLAYBACK_UI_UPDATE_INTERVAL 1000
 
 void omp_playback_init();
 void omp_playback_free();
+void omp_playback_save_state();
 
 gboolean omp_playback_load_track_from_uri(gchar *uri);
 
@@ -53,6 +54,7 @@
 gulong omp_playback_get_track_length();
 
 static gboolean omp_gst_message_eos(GstBus *bus, GstMessage *message, gpointer data);
+static gboolean omp_gst_message_state_changed(GstBus *bus, GstMessage *message, gpointer data);
 static gboolean omp_gst_message_error(GstBus *bus, GstMessage *message, gpointer data);
 static gboolean omp_gst_message_warning(GstBus *bus, GstMessage *message, gpointer data);
 

Modified: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/playlist.c
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/playlist.c	2007-08-05 22:50:00 UTC (rev 2642)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/playlist.c	2007-08-06 10:51:19 UTC (rev 2643)
@@ -30,9 +30,9 @@
 #include <spiff/spiff_c.h>
 
 #include "playlist.h"
-#include "main.h"
 #include "mainwin.h"
 #include "playback.h"
+#include "persistent.h"
 
 struct spiff_list *omp_playlist = NULL;										///< Loaded playlist
 guint omp_playlist_track_count = 0;												///< Number of tracks stored within the current playlist
@@ -66,7 +66,7 @@
 }
 
 /**
- * Frees resouces allocated for playlist handling
+ * Frees resources allocated for playlist handling
  */
 void
 omp_playlist_free()
@@ -105,10 +105,10 @@
 		spiff_free(omp_playlist);
 	}
 
-	// Update config unless target and source are the same
-	if (omp_config->playlist_file != playlist_file)
+	// Update session unless target and source are the same
+	if (omp_session->playlist_file != playlist_file)
 	{
-		g_snprintf(omp_config->playlist_file, sizeof(omp_config->playlist_file), "%s", playlist_file);
+		omp_session_set_playlist(playlist_file);
 	}
 
 	// Load playlist
@@ -239,6 +239,7 @@
 			{
 				omp_playlist_current_track = track;
 				omp_playlist_current_track_id--;
+				is_new_track = TRUE;
 			}
 		}
 	}

Modified: trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/playlist.h
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/playlist.h	2007-08-05 22:50:00 UTC (rev 2642)
+++ trunk/src/target/OM-2007.2/applications/openmoko-mediaplayer2/src/playlist.h	2007-08-06 10:51:19 UTC (rev 2643)
@@ -31,6 +31,15 @@
 
 #define OMP_EVENT_PLAYLIST_TRACK_CHANGED "playlist_track_changed"
 
+/// Modes available for repetitive track playback
+enum omp_repeat_modes
+{
+	OMP_REPEAT_OFF,									///< Repeat off
+	OMP_REPEAT_CURRENT_ONCE,				///< Repeat current track once, then proceed with next track
+	OMP_REPEAT_CURRENT,							///< Repeat current track forever
+	OMP_REPEAT_PLAYLIST							///< Repeat entire playlist
+};
+
 extern struct spiff_list *omp_playlist;
 extern guint omp_playlist_track_count;
 





More information about the commitlog mailing list