]> code.delx.au - pulseaudio/commitdiff
dbus-protocol: Implement extension registration.
authorTanu Kaskinen <tanuk@iki.fi>
Fri, 31 Jul 2009 09:05:49 +0000 (12:05 +0300)
committerTanu Kaskinen <tanuk@iki.fi>
Fri, 31 Jul 2009 09:05:49 +0000 (12:05 +0300)
src/pulsecore/protocol-dbus.c
src/pulsecore/protocol-dbus.h

index fb7d168d5d985697e5f55da12c41059efe3c4d4e..81a6c02454cad38f533e4a63e25631f2bfa885b0 100644 (file)
@@ -41,7 +41,9 @@ struct pa_dbus_protocol {
     pa_core *core;
     pa_hashmap *objects; /* Object path -> struct object_entry */
     pa_hashmap *connections; /* DBusConnection -> struct connection_entry */
-    pa_hashmap *extensions; /* String -> anything */
+    pa_idxset *extensions; /* Strings */
+
+    pa_hook hooks[PA_DBUS_PROTOCOL_HOOK_MAX];
 };
 
 struct object_entry {
@@ -109,6 +111,7 @@ char *pa_get_dbus_address_from_server_type(pa_server_type_t server_type) {
 
 static pa_dbus_protocol *dbus_protocol_new(pa_core *c) {
     pa_dbus_protocol *p;
+    unsigned i;
 
     pa_assert(c);
 
@@ -117,7 +120,10 @@ static pa_dbus_protocol *dbus_protocol_new(pa_core *c) {
     p->core = c;
     p->objects = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
     p->connections = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
-    p->extensions = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
+    p->extensions = pa_idxset_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
+
+    for (i = 0; i < PA_DBUS_PROTOCOL_HOOK_MAX; ++i)
+        pa_hook_init(&p->hooks[i], p);
 
     pa_assert_se(pa_shared_set(c, "dbus-protocol", p) >= 0);
 
@@ -143,6 +149,8 @@ pa_dbus_protocol* pa_dbus_protocol_ref(pa_dbus_protocol *p) {
 }
 
 void pa_dbus_protocol_unref(pa_dbus_protocol *p) {
+    unsigned i;
+
     pa_assert(p);
     pa_assert(PA_REFCNT_VALUE(p) >= 1);
 
@@ -151,11 +159,14 @@ void pa_dbus_protocol_unref(pa_dbus_protocol *p) {
 
     pa_assert(pa_hashmap_isempty(p->objects));
     pa_assert(pa_hashmap_isempty(p->connections));
-    pa_assert(pa_hashmap_isempty(p->extensions));
+    pa_assert(pa_idxset_isempty(p->extensions));
 
     pa_hashmap_free(p->objects, NULL, NULL);
     pa_hashmap_free(p->connections, NULL, NULL);
-    pa_hashmap_free(p->extensions, NULL, NULL);
+    pa_idxset_free(p->extensions, NULL, NULL);
+
+    for (i = 0; i < PA_DBUS_PROTOCOL_HOOK_MAX; ++i)
+        pa_hook_done(&p->hooks[i]);
 
     pa_assert_se(pa_shared_remove(p->core, "dbus-protocol") >= 0);
 
@@ -660,6 +671,8 @@ static void property_handler_free_cb(void *p, void *userdata) {
 
     pa_xfree((char *) h->property_name);
     pa_xfree((char *) h->type);
+
+    pa_xfree(h);
 }
 
 int pa_dbus_protocol_remove_interface(pa_dbus_protocol *p, const char* path, const char* interface) {
@@ -792,6 +805,18 @@ int pa_dbus_protocol_unregister_connection(pa_dbus_protocol *p, DBusConnection *
     return 0;
 }
 
+pa_client *pa_dbus_protocol_get_client(pa_dbus_protocol *p, DBusConnection *conn) {
+    struct connection_entry *conn_entry;
+
+    pa_assert(p);
+    pa_assert(conn);
+
+    if (!(conn_entry = pa_hashmap_get(p->connections, conn)))
+        return NULL;
+
+    return conn_entry->client;
+}
+
 void pa_dbus_protocol_add_signal_listener(pa_dbus_protocol *p, DBusConnection *conn, const char *signal, char **objects, unsigned n_objects) {
     struct connection_entry *conn_entry;
     pa_idxset *object_set;
@@ -893,18 +918,6 @@ void pa_dbus_protocol_send_signal(pa_dbus_protocol *p, DBusMessage *signal) {
     }
 }
 
-pa_client *pa_dbus_protocol_get_client(pa_dbus_protocol *p, DBusConnection *conn) {
-    struct connection_entry *conn_entry;
-
-    pa_assert(p);
-    pa_assert(conn);
-
-    if (!(conn_entry = pa_hashmap_get(p->connections, conn)))
-        return NULL;
-
-    return conn_entry->client;
-}
-
 const char **pa_dbus_protocol_get_extensions(pa_dbus_protocol *p, unsigned *n) {
     const char **extensions;
     const char *ext_name;
@@ -914,17 +927,59 @@ const char **pa_dbus_protocol_get_extensions(pa_dbus_protocol *p, unsigned *n) {
     pa_assert(p);
     pa_assert(n);
 
-    *n = pa_hashmap_size(p->extensions);
+    *n = pa_idxset_size(p->extensions);
 
     if (*n <= 0)
         return NULL;
 
     extensions = pa_xnew(const char *, *n);
 
-    while (pa_hashmap_iterate(p->extensions, &state, (const void **) &ext_name)) {
+    while ((ext_name = pa_idxset_iterate(p->extensions, &state, NULL))) {
         extensions[i] = ext_name;
         ++i;
     }
 
     return extensions;
 }
+
+int pa_dbus_protocol_register_extension(pa_dbus_protocol *p, const char *name) {
+    char *internal_name;
+
+    pa_assert(p);
+    pa_assert(name);
+
+    internal_name = pa_xstrdup(name);
+
+    if (pa_idxset_put(p->extensions, internal_name, NULL) < 0) {
+        pa_xfree(internal_name);
+        return -1;
+    }
+
+    pa_hook_fire(&p->hooks[PA_DBUS_PROTOCOL_HOOK_EXTENSION_REGISTERED], internal_name);
+
+    return 0;
+}
+
+int pa_dbus_protocol_unregister_extension(pa_dbus_protocol *p, const char *name) {
+    char *internal_name;
+
+    pa_assert(p);
+    pa_assert(name);
+
+    if (!(internal_name = pa_idxset_remove_by_data(p->extensions, name, NULL)))
+        return -1;
+
+    pa_hook_fire(&p->hooks[PA_DBUS_PROTOCOL_HOOK_EXTENSION_UNREGISTERED], internal_name);
+
+    pa_xfree(internal_name);
+
+    return 0;
+}
+
+pa_hook_slot *pa_dbus_protocol_hook_connect(pa_dbus_protocol *p, pa_dbus_protocol_hook_t hook, pa_hook_priority_t prio, pa_hook_cb_t cb, void *data) {
+    pa_assert(p);
+    pa_assert(hook < PA_DBUS_PROTOCOL_HOOK_MAX);
+    pa_assert(cb);
+
+    return pa_hook_connect(&p->hooks[hook], prio, cb, data);
+}
index 27198f48cec187513d69fa44c44cda31cc4b66f3..f2b1b50b8b370ae50cb25815095155f0f108c53d 100644 (file)
@@ -119,9 +119,12 @@ int pa_dbus_protocol_remove_interface(pa_dbus_protocol *p, const char* path, con
  * registered. */
 int pa_dbus_protocol_register_connection(pa_dbus_protocol *p, DBusConnection *conn, pa_client *client);
 
-/* Returns a negative number if the connection wasn't registered. */
+/* Returns a negative number if the connection isn't registered. */
 int pa_dbus_protocol_unregister_connection(pa_dbus_protocol *p, DBusConnection *conn);
 
+/* Returns NULL if the connection isn't registered. */
+pa_client *pa_dbus_protocol_get_client(pa_dbus_protocol *p, DBusConnection *conn);
+
 /* Enables signal receiving for the given connection. The connection must have
  * been registered earlier.
  *
@@ -145,9 +148,6 @@ void pa_dbus_protocol_remove_signal_listener(pa_dbus_protocol *p, DBusConnection
 
 void pa_dbus_protocol_send_signal(pa_dbus_protocol *p, DBusMessage *signal);
 
-/* Returns NULL if the connection isn't registered. */
-pa_client *pa_dbus_protocol_get_client(pa_dbus_protocol *p, DBusConnection *conn);
-
 /* Returns an array of extension identifier strings. The strings pointers point
  * to the internal copies, so don't free the strings. The caller must free the
  * array, however. Also, do not save the returned pointer or any of the string
@@ -155,4 +155,35 @@ pa_client *pa_dbus_protocol_get_client(pa_dbus_protocol *p, DBusConnection *conn
  * need to save the array, copy it. */
 const char **pa_dbus_protocol_get_extensions(pa_dbus_protocol *p, unsigned *n);
 
+/* Modules that want to provide a D-Bus interface for clients should register
+ * an identifier that the clients can use to check whether the additional
+ * functionality is available.
+ *
+ * This function registers the extension with the given name. It is recommended
+ * that the name follows the D-Bus interface naming convention, so that the
+ * names remain unique in case there will be at some point in the future
+ * extensions that aren't included with the main PulseAudio source tree. For
+ * in-tree extensions the convention is to use the org.PulseAudio.Ext
+ * namespace.
+ *
+ * It is suggested that the name contains a version number, and whenever the
+ * extension interface is modified in non-backwards compatible way, the version
+ * number is incremented.
+ *
+ * Fails and returns a negative number if the extension is already registered.
+ */
+int pa_dbus_protocol_register_extension(pa_dbus_protocol *p, const char *name);
+
+/* Returns a negative number if the extension isn't registered. */
+int pa_dbus_protocol_unregister_extension(pa_dbus_protocol *p, const char *name);
+
+/* All hooks have the pa_dbus_protocol object as hook data. */
+typedef enum pa_dbus_protocol_hook {
+    PA_DBUS_PROTOCOL_HOOK_EXTENSION_REGISTERED, /* Extension name as call data. */
+    PA_DBUS_PROTOCOL_HOOK_EXTENSION_UNREGISTERED, /* Extension name as call data. */
+    PA_DBUS_PROTOCOL_HOOK_MAX
+} pa_dbus_protocol_hook_t;
+
+pa_hook_slot *pa_dbus_protocol_hook_connect(pa_dbus_protocol *p, pa_dbus_protocol_hook_t hook, pa_hook_priority_t prio, pa_hook_cb_t cb, void *data);
+
 #endif