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