[rygel-grilo] Notify when provider comes and goes.
- From: Juan A. Suarez Romero <jasuarez src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [rygel-grilo] Notify when provider comes and goes.
- Date: Thu, 22 Apr 2010 14:31:10 +0000 (UTC)
commit 1c09e8899a23277789a6486f07d26673b643ec08
Author: Juan A. Suarez Romero <jasuarez igalia com>
Date: Thu Apr 22 16:13:12 2010 +0200
Notify when provider comes and goes.
Clients must be notified when a provider goes away.
The same when a new provider appears.
First part is through a signal, "destroy", which will tell user that provider
have been removed.
Second part is done with an observer, which will emit the "new" signal
everytime a new provider comes up.
lib/Makefile.am | 6 +-
lib/media-server2-client.c | 77 ++++++-
lib/media-server2-client.h | 4 +
lib/media-server2-observer.c | 224 ++++++++++++++++++++
lib/media-server2-observer.h | 83 +++++++
...r2-server-private.h => media-server2-private.h} | 20 ++-
lib/media-server2-server.c | 5 +-
src/test-client.c | 89 ++++++++-
8 files changed, 490 insertions(+), 18 deletions(-)
---
diff --git a/lib/Makefile.am b/lib/Makefile.am
index e5df246..10db94d 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -30,14 +30,16 @@ libmediaserver2_la_LIBADD = \
$(DEPS_LIBS)
libmediaserver2_la_SOURCES = \
+ media-server2-private.h \
media-server2-common.h \
media-server2-server-glue.h \
- media-server2-server-private.h \
media-server2-server.h \
media-server2-server.c \
media-server2-client-glue.h \
media-server2-client.h \
- media-server2-client.c
+ media-server2-client.c \
+ media-server2-observer.h \
+ media-server2-observer.c
MAINTAINERCLEANFILES = \
*.in
diff --git a/lib/media-server2-client.c b/lib/media-server2-client.c
index 0992335..b8e4da0 100644
--- a/lib/media-server2-client.c
+++ b/lib/media-server2-client.c
@@ -24,16 +24,10 @@
#include <dbus/dbus-glib.h>
#include <string.h>
+#include "media-server2-private.h"
#include "media-server2-client-glue.h"
#include "media-server2-client.h"
-#define MS2_DBUS_SERVICE_PREFIX "org.gnome.UPnP.MediaServer2."
-#define MS2_DBUS_PATH_PREFIX "/org/gnome/UPnP/MediaServer2/"
-#define MS2_DBUS_IFACE "org.gnome.UPnP.MediaServer2"
-
-#define ENTRY_POINT_IFACE "/org/gnome/UPnP/MediaServer2/"
-#define ENTRY_POINT_NAME "org.gnome.UPnP.MediaServer2."
-
#define DBUS_TYPE_G_ARRAY_OF_STRING \
(dbus_g_type_get_collection ("GPtrArray", G_TYPE_STRING))
@@ -48,6 +42,7 @@
enum {
UPDATED,
+ DESTROY,
LAST_SIGNAL
};
@@ -72,9 +67,11 @@ typedef struct {
/*
* Private MS2Client structure
* proxy_provider: a dbus proxy of content provider
+ * name: name of provider
*/
struct _MS2ClientPrivate {
DBusGProxy *proxy_provider;
+ gchar *name;
};
static guint32 signals[LAST_SIGNAL] = { 0 };
@@ -208,6 +205,8 @@ ms2_client_dispose (GObject *object)
{
MS2Client *client = MS2_CLIENT (object);
+ ms2_observer_remove_client (client, client->priv->name);
+
if (client->priv->proxy_provider) {
g_object_unref (client->priv->proxy_provider);
client->priv->proxy_provider = NULL;
@@ -216,6 +215,16 @@ ms2_client_dispose (GObject *object)
G_OBJECT_CLASS (ms2_client_parent_class)->dispose (object);
}
+static void
+ms2_client_finalize (GObject *object)
+{
+ MS2Client *client = MS2_CLIENT (object);
+
+ g_free (client->priv->name);
+
+ G_OBJECT_CLASS (ms2_client_parent_class)->finalize (object);
+}
+
/* Class init function */
static void
ms2_client_class_init (MS2ClientClass *klass)
@@ -225,6 +234,7 @@ ms2_client_class_init (MS2ClientClass *klass)
g_type_class_add_private (klass, sizeof (MS2ClientPrivate));
gobject_class->dispose = ms2_client_dispose;
+ gobject_class->finalize = ms2_client_finalize;
/**
* MS2Client::updated:
@@ -243,6 +253,27 @@ ms2_client_class_init (MS2ClientClass *klass)
G_TYPE_NONE,
1,
G_TYPE_STRING);
+
+ /**
+ * MS2Client::destroy:
+ * @client: a #MS2Client
+ *
+ * Notifies when a client is going to be destroyed. Usually this happens when
+ * provider goes away.
+ *
+ * User should not use the object, as provider is not present.
+ *
+ * After this, client will be automatically destroyed.
+ **/
+ signals[DESTROY] = g_signal_new ("destroy",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_RUN_CLEANUP,
+ G_STRUCT_OFFSET (MS2ClientClass, destroy),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
}
/* Object init function */
@@ -252,6 +283,18 @@ ms2_client_init (MS2Client *client)
client->priv = MS2_CLIENT_GET_PRIVATE (client);
}
+/****************** INTERNAL PUBLIC API (NOT TO BE EXPORTED) ******************/
+
+/* Notify destruction of client, and unref it */
+void
+ms2_client_notify_unref (MS2Client *client)
+{
+ g_return_if_fail (MS2_IS_CLIENT (client));
+
+ g_signal_emit (client, signals[DESTROY], 0);
+ g_object_unref (client);
+}
+
/******************** PUBLIC API ********************/
/**
@@ -372,16 +415,34 @@ MS2Client *ms2_client_new (const gchar *provider)
client = g_object_new (MS2_TYPE_CLIENT, NULL);
client->priv->proxy_provider = gproxy;
+ client->priv->name = g_strdup (provider);
+
+ ms2_observer_add_client (client, provider);
/* Listen to "updated" signal */
dbus_g_proxy_add_signal (gproxy, "Updated", G_TYPE_STRING, G_TYPE_INVALID);
- g_return_val_if_fail (MS2_IS_CLIENT(client), NULL);
dbus_g_proxy_connect_signal (gproxy, "Updated", G_CALLBACK (updated), client, NULL);
return client;
}
/**
+ * ms2_client_get_provider_name:
+ * @client: a #MS2Client
+ *
+ * Returns name of provider which client is attending
+ *
+ * Returns: name of provider
+ **/
+const gchar *
+ms2_client_get_provider_name (MS2Client *client)
+{
+ g_return_val_if_fail (MS2_IS_CLIENT (client), NULL);
+
+ return client->priv->name;
+}
+
+/**
* ms2_client_get_properties:
* @client: a #MS2Client
* @id: media identifier to obtain properties from
diff --git a/lib/media-server2-client.h b/lib/media-server2-client.h
index adeb623..64bfbfa 100644
--- a/lib/media-server2-client.h
+++ b/lib/media-server2-client.h
@@ -74,6 +74,8 @@ struct _MS2ClientClass {
void (*updated) (MS2Client *client,
const gchar *id);
+
+ void (*destroy) (MS2Client *client);
};
GType ms2_client_get_type (void);
@@ -82,6 +84,8 @@ gchar **ms2_client_get_providers (void);
MS2Client *ms2_client_new (const gchar *provider);
+const gchar *ms2_client_get_provider_name (MS2Client *client);
+
GHashTable *ms2_client_get_properties (MS2Client *client,
const gchar *id,
const gchar **properties,
diff --git a/lib/media-server2-observer.c b/lib/media-server2-observer.c
new file mode 100644
index 0000000..9bf360c
--- /dev/null
+++ b/lib/media-server2-observer.c
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2010 Igalia S.L.
+ *
+ * Authors: Juan A. Suarez Romero <jasuarez igalia com>
+ *
+ * This library 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; version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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 library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <dbus/dbus-glib-bindings.h>
+#include <dbus/dbus-glib.h>
+
+#include "media-server2-private.h"
+#include "media-server2-observer.h"
+#include "media-server2-client.h"
+
+#define ENTRY_POINT_NAME "org.gnome.UPnP.MediaServer2."
+#define ENTRY_POINT_NAME_LENGTH 28
+
+#define MS2_OBSERVER_GET_PRIVATE(o) \
+ G_TYPE_INSTANCE_GET_PRIVATE((o), MS2_TYPE_OBSERVER, MS2ObserverPrivate)
+
+enum {
+ NEW,
+ LAST_SIGNAL
+};
+
+/*
+ * Private MS2Observer structure
+ * clients: a table with the clients
+ * proxy: proxy to dbus service
+ */
+struct _MS2ObserverPrivate {
+ GHashTable *clients;
+ DBusGProxy *proxy;
+};
+
+static MS2Observer *observer_instance = NULL;
+static guint32 signals[LAST_SIGNAL] = { 0 };
+
+G_DEFINE_TYPE (MS2Observer, ms2_observer, G_TYPE_OBJECT);
+
+/******************** PRIVATE API ********************/
+
+static void
+name_owner_changed (DBusGProxy *proxy,
+ const gchar *name,
+ const gchar *old_owner,
+ const gchar *new_owner,
+ MS2Observer *observer)
+{
+ GList *clients;
+
+ /* Check if it has something to do with the spec */
+ if (!g_str_has_prefix (name, MS2_DBUS_SERVICE_PREFIX)) {
+ return;
+ }
+
+ name += MS2_DBUS_SERVICE_PREFIX_LENGTH;
+
+ /* Check if it has been removed */
+ if (*new_owner == '\0') {
+ clients = g_hash_table_lookup (observer->priv->clients, name);
+ g_list_foreach (clients, (GFunc) ms2_client_notify_unref, NULL);
+ return;
+ }
+
+ /* Check if it has been added */
+ if (*old_owner == '\0') {
+ g_signal_emit (observer, signals[NEW], 0, name);
+ }
+}
+
+/* Creates an instance of observer */
+static MS2Observer *
+create_instance ()
+{
+ DBusGConnection *connection;
+ GError *error = NULL;
+ MS2Observer *observer;
+
+ connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
+ if (!connection) {
+ g_printerr ("Could not connect to session bus, %s\n", error->message);
+ g_error_free (error);
+ return NULL;
+ }
+
+ observer = g_object_new (MS2_TYPE_OBSERVER, NULL);
+
+ observer->priv->proxy = dbus_g_proxy_new_for_name (connection,
+ DBUS_SERVICE_DBUS,
+ DBUS_PATH_DBUS,
+ DBUS_INTERFACE_DBUS);
+
+ /* Listen for name-owner-changed signal */
+ dbus_g_proxy_add_signal (observer->priv->proxy,
+ "NameOwnerChanged",
+ G_TYPE_STRING,
+ G_TYPE_STRING,
+ G_TYPE_STRING,
+ G_TYPE_INVALID);
+ dbus_g_proxy_connect_signal (observer->priv->proxy,
+ "NameOwnerChanged",
+ G_CALLBACK (name_owner_changed),
+ observer,
+ NULL);
+
+ return observer;
+}
+
+/* Class init function */
+static void
+ms2_observer_class_init (MS2ObserverClass *klass)
+{
+ g_type_class_add_private (klass, sizeof (MS2ObserverPrivate));
+
+ /**
+ * MS2Observer::observer:
+ * @observer: the #MS2Observer
+ * @provider: name of provider that has been added to dbus
+ *
+ * Notifies when a new provider comes up.
+ **/
+ signals[NEW] = g_signal_new ("new",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE,
+ G_STRUCT_OFFSET (MS2ObserverClass, new),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_STRING);
+}
+
+/* Object init function */
+static void
+ms2_observer_init (MS2Observer *client)
+{
+ client->priv = MS2_OBSERVER_GET_PRIVATE (client);
+ client->priv->clients = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ NULL);
+}
+
+/****************** INTERNAL PUBLIC API (NOT TO BE EXPORTED) ******************/
+
+/* Register a client */
+void
+ms2_observer_add_client (MS2Client *client,
+ const gchar *provider)
+{
+ GList *clients;
+ MS2Observer *observer;
+
+ observer = ms2_observer_get_instance ();
+ if (!observer) {
+ return;
+ }
+
+ clients = g_hash_table_lookup (observer->priv->clients, provider);
+ clients = g_list_prepend (clients, client);
+ g_hash_table_insert (observer->priv->clients, g_strdup (provider), clients);
+}
+
+/* Remove a client */
+void
+ms2_observer_remove_client (MS2Client *client,
+ const gchar *provider)
+{
+ GList *clients;
+ GList *remove_client;
+ MS2Observer *observer;
+
+ observer = ms2_observer_get_instance ();
+ if (!observer) {
+ return;
+ }
+
+ clients = g_hash_table_lookup (observer->priv->clients, provider);
+ remove_client = g_list_find (clients, client);
+ if (remove_client) {
+ clients = g_list_delete_link (clients, remove_client);
+ /* Check if there are more clients */
+ if (clients) {
+ g_hash_table_insert (observer->priv->clients, g_strdup (provider), clients);
+ } else {
+ g_hash_table_remove (observer->priv->clients, provider);
+ }
+ }
+}
+
+/******************** PUBLIC API ********************/
+
+/**
+ * ms2_observer_get_instance:
+ *
+ * Returns the observer instance
+ *
+ * Returns: the observer instance or @NULL if it could not be created
+ **/
+MS2Observer *ms2_observer_get_instance ()
+{
+ if (!observer_instance) {
+ observer_instance = create_instance ();
+ }
+
+ return observer_instance;
+}
diff --git a/lib/media-server2-observer.h b/lib/media-server2-observer.h
new file mode 100644
index 0000000..619c136
--- /dev/null
+++ b/lib/media-server2-observer.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2010 Igalia S.L.
+ *
+ * Authors: Juan A. Suarez Romero <jasuarez igalia com>
+ *
+ * This library 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; version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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 library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef _MEDIA_SERVER2_OBSERVER_H_
+#define _MEDIA_SERVER2_OBSERVER_H_
+
+/* #include <gio/gio.h> */
+#include <glib-object.h>
+/* #include <glib.h> */
+
+#include "media-server2-common.h"
+
+#define MS2_TYPE_OBSERVER \
+ (ms2_observer_get_type ())
+
+#define MS2_OBSERVER(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ MS2_TYPE_OBSERVER, \
+ MS2Observer))
+
+#define MS2_IS_OBSERVER(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ MS2_TYPE_OBSERVER))
+
+#define MS2_OBSERVER_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), \
+ MS2_TYPE_OBSERVER, \
+ MS2ObserverClass))
+
+#define MS2_IS_OBSERVER_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass), \
+ MS2_TYPE_OBSERVER))
+
+#define MS2_OBSERVER_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ MS2_TYPE_OBSERVER, \
+ MS2ObserverClass))
+
+typedef struct _MS2Observer MS2Observer;
+typedef struct _MS2ObserverPrivate MS2ObserverPrivate;
+
+struct _MS2Observer {
+
+ GObject parent;
+
+ /*< private >*/
+ MS2ObserverPrivate *priv;
+};
+
+typedef struct _MS2ObserverClass MS2ObserverClass;
+
+struct _MS2ObserverClass {
+
+ GObjectClass parent_class;
+
+ void (*new) (MS2Observer *observer,
+ const gchar *provider);
+};
+
+GType ms2_observer_get_type (void);
+
+MS2Observer *ms2_observer_get_instance (void);
+
+#endif /* _MEDIA_SERVER2_OBSERVER_H_ */
diff --git a/lib/media-server2-server-private.h b/lib/media-server2-private.h
similarity index 73%
rename from lib/media-server2-server-private.h
rename to lib/media-server2-private.h
index 9de4d02..b136c63 100644
--- a/lib/media-server2-server-private.h
+++ b/lib/media-server2-private.h
@@ -20,10 +20,18 @@
*
*/
-#ifndef _MEDIA_SERVER2_SERVER_PRIVATE_H_
-#define _MEDIA_SERVER2_SERVER_PRIVATE_H_
+#ifndef _MEDIA_SERVER2_PRIVATE_H_
+#define _MEDIA_SERVER2_PRIVATE_H_
+
+#define MS2_DBUS_SERVICE_PREFIX "org.gnome.UPnP.MediaServer2."
+#define MS2_DBUS_PATH_PREFIX "/org/gnome/UPnP/MediaServer2/"
+
+#define MS2_DBUS_SERVICE_PREFIX_LENGTH 28
+
+#define MS2_DBUS_IFACE "org.gnome.UPnP.MediaServer"
#include "media-server2-server.h"
+#include "media-server2-client.h"
gboolean ms2_server_get_properties (MS2Server *server,
const gchar *id,
@@ -39,4 +47,10 @@ gboolean ms2_server_get_children (MS2Server *server,
DBusGMethodInvocation *context,
GError **error);
-#endif /* _MEDIA_SERVER2_SERVER_PRIVATE_H_ */
+void ms2_client_notify_unref (MS2Client *client);
+
+void ms2_observer_add_client (MS2Client *client, const gchar *provider);
+
+void ms2_observer_remove_client (MS2Client *client, const gchar *provider);
+
+#endif /* _MEDIA_SERVER2_PRIVATE_H_ */
diff --git a/lib/media-server2-server.c b/lib/media-server2-server.c
index f173fa7..3f4e2cb 100644
--- a/lib/media-server2-server.c
+++ b/lib/media-server2-server.c
@@ -24,13 +24,10 @@
#include <dbus/dbus-glib.h>
#include <string.h>
-#include "media-server2-server-private.h"
+#include "media-server2-private.h"
#include "media-server2-server-glue.h"
#include "media-server2-server.h"
-#define MS2_DBUS_SERVICE_PREFIX "org.gnome.UPnP.MediaServer2."
-#define MS2_DBUS_PATH_PREFIX "/org/gnome/UPnP/MediaServer2/"
-
#define DBUS_TYPE_G_ARRAY_OF_STRING \
(dbus_g_type_get_collection ("GPtrArray", G_TYPE_STRING))
diff --git a/src/test-client.c b/src/test-client.c
index f8d5078..472765c 100644
--- a/src/test-client.c
+++ b/src/test-client.c
@@ -1,4 +1,5 @@
#include <media-server2-client.h>
+#include <media-server2-observer.h>
#include <glib.h>
#include <string.h>
@@ -238,6 +239,90 @@ test_children_sync ()
g_strfreev (providers);
}
+static void
+destroy_cb (MS2Client *client, gpointer user_data)
+{
+ g_print ("End of provider %s\n", ms2_client_get_provider_name(client));
+}
+
+static void
+new_cb (MS2Observer *observer, const gchar *provider, gpointer user_data)
+{
+ MS2Client *client;
+
+ client = ms2_client_new (provider);
+ if (!client) {
+ g_printerr ("Unable to create client for %s\n", provider);
+ } else {
+ g_print ("New provider %s\n", provider);
+ g_signal_connect (client, "destroy", G_CALLBACK (destroy_cb), NULL);
+ }
+}
+
+static void
+test_provider_free ()
+{
+ MS2Client *client;
+ gchar **provider;
+ gchar **providers;
+
+ providers = ms2_client_get_providers ();
+
+ if (!providers) {
+ g_print ("There is no MediaServer2 provider\n");
+ return;
+ }
+
+ for (provider = providers; *provider; provider++) {
+ client = ms2_client_new (*provider);
+ if (!client) {
+ g_printerr ("Unable to create a client\n");
+ continue;
+ }
+
+ g_print ("Provider %s\n", *provider);
+ g_signal_connect (G_OBJECT (client), "destroy", G_CALLBACK (destroy_cb), NULL);
+ }
+
+ g_strfreev (providers);
+}
+
+static void
+test_dynamic_providers ()
+{
+ MS2Client *client;
+ MS2Observer *observer;
+ gchar **provider;
+ gchar **providers;
+
+ observer = ms2_observer_get_instance ();
+ if (!observer) {
+ g_printerr ("Unable to get the observer\n");
+ return;
+ }
+
+ g_signal_connect (observer, "new", G_CALLBACK (new_cb), NULL);
+
+ providers = ms2_client_get_providers ();
+ if (!providers) {
+ g_print ("There is no MediaServer2 providers\n");
+ return;
+ }
+
+ for (provider = providers; *provider; provider++) {
+ client = ms2_client_new (*provider);
+ if (!client) {
+ g_printerr ("Unable to create a client for %s\n", *provider);
+ continue;
+ }
+
+ g_print ("New provider %s\n", *provider);
+ g_signal_connect (client, "destroy", G_CALLBACK (destroy_cb), NULL);
+ }
+
+ g_strfreev (providers);
+}
+
int main (int argc, char **argv)
{
GMainLoop *mainloop;
@@ -246,8 +331,10 @@ int main (int argc, char **argv)
if (0) test_properties_sync ();
if (0) test_children_sync ();
- if (1) test_properties_async ();
+ if (0) test_properties_async ();
if (0) test_children_async ();
+ if (0) test_provider_free ();
+ if (1) test_dynamic_providers ();
mainloop = g_main_loop_new (NULL, FALSE);
g_main_loop_run (mainloop);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]