[rhythmbox] mtp: add a GStreamer source element for reading from MTP devices
- From: Jonathan Matthew <jmatthew src gnome org>
- To: svn-commits-list gnome org
- Subject: [rhythmbox] mtp: add a GStreamer source element for reading from MTP devices
- Date: Tue, 2 Jun 2009 09:20:57 -0400 (EDT)
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]