153a5a1b3Sopenharmony_ci/*** 253a5a1b3Sopenharmony_ci This file is part of PulseAudio. 353a5a1b3Sopenharmony_ci 453a5a1b3Sopenharmony_ci Copyright 2009 Tanu Kaskinen 553a5a1b3Sopenharmony_ci Copyright 2009 Vincent Filali-Ansary <filali.v@azurdigitalnetworks.net> 653a5a1b3Sopenharmony_ci 753a5a1b3Sopenharmony_ci PulseAudio is free software; you can redistribute it and/or modify 853a5a1b3Sopenharmony_ci it under the terms of the GNU Lesser General Public License as published 953a5a1b3Sopenharmony_ci by the Free Software Foundation; either version 2.1 of the License, 1053a5a1b3Sopenharmony_ci or (at your option) any later version. 1153a5a1b3Sopenharmony_ci 1253a5a1b3Sopenharmony_ci PulseAudio is distributed in the hope that it will be useful, but 1353a5a1b3Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 1453a5a1b3Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1553a5a1b3Sopenharmony_ci General Public License for more details. 1653a5a1b3Sopenharmony_ci 1753a5a1b3Sopenharmony_ci You should have received a copy of the GNU Lesser General Public License 1853a5a1b3Sopenharmony_ci along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 1953a5a1b3Sopenharmony_ci***/ 2053a5a1b3Sopenharmony_ci 2153a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H 2253a5a1b3Sopenharmony_ci#include <config.h> 2353a5a1b3Sopenharmony_ci#endif 2453a5a1b3Sopenharmony_ci 2553a5a1b3Sopenharmony_ci#include <dbus/dbus.h> 2653a5a1b3Sopenharmony_ci 2753a5a1b3Sopenharmony_ci#include <pulsecore/core-util.h> 2853a5a1b3Sopenharmony_ci#include <pulsecore/dbus-util.h> 2953a5a1b3Sopenharmony_ci#include <pulsecore/protocol-dbus.h> 3053a5a1b3Sopenharmony_ci 3153a5a1b3Sopenharmony_ci#include "iface-client.h" 3253a5a1b3Sopenharmony_ci 3353a5a1b3Sopenharmony_ci#define OBJECT_NAME "client" 3453a5a1b3Sopenharmony_ci 3553a5a1b3Sopenharmony_cistruct pa_dbusiface_client { 3653a5a1b3Sopenharmony_ci pa_dbusiface_core *core; 3753a5a1b3Sopenharmony_ci 3853a5a1b3Sopenharmony_ci pa_client *client; 3953a5a1b3Sopenharmony_ci char *path; 4053a5a1b3Sopenharmony_ci pa_proplist *proplist; 4153a5a1b3Sopenharmony_ci 4253a5a1b3Sopenharmony_ci pa_hook_slot *client_proplist_changed_slot; 4353a5a1b3Sopenharmony_ci 4453a5a1b3Sopenharmony_ci pa_dbus_protocol *dbus_protocol; 4553a5a1b3Sopenharmony_ci}; 4653a5a1b3Sopenharmony_ci 4753a5a1b3Sopenharmony_cistatic void handle_get_index(DBusConnection *conn, DBusMessage *msg, void *userdata); 4853a5a1b3Sopenharmony_cistatic void handle_get_driver(DBusConnection *conn, DBusMessage *msg, void *userdata); 4953a5a1b3Sopenharmony_cistatic void handle_get_owner_module(DBusConnection *conn, DBusMessage *msg, void *userdata); 5053a5a1b3Sopenharmony_cistatic void handle_get_playback_streams(DBusConnection *conn, DBusMessage *msg, void *userdata); 5153a5a1b3Sopenharmony_cistatic void handle_get_record_streams(DBusConnection *conn, DBusMessage *msg, void *userdata); 5253a5a1b3Sopenharmony_cistatic void handle_get_property_list(DBusConnection *conn, DBusMessage *msg, void *userdata); 5353a5a1b3Sopenharmony_ci 5453a5a1b3Sopenharmony_cistatic void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata); 5553a5a1b3Sopenharmony_ci 5653a5a1b3Sopenharmony_cistatic void handle_kill(DBusConnection *conn, DBusMessage *msg, void *userdata); 5753a5a1b3Sopenharmony_cistatic void handle_update_properties(DBusConnection *conn, DBusMessage *msg, void *userdata); 5853a5a1b3Sopenharmony_cistatic void handle_remove_properties(DBusConnection *conn, DBusMessage *msg, void *userdata); 5953a5a1b3Sopenharmony_ci 6053a5a1b3Sopenharmony_cienum property_handler_index { 6153a5a1b3Sopenharmony_ci PROPERTY_HANDLER_INDEX, 6253a5a1b3Sopenharmony_ci PROPERTY_HANDLER_DRIVER, 6353a5a1b3Sopenharmony_ci PROPERTY_HANDLER_OWNER_MODULE, 6453a5a1b3Sopenharmony_ci PROPERTY_HANDLER_PLAYBACK_STREAMS, 6553a5a1b3Sopenharmony_ci PROPERTY_HANDLER_RECORD_STREAMS, 6653a5a1b3Sopenharmony_ci PROPERTY_HANDLER_PROPERTY_LIST, 6753a5a1b3Sopenharmony_ci PROPERTY_HANDLER_MAX 6853a5a1b3Sopenharmony_ci}; 6953a5a1b3Sopenharmony_ci 7053a5a1b3Sopenharmony_cistatic pa_dbus_property_handler property_handlers[PROPERTY_HANDLER_MAX] = { 7153a5a1b3Sopenharmony_ci [PROPERTY_HANDLER_INDEX] = { .property_name = "Index", .type = "u", .get_cb = handle_get_index, .set_cb = NULL }, 7253a5a1b3Sopenharmony_ci [PROPERTY_HANDLER_DRIVER] = { .property_name = "Driver", .type = "s", .get_cb = handle_get_driver, .set_cb = NULL }, 7353a5a1b3Sopenharmony_ci [PROPERTY_HANDLER_OWNER_MODULE] = { .property_name = "OwnerModule", .type = "o", .get_cb = handle_get_owner_module, .set_cb = NULL }, 7453a5a1b3Sopenharmony_ci [PROPERTY_HANDLER_PLAYBACK_STREAMS] = { .property_name = "PlaybackStreams", .type = "ao", .get_cb = handle_get_playback_streams, .set_cb = NULL }, 7553a5a1b3Sopenharmony_ci [PROPERTY_HANDLER_RECORD_STREAMS] = { .property_name = "RecordStreams", .type = "ao", .get_cb = handle_get_record_streams, .set_cb = NULL }, 7653a5a1b3Sopenharmony_ci [PROPERTY_HANDLER_PROPERTY_LIST] = { .property_name = "PropertyList", .type = "a{say}", .get_cb = handle_get_property_list, .set_cb = NULL } 7753a5a1b3Sopenharmony_ci}; 7853a5a1b3Sopenharmony_ci 7953a5a1b3Sopenharmony_cienum method_handler_index { 8053a5a1b3Sopenharmony_ci METHOD_HANDLER_KILL, 8153a5a1b3Sopenharmony_ci METHOD_HANDLER_UPDATE_PROPERTIES, 8253a5a1b3Sopenharmony_ci METHOD_HANDLER_REMOVE_PROPERTIES, 8353a5a1b3Sopenharmony_ci METHOD_HANDLER_MAX 8453a5a1b3Sopenharmony_ci}; 8553a5a1b3Sopenharmony_ci 8653a5a1b3Sopenharmony_cistatic pa_dbus_arg_info update_properties_args[] = { { "property_list", "a{say}", "in" }, { "update_mode", "u", "in" } }; 8753a5a1b3Sopenharmony_cistatic pa_dbus_arg_info remove_properties_args[] = { { "keys", "as", "in" } }; 8853a5a1b3Sopenharmony_ci 8953a5a1b3Sopenharmony_cistatic pa_dbus_method_handler method_handlers[METHOD_HANDLER_MAX] = { 9053a5a1b3Sopenharmony_ci [METHOD_HANDLER_KILL] = { 9153a5a1b3Sopenharmony_ci .method_name = "Kill", 9253a5a1b3Sopenharmony_ci .arguments = NULL, 9353a5a1b3Sopenharmony_ci .n_arguments = 0, 9453a5a1b3Sopenharmony_ci .receive_cb = handle_kill }, 9553a5a1b3Sopenharmony_ci [METHOD_HANDLER_UPDATE_PROPERTIES] = { 9653a5a1b3Sopenharmony_ci .method_name = "UpdateProperties", 9753a5a1b3Sopenharmony_ci .arguments = update_properties_args, 9853a5a1b3Sopenharmony_ci .n_arguments = sizeof(update_properties_args) / sizeof(pa_dbus_arg_info), 9953a5a1b3Sopenharmony_ci .receive_cb = handle_update_properties }, 10053a5a1b3Sopenharmony_ci [METHOD_HANDLER_REMOVE_PROPERTIES] = { 10153a5a1b3Sopenharmony_ci .method_name = "RemoveProperties", 10253a5a1b3Sopenharmony_ci .arguments = remove_properties_args, 10353a5a1b3Sopenharmony_ci .n_arguments = sizeof(remove_properties_args) / sizeof(pa_dbus_arg_info), 10453a5a1b3Sopenharmony_ci .receive_cb = handle_remove_properties } 10553a5a1b3Sopenharmony_ci}; 10653a5a1b3Sopenharmony_ci 10753a5a1b3Sopenharmony_cienum signal_index { 10853a5a1b3Sopenharmony_ci SIGNAL_PROPERTY_LIST_UPDATED, 10953a5a1b3Sopenharmony_ci SIGNAL_CLIENT_EVENT, 11053a5a1b3Sopenharmony_ci SIGNAL_MAX 11153a5a1b3Sopenharmony_ci}; 11253a5a1b3Sopenharmony_ci 11353a5a1b3Sopenharmony_cistatic pa_dbus_arg_info property_list_updated_args[] = { { "property_list", "a{say}", NULL } }; 11453a5a1b3Sopenharmony_cistatic pa_dbus_arg_info client_event_args[] = { { "name", "s", NULL }, 11553a5a1b3Sopenharmony_ci { "property_list", "a{say}", NULL } }; 11653a5a1b3Sopenharmony_ci 11753a5a1b3Sopenharmony_cistatic pa_dbus_signal_info signals[SIGNAL_MAX] = { 11853a5a1b3Sopenharmony_ci [SIGNAL_PROPERTY_LIST_UPDATED] = { .name = "PropertyListUpdated", .arguments = property_list_updated_args, .n_arguments = 1 }, 11953a5a1b3Sopenharmony_ci /* ClientEvent is sent from module-dbus-protocol.c. */ 12053a5a1b3Sopenharmony_ci [SIGNAL_CLIENT_EVENT] = { .name = "ClientEvent", .arguments = client_event_args, .n_arguments = 1 } 12153a5a1b3Sopenharmony_ci}; 12253a5a1b3Sopenharmony_ci 12353a5a1b3Sopenharmony_cistatic pa_dbus_interface_info client_interface_info = { 12453a5a1b3Sopenharmony_ci .name = PA_DBUSIFACE_CLIENT_INTERFACE, 12553a5a1b3Sopenharmony_ci .method_handlers = method_handlers, 12653a5a1b3Sopenharmony_ci .n_method_handlers = METHOD_HANDLER_MAX, 12753a5a1b3Sopenharmony_ci .property_handlers = property_handlers, 12853a5a1b3Sopenharmony_ci .n_property_handlers = PROPERTY_HANDLER_MAX, 12953a5a1b3Sopenharmony_ci .get_all_properties_cb = handle_get_all, 13053a5a1b3Sopenharmony_ci .signals = signals, 13153a5a1b3Sopenharmony_ci .n_signals = SIGNAL_MAX 13253a5a1b3Sopenharmony_ci}; 13353a5a1b3Sopenharmony_ci 13453a5a1b3Sopenharmony_cistatic void handle_get_index(DBusConnection *conn, DBusMessage *msg, void *userdata) { 13553a5a1b3Sopenharmony_ci pa_dbusiface_client *c = userdata; 13653a5a1b3Sopenharmony_ci dbus_uint32_t idx = 0; 13753a5a1b3Sopenharmony_ci 13853a5a1b3Sopenharmony_ci pa_assert(conn); 13953a5a1b3Sopenharmony_ci pa_assert(msg); 14053a5a1b3Sopenharmony_ci pa_assert(c); 14153a5a1b3Sopenharmony_ci 14253a5a1b3Sopenharmony_ci idx = c->client->index; 14353a5a1b3Sopenharmony_ci 14453a5a1b3Sopenharmony_ci pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &idx); 14553a5a1b3Sopenharmony_ci} 14653a5a1b3Sopenharmony_ci 14753a5a1b3Sopenharmony_cistatic void handle_get_driver(DBusConnection *conn, DBusMessage *msg, void *userdata) { 14853a5a1b3Sopenharmony_ci pa_dbusiface_client *c = userdata; 14953a5a1b3Sopenharmony_ci 15053a5a1b3Sopenharmony_ci pa_assert(conn); 15153a5a1b3Sopenharmony_ci pa_assert(msg); 15253a5a1b3Sopenharmony_ci pa_assert(c); 15353a5a1b3Sopenharmony_ci 15453a5a1b3Sopenharmony_ci pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_STRING, &c->client->driver); 15553a5a1b3Sopenharmony_ci} 15653a5a1b3Sopenharmony_ci 15753a5a1b3Sopenharmony_cistatic void handle_get_owner_module(DBusConnection *conn, DBusMessage *msg, void *userdata) { 15853a5a1b3Sopenharmony_ci pa_dbusiface_client *c = userdata; 15953a5a1b3Sopenharmony_ci const char *owner_module = NULL; 16053a5a1b3Sopenharmony_ci 16153a5a1b3Sopenharmony_ci pa_assert(conn); 16253a5a1b3Sopenharmony_ci pa_assert(msg); 16353a5a1b3Sopenharmony_ci pa_assert(c); 16453a5a1b3Sopenharmony_ci 16553a5a1b3Sopenharmony_ci if (!c->client->module) { 16653a5a1b3Sopenharmony_ci pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "Client %d doesn't have an owner module.", c->client->index); 16753a5a1b3Sopenharmony_ci return; 16853a5a1b3Sopenharmony_ci } 16953a5a1b3Sopenharmony_ci 17053a5a1b3Sopenharmony_ci owner_module = pa_dbusiface_core_get_module_path(c->core, c->client->module); 17153a5a1b3Sopenharmony_ci 17253a5a1b3Sopenharmony_ci pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &owner_module); 17353a5a1b3Sopenharmony_ci} 17453a5a1b3Sopenharmony_ci 17553a5a1b3Sopenharmony_ci/* The caller frees the array, but not the strings. */ 17653a5a1b3Sopenharmony_cistatic const char **get_playback_streams(pa_dbusiface_client *c, unsigned *n) { 17753a5a1b3Sopenharmony_ci const char **playback_streams = NULL; 17853a5a1b3Sopenharmony_ci unsigned i = 0; 17953a5a1b3Sopenharmony_ci uint32_t idx = 0; 18053a5a1b3Sopenharmony_ci pa_sink_input *sink_input = NULL; 18153a5a1b3Sopenharmony_ci 18253a5a1b3Sopenharmony_ci pa_assert(c); 18353a5a1b3Sopenharmony_ci pa_assert(n); 18453a5a1b3Sopenharmony_ci 18553a5a1b3Sopenharmony_ci *n = pa_idxset_size(c->client->sink_inputs); 18653a5a1b3Sopenharmony_ci 18753a5a1b3Sopenharmony_ci if (*n == 0) 18853a5a1b3Sopenharmony_ci return NULL; 18953a5a1b3Sopenharmony_ci 19053a5a1b3Sopenharmony_ci playback_streams = pa_xnew(const char *, *n); 19153a5a1b3Sopenharmony_ci 19253a5a1b3Sopenharmony_ci PA_IDXSET_FOREACH(sink_input, c->client->sink_inputs, idx) 19353a5a1b3Sopenharmony_ci playback_streams[i++] = pa_dbusiface_core_get_playback_stream_path(c->core, sink_input); 19453a5a1b3Sopenharmony_ci 19553a5a1b3Sopenharmony_ci return playback_streams; 19653a5a1b3Sopenharmony_ci} 19753a5a1b3Sopenharmony_ci 19853a5a1b3Sopenharmony_cistatic void handle_get_playback_streams(DBusConnection *conn, DBusMessage *msg, void *userdata) { 19953a5a1b3Sopenharmony_ci pa_dbusiface_client *c = userdata; 20053a5a1b3Sopenharmony_ci const char **playback_streams = NULL; 20153a5a1b3Sopenharmony_ci unsigned n_playback_streams = 0; 20253a5a1b3Sopenharmony_ci 20353a5a1b3Sopenharmony_ci pa_assert(conn); 20453a5a1b3Sopenharmony_ci pa_assert(msg); 20553a5a1b3Sopenharmony_ci pa_assert(c); 20653a5a1b3Sopenharmony_ci 20753a5a1b3Sopenharmony_ci playback_streams = get_playback_streams(c, &n_playback_streams); 20853a5a1b3Sopenharmony_ci 20953a5a1b3Sopenharmony_ci pa_dbus_send_basic_array_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, playback_streams, n_playback_streams); 21053a5a1b3Sopenharmony_ci 21153a5a1b3Sopenharmony_ci pa_xfree(playback_streams); 21253a5a1b3Sopenharmony_ci} 21353a5a1b3Sopenharmony_ci 21453a5a1b3Sopenharmony_ci/* The caller frees the array, but not the strings. */ 21553a5a1b3Sopenharmony_cistatic const char **get_record_streams(pa_dbusiface_client *c, unsigned *n) { 21653a5a1b3Sopenharmony_ci const char **record_streams = NULL; 21753a5a1b3Sopenharmony_ci unsigned i = 0; 21853a5a1b3Sopenharmony_ci uint32_t idx = 0; 21953a5a1b3Sopenharmony_ci pa_source_output *source_output = NULL; 22053a5a1b3Sopenharmony_ci 22153a5a1b3Sopenharmony_ci pa_assert(c); 22253a5a1b3Sopenharmony_ci pa_assert(n); 22353a5a1b3Sopenharmony_ci 22453a5a1b3Sopenharmony_ci *n = pa_idxset_size(c->client->source_outputs); 22553a5a1b3Sopenharmony_ci 22653a5a1b3Sopenharmony_ci if (*n == 0) 22753a5a1b3Sopenharmony_ci return NULL; 22853a5a1b3Sopenharmony_ci 22953a5a1b3Sopenharmony_ci record_streams = pa_xnew(const char *, *n); 23053a5a1b3Sopenharmony_ci 23153a5a1b3Sopenharmony_ci PA_IDXSET_FOREACH(source_output, c->client->source_outputs, idx) 23253a5a1b3Sopenharmony_ci record_streams[i++] = pa_dbusiface_core_get_record_stream_path(c->core, source_output); 23353a5a1b3Sopenharmony_ci 23453a5a1b3Sopenharmony_ci return record_streams; 23553a5a1b3Sopenharmony_ci} 23653a5a1b3Sopenharmony_ci 23753a5a1b3Sopenharmony_cistatic void handle_get_record_streams(DBusConnection *conn, DBusMessage *msg, void *userdata) { 23853a5a1b3Sopenharmony_ci pa_dbusiface_client *c = userdata; 23953a5a1b3Sopenharmony_ci const char **record_streams = NULL; 24053a5a1b3Sopenharmony_ci unsigned n_record_streams = 0; 24153a5a1b3Sopenharmony_ci 24253a5a1b3Sopenharmony_ci pa_assert(conn); 24353a5a1b3Sopenharmony_ci pa_assert(msg); 24453a5a1b3Sopenharmony_ci pa_assert(c); 24553a5a1b3Sopenharmony_ci 24653a5a1b3Sopenharmony_ci record_streams = get_record_streams(c, &n_record_streams); 24753a5a1b3Sopenharmony_ci 24853a5a1b3Sopenharmony_ci pa_dbus_send_basic_array_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, record_streams, n_record_streams); 24953a5a1b3Sopenharmony_ci 25053a5a1b3Sopenharmony_ci pa_xfree(record_streams); 25153a5a1b3Sopenharmony_ci} 25253a5a1b3Sopenharmony_ci 25353a5a1b3Sopenharmony_cistatic void handle_get_property_list(DBusConnection *conn, DBusMessage *msg, void *userdata) { 25453a5a1b3Sopenharmony_ci pa_dbusiface_client *c = userdata; 25553a5a1b3Sopenharmony_ci 25653a5a1b3Sopenharmony_ci pa_assert(conn); 25753a5a1b3Sopenharmony_ci pa_assert(msg); 25853a5a1b3Sopenharmony_ci pa_assert(c); 25953a5a1b3Sopenharmony_ci 26053a5a1b3Sopenharmony_ci pa_dbus_send_proplist_variant_reply(conn, msg, c->client->proplist); 26153a5a1b3Sopenharmony_ci} 26253a5a1b3Sopenharmony_ci 26353a5a1b3Sopenharmony_cistatic void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata) { 26453a5a1b3Sopenharmony_ci pa_dbusiface_client *c = userdata; 26553a5a1b3Sopenharmony_ci DBusMessage *reply = NULL; 26653a5a1b3Sopenharmony_ci DBusMessageIter msg_iter; 26753a5a1b3Sopenharmony_ci DBusMessageIter dict_iter; 26853a5a1b3Sopenharmony_ci dbus_uint32_t idx = 0; 26953a5a1b3Sopenharmony_ci const char *owner_module = NULL; 27053a5a1b3Sopenharmony_ci const char **playback_streams = NULL; 27153a5a1b3Sopenharmony_ci unsigned n_playback_streams = 0; 27253a5a1b3Sopenharmony_ci const char **record_streams = NULL; 27353a5a1b3Sopenharmony_ci unsigned n_record_streams = 0; 27453a5a1b3Sopenharmony_ci 27553a5a1b3Sopenharmony_ci pa_assert(conn); 27653a5a1b3Sopenharmony_ci pa_assert(msg); 27753a5a1b3Sopenharmony_ci pa_assert(c); 27853a5a1b3Sopenharmony_ci 27953a5a1b3Sopenharmony_ci idx = c->client->index; 28053a5a1b3Sopenharmony_ci if (c->client->module) 28153a5a1b3Sopenharmony_ci owner_module = pa_dbusiface_core_get_module_path(c->core, c->client->module); 28253a5a1b3Sopenharmony_ci playback_streams = get_playback_streams(c, &n_playback_streams); 28353a5a1b3Sopenharmony_ci record_streams = get_record_streams(c, &n_record_streams); 28453a5a1b3Sopenharmony_ci 28553a5a1b3Sopenharmony_ci pa_assert_se((reply = dbus_message_new_method_return(msg))); 28653a5a1b3Sopenharmony_ci 28753a5a1b3Sopenharmony_ci dbus_message_iter_init_append(reply, &msg_iter); 28853a5a1b3Sopenharmony_ci pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "{sv}", &dict_iter)); 28953a5a1b3Sopenharmony_ci 29053a5a1b3Sopenharmony_ci pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_INDEX].property_name, DBUS_TYPE_UINT32, &idx); 29153a5a1b3Sopenharmony_ci pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_DRIVER].property_name, DBUS_TYPE_STRING, &c->client->driver); 29253a5a1b3Sopenharmony_ci 29353a5a1b3Sopenharmony_ci if (owner_module) 29453a5a1b3Sopenharmony_ci pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_OWNER_MODULE].property_name, DBUS_TYPE_OBJECT_PATH, &owner_module); 29553a5a1b3Sopenharmony_ci 29653a5a1b3Sopenharmony_ci pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_PLAYBACK_STREAMS].property_name, DBUS_TYPE_OBJECT_PATH, playback_streams, n_playback_streams); 29753a5a1b3Sopenharmony_ci pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_RECORD_STREAMS].property_name, DBUS_TYPE_OBJECT_PATH, record_streams, n_record_streams); 29853a5a1b3Sopenharmony_ci pa_dbus_append_proplist_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_PROPERTY_LIST].property_name, c->client->proplist); 29953a5a1b3Sopenharmony_ci 30053a5a1b3Sopenharmony_ci pa_assert_se(dbus_message_iter_close_container(&msg_iter, &dict_iter)); 30153a5a1b3Sopenharmony_ci 30253a5a1b3Sopenharmony_ci pa_assert_se(dbus_connection_send(conn, reply, NULL)); 30353a5a1b3Sopenharmony_ci 30453a5a1b3Sopenharmony_ci dbus_message_unref(reply); 30553a5a1b3Sopenharmony_ci 30653a5a1b3Sopenharmony_ci pa_xfree(playback_streams); 30753a5a1b3Sopenharmony_ci pa_xfree(record_streams); 30853a5a1b3Sopenharmony_ci} 30953a5a1b3Sopenharmony_ci 31053a5a1b3Sopenharmony_cistatic void handle_kill(DBusConnection *conn, DBusMessage *msg, void *userdata) { 31153a5a1b3Sopenharmony_ci pa_dbusiface_client *c = userdata; 31253a5a1b3Sopenharmony_ci 31353a5a1b3Sopenharmony_ci pa_assert(conn); 31453a5a1b3Sopenharmony_ci pa_assert(msg); 31553a5a1b3Sopenharmony_ci pa_assert(c); 31653a5a1b3Sopenharmony_ci 31753a5a1b3Sopenharmony_ci dbus_connection_ref(conn); 31853a5a1b3Sopenharmony_ci 31953a5a1b3Sopenharmony_ci pa_client_kill(c->client); 32053a5a1b3Sopenharmony_ci 32153a5a1b3Sopenharmony_ci pa_dbus_send_empty_reply(conn, msg); 32253a5a1b3Sopenharmony_ci 32353a5a1b3Sopenharmony_ci dbus_connection_unref(conn); 32453a5a1b3Sopenharmony_ci} 32553a5a1b3Sopenharmony_ci 32653a5a1b3Sopenharmony_cistatic void handle_update_properties(DBusConnection *conn, DBusMessage *msg, void *userdata) { 32753a5a1b3Sopenharmony_ci pa_dbusiface_client *c = userdata; 32853a5a1b3Sopenharmony_ci DBusMessageIter msg_iter; 32953a5a1b3Sopenharmony_ci pa_proplist *property_list = NULL; 33053a5a1b3Sopenharmony_ci dbus_uint32_t update_mode = 0; 33153a5a1b3Sopenharmony_ci 33253a5a1b3Sopenharmony_ci pa_assert(conn); 33353a5a1b3Sopenharmony_ci pa_assert(msg); 33453a5a1b3Sopenharmony_ci pa_assert(c); 33553a5a1b3Sopenharmony_ci 33653a5a1b3Sopenharmony_ci if (pa_dbus_protocol_get_client(c->dbus_protocol, conn) != c->client) { 33753a5a1b3Sopenharmony_ci pa_dbus_send_error(conn, msg, DBUS_ERROR_ACCESS_DENIED, "Client tried to modify the property list of another client."); 33853a5a1b3Sopenharmony_ci return; 33953a5a1b3Sopenharmony_ci } 34053a5a1b3Sopenharmony_ci 34153a5a1b3Sopenharmony_ci pa_assert_se(dbus_message_iter_init(msg, &msg_iter)); 34253a5a1b3Sopenharmony_ci 34353a5a1b3Sopenharmony_ci if (!(property_list = pa_dbus_get_proplist_arg(conn, msg, &msg_iter))) 34453a5a1b3Sopenharmony_ci return; 34553a5a1b3Sopenharmony_ci 34653a5a1b3Sopenharmony_ci dbus_message_iter_get_basic(&msg_iter, &update_mode); 34753a5a1b3Sopenharmony_ci 34853a5a1b3Sopenharmony_ci if (!(update_mode == PA_UPDATE_SET || update_mode == PA_UPDATE_MERGE || update_mode == PA_UPDATE_REPLACE)) { 34953a5a1b3Sopenharmony_ci pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "Invalid update mode: %u", update_mode); 35053a5a1b3Sopenharmony_ci goto finish; 35153a5a1b3Sopenharmony_ci } 35253a5a1b3Sopenharmony_ci 35353a5a1b3Sopenharmony_ci pa_client_update_proplist(c->client, update_mode, property_list); 35453a5a1b3Sopenharmony_ci 35553a5a1b3Sopenharmony_ci pa_dbus_send_empty_reply(conn, msg); 35653a5a1b3Sopenharmony_ci 35753a5a1b3Sopenharmony_cifinish: 35853a5a1b3Sopenharmony_ci if (property_list) 35953a5a1b3Sopenharmony_ci pa_proplist_free(property_list); 36053a5a1b3Sopenharmony_ci} 36153a5a1b3Sopenharmony_ci 36253a5a1b3Sopenharmony_cistatic void handle_remove_properties(DBusConnection *conn, DBusMessage *msg, void *userdata) { 36353a5a1b3Sopenharmony_ci pa_dbusiface_client *c = userdata; 36453a5a1b3Sopenharmony_ci char **keys = NULL; 36553a5a1b3Sopenharmony_ci int n_keys = 0; 36653a5a1b3Sopenharmony_ci bool changed = false; 36753a5a1b3Sopenharmony_ci int i = 0; 36853a5a1b3Sopenharmony_ci 36953a5a1b3Sopenharmony_ci pa_assert(conn); 37053a5a1b3Sopenharmony_ci pa_assert(msg); 37153a5a1b3Sopenharmony_ci pa_assert(c); 37253a5a1b3Sopenharmony_ci 37353a5a1b3Sopenharmony_ci if (pa_dbus_protocol_get_client(c->dbus_protocol, conn) != c->client) { 37453a5a1b3Sopenharmony_ci pa_dbus_send_error(conn, msg, DBUS_ERROR_ACCESS_DENIED, "Client tried to modify the property list of another client."); 37553a5a1b3Sopenharmony_ci return; 37653a5a1b3Sopenharmony_ci } 37753a5a1b3Sopenharmony_ci 37853a5a1b3Sopenharmony_ci pa_assert_se(dbus_message_get_args(msg, NULL, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &keys, &n_keys, DBUS_TYPE_INVALID)); 37953a5a1b3Sopenharmony_ci 38053a5a1b3Sopenharmony_ci for (i = 0; i < n_keys; ++i) 38153a5a1b3Sopenharmony_ci changed |= pa_proplist_unset(c->client->proplist, keys[i]) >= 0; 38253a5a1b3Sopenharmony_ci 38353a5a1b3Sopenharmony_ci pa_dbus_send_empty_reply(conn, msg); 38453a5a1b3Sopenharmony_ci 38553a5a1b3Sopenharmony_ci if (changed) { 38653a5a1b3Sopenharmony_ci pa_hook_fire(&c->client->core->hooks[PA_CORE_HOOK_CLIENT_PROPLIST_CHANGED], c->client); 38753a5a1b3Sopenharmony_ci pa_subscription_post(c->client->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_CHANGE, c->client->index); 38853a5a1b3Sopenharmony_ci } 38953a5a1b3Sopenharmony_ci 39053a5a1b3Sopenharmony_ci dbus_free_string_array(keys); 39153a5a1b3Sopenharmony_ci} 39253a5a1b3Sopenharmony_ci 39353a5a1b3Sopenharmony_cistatic pa_hook_result_t client_proplist_changed_cb(void *hook_data, void *call_data, void *slot_data) { 39453a5a1b3Sopenharmony_ci pa_dbusiface_client *c = slot_data; 39553a5a1b3Sopenharmony_ci pa_client *client = call_data; 39653a5a1b3Sopenharmony_ci DBusMessage *signal_msg; 39753a5a1b3Sopenharmony_ci 39853a5a1b3Sopenharmony_ci pa_assert(c); 39953a5a1b3Sopenharmony_ci pa_assert(client); 40053a5a1b3Sopenharmony_ci 40153a5a1b3Sopenharmony_ci if (c->client != client) 40253a5a1b3Sopenharmony_ci return PA_HOOK_OK; 40353a5a1b3Sopenharmony_ci 40453a5a1b3Sopenharmony_ci if (!pa_proplist_equal(c->proplist, c->client->proplist)) { 40553a5a1b3Sopenharmony_ci DBusMessageIter msg_iter; 40653a5a1b3Sopenharmony_ci 40753a5a1b3Sopenharmony_ci pa_proplist_update(c->proplist, PA_UPDATE_SET, c->client->proplist); 40853a5a1b3Sopenharmony_ci 40953a5a1b3Sopenharmony_ci pa_assert_se(signal_msg = dbus_message_new_signal(c->path, 41053a5a1b3Sopenharmony_ci PA_DBUSIFACE_CLIENT_INTERFACE, 41153a5a1b3Sopenharmony_ci signals[SIGNAL_PROPERTY_LIST_UPDATED].name)); 41253a5a1b3Sopenharmony_ci dbus_message_iter_init_append(signal_msg, &msg_iter); 41353a5a1b3Sopenharmony_ci pa_dbus_append_proplist(&msg_iter, c->proplist); 41453a5a1b3Sopenharmony_ci 41553a5a1b3Sopenharmony_ci pa_dbus_protocol_send_signal(c->dbus_protocol, signal_msg); 41653a5a1b3Sopenharmony_ci dbus_message_unref(signal_msg); 41753a5a1b3Sopenharmony_ci } 41853a5a1b3Sopenharmony_ci 41953a5a1b3Sopenharmony_ci return PA_HOOK_OK; 42053a5a1b3Sopenharmony_ci} 42153a5a1b3Sopenharmony_ci 42253a5a1b3Sopenharmony_cipa_dbusiface_client *pa_dbusiface_client_new(pa_dbusiface_core *core, pa_client *client) { 42353a5a1b3Sopenharmony_ci pa_dbusiface_client *c = NULL; 42453a5a1b3Sopenharmony_ci 42553a5a1b3Sopenharmony_ci pa_assert(core); 42653a5a1b3Sopenharmony_ci pa_assert(client); 42753a5a1b3Sopenharmony_ci 42853a5a1b3Sopenharmony_ci c = pa_xnew(pa_dbusiface_client, 1); 42953a5a1b3Sopenharmony_ci c->core = core; 43053a5a1b3Sopenharmony_ci c->client = client; 43153a5a1b3Sopenharmony_ci c->path = pa_sprintf_malloc("%s/%s%u", PA_DBUS_CORE_OBJECT_PATH, OBJECT_NAME, client->index); 43253a5a1b3Sopenharmony_ci c->proplist = pa_proplist_copy(client->proplist); 43353a5a1b3Sopenharmony_ci c->dbus_protocol = pa_dbus_protocol_get(client->core); 43453a5a1b3Sopenharmony_ci c->client_proplist_changed_slot = pa_hook_connect(&client->core->hooks[PA_CORE_HOOK_CLIENT_PROPLIST_CHANGED], 43553a5a1b3Sopenharmony_ci PA_HOOK_NORMAL, client_proplist_changed_cb, c); 43653a5a1b3Sopenharmony_ci 43753a5a1b3Sopenharmony_ci pa_assert_se(pa_dbus_protocol_add_interface(c->dbus_protocol, c->path, &client_interface_info, c) >= 0); 43853a5a1b3Sopenharmony_ci 43953a5a1b3Sopenharmony_ci return c; 44053a5a1b3Sopenharmony_ci} 44153a5a1b3Sopenharmony_ci 44253a5a1b3Sopenharmony_civoid pa_dbusiface_client_free(pa_dbusiface_client *c) { 44353a5a1b3Sopenharmony_ci pa_assert(c); 44453a5a1b3Sopenharmony_ci 44553a5a1b3Sopenharmony_ci pa_assert_se(pa_dbus_protocol_remove_interface(c->dbus_protocol, c->path, client_interface_info.name) >= 0); 44653a5a1b3Sopenharmony_ci 44753a5a1b3Sopenharmony_ci pa_hook_slot_free(c->client_proplist_changed_slot); 44853a5a1b3Sopenharmony_ci pa_proplist_free(c->proplist); 44953a5a1b3Sopenharmony_ci pa_dbus_protocol_unref(c->dbus_protocol); 45053a5a1b3Sopenharmony_ci 45153a5a1b3Sopenharmony_ci pa_xfree(c->path); 45253a5a1b3Sopenharmony_ci pa_xfree(c); 45353a5a1b3Sopenharmony_ci} 45453a5a1b3Sopenharmony_ci 45553a5a1b3Sopenharmony_ciconst char *pa_dbusiface_client_get_path(pa_dbusiface_client *c) { 45653a5a1b3Sopenharmony_ci pa_assert(c); 45753a5a1b3Sopenharmony_ci 45853a5a1b3Sopenharmony_ci return c->path; 45953a5a1b3Sopenharmony_ci} 460