commit e21b061c9d774ea3bc913f686c529dc618f4585f
Author: phantomjinx <[email protected]>
Date: Sat Oct 9 22:24:24 2010 +0100
Reworking of media player plugin
* Remove loop in the play thread as unnecessary and problematic
plugins/media_player/media_player.c | 381 ++++++++++++++++++-----------------
plugins/media_player/media_player.h | 6 +-
2 files changed, 202 insertions(+), 185 deletions(-)
---
diff --git a/plugins/media_player/media_player.c
b/plugins/media_player/media_player.c
index 9cf57cd..cd5160a 100644
--- a/plugins/media_player/media_player.c
+++ b/plugins/media_player/media_player.c
@@ -48,6 +48,11 @@
static MediaPlayer *player;
+// Declarations
+static void thread_play_song();
+static gint thread_stop_song(void *data);
+static gint thread_next_song(void *data);
+
static int pipeline_bus_watch_cb(GstBus *bus, GstMessage *msg, gpointer data);
static gboolean set_scale_range(GstElement *pipeline) {
@@ -117,56 +122,6 @@ static void update_volume(gdouble value) {
g_object_set(player->play_element, "volume", player->volume_level, NULL);
}
-static gboolean volume_changed_cb(GtkRange *range, GtkScrollType scroll,
gdouble value, gpointer user_data) {
- update_volume(value);
- return FALSE;
-}
-
-//static void new_decoded_pad_cb(GstElement *decodebin, GstPad *pad, gboolean
last, gpointer data) {
-// GstCaps *caps;
-// GstStructure *str;
-// GstPad *audiopad2;
-// // , *videopad2;
-//
-// if (!player)
-// return;
-//
-// /* check media type */
-// caps = gst_pad_get_caps(pad);
-// str = gst_caps_get_structure(caps, 0);
-// const gchar *name = gst_structure_get_name(str);
-// if (g_strrstr(name, "audio")) {
-// /* only link once */
-// audiopad2 = gst_element_get_pad(player->audio, "sink");
-// if (GST_PAD_IS_LINKED (audiopad2)) {
-// g_object_unref(audiopad2);
-// return;
-// }
-//
-// /* link'n'play */
-// gst_pad_link(pad, audiopad2); // Link audiopad to pad or other way
around, dunno
-// //gst_element_link (volume, dec); //Doesn't seem to work...
-// //volume_changed_callback (vol_scale, volume); //Change volume to
default
-// }
-//
-// if (g_strrstr(name, "video")) {
-// // only link once
-//
-// // videopad2 = gst_element_get_pad(videoconv, "sink");
-// // if (GST_PAD_IS_LINKED (videopad2)) {
-// // printf("video pad is linked!unreffing\n");
-// // g_object_unref(videopad2);
-// // return;
-// // }
-// // link'n'play
-// // gst_pad_link(pad, videopad2);
-// //set_video_mode (TRUE);//Not needed since We can't actually SEE the
video
-// }
-//
-// gst_caps_unref(caps);
-//
-//}
-
static void set_song_label(Track *track) {
if (!track) {
gtk_label_set_markup(GTK_LABEL(player->song_label), "");
@@ -195,70 +150,26 @@ static void set_song_label(Track *track) {
g_free(label);
}
-static void thread_play_song() {
- GstStateChangeReturn sret;
- GstState state;
- gchar *track_name;
- gchar *uri;
- GstBus *bus;
-
- if (!player || !player->tracks)
- return;
-
- while (player->tracks) {
- Track *tr = player->tracks->data;
- g_return_if_fail(tr);
- track_name = get_file_name_from_source(tr, SOURCE_PREFER_LOCAL);
- if (!track_name)
- continue;
+static void set_control_state(GstState state) {
+ Track *tr = g_list_nth_data(player->tracks, player->track_index);
+ if (tr) {
set_song_label(tr);
-
- /* init GStreamer */
- player->loop = g_main_loop_new(NULL, FALSE); // make new loop
-
- uri = g_strconcat("file://", track_name, NULL);
- player->play_element = gst_element_factory_make("playbin2", "play");
- g_object_set(G_OBJECT (player->play_element), "uri", uri, NULL);
- g_object_set(player->play_element, "volume", player->volume_level,
NULL);
-
- bus = gst_pipeline_get_bus(GST_PIPELINE (player->play_element));
- gst_bus_add_watch(bus, pipeline_bus_watch_cb, player->loop); //Add a
watch to the bus
- gst_object_unref(bus); //unref the bus
-
- /* run */
- gst_element_set_state(player->play_element, GST_STATE_PLAYING);// set
state
- g_timeout_add(250, (GSourceFunc) set_scale_range, GST_PIPELINE
(player->play_element));
- g_timeout_add(1000, (GSourceFunc) set_scale_position, GST_PIPELINE
(player->play_element));
- g_main_loop_run(player->loop);
-
- /* cleanup */
- sret = gst_element_set_state(player->play_element, GST_STATE_NULL);
-#ifndef NEW_PIPE_PER_FILE
- if (GST_STATE_CHANGE_ASYNC == sret) {
- if (gst_element_get_state(GST_ELEMENT (player->play_element),
&state, NULL, GST_CLOCK_TIME_NONE)
- == GST_STATE_CHANGE_FAILURE) {
- break;
- }
- }
-#endif
- gst_element_set_state(player->play_element, GST_STATE_NULL);
- g_free(uri);
- g_free(track_name);//Free it since it is no longer needed.
-
-
- if (player->stopButtonPressed)
- break;
-
- if (!player->previousButtonPressed)
- player->tracks = g_list_next(player->tracks);
- else
- player->previousButtonPressed = FALSE;
}
- player->thread = NULL;
- player->stopButtonPressed = FALSE;
- g_thread_exit(0);
+ switch (state) {
+ case GST_STATE_PLAYING:
+ gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(player->play_button),
GTK_STOCK_MEDIA_PAUSE);
+ break;
+ case GST_STATE_PAUSED:
+ gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(player->play_button),
GTK_STOCK_MEDIA_PLAY);
+ break;
+ default:
+ gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(player->play_button),
GTK_STOCK_MEDIA_PLAY);
+ gtk_range_set_range(GTK_RANGE(player->song_scale), 0, 1);
+ gtk_range_set_value(GTK_RANGE(player->song_scale), 0);
+ gtk_label_set_text(GTK_LABEL(player->song_time_label), "");
+ }
}
static void waitforpipeline(int state) {
@@ -268,12 +179,19 @@ static void waitforpipeline(int state) {
if (!player->loop || !player->thread)
return;
+ if (!player->play_element)
+ return;
+
GstState istate, ipending;
gst_element_get_state(player->play_element, &istate, &ipending,
GST_CLOCK_TIME_NONE);
if (istate == GST_STATE_VOID_PENDING) {
return;
}
+
+ if (istate == state)
+ return;
+
gst_element_set_state(player->play_element, state);
do {
@@ -284,114 +202,139 @@ static void waitforpipeline(int state) {
}
}
while (istate != state);
+}
+
+static gboolean is_playing() {
+ if (!player || !player->loop || !player->play_element || !player->thread
|| !g_main_loop_is_running(player->loop))
+ return FALSE;
- return;
+ GstState state, pending;
+ gst_element_get_state(player->play_element, &state, &pending,
GST_CLOCK_TIME_NONE);
+
+ if (state == GST_STATE_PLAYING)
+ return TRUE;
+
+ return FALSE;
}
-static void stop_song(gboolean stopButtonPressed) {
- if (!player)
- return;
+static gboolean is_paused() {
+ if (!player || !player->loop || !player->play_element || !player->thread
|| !g_main_loop_is_running(player->loop))
+ return FALSE;
- player->stopButtonPressed = stopButtonPressed;
- if (player->loop && g_main_loop_is_running(player->loop)) {
- g_main_loop_quit(player->loop);
+ GstState state, pending;
+ gst_element_get_state(player->play_element, &state, &pending,
GST_CLOCK_TIME_NONE);
+
+ if (state == GST_STATE_PAUSED)
+ return TRUE;
+
+ return FALSE;
+}
+
+static gboolean is_stopped() {
+ if (!player || !player->loop || !player->play_element || !player->thread
|| !g_main_loop_is_running(player->loop)) {
+ return TRUE;
}
- waitforpipeline(1);
- gtk_range_set_range(GTK_RANGE(player->song_scale), 0, 1);
- gtk_range_set_value(GTK_RANGE(player->song_scale), 0);
- gtk_label_set_text(GTK_LABEL(player->song_time_label), "");
- gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(player->play_button),
GTK_STOCK_MEDIA_PLAY);
+ GstState state, pending;
+ gst_element_get_state(player->play_element, &state, &pending,
GST_CLOCK_TIME_NONE);
+
+ if (state == GST_STATE_NULL)
+ return TRUE;
+
+ return FALSE;
}
-static void previous_song() {
+static void stop_song() {
if (!player)
return;
- if (!player->tracks)
- return;
+ if (player->loop && g_main_loop_is_running(player->loop)) {
+ g_main_loop_quit(player->loop);
+ }
- player->previousButtonPressed = TRUE;
- player->tracks = g_list_previous (player->tracks);
- stop_song(FALSE);
-}
+ waitforpipeline(GST_STATE_NULL);
-static void next_song() {
- stop_song(FALSE);
+ player->thread = NULL;
}
-static void play_song() {
- GError *err1 = NULL;
-
- if (!player)
+static void pause_or_play_song() {
+ if (!player || !player->tracks)
return;
- if (!player->tracks)
- return;
+ if (is_stopped()) {
+ GError *err1 = NULL;
+
+ set_control_state(GST_STATE_PLAYING);
- if (!g_thread_supported ()) {
- g_thread_init(NULL);
- gdk_threads_init();
+ player->thread = g_thread_create ((GThreadFunc)thread_play_song, NULL,
TRUE, &err1);
+ if (!player->thread) {
+ gtkpod_statusbar_message("GStreamer thread creation failed: %s\n",
err1->message);
+ g_error_free(err1);
+ }
+ } else if (is_playing()) {
+ waitforpipeline(GST_STATE_PAUSED);
+ set_control_state(GST_STATE_PAUSED);
+ } else if (is_paused()) {
+ waitforpipeline(GST_STATE_PLAYING);
+ set_control_state(GST_STATE_PLAYING);
}
+}
- stop_song(TRUE);
+static void next_song() {
+ gboolean playing = is_playing() || is_paused();
- player->stopButtonPressed = FALSE;
- gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(player->play_button),
GTK_STOCK_MEDIA_PLAY);
+ if (playing) {
+ stop_song();
+ }
- player->thread = g_thread_create ((GThreadFunc)thread_play_song, NULL,
TRUE, &err1);
- if (!player->thread) {
- gtkpod_statusbar_message("GStreamer thread creation failed: %s\n",
err1->message);
- g_error_free(err1);
+ if (player->track_index < g_list_length(player->tracks) - 1) {
+ player->track_index++;
+ } else {
+ player->track_index = 0;
}
- gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(player->play_button),
GTK_STOCK_MEDIA_PAUSE);
-}
+ set_song_label(g_list_nth_data(player->tracks, player->track_index));
-static void pause_or_play_song() {
- if (!player)
- return;
-
- if (!player->loop || !player->play_element || !player->thread ||
!g_main_loop_is_running(player->loop)) {
- play_song();
- return;
+ if (playing) {
+ pause_or_play_song();
}
+}
- GstState state, pending;
- gst_element_get_state(player->play_element, &state, &pending,
GST_CLOCK_TIME_NONE);
+static void previous_song() {
+ gboolean playing = is_playing() || is_paused();
- if (state == GST_STATE_PLAYING) {
- gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(player->play_button),
GTK_STOCK_MEDIA_PLAY);
- gst_element_set_state(player->play_element, GST_STATE_PAUSED);
+ if (playing) {
+ stop_song();
}
- else if (state == GST_STATE_PAUSED) {
- gtk_tool_button_set_stock_id(GTK_TOOL_BUTTON(player->play_button),
GTK_STOCK_MEDIA_PAUSE);
- gst_element_set_state(player->play_element, GST_STATE_PLAYING);
+
+ if (player->track_index > 0) {
+ player->track_index--;
+ } else {
+ player->track_index = g_list_length(player->tracks) - 1;
}
-}
-void seek_to_time(gint64 time_seconds) {
- if (!player)
- return;
+ set_song_label(g_list_nth_data(player->tracks, player->track_index));
- if (!player->loop || !player->play_element || !player->thread)
- return;
+ if (playing)
+ pause_or_play_song();
+}
- if (!g_main_loop_is_running(player->loop))
+void seek_to_time(gint64 time_seconds) {
+ if (is_stopped())
return;
if (!gst_element_seek(player->play_element, 1.0, GST_FORMAT_TIME,
GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, time_seconds
* 1000000000, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE))
- g_print("Seek failed!\n");
+ gtkpod_statusbar_message("Seek failed!\n");
}
static int pipeline_bus_watch_cb(GstBus *bus, GstMessage *msg, gpointer data) {
switch (GST_MESSAGE_TYPE (msg)) {
case GST_MESSAGE_EOS:
- stop_song(FALSE);
+ g_idle_add(thread_next_song, NULL);
break;
case GST_MESSAGE_ERROR: {
- stop_song(TRUE);
+ g_idle_add(thread_stop_song, NULL);
break;
}
default:
@@ -401,11 +344,70 @@ static int pipeline_bus_watch_cb(GstBus *bus, GstMessage
*msg, gpointer data) {
return TRUE;
}
+static void thread_play_song() {
+ gchar *track_name;
+ gchar *uri;
+ GstBus *bus;
+ GError *error;
+
+ if (!player || !player->tracks)
+ return;
+
+ Track *tr = g_list_nth_data(player->tracks, player->track_index);
+ if (!tr)
+ return;
+
+ error = NULL;
+ track_name = get_file_name_from_source(tr, SOURCE_PREFER_LOCAL);
+ if (!track_name)
+ return;
+
+ /* init GStreamer */
+ player->loop = g_main_loop_new(NULL, FALSE); // make new loop
+ uri = g_filename_to_uri (track_name, NULL, &error);
+ g_free(track_name);
+ if (error) {
+ gtkpod_statusbar_message("Failed to play track: %s", error->message);
+ g_free(uri);
+ return;
+ }
+
+ player->play_element = gst_element_factory_make("playbin2", "play");
+ g_object_set(G_OBJECT (player->play_element), "uri", uri, NULL);
+ g_object_set(player->play_element, "volume", player->volume_level, NULL);
+
+ bus = gst_pipeline_get_bus(GST_PIPELINE (player->play_element));
+ gst_bus_add_watch(bus, pipeline_bus_watch_cb, player->loop); //Add a watch
to the bus
+ gst_object_unref(bus); //unref the bus
+
+ /* run */
+ gst_element_set_state(player->play_element, GST_STATE_PLAYING);// set state
+ g_timeout_add(250, (GSourceFunc) set_scale_range, GST_PIPELINE
(player->play_element));
+ g_timeout_add(1000, (GSourceFunc) set_scale_position, GST_PIPELINE
(player->play_element));
+ g_main_loop_run(player->loop);
+
+ g_free(uri);
+
+ gst_element_set_state(player->play_element, GST_STATE_NULL);
+ g_thread_exit(0);
+}
+
+static gint thread_stop_song(void *data) {
+ stop_song();
+ return FALSE; // call only once
+}
+
+static gint thread_next_song(void *data) {
+ next_song();
+ return FALSE; // call only once
+}
+
void set_selected_tracks(GList *tracks) {
- if (!player)
+ if (! tracks)
return;
- stop_song(TRUE);
+ if (is_playing() || is_paused())
+ return;
if (player->tracks) {
g_list_free(player->tracks);
@@ -413,9 +415,6 @@ void set_selected_tracks(GList *tracks) {
set_song_label(NULL);
}
- if (! tracks)
- return;
-
GList *l = g_list_copy(tracks);
//Does the same thing as generate_random_playlist()
if (player->shuffle) {
@@ -471,10 +470,9 @@ void init_media_player(GtkWidget *parent) {
player->thread = NULL;
player->loop = NULL;
- player->previousButtonPressed = FALSE;
- player->stopButtonPressed = FALSE;
player->shuffle = FALSE;
player->play_element = NULL;
+ player->track_index = 0;
/* Set the volume based on preference */
gint volume_mute = prefs_get_int(MEDIA_PLAYER_VOLUME_MUTE);
@@ -506,6 +504,11 @@ void destroy_media_player() {
player = NULL;
}
+static gboolean on_volume_changed_cb(GtkRange *range, GtkScrollType scroll,
gdouble value, gpointer user_data) {
+ update_volume(value);
+ return FALSE;
+}
+
G_MODULE_EXPORT gboolean on_volume_window_focus_out(GtkWidget *widget,
GdkEventFocus *event, gpointer data) {
GtkWidget *vol_scale = (GtkWidget *) g_object_get_data(G_OBJECT(widget),
"scale");
update_volume(gtk_range_get_value(GTK_RANGE(vol_scale)));
@@ -528,7 +531,7 @@ G_MODULE_EXPORT void
on_volume_button_clicked_cb(GtkToolButton *toolbutton, gpoi
gtk_range_set_value(GTK_RANGE(vol_scale), (player->volume_level * 10));
g_signal_connect(G_OBJECT (vol_scale),
"change-value",
- G_CALLBACK(volume_changed_cb),
+ G_CALLBACK(on_volume_changed_cb),
NULL);
g_signal_connect (G_OBJECT (vol_window),
@@ -551,7 +554,7 @@ G_MODULE_EXPORT void
on_play_button_clicked_cb(GtkToolButton *toolbutton, gpoint
}
G_MODULE_EXPORT void on_stop_button_clicked_cb(GtkToolButton *toolbutton,
gpointer *userdata) {
- stop_song(TRUE);
+ stop_song();
}
G_MODULE_EXPORT void on_next_button_clicked_cb(GtkToolButton *toolbutton,
gpointer *userdata) {
@@ -563,6 +566,18 @@ G_MODULE_EXPORT gboolean
on_song_scale_change_value_cb(GtkRange *range, GtkScrol
return FALSE;
}
+void media_player_play_tracks(GList *tracks) {
+ if (!player)
+ return;
+
+ if (is_playing())
+ stop_song();
+
+ set_selected_tracks(tracks);
+
+ pause_or_play_song();
+}
+
void media_player_track_removed_cb(GtkPodApp *app, gpointer tk, gpointer data)
{
Track *old_track = tk;
if (!player)
diff --git a/plugins/media_player/media_player.h
b/plugins/media_player/media_player.h
index 8d4237c..a0ea940 100644
--- a/plugins/media_player/media_player.h
+++ b/plugins/media_player/media_player.h
@@ -48,11 +48,11 @@ typedef struct {
gchar *glade_path;
GList *tracks;
+ int track_index;
+
GThread *thread;
GMainLoop *loop;
- gboolean previousButtonPressed;
- gboolean stopButtonPressed;
gboolean shuffle;
gdouble volume_level;
@@ -63,6 +63,8 @@ typedef struct {
void init_media_player (GtkWidget *parent);
void destroy_media_player();
+void media_player_play_tracks(GList *tracks);
+
void media_player_track_removed_cb(GtkPodApp *app, gpointer tk, gpointer data);
void media_player_set_tracks_cb(GtkPodApp *app, gpointer tks, gpointer data);
void media_player_track_updated_cb(GtkPodApp *app, gpointer tk, gpointer data);
------------------------------------------------------------------------------
Beautiful is writing same markup. Internet Explorer 9 supports
standards for HTML5, CSS3, SVG 1.1, ECMAScript5, and DOM L2 & L3.
Spend less time writing and rewriting code and more time creating great
experiences on the web. Be a part of the beta today.
http://p.sf.net/sfu/beautyoftheweb
_______________________________________________
gtkpod-cvs2 mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/gtkpod-cvs2