[rhythmbox] mtp: add a GStreamer source element for reading from MTP devices



commit 398a30c7acbad05902ae8e75a91dfefbda0f2af6
Author: Jonathan Matthew <jonathan d14n org>
Date:   Tue Jun 2 23:12:42 2009 +1000

    mtp: add a GStreamer source element for reading from MTP devices
    
    This just copies the file to /tmp (using a random filename, thus fixing
    bug #583700) in the NULL->READY transition, and deletes it in the
    READY->NULL transition (fixing bug #576005), and uses a filesrc element
    to handle the rest of the job.
---
 plugins/mtpdevice/Makefile.am      |    1 +
 plugins/mtpdevice/rb-mtp-gst-src.c |  439 ++++++++++++++++++++++++++++++++++++
 plugins/mtpdevice/rb-mtp-plugin.c  |    6 +
 plugins/mtpdevice/rb-mtp-source.c  |  208 +++++++----------
 po/POTFILES.in                     |    1 +
 5 files changed, 529 insertions(+), 126 deletions(-)

diff --git a/plugins/mtpdevice/Makefile.am b/plugins/mtpdevice/Makefile.am
index 6e6e4de..ebdd6d5 100644
--- a/plugins/mtpdevice/Makefile.am
+++ b/plugins/mtpdevice/Makefile.am
@@ -5,6 +5,7 @@ plugin_LTLIBRARIES = libmtpdevice.la
 
 libmtpdevice_la_SOURCES = \
 	rb-mtp-plugin.c	\
+	rb-mtp-gst-src.c \
 	rb-mtp-source.c	\
 	rb-mtp-source.h
 	
diff --git a/plugins/mtpdevice/rb-mtp-gst-src.c b/plugins/mtpdevice/rb-mtp-gst-src.c
new file mode 100644
index 0000000..f7f227d
--- /dev/null
+++ b/plugins/mtpdevice/rb-mtp-gst-src.c
@@ -0,0 +1,439 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ *  Copyright (C) 2009  Jonathan Matthew  <jonathan d14n org>
+ *
+ *  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.
+ *
+ *  The Rhythmbox authors hereby grant permission for non-GPL compatible
+ *  GStreamer plugins to be used and distributed together with GStreamer
+ *  and Rhythmbox. This permission is above and beyond the permissions granted
+ *  by the GPL license by which Rhythmbox is covered. If you modify this code
+ *  you may extend this exception to your version of the code, but you are not
+ *  obligated to do so. If you do not wish to do so, delete this exception
+ *  statement from your 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
+ *
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <glib/gi18n.h>
+#include <libmtp.h>
+#include <gst/gst.h>
+
+#include "rb-debug.h"
+#include "rb-file-helpers.h"
+
+#define RB_TYPE_MTP_SRC (rb_mtp_src_get_type())
+#define RB_MTP_SRC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),RB_TYPE_MTP_SRC,RBMTPSrc))
+#define RB_MTP_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),RB_TYPE_MTP_SRC,RBMTPSrcClass))
+#define RB_IS_MTP_SRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),RB_TYPE_MTP_SRC))
+#define RB_IS_MTP_SRC_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),RB_TYPE_MTP_SRC))
+
+typedef struct _RBMTPSrc RBMTPSrc;
+typedef struct _RBMTPSrcClass RBMTPSrcClass;
+
+struct _RBMTPSrc
+{
+	GstBin parent;
+
+	LIBMTP_mtpdevice_t *device;
+
+	char *track_uri;
+	uint32_t track_id;
+	char *tempfile;
+
+	GstElement *filesrc;
+	GstPad *ghostpad;
+};
+
+struct _RBMTPSrcClass
+{
+	GstBinClass parent_class;
+};
+
+enum
+{
+	PROP_0,
+	PROP_URI,
+	PROP_DEVICE
+};
+
+static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+	GST_PAD_SRC,
+	GST_PAD_ALWAYS,
+	GST_STATIC_CAPS_ANY);
+
+static GstElementDetails rb_mtp_src_details =
+GST_ELEMENT_DETAILS ("RB MTP Source",
+	"Source/File",
+	"Downloads and plays files from MTP devices",
+	"Jonathan Matthew <jonathan d14n org>");
+
+
+static void rb_mtp_src_uri_handler_init (gpointer g_iface, gpointer iface_data);
+
+static void
+_do_init (GType mtp_src_type)
+{
+	static const GInterfaceInfo urihandler_info = {
+		rb_mtp_src_uri_handler_init,
+		NULL,
+		NULL
+	};
+
+	g_type_add_interface_static (mtp_src_type, GST_TYPE_URI_HANDLER,
+			&urihandler_info);
+}
+
+GST_BOILERPLATE_FULL (RBMTPSrc, rb_mtp_src, GstBin, GST_TYPE_BIN, _do_init);
+
+static void
+rb_mtp_src_base_init (gpointer g_class)
+{
+	GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+	gst_element_class_add_pad_template (element_class,
+		gst_static_pad_template_get (&srctemplate));
+	gst_element_class_set_details (element_class, &rb_mtp_src_details);
+}
+
+static void
+rb_mtp_src_init (RBMTPSrc *src, RBMTPSrcClass *klass)
+{
+	GstPad *pad;
+
+	/* create actual source */
+	src->filesrc = gst_element_factory_make ("filesrc", NULL);
+	if (src->filesrc == NULL) {
+		g_warning ("couldn't create filesrc element");
+		return;
+	}
+
+	gst_bin_add (GST_BIN (src), src->filesrc);
+	gst_object_ref (src->filesrc);
+
+	/* create ghost pad */
+	pad = gst_element_get_pad (src->filesrc, "src");
+	src->ghostpad = gst_ghost_pad_new ("src", pad);
+	gst_element_add_pad (GST_ELEMENT (src), src->ghostpad);
+	gst_object_ref (src->ghostpad);
+	gst_object_unref (pad);
+}
+
+static gboolean
+rb_mtp_src_set_uri (RBMTPSrc *src, const char *uri)
+{
+	const char *trackid;
+
+	rb_debug ("stream uri: %s", uri);
+
+	src->track_uri = g_strdup (uri);
+
+	/* extract the track ID */
+	if (g_str_has_prefix (uri, "xrbmtp://") == FALSE) {
+		rb_debug ("unexpected uri scheme");
+		return FALSE;
+	}
+	trackid = uri + strlen ("xrbmtp://");
+	src->track_id = strtoul (trackid, NULL, 0);
+	return TRUE;
+}
+
+static GstStateChangeReturn
+rb_mtp_src_get_file (RBMTPSrc *src)
+{
+	LIBMTP_file_t *fileinfo;
+	GFile *dir;
+	GError *error;
+	char *tempfile;
+	int fd;
+	gboolean check;
+	int mtpret;
+
+	/* get file info */
+	fileinfo = LIBMTP_Get_Filemetadata (src->device, src->track_id);
+	if (fileinfo == NULL) {
+		rb_debug ("unable to get mtp file metadata");
+		LIBMTP_error_t *stack;
+
+		stack = LIBMTP_Get_Errorstack (src->device);
+		GST_ELEMENT_ERROR(src, RESOURCE, READ,
+				  (_("Unable to copy file from MTP device: %s"), stack->error_text),
+				  (NULL));
+		LIBMTP_Clear_Errorstack (src->device);
+	}
+
+	/* check for free space */
+	dir = g_file_new_for_path (g_get_tmp_dir ());
+	rb_debug ("checking we've got %" G_GUINT64_FORMAT " bytes available in %s",
+		  fileinfo->filesize,
+		  g_get_tmp_dir ());
+	check = rb_check_dir_has_space (dir, fileinfo->filesize);
+	LIBMTP_destroy_file_t (fileinfo);
+	g_object_unref (dir);
+	if (check == FALSE) {
+		rb_debug ("not enough space to copy track from MTP device");
+		GST_ELEMENT_ERROR(src, RESOURCE, NO_SPACE_LEFT,
+				  (_("Not enough space in %s"), g_get_tmp_dir ()),
+				  (NULL));
+		g_object_unref (dir);
+		LIBMTP_destroy_file_t (fileinfo);
+		return GST_STATE_CHANGE_FAILURE;
+	}
+
+	/* open temporary file */
+	fd = g_file_open_tmp ("rb-mtp-temp-XXXXXX", &tempfile, &error);
+	if (fd == -1) {
+		rb_debug ("failed to open temporary file");
+		GST_ELEMENT_ERROR(src, RESOURCE, OPEN_READ_WRITE,
+				  (_("Unable to open temporary file: %s"), error->message), (NULL));
+		g_error_free (error);
+		return GST_STATE_CHANGE_FAILURE;
+	}
+	rb_debug ("created temporary file %s", tempfile);
+
+	/* copy file from MTP device */
+	mtpret = LIBMTP_Get_Track_To_File_Descriptor (src->device, src->track_id, fd, NULL, NULL);
+	if (mtpret != 0) {
+		rb_debug ("failed to copy file from MTP device");
+		LIBMTP_error_t *stack;
+
+		stack = LIBMTP_Get_Errorstack (src->device);
+		GST_ELEMENT_ERROR(src, RESOURCE, READ,
+				  (_("Unable to copy file from MTP device: %s"), stack->error_text),
+				  (NULL));
+		LIBMTP_Clear_Errorstack (src->device);
+
+		close (fd);
+		remove (tempfile);
+		g_free (tempfile);
+		return GST_STATE_CHANGE_FAILURE;
+	}
+
+	rb_debug ("copied file from mtp device");
+
+	close (fd);
+	src->tempfile = tempfile;
+
+	/* point the filesrc at the file */
+	g_object_set (src->filesrc, "location", src->tempfile, NULL);
+	return GST_STATE_CHANGE_SUCCESS;
+}
+
+static GstStateChangeReturn
+rb_mtp_src_close_tempfile (RBMTPSrc *src)
+{
+	if (src->tempfile != NULL) {
+		rb_debug ("deleting tempfile %s", src->tempfile);
+		remove (src->tempfile);
+		g_free (src->tempfile);
+		src->tempfile = NULL;
+	}
+
+	return GST_STATE_CHANGE_SUCCESS;
+}
+
+static GstStateChangeReturn
+rb_mtp_src_change_state (GstElement *element, GstStateChange transition)
+{
+	GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+	RBMTPSrc *src = RB_MTP_SRC (element);
+
+	switch (transition) {
+		case GST_STATE_CHANGE_NULL_TO_READY:
+			ret = rb_mtp_src_get_file (src);
+			if (ret != GST_STATE_CHANGE_SUCCESS)
+				return ret;
+			break;
+
+		case GST_STATE_CHANGE_READY_TO_PAUSED:
+			break;
+
+		case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+			break;
+
+		default:
+			break;
+	}
+
+	ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+	switch (transition) {
+		case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+			break;
+		case GST_STATE_CHANGE_PAUSED_TO_READY:
+			break;
+		case GST_STATE_CHANGE_READY_TO_NULL:
+			ret = rb_mtp_src_close_tempfile (src);
+			break;
+		default:
+			break;
+	}
+
+	return ret;
+}
+
+static void
+rb_mtp_src_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+	RBMTPSrc *src = RB_MTP_SRC (object);
+
+	switch (prop_id) {
+	case PROP_URI:
+		rb_mtp_src_set_uri (src, g_value_get_string (value));
+		break;
+	case PROP_DEVICE:
+		src->device = g_value_get_pointer (value);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+rb_mtp_src_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+	RBMTPSrc *src = RB_MTP_SRC (object);
+
+	switch (prop_id) {
+	case PROP_URI:
+		g_value_set_string (value, src->track_uri);
+		break;
+	case PROP_DEVICE:
+		g_value_set_pointer (value, src->device);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+rb_mtp_src_dispose (GObject *object)
+{
+	RBMTPSrc *src;
+	src = RB_MTP_SRC (object);
+
+	if (src->ghostpad) {
+		gst_object_unref (src->ghostpad);
+		src->ghostpad = NULL;
+	}
+
+	if (src->filesrc) {
+		gst_object_unref (src->filesrc);
+		src->filesrc = NULL;
+	}
+
+	G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+rb_mtp_src_class_init (RBMTPSrcClass *klass)
+{
+	GObjectClass *gobject_class;
+	GstElementClass *element_class;
+
+	gobject_class = G_OBJECT_CLASS (klass);
+	gobject_class->dispose = rb_mtp_src_dispose;
+	gobject_class->set_property = rb_mtp_src_set_property;
+	gobject_class->get_property = rb_mtp_src_get_property;
+
+	element_class = GST_ELEMENT_CLASS (klass);
+	element_class->change_state = rb_mtp_src_change_state;
+
+	g_object_class_install_property (gobject_class,
+					 PROP_URI,
+					 g_param_spec_string ("uri",
+							      "uri",
+							      "MTP track uri",
+							      NULL,
+							      G_PARAM_READWRITE));
+	g_object_class_install_property (gobject_class,
+					 PROP_DEVICE,
+					 g_param_spec_pointer ("device",
+							       "device",
+							       "libmtp device",
+							       G_PARAM_READWRITE));
+}
+
+
+/* URI handler interface */
+
+static guint
+rb_mtp_src_uri_get_type (void)
+{
+	return GST_URI_SRC;
+}
+
+static gchar **
+rb_mtp_src_uri_get_protocols (void)
+{
+	static gchar *protocols[] = {"xrbmtp", NULL};
+	return protocols;
+}
+
+static const gchar *
+rb_mtp_src_uri_get_uri (GstURIHandler *handler)
+{
+	RBMTPSrc *src = RB_MTP_SRC (handler);
+
+	return src->track_uri;
+}
+
+static gboolean
+rb_mtp_src_uri_set_uri (GstURIHandler *handler, const gchar *uri)
+{
+	RBMTPSrc *src = RB_MTP_SRC (handler);
+
+	if (GST_STATE (src) == GST_STATE_PLAYING || GST_STATE (src) == GST_STATE_PAUSED) {
+		return FALSE;
+	}
+
+	if (g_str_has_prefix (uri, "xrbmtp://") == FALSE) {
+		return FALSE;
+	}
+
+	return rb_mtp_src_set_uri (src, uri);
+}
+
+static void
+rb_mtp_src_uri_handler_init (gpointer g_iface, gpointer iface_data)
+{
+	GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
+
+	iface->get_type = rb_mtp_src_uri_get_type;
+	iface->get_protocols = rb_mtp_src_uri_get_protocols;
+	iface->get_uri = rb_mtp_src_uri_get_uri;
+	iface->set_uri = rb_mtp_src_uri_set_uri;
+}
+
+static gboolean
+plugin_init (GstPlugin *plugin)
+{
+	gboolean ret = gst_element_register (plugin, "rbmtpsrc", GST_RANK_PRIMARY, RB_TYPE_MTP_SRC);
+	return ret;
+}
+
+GST_PLUGIN_DEFINE_STATIC (GST_VERSION_MAJOR,
+			  GST_VERSION_MINOR,
+			  "rbmtpsrc",
+			  "element to download and play files from MTP devices",
+			  plugin_init,
+			  VERSION,
+			  "GPL",
+			  PACKAGE,
+			  "");
diff --git a/plugins/mtpdevice/rb-mtp-plugin.c b/plugins/mtpdevice/rb-mtp-plugin.c
index c80aeb7..8aa40f4 100644
--- a/plugins/mtpdevice/rb-mtp-plugin.c
+++ b/plugins/mtpdevice/rb-mtp-plugin.c
@@ -60,6 +60,7 @@
 #define RB_IS_MTP_PLUGIN_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), RB_TYPE_MTP_PLUGIN))
 #define RB_MTP_PLUGIN_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), RB_TYPE_MTP_PLUGIN, RBMtpPluginClass))
 
+
 typedef struct
 {
 	RBPlugin parent;
@@ -96,6 +97,8 @@ static RBSource* create_source_cb (RBMtpPlugin *plugin, LIBMTP_mtpdevice_t *devi
 static void rb_mtp_plugin_eject  (GtkAction *action, RBMtpPlugin *plugin);
 static void rb_mtp_plugin_rename (GtkAction *action, RBMtpPlugin *plugin);
 
+GType rb_mtp_src_get_type (void);
+
 RB_PLUGIN_REGISTER(RBMtpPlugin, rb_mtp_plugin)
 
 static GtkActionEntry rb_mtp_plugin_actions [] =
@@ -121,6 +124,9 @@ rb_mtp_plugin_class_init (RBMtpPluginClass *klass)
 
 	/* register types used by the plugin */
 	RB_PLUGIN_REGISTER_TYPE (rb_mtp_source);
+
+	/* ensure the gstreamer src element gets linked in */
+	rb_mtp_src_get_type ();
 }
 
 static void
diff --git a/plugins/mtpdevice/rb-mtp-source.c b/plugins/mtpdevice/rb-mtp-source.c
index 27c4a46..33e24f6 100644
--- a/plugins/mtpdevice/rb-mtp-source.c
+++ b/plugins/mtpdevice/rb-mtp-source.c
@@ -32,6 +32,7 @@
 #include <string.h>
 #include <gtk/gtk.h>
 #include <glib/gi18n.h>
+#include <gst/gst.h>
 
 #include "rhythmdb.h"
 #include "eel-gconf-extensions.h"
@@ -43,8 +44,10 @@
 #include "rb-util.h"
 #include "rb-refstring.h"
 #include "rhythmdb.h"
-#include "rb-encoder.h"
 #include "rb-dialog.h"
+#include "rb-shell-player.h"
+#include "rb-player.h"
+#include "rb-encoder.h"
 
 #include "rb-mtp-source.h"
 
@@ -103,16 +106,10 @@ static char *impl_get_browser_key (RBSource *source);
 static char *impl_get_paned_key (RBBrowserSource *source);
 
 static void rb_mtp_source_load_tracks (RBMtpSource*);
-static gboolean rb_mtp_source_transfer_track_to_disk (LIBMTP_mtpdevice_t *device,
-						      LIBMTP_track_t *track,
-						      const char *uri);
-static char* rb_mtp_source_get_playback_uri (RhythmDBEntry *entry,
-					     gpointer data);
 
 static void impl_delete (RBSource *asource);
 static gboolean impl_show_popup (RBSource *source);
 static GList* impl_get_ui_actions (RBSource *source);
-static GList* impl_copy (RBSource *source);
 
 static GList * impl_get_mime_types (RBRemovableMediaSource *source);
 static gboolean impl_track_added (RBRemovableMediaSource *source,
@@ -134,6 +131,15 @@ static void artwork_notify_cb (RhythmDB *db,
 
 static void add_track_to_album (RBMtpSource *source, const char *album_name, LIBMTP_track_t *track);
 
+static void prepare_player_source_cb (RBPlayer *player,
+				      const char *stream_uri,
+				      GstElement *src,
+				      RBMtpSource *source);
+static void prepare_encoder_source_cb (RBEncoderFactory *factory,
+				       const char *stream_uri,
+				       GObject *src,
+				       RBMtpSource *source);
+
 typedef struct
 {
 	LIBMTP_mtpdevice_t *device;
@@ -207,7 +213,6 @@ rb_mtp_source_class_init (RBMtpSourceClass *klass)
 	source_class->impl_show_popup = impl_show_popup;
 	source_class->impl_get_ui_actions = impl_get_ui_actions;
 	source_class->impl_delete = impl_delete;
-	source_class->impl_copy = impl_copy;
 
 	browser_source_class->impl_get_paned_key = impl_get_paned_key;
 
@@ -271,6 +276,9 @@ rb_mtp_source_constructor (GType type, guint n_construct_properties,
 	RBMtpSource *source;
 	RBMtpSourcePrivate *priv;
 	RBEntryView *tracks;
+	RBShell *shell;
+	RBShellPlayer *shell_player;
+	GObject *player_backend;
 	GtkIconTheme *theme;
 	GdkPixbuf *pixbuf;
 	gint size;
@@ -280,10 +288,30 @@ rb_mtp_source_constructor (GType type, guint n_construct_properties,
 	source = RB_MTP_SOURCE (G_OBJECT_CLASS (rb_mtp_source_parent_class)->
 				constructor (type, n_construct_properties, construct_properties));
 
+	priv = MTP_SOURCE_GET_PRIVATE (source);
+
 	tracks = rb_source_get_entry_view (RB_SOURCE (source));
 	rb_entry_view_append_column (tracks, RB_ENTRY_VIEW_COL_RATING, FALSE);
 	rb_entry_view_append_column (tracks, RB_ENTRY_VIEW_COL_LAST_PLAYED, FALSE);
 
+	/* the source element needs our cooperation */
+	g_object_get (source, "shell", &shell, NULL);
+	shell_player = RB_SHELL_PLAYER (rb_shell_get_player (shell));
+	g_object_get (shell_player, "player", &player_backend, NULL);
+
+	g_signal_connect_object (player_backend,
+				 "prepare-source",
+				 G_CALLBACK (prepare_player_source_cb),
+				 source, 0);
+
+	g_object_unref (player_backend);
+	g_object_unref (shell);
+
+	g_signal_connect_object (rb_encoder_factory_get (),
+				 "prepare-source",
+				 G_CALLBACK (prepare_encoder_source_cb),
+				 source, 0);
+
 	/* icon */
 	theme = gtk_icon_theme_get_default ();
 	gtk_icon_size_lookup (GTK_ICON_SIZE_LARGE_TOOLBAR, &size, NULL);
@@ -296,7 +324,6 @@ rb_mtp_source_constructor (GType type, guint n_construct_properties,
 			  (GCallback)rb_mtp_source_name_changed_cb, NULL);
 	
 	/* figure out supported file types */
-	priv = MTP_SOURCE_GET_PRIVATE (source);
 	if (LIBMTP_Get_Supported_Filetypes(priv->device, &types, &num_types) == 0) {
 		int i;
 		gboolean has_mp3 = FALSE;
@@ -494,7 +521,6 @@ rb_mtp_source_new (RBShell *shell,
 	entry_type = rhythmdb_entry_register_type (db, name);
 	entry_type->save_to_disk = FALSE;
 	entry_type->category = RHYTHMDB_ENTRY_NORMAL;
-	entry_type->get_playback_uri = (RhythmDBEntryStringFunc)rb_mtp_source_get_playback_uri;
 
 	g_free (name);
 	g_object_unref (db);
@@ -509,8 +535,6 @@ rb_mtp_source_new (RBShell *shell,
 					      "udi", udi,
 					      NULL));
 
-	entry_type->get_playback_uri_data = source;
-
 	rb_shell_register_entry_type_for_source (shell, RB_SOURCE (source), entry_type);
 
 	return RB_BROWSER_SOURCE (source);
@@ -553,7 +577,7 @@ add_mtp_track_to_db (RBMtpSource *source,
 
 	/* Set URI */
 	g_object_get (G_OBJECT (source), "entry-type", &entry_type, NULL);
-	name = g_strdup_printf ("x-rb-mtp://%i/%s", track->item_id, track->filename);
+	name = g_strdup_printf ("xrbmtp://%i/%s", track->item_id, track->filename);
 	entry = rhythmdb_entry_new (RHYTHMDB (db), entry_type, name);
 	g_free (name);
         g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
@@ -927,119 +951,6 @@ impl_get_ui_actions (RBSource *source)
 	return actions;
 }
 
-static gboolean
-rb_mtp_source_transfer_track_to_disk (LIBMTP_mtpdevice_t *device,
-				      LIBMTP_track_t *track,
-				      const char *uri)
-{
-	int ret = -1;
-	char *path;
-
-	if (device == NULL || track == NULL || strlen (uri) == 0) {
-		rb_debug ("device (%p), track (%p), or URI (%s) not supplied", device, track, uri);
-		return FALSE;
-	}
-
-	if (rb_check_dir_has_space_uri (uri, track->filesize) == FALSE) {
-		rb_debug ("not enough space to transfer track %d to %s", track->item_id, uri);
-		return FALSE;
-	}
-
-	path = g_filename_from_uri (uri, NULL, NULL);
-	if (path != NULL) {
-		ret = LIBMTP_Get_Track_To_File (device, track->item_id, path, NULL, NULL);
-		rb_debug ("LIBMTP_Get_Track_To_File(%d, %s) returned %d", track->item_id, path, ret);
-		if (ret != 0) {
-			report_libmtp_errors (device, TRUE);
-		}
-		g_free (path);
-	} else {
-		g_warning ("couldn't get path from URI %s", uri);
-	}
-
-	return (ret == 0);
-}
-
-static char *
-rb_mtp_source_get_playback_uri (RhythmDBEntry *entry, gpointer data)
-{
-	RBMtpSourcePrivate *priv;
-	LIBMTP_track_t *track;
-	char *path;
-	char *uri = NULL;
-	GError *error = NULL;
-
-	priv = MTP_SOURCE_GET_PRIVATE (data);
-
-	track = g_hash_table_lookup (priv->entry_map, entry);
-	path = g_strdup_printf ("%s/%s-%s",
-				g_get_tmp_dir (),
-				rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP_ARTIST),
-				rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP_TITLE));
-	uri = g_filename_to_uri (path, NULL, &error);
-	g_free (path);
-	if (error != NULL) {
-		g_warning ("unable to convert path %s to filename: %s", path, error->message);
-		g_error_free (error);
-		g_free (path);
-		return NULL;
-	}
-
-	if (rb_mtp_source_transfer_track_to_disk (priv->device, track, uri) == TRUE) {
-		rb_debug ("playback URI for %s: %s",
-			  rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION),
-			  uri);
-		return uri;
-	} else {
-		g_free (uri);
-		return NULL;
-	}
-}
-
-static GList *
-impl_copy (RBSource *source)
-{
-	RBMtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (RB_MTP_SOURCE (source));
-	RhythmDB *db;
-	GList *selected_entries;
-	GList *iter;
-	GList *copy_entries;
-	int ret = -1;
-	LIBMTP_track_t *track = NULL;
-
-	db = get_db_for_source (RB_MTP_SOURCE (source));
-
-	copy_entries = NULL;
-	selected_entries = rb_entry_view_get_selected_entries (rb_source_get_entry_view (source));
-	for (iter = selected_entries; iter != NULL; iter = g_list_next (iter)) {
-		RhythmDBEntry *entry;
-		char *path;
-		char *uri;
-
-		entry = (RhythmDBEntry *)iter->data;
-		track = g_hash_table_lookup (priv->entry_map, entry);
-
-		if (track == NULL)
-			continue;
-
-		path = g_strdup_printf ("%s/%s", g_get_tmp_dir (), track->filename);
-		uri = g_filename_to_uri (path, NULL, NULL);
-		g_free (path);
-		ret = rb_mtp_source_transfer_track_to_disk (priv->device, track, uri);
-
-		if (ret == 0) {
-			entry_set_string_prop (RHYTHMDB (db), entry, RHYTHMDB_PROP_LOCATION, uri);
-			copy_entries = g_list_prepend (copy_entries, entry);
-		}
-		g_free (uri);
-	}
-
-	g_list_free (selected_entries);
-	g_object_unref (G_OBJECT (db));
-
-	return copy_entries;
-}
-
 static RhythmDB *
 get_db_for_source (RBMtpSource *source)
 {
@@ -1241,3 +1152,48 @@ artwork_notify_cb (RhythmDB *db,
 	g_free (image_data);
 }
 
+static void
+prepare_source (RBMtpSource *source, const char *stream_uri, GObject *src)
+{
+	RBMtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (source);
+	RhythmDBEntry *entry;
+	RhythmDB *db;
+
+	/* make sure this stream is for a file on our device */
+	if (g_str_has_prefix (stream_uri, "xrbmtp://") == FALSE)
+		return;
+
+	db = get_db_for_source (source);
+	entry = rhythmdb_entry_lookup_by_location (db, stream_uri);
+	g_object_unref (db);
+	if (entry == NULL)
+		return;
+
+	if (_rb_source_check_entry_type (RB_SOURCE (source), entry) == FALSE) {
+		rhythmdb_entry_unref (entry);
+		return;
+	}
+
+	rb_debug ("setting device %p for stream %s", priv->device, stream_uri);
+	g_object_set (src, "device", priv->device, NULL);
+	rhythmdb_entry_unref (entry);
+}
+
+static void
+prepare_player_source_cb (RBPlayer *player,
+			  const char *stream_uri,
+			  GstElement *src,
+			  RBMtpSource *source)
+{
+	prepare_source (source, stream_uri, G_OBJECT (src));
+}
+
+static void
+prepare_encoder_source_cb (RBEncoderFactory *factory,
+			   const char *stream_uri,
+			   GObject *src,
+			   RBMtpSource *source)
+{
+	prepare_source (source, stream_uri, src);
+}
+
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 17fa661..810e933 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -108,6 +108,7 @@ plugins/magnatune/magnatune/MagnatuneSource.py
 plugins/magnatune/magnatune/__init__.py
 [type: gettext/ini]plugins/mmkeys/mmkeys.rb-plugin.in
 [type: gettext/ini]plugins/mtpdevice/mtpdevice.rb-plugin.in
+plugins/mtpdevice/rb-mtp-gst-src.c
 plugins/mtpdevice/rb-mtp-plugin.c
 plugins/mtpdevice/rb-mtp-source.c
 [type: gettext/ini]plugins/power-manager/power-manager.rb-plugin.in



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]