rygel r14 - in trunk: . src
- From: zeeshanak svn gnome org
- To: svn-commits-list gnome org
- Subject: rygel r14 - in trunk: . src
- Date: Tue, 28 Oct 2008 20:58:16 +0000 (UTC)
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]