[pulseaudio-commits] 9 commits - src/modules src/pulsecore

David Henningsson diwic at kemper.freedesktop.org
Thu Apr 2 07:20:26 PDT 2015


 src/modules/dbus/iface-card.c   |   69 ++---
 src/modules/dbus/iface-client.c |   34 +-
 src/modules/dbus/iface-core.c   |  511 ++++++++++++++++++++++++----------------
 src/modules/dbus/iface-device.c |  121 +++++++--
 src/modules/dbus/iface-stream.c |  179 +++++++++-----
 src/pulsecore/core.h            |    2 
 src/pulsecore/namereg.c         |    2 
 7 files changed, 589 insertions(+), 329 deletions(-)

New commits:
commit 42eac216cf470f36e4be853b46c8105f4621a9f7
Author: Juho Hämäläinen <juho.hamalainen at tieto.com>
Date:   Thu Mar 19 13:50:50 2015 +0200

    dbus: Use hooks for default sink and source changes
    
    [Fixes by David Henningsson <david.henningsson at canonical.com>]

diff --git a/src/modules/dbus/iface-core.c b/src/modules/dbus/iface-core.c
index 3d58754..41a75b1 100644
--- a/src/modules/dbus/iface-core.c
+++ b/src/modules/dbus/iface-core.c
@@ -109,6 +109,8 @@ struct pa_dbusiface_core {
     pa_sink *fallback_sink;
     pa_source *fallback_source;
 
+    pa_hook_slot *default_sink_changed_slot;
+    pa_hook_slot *default_source_changed_slot;
     pa_hook_slot *card_put_slot;
     pa_hook_slot *card_unlink_slot;
     pa_hook_slot *sink_input_put_slot;
@@ -1576,76 +1578,14 @@ static void handle_stop_listening_for_signal(DBusConnection *conn, DBusMessage *
 
 static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint32_t idx, void *userdata) {
     pa_dbusiface_core *c = userdata;
-    pa_dbusiface_device *device_iface = NULL;
     pa_dbusiface_sample *sample_iface = NULL;
     pa_dbusiface_module *module_iface = NULL;
     DBusMessage *signal_msg = NULL;
     const char *object_path = NULL;
-    pa_sink *new_fallback_sink = NULL;
-    pa_source *new_fallback_source = NULL;
 
     pa_assert(c);
 
     switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) {
-        case PA_SUBSCRIPTION_EVENT_SERVER:
-            new_fallback_sink = pa_namereg_get_default_sink(core);
-            new_fallback_source = pa_namereg_get_default_source(core);
-
-            if (c->fallback_sink != new_fallback_sink) {
-                if (c->fallback_sink)
-                    pa_sink_unref(c->fallback_sink);
-                c->fallback_sink = new_fallback_sink ? pa_sink_ref(new_fallback_sink) : NULL;
-
-                if (c->fallback_sink) {
-                    pa_assert_se(device_iface = pa_hashmap_get(c->sinks_by_index, PA_UINT32_TO_PTR(c->fallback_sink->index)));
-                    object_path = pa_dbusiface_device_get_path(device_iface);
-
-                    pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
-                                                                       PA_DBUS_CORE_INTERFACE,
-                                                                       signals[SIGNAL_FALLBACK_SINK_UPDATED].name)));
-                    pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
-                    pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg);
-                    dbus_message_unref(signal_msg);
-                    signal_msg = NULL;
-
-                } else {
-                    pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
-                                                                       PA_DBUS_CORE_INTERFACE,
-                                                                       signals[SIGNAL_FALLBACK_SINK_UNSET].name)));
-                    pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg);
-                    dbus_message_unref(signal_msg);
-                    signal_msg = NULL;
-                }
-            }
-
-            if (c->fallback_source != new_fallback_source) {
-                if (c->fallback_source)
-                    pa_source_unref(c->fallback_source);
-                c->fallback_source = new_fallback_source ? pa_source_ref(new_fallback_source) : NULL;
-
-                if (c->fallback_source) {
-                    pa_assert_se(device_iface = pa_hashmap_get(c->sources_by_index, PA_UINT32_TO_PTR(c->fallback_source->index)));
-                    object_path = pa_dbusiface_device_get_path(device_iface);
-
-                    pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
-                                                                       PA_DBUS_CORE_INTERFACE,
-                                                                       signals[SIGNAL_FALLBACK_SOURCE_UPDATED].name)));
-                    pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
-                    pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg);
-                    dbus_message_unref(signal_msg);
-                    signal_msg = NULL;
-
-                } else {
-                    pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
-                                                                       PA_DBUS_CORE_INTERFACE,
-                                                                       signals[SIGNAL_FALLBACK_SOURCE_UNSET].name)));
-                    pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg);
-                    dbus_message_unref(signal_msg);
-                    signal_msg = NULL;
-                }
-            }
-            break;
-
         case PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE:
             if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) {
                 pa_scache_entry *sample = NULL;
@@ -1721,6 +1661,82 @@ static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint3
     }
 }
 
+static pa_hook_result_t default_sink_changed_cb(void *hook_data, void *call_data, void *slot_data) {
+    pa_dbusiface_core *c = slot_data;
+    pa_sink *new_fallback_sink = call_data;
+    pa_dbusiface_device *device_iface;
+    const char *object_path;
+    DBusMessage *signal_msg = NULL;
+
+    pa_assert(c);
+
+    if (c->fallback_sink != new_fallback_sink) {
+        if (c->fallback_sink)
+            pa_sink_unref(c->fallback_sink);
+        c->fallback_sink = new_fallback_sink ? pa_sink_ref(new_fallback_sink) : NULL;
+
+        if (c->fallback_sink) {
+            pa_assert_se((device_iface = pa_hashmap_get(c->sinks_by_index, PA_UINT32_TO_PTR(c->fallback_sink->index))));
+            object_path = pa_dbusiface_device_get_path(device_iface);
+
+            pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
+                                                               PA_DBUS_CORE_INTERFACE,
+                                                               signals[SIGNAL_FALLBACK_SINK_UPDATED].name)));
+            pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
+
+        } else {
+            pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
+                                                               PA_DBUS_CORE_INTERFACE,
+                                                               signals[SIGNAL_FALLBACK_SINK_UNSET].name)));
+        }
+    }
+
+    if (signal_msg) {
+        pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg);
+        dbus_message_unref(signal_msg);
+    }
+
+    return PA_HOOK_OK;
+}
+
+static pa_hook_result_t default_source_changed_cb(void *hook_data, void *call_data, void *slot_data) {
+    pa_dbusiface_core *c = slot_data;
+    pa_source *new_fallback_source = call_data;
+    pa_dbusiface_device *device_iface;
+    const char *object_path;
+    DBusMessage *signal_msg = NULL;
+
+    pa_assert(c);
+
+    if (c->fallback_source != new_fallback_source) {
+        if (c->fallback_source)
+            pa_source_unref(c->fallback_source);
+        c->fallback_source = new_fallback_source ? pa_source_ref(new_fallback_source) : NULL;
+
+        if (c->fallback_source) {
+            pa_assert_se((device_iface = pa_hashmap_get(c->sources_by_index, PA_UINT32_TO_PTR(c->fallback_source->index))));
+            object_path = pa_dbusiface_device_get_path(device_iface);
+
+            pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
+                                                               PA_DBUS_CORE_INTERFACE,
+                                                               signals[SIGNAL_FALLBACK_SOURCE_UPDATED].name)));
+            pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
+
+        } else {
+            pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
+                                                               PA_DBUS_CORE_INTERFACE,
+                                                               signals[SIGNAL_FALLBACK_SOURCE_UNSET].name)));
+        }
+    }
+
+    if (signal_msg) {
+        pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg);
+        dbus_message_unref(signal_msg);
+    }
+
+    return PA_HOOK_OK;
+}
+
 static pa_hook_result_t card_put_cb(void *hook_data, void *call_data, void *slot_data) {
     pa_dbusiface_core *c = slot_data;
     pa_card *card = call_data;
@@ -2114,6 +2130,10 @@ pa_dbusiface_core *pa_dbusiface_core_new(pa_core *core) {
     c->clients = pa_hashmap_new_full(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func, NULL, (pa_free_cb_t) pa_dbusiface_client_free);
     c->fallback_sink = pa_namereg_get_default_sink(core);
     c->fallback_source = pa_namereg_get_default_source(core);
+    c->default_sink_changed_slot = pa_hook_connect(&core->hooks[PA_CORE_HOOK_DEFAULT_SINK_CHANGED],
+                                                   PA_HOOK_NORMAL, default_sink_changed_cb, c);
+    c->default_source_changed_slot = pa_hook_connect(&core->hooks[PA_CORE_HOOK_DEFAULT_SOURCE_CHANGED],
+                                                     PA_HOOK_NORMAL, default_source_changed_cb, c);
     c->card_put_slot = pa_hook_connect(&core->hooks[PA_CORE_HOOK_CARD_PUT],
                                        PA_HOOK_NORMAL, card_put_cb, c);
     c->card_unlink_slot = pa_hook_connect(&core->hooks[PA_CORE_HOOK_CARD_UNLINK],
@@ -2204,6 +2224,8 @@ void pa_dbusiface_core_free(pa_dbusiface_core *c) {
     pa_hashmap_free(c->samples);
     pa_hashmap_free(c->modules);
     pa_hashmap_free(c->clients);
+    pa_hook_slot_free(c->default_sink_changed_slot);
+    pa_hook_slot_free(c->default_source_changed_slot);
     pa_hook_slot_free(c->card_put_slot);
     pa_hook_slot_free(c->card_unlink_slot);
     pa_hook_slot_free(c->sink_input_put_slot);

commit 3bb69ebfc2abffd106426e0c14bf034f5ebce319
Author: Juho Hämäläinen <juho.hamalainen at tieto.com>
Date:   Thu Mar 19 13:50:47 2015 +0200

    dbus: Use hooks for put and unlink
    
    Use hooks for all events that have core hooks defined. Some events
    handled in iface-core don't have hooks so leave those for later.

diff --git a/src/modules/dbus/iface-core.c b/src/modules/dbus/iface-core.c
index 4563b3f..3d58754 100644
--- a/src/modules/dbus/iface-core.c
+++ b/src/modules/dbus/iface-core.c
@@ -109,6 +109,14 @@ struct pa_dbusiface_core {
     pa_sink *fallback_sink;
     pa_source *fallback_source;
 
+    pa_hook_slot *card_put_slot;
+    pa_hook_slot *card_unlink_slot;
+    pa_hook_slot *sink_input_put_slot;
+    pa_hook_slot *sink_input_unlink_slot;
+    pa_hook_slot *source_output_put_slot;
+    pa_hook_slot *source_output_unlink_slot;
+    pa_hook_slot *client_put_slot;
+    pa_hook_slot *client_unlink_slot;
     pa_hook_slot *sink_put_slot;
     pa_hook_slot *sink_unlink_slot;
     pa_hook_slot *source_put_slot;
@@ -1568,12 +1576,9 @@ static void handle_stop_listening_for_signal(DBusConnection *conn, DBusMessage *
 
 static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint32_t idx, void *userdata) {
     pa_dbusiface_core *c = userdata;
-    pa_dbusiface_card *card_iface = NULL;
     pa_dbusiface_device *device_iface = NULL;
-    pa_dbusiface_stream *stream_iface = NULL;
     pa_dbusiface_sample *sample_iface = NULL;
     pa_dbusiface_module *module_iface = NULL;
-    pa_dbusiface_client *client_iface = NULL;
     DBusMessage *signal_msg = NULL;
     const char *object_path = NULL;
     pa_sink *new_fallback_sink = NULL;
@@ -1641,215 +1646,291 @@ static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint3
             }
             break;
 
-        case PA_SUBSCRIPTION_EVENT_CARD:
+        case PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE:
             if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) {
-                if (!(card_iface = pa_hashmap_get(c->cards, PA_UINT32_TO_PTR(idx)))) {
-                    pa_card *card = NULL;
+                pa_scache_entry *sample = NULL;
 
-                    if (!(card = pa_idxset_get_by_index(core->cards, idx)))
-                        return; /* The card was removed immediately after creation. */
+                if (!(sample = pa_idxset_get_by_index(core->scache, idx)))
+                    return; /* The sample was removed immediately after creation. */
 
-                    card_iface = pa_dbusiface_card_new(c, card);
-                    pa_hashmap_put(c->cards, PA_UINT32_TO_PTR(idx), card_iface);
+                if (!(sample_iface = pa_hashmap_get(c->samples, PA_UINT32_TO_PTR(idx)))) {
+                    sample_iface = pa_dbusiface_sample_new(c, sample);
+                    pa_hashmap_put(c->samples, PA_UINT32_TO_PTR(idx), sample_iface);
                 }
 
-                object_path = pa_dbusiface_card_get_path(card_iface);
+                object_path = pa_dbusiface_sample_get_path(sample_iface);
 
                 pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
                                                                    PA_DBUS_CORE_INTERFACE,
-                                                                   signals[SIGNAL_NEW_CARD].name)));
+                                                                   signals[SIGNAL_NEW_SAMPLE].name)));
                 pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
 
             } else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
-                if (!(card_iface = pa_hashmap_remove(c->cards, PA_UINT32_TO_PTR(idx))))
+                if (!(sample_iface = pa_hashmap_remove(c->samples, PA_UINT32_TO_PTR(idx))))
                     return;
 
-                object_path = pa_dbusiface_card_get_path(card_iface);
+                object_path = pa_dbusiface_sample_get_path(sample_iface);
 
                 pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
                                                                    PA_DBUS_CORE_INTERFACE,
-                                                                   signals[SIGNAL_CARD_REMOVED].name)));
+                                                                   signals[SIGNAL_SAMPLE_REMOVED].name)));
                 pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
 
-                pa_dbusiface_card_free(card_iface);
+                pa_dbusiface_sample_free(sample_iface);
             }
             break;
 
-        case PA_SUBSCRIPTION_EVENT_SINK_INPUT:
+        case PA_SUBSCRIPTION_EVENT_MODULE:
             if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) {
-                pa_sink_input *sink_input = NULL;
+                pa_module *module = NULL;
 
-                if (!(sink_input = pa_idxset_get_by_index(core->sink_inputs, idx)))
-                    return; /* The sink input was removed immediately after creation. */
+                if (!(module = pa_idxset_get_by_index(core->modules, idx)))
+                    return; /* The module was removed immediately after creation. */
 
-                if (!(stream_iface = pa_hashmap_get(c->playback_streams, PA_UINT32_TO_PTR(idx)))) {
-                    stream_iface = pa_dbusiface_stream_new_playback(c, sink_input);
-                    pa_hashmap_put(c->playback_streams, PA_UINT32_TO_PTR(idx), stream_iface);
+                if (!(module_iface = pa_hashmap_get(c->modules, PA_UINT32_TO_PTR(idx)))) {
+                    module_iface = pa_dbusiface_module_new(module);
+                    pa_hashmap_put(c->modules, PA_UINT32_TO_PTR(idx), module_iface);
                 }
 
-                object_path = pa_dbusiface_stream_get_path(stream_iface);
+                object_path = pa_dbusiface_module_get_path(module_iface);
 
                 pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
                                                                    PA_DBUS_CORE_INTERFACE,
-                                                                   signals[SIGNAL_NEW_PLAYBACK_STREAM].name)));
+                                                                   signals[SIGNAL_NEW_MODULE].name)));
                 pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
 
             } else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
-                if (!(stream_iface = pa_hashmap_remove(c->playback_streams, PA_UINT32_TO_PTR(idx))))
+                if (!(module_iface = pa_hashmap_remove(c->modules, PA_UINT32_TO_PTR(idx))))
                     return;
 
-                object_path = pa_dbusiface_stream_get_path(stream_iface);
+                object_path = pa_dbusiface_module_get_path(module_iface);
 
                 pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
                                                                    PA_DBUS_CORE_INTERFACE,
-                                                                   signals[SIGNAL_PLAYBACK_STREAM_REMOVED].name)));
+                                                                   signals[SIGNAL_MODULE_REMOVED].name)));
                 pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
 
-                pa_dbusiface_stream_free(stream_iface);
+                pa_dbusiface_module_free(module_iface);
             }
             break;
+    }
 
-        case PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT:
-            if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) {
-                pa_source_output *source_output = NULL;
+    if (signal_msg) {
+        pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg);
+        dbus_message_unref(signal_msg);
+    }
+}
 
-                if (!(source_output = pa_idxset_get_by_index(core->source_outputs, idx)))
-                    return; /* The source output was removed immediately after creation. */
+static pa_hook_result_t card_put_cb(void *hook_data, void *call_data, void *slot_data) {
+    pa_dbusiface_core *c = slot_data;
+    pa_card *card = call_data;
+    pa_dbusiface_card *card_iface = NULL;
+    const char *object_path;
+    DBusMessage *signal_msg;
 
-                if (!(stream_iface = pa_hashmap_get(c->record_streams, PA_UINT32_TO_PTR(idx)))) {
-                    stream_iface = pa_dbusiface_stream_new_record(c, source_output);
-                    pa_hashmap_put(c->record_streams, PA_UINT32_TO_PTR(idx), stream_iface);
-                }
+    pa_assert(c);
+    pa_assert(card);
 
-                object_path = pa_dbusiface_stream_get_path(stream_iface);
+    card_iface = pa_dbusiface_card_new(c, card);
+    pa_assert_se(pa_hashmap_put(c->cards, PA_UINT32_TO_PTR(card->index), card_iface) >= 0);
 
-                pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
-                                                                   PA_DBUS_CORE_INTERFACE,
-                                                                   signals[SIGNAL_NEW_RECORD_STREAM].name)));
-                pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
+    object_path = pa_dbusiface_card_get_path(card_iface);
 
-            } else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
-                if (!(stream_iface = pa_hashmap_remove(c->record_streams, PA_UINT32_TO_PTR(idx))))
-                    return;
+    pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
+                                                       PA_DBUS_CORE_INTERFACE,
+                                                       signals[SIGNAL_NEW_CARD].name)));
+    pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
 
-                object_path = pa_dbusiface_stream_get_path(stream_iface);
+    pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg);
+    dbus_message_unref(signal_msg);
 
-                pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
-                                                                   PA_DBUS_CORE_INTERFACE,
-                                                                   signals[SIGNAL_RECORD_STREAM_REMOVED].name)));
-                pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
+    return PA_HOOK_OK;
+}
 
-                pa_dbusiface_stream_free(stream_iface);
-            }
-            break;
+static pa_hook_result_t card_unlink_cb(void *hook_data, void *call_data, void *slot_data) {
+    pa_dbusiface_core *c = slot_data;
+    pa_card *card = call_data;
+    pa_dbusiface_card *card_iface;
+    const char *object_path;
+    DBusMessage *signal_msg;
 
-        case PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE:
-            if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) {
-                pa_scache_entry *sample = NULL;
+    pa_assert(c);
+    pa_assert(card);
 
-                if (!(sample = pa_idxset_get_by_index(core->scache, idx)))
-                    return; /* The sample was removed immediately after creation. */
+    pa_assert_se((card_iface = pa_hashmap_remove(c->cards, PA_UINT32_TO_PTR(card->index))));
 
-                if (!(sample_iface = pa_hashmap_get(c->samples, PA_UINT32_TO_PTR(idx)))) {
-                    sample_iface = pa_dbusiface_sample_new(c, sample);
-                    pa_hashmap_put(c->samples, PA_UINT32_TO_PTR(idx), sample_iface);
-                }
+    object_path = pa_dbusiface_card_get_path(card_iface);
 
-                object_path = pa_dbusiface_sample_get_path(sample_iface);
+    pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
+                                                       PA_DBUS_CORE_INTERFACE,
+                                                       signals[SIGNAL_CARD_REMOVED].name)));
+    pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
 
-                pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
-                                                                   PA_DBUS_CORE_INTERFACE,
-                                                                   signals[SIGNAL_NEW_SAMPLE].name)));
-                pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
+    pa_dbusiface_card_free(card_iface);
 
-            } else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
-                if (!(sample_iface = pa_hashmap_remove(c->samples, PA_UINT32_TO_PTR(idx))))
-                    return;
+    pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg);
+    dbus_message_unref(signal_msg);
 
-                object_path = pa_dbusiface_sample_get_path(sample_iface);
+    return PA_HOOK_OK;
+}
 
-                pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
-                                                                   PA_DBUS_CORE_INTERFACE,
-                                                                   signals[SIGNAL_SAMPLE_REMOVED].name)));
-                pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
+static pa_hook_result_t sink_input_put_cb(void *hook_data, void *call_data, void *slot_data) {
+    pa_dbusiface_core *c = slot_data;
+    pa_sink_input *sink_input = call_data;
+    pa_dbusiface_stream *stream_iface;
+    const char *object_path;
+    DBusMessage *signal_msg;
 
-                pa_dbusiface_sample_free(sample_iface);
-            }
-            break;
+    pa_assert(c);
+    pa_assert(sink_input);
 
-        case PA_SUBSCRIPTION_EVENT_MODULE:
-            if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) {
-                pa_module *module = NULL;
+    stream_iface = pa_dbusiface_stream_new_playback(c, sink_input);
+    pa_assert_se(pa_hashmap_put(c->playback_streams, PA_UINT32_TO_PTR(sink_input->index), stream_iface) >= 0);
 
-                if (!(module = pa_idxset_get_by_index(core->modules, idx)))
-                    return; /* The module was removed immediately after creation. */
+    object_path = pa_dbusiface_stream_get_path(stream_iface);
 
-                if (!(module_iface = pa_hashmap_get(c->modules, PA_UINT32_TO_PTR(idx)))) {
-                    module_iface = pa_dbusiface_module_new(module);
-                    pa_hashmap_put(c->modules, PA_UINT32_TO_PTR(idx), module_iface);
-                }
+    pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
+                                                       PA_DBUS_CORE_INTERFACE,
+                                                       signals[SIGNAL_NEW_PLAYBACK_STREAM].name)));
+    pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
 
-                object_path = pa_dbusiface_module_get_path(module_iface);
+    pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg);
+    dbus_message_unref(signal_msg);
 
-                pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
-                                                                   PA_DBUS_CORE_INTERFACE,
-                                                                   signals[SIGNAL_NEW_MODULE].name)));
-                pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
+    return PA_HOOK_OK;
+}
 
-            } else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
-                if (!(module_iface = pa_hashmap_remove(c->modules, PA_UINT32_TO_PTR(idx))))
-                    return;
+static pa_hook_result_t sink_input_unlink_cb(void *hook_data, void *call_data, void *slot_data) {
+    pa_dbusiface_core *c = slot_data;
+    pa_sink_input *sink_input = call_data;
+    pa_dbusiface_stream *stream_iface;
+    const char *object_path;
+    DBusMessage *signal_msg;
 
-                object_path = pa_dbusiface_module_get_path(module_iface);
+    pa_assert(c);
+    pa_assert(sink_input);
 
-                pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
-                                                                   PA_DBUS_CORE_INTERFACE,
-                                                                   signals[SIGNAL_MODULE_REMOVED].name)));
-                pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
+    pa_assert_se((stream_iface = pa_hashmap_remove(c->playback_streams, PA_UINT32_TO_PTR(sink_input->index))));
 
-                pa_dbusiface_module_free(module_iface);
-            }
-            break;
+    object_path = pa_dbusiface_stream_get_path(stream_iface);
 
-        case PA_SUBSCRIPTION_EVENT_CLIENT:
-            if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) {
-                pa_client *client = NULL;
+    pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
+                                                       PA_DBUS_CORE_INTERFACE,
+                                                       signals[SIGNAL_PLAYBACK_STREAM_REMOVED].name)));
+    pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
 
-                if (!(client = pa_idxset_get_by_index(core->clients, idx)))
-                    return; /* The client was removed immediately after creation. */
+    pa_dbusiface_stream_free(stream_iface);
 
-                if (!(client_iface = pa_hashmap_get(c->clients, PA_UINT32_TO_PTR(idx)))) {
-                    client_iface = pa_dbusiface_client_new(c, client);
-                    pa_hashmap_put(c->clients, PA_UINT32_TO_PTR(idx), client_iface);
-                }
+    pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg);
+    dbus_message_unref(signal_msg);
 
-                object_path = pa_dbusiface_client_get_path(client_iface);
+    return PA_HOOK_OK;
+}
 
-                pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
-                                                                   PA_DBUS_CORE_INTERFACE,
-                                                                   signals[SIGNAL_NEW_CLIENT].name)));
-                pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
+static pa_hook_result_t source_output_put_cb(void *hook_data, void *call_data, void *slot_data) {
+    pa_dbusiface_core *c = slot_data;
+    pa_source_output *source_output = call_data;
+    pa_dbusiface_stream *stream_iface;
+    const char *object_path;
+    DBusMessage *signal_msg;
 
-            } else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
-                if (!(client_iface = pa_hashmap_remove(c->clients, PA_UINT32_TO_PTR(idx))))
-                    return;
+    pa_assert(c);
+    pa_assert(source_output);
 
-                object_path = pa_dbusiface_client_get_path(client_iface);
+    stream_iface = pa_dbusiface_stream_new_record(c, source_output);
+    pa_assert_se(pa_hashmap_put(c->record_streams, PA_UINT32_TO_PTR(source_output->index), stream_iface) >= 0);
 
-                pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
-                                                                   PA_DBUS_CORE_INTERFACE,
-                                                                   signals[SIGNAL_CLIENT_REMOVED].name)));
-                pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
+    object_path = pa_dbusiface_stream_get_path(stream_iface);
 
-                pa_dbusiface_client_free(client_iface);
-            }
-            break;
-    }
+    pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
+                                                       PA_DBUS_CORE_INTERFACE,
+                                                       signals[SIGNAL_NEW_RECORD_STREAM].name)));
+    pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
 
-    if (signal_msg) {
-        pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg);
-        dbus_message_unref(signal_msg);
-    }
+    pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg);
+    dbus_message_unref(signal_msg);
+
+    return PA_HOOK_OK;
+}
+
+static pa_hook_result_t source_output_unlink_cb(void *hook_data, void *call_data, void *slot_data) {
+    pa_dbusiface_core *c = slot_data;
+    pa_source_output *source_output = call_data;
+    pa_dbusiface_stream *stream_iface;
+    const char *object_path;
+    DBusMessage *signal_msg;
+
+    pa_assert(c);
+    pa_assert(source_output);
+
+    pa_assert_se((stream_iface = pa_hashmap_remove(c->record_streams, PA_UINT32_TO_PTR(source_output->index))));
+
+    object_path = pa_dbusiface_stream_get_path(stream_iface);
+
+    pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
+                                                       PA_DBUS_CORE_INTERFACE,
+                                                       signals[SIGNAL_RECORD_STREAM_REMOVED].name)));
+    pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
+
+    pa_dbusiface_stream_free(stream_iface);
+
+    pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg);
+    dbus_message_unref(signal_msg);
+
+    return PA_HOOK_OK;
+}
+
+static pa_hook_result_t client_put_cb(void *hook_data, void *call_data, void *slot_data) {
+    pa_dbusiface_core *c = slot_data;
+    pa_client *client = call_data;
+    pa_dbusiface_client *client_iface;
+    const char *object_path;
+    DBusMessage *signal_msg;
+
+    pa_assert(c);
+    pa_assert(client);
+
+    client_iface = pa_dbusiface_client_new(c, client);
+    pa_assert_se(pa_hashmap_put(c->clients, PA_UINT32_TO_PTR(client->index), client_iface) >= 0);
+
+    object_path = pa_dbusiface_client_get_path(client_iface);
+
+    pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
+                                                       PA_DBUS_CORE_INTERFACE,
+                                                       signals[SIGNAL_NEW_CLIENT].name)));
+    pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
+
+    pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg);
+    dbus_message_unref(signal_msg);
+
+    return PA_HOOK_OK;
+}
+
+static pa_hook_result_t client_unlink_cb(void *hook_data, void *call_data, void *slot_data) {
+    pa_dbusiface_core *c = slot_data;
+    pa_client *client = call_data;
+    pa_dbusiface_client *client_iface;
+    const char *object_path;
+    DBusMessage *signal_msg;
+
+    pa_assert(c);
+    pa_assert(client);
+
+    pa_assert_se((client_iface = pa_hashmap_remove(c->clients, PA_UINT32_TO_PTR(client->index))));
+
+    object_path = pa_dbusiface_client_get_path(client_iface);
+
+    pa_assert_se((signal_msg = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
+                                                       PA_DBUS_CORE_INTERFACE,
+                                                       signals[SIGNAL_CLIENT_REMOVED].name)));
+    pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
+
+    pa_dbusiface_client_free(client_iface);
+
+    pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg);
+    dbus_message_unref(signal_msg);
+
+    return PA_HOOK_OK;
 }
 
 static pa_hook_result_t sink_put_cb(void *hook_data, void *call_data, void *slot_data) {
@@ -2033,6 +2114,22 @@ pa_dbusiface_core *pa_dbusiface_core_new(pa_core *core) {
     c->clients = pa_hashmap_new_full(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func, NULL, (pa_free_cb_t) pa_dbusiface_client_free);
     c->fallback_sink = pa_namereg_get_default_sink(core);
     c->fallback_source = pa_namereg_get_default_source(core);
+    c->card_put_slot = pa_hook_connect(&core->hooks[PA_CORE_HOOK_CARD_PUT],
+                                       PA_HOOK_NORMAL, card_put_cb, c);
+    c->card_unlink_slot = pa_hook_connect(&core->hooks[PA_CORE_HOOK_CARD_UNLINK],
+                                          PA_HOOK_NORMAL, card_unlink_cb, c);
+    c->sink_input_put_slot = pa_hook_connect(&core->hooks[PA_CORE_HOOK_SINK_INPUT_PUT],
+                                             PA_HOOK_NORMAL, sink_input_put_cb, c);
+    c->sink_input_unlink_slot = pa_hook_connect(&core->hooks[PA_CORE_HOOK_SINK_INPUT_UNLINK],
+                                                PA_HOOK_NORMAL, sink_input_unlink_cb, c);
+    c->source_output_put_slot = pa_hook_connect(&core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PUT],
+                                                PA_HOOK_NORMAL, source_output_put_cb, c);
+    c->source_output_unlink_slot = pa_hook_connect(&core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK],
+                                                   PA_HOOK_NORMAL, source_output_unlink_cb, c);
+    c->client_put_slot = pa_hook_connect(&core->hooks[PA_CORE_HOOK_CLIENT_PUT],
+                                         PA_HOOK_NORMAL, client_put_cb, c);
+    c->client_unlink_slot = pa_hook_connect(&core->hooks[PA_CORE_HOOK_CLIENT_UNLINK],
+                                            PA_HOOK_NORMAL, client_unlink_cb, c);
     c->sink_put_slot = pa_hook_connect(&core->hooks[PA_CORE_HOOK_SINK_PUT], PA_HOOK_NORMAL, sink_put_cb, c);
     c->sink_unlink_slot = pa_hook_connect(&core->hooks[PA_CORE_HOOK_SINK_UNLINK], PA_HOOK_NORMAL, sink_unlink_cb, c);
     c->source_put_slot = pa_hook_connect(&core->hooks[PA_CORE_HOOK_SOURCE_PUT], PA_HOOK_NORMAL, source_put_cb, c);
@@ -2107,6 +2204,14 @@ void pa_dbusiface_core_free(pa_dbusiface_core *c) {
     pa_hashmap_free(c->samples);
     pa_hashmap_free(c->modules);
     pa_hashmap_free(c->clients);
+    pa_hook_slot_free(c->card_put_slot);
+    pa_hook_slot_free(c->card_unlink_slot);
+    pa_hook_slot_free(c->sink_input_put_slot);
+    pa_hook_slot_free(c->sink_input_unlink_slot);
+    pa_hook_slot_free(c->source_output_put_slot);
+    pa_hook_slot_free(c->source_output_unlink_slot);
+    pa_hook_slot_free(c->client_put_slot);
+    pa_hook_slot_free(c->client_unlink_slot);
     pa_hook_slot_free(c->sink_put_slot);
     pa_hook_slot_free(c->sink_unlink_slot);
     pa_hook_slot_free(c->source_put_slot);

commit 297fdb5c2586a6bcd1274b7559e59b2cd55071ff
Author: Juho Hämäläinen <juho.hamalainen at tieto.com>
Date:   Thu Mar 19 13:50:49 2015 +0200

    namereg: Fire hooks for default sink and source changes

diff --git a/src/pulsecore/namereg.c b/src/pulsecore/namereg.c
index b2320c0..47bfc08 100644
--- a/src/pulsecore/namereg.c
+++ b/src/pulsecore/namereg.c
@@ -257,6 +257,7 @@ pa_sink* pa_namereg_set_default_sink(pa_core*c, pa_sink *s) {
 
     if (c->default_sink != s) {
         c->default_sink = s;
+        pa_hook_fire(&c->hooks[PA_CORE_HOOK_DEFAULT_SINK_CHANGED], c->default_sink);
         pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SERVER|PA_SUBSCRIPTION_EVENT_CHANGE, PA_INVALID_INDEX);
     }
 
@@ -271,6 +272,7 @@ pa_source* pa_namereg_set_default_source(pa_core*c, pa_source *s) {
 
     if (c->default_source != s) {
         c->default_source = s;
+        pa_hook_fire(&c->hooks[PA_CORE_HOOK_DEFAULT_SOURCE_CHANGED], c->default_source);
         pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SERVER|PA_SUBSCRIPTION_EVENT_CHANGE, PA_INVALID_INDEX);
     }
 

commit 88d672449370e83825797188abc1c9199c9c0281
Author: Juho Hämäläinen <juho.hamalainen at tieto.com>
Date:   Thu Mar 19 13:50:48 2015 +0200

    core: Add hooks for default sink and source changes

diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h
index 8570d47..9fefd1b 100644
--- a/src/pulsecore/core.h
+++ b/src/pulsecore/core.h
@@ -126,6 +126,8 @@ typedef enum pa_core_hook {
     PA_CORE_HOOK_CARD_PROFILE_AVAILABLE_CHANGED,
     PA_CORE_HOOK_PORT_AVAILABLE_CHANGED,
     PA_CORE_HOOK_PORT_LATENCY_OFFSET_CHANGED,
+    PA_CORE_HOOK_DEFAULT_SINK_CHANGED,
+    PA_CORE_HOOK_DEFAULT_SOURCE_CHANGED,
     PA_CORE_HOOK_MAX
 } pa_core_hook_t;
 

commit 86fcc3f44518d020f824d50b7806b48b891e9119
Author: Juho Hämäläinen <juho.hamalainen at tieto.com>
Date:   Thu Mar 19 13:50:46 2015 +0200

    dbus: Use state changed hook for sink-input and source-output rate changes

diff --git a/src/modules/dbus/iface-stream.c b/src/modules/dbus/iface-stream.c
index 566759e..ade62ca 100644
--- a/src/modules/dbus/iface-stream.c
+++ b/src/modules/dbus/iface-stream.c
@@ -62,6 +62,7 @@ struct pa_dbusiface_stream {
     pa_hook_slot *volume_changed_slot;
     pa_hook_slot *mute_changed_slot;
     pa_hook_slot *proplist_changed_slot;
+    pa_hook_slot *state_changed_slot;
 };
 
 static void handle_get_index(DBusConnection *conn, DBusMessage *msg, void *userdata);
@@ -830,6 +831,20 @@ static pa_hook_result_t proplist_changed_cb(void *hook_data, void *call_data, vo
     return PA_HOOK_OK;
 }
 
+static pa_hook_result_t state_changed_cb(void *hook_data, void *call_data, void *slot_data) {
+    pa_dbusiface_stream *s = slot_data;
+
+    pa_assert(s);
+
+    if ((s->type == STREAM_TYPE_PLAYBACK && s->sink_input != call_data) ||
+        (s->type == STREAM_TYPE_RECORD && s->source_output != call_data))
+        return PA_HOOK_OK;
+
+    check_and_signal_rate(s);
+
+    return PA_HOOK_OK;
+}
+
 static pa_hook_result_t send_event_cb(void *hook_data, void *call_data, void *slot_data) {
     pa_dbusiface_stream *s = slot_data;
     DBusMessage *signal_msg = NULL;
@@ -906,6 +921,8 @@ pa_dbusiface_stream *pa_dbusiface_stream_new_playback(pa_dbusiface_core *core, p
                                            PA_HOOK_NORMAL, mute_changed_cb, s);
     s->proplist_changed_slot = pa_hook_connect(&sink_input->core->hooks[PA_CORE_HOOK_SINK_INPUT_PROPLIST_CHANGED],
                                                PA_HOOK_NORMAL, proplist_changed_cb, s);
+    s->state_changed_slot = pa_hook_connect(&sink_input->core->hooks[PA_CORE_HOOK_SINK_INPUT_STATE_CHANGED],
+                                            PA_HOOK_NORMAL, state_changed_cb, s);
 
     pa_assert_se(pa_dbus_protocol_add_interface(s->dbus_protocol, s->path, &stream_interface_info, s) >= 0);
 
@@ -942,6 +959,8 @@ pa_dbusiface_stream *pa_dbusiface_stream_new_record(pa_dbusiface_core *core, pa_
                                            PA_HOOK_NORMAL, mute_changed_cb, s);
     s->proplist_changed_slot = pa_hook_connect(&source_output->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PROPLIST_CHANGED],
                                                PA_HOOK_NORMAL, proplist_changed_cb, s);
+    s->state_changed_slot = pa_hook_connect(&source_output->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_STATE_CHANGED],
+                                            PA_HOOK_NORMAL, state_changed_cb, s);
 
     pa_assert_se(pa_dbus_protocol_add_interface(s->dbus_protocol, s->path, &stream_interface_info, s) >= 0);
 
@@ -968,6 +987,7 @@ void pa_dbusiface_stream_free(pa_dbusiface_stream *s) {
     pa_hook_slot_free(s->volume_changed_slot);
     pa_hook_slot_free(s->mute_changed_slot);
     pa_hook_slot_free(s->proplist_changed_slot);
+    pa_hook_slot_free(s->state_changed_slot);
 
     pa_xfree(s->path);
     pa_xfree(s);

commit 7f83817eddc91f6a2f017e658c00625aeec65b2f
Author: Juho Hämäläinen <juho.hamalainen at tieto.com>
Date:   Thu Mar 19 13:50:45 2015 +0200

    dbus: Use hooks for sink-input and source-output events

diff --git a/src/modules/dbus/iface-stream.c b/src/modules/dbus/iface-stream.c
index 144817d..566759e 100644
--- a/src/modules/dbus/iface-stream.c
+++ b/src/modules/dbus/iface-stream.c
@@ -57,8 +57,11 @@ struct pa_dbusiface_stream {
     bool has_volume;
 
     pa_dbus_protocol *dbus_protocol;
-    pa_subscription *subscription;
     pa_hook_slot *send_event_slot;
+    pa_hook_slot *move_finish_slot;
+    pa_hook_slot *volume_changed_slot;
+    pa_hook_slot *mute_changed_slot;
+    pa_hook_slot *proplist_changed_slot;
 };
 
 static void handle_get_index(DBusConnection *conn, DBusMessage *msg, void *userdata);
@@ -657,28 +660,37 @@ static void handle_kill(DBusConnection *conn, DBusMessage *msg, void *userdata)
     pa_dbus_send_empty_reply(conn, msg);
 }
 
-static void subscription_cb(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) {
-    pa_dbusiface_stream *s = userdata;
+static void check_and_signal_rate(pa_dbusiface_stream *s) {
     DBusMessage *signal_msg = NULL;
-    const char *new_device_path = NULL;
     uint32_t new_sample_rate = 0;
-    pa_proplist *new_proplist = NULL;
-    unsigned i = 0;
 
-    pa_assert(c);
     pa_assert(s);
 
-    if ((s->type == STREAM_TYPE_PLAYBACK && idx != s->sink_input->index)
-        || (s->type == STREAM_TYPE_RECORD && idx != s->source_output->index))
-        return;
+    new_sample_rate = (s->type == STREAM_TYPE_PLAYBACK)
+                      ? s->sink_input->sample_spec.rate
+                      : s->source_output->sample_spec.rate;
 
-    if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) != PA_SUBSCRIPTION_EVENT_CHANGE)
-        return;
+    if (s->sample_rate != new_sample_rate) {
+        s->sample_rate = new_sample_rate;
 
-    pa_assert(((s->type == STREAM_TYPE_PLAYBACK)
-                && ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK_INPUT))
-              || ((s->type == STREAM_TYPE_RECORD)
-                   && ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT)));
+        pa_assert_se(signal_msg = dbus_message_new_signal(s->path,
+                                                          PA_DBUSIFACE_STREAM_INTERFACE,
+                                                          signals[SIGNAL_SAMPLE_RATE_UPDATED].name));
+        pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_UINT32, &s->sample_rate, DBUS_TYPE_INVALID));
+
+        pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg);
+        dbus_message_unref(signal_msg);
+    }
+}
+
+static pa_hook_result_t move_finish_cb(void *hook_data, void *call_data, void *slot_data) {
+    pa_dbusiface_stream *s = slot_data;
+    const char *new_device_path = NULL;
+    DBusMessage *signal_msg = NULL;
+
+    if ((s->type == STREAM_TYPE_PLAYBACK && s->sink_input != call_data) ||
+        (s->type == STREAM_TYPE_RECORD && s->source_output != call_data))
+        return PA_HOOK_OK;
 
     if (s->type == STREAM_TYPE_PLAYBACK) {
         pa_sink *new_sink = s->sink_input->sink;
@@ -696,7 +708,6 @@ static void subscription_cb(pa_core *c, pa_subscription_event_type_t t, uint32_t
 
             pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg);
             dbus_message_unref(signal_msg);
-            signal_msg = NULL;
         }
     } else {
         pa_source *new_source = s->source_output->source;
@@ -714,54 +725,62 @@ static void subscription_cb(pa_core *c, pa_subscription_event_type_t t, uint32_t
 
             pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg);
             dbus_message_unref(signal_msg);
-            signal_msg = NULL;
         }
     }
 
-    new_sample_rate = (s->type == STREAM_TYPE_PLAYBACK) ? s->sink_input->sample_spec.rate : s->source_output->sample_spec.rate;
-
-    if (s->sample_rate != new_sample_rate) {
-        s->sample_rate = new_sample_rate;
+    check_and_signal_rate(s);
 
-        pa_assert_se(signal_msg = dbus_message_new_signal(s->path,
-                                                          PA_DBUSIFACE_STREAM_INTERFACE,
-                                                          signals[SIGNAL_SAMPLE_RATE_UPDATED].name));
-        pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_UINT32, &s->sample_rate, DBUS_TYPE_INVALID));
+    return PA_HOOK_OK;
+}
 
-        pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg);
-        dbus_message_unref(signal_msg);
-        signal_msg = NULL;
-    }
+static pa_hook_result_t volume_changed_cb(void *hook_data, void *call_data, void *slot_data) {
+    pa_dbusiface_stream *s = slot_data;
+    DBusMessage *signal_msg = NULL;
+    unsigned i = 0;
 
-    if (s->type == STREAM_TYPE_PLAYBACK) {
-        bool new_mute = false;
+    if ((s->type == STREAM_TYPE_PLAYBACK && s->sink_input != call_data) ||
+        (s->type == STREAM_TYPE_RECORD && s->source_output != call_data))
+        return PA_HOOK_OK;
 
-        if (s->has_volume) {
-            pa_cvolume new_volume;
+    if (s->type == STREAM_TYPE_PLAYBACK && s->has_volume) {
+        pa_cvolume new_volume;
 
-            pa_sink_input_get_volume(s->sink_input, &new_volume, true);
+        pa_sink_input_get_volume(s->sink_input, &new_volume, true);
 
-            if (!pa_cvolume_equal(&s->volume, &new_volume)) {
-                dbus_uint32_t volume[PA_CHANNELS_MAX];
-                dbus_uint32_t *volume_ptr = volume;
+        if (!pa_cvolume_equal(&s->volume, &new_volume)) {
+            dbus_uint32_t volume[PA_CHANNELS_MAX];
+            dbus_uint32_t *volume_ptr = volume;
 
-                s->volume = new_volume;
+            s->volume = new_volume;
 
-                for (i = 0; i < s->volume.channels; ++i)
-                    volume[i] = s->volume.values[i];
+            for (i = 0; i < s->volume.channels; ++i)
+                volume[i] = s->volume.values[i];
 
-                pa_assert_se(signal_msg = dbus_message_new_signal(s->path,
-                                                                  PA_DBUSIFACE_STREAM_INTERFACE,
-                                                                  signals[SIGNAL_VOLUME_UPDATED].name));
-                pa_assert_se(dbus_message_append_args(signal_msg,
-                                                      DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &volume_ptr, s->volume.channels,
-                                                      DBUS_TYPE_INVALID));
+            pa_assert_se(signal_msg = dbus_message_new_signal(s->path,
+                                                              PA_DBUSIFACE_STREAM_INTERFACE,
+                                                              signals[SIGNAL_VOLUME_UPDATED].name));
+            pa_assert_se(dbus_message_append_args(signal_msg,
+                                                  DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &volume_ptr, s->volume.channels,
+                                                  DBUS_TYPE_INVALID));
 
-                pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg);
-                dbus_message_unref(signal_msg);
-                signal_msg = NULL;
-            }
+            pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg);
+            dbus_message_unref(signal_msg);
         }
+    }
+
+    return PA_HOOK_OK;
+}
+
+static pa_hook_result_t mute_changed_cb(void *hook_data, void *call_data, void *slot_data) {
+    pa_dbusiface_stream *s = slot_data;
+    DBusMessage *signal_msg = NULL;
+
+    if ((s->type == STREAM_TYPE_PLAYBACK && s->sink_input != call_data) ||
+        (s->type == STREAM_TYPE_RECORD && s->source_output != call_data))
+        return PA_HOOK_OK;
+
+    if (s->type == STREAM_TYPE_PLAYBACK) {
+        bool new_mute = false;
 
         new_mute = s->sink_input->muted;
 
@@ -779,6 +798,18 @@ static void subscription_cb(pa_core *c, pa_subscription_event_type_t t, uint32_t
         }
     }
 
+    return PA_HOOK_OK;
+}
+
+static pa_hook_result_t proplist_changed_cb(void *hook_data, void *call_data, void *slot_data) {
+    pa_dbusiface_stream *s = slot_data;
+    DBusMessage *signal_msg = NULL;
+    pa_proplist *new_proplist = NULL;
+
+    if ((s->type == STREAM_TYPE_PLAYBACK && s->sink_input != call_data) ||
+        (s->type == STREAM_TYPE_RECORD && s->source_output != call_data))
+        return PA_HOOK_OK;
+
     new_proplist = (s->type == STREAM_TYPE_PLAYBACK) ? s->sink_input->proplist : s->source_output->proplist;
 
     if (!pa_proplist_equal(s->proplist, new_proplist)) {
@@ -794,8 +825,9 @@ static void subscription_cb(pa_core *c, pa_subscription_event_type_t t, uint32_t
 
         pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg);
         dbus_message_unref(signal_msg);
-        signal_msg = NULL;
     }
+
+    return PA_HOOK_OK;
 }
 
 static pa_hook_result_t send_event_cb(void *hook_data, void *call_data, void *slot_data) {
@@ -862,11 +894,18 @@ pa_dbusiface_stream *pa_dbusiface_stream_new_playback(pa_dbusiface_core *core, p
     s->mute = sink_input->muted;
     s->proplist = pa_proplist_copy(sink_input->proplist);
     s->dbus_protocol = pa_dbus_protocol_get(sink_input->core);
-    s->subscription = pa_subscription_new(sink_input->core, PA_SUBSCRIPTION_MASK_SINK_INPUT, subscription_cb, s);
     s->send_event_slot = pa_hook_connect(&sink_input->core->hooks[PA_CORE_HOOK_SINK_INPUT_SEND_EVENT],
                                          PA_HOOK_NORMAL,
                                          send_event_cb,
                                          s);
+    s->move_finish_slot = pa_hook_connect(&sink_input->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE_FINISH],
+                                          PA_HOOK_NORMAL, move_finish_cb, s);
+    s->volume_changed_slot = pa_hook_connect(&sink_input->core->hooks[PA_CORE_HOOK_SINK_INPUT_VOLUME_CHANGED],
+                                             PA_HOOK_NORMAL, volume_changed_cb, s);
+    s->mute_changed_slot = pa_hook_connect(&sink_input->core->hooks[PA_CORE_HOOK_SINK_INPUT_MUTE_CHANGED],
+                                           PA_HOOK_NORMAL, mute_changed_cb, s);
+    s->proplist_changed_slot = pa_hook_connect(&sink_input->core->hooks[PA_CORE_HOOK_SINK_INPUT_PROPLIST_CHANGED],
+                                               PA_HOOK_NORMAL, proplist_changed_cb, s);
 
     pa_assert_se(pa_dbus_protocol_add_interface(s->dbus_protocol, s->path, &stream_interface_info, s) >= 0);
 
@@ -891,11 +930,18 @@ pa_dbusiface_stream *pa_dbusiface_stream_new_record(pa_dbusiface_core *core, pa_
     s->proplist = pa_proplist_copy(source_output->proplist);
     s->has_volume = false;
     s->dbus_protocol = pa_dbus_protocol_get(source_output->core);
-    s->subscription = pa_subscription_new(source_output->core, PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT, subscription_cb, s);
     s->send_event_slot = pa_hook_connect(&source_output->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_SEND_EVENT],
                                          PA_HOOK_NORMAL,
                                          send_event_cb,
                                          s);
+    s->move_finish_slot = pa_hook_connect(&source_output->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_FINISH],
+                                          PA_HOOK_NORMAL, move_finish_cb, s);
+    s->volume_changed_slot = pa_hook_connect(&source_output->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_VOLUME_CHANGED],
+                                             PA_HOOK_NORMAL, volume_changed_cb, s);
+    s->mute_changed_slot = pa_hook_connect(&source_output->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MUTE_CHANGED],
+                                           PA_HOOK_NORMAL, mute_changed_cb, s);
+    s->proplist_changed_slot = pa_hook_connect(&source_output->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PROPLIST_CHANGED],
+                                               PA_HOOK_NORMAL, proplist_changed_cb, s);
 
     pa_assert_se(pa_dbus_protocol_add_interface(s->dbus_protocol, s->path, &stream_interface_info, s) >= 0);
 
@@ -917,8 +963,11 @@ void pa_dbusiface_stream_free(pa_dbusiface_stream *s) {
 
     pa_proplist_free(s->proplist);
     pa_dbus_protocol_unref(s->dbus_protocol);
-    pa_subscription_free(s->subscription);
     pa_hook_slot_free(s->send_event_slot);
+    pa_hook_slot_free(s->move_finish_slot);
+    pa_hook_slot_free(s->volume_changed_slot);
+    pa_hook_slot_free(s->mute_changed_slot);
+    pa_hook_slot_free(s->proplist_changed_slot);
 
     pa_xfree(s->path);
     pa_xfree(s);

commit 5087af78d50409ddcb9ef33b7c2df8896b4cb96d
Author: Juho Hämäläinen <juho.hamalainen at tieto.com>
Date:   Thu Mar 19 13:50:44 2015 +0200

    dbus: Use hooks for sink and source events

diff --git a/src/modules/dbus/iface-device.c b/src/modules/dbus/iface-device.c
index efa4141..2c370a8 100644
--- a/src/modules/dbus/iface-device.c
+++ b/src/modules/dbus/iface-device.c
@@ -94,8 +94,13 @@ struct pa_dbusiface_device {
     pa_device_port *active_port;
     pa_proplist *proplist;
 
+    pa_hook_slot *volume_changed_slot;
+    pa_hook_slot *mute_changed_slot;
+    pa_hook_slot *state_changed_slot;
+    pa_hook_slot *port_changed_slot;
+    pa_hook_slot *proplist_changed_slot;
+
     pa_dbus_protocol *dbus_protocol;
-    pa_subscription *subscription;
 };
 
 enum property_handler_index {
@@ -1077,30 +1082,15 @@ static void handle_source_get_all(DBusConnection *conn, DBusMessage *msg, void *
     dbus_message_unref(reply);
 }
 
-static void subscription_cb(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) {
-    pa_dbusiface_device *d = userdata;
+static pa_hook_result_t volume_changed_cb(void *hook_data, void *call_data, void *slot_data) {
+    pa_dbusiface_device *d = slot_data;
     DBusMessage *signal_msg = NULL;
     const pa_cvolume *new_volume = NULL;
-    bool new_mute = false;
-    pa_sink_state_t new_sink_state = 0;
-    pa_source_state_t new_source_state = 0;
-    pa_device_port *new_active_port = NULL;
-    pa_proplist *new_proplist = NULL;
     unsigned i = 0;
 
-    pa_assert(c);
-    pa_assert(d);
-
-    if ((d->type == PA_DEVICE_TYPE_SINK && idx != d->sink->index) || (d->type == PA_DEVICE_TYPE_SOURCE && idx != d->source->index))
-        return;
-
-    if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) != PA_SUBSCRIPTION_EVENT_CHANGE)
-        return;
-
-    pa_assert(((d->type == PA_DEVICE_TYPE_SINK)
-                && ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK))
-              || ((d->type == PA_DEVICE_TYPE_SOURCE)
-                   && ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE)));
+    if ((d->type == PA_DEVICE_TYPE_SINK && d->sink != call_data) ||
+        (d->type == PA_DEVICE_TYPE_SOURCE && d->source != call_data))
+        return PA_HOOK_OK;
 
     new_volume = (d->type == PA_DEVICE_TYPE_SINK)
                  ? pa_sink_get_volume(d->sink, false)
@@ -1124,10 +1114,23 @@ static void subscription_cb(pa_core *c, pa_subscription_event_type_t t, uint32_t
 
         pa_dbus_protocol_send_signal(d->dbus_protocol, signal_msg);
         dbus_message_unref(signal_msg);
-        signal_msg = NULL;
     }
 
-    new_mute = (d->type == PA_DEVICE_TYPE_SINK) ? pa_sink_get_mute(d->sink, false) : pa_source_get_mute(d->source, false);
+    return PA_HOOK_OK;
+}
+
+static pa_hook_result_t mute_changed_cb(void *hook_data, void *call_data, void *slot_data) {
+    pa_dbusiface_device *d = slot_data;
+    DBusMessage *signal_msg = NULL;
+    bool new_mute = false;
+
+    if ((d->type == PA_DEVICE_TYPE_SINK && d->sink != call_data) ||
+        (d->type == PA_DEVICE_TYPE_SOURCE && d->source != call_data))
+        return PA_HOOK_OK;
+
+    new_mute = (d->type == PA_DEVICE_TYPE_SINK)
+               ? pa_sink_get_mute(d->sink, false)
+               : pa_source_get_mute(d->source, false);
 
     if (d->mute != new_mute) {
         d->mute = new_mute;
@@ -1139,9 +1142,21 @@ static void subscription_cb(pa_core *c, pa_subscription_event_type_t t, uint32_t
 
         pa_dbus_protocol_send_signal(d->dbus_protocol, signal_msg);
         dbus_message_unref(signal_msg);
-        signal_msg = NULL;
     }
 
+    return PA_HOOK_OK;
+}
+
+static pa_hook_result_t state_changed_cb(void *hook_data, void *call_data, void *slot_data) {
+    pa_dbusiface_device *d = slot_data;
+    DBusMessage *signal_msg = NULL;
+    pa_sink_state_t new_sink_state = 0;
+    pa_source_state_t new_source_state = 0;
+
+    if ((d->type == PA_DEVICE_TYPE_SINK && d->sink != call_data) ||
+        (d->type == PA_DEVICE_TYPE_SOURCE && d->source != call_data))
+        return PA_HOOK_OK;
+
     if (d->type == PA_DEVICE_TYPE_SINK)
         new_sink_state = pa_sink_get_state(d->sink);
     else
@@ -1165,9 +1180,20 @@ static void subscription_cb(pa_core *c, pa_subscription_event_type_t t, uint32_t
 
         pa_dbus_protocol_send_signal(d->dbus_protocol, signal_msg);
         dbus_message_unref(signal_msg);
-        signal_msg = NULL;
     }
 
+    return PA_HOOK_OK;
+}
+
+static pa_hook_result_t port_changed_cb(void *hook_data, void *call_data, void *slot_data) {
+    pa_dbusiface_device *d = slot_data;
+    DBusMessage *signal_msg = NULL;
+    pa_device_port *new_active_port = NULL;
+
+    if ((d->type == PA_DEVICE_TYPE_SINK && d->sink != call_data) ||
+        (d->type == PA_DEVICE_TYPE_SOURCE && d->source != call_data))
+        return PA_HOOK_OK;
+
     new_active_port = (d->type == PA_DEVICE_TYPE_SINK) ? d->sink->active_port : d->source->active_port;
 
     if (d->active_port != new_active_port) {
@@ -1183,9 +1209,20 @@ static void subscription_cb(pa_core *c, pa_subscription_event_type_t t, uint32_t
 
         pa_dbus_protocol_send_signal(d->dbus_protocol, signal_msg);
         dbus_message_unref(signal_msg);
-        signal_msg = NULL;
     }
 
+    return PA_HOOK_OK;
+}
+
+static pa_hook_result_t proplist_changed_cb(void *hook_data, void *call_data, void *slot_data) {
+    pa_dbusiface_device *d = slot_data;
+    DBusMessage *signal_msg = NULL;
+    pa_proplist *new_proplist = NULL;
+
+    if ((d->type == PA_DEVICE_TYPE_SINK && d->sink != call_data) ||
+        (d->type == PA_DEVICE_TYPE_SOURCE && d->source != call_data))
+        return PA_HOOK_OK;
+
     new_proplist = (d->type == PA_DEVICE_TYPE_SINK) ? d->sink->proplist : d->source->proplist;
 
     if (!pa_proplist_equal(d->proplist, new_proplist)) {
@@ -1201,8 +1238,9 @@ static void subscription_cb(pa_core *c, pa_subscription_event_type_t t, uint32_t
 
         pa_dbus_protocol_send_signal(d->dbus_protocol, signal_msg);
         dbus_message_unref(signal_msg);
-        signal_msg = NULL;
     }
+
+    return PA_HOOK_OK;
 }
 
 pa_dbusiface_device *pa_dbusiface_device_new_sink(pa_dbusiface_core *core, pa_sink *sink) {
@@ -1226,7 +1264,16 @@ pa_dbusiface_device *pa_dbusiface_device_new_sink(pa_dbusiface_core *core, pa_si
     d->active_port = sink->active_port;
     d->proplist = pa_proplist_copy(sink->proplist);
     d->dbus_protocol = pa_dbus_protocol_get(sink->core);
-    d->subscription = pa_subscription_new(sink->core, PA_SUBSCRIPTION_MASK_SINK, subscription_cb, d);
+    d->volume_changed_slot = pa_hook_connect(&sink->core->hooks[PA_CORE_HOOK_SINK_VOLUME_CHANGED],
+                                             PA_HOOK_NORMAL, volume_changed_cb, d);
+    d->mute_changed_slot = pa_hook_connect(&sink->core->hooks[PA_CORE_HOOK_SINK_MUTE_CHANGED],
+                                           PA_HOOK_NORMAL, mute_changed_cb, d);
+    d->state_changed_slot = pa_hook_connect(&sink->core->hooks[PA_CORE_HOOK_SINK_STATE_CHANGED],
+                                            PA_HOOK_NORMAL, state_changed_cb, d);
+    d->port_changed_slot = pa_hook_connect(&sink->core->hooks[PA_CORE_HOOK_SINK_PORT_CHANGED],
+                                           PA_HOOK_NORMAL, port_changed_cb, d);
+    d->proplist_changed_slot = pa_hook_connect(&sink->core->hooks[PA_CORE_HOOK_SINK_PROPLIST_CHANGED],
+                                               PA_HOOK_NORMAL, proplist_changed_cb, d);
 
     PA_HASHMAP_FOREACH(port, sink->ports, state) {
         pa_dbusiface_device_port *p = pa_dbusiface_device_port_new(d, sink->core, port, d->next_port_index++);
@@ -1260,7 +1307,16 @@ pa_dbusiface_device *pa_dbusiface_device_new_source(pa_dbusiface_core *core, pa_
     d->active_port = source->active_port;
     d->proplist = pa_proplist_copy(source->proplist);
     d->dbus_protocol = pa_dbus_protocol_get(source->core);
-    d->subscription = pa_subscription_new(source->core, PA_SUBSCRIPTION_MASK_SOURCE, subscription_cb, d);
+    d->volume_changed_slot = pa_hook_connect(&source->core->hooks[PA_CORE_HOOK_SOURCE_VOLUME_CHANGED],
+                                             PA_HOOK_NORMAL, volume_changed_cb, d);
+    d->mute_changed_slot = pa_hook_connect(&source->core->hooks[PA_CORE_HOOK_SOURCE_MUTE_CHANGED],
+                                           PA_HOOK_NORMAL, mute_changed_cb, d);
+    d->state_changed_slot = pa_hook_connect(&source->core->hooks[PA_CORE_HOOK_SOURCE_STATE_CHANGED],
+                                            PA_HOOK_NORMAL, state_changed_cb, d);
+    d->port_changed_slot = pa_hook_connect(&source->core->hooks[PA_CORE_HOOK_SOURCE_PORT_CHANGED],
+                                           PA_HOOK_NORMAL, port_changed_cb, d);
+    d->proplist_changed_slot = pa_hook_connect(&source->core->hooks[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED],
+                                               PA_HOOK_NORMAL, proplist_changed_cb, d);
 
     PA_HASHMAP_FOREACH(port, source->ports, state) {
         pa_dbusiface_device_port *p = pa_dbusiface_device_port_new(d, source->core, port, d->next_port_index++);
@@ -1276,6 +1332,12 @@ pa_dbusiface_device *pa_dbusiface_device_new_source(pa_dbusiface_core *core, pa_
 void pa_dbusiface_device_free(pa_dbusiface_device *d) {
     pa_assert(d);
 
+    pa_hook_slot_free(d->volume_changed_slot);
+    pa_hook_slot_free(d->mute_changed_slot);
+    pa_hook_slot_free(d->state_changed_slot);
+    pa_hook_slot_free(d->port_changed_slot);
+    pa_hook_slot_free(d->proplist_changed_slot);
+
     pa_assert_se(pa_dbus_protocol_remove_interface(d->dbus_protocol, d->path, device_interface_info.name) >= 0);
 
     if (d->type == PA_DEVICE_TYPE_SINK) {
@@ -1289,7 +1351,6 @@ void pa_dbusiface_device_free(pa_dbusiface_device *d) {
     pa_hashmap_free(d->ports);
     pa_proplist_free(d->proplist);
     pa_dbus_protocol_unref(d->dbus_protocol);
-    pa_subscription_free(d->subscription);
 
     pa_xfree(d->path);
     pa_xfree(d);

commit 36c3f01cb2d5053bf3ed353fa70f1330608ef646
Author: Juho Hämäläinen <juho.hamalainen at tieto.com>
Date:   Thu Mar 19 13:50:43 2015 +0200

    dbus: Use hooks for client proplist changes

diff --git a/src/modules/dbus/iface-client.c b/src/modules/dbus/iface-client.c
index 76ad427..455ea45 100644
--- a/src/modules/dbus/iface-client.c
+++ b/src/modules/dbus/iface-client.c
@@ -39,8 +39,9 @@ struct pa_dbusiface_client {
     char *path;
     pa_proplist *proplist;
 
+    pa_hook_slot *client_proplist_changed_slot;
+
     pa_dbus_protocol *dbus_protocol;
-    pa_subscription *subscription;
 };
 
 static void handle_get_index(DBusConnection *conn, DBusMessage *msg, void *userdata);
@@ -381,27 +382,24 @@ static void handle_remove_properties(DBusConnection *conn, DBusMessage *msg, voi
 
     pa_dbus_send_empty_reply(conn, msg);
 
-    if (changed)
+    if (changed) {
+        pa_hook_fire(&c->client->core->hooks[PA_CORE_HOOK_CLIENT_PROPLIST_CHANGED], c->client);
         pa_subscription_post(c->client->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_CHANGE, c->client->index);
+    }
 
     dbus_free_string_array(keys);
 }
 
-static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint32_t idx, void *userdata) {
-    pa_dbusiface_client *c = userdata;
-    DBusMessage *signal_msg = NULL;
+static pa_hook_result_t client_proplist_changed_cb(void *hook_data, void *call_data, void *slot_data) {
+    pa_dbusiface_client *c = slot_data;
+    pa_client *client = call_data;
+    DBusMessage *signal_msg;
 
-    pa_assert(core);
-    pa_assert((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_CLIENT);
     pa_assert(c);
+    pa_assert(client);
 
-    /* We can't use idx != c->client->index, because the c->client pointer may
-     * be stale at this point. */
-    if (pa_idxset_get_by_index(core->clients, idx) != c->client)
-        return;
-
-    if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) != PA_SUBSCRIPTION_EVENT_CHANGE)
-        return;
+    if (c->client != client)
+        return PA_HOOK_OK;
 
     if (!pa_proplist_equal(c->proplist, c->client->proplist)) {
         DBusMessageIter msg_iter;
@@ -416,8 +414,9 @@ static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint3
 
         pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg);
         dbus_message_unref(signal_msg);
-        signal_msg = NULL;
     }
+
+    return PA_HOOK_OK;
 }
 
 pa_dbusiface_client *pa_dbusiface_client_new(pa_dbusiface_core *core, pa_client *client) {
@@ -432,7 +431,8 @@ pa_dbusiface_client *pa_dbusiface_client_new(pa_dbusiface_core *core, pa_client
     c->path = pa_sprintf_malloc("%s/%s%u", PA_DBUS_CORE_OBJECT_PATH, OBJECT_NAME, client->index);
     c->proplist = pa_proplist_copy(client->proplist);
     c->dbus_protocol = pa_dbus_protocol_get(client->core);
-    c->subscription = pa_subscription_new(client->core, PA_SUBSCRIPTION_MASK_CLIENT, subscription_cb, c);
+    c->client_proplist_changed_slot = pa_hook_connect(&client->core->hooks[PA_CORE_HOOK_CLIENT_PROPLIST_CHANGED],
+                                                      PA_HOOK_NORMAL, client_proplist_changed_cb, c);
 
     pa_assert_se(pa_dbus_protocol_add_interface(c->dbus_protocol, c->path, &client_interface_info, c) >= 0);
 
@@ -444,9 +444,9 @@ void pa_dbusiface_client_free(pa_dbusiface_client *c) {
 
     pa_assert_se(pa_dbus_protocol_remove_interface(c->dbus_protocol, c->path, client_interface_info.name) >= 0);
 
+    pa_hook_slot_free(c->client_proplist_changed_slot);
     pa_proplist_free(c->proplist);
     pa_dbus_protocol_unref(c->dbus_protocol);
-    pa_subscription_free(c->subscription);
 
     pa_xfree(c->path);
     pa_xfree(c);

commit c324255e3ead80e85f873b0995f5ddc9a2904454
Author: Juho Hämäläinen <juho.hamalainen at tieto.com>
Date:   Thu Mar 19 13:50:42 2015 +0200

    dbus: Use hooks for card profile events

diff --git a/src/modules/dbus/iface-card.c b/src/modules/dbus/iface-card.c
index da975c8..d0f13c9 100644
--- a/src/modules/dbus/iface-card.c
+++ b/src/modules/dbus/iface-card.c
@@ -59,9 +59,9 @@ struct pa_dbusiface_card {
     pa_proplist *proplist;
 
     pa_hook_slot *card_profile_added_slot;
+    pa_hook_slot *card_profile_changed_slot;
 
     pa_dbus_protocol *dbus_protocol;
-    pa_subscription *subscription;
 };
 
 enum property_handler_index {
@@ -432,37 +432,8 @@ static void handle_get_profile_by_name(DBusConnection *conn, DBusMessage *msg, v
     pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &profile_path);
 }
 
-static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint32_t idx, void *userdata) {
-    pa_dbusiface_card *c = userdata;
-    DBusMessage *signal_msg = NULL;
-
-    pa_assert(core);
-    pa_assert((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_CARD);
-    pa_assert(c);
-
-    /* We can't use idx != c->card->index, because the c->card pointer may
-     * be stale at this point. */
-    if (pa_idxset_get_by_index(core->cards, idx) != c->card)
-        return;
-
-    if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) != PA_SUBSCRIPTION_EVENT_CHANGE)
-        return;
-
-    if (c->active_profile != c->card->active_profile) {
-        const char *object_path;
-
-        c->active_profile = c->card->active_profile;
-        object_path = pa_dbusiface_card_profile_get_path(pa_hashmap_get(c->profiles, c->active_profile->name));
-
-        pa_assert_se(signal_msg = dbus_message_new_signal(c->path,
-                                                          PA_DBUSIFACE_CARD_INTERFACE,
-                                                          signals[SIGNAL_ACTIVE_PROFILE_UPDATED].name));
-        pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
-
-        pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg);
-        dbus_message_unref(signal_msg);
-        signal_msg = NULL;
-    }
+static void check_card_proplist(pa_dbusiface_card *c) {
+    DBusMessage *signal_msg;
 
     if (!pa_proplist_equal(c->proplist, c->card->proplist)) {
         DBusMessageIter msg_iter;
@@ -477,10 +448,35 @@ static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint3
 
         pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg);
         dbus_message_unref(signal_msg);
-        signal_msg = NULL;
     }
 }
 
+static pa_hook_result_t card_profile_changed_cb(void *hook_data, void *call_data, void *slot_data) {
+    pa_dbusiface_card *c = slot_data;
+    pa_card_profile *profile = call_data;
+    const char *object_path;
+    DBusMessage *signal_msg;
+
+    if (profile->card != c->card)
+        return PA_HOOK_OK;
+
+    c->active_profile = c->card->active_profile;
+
+    object_path = pa_dbusiface_card_profile_get_path(pa_hashmap_get(c->profiles, c->active_profile->name));
+
+    pa_assert_se(signal_msg = dbus_message_new_signal(c->path,
+                                                      PA_DBUSIFACE_CARD_INTERFACE,
+                                                      signals[SIGNAL_ACTIVE_PROFILE_UPDATED].name));
+    pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
+
+    pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg);
+    dbus_message_unref(signal_msg);
+
+    check_card_proplist(c);
+
+    return PA_HOOK_OK;
+}
+
 static pa_hook_result_t card_profile_added_cb(void *hook_data, void *call_data, void *slot_data) {
     pa_core *core = hook_data;
     pa_dbusiface_card *c = slot_data;
@@ -506,6 +502,8 @@ static pa_hook_result_t card_profile_added_cb(void *hook_data, void *call_data,
     pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg);
     dbus_message_unref(signal_msg);
 
+    check_card_proplist(c);
+
     return PA_HOOK_OK;
 }
 
@@ -527,7 +525,6 @@ pa_dbusiface_card *pa_dbusiface_card_new(pa_dbusiface_core *core, pa_card *card)
     c->active_profile = card->active_profile;
     c->proplist = pa_proplist_copy(card->proplist);
     c->dbus_protocol = pa_dbus_protocol_get(card->core);
-    c->subscription = pa_subscription_new(card->core, PA_SUBSCRIPTION_MASK_CARD, subscription_cb, c);
 
     PA_HASHMAP_FOREACH(profile, card->profiles, state) {
         pa_dbusiface_card_profile *p = pa_dbusiface_card_profile_new(c, card->core, profile, c->next_profile_index++);
@@ -536,6 +533,8 @@ pa_dbusiface_card *pa_dbusiface_card_new(pa_dbusiface_core *core, pa_card *card)
 
     pa_assert_se(pa_dbus_protocol_add_interface(c->dbus_protocol, c->path, &card_interface_info, c) >= 0);
 
+    c->card_profile_changed_slot = pa_hook_connect(&card->core->hooks[PA_CORE_HOOK_CARD_PROFILE_CHANGED], PA_HOOK_NORMAL,
+                                                   card_profile_changed_cb, c);
     c->card_profile_added_slot = pa_hook_connect(&card->core->hooks[PA_CORE_HOOK_CARD_PROFILE_ADDED], PA_HOOK_NORMAL,
                                                  card_profile_added_cb, c);
 
@@ -548,11 +547,11 @@ void pa_dbusiface_card_free(pa_dbusiface_card *c) {
     pa_assert_se(pa_dbus_protocol_remove_interface(c->dbus_protocol, c->path, card_interface_info.name) >= 0);
 
     pa_hook_slot_free(c->card_profile_added_slot);
+    pa_hook_slot_free(c->card_profile_changed_slot);
 
     pa_hashmap_free(c->profiles);
     pa_proplist_free(c->proplist);
     pa_dbus_protocol_unref(c->dbus_protocol);
-    pa_subscription_free(c->subscription);
 
     pa_xfree(c->path);
     pa_xfree(c);



More information about the pulseaudio-commits mailing list