Initial commit
[jamendo] / src / player.c
diff --git a/src/player.c b/src/player.c
new file mode 100644 (file)
index 0000000..9923802
--- /dev/null
@@ -0,0 +1,313 @@
+/*
+ * player.c
+ *
+ *  Created on: 2009-10-22
+ *      Author: marcin
+ */
+
+#include "player.h"
+#include <gst/gst.h>
+#include <hildon/hildon.h>
+#include "resource_utils.h"
+
+/****************************************************************************
+ * Simple playing functions
+ */
+/** TODO: Get rid of global variable pipeline */
+static GstElement *pipeline = NULL;
+static GList* tracklist = 0;
+static GList* tracklist_item = 0;
+
+GtkWidget* toolbar;
+GtkWidget* playing_label;
+guint playing_label_timer = 0;
+GtkToolButton* play_pause_button;
+gboolean error=FALSE;
+
+enum {
+       STOPPED,
+       PAUSED,
+       PLAYING
+} state;
+
+enum {
+       CMD_PREV,
+       CMD_PLAY,
+       CMD_PAUSE,
+       CMD_STOP,
+       CMD_NEXT
+};
+
+static struct {
+       const gchar* image;
+       const gchar* label;
+       const int cmd;
+       GtkWidget* icon;
+} toolbar_data[] = {
+               { "player_prev_light.png", "prev", CMD_PREV, NULL },
+               { "player_play_light.png", "play", CMD_PLAY, NULL },
+               { "player_pause_light.png", "pause", CMD_PAUSE, NULL },
+               { "player_stop_light.png", "stop", CMD_STOP, NULL },
+               { "player_next_light.png", "next", CMD_NEXT, NULL }
+};
+
+void pause_track();
+void stop_track();
+void prev_track();
+void next_track();
+void update_toolbar();
+
+static void handle_eos(GstBus * bus, GstMessage * message, gpointer * appdata) {
+       if(!error) {
+               next_track();
+       }
+}
+
+static void handle_error(GstBus * bus, GstMessage * msg, gpointer * appdata) {
+       gchar  *dbg;
+    GError *err;
+
+    error = TRUE;
+
+    gst_message_parse_error (msg, &err, &dbg);
+    g_debug("player: ERROR: %s\nDEBUG: %s",err->message,dbg);
+
+       hildon_banner_show_informationf(NULL,NULL,"Error: %s",err->message);
+}
+
+static void handle_buffering(GstBus * bus, GstMessage * msg, gpointer * appdata) {
+       gint percent;
+
+    gst_message_parse_buffering (msg, &percent);
+
+    if(percent!=100) {
+               gchar* text = g_strdup_printf("Buffering %d%%", percent);
+               gtk_label_set_text(GTK_LABEL(playing_label),text);
+               g_free(text);
+    }
+}
+
+static void handle_any(GstBus * bus, GstMessage * msg, gchar *name) {
+       g_debug("handle_%s",name);
+       if(g_strcmp0(name,"duration")==0) {
+               GstFormat format;
+               gint64 duration;
+               gst_message_parse_duration(msg, &format, &duration);
+               g_debug("duration %d: %Ld",format,duration);
+       }
+}
+
+static gboolean handle_timer(gpointer* ptr) {
+       if (pipeline) {
+               GstQuery* query = gst_query_new_position(GST_FORMAT_TIME);
+               gboolean res = gst_element_query(pipeline, query);
+               if (res) {
+                       GstFormat format;
+                       gint64 cur;
+                       gst_query_parse_position(query, &format, &cur);
+                       int sec = cur / GST_SECOND;
+                       gchar *text = g_strdup_printf("%u:%02u:%02u", sec / 60 / 60, (sec / 60) % 60, sec % 60);
+                       gtk_label_set_text(GTK_LABEL(playing_label), text);
+                       g_free(text);
+               }
+               gst_query_unref(query);
+       }
+       return TRUE;
+}
+
+void play_track(Track* track) {
+       if (pipeline) {
+               gst_element_set_state(pipeline, GST_STATE_NULL);
+               g_object_unref(GST_OBJECT(pipeline));
+               pipeline = NULL;
+       }
+
+       hildon_banner_show_informationf(NULL,NULL,"Playing %s by %s",track->name,track->artist_name);
+
+       if (0) {
+               GstElement *src, *decoder, *sink;
+               pipeline = gst_pipeline_new(NULL);
+               src = gst_element_factory_make("souphttpsrc", NULL);
+               g_object_set(G_OBJECT(src), "location", track->stream, NULL);
+               decoder = gst_element_factory_make("decodebin", NULL);
+               sink = gst_element_factory_make("alsasink", NULL);
+               gst_bin_add_many(GST_BIN(pipeline), src, decoder, sink, NULL);
+               gst_element_link_many(src, decoder, sink, NULL);
+       } else {
+               pipeline = gst_element_factory_make("playbin2", NULL);
+               g_object_set(G_OBJECT(pipeline), "uri", track->stream, NULL);
+       }
+
+       error = FALSE;
+       /* setup message handling */
+       GstBus* bus = gst_pipeline_get_bus(GST_PIPELINE (pipeline));
+       gst_bus_add_signal_watch_full(bus, G_PRIORITY_HIGH);
+       g_signal_connect(bus, "message::error", (GCallback) handle_error, NULL);
+       g_signal_connect(bus, "message::eos", (GCallback) handle_eos, NULL);
+       g_signal_connect(bus, "message::buffering", (GCallback) handle_buffering, NULL);
+       g_signal_connect(bus, "message::duration", (GCallback) handle_any, "duration");
+       gst_object_unref(GST_OBJECT(bus));
+
+       if(!playing_label_timer) {
+               playing_label_timer = gdk_threads_add_timeout_seconds(1, (GSourceFunc)handle_timer, NULL);
+       }
+
+       g_debug("Playing %s",track->stream);
+       gst_element_set_state(pipeline, GST_STATE_PLAYING);
+
+       state = PLAYING;
+       update_toolbar();
+
+       if (tracklist_item->data != track) {
+               tracklist_item = g_list_first(tracklist);
+               while (tracklist_item && tracklist_item->data != track) {
+                       tracklist_item = g_list_next(tracklist_item);
+               }
+       }
+}
+
+void pause_track() {
+       hildon_banner_show_information(NULL,NULL,"Paused");
+
+       gst_element_set_state(pipeline,GST_STATE_PAUSED);
+
+       state = PAUSED;
+       update_toolbar();
+}
+
+
+void resume_track() {
+       gst_element_set_state(pipeline, GST_STATE_PLAYING);
+
+       state = PLAYING;
+       update_toolbar();
+}
+
+void stop_track() {
+       if (pipeline) {
+               hildon_banner_show_information(NULL,NULL,"Stopped");
+
+               gst_element_set_state(pipeline, GST_STATE_NULL);
+               g_object_unref(GST_OBJECT(pipeline));
+               pipeline = NULL;
+       }
+
+       state = STOPPED;
+       update_toolbar();
+}
+
+void next_track() {
+       if (!tracklist_item) return;
+
+       tracklist_item = g_list_next(tracklist_item);
+       if (!tracklist_item) {
+               tracklist_item = g_list_first(tracklist);
+       }
+       play_track(tracklist_item->data);
+}
+
+void prev_track() {
+       if (!tracklist_item) return;
+
+       tracklist_item = g_list_previous(tracklist_item);
+       if (!tracklist_item) {
+               tracklist_item = g_list_last(tracklist);
+       }
+       play_track(tracklist_item->data);
+}
+
+
+void on_clicked(GtkToolButton *toolbutton, gint cmd) {
+       switch (cmd) {
+       case CMD_PREV:
+               prev_track();
+               break;
+       case CMD_PLAY:
+               switch(state) {
+               case STOPPED:
+                       if (tracklist_item) {
+                               play_track(tracklist_item->data);
+                       }
+                       break;
+               case PAUSED:
+                       resume_track();
+                       break;
+               case PLAYING:
+                       pause_track();
+                       break;
+               }
+               break;
+       case CMD_STOP:
+               stop_track();
+               break;
+       case CMD_NEXT:
+               next_track();
+               break;
+       }
+}
+
+void update_toolbar() {
+       if (state == PLAYING) {
+               gtk_tool_button_set_icon_widget(play_pause_button, toolbar_data[CMD_PAUSE].icon);
+               gtk_tool_button_set_label(play_pause_button, toolbar_data[CMD_PAUSE].label);
+               gtk_widget_show_all(GTK_WIDGET(play_pause_button));
+       }
+       else if (state == PAUSED) {
+               gtk_tool_button_set_icon_widget(play_pause_button, toolbar_data[CMD_PLAY].icon);
+               gtk_tool_button_set_label(play_pause_button, toolbar_data[CMD_PLAY].label);
+               gtk_widget_show_all(GTK_WIDGET(play_pause_button));
+       }
+}
+
+GtkWidget* player_toolbar_create() {
+       if (!toolbar) {
+               GtkToolItem *toolitem;
+               int i,pos=0;
+
+               /* Create a toolbar */
+               toolbar = gtk_toolbar_new();
+
+               /* Add items to the toolbar */
+               for (i = 0; i < G_N_ELEMENTS(toolbar_data); i++) {
+                       toolbar_data[i].icon = resource_get_image(toolbar_data[i].image);
+                       g_object_ref(toolbar_data[i].icon);
+
+                       if (i != CMD_PAUSE) {
+                               toolitem = gtk_tool_button_new(toolbar_data[i].icon, toolbar_data[i].label);
+                               g_signal_connect (G_OBJECT (toolitem), "clicked", G_CALLBACK (on_clicked), (gpointer) toolbar_data[i].cmd);
+                               gtk_widget_show_all(GTK_WIDGET(toolitem));
+                               gtk_toolbar_insert(GTK_TOOLBAR (toolbar), toolitem, pos++);
+                       }
+                       if (i == CMD_PLAY) {
+                               play_pause_button = GTK_TOOL_BUTTON(toolitem);
+                       }
+               }
+
+               toolitem = gtk_separator_tool_item_new();
+               gtk_tool_item_set_expand(toolitem,TRUE);
+               gtk_separator_tool_item_set_draw(GTK_SEPARATOR_TOOL_ITEM(toolitem), FALSE);
+               gtk_toolbar_insert(GTK_TOOLBAR(toolbar),toolitem,pos++);
+
+               playing_label= gtk_label_new("");
+               toolitem = gtk_tool_button_new(NULL, NULL);
+               gtk_widget_set_usize((GtkWidget*)playing_label, 200, -1);
+               gtk_tool_button_set_label_widget(GTK_TOOL_BUTTON(toolitem), playing_label);
+               gtk_toolbar_insert(GTK_TOOLBAR(toolbar),toolitem,pos++);
+
+               gtk_widget_show_all(GTK_WIDGET(toolbar));
+       }
+       update_toolbar();
+       return toolbar;
+}
+
+void player_set_track_list(GList* track_list) {
+       g_debug("player_set_track_list length:%d",g_list_length(track_list));
+
+       if (tracklist) {
+               track_list_free(tracklist);
+               tracklist = NULL;
+       }
+
+       tracklist = track_list;
+       tracklist_item = g_list_first(tracklist);
+}