From 15cdac0c7d9fd0667100c7eedd1a98bd40c6298b Mon Sep 17 00:00:00 2001 From: "Zeeshan Ali (Khattak)" Date: Thu, 7 May 2009 00:40:42 +0300 Subject: [PATCH] First implementation of External plugin This is the implementation of external MediaServer spec Lennart wrote: http://live.gnome.org/Rygel/MediaServerSpec. It builds but it's totally untested and also currently specific to the PulseAudio implementation. --- configure.ac | 7 + src/plugins/Makefile.am | 11 +- src/plugins/external/rygel-external-container.vala | 164 +++++++++++++++++++++ .../external/rygel-external-content-dir.vala | 47 ++++++ src/plugins/external/rygel-external-item.vala | 79 ++++++++++ src/plugins/external/rygel-external-plugin.vala | 43 ++++++ 6 files changed, 350 insertions(+), 1 deletion(-) create mode 100644 src/plugins/external/rygel-external-container.vala create mode 100644 src/plugins/external/rygel-external-content-dir.vala create mode 100644 src/plugins/external/rygel-external-item.vala create mode 100644 src/plugins/external/rygel-external-plugin.vala diff --git a/configure.ac b/configure.ac index 270dcc4..2daf888 100644 --- a/configure.ac +++ b/configure.ac @@ -171,6 +171,11 @@ AC_ARG_ENABLE(folder-plugin, [ --enable-folder-plugin build Folder plugin],, enable_folder_plugin=yes) +# Build External plugin +AC_ARG_ENABLE(external-plugin, + [ --enable-external-plugin build External plugin],, + enable_external_plugin=yes) + # Build Mediathek plugin AC_ARG_ENABLE(mediathek-plugin, [ --enable-mediathek-plugin build Mediathek plugin],, @@ -186,6 +191,7 @@ AM_CONDITIONAL([BUILD_TRACKER_PLUGIN], AM_CONDITIONAL([BUILD_DVB_PLUGIN], [test "x$enable_dvb_plugin" = "xyes"]) AM_CONDITIONAL([BUILD_MEDIATHEK_PLUGIN], [test "x$enable_mediathek_plugin" = "xyes"]) AM_CONDITIONAL([BUILD_FOLDER_PLUGIN], [test "x$enable_folder_plugin" = "xyes"]) +AM_CONDITIONAL([BUILD_EXTERNAL_PLUGIN], [test "x$enable_external_plugin" = "xyes"]) # Gettext GETTEXT_PACKAGE=rygel @@ -205,6 +211,7 @@ src/ui/Makefile src/plugins/Makefile src/plugins/dvb/Makefile src/plugins/folder/Makefile +src/plugins/external/Makefile src/plugins/mediathek/Makefile src/plugins/tracker/Makefile src/plugins/test/Makefile diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am index 3a5515a..91b3c81 100644 --- a/src/plugins/Makefile.am +++ b/src/plugins/Makefile.am @@ -18,6 +18,15 @@ if BUILD_FOLDER_PLUGIN FOLDER_PLUGIN = folder endif -SUBDIRS = $(TEST_PLUGIN) $(TRACKER_PLUGIN) $(DVB_PLUGIN) $(MEDIATHEK_PLUGIN) $(FOLDER_PLUGIN) +if BUILD_EXTERNAL_PLUGIN +EXTERNAL_PLUGIN = external +endif + +SUBDIRS = $(TEST_PLUGIN) \ + $(TRACKER_PLUGIN) \ + $(DVB_PLUGIN) \ + $(MEDIATHEK_PLUGIN) \ + $(FOLDER_PLUGIN) \ + $(EXTERNAL_PLUGIN) MAINTAINERCLEANFILES = Makefile.in diff --git a/src/plugins/external/rygel-external-container.vala b/src/plugins/external/rygel-external-container.vala new file mode 100644 index 0000000..97340fc --- /dev/null +++ b/src/plugins/external/rygel-external-container.vala @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2009 Zeeshan Ali (Khattak) . + * Copyright (C) 2009 Nokia Corporation, all rights reserved. + * + * Author: Zeeshan Ali (Khattak) + * + * + * This file is part of Rygel. + * + * Rygel is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Rygel 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +using Rygel; +using GUPnP; +using DBus; +using Gee; + +/** + * Represents and external container. + */ +public class Rygel.ExternalContainer : MediaContainer { + // class-wide constants + private static string PROPS_IFACE = "org.freedesktop.DBus.Properties"; + private const string OBJECT_IFACE = "org.Rygel.MediaObject1"; + private const string CONTAINER_IFACE = "org.Rygel.MediaContainer1"; + private const string ITEM_IFACE = "org.Rygel.MediaItem1"; + + public dynamic DBus.Object actual_container; + + private string service_path; + private string object_path; + + private ArrayList media_objects; + + public ExternalContainer (string id, + string service_path, + string object_path, + ExternalContainer? parent) { + base (id, parent, "Uknown", 0); + + this.service_path = service_path; + this.object_path = object_path; + + this.media_objects = new ArrayList (); + + try { + DBus.Connection connection = DBus.Bus.get (DBus.BusType.SESSION); + + // Create proxy to MediaObject iface to get the display name through + dynamic DBus.Object props = connection.get_object (service_path, + object_path, + PROPS_IFACE); + Value value; + props.Get (OBJECT_IFACE, "display-name", out value); + this.title = value.get_string (); + + // Now proxy to MediaContainer iface for the rest of the stuff + this.actual_container = connection.get_object (service_path, + object_path, + CONTAINER_IFACE); + + this.fetch_media_objects (connection); + } catch (DBus.Error error) { + critical ("Failed to fetch root media objects: %s\n", + error.message); + } + } + + public override void get_children (uint offset, + uint max_count, + Cancellable? cancellable, + AsyncReadyCallback callback) { + uint stop = offset + max_count; + + stop = stop.clamp (0, this.child_count); + var containers = this.media_objects.slice ((int) offset, (int) stop); + + var res = new Rygel.SimpleAsyncResult> + (this, callback); + res.data = containers; + res.complete_in_idle (); + } + + public override Gee.List? get_children_finish ( + AsyncResult res) + throws GLib.Error { + var simple_res = (Rygel.SimpleAsyncResult>) res; + return simple_res.data; + } + + public override void find_object (string id, + Cancellable? cancellable, + AsyncReadyCallback callback) { + MediaObject media_object = find_object_sync (id); + + var res = new Rygel.SimpleAsyncResult (this, callback); + + res.data = media_object; + res.complete_in_idle (); + } + + public override MediaObject? find_object_finish (AsyncResult res) + throws GLib.Error { + var simple_res = (Rygel.SimpleAsyncResult) res; + return simple_res.data; + } + + // Private methods + private MediaObject? find_object_sync (string id) { + MediaObject obj = null; + + foreach (var tmp in this.media_objects) { + if (id == tmp.id) { + obj = tmp; + } else if (tmp is ExternalContainer) { + // Check it's children + var container = (ExternalContainer) tmp; + + obj = container.find_object_sync (id); + } + + if (obj != null) { + break; + } + } + + return obj; + } + + private void fetch_media_objects (DBus.Connection connection) + throws GLib.Error { + string[] object_paths = null; + + object_paths = this.actual_container.GetContainers (); + foreach (var object_path in object_paths) { + this.media_objects.add (new ExternalContainer (object_path, + this.service_path, + object_path, + this)); + } + + object_paths = this.actual_container.GetItems (); + foreach (var object_path in object_paths) { + this.media_objects.add (new ExternalItem (this.service_path, + object_path, + this)); + } + + this.child_count = this.media_objects.size; + } +} + diff --git a/src/plugins/external/rygel-external-content-dir.vala b/src/plugins/external/rygel-external-content-dir.vala new file mode 100644 index 0000000..73d4fef --- /dev/null +++ b/src/plugins/external/rygel-external-content-dir.vala @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2009 Zeeshan Ali (Khattak) . + * Copyright (C) 2009 Nokia Corporation, all rights reserved. + * + * Author: Zeeshan Ali (Khattak) + * + * + * This file is part of Rygel. + * + * Rygel is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Rygel 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +using Rygel; +using GUPnP; +using DBus; +using Gee; + +/** + * Implementation of External ContentDirectory service. + */ +public class Rygel.ExternalContentDir : ContentDirectory { + private const string EXTERNAL_SERVICE = "org.Rygel.MediaServer1.PulseAudio"; + private const string EXTERNAL_PATH = "/org/Rygel/MediaServer1/PulseAudio"; + + // Pubic methods + public override MediaContainer? create_root_container () { + //string friendly_name = this.root_device.get_friendly_name (); + + return new ExternalContainer ("0", + EXTERNAL_SERVICE, + EXTERNAL_PATH, + null); + } +} + diff --git a/src/plugins/external/rygel-external-item.vala b/src/plugins/external/rygel-external-item.vala new file mode 100644 index 0000000..b478928 --- /dev/null +++ b/src/plugins/external/rygel-external-item.vala @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2009 Zeeshan Ali (Khattak) . + * Copyright (C) 2009 Nokia Corporation, all rights reserved. + * + * Author: Zeeshan Ali (Khattak) + * + * + * This file is part of Rygel. + * + * Rygel is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Rygel 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +using Rygel; +using GUPnP; +using DBus; + +/** + * Represents External item. + */ +public class Rygel.ExternalItem : MediaItem { + private static string PROPS_IFACE = "org.freedesktop.DBus.Properties"; + private static string OBJECT_IFACE = "org.Rygel.MediaObject1"; + private static string ITEM_IFACE = "org.Rygel.MediaItem1"; + + public ExternalItem (string service_path, + string object_path, + MediaContainer parent) + throws GLib.Error { + base (object_path, + parent, + "Unknown", /* Title Unknown at this point */ + "Unknown"); /* UPnP Class Unknown at this point */ + + DBus.Connection connection = DBus.Bus.get (DBus.BusType.SESSION); + + dynamic DBus.Object props = connection.get_object (service_path, + object_path, + PROPS_IFACE); + + Value value; + props.Get (OBJECT_IFACE, "display-name", out value); + this.title = value.get_string (); + + props.Get (ITEM_IFACE, "type", out value); + string type = value.get_string (); + if (type == "audio") { + this.upnp_class = MediaItem.AUDIO_CLASS; + } else if (type == "music") { + this.upnp_class = MediaItem.MUSIC_CLASS; + } else if (type == "video") { + this.upnp_class = MediaItem.VIDEO_CLASS; + } else { + this.upnp_class = MediaItem.IMAGE_CLASS; + } + + props.Get (ITEM_IFACE, "mime-type", out value); + this.mime_type = value.get_string (); + + props.Get (ITEM_IFACE, "urls", out value); + string[] uris = (string[]) value.get_boxed (); + + foreach (var uri in uris) { + this.uris.add (uri); + } + } +} + diff --git a/src/plugins/external/rygel-external-plugin.vala b/src/plugins/external/rygel-external-plugin.vala new file mode 100644 index 0000000..10850f9 --- /dev/null +++ b/src/plugins/external/rygel-external-plugin.vala @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2009 Zeeshan Ali (Khattak) . + * Copyright (C) 2009 Nokia Corporation, all rights reserved. + * + * Author: Zeeshan Ali (Khattak) + * + * + * This file is part of Rygel. + * + * Rygel is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Rygel 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +using Rygel; +using Gee; +using CStuff; + +[ModuleInit] +public void load_plugin (PluginLoader loader) { + Plugin plugin = new Plugin ("PulseAudio"); + + // We only implement a ContentDirectory service + var resource_info = new ResourceInfo (ContentDirectory.UPNP_ID, + ContentDirectory.UPNP_TYPE, + ContentDirectory.DESCRIPTION_PATH, + typeof (ExternalContentDir)); + + plugin.add_resource (resource_info); + + loader.add_plugin (plugin); +} + -- 2.7.4