rygel r14 - in trunk: . src



Author: zeeshanak
Date: Tue Oct 28 20:58:16 2008
New Revision: 14
URL: http://svn.gnome.org/viewvc/rygel?rev=14&view=rev

Log:
Implement a dummy MS.

Modified:
   trunk/ChangeLog
   trunk/src/gupnp-media-server.c
   trunk/src/gupnp-media-server.h
   trunk/src/main.c

Modified: trunk/src/gupnp-media-server.c
==============================================================================
--- trunk/src/gupnp-media-server.c	(original)
+++ trunk/src/gupnp-media-server.c	Tue Oct 28 20:58:16 2008
@@ -25,6 +25,9 @@
  */
 
 #include <string.h>
+#include <libgupnp/gupnp.h>
+#include <libgupnp-av/gupnp-av.h>
+
 #include "gupnp-media-server.h"
 
 G_DEFINE_TYPE (GUPnPMediaServer,
@@ -32,20 +35,49 @@
                GUPNP_TYPE_ROOT_DEVICE);
 
 struct _GUPnPMediaServerPrivate {
-        GUPnPRootDevice *root_device;
+        guint32 system_update_id;
+
+        GUPnPService *content_dir;
+
+        GUPnPDIDLLiteWriter *didl_writer;
+        GUPnPSearchCriteriaParser *search_parser;
 };
 
+/* Hard-coded items (mime, title, path) */
+char *items[3][4] = {
+        { "4000",
+          "audio/mp3",
+          "Maa",
+          "/home/zeenix/entertainment/songs/Maa.mp3" },
+        { "4001",
+          "audio/mp3",
+          "Hoo",
+          "/home/zeenix/entertainment/songs/Ho.mp3" },
+        { NULL }
+};
+
+/* GObject stuff */
 static void
 gupnp_media_server_dispose (GObject *object)
 {
         GUPnPMediaServer *server;
         GObjectClass *object_class;
 
-        server = GUPNP_DEVICE (object);
+        server = GUPNP_MEDIA_SERVER (object);
 
-        if (server->priv->root_device) {
-                g_object_unref (server->priv->root_device);
-                server->priv->root_device = NULL;
+        /* Free GUPnP resources */
+        if (server->priv->search_parser) {
+                g_object_unref (server->priv->search_parser);
+                server->priv->search_parser = NULL;
+        }
+
+        if (server->priv->didl_writer) {
+                g_object_unref (server->priv->didl_writer);
+                server->priv->didl_writer = NULL;
+        }
+        if (server->priv->content_dir) {
+                g_object_unref (server->priv->content_dir);
+                server->priv->content_dir = NULL;
         }
 
         /* Call super */
@@ -56,23 +88,272 @@
 static void
 gupnp_media_server_init (GUPnPMediaServer *server)
 {
-        server->priv = G_TYPE_INSTANCE_GET_PRIVATE (server,
-                                                    GUPNP_TYPE_DEVICE,
-                                                    GUPnPMediaServerPrivate);
+         server->priv = G_TYPE_INSTANCE_GET_PRIVATE (server,
+                                                     GUPNP_TYPE_MEDIA_SERVER,
+                                                     GUPnPMediaServerPrivate);
+
+         /* Create a new DIDL-Lite writer */
+        server->priv->didl_writer = gupnp_didl_lite_writer_new ();
+
+        /* Create a new search criteria parser */
+        server->priv->search_parser = gupnp_search_criteria_parser_new ();
+}
+
+static GObject *
+gupnp_media_server_constructor (GType                  type,
+                                guint                  n_construct_params,
+                                GObjectConstructParam *construct_params)
+{
+        GObject *object;
+        GObjectClass *object_class;
+        GUPnPMediaServer *server;
+        GUPnPServiceInfo *service;
+
+        object_class = G_OBJECT_CLASS (gupnp_media_server_parent_class);
+        object = object_class->constructor (type,
+                                            n_construct_params,
+                                            construct_params);
+
+        if (object == NULL)
+                return NULL;
+
+        server = GUPNP_MEDIA_SERVER (object);
+
+        /* Connect ContentDirectory signals */
+        service = gupnp_device_info_get_service
+                        (GUPNP_DEVICE_INFO (server),
+                         "urn:schemas-upnp-org:service:ContentDirectory:2");
+        if (service != NULL) {
+                GError *error;
+
+                server->priv->content_dir = GUPNP_SERVICE (service);
+
+                error = NULL;
+                gupnp_service_signals_autoconnect (server->priv->content_dir,
+                                                   server,
+                                                   &error);
+                if (error) {
+                        g_warning ("Error autoconnecting signals: %s",
+                                   error->message);
+                        g_error_free (error);
+                }
+        }
+
+        return object;
 }
 
 static void
 gupnp_media_server_class_init (GUPnPMediaServerClass *klass)
 {
         GObjectClass *object_class;
-        GUPnPMediaServerInfoClass *info_class;
 
         object_class = G_OBJECT_CLASS (klass);
 
         object_class->dispose = gupnp_media_server_dispose;
-
-        info_class = GUPNP_DEVICE_INFO_CLASS (klass);
+        object_class->constructor = gupnp_media_server_constructor;
 
         g_type_class_add_private (klass, sizeof (GUPnPMediaServerPrivate));
 }
 
+static void
+add_item (GUPnPContext        *context,
+          GUPnPDIDLLiteWriter *didl_writer,
+          const char          *id,
+          const char          *parent_id,
+          const char          *mime,
+          const char          *title,
+          const char          *path)
+{
+        GUPnPDIDLLiteResource res;
+
+        gupnp_didl_lite_writer_start_item (didl_writer,
+                                           id,
+                                           parent_id,
+                                           NULL,
+                                           FALSE);
+
+        /* Add fields */
+        gupnp_didl_lite_writer_add_string (didl_writer,
+                                           "title",
+                                           GUPNP_DIDL_LITE_WRITER_NAMESPACE_DC,
+                                           NULL,
+                                           title);
+
+        gupnp_didl_lite_writer_add_string
+                        (didl_writer,
+                         "class",
+                         GUPNP_DIDL_LITE_WRITER_NAMESPACE_UPNP,
+                         NULL,
+                         "object.item.audioItem.musicTrack");
+
+        gupnp_didl_lite_writer_add_string
+                        (didl_writer,
+                         "album",
+                         GUPNP_DIDL_LITE_WRITER_NAMESPACE_UPNP,
+                         NULL,
+                         "Some album");
+
+        /* Add resource data */
+        gupnp_didl_lite_resource_reset (&res);
+
+        /* URI */
+        res.uri = g_strdup_printf ("http://%s:%d%s";,
+                                   gupnp_context_get_host_ip (context),
+                                   gupnp_context_get_port (context),
+                                   path);
+
+        /* Protocol info */
+        res.protocol_info = g_strdup_printf ("http-get:*:%s:*", mime);
+
+        gupnp_didl_lite_writer_add_res (didl_writer, &res);
+
+        /* Cleanup */
+        g_free (res.protocol_info);
+        g_free (res.uri);
+
+        /* End of item */
+        gupnp_didl_lite_writer_end_item (didl_writer);
+}
+
+static char *
+browse_direct_children (GUPnPMediaServer *server, guint *num_returned)
+{
+        GUPnPContext *context;
+        const char *didl;
+        char *result;
+        guint i;
+
+        context = gupnp_device_info_get_context (GUPNP_DEVICE_INFO (server));
+
+        /* Start DIDL-Lite fragment */
+        gupnp_didl_lite_writer_start_didl_lite (server->priv->didl_writer,
+                                                NULL,
+                                                NULL,
+                                                TRUE);
+        /* Add items */
+        for (i = 0; items[i][0]; i++)
+                add_item (context,
+                          server->priv->didl_writer,
+                          items[i][0],
+                          "0",
+                          items[i][1],
+                          items[i][2],
+                          items[i][3]);
+
+        /* End DIDL-Lite fragment */
+        gupnp_didl_lite_writer_end_didl_lite (server->priv->didl_writer);
+
+        /* Retrieve generated string */
+        didl = gupnp_didl_lite_writer_get_string (server->priv->didl_writer);
+        result = g_strdup (didl);
+
+        /* Reset the parser state */
+        gupnp_didl_lite_writer_reset (server->priv->didl_writer);
+
+        *num_returned = i;
+
+        return result;
+}
+
+/* Browse action implementation */
+void
+browse_cb (GUPnPService       *service,
+           GUPnPServiceAction *action,
+           gpointer            user_data)
+{
+        GUPnPMediaServer *server;
+        char *object_id, *browse_flag;
+        gboolean browse_metadata;
+        char *result;
+        guint num_returned;
+
+        server = GUPNP_MEDIA_SERVER (user_data);
+
+        /* Handle incoming arguments */
+        gupnp_service_action_get (action,
+                                  "ObjectID",
+                                        G_TYPE_STRING,
+                                        &object_id,
+                                  "BrowseFlag",
+                                        G_TYPE_STRING,
+                                        &browse_flag,
+                                  NULL);
+
+        /* BrowseFlag */
+        if (browse_flag && !strcmp (browse_flag, "BrowseDirectChildren")) {
+                browse_metadata = FALSE;
+        } else if (browse_flag && !strcmp (browse_flag, "BrowseMetadata")) {
+                browse_metadata = TRUE;
+        } else {
+                gupnp_service_action_return_error
+                        (action, GUPNP_CONTROL_ERROR_INVALID_ARGS, NULL);
+
+                goto OUT;
+        }
+
+        /* ObjectID */
+        if (!object_id) {
+                gupnp_service_action_return_error
+                        (action, 701, "No such object");
+
+                goto OUT;
+        }
+
+        if (browse_metadata) {
+                gupnp_service_action_return_error
+                        (action, 709, "Not implemented");
+
+                goto OUT;
+        } else {
+                /* We only have a root object */
+                if (strcmp (object_id, "0")) {
+                        gupnp_service_action_return_error
+                                (action, 701, "No such object");
+
+                        goto OUT;
+                }
+        }
+
+        result = browse_direct_children (server, &num_returned);
+
+        /* Set action return arguments */
+        gupnp_service_action_set (action,
+                                  "Result",
+                                        G_TYPE_STRING,
+                                        result,
+                                  "NumberReturned",
+                                        G_TYPE_UINT,
+                                        num_returned,
+                                  "TotalMatches",
+                                        G_TYPE_UINT,
+                                        num_returned,
+                                  "UpdateID",
+                                        G_TYPE_UINT,
+                                        server->priv->system_update_id,
+                                  NULL);
+
+        gupnp_service_action_return (action);
+
+        g_free (result);
+OUT:
+        g_free (object_id);
+}
+
+GUPnPMediaServer *
+gupnp_media_server_new (GUPnPContext *context,
+                        xmlDoc       *description_doc,
+                        const char   *relative_location)
+{
+        GUPnPResourceFactory *factory;
+
+        factory = gupnp_resource_factory_get_default ();
+
+        return g_object_new (GUPNP_TYPE_MEDIA_SERVER,
+                             "context", context,
+                             "resource-factory", factory,
+                             "root-device", NULL,
+                             "description-doc", description_doc,
+                             "relative-location", relative_location,
+                             NULL);
+}
+

Modified: trunk/src/gupnp-media-server.h
==============================================================================
--- trunk/src/gupnp-media-server.h	(original)
+++ trunk/src/gupnp-media-server.h	Tue Oct 28 20:58:16 2008
@@ -23,7 +23,7 @@
 #ifndef __GUPNP_MEDIA_SERVER_H__
 #define __GUPNP_MEDIA_SERVER_H__
 
-#include "gupnp-root-device.h"
+#include <libgupnp/gupnp.h>
 
 G_BEGIN_DECLS
 
@@ -69,6 +69,11 @@
         void (* _gupnp_reserved4) (void);
 } GUPnPMediaServerClass;
 
+GUPnPMediaServer *
+gupnp_media_server_new             (GUPnPContext *context,
+                                    xmlDoc       *description_doc,
+                                    const char   *relative_location);
+
 G_END_DECLS
 
 #endif /* __GUPNP_MEDIA_SERVER_H__ */

Modified: trunk/src/main.c
==============================================================================
--- trunk/src/main.c	(original)
+++ trunk/src/main.c	Tue Oct 28 20:58:16 2008
@@ -23,67 +23,271 @@
 #include <stdio.h>
 #include <locale.h>
 #include <string.h>
+#include <gconf/gconf-client.h>
+#include <uuid/uuid.h>
 
-#include "gui.h"
-#include "upnp.h"
-#include "main.h"
+#include "gupnp-media-server.h"
 
-static gboolean light_status;
-static gint     light_load_level;
-
-void
-set_status (gboolean status)
+#define DESC_DOC "xml/description.xml"
+#define MODIFIED_DESC_DOC "gupnp-media-server.xml"
+#define GCONF_PATH "/apps/gupnp-media-server/"
+#define DEFAULT_PORT 2700
+
+static GMainLoop *main_loop;
+
+/* Copy-paste from gupnp. */
+static xmlNode *
+xml_util_get_element (xmlNode *node,
+                      ...)
 {
-        if (status != light_status) {
-                light_status = status;
-                update_image ();
+        va_list var_args;
+
+        va_start (var_args, node);
+
+        while (TRUE) {
+                const char *arg;
+
+                arg = va_arg (var_args, const char *);
+                if (!arg)
+                        break;
 
-                notify_status_change (status);
+                for (node = node->children; node; node = node->next)
+                        if (!strcmp (arg, (char *) node->name))
+                                break;
+
+                if (!node)
+                        break;
         }
+
+        va_end (var_args);
+
+        return node;
 }
 
-gboolean
-get_status (void)
+static GUPnPContext *
+create_context (char *desc_path)
 {
-        return light_status;
+        GUPnPContext *context;
+        GConfClient *gconf_client;
+        char *host_ip;
+        int port;
+        GError *error;
+
+        gconf_client = gconf_client_get_default ();
+
+        error = NULL;
+        host_ip = gconf_client_get_string (gconf_client,
+                                           GCONF_PATH "host-ip",
+                                           &error);
+        if (host_ip == NULL) {
+                host_ip = g_strdup (g_get_host_name ());
+
+                if (error) {
+                        g_warning ("%s", error->message);
+
+                        g_error_free (error);
+                }
+        }
+
+        error = NULL;
+        port = gconf_client_get_int (gconf_client,
+                                     GCONF_PATH "port",
+                                     &error);
+        if (error) {
+                port = DEFAULT_PORT;
+
+                g_warning ("%s", error->message);
+                g_warning ("Failed to get port from configuration."
+                           " Assuming default: %d", port);
+
+                g_error_free (error);
+        }
+
+        g_object_unref (gconf_client);
+
+        error = NULL;
+        context = gupnp_context_new (NULL, host_ip, port, &error);
+
+        g_free (host_ip);
+
+        if (error) {
+                g_warning ("Error setting up GUPnP context: %s",
+                           error->message);
+                g_error_free (error);
+
+                return NULL;
+        }
+
+        /* Host UPnP dir */
+        gupnp_context_host_path (context, DATA_DIR, "");
+
+        /* Host our modified file */
+        gupnp_context_host_path (context, desc_path, "/" MODIFIED_DESC_DOC);
+
+        return context;
 }
 
-void
-set_load_level (gint load_level)
+/* Fills the description doc @doc with a friendly name, including
+ * the full name of the user, and a UDN if not already present. */
+static void
+set_friendly_name_and_udn (xmlDoc *doc)
 {
-        if (load_level != light_load_level) {
-                light_load_level = CLAMP (load_level, 0, 100);
-                update_image ();
+        xmlNode *device_element;
+        xmlNode *element;
+        char *str;
+        xmlChar *xml_str;
+
+        device_element = xml_util_get_element ((xmlNode *) doc,
+                                               "root",
+                                               "device",
+                                               NULL);
+        if (device_element == NULL) {
+                g_warning ("Element /root/device not found.");
+
+                return;
+        }
+
+        /* friendlyName */
+        element = xml_util_get_element (device_element,
+                                        "friendlyName",
+                                        NULL);
+        if (element == NULL) {
+                g_warning ("Element /root/device/friendlyName not found.");
 
-                notify_load_level_change (light_load_level);
+                return;
         }
+
+        str = g_strdup_printf ("%s's GUPnP MediaServer", g_get_real_name ());
+        xml_str = xmlEncodeSpecialChars (doc, (xmlChar *) str);
+        g_free (str);
+
+        xmlNodeSetContent (element, xml_str);
+
+        xmlFree (xml_str);
+
+        /* UDN */
+        element = xml_util_get_element (device_element,
+                                        "UDN",
+                                        NULL);
+        if (element == NULL) {
+                g_warning ("Element /root/device/UDN not found.");
+
+                return;
+        }
+
+        xml_str = xmlNodeGetContent (element);
+        if (!xml_str || strncmp ((char *) xml_str, "uuid:", 5)) {
+                uuid_t id;
+                char out[44];
+
+                strcpy (out, "uuid:");
+
+                /* Generate new UUID */
+                uuid_generate (id);
+                uuid_unparse (id, out + 5);
+
+                xmlNodeSetContent (element, (xmlChar *) out);
+        }
+
+        if (xml_str)
+                xmlFree (xml_str);
 }
 
-gint
-get_load_level (void)
+static GUPnPMediaServer *
+create_ms (void)
 {
-        return light_load_level;
+        GUPnPMediaServer *server;
+        GUPnPContext *context;
+        char *desc_path;
+        xmlDoc *doc;
+        FILE *f;
+        int res;
+
+        /* We store a modified description.xml in the user's config dir */
+        desc_path = g_build_filename (g_get_user_config_dir (),
+                                      MODIFIED_DESC_DOC,
+                                      NULL);
+
+        /* Load description.xml. Loads the already-modified version, if it
+         * exists. */
+        if (g_file_test (desc_path, G_FILE_TEST_EXISTS))
+                doc = xmlParseFile (desc_path);
+        else
+                doc = xmlParseFile (DATA_DIR
+                                    G_DIR_SEPARATOR_S
+                                    DESC_DOC);
+
+        if (doc == NULL)
+                return NULL;
+
+        /* Modify description.xml to include a UDN and a friendy name */
+        set_friendly_name_and_udn (doc);
+
+        /* Save the modified description.xml into the user's config dir.
+         * We do this so that we can host the modified file, and also to
+         * make sure the generated UDN stays the same between sessions. */
+        f = fopen (desc_path, "w+");
+
+        if (f != NULL) {
+                res = xmlDocDump (f, doc);
+
+                fclose (f);
+        }
+
+        if (f == NULL || res == -1) {
+                g_critical ("Failed to write modified"
+                            " description.xml to %s.\n",
+                             desc_path);
+
+                g_free (desc_path);
+                xmlFreeDoc (doc);
+
+                return NULL;
+        }
+
+        /* Set up GUPnP context */
+        context = create_context (desc_path);
+        if (!context) {
+                g_free (desc_path);
+                xmlFreeDoc (doc);
+
+                return NULL;
+        }
+
+        g_free (desc_path);
+
+        /* Set up the root device */
+        server = gupnp_media_server_new (context,
+                                         doc,
+                                         MODIFIED_DESC_DOC);
+        g_object_unref (context);
+        g_object_weak_ref (G_OBJECT (server),
+                           (GWeakNotify) xmlFreeDoc, doc);
+
+        /* Make our device available */
+        gupnp_root_device_set_available (GUPNP_ROOT_DEVICE (server), TRUE);
+
+        return server;
 }
 
 int
 main (int argc, char **argv)
 {
-        /* Light is off in the beginning */
-        light_status = FALSE;
-        light_load_level = 100;
+        GUPnPMediaServer *server;
 
-        if (!init_ui (&argc, &argv)) {
-                return -1;
-        }
+        g_type_init ();
 
-        if (!init_upnp ()) {
-                return -2;
+        server = create_ms ();
+        if (server == NULL) {
+                return -1;
         }
 
-        gtk_main ();
+        main_loop = g_main_loop_new (NULL, FALSE);
+        g_main_loop_run (main_loop);
 
-        deinit_ui ();
-        deinit_upnp ();
+        g_main_loop_unref (main_loop);
+        g_object_unref (server);
 
         return 0;
 }
+



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