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