From 123c6a3c6ffc9903c0855e38445fc3b6588311ce Mon Sep 17 00:00:00 2001 From: Tanu Kaskinen Date: Fri, 19 Jun 2009 10:28:08 +0300 Subject: [PATCH] dbus-common: Implement infrastructure for registering D-Bus objects on all client connections and for receiving method calls from clients. --- src/Makefile.am | 9 +- src/daemon/server-lookup.c | 8 +- src/modules/module-dbus-protocol.c | 18 +- src/pulsecore/dbus-common.c | 430 +++++++++++++++++++++++++++++ src/pulsecore/dbus-common.h | 34 +++ src/pulsecore/dbus-objs/core.c | 120 ++++++++ src/pulsecore/dbus-objs/core.h | 39 +++ 7 files changed, 649 insertions(+), 9 deletions(-) create mode 100644 src/pulsecore/dbus-objs/core.c create mode 100644 src/pulsecore/dbus-objs/core.h diff --git a/src/Makefile.am b/src/Makefile.am index 5302bc22..d28ffa1e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -783,7 +783,6 @@ libpulsecore_@PA_MAJORMINORMICRO@_la_SOURCES = \ pulsecore/core-scache.c pulsecore/core-scache.h \ pulsecore/core-subscribe.c pulsecore/core-subscribe.h \ pulsecore/core.c pulsecore/core.h \ - pulsecore/dbus-common.c pulsecore/dbus-common.h \ pulsecore/envelope.c pulsecore/envelope.h \ pulsecore/fdsem.c pulsecore/fdsem.h \ pulsecore/g711.c pulsecore/g711.h \ @@ -830,7 +829,9 @@ libpulsecore_@PA_MAJORMINORMICRO@_la_LDFLAGS += $(X11_LIBS) endif if HAVE_DBUS -libpulsecore_@PA_MAJORMINORMICRO@_la_SOURCES += pulsecore/dbus-shared.c pulsecore/dbus-shared.h +libpulsecore_@PA_MAJORMINORMICRO@_la_SOURCES += \ + pulsecore/dbus-shared.c pulsecore/dbus-shared.h \ + pulsecore/dbus-common.c pulsecore/dbus-common.h libpulsecore_@PA_MAJORMINORMICRO@_la_CFLAGS += $(DBUS_CFLAGS) libpulsecore_@PA_MAJORMINORMICRO@_la_LIBADD += $(DBUS_LIBS) endif @@ -1220,7 +1221,9 @@ module_http_protocol_unix_la_LIBADD = $(AM_LIBADD) libpulsecore-@PA_MAJORMINORMI # D-Bus protocol -module_dbus_protocol_la_SOURCES = modules/module-dbus-protocol.c +module_dbus_protocol_la_SOURCES = \ + pulsecore/dbus-objs/core.c pulsecore/dbus-objs/core.h \ + modules/module-dbus-protocol.c module_dbus_protocol_la_CFLAGS = $(AM_CFLAGS) $(DBUS_CFLAGS) module_dbus_protocol_la_LDFLAGS = $(MODULE_LDFLAGS) module_dbus_protocol_la_LIBADD = $(AM_LIBADD) $(DBUS_LIBS) libpulsecore-@PA_MAJORMINORMICRO@.la libpulsecommon-@PA_MAJORMINORMICRO@.la libpulse.la diff --git a/src/daemon/server-lookup.c b/src/daemon/server-lookup.c index b53fda76..2d2d8ce6 100644 --- a/src/daemon/server-lookup.c +++ b/src/daemon/server-lookup.c @@ -48,7 +48,7 @@ static const char introspection[] = " \n" " " - " " + " " " " " " " " @@ -101,7 +101,7 @@ oom: return DBUS_HANDLER_RESULT_NEED_MEMORY; } -static DBusHandlerResult handle_get_dbus_address(DBusConnection *conn, DBusMessage *msg, pa_dbusobj_server_lookup *sl) { +static DBusHandlerResult handle_get_address(DBusConnection *conn, DBusMessage *msg, pa_dbusobj_server_lookup *sl) { DBusMessage *reply = NULL; pa_client_conf *conf = NULL; char *address = NULL; @@ -187,8 +187,8 @@ static DBusHandlerResult message_cb(DBusConnection *conn, DBusMessage *msg, void if (dbus_message_is_method_call(msg, "org.freedesktop.DBus.Introspectable", "Introspect")) return handle_introspect(conn, msg, sl); - if (dbus_message_is_method_call(msg, "org.pulseaudio.ServerLookup", "GetDBusAddress")) - return handle_get_dbus_address(conn, msg, sl); + if (dbus_message_is_method_call(msg, "org.pulseaudio.ServerLookup", "GetAddress")) + return handle_get_address(conn, msg, sl); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } diff --git a/src/modules/module-dbus-protocol.c b/src/modules/module-dbus-protocol.c index 14551488..74dfeef0 100644 --- a/src/modules/module-dbus-protocol.c +++ b/src/modules/module-dbus-protocol.c @@ -40,6 +40,8 @@ #include #include +#include + #include "module-dbus-protocol-symdef.h" PA_MODULE_DESCRIPTION("D-Bus interface"); @@ -67,6 +69,8 @@ struct userdata { pa_idxset *connections; pa_time_event *cleanup_event; + + pa_dbusobj_core *core_object; }; struct server { @@ -89,12 +93,15 @@ static const char* const valid_modargs[] = { static void connection_free(struct connection *c) { pa_assert(c); + pa_assert_se(pa_dbus_unregister_connection(c->server->userdata->module->core, pa_dbus_wrap_connection_get(c->wrap_conn)) >= 0); + pa_client_free(c->client); pa_assert_se(pa_idxset_remove_by_data(c->server->userdata->connections, c, NULL)); pa_dbus_wrap_connection_free(c->wrap_conn); pa_xfree(c); } +/* Called from pa_client_kill(). */ static void client_kill_cb(pa_client *c) { struct connection *conn; @@ -120,7 +127,7 @@ static void connection_new_cb(DBusServer *dbus_server, DBusConnection *new_conne pa_client_new_data_init(&new_data); new_data.module = s->userdata->module; new_data.driver = __FILE__; - pa_proplist_sets(new_data.proplist, PA_PROP_APPLICATION_NAME, "D-Bus client"); /* TODO: Fancier name. */ + pa_proplist_sets(new_data.proplist, PA_PROP_APPLICATION_NAME, "D-Bus client"); /* TODO: It's probably possible to generate a fancier name. Other props? */ client = pa_client_new(s->userdata->module->core, &new_data); pa_client_new_data_done(&new_data); @@ -133,10 +140,12 @@ static void connection_new_cb(DBusServer *dbus_server, DBusConnection *new_conne c->client = client; c->client->kill = client_kill_cb; - c->client->send_event = NULL; + c->client->send_event = NULL; /* TODO: Implement this. */ c->client->userdata = c; pa_idxset_put(s->userdata->connections, c, NULL); + + pa_assert_se(pa_dbus_register_connection(s->userdata->module->core, new_connection) >= 0); } /* Called by PA mainloop when a D-Bus fd watch event needs handling. */ @@ -485,6 +494,8 @@ int pa__init(pa_module *m) { cleanup_timeval.tv_sec += CLEANUP_INTERVAL; u->cleanup_event = m->core->mainloop->time_new(m->core->mainloop, &cleanup_timeval, cleanup_cb, u); + u->core_object = pa_dbusobj_core_new(m->core); + return 0; fail: @@ -513,6 +524,9 @@ void pa__done(pa_module *m) { if (!(u = m->userdata)) return; + if (u->core_object) + pa_dbusobj_core_free(u->core_object); + if (u->cleanup_event) m->core->mainloop->time_free(u->cleanup_event); diff --git a/src/pulsecore/dbus-common.c b/src/pulsecore/dbus-common.c index 05931e0a..350add82 100644 --- a/src/pulsecore/dbus-common.c +++ b/src/pulsecore/dbus-common.c @@ -25,10 +25,35 @@ #include +#include + #include +#include +#include +#include #include "dbus-common.h" +struct dbus_state { + pa_core *core; + pa_hashmap *objects; /* Object path -> struct object_entry */ + pa_idxset *connections; /* DBusConnections */ +}; + +struct object_entry { + char *path; + pa_hashmap *interfaces; /* Interface name -> struct interface_entry */ + char *introspection; +}; + +struct interface_entry { + char *name; + char **methods; + char *introspection_snippet; + DBusObjectPathMessageFunction receive; + void *userdata; +}; + char *pa_get_dbus_address_from_server_type(pa_server_type_t server_type) { char *address = NULL; char *runtime_path = NULL; @@ -71,3 +96,408 @@ char *pa_get_dbus_address_from_server_type(pa_server_type_t server_type) { return address; } + +static void update_introspection(struct object_entry *oe) { + pa_strbuf *buf; + void *state = NULL; + struct interface_entry *iface_entry = NULL; + + pa_assert(oe); + + buf = pa_strbuf_new(); + pa_strbuf_puts(buf, DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE); + pa_strbuf_puts(buf, ""); + + while ((iface_entry = pa_hashmap_iterate(oe->interfaces, &state, NULL))) + pa_strbuf_puts(buf, iface_entry->introspection_snippet); + + pa_strbuf_puts(buf, " " + " " + " " + " " + " "); + + pa_strbuf_puts(buf, ""); + + pa_xfree(oe->introspection); + oe->introspection = pa_strbuf_tostring_free(buf); +} + +static struct interface_entry *find_interface(struct object_entry *obj_entry, DBusMessage *msg) { + const char *interface; + struct interface_entry *iface_entry; + void *state = NULL; + + pa_assert(obj_entry); + pa_assert(msg); + + if ((interface = dbus_message_get_interface(msg))) + return pa_hashmap_get(obj_entry->interfaces, interface); + + /* NULL interface, we'll have to search for an interface that contains the + * method. */ + + while ((iface_entry = pa_hashmap_iterate(obj_entry->interfaces, &state, NULL))) { + char *method; + char **pos = iface_entry->methods; + + while ((method = *pos++)) { + if (!strcmp(dbus_message_get_member(msg), method)) + return iface_entry; + } + } + + return NULL; +} + +static DBusHandlerResult handle_message_cb(DBusConnection *connection, DBusMessage *message, void *user_data) { + struct dbus_state *dbus_state = user_data; + struct object_entry *obj_entry; + struct interface_entry *iface_entry; + DBusMessage *reply = NULL; + + pa_assert(connection); + pa_assert(message); + pa_assert(dbus_state); + pa_assert(dbus_state->objects); + + if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_METHOD_CALL) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + pa_assert_se((obj_entry = pa_hashmap_get(dbus_state->objects, dbus_message_get_path(message)))); + + if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) { + if (!(reply = dbus_message_new_method_return(message))) + goto oom; + + if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &obj_entry->introspection, DBUS_TYPE_INVALID)) + goto fail; + + if (!dbus_connection_send(connection, reply, NULL)) + goto oom; + + pa_log_debug("%s.%s handled.", obj_entry->path, "Introspect"); + + dbus_message_unref(reply); + + return DBUS_HANDLER_RESULT_HANDLED; + } + + if (!(iface_entry = find_interface(obj_entry, message))) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + return iface_entry->receive(connection, message, iface_entry->userdata); + +fail: + if (reply) + dbus_message_unref(reply); + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + +oom: + if (reply) + dbus_message_unref(reply); + + return DBUS_HANDLER_RESULT_NEED_MEMORY; +} + +static DBusObjectPathVTable vtable = { + .unregister_function = NULL, + .message_function = handle_message_cb, + .dbus_internal_pad1 = NULL, + .dbus_internal_pad2 = NULL, + .dbus_internal_pad3 = NULL, + .dbus_internal_pad4 = NULL +}; + +static void register_object(struct dbus_state *dbus_state, struct object_entry *obj_entry) { + DBusConnection *conn; + void *state = NULL; + + pa_assert(dbus_state); + pa_assert(obj_entry); + + if (!dbus_state->connections) + return; + + while ((conn = pa_idxset_iterate(dbus_state->connections, &state, NULL))) { + if (!dbus_connection_register_object_path(conn, obj_entry->path, &vtable, dbus_state)) + pa_log_debug("dbus_connection_register_object_path() failed."); + } +} + +static char **copy_methods(const char * const *methods) { + unsigned n = 0; + char **copy; + unsigned i; + + while (methods[n++]) + ; + + copy = pa_xnew0(char *, n); + + for (i = 0; i < n - 1; ++i) + copy[i] = pa_xstrdup(methods[i]); + + return copy; +} + +int pa_dbus_add_interface(pa_core *c, const char* path, const char* interface, const char * const *methods, const char* introspection_snippet, DBusObjectPathMessageFunction receive_cb, void *userdata) { + struct dbus_state *dbus_state; + pa_hashmap *objects; + struct object_entry *obj_entry; + struct interface_entry *iface_entry; + pa_bool_t state_created = FALSE; + pa_bool_t object_map_created = FALSE; + pa_bool_t obj_entry_created = FALSE; + + pa_assert(c); + pa_assert(path); + pa_assert(introspection_snippet); + pa_assert(receive_cb); + + if (!(dbus_state = pa_hashmap_get(c->shared, "dbus-state"))) { + dbus_state = pa_xnew0(struct dbus_state, 1); + dbus_state->core = c; + pa_hashmap_put(c->shared, "dbus-state", dbus_state); + state_created = TRUE; + } + + if (!(objects = dbus_state->objects)) { + objects = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); + dbus_state->objects = objects; + object_map_created = TRUE; + } + + if (!(obj_entry = pa_hashmap_get(objects, path))) { + obj_entry = pa_xnew(struct object_entry, 1); + obj_entry->path = pa_xstrdup(path); + obj_entry->interfaces = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); + obj_entry->introspection = NULL; + pa_hashmap_put(objects, path, obj_entry); + obj_entry_created = TRUE; + } + + if (pa_hashmap_get(obj_entry->interfaces, interface) != NULL) + goto fail; /* The interface was already registered. */ + + iface_entry = pa_xnew(struct interface_entry, 1); + iface_entry->name = pa_xstrdup(interface); + iface_entry->methods = copy_methods(methods); + iface_entry->introspection_snippet = pa_xstrdup(introspection_snippet); + iface_entry->receive = receive_cb; + iface_entry->userdata = userdata; + pa_hashmap_put(obj_entry->interfaces, iface_entry->name, iface_entry); + + update_introspection(obj_entry); + + if (obj_entry_created) + register_object(dbus_state, obj_entry); + + return 0; + +fail: + if (obj_entry_created) { + pa_hashmap_remove(objects, path); + pa_xfree(obj_entry); + } + + if (object_map_created) { + dbus_state->objects = NULL; + pa_hashmap_free(objects, NULL, NULL); + } + + if (state_created) { + pa_hashmap_remove(c->shared, "dbus-state"); + pa_xfree(dbus_state); + } + + return -1; +} + +static void unregister_object(struct dbus_state *dbus_state, struct object_entry *obj_entry) { + DBusConnection *conn; + void *state = NULL; + + pa_assert(dbus_state); + pa_assert(obj_entry); + + if (!dbus_state->connections) + return; + + while ((conn = pa_idxset_iterate(dbus_state->connections, &state, NULL))) { + if (!dbus_connection_unregister_object_path(conn, obj_entry->path)) + pa_log_debug("dbus_connection_unregister_object_path() failed."); + } +} + +static void free_methods(char **methods) { + char **pos = methods; + + while (*pos++) + pa_xfree(*pos); + + pa_xfree(methods); +} + +int pa_dbus_remove_interface(pa_core *c, const char* path, const char* interface) { + struct dbus_state *dbus_state; + pa_hashmap *objects; + struct object_entry *obj_entry; + struct interface_entry *iface_entry; + + pa_assert(c); + pa_assert(path); + pa_assert(interface); + + if (!(dbus_state = pa_hashmap_get(c->shared, "dbus-state"))) + return -1; + + if (!(objects = dbus_state->objects)) + return -1; + + if (!(obj_entry = pa_hashmap_get(objects, path))) + return -1; + + if (!(iface_entry = pa_hashmap_remove(obj_entry->interfaces, interface))) + return -1; + + update_introspection(obj_entry); + + pa_xfree(iface_entry->name); + free_methods(iface_entry->methods); + pa_xfree(iface_entry->introspection_snippet); + pa_xfree(iface_entry); + + if (pa_hashmap_isempty(obj_entry->interfaces)) { + unregister_object(dbus_state, obj_entry); + + pa_hashmap_remove(objects, path); + pa_xfree(obj_entry->path); + pa_hashmap_free(obj_entry->interfaces, NULL, NULL); + pa_xfree(obj_entry->introspection); + pa_xfree(obj_entry); + } + + if (pa_hashmap_isempty(objects)) { + dbus_state->objects = NULL; + pa_hashmap_free(objects, NULL, NULL); + } + + if (!dbus_state->objects && !dbus_state->connections) { + pa_hashmap_remove(c->shared, "dbus-state"); + pa_xfree(dbus_state); + } + + return 0; +} + +static void register_all_objects(struct dbus_state *dbus_state, DBusConnection *conn) { + struct object_entry *obj_entry; + void *state = NULL; + + pa_assert(dbus_state); + pa_assert(conn); + + if (!dbus_state->objects) + return; + + while ((obj_entry = pa_hashmap_iterate(dbus_state->objects, &state, NULL))) { + if (!dbus_connection_register_object_path(conn, obj_entry->path, &vtable, dbus_state)) + pa_log_debug("dbus_connection_register_object_path() failed."); + } +} + +int pa_dbus_register_connection(pa_core *c, DBusConnection *conn) { + struct dbus_state *dbus_state; + pa_idxset *connections; + pa_bool_t state_created = FALSE; + pa_bool_t connection_set_created = FALSE; + + pa_assert(c); + pa_assert(conn); + + if (!(dbus_state = pa_hashmap_get(c->shared, "dbus-state"))) { + dbus_state = pa_xnew0(struct dbus_state, 1); + dbus_state->core = c; + pa_hashmap_put(c->shared, "dbus-state", dbus_state); + state_created = TRUE; + } + + if (!(connections = dbus_state->connections)) { + connections = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); + dbus_state->connections = connections; + connection_set_created = TRUE; + } + + if (pa_idxset_get_by_data(connections, conn, NULL)) + goto fail; /* The connection was already registered. */ + + register_all_objects(dbus_state, conn); + + pa_idxset_put(connections, dbus_connection_ref(conn), NULL); + + return 0; + +fail: + if (connection_set_created) { + dbus_state->connections = NULL; + pa_idxset_free(connections, NULL, NULL); + } + + if (state_created) { + pa_hashmap_remove(c->shared, "dbus-state"); + pa_xfree(dbus_state); + } + + return -1; +} + +static void unregister_all_objects(struct dbus_state *dbus_state, DBusConnection *conn) { + struct object_entry *obj_entry; + void *state = NULL; + + pa_assert(dbus_state); + pa_assert(conn); + + if (!dbus_state->objects) + return; + + while ((obj_entry = pa_hashmap_iterate(dbus_state->objects, &state, NULL))) { + if (!dbus_connection_unregister_object_path(conn, obj_entry->path)) + pa_log_debug("dus_connection_unregister_object_path() failed."); + } +} + +int pa_dbus_unregister_connection(pa_core *c, DBusConnection *conn) { + struct dbus_state *dbus_state; + pa_idxset *connections; + + pa_assert(c); + pa_assert(conn); + + if (!(dbus_state = pa_hashmap_get(c->shared, "dbus-state"))) + return -1; + + if (!(connections = dbus_state->connections)) + return -1; + + if (!pa_idxset_remove_by_data(connections, conn, NULL)) + return -1; + + unregister_all_objects(dbus_state, conn); + + dbus_connection_unref(conn); + + if (pa_idxset_isempty(connections)) { + dbus_state->connections = NULL; + pa_idxset_free(connections, NULL, NULL); + } + + if (!dbus_state->objects && !dbus_state->connections) { + pa_hashmap_remove(c->shared, "dbus-state"); + pa_xfree(dbus_state); + } + + return 0; +} diff --git a/src/pulsecore/dbus-common.h b/src/pulsecore/dbus-common.h index 26bd05d4..23c7c221 100644 --- a/src/pulsecore/dbus-common.h +++ b/src/pulsecore/dbus-common.h @@ -22,6 +22,8 @@ USA. ***/ +#include + #include #include @@ -30,10 +32,42 @@ #define PA_DBUS_SYSTEM_SOCKET_PATH PA_SYSTEM_RUNTIME_PATH PA_PATH_SEP PA_DBUS_SOCKET_NAME +/* NOTE: These functions may only be called from the main thread. */ + /* Returns the default address of the server type in the escaped form. For * PA_SERVER_TYPE_NONE an empty string is returned. The caller frees the * string. This function may fail in some rare cases, in which case NULL is * returned. */ char *pa_get_dbus_address_from_server_type(pa_server_type_t server_type); +/* Registers the given interface to the given object path. This is additive: it + * doesn't matter whether or not the object has already been registered; if it + * is, then its interface set is just extended. + * + * Introspection requests are handled automatically. For that to work, the + * caller gives an XML snippet containing the interface introspection element. + * All interface snippets are automatically combined to provide the final + * introspection string. + * + * The introspection snippet contains the interface name and the methods, but + * since this function doesn't do XML parsing, the interface name and the set + * of method names have to be supplied separately. If the interface doesn't + * contain any methods, NULL may be given as the methods parameter, otherwise + * the methods parameter must be a NULL-terminated array of strings. + * + * Fails and returns a negative number if the object already has the interface + * registered. */ +int pa_dbus_add_interface(pa_core *c, const char* path, const char* interface, const char * const *methods, const char* introspection_snippet, DBusObjectPathMessageFunction receive_cb, void *userdata); + +/* Returns a negative number if the given object doesn't have the given + * interface registered. */ +int pa_dbus_remove_interface(pa_core *c, const char* path, const char* interface); + +/* Fails and returns a negative number if the connection is already + * registered. */ +int pa_dbus_register_connection(pa_core *c, DBusConnection *conn); + +/* Returns a negative number if the connection wasn't registered. */ +int pa_dbus_unregister_connection(pa_core *c, DBusConnection *conn); + #endif diff --git a/src/pulsecore/dbus-objs/core.c b/src/pulsecore/dbus-objs/core.c new file mode 100644 index 00000000..f59c478a --- /dev/null +++ b/src/pulsecore/dbus-objs/core.c @@ -0,0 +1,120 @@ +/*** + This file is part of PulseAudio. + + Copyright 2009 Tanu Kaskinen + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include + +#include +#include + +#include "core.h" + +#define OBJECT_NAME "/org/pulseaudio/core" +#define INTERFACE_NAME "org.pulseaudio.Core" + +struct pa_dbusobj_core { + pa_core *core; +}; + +static const char *introspection_snippet = + " " + " " + " " + " " + " "; + +static const char *methods[] = { + "Test", + NULL +}; + +static DBusHandlerResult handle_test(DBusConnection *conn, DBusMessage *msg, pa_dbusobj_core *c) { + DBusMessage *reply = NULL; + const char *reply_message = "Hello!"; + + pa_assert(conn); + pa_assert(msg); + pa_assert(c); + + if (!(reply = dbus_message_new_method_return(msg))) + goto oom; + + if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &reply_message, DBUS_TYPE_INVALID)) + goto fail; + + if (!dbus_connection_send(conn, reply, NULL)) + goto oom; + + dbus_message_unref(reply); + + return DBUS_HANDLER_RESULT_HANDLED; + +fail: + if (reply) + dbus_message_unref(reply); + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + +oom: + if (reply) + dbus_message_unref(reply); + + return DBUS_HANDLER_RESULT_NEED_MEMORY; +} + +static DBusHandlerResult receive_cb(DBusConnection *connection, DBusMessage *message, void *user_data) { + pa_dbusobj_core *c = user_data; + + pa_assert(connection); + pa_assert(message); + pa_assert(c); + + if (dbus_message_is_method_call(message, INTERFACE_NAME, "Test")) + return handle_test(connection, message, c); + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +pa_dbusobj_core *pa_dbusobj_core_new(pa_core *core) { + pa_dbusobj_core *c; + + pa_assert(core); + + c = pa_xnew(pa_dbusobj_core, 1); + c->core = core; + + pa_dbus_add_interface(core, OBJECT_NAME, INTERFACE_NAME, methods, introspection_snippet, receive_cb, c); + + return c; +} + +void pa_dbusobj_core_free(pa_dbusobj_core *c) { + pa_assert(c); + + pa_dbus_remove_interface(c->core, OBJECT_NAME, INTERFACE_NAME); + + pa_xfree(c); +} diff --git a/src/pulsecore/dbus-objs/core.h b/src/pulsecore/dbus-objs/core.h new file mode 100644 index 00000000..8e59cc3d --- /dev/null +++ b/src/pulsecore/dbus-objs/core.h @@ -0,0 +1,39 @@ +#ifndef foodbusobjscorehfoo +#define foodbusobjscorehfoo + +/*** + This file is part of PulseAudio. + + Copyright 2009 Tanu Kaskinen + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +/* This object implements the D-Bus object at path /org/pulseaudio/core. + * The implemented interface is org.pulseaudio.Core. + * + * See http://pulseaudio.org/wiki/DBusInterface for the Core interface + * documentation. + */ + +#include + +typedef struct pa_dbusobj_core pa_dbusobj_core; + +pa_dbusobj_core *pa_dbusobj_core_new(pa_core *core); +void pa_dbusobj_core_free(pa_dbusobj_core *c); + +#endif -- 2.39.2