commit e21b061c9d774ea3bc913f686c529dc618f4585f
Author: phantomjinx <p.g.richard...@phantomjinx.co.uk>
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
gtkpod-cvs2@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/gtkpod-cvs2

Reply via email to