]> code.delx.au - pulseaudio/blobdiff - src/modules/dbus/iface-core.c
dbusiface-module: Implement the Module D-Bus interface.
[pulseaudio] / src / modules / dbus / iface-core.c
index 695e4a3cfbae92ed0019b8a9323c1eb11a059479..9e8f775e6a9b2538529ac56c46861d4b1e3ae6e2 100644 (file)
 #include "iface-card.h"
 #include "iface-client.h"
 #include "iface-device.h"
+#include "iface-memstats.h"
 #include "iface-module.h"
 #include "iface-sample.h"
 #include "iface-stream.h"
 
 #include "iface-core.h"
 
-#define OBJECT_PATH "/org/pulseaudio/core1"
-
 #define INTERFACE_REVISION 0
 
-
-
 static void handle_get_interface_revision(DBusConnection *conn, DBusMessage *msg, void *userdata);
 static void handle_get_name(DBusConnection *conn, DBusMessage *msg, void *userdata);
 static void handle_get_version(DBusConnection *conn, DBusMessage *msg, void *userdata);
@@ -114,6 +111,8 @@ struct pa_dbusiface_core {
 
     pa_hook_slot *extension_registered_slot;
     pa_hook_slot *extension_unregistered_slot;
+
+    pa_dbusiface_memstats *memstats;
 };
 
 enum property_handler_index {
@@ -311,7 +310,7 @@ static pa_dbus_signal_info signals[SIGNAL_MAX] = {
 };
 
 static pa_dbus_interface_info core_interface_info = {
-    .name = PA_DBUSIFACE_CORE_INTERFACE,
+    .name = PA_DBUS_CORE_INTERFACE,
     .method_handlers = method_handlers,
     .n_method_handlers = METHOD_HANDLER_MAX,
     .property_handlers = property_handlers,
@@ -451,7 +450,8 @@ static void handle_set_default_channels(DBusConnection *conn, DBusMessage *msg,
     }
 
     if (n_channels > PA_CHANNELS_MAX) {
-        pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "Too many channels: %u. The maximum number of channels is %u.", n_channels, PA_CHANNELS_MAX);
+        pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS,
+                           "Too many channels: %u. The maximum number of channels is %u.", n_channels, PA_CHANNELS_MAX);
         return;
     }
 
@@ -543,7 +543,7 @@ static void handle_set_default_sample_rate(DBusConnection *conn, DBusMessage *ms
 /* The caller frees the array, but not the strings. */
 static const char **get_cards(pa_dbusiface_core *c, unsigned *n) {
     const char **cards;
-    unsigned i;
+    unsigned i = 0;
     void *state = NULL;
     pa_dbusiface_card *card;
 
@@ -557,10 +557,8 @@ static const char **get_cards(pa_dbusiface_core *c, unsigned *n) {
 
     cards = pa_xnew(const char *, *n);
 
-    for (i = 0, card = pa_hashmap_iterate(c->cards, &state, NULL); card; ++i, card = pa_hashmap_iterate(c->cards, &state, NULL))
-        cards[i] = pa_dbusiface_card_get_path(card);
-
-    pa_assert(i == *n);
+    PA_HASHMAP_FOREACH(card, c->cards, state)
+        cards[i++] = pa_dbusiface_card_get_path(card);
 
     return cards;
 }
@@ -584,7 +582,7 @@ static void handle_get_cards(DBusConnection *conn, DBusMessage *msg, void *userd
 /* The caller frees the array, but not the strings. */
 static const char **get_sinks(pa_dbusiface_core *c, unsigned *n) {
     const char **sinks;
-    unsigned i;
+    unsigned i = 0;
     void *state = NULL;
     pa_dbusiface_device *sink;
 
@@ -598,10 +596,8 @@ static const char **get_sinks(pa_dbusiface_core *c, unsigned *n) {
 
     sinks = pa_xnew(const char *, *n);
 
-    for (i = 0, sink = pa_hashmap_iterate(c->sinks_by_index, &state, NULL); sink; ++i, sink = pa_hashmap_iterate(c->sinks_by_index, &state, NULL))
-        sinks[i] = pa_dbusiface_device_get_path(sink);
-
-    pa_assert(i == *n);
+    PA_HASHMAP_FOREACH(sink, c->sinks_by_index, state)
+        sinks[i++] = pa_dbusiface_device_get_path(sink);
 
     return sinks;
 }
@@ -632,7 +628,8 @@ static void handle_get_fallback_sink(DBusConnection *conn, DBusMessage *msg, voi
     pa_assert(c);
 
     if (!c->fallback_sink) {
-        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "There are no sinks, and therefore no fallback sink either.");
+        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY,
+                           "There are no sinks, and therefore no fallback sink either.");
         return;
     }
 
@@ -652,7 +649,8 @@ static void handle_set_fallback_sink(DBusConnection *conn, DBusMessage *msg, voi
     pa_assert(c);
 
     if (!c->fallback_sink) {
-        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "There are no sinks, and therefore no fallback sink either.");
+        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY,
+                           "There are no sinks, and therefore no fallback sink either.");
         return;
     }
 
@@ -660,7 +658,7 @@ static void handle_set_fallback_sink(DBusConnection *conn, DBusMessage *msg, voi
         return;
 
     if (!(fallback_sink = pa_hashmap_get(c->sinks_by_path, object_path))) {
-        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NOT_FOUND, "No such sink.");
+        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NOT_FOUND, "%s: No such sink.", object_path);
         return;
     }
 
@@ -672,7 +670,7 @@ static void handle_set_fallback_sink(DBusConnection *conn, DBusMessage *msg, voi
 /* The caller frees the array, but not the strings. */
 static const char **get_sources(pa_dbusiface_core *c, unsigned *n) {
     const char **sources;
-    unsigned i;
+    unsigned i = 0;
     void *state = NULL;
     pa_dbusiface_device *source;
 
@@ -686,10 +684,8 @@ static const char **get_sources(pa_dbusiface_core *c, unsigned *n) {
 
     sources = pa_xnew(const char *, *n);
 
-    for (i = 0, source = pa_hashmap_iterate(c->sources_by_index, &state, NULL); source; ++i, source = pa_hashmap_iterate(c->sources_by_index, &state, NULL))
-        sources[i] = pa_dbusiface_device_get_path(source);
-
-    pa_assert(i == *n);
+    PA_HASHMAP_FOREACH(source, c->sources_by_index, state)
+        sources[i++] = pa_dbusiface_device_get_path(source);
 
     return sources;
 }
@@ -720,7 +716,8 @@ static void handle_get_fallback_source(DBusConnection *conn, DBusMessage *msg, v
     pa_assert(c);
 
     if (!c->fallback_source) {
-        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "There are no sources, and therefore no fallback source either.");
+        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY,
+                           "There are no sources, and therefore no fallback source either.");
         return;
     }
 
@@ -740,7 +737,8 @@ static void handle_set_fallback_source(DBusConnection *conn, DBusMessage *msg, v
     pa_assert(c);
 
     if (!c->fallback_source) {
-        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "There are no sources, and therefore no fallback source either.");
+        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY,
+                           "There are no sources, and therefore no fallback source either.");
         return;
     }
 
@@ -748,7 +746,7 @@ static void handle_set_fallback_source(DBusConnection *conn, DBusMessage *msg, v
         return;
 
     if (!(fallback_source = pa_hashmap_get(c->sources_by_path, object_path))) {
-        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NOT_FOUND, "No such source.");
+        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NOT_FOUND, "%s: No such source.", object_path);
         return;
     }
 
@@ -760,7 +758,7 @@ static void handle_set_fallback_source(DBusConnection *conn, DBusMessage *msg, v
 /* The caller frees the array, but not the strings. */
 static const char **get_playback_streams(pa_dbusiface_core *c, unsigned *n) {
     const char **streams;
-    unsigned i;
+    unsigned i = 0;
     void *state = NULL;
     pa_dbusiface_stream *stream;
 
@@ -774,10 +772,8 @@ static const char **get_playback_streams(pa_dbusiface_core *c, unsigned *n) {
 
     streams = pa_xnew(const char *, *n);
 
-    for (i = 0, stream = pa_hashmap_iterate(c->playback_streams, &state, NULL); stream; ++i, stream = pa_hashmap_iterate(c->playback_streams, &state, NULL))
-        streams[i] = pa_dbusiface_stream_get_path(stream);
-
-    pa_assert(i == *n);
+    PA_HASHMAP_FOREACH(stream, c->playback_streams, state)
+        streams[i++] = pa_dbusiface_stream_get_path(stream);
 
     return streams;
 }
@@ -801,7 +797,7 @@ static void handle_get_playback_streams(DBusConnection *conn, DBusMessage *msg,
 /* The caller frees the array, but not the strings. */
 static const char **get_record_streams(pa_dbusiface_core *c, unsigned *n) {
     const char **streams;
-    unsigned i;
+    unsigned i = 0;
     void *state = NULL;
     pa_dbusiface_stream *stream;
 
@@ -815,10 +811,8 @@ static const char **get_record_streams(pa_dbusiface_core *c, unsigned *n) {
 
     streams = pa_xnew(const char *, *n);
 
-    for (i = 0, stream = pa_hashmap_iterate(c->record_streams, &state, NULL); stream; ++i, stream = pa_hashmap_iterate(c->record_streams, &state, NULL))
-        streams[i] = pa_dbusiface_stream_get_path(stream);
-
-    pa_assert(i == *n);
+    PA_HASHMAP_FOREACH(stream, c->record_streams, state)
+        streams[i++] = pa_dbusiface_stream_get_path(stream);
 
     return streams;
 }
@@ -842,7 +836,7 @@ static void handle_get_record_streams(DBusConnection *conn, DBusMessage *msg, vo
 /* The caller frees the array, but not the strings. */
 static const char **get_samples(pa_dbusiface_core *c, unsigned *n) {
     const char **samples;
-    unsigned i;
+    unsigned i = 0;
     void *state = NULL;
     pa_dbusiface_sample *sample;
 
@@ -856,10 +850,8 @@ static const char **get_samples(pa_dbusiface_core *c, unsigned *n) {
 
     samples = pa_xnew(const char *, *n);
 
-    for (i = 0, sample = pa_hashmap_iterate(c->samples, &state, NULL); sample; ++i, sample = pa_hashmap_iterate(c->samples, &state, NULL))
-        samples[i] = pa_dbusiface_sample_get_path(sample);
-
-    pa_assert(i == *n);
+    PA_HASHMAP_FOREACH(sample, c->samples, state)
+        samples[i++] = pa_dbusiface_sample_get_path(sample);
 
     return samples;
 }
@@ -883,7 +875,7 @@ static void handle_get_samples(DBusConnection *conn, DBusMessage *msg, void *use
 /* The caller frees the array, but not the strings. */
 static const char **get_modules(pa_dbusiface_core *c, unsigned *n) {
     const char **modules;
-    unsigned i;
+    unsigned i = 0;
     void *state = NULL;
     pa_dbusiface_module *module;
 
@@ -897,10 +889,8 @@ static const char **get_modules(pa_dbusiface_core *c, unsigned *n) {
 
     modules = pa_xnew(const char *, *n);
 
-    for (i = 0, module = pa_hashmap_iterate(c->modules, &state, NULL); module; ++i, module = pa_hashmap_iterate(c->modules, &state, NULL))
-        modules[i] = pa_dbusiface_module_get_path(module);
-
-    pa_assert(i == *n);
+    PA_HASHMAP_FOREACH(module, c->modules, state)
+        modules[i++] = pa_dbusiface_module_get_path(module);
 
     return modules;
 }
@@ -924,7 +914,7 @@ static void handle_get_modules(DBusConnection *conn, DBusMessage *msg, void *use
 /* The caller frees the array, but not the strings. */
 static const char **get_clients(pa_dbusiface_core *c, unsigned *n) {
     const char **clients;
-    unsigned i;
+    unsigned i = 0;
     void *state = NULL;
     pa_dbusiface_client *client;
 
@@ -938,10 +928,8 @@ static const char **get_clients(pa_dbusiface_core *c, unsigned *n) {
 
     clients = pa_xnew(const char *, *n);
 
-    for (i = 0, client = pa_hashmap_iterate(c->clients, &state, NULL); client; ++i, client = pa_hashmap_iterate(c->clients, &state, NULL))
-        clients[i] = pa_dbusiface_client_get_path(client);
-
-    pa_assert(i == *n);
+    PA_HASHMAP_FOREACH(client, c->clients, state)
+        clients[i++] = pa_dbusiface_client_get_path(client);
 
     return clients;
 }
@@ -1054,9 +1042,14 @@ static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdat
     default_sample_rate = c->core->default_sample_spec.rate;
     cards = get_cards(c, &n_cards);
     sinks = get_sinks(c, &n_sinks);
-    fallback_sink = c->fallback_sink ? pa_dbusiface_device_get_path(pa_hashmap_get(c->sinks_by_index, PA_UINT32_TO_PTR(c->fallback_sink->index))) : NULL;
+    fallback_sink = c->fallback_sink
+                    ? pa_dbusiface_device_get_path(pa_hashmap_get(c->sinks_by_index, PA_UINT32_TO_PTR(c->fallback_sink->index)))
+                    : NULL;
     sources = get_sources(c, &n_sources);
-    fallback_source = c->fallback_source ? pa_dbusiface_device_get_path(pa_hashmap_get(c->sources_by_index, PA_UINT32_TO_PTR(c->fallback_source->index))) : NULL;
+    fallback_source = c->fallback_source
+                      ? pa_dbusiface_device_get_path(pa_hashmap_get(c->sources_by_index,
+                                                                    PA_UINT32_TO_PTR(c->fallback_source->index)))
+                      : NULL;
     playback_streams = get_playback_streams(c, &n_playback_streams);
     record_streams = get_record_streams(c, &n_record_streams);
     samples = get_samples(c, &n_samples);
@@ -1171,7 +1164,7 @@ static void handle_get_sink_by_name(DBusConnection *conn, DBusMessage *msg, void
     }
 
     if (!(sink = pa_namereg_get(c->core, sink_name, PA_NAMEREG_SINK))) {
-        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NOT_FOUND, "No such sink.");
+        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NOT_FOUND, "%s: No such sink.", sink_name);
         return;
     }
 
@@ -1203,7 +1196,7 @@ static void handle_get_source_by_name(DBusConnection *conn, DBusMessage *msg, vo
     }
 
     if (!(source = pa_namereg_get(c->core, source_name, PA_NAMEREG_SOURCE))) {
-        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NOT_FOUND, "No such source.");
+        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NOT_FOUND, "%s: No such source.", source_name);
         return;
     }
 
@@ -1316,7 +1309,8 @@ static void handle_upload_sample(DBusConnection *conn, DBusMessage *msg, void *u
     }
 
     if (n_channels > PA_CHANNELS_MAX) {
-        pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "Too many channels.");
+        pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS,
+                           "Too many channels: %u. The maximum is %u.", n_channels, PA_CHANNELS_MAX);
         goto finish;
     }
 
@@ -1328,7 +1322,8 @@ static void handle_upload_sample(DBusConnection *conn, DBusMessage *msg, void *u
     }
 
     if (n_volume_entries != 0 && n_volume_entries != n_channels) {
-        pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "The channels and default_volume arguments have different number of elements.");
+        pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS,
+                           "The channels and default_volume arguments have different number of elements.");
         goto finish;
     }
 
@@ -1354,7 +1349,8 @@ static void handle_upload_sample(DBusConnection *conn, DBusMessage *msg, void *u
     ss.channels = n_channels;
 
     if (!pa_frame_aligned(data_length, &ss)) {
-        pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "The sample length in bytes doesn't align with the sample format and channels.");
+        pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS,
+                           "The sample length in bytes doesn't align with the sample format and channels.");
         goto finish;
     }
 
@@ -1385,7 +1381,7 @@ static void handle_upload_sample(DBusConnection *conn, DBusMessage *msg, void *u
         sample->volume_is_set = FALSE;
     }
 
-    dbus_sample = pa_dbusiface_sample_new(sample, OBJECT_PATH);
+    dbus_sample = pa_dbusiface_sample_new(c, sample);
     pa_hashmap_put(c->samples, PA_UINT32_TO_PTR(idx), dbus_sample);
 
     object_path = pa_dbusiface_sample_get_path(dbus_sample);
@@ -1448,15 +1444,19 @@ static void handle_load_module(DBusConnection *conn, DBusMessage *msg, void *use
     arg_type = dbus_message_iter_get_arg_type(&msg_iter);
     if (arg_type != DBUS_TYPE_ARRAY) {
         if (arg_type == DBUS_TYPE_INVALID)
-            pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "Too few arguments. A dictionary from strings to strings was expected.");
+            pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS,
+                               "Too few arguments. A dictionary from strings to strings was expected.");
         else
-            pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "Wrong argument type: '%c'. An dictionary from strings to strings was expected.", (char) arg_type);
+            pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS,
+                               "Wrong argument type: '%c'. An dictionary from strings to strings was expected.",
+                               (char) arg_type);
         return;
     }
 
     arg_type = dbus_message_iter_get_element_type(&msg_iter);
     if (arg_type != DBUS_TYPE_DICT_ENTRY) {
-        pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "Wrong array element type: '%c'. A dict entry (string to string) was expected.", (char) arg_type);
+        pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS,
+                           "Wrong array element type: '%c'. A dict entry (string to string) was expected.", (char) arg_type);
         return;
     }
 
@@ -1472,7 +1472,8 @@ static void handle_load_module(DBusConnection *conn, DBusMessage *msg, void *use
 
         arg_type = dbus_message_iter_get_arg_type(&dict_entry_iter);
         if (arg_type != DBUS_TYPE_STRING) {
-            pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "Wrong dict key type: '%c'. A string was expected.", (char) arg_type);
+            pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS,
+                               "Wrong dict key type: '%c'. A string was expected.", (char) arg_type);
             goto finish;
         }
 
@@ -1489,7 +1490,8 @@ static void handle_load_module(DBusConnection *conn, DBusMessage *msg, void *use
             if (arg_type == DBUS_TYPE_INVALID)
                 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "Dict value missing.");
             else
-                pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "Wrong dict value type: '%c'. A string was expected.", (char) arg_type);
+                pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS,
+                                   "Wrong dict value type: '%c'. A string was expected.", (char) arg_type);
             goto finish;
         }
 
@@ -1507,7 +1509,7 @@ static void handle_load_module(DBusConnection *conn, DBusMessage *msg, void *use
         goto finish;
     }
 
-    dbus_module = pa_dbusiface_module_new(module, OBJECT_PATH);
+    dbus_module = pa_dbusiface_module_new(module);
     pa_hashmap_put(c->modules, PA_UINT32_TO_PTR(module->index), dbus_module);
 
     object_path = pa_dbusiface_module_get_path(dbus_module);
@@ -1549,7 +1551,10 @@ static void handle_listen_for_signal(DBusConnection *conn, DBusMessage *msg, voi
 
     dbus_error_init(&error);
 
-    if (!dbus_message_get_args(msg, &error, DBUS_TYPE_STRING, &signal, DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH, &objects, &n_objects, DBUS_TYPE_INVALID)) {
+    if (!dbus_message_get_args(msg, &error,
+                               DBUS_TYPE_STRING, &signal,
+                               DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH, &objects, &n_objects,
+                               DBUS_TYPE_INVALID)) {
         pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", error.message);
         dbus_error_free(&error);
         goto finish;
@@ -1608,10 +1613,13 @@ static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint3
             if (c->fallback_sink != new_fallback_sink) {
                 c->fallback_sink = new_fallback_sink;
 
-                if (new_fallback_sink && (device = pa_hashmap_get(c->sinks_by_index, PA_UINT32_TO_PTR(new_fallback_sink->index)))) {
+                if (new_fallback_sink
+                    && (device = pa_hashmap_get(c->sinks_by_index, PA_UINT32_TO_PTR(new_fallback_sink->index)))) {
                     object_path = pa_dbusiface_device_get_path(device);
 
-                    pa_assert_se((signal = dbus_message_new_signal(OBJECT_PATH, PA_DBUSIFACE_CORE_INTERFACE, signals[SIGNAL_FALLBACK_SINK_UPDATED].name)));
+                    pa_assert_se((signal = 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, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
                     pa_dbus_protocol_send_signal(c->dbus_protocol, signal);
                     dbus_message_unref(signal);
@@ -1622,10 +1630,13 @@ static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint3
             if (c->fallback_source != new_fallback_source) {
                 c->fallback_source = new_fallback_source;
 
-                if (new_fallback_source && (device = pa_hashmap_get(c->sources_by_index, PA_UINT32_TO_PTR(new_fallback_source->index)))) {
+                if (new_fallback_source
+                    && (device = pa_hashmap_get(c->sources_by_index, PA_UINT32_TO_PTR(new_fallback_source->index)))) {
                     object_path = pa_dbusiface_device_get_path(device);
 
-                    pa_assert_se((signal = dbus_message_new_signal(OBJECT_PATH, PA_DBUSIFACE_CORE_INTERFACE, signals[SIGNAL_FALLBACK_SOURCE_UPDATED].name)));
+                    pa_assert_se((signal = 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, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
                     pa_dbus_protocol_send_signal(c->dbus_protocol, signal);
                     dbus_message_unref(signal);
@@ -1637,13 +1648,15 @@ static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint3
         case PA_SUBSCRIPTION_EVENT_CARD:
             if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) {
                 if (!(card = pa_hashmap_get(c->cards, PA_UINT32_TO_PTR(idx)))) {
-                    card = pa_dbusiface_card_new(pa_idxset_get_by_index(core->cards, idx), OBJECT_PATH);
+                    card = pa_dbusiface_card_new(c, pa_idxset_get_by_index(core->cards, idx));
                     pa_hashmap_put(c->cards, PA_UINT32_TO_PTR(idx), card);
                 }
 
                 object_path = pa_dbusiface_card_get_path(card);
 
-                pa_assert_se((signal = dbus_message_new_signal(OBJECT_PATH, PA_DBUSIFACE_CORE_INTERFACE, signals[SIGNAL_NEW_CARD].name)));
+                pa_assert_se((signal = 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, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
 
             } else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
@@ -1651,7 +1664,9 @@ static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint3
 
                 object_path = pa_dbusiface_card_get_path(card);
 
-                pa_assert_se((signal = dbus_message_new_signal(OBJECT_PATH, PA_DBUSIFACE_CORE_INTERFACE, signals[SIGNAL_CARD_REMOVED].name)));
+                pa_assert_se((signal = 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, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
 
                 pa_dbusiface_card_free(card);
@@ -1663,14 +1678,16 @@ static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint3
                 pa_sink *sink = pa_idxset_get_by_index(core->sinks, idx);
 
                 if (!(device = pa_hashmap_get(c->sinks_by_index, PA_UINT32_TO_PTR(idx)))) {
-                    device = pa_dbusiface_device_new_sink(sink, OBJECT_PATH);
+                    device = pa_dbusiface_device_new_sink(c, sink);
                     pa_hashmap_put(c->sinks_by_index, PA_UINT32_TO_PTR(idx), device);
                     pa_hashmap_put(c->sinks_by_path, pa_dbusiface_device_get_path(device), device);
                 }
 
                 object_path = pa_dbusiface_device_get_path(device);
 
-                pa_assert_se((signal = dbus_message_new_signal(OBJECT_PATH, PA_DBUSIFACE_CORE_INTERFACE, signals[SIGNAL_NEW_SINK].name)));
+                pa_assert_se((signal = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
+                                                               PA_DBUS_CORE_INTERFACE,
+                                                               signals[SIGNAL_NEW_SINK].name)));
                 pa_assert_se(dbus_message_append_args(signal, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
 
                 pa_dbus_protocol_send_signal(c->dbus_protocol, signal);
@@ -1682,7 +1699,9 @@ static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint3
                      * the D-Bus sink object wasn't created yet. Now that the
                      * object is created, let's send the fallback sink change
                      * signal. */
-                    pa_assert_se((signal = dbus_message_new_signal(OBJECT_PATH, PA_DBUSIFACE_CORE_INTERFACE, signals[SIGNAL_FALLBACK_SINK_UPDATED].name)));
+                    pa_assert_se((signal = 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, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
 
                     pa_dbus_protocol_send_signal(c->dbus_protocol, signal);
@@ -1695,7 +1714,9 @@ static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint3
                 object_path = pa_dbusiface_device_get_path(device);
                 pa_assert_se(pa_hashmap_remove(c->sinks_by_path, object_path));
 
-                pa_assert_se((signal = dbus_message_new_signal(OBJECT_PATH, PA_DBUSIFACE_CORE_INTERFACE, signals[SIGNAL_SINK_REMOVED].name)));
+                pa_assert_se((signal = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
+                                                               PA_DBUS_CORE_INTERFACE,
+                                                               signals[SIGNAL_SINK_REMOVED].name)));
                 pa_assert_se(dbus_message_append_args(signal, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
 
                 pa_dbusiface_device_free(device);
@@ -1707,14 +1728,16 @@ static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint3
                 pa_source *source = pa_idxset_get_by_index(core->sources, idx);
 
                 if (!(device = pa_hashmap_get(c->sources_by_index, PA_UINT32_TO_PTR(idx)))) {
-                    device = pa_dbusiface_device_new_source(source, OBJECT_PATH);
+                    device = pa_dbusiface_device_new_source(c, source);
                     pa_hashmap_put(c->sources_by_index, PA_UINT32_TO_PTR(idx), device);
                     pa_hashmap_put(c->sources_by_path, pa_dbusiface_device_get_path(device), device);
                 }
 
                 object_path = pa_dbusiface_device_get_path(device);
 
-                pa_assert_se((signal = dbus_message_new_signal(OBJECT_PATH, PA_DBUSIFACE_CORE_INTERFACE, signals[SIGNAL_NEW_SOURCE].name)));
+                pa_assert_se((signal = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
+                                                               PA_DBUS_CORE_INTERFACE,
+                                                               signals[SIGNAL_NEW_SOURCE].name)));
                 pa_assert_se(dbus_message_append_args(signal, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
 
                 pa_dbus_protocol_send_signal(c->dbus_protocol, signal);
@@ -1726,7 +1749,9 @@ static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint3
                      * point the D-Bus source object wasn't created yet. Now
                      * that the object is created, let's send the fallback
                      * source change signal. */
-                    pa_assert_se((signal = dbus_message_new_signal(OBJECT_PATH, PA_DBUSIFACE_CORE_INTERFACE, signals[SIGNAL_FALLBACK_SOURCE_UPDATED].name)));
+                    pa_assert_se((signal = 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, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
 
                     pa_dbus_protocol_send_signal(c->dbus_protocol, signal);
@@ -1739,7 +1764,9 @@ static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint3
                 object_path = pa_dbusiface_device_get_path(device);
                 pa_assert_se(pa_hashmap_remove(c->sources_by_path, object_path));
 
-                pa_assert_se((signal = dbus_message_new_signal(OBJECT_PATH, PA_DBUSIFACE_CORE_INTERFACE, signals[SIGNAL_SOURCE_REMOVED].name)));
+                pa_assert_se((signal = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
+                                                               PA_DBUS_CORE_INTERFACE,
+                                                               signals[SIGNAL_SOURCE_REMOVED].name)));
                 pa_assert_se(dbus_message_append_args(signal, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
 
                 pa_dbusiface_device_free(device);
@@ -1749,13 +1776,15 @@ static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint3
         case PA_SUBSCRIPTION_EVENT_SINK_INPUT:
             if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) {
                 if (!(stream = pa_hashmap_get(c->playback_streams, PA_UINT32_TO_PTR(idx)))) {
-                    stream = pa_dbusiface_stream_new_playback(pa_idxset_get_by_index(core->sink_inputs, idx), OBJECT_PATH);
+                    stream = pa_dbusiface_stream_new_playback(c, pa_idxset_get_by_index(core->sink_inputs, idx));
                     pa_hashmap_put(c->playback_streams, PA_UINT32_TO_PTR(idx), stream);
                 }
 
                 object_path = pa_dbusiface_stream_get_path(stream);
 
-                pa_assert_se((signal = dbus_message_new_signal(OBJECT_PATH, PA_DBUSIFACE_CORE_INTERFACE, signals[SIGNAL_NEW_PLAYBACK_STREAM].name)));
+                pa_assert_se((signal = 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, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
 
             } else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
@@ -1763,7 +1792,9 @@ static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint3
 
                 object_path = pa_dbusiface_stream_get_path(stream);
 
-                pa_assert_se((signal = dbus_message_new_signal(OBJECT_PATH, PA_DBUSIFACE_CORE_INTERFACE, signals[SIGNAL_PLAYBACK_STREAM_REMOVED].name)));
+                pa_assert_se((signal = 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, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
 
                 pa_dbusiface_stream_free(stream);
@@ -1773,13 +1804,15 @@ static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint3
         case PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT:
             if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) {
                 if (!(stream = pa_hashmap_get(c->record_streams, PA_UINT32_TO_PTR(idx)))) {
-                    stream = pa_dbusiface_stream_new_record(pa_idxset_get_by_index(core->source_outputs, idx), OBJECT_PATH);
+                    stream = pa_dbusiface_stream_new_record(c, pa_idxset_get_by_index(core->source_outputs, idx));
                     pa_hashmap_put(c->record_streams, PA_UINT32_TO_PTR(idx), stream);
                 }
 
                 object_path = pa_dbusiface_stream_get_path(stream);
 
-                pa_assert_se((signal = dbus_message_new_signal(OBJECT_PATH, PA_DBUSIFACE_CORE_INTERFACE, signals[SIGNAL_NEW_RECORD_STREAM].name)));
+                pa_assert_se((signal = 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, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
 
             } else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
@@ -1787,7 +1820,9 @@ static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint3
 
                 object_path = pa_dbusiface_stream_get_path(stream);
 
-                pa_assert_se((signal = dbus_message_new_signal(OBJECT_PATH, PA_DBUSIFACE_CORE_INTERFACE, signals[SIGNAL_RECORD_STREAM_REMOVED].name)));
+                pa_assert_se((signal = 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, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
 
                 pa_dbusiface_stream_free(stream);
@@ -1797,13 +1832,15 @@ static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint3
         case PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE:
             if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) {
                 if (!(sample = pa_hashmap_get(c->samples, PA_UINT32_TO_PTR(idx)))) {
-                    sample = pa_dbusiface_sample_new(pa_idxset_get_by_index(core->scache, idx), OBJECT_PATH);
+                    sample = pa_dbusiface_sample_new(c, pa_idxset_get_by_index(core->scache, idx));
                     pa_hashmap_put(c->samples, PA_UINT32_TO_PTR(idx), sample);
                 }
 
                 object_path = pa_dbusiface_sample_get_path(sample);
 
-                pa_assert_se((signal = dbus_message_new_signal(OBJECT_PATH, PA_DBUSIFACE_CORE_INTERFACE, signals[SIGNAL_NEW_SAMPLE].name)));
+                pa_assert_se((signal = 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, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
 
             } else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
@@ -1811,7 +1848,9 @@ static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint3
 
                 object_path = pa_dbusiface_sample_get_path(sample);
 
-                pa_assert_se((signal = dbus_message_new_signal(OBJECT_PATH, PA_DBUSIFACE_CORE_INTERFACE, signals[SIGNAL_SAMPLE_REMOVED].name)));
+                pa_assert_se((signal = 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, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
 
                 pa_dbusiface_sample_free(sample);
@@ -1821,13 +1860,15 @@ static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint3
         case PA_SUBSCRIPTION_EVENT_MODULE:
             if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) {
                 if (!(module = pa_hashmap_get(c->modules, PA_UINT32_TO_PTR(idx)))) {
-                    module = pa_dbusiface_module_new(pa_idxset_get_by_index(core->modules, idx), OBJECT_PATH);
+                    module = pa_dbusiface_module_new(pa_idxset_get_by_index(core->modules, idx));
                     pa_hashmap_put(c->modules, PA_UINT32_TO_PTR(idx), module);
                 }
 
                 object_path = pa_dbusiface_module_get_path(module);
 
-                pa_assert_se((signal = dbus_message_new_signal(OBJECT_PATH, PA_DBUSIFACE_CORE_INTERFACE, signals[SIGNAL_NEW_MODULE].name)));
+                pa_assert_se((signal = 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, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
 
             } else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
@@ -1835,7 +1876,9 @@ static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint3
 
                 object_path = pa_dbusiface_module_get_path(module);
 
-                pa_assert_se((signal = dbus_message_new_signal(OBJECT_PATH, PA_DBUSIFACE_CORE_INTERFACE, signals[SIGNAL_MODULE_REMOVED].name)));
+                pa_assert_se((signal = 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, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
 
                 pa_dbusiface_module_free(module);
@@ -1845,13 +1888,15 @@ static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint3
         case PA_SUBSCRIPTION_EVENT_CLIENT:
             if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) {
                 if (!(client = pa_hashmap_get(c->clients, PA_UINT32_TO_PTR(idx)))) {
-                    client = pa_dbusiface_client_new(pa_idxset_get_by_index(core->clients, idx), OBJECT_PATH);
+                    client = pa_dbusiface_client_new(c, pa_idxset_get_by_index(core->clients, idx));
                     pa_hashmap_put(c->clients, PA_UINT32_TO_PTR(idx), client);
                 }
 
                 object_path = pa_dbusiface_client_get_path(client);
 
-                pa_assert_se((signal = dbus_message_new_signal(OBJECT_PATH, PA_DBUSIFACE_CORE_INTERFACE, signals[SIGNAL_NEW_CLIENT].name)));
+                pa_assert_se((signal = 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, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
 
             } else if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
@@ -1859,7 +1904,9 @@ static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint3
 
                 object_path = pa_dbusiface_client_get_path(client);
 
-                pa_assert_se((signal = dbus_message_new_signal(OBJECT_PATH, PA_DBUSIFACE_CORE_INTERFACE, signals[SIGNAL_CLIENT_REMOVED].name)));
+                pa_assert_se((signal = 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, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
 
                 pa_dbusiface_client_free(client);
@@ -1881,7 +1928,9 @@ static pa_hook_result_t extension_registered_cb(void *hook_data, void *call_data
     pa_assert(c);
     pa_assert(ext_name);
 
-    pa_assert_se((signal = dbus_message_new_signal(OBJECT_PATH, PA_DBUSIFACE_CORE_INTERFACE, signals[SIGNAL_NEW_EXTENSION].name)));
+    pa_assert_se((signal = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
+                                                   PA_DBUS_CORE_INTERFACE,
+                                                   signals[SIGNAL_NEW_EXTENSION].name)));
     pa_assert_se(dbus_message_append_args(signal, DBUS_TYPE_STRING, &ext_name, DBUS_TYPE_INVALID));
 
     pa_dbus_protocol_send_signal(c->dbus_protocol, signal);
@@ -1898,7 +1947,9 @@ static pa_hook_result_t extension_unregistered_cb(void *hook_data, void *call_da
     pa_assert(c);
     pa_assert(ext_name);
 
-    pa_assert_se((signal = dbus_message_new_signal(OBJECT_PATH, PA_DBUSIFACE_CORE_INTERFACE, signals[SIGNAL_EXTENSION_REMOVED].name)));
+    pa_assert_se((signal = dbus_message_new_signal(PA_DBUS_CORE_OBJECT_PATH,
+                                                   PA_DBUS_CORE_INTERFACE,
+                                                   signals[SIGNAL_EXTENSION_REMOVED].name)));
     pa_assert_se(dbus_message_append_args(signal, DBUS_TYPE_STRING, &ext_name, DBUS_TYPE_INVALID));
 
     pa_dbus_protocol_send_signal(c->dbus_protocol, signal);
@@ -1923,7 +1974,7 @@ pa_dbusiface_core *pa_dbusiface_core_new(pa_core *core) {
     pa_assert(core);
 
     c = pa_xnew(pa_dbusiface_core, 1);
-    c->core = core;
+    c->core = pa_core_ref(core);
     c->subscription = pa_subscription_new(core, PA_SUBSCRIPTION_MASK_ALL, subscription_cb, c);
     c->dbus_protocol = pa_dbus_protocol_get(core);
     c->cards = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
@@ -1938,40 +1989,49 @@ pa_dbusiface_core *pa_dbusiface_core_new(pa_core *core) {
     c->clients = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
     c->fallback_sink = pa_namereg_get_default_sink(core);
     c->fallback_source = pa_namereg_get_default_source(core);
-    c->extension_registered_slot = pa_dbus_protocol_hook_connect(c->dbus_protocol, PA_DBUS_PROTOCOL_HOOK_EXTENSION_REGISTERED, PA_HOOK_NORMAL, extension_registered_cb, c);
-    c->extension_unregistered_slot = pa_dbus_protocol_hook_connect(c->dbus_protocol, PA_DBUS_PROTOCOL_HOOK_EXTENSION_UNREGISTERED, PA_HOOK_NORMAL, extension_unregistered_cb, c);
-
-    for (card = pa_idxset_first(core->cards, &idx); card; card = pa_idxset_next(core->cards, &idx))
-        pa_hashmap_put(c->cards, PA_UINT32_TO_PTR(idx), pa_dbusiface_card_new(card, OBJECT_PATH));
-
-    for (sink = pa_idxset_first(core->sinks, &idx); sink; sink = pa_idxset_next(core->sinks, &idx)) {
-        device = pa_dbusiface_device_new_sink(sink, OBJECT_PATH);
+    c->extension_registered_slot = pa_dbus_protocol_hook_connect(c->dbus_protocol,
+                                                                 PA_DBUS_PROTOCOL_HOOK_EXTENSION_REGISTERED,
+                                                                 PA_HOOK_NORMAL,
+                                                                 extension_registered_cb,
+                                                                 c);
+    c->extension_unregistered_slot = pa_dbus_protocol_hook_connect(c->dbus_protocol,
+                                                                   PA_DBUS_PROTOCOL_HOOK_EXTENSION_UNREGISTERED,
+                                                                   PA_HOOK_NORMAL,
+                                                                   extension_unregistered_cb,
+                                                                   c);
+    c->memstats = pa_dbusiface_memstats_new(c, core);
+
+    PA_IDXSET_FOREACH(card, core->cards, idx)
+        pa_hashmap_put(c->cards, PA_UINT32_TO_PTR(idx), pa_dbusiface_card_new(c, card));
+
+    PA_IDXSET_FOREACH(sink, core->sinks, idx) {
+        device = pa_dbusiface_device_new_sink(c, sink);
         pa_hashmap_put(c->sinks_by_index, PA_UINT32_TO_PTR(idx), device);
         pa_hashmap_put(c->sinks_by_path, pa_dbusiface_device_get_path(device), device);
     }
 
-    for (source = pa_idxset_first(core->sources, &idx); source; source = pa_idxset_next(core->sources, &idx)) {
-        device = pa_dbusiface_device_new_source(source, OBJECT_PATH);
+    PA_IDXSET_FOREACH(source, core->sources, idx) {
+        device = pa_dbusiface_device_new_source(c, source);
         pa_hashmap_put(c->sources_by_index, PA_UINT32_TO_PTR(idx), device);
         pa_hashmap_put(c->sources_by_path, pa_dbusiface_device_get_path(device), device);
     }
 
-    for (sink_input = pa_idxset_first(core->sink_inputs, &idx); sink_input; sink_input = pa_idxset_next(core->sink_inputs, &idx))
-        pa_hashmap_put(c->playback_streams, PA_UINT32_TO_PTR(idx), pa_dbusiface_stream_new_playback(sink_input, OBJECT_PATH));
+    PA_IDXSET_FOREACH(sink_input, core->sink_inputs, idx)
+        pa_hashmap_put(c->playback_streams, PA_UINT32_TO_PTR(idx), pa_dbusiface_stream_new_playback(c, sink_input));
 
-    for (source_output = pa_idxset_first(core->source_outputs, &idx); source_output; source_output = pa_idxset_next(core->source_outputs, &idx))
-        pa_hashmap_put(c->record_streams, PA_UINT32_TO_PTR(idx), pa_dbusiface_stream_new_record(source_output, OBJECT_PATH));
+    PA_IDXSET_FOREACH(source_output, core->source_outputs, idx)
+        pa_hashmap_put(c->record_streams, PA_UINT32_TO_PTR(idx), pa_dbusiface_stream_new_record(c, source_output));
 
-    for (sample = pa_idxset_first(core->scache, &idx); sample; sample = pa_idxset_next(core->scache, &idx))
-        pa_hashmap_put(c->samples, PA_UINT32_TO_PTR(idx), pa_dbusiface_sample_new(sample, OBJECT_PATH));
+    PA_IDXSET_FOREACH(sample, core->scache, idx)
+        pa_hashmap_put(c->samples, PA_UINT32_TO_PTR(idx), pa_dbusiface_sample_new(c, sample));
 
-    for (module = pa_idxset_first(core->modules, &idx); module; module = pa_idxset_next(core->modules, &idx))
-        pa_hashmap_put(c->modules, PA_UINT32_TO_PTR(idx), pa_dbusiface_module_new(module, OBJECT_PATH));
+    PA_IDXSET_FOREACH(module, core->modules, idx)
+        pa_hashmap_put(c->modules, PA_UINT32_TO_PTR(idx), pa_dbusiface_module_new(module));
 
-    for (client = pa_idxset_first(core->clients, &idx); client; client = pa_idxset_next(core->clients, &idx))
-        pa_hashmap_put(c->clients, PA_UINT32_TO_PTR(idx), pa_dbusiface_client_new(client, OBJECT_PATH));
+    PA_IDXSET_FOREACH(client, core->clients, idx)
+        pa_hashmap_put(c->clients, PA_UINT32_TO_PTR(idx), pa_dbusiface_client_new(c, client));
 
-    pa_dbus_protocol_add_interface(c->dbus_protocol, OBJECT_PATH, &core_interface_info, c);
+    pa_assert_se(pa_dbus_protocol_add_interface(c->dbus_protocol, PA_DBUS_CORE_OBJECT_PATH, &core_interface_info, c) >= 0);
 
     return c;
 }
@@ -2027,7 +2087,7 @@ static void free_client_cb(void *p, void *userdata) {
 void pa_dbusiface_core_free(pa_dbusiface_core *c) {
     pa_assert(c);
 
-    pa_dbus_protocol_remove_interface(c->dbus_protocol, OBJECT_PATH, core_interface_info.name);
+    pa_assert_se(pa_dbus_protocol_remove_interface(c->dbus_protocol, PA_DBUS_CORE_OBJECT_PATH, core_interface_info.name) >= 0);
 
     pa_subscription_free(c->subscription);
     pa_hashmap_free(c->cards, free_card_cb, NULL);
@@ -2042,8 +2102,87 @@ void pa_dbusiface_core_free(pa_dbusiface_core *c) {
     pa_hashmap_free(c->clients, free_client_cb, NULL);
     pa_hook_slot_free(c->extension_registered_slot);
     pa_hook_slot_free(c->extension_unregistered_slot);
+    pa_dbusiface_memstats_free(c->memstats);
 
     pa_dbus_protocol_unref(c->dbus_protocol);
+    pa_core_unref(c->core);
 
     pa_xfree(c);
 }
+
+const char *pa_dbusiface_core_get_card_path(pa_dbusiface_core *c, const pa_card *card) {
+    pa_assert(c);
+    pa_assert(card);
+
+    return pa_dbusiface_card_get_path(pa_hashmap_get(c->cards, PA_UINT32_TO_PTR(card->index)));
+}
+
+const char *pa_dbusiface_core_get_sink_path(pa_dbusiface_core *c, const pa_sink *sink) {
+    pa_assert(c);
+    pa_assert(sink);
+
+    return pa_dbusiface_device_get_path(pa_hashmap_get(c->sinks_by_index, PA_UINT32_TO_PTR(sink->index)));
+}
+
+const char *pa_dbusiface_core_get_source_path(pa_dbusiface_core *c, const pa_source *source) {
+    pa_assert(c);
+    pa_assert(source);
+
+    return pa_dbusiface_device_get_path(pa_hashmap_get(c->sources_by_index, PA_UINT32_TO_PTR(source->index)));
+}
+
+const char *pa_dbusiface_core_get_playback_stream_path(pa_dbusiface_core *c, const pa_sink_input *sink_input) {
+    pa_assert(c);
+    pa_assert(sink_input);
+
+    return pa_dbusiface_stream_get_path(pa_hashmap_get(c->playback_streams, PA_UINT32_TO_PTR(sink_input->index)));
+}
+
+const char *pa_dbusiface_core_get_record_stream_path(pa_dbusiface_core *c, const pa_source_output *source_output) {
+    pa_assert(c);
+    pa_assert(source_output);
+
+    return pa_dbusiface_stream_get_path(pa_hashmap_get(c->record_streams, PA_UINT32_TO_PTR(source_output->index)));
+}
+
+const char *pa_dbusiface_core_get_module_path(pa_dbusiface_core *c, const pa_module *module) {
+    pa_assert(c);
+    pa_assert(module);
+
+    return pa_dbusiface_module_get_path(pa_hashmap_get(c->modules, PA_UINT32_TO_PTR(module->index)));
+}
+
+const char *pa_dbusiface_core_get_client_path(pa_dbusiface_core *c, const pa_client *client) {
+    pa_assert(c);
+    pa_assert(client);
+
+    return pa_dbusiface_client_get_path(pa_hashmap_get(c->clients, PA_UINT32_TO_PTR(client->index)));
+}
+
+pa_sink *pa_dbusiface_core_get_sink(pa_dbusiface_core *c, const char *object_path) {
+    pa_dbusiface_device *device = NULL;
+
+    pa_assert(c);
+    pa_assert(object_path);
+
+    device = pa_hashmap_get(c->sinks_by_path, object_path);
+
+    if (device)
+        return pa_dbusiface_device_get_sink(device);
+    else
+        return NULL;
+}
+
+pa_source *pa_dbusiface_core_get_source(pa_dbusiface_core *c, const char *object_path) {
+    pa_dbusiface_device *device = NULL;
+
+    pa_assert(c);
+    pa_assert(object_path);
+
+    device = pa_hashmap_get(c->sources_by_path, object_path);
+
+    if (device)
+        return pa_dbusiface_device_get_source(device);
+    else
+        return NULL;
+}