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 <pulsecore/core-util.h>
2653a5a1b3Sopenharmony_ci#include <pulsecore/dbus-util.h>
2753a5a1b3Sopenharmony_ci#include <pulsecore/protocol-dbus.h>
2853a5a1b3Sopenharmony_ci
2953a5a1b3Sopenharmony_ci#include "iface-stream.h"
3053a5a1b3Sopenharmony_ci
3153a5a1b3Sopenharmony_ci#define PLAYBACK_OBJECT_NAME "playback_stream"
3253a5a1b3Sopenharmony_ci#define RECORD_OBJECT_NAME "record_stream"
3353a5a1b3Sopenharmony_ci
3453a5a1b3Sopenharmony_cienum stream_type {
3553a5a1b3Sopenharmony_ci    STREAM_TYPE_PLAYBACK,
3653a5a1b3Sopenharmony_ci    STREAM_TYPE_RECORD
3753a5a1b3Sopenharmony_ci};
3853a5a1b3Sopenharmony_ci
3953a5a1b3Sopenharmony_cistruct pa_dbusiface_stream {
4053a5a1b3Sopenharmony_ci    pa_dbusiface_core *core;
4153a5a1b3Sopenharmony_ci
4253a5a1b3Sopenharmony_ci    union {
4353a5a1b3Sopenharmony_ci        pa_sink_input *sink_input;
4453a5a1b3Sopenharmony_ci        pa_source_output *source_output;
4553a5a1b3Sopenharmony_ci    };
4653a5a1b3Sopenharmony_ci    enum stream_type type;
4753a5a1b3Sopenharmony_ci    char *path;
4853a5a1b3Sopenharmony_ci    union {
4953a5a1b3Sopenharmony_ci        pa_sink *sink;
5053a5a1b3Sopenharmony_ci        pa_source *source;
5153a5a1b3Sopenharmony_ci    };
5253a5a1b3Sopenharmony_ci    uint32_t sample_rate;
5353a5a1b3Sopenharmony_ci    pa_cvolume volume;
5453a5a1b3Sopenharmony_ci    dbus_bool_t mute;
5553a5a1b3Sopenharmony_ci    pa_proplist *proplist;
5653a5a1b3Sopenharmony_ci
5753a5a1b3Sopenharmony_ci    bool has_volume;
5853a5a1b3Sopenharmony_ci
5953a5a1b3Sopenharmony_ci    pa_dbus_protocol *dbus_protocol;
6053a5a1b3Sopenharmony_ci    pa_hook_slot *send_event_slot;
6153a5a1b3Sopenharmony_ci    pa_hook_slot *move_finish_slot;
6253a5a1b3Sopenharmony_ci    pa_hook_slot *volume_changed_slot;
6353a5a1b3Sopenharmony_ci    pa_hook_slot *mute_changed_slot;
6453a5a1b3Sopenharmony_ci    pa_hook_slot *proplist_changed_slot;
6553a5a1b3Sopenharmony_ci    pa_hook_slot *state_changed_slot;
6653a5a1b3Sopenharmony_ci};
6753a5a1b3Sopenharmony_ci
6853a5a1b3Sopenharmony_cistatic void handle_get_index(DBusConnection *conn, DBusMessage *msg, void *userdata);
6953a5a1b3Sopenharmony_cistatic void handle_get_driver(DBusConnection *conn, DBusMessage *msg, void *userdata);
7053a5a1b3Sopenharmony_cistatic void handle_get_owner_module(DBusConnection *conn, DBusMessage *msg, void *userdata);
7153a5a1b3Sopenharmony_cistatic void handle_get_client(DBusConnection *conn, DBusMessage *msg, void *userdata);
7253a5a1b3Sopenharmony_cistatic void handle_get_device(DBusConnection *conn, DBusMessage *msg, void *userdata);
7353a5a1b3Sopenharmony_cistatic void handle_get_sample_format(DBusConnection *conn, DBusMessage *msg, void *userdata);
7453a5a1b3Sopenharmony_cistatic void handle_get_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata);
7553a5a1b3Sopenharmony_cistatic void handle_get_channels(DBusConnection *conn, DBusMessage *msg, void *userdata);
7653a5a1b3Sopenharmony_cistatic void handle_get_volume(DBusConnection *conn, DBusMessage *msg, void *userdata);
7753a5a1b3Sopenharmony_cistatic void handle_set_volume(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata);
7853a5a1b3Sopenharmony_cistatic void handle_get_mute(DBusConnection *conn, DBusMessage *msg, void *userdata);
7953a5a1b3Sopenharmony_cistatic void handle_set_mute(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata);
8053a5a1b3Sopenharmony_cistatic void handle_get_buffer_latency(DBusConnection *conn, DBusMessage *msg, void *userdata);
8153a5a1b3Sopenharmony_cistatic void handle_get_device_latency(DBusConnection *conn, DBusMessage *msg, void *userdata);
8253a5a1b3Sopenharmony_cistatic void handle_get_resample_method(DBusConnection *conn, DBusMessage *msg, void *userdata);
8353a5a1b3Sopenharmony_cistatic void handle_get_property_list(DBusConnection *conn, DBusMessage *msg, void *userdata);
8453a5a1b3Sopenharmony_ci
8553a5a1b3Sopenharmony_cistatic void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata);
8653a5a1b3Sopenharmony_ci
8753a5a1b3Sopenharmony_cistatic void handle_move(DBusConnection *conn, DBusMessage *msg, void *userdata);
8853a5a1b3Sopenharmony_cistatic void handle_kill(DBusConnection *conn, DBusMessage *msg, void *userdata);
8953a5a1b3Sopenharmony_ci
9053a5a1b3Sopenharmony_cienum property_handler_index {
9153a5a1b3Sopenharmony_ci    PROPERTY_HANDLER_INDEX,
9253a5a1b3Sopenharmony_ci    PROPERTY_HANDLER_DRIVER,
9353a5a1b3Sopenharmony_ci    PROPERTY_HANDLER_OWNER_MODULE,
9453a5a1b3Sopenharmony_ci    PROPERTY_HANDLER_CLIENT,
9553a5a1b3Sopenharmony_ci    PROPERTY_HANDLER_DEVICE,
9653a5a1b3Sopenharmony_ci    PROPERTY_HANDLER_SAMPLE_FORMAT,
9753a5a1b3Sopenharmony_ci    PROPERTY_HANDLER_SAMPLE_RATE,
9853a5a1b3Sopenharmony_ci    PROPERTY_HANDLER_CHANNELS,
9953a5a1b3Sopenharmony_ci    PROPERTY_HANDLER_VOLUME,
10053a5a1b3Sopenharmony_ci    PROPERTY_HANDLER_MUTE,
10153a5a1b3Sopenharmony_ci    PROPERTY_HANDLER_BUFFER_LATENCY,
10253a5a1b3Sopenharmony_ci    PROPERTY_HANDLER_DEVICE_LATENCY,
10353a5a1b3Sopenharmony_ci    PROPERTY_HANDLER_RESAMPLE_METHOD,
10453a5a1b3Sopenharmony_ci    PROPERTY_HANDLER_PROPERTY_LIST,
10553a5a1b3Sopenharmony_ci    PROPERTY_HANDLER_MAX
10653a5a1b3Sopenharmony_ci};
10753a5a1b3Sopenharmony_ci
10853a5a1b3Sopenharmony_cistatic pa_dbus_property_handler property_handlers[PROPERTY_HANDLER_MAX] = {
10953a5a1b3Sopenharmony_ci    [PROPERTY_HANDLER_INDEX]           = { .property_name = "Index",          .type = "u",      .get_cb = handle_get_index,           .set_cb = NULL },
11053a5a1b3Sopenharmony_ci    [PROPERTY_HANDLER_DRIVER]          = { .property_name = "Driver",         .type = "s",      .get_cb = handle_get_driver,          .set_cb = NULL },
11153a5a1b3Sopenharmony_ci    [PROPERTY_HANDLER_OWNER_MODULE]    = { .property_name = "OwnerModule",    .type = "o",      .get_cb = handle_get_owner_module,    .set_cb = NULL },
11253a5a1b3Sopenharmony_ci    [PROPERTY_HANDLER_CLIENT]          = { .property_name = "Client",         .type = "o",      .get_cb = handle_get_client,          .set_cb = NULL },
11353a5a1b3Sopenharmony_ci    [PROPERTY_HANDLER_DEVICE]          = { .property_name = "Device",         .type = "o",      .get_cb = handle_get_device,          .set_cb = NULL },
11453a5a1b3Sopenharmony_ci    [PROPERTY_HANDLER_SAMPLE_FORMAT]   = { .property_name = "SampleFormat",   .type = "u",      .get_cb = handle_get_sample_format,   .set_cb = NULL },
11553a5a1b3Sopenharmony_ci    [PROPERTY_HANDLER_SAMPLE_RATE]     = { .property_name = "SampleRate",     .type = "u",      .get_cb = handle_get_sample_rate,     .set_cb = NULL },
11653a5a1b3Sopenharmony_ci    [PROPERTY_HANDLER_CHANNELS]        = { .property_name = "Channels",       .type = "au",     .get_cb = handle_get_channels,        .set_cb = NULL },
11753a5a1b3Sopenharmony_ci    [PROPERTY_HANDLER_VOLUME]          = { .property_name = "Volume",         .type = "au",     .get_cb = handle_get_volume,          .set_cb = handle_set_volume },
11853a5a1b3Sopenharmony_ci    [PROPERTY_HANDLER_MUTE]            = { .property_name = "Mute",           .type = "b",      .get_cb = handle_get_mute,            .set_cb = handle_set_mute },
11953a5a1b3Sopenharmony_ci    [PROPERTY_HANDLER_BUFFER_LATENCY]  = { .property_name = "BufferLatency",  .type = "t",      .get_cb = handle_get_buffer_latency,  .set_cb = NULL },
12053a5a1b3Sopenharmony_ci    [PROPERTY_HANDLER_DEVICE_LATENCY]  = { .property_name = "DeviceLatency",  .type = "t",      .get_cb = handle_get_device_latency,  .set_cb = NULL },
12153a5a1b3Sopenharmony_ci    [PROPERTY_HANDLER_RESAMPLE_METHOD] = { .property_name = "ResampleMethod", .type = "s",      .get_cb = handle_get_resample_method, .set_cb = NULL },
12253a5a1b3Sopenharmony_ci    [PROPERTY_HANDLER_PROPERTY_LIST]   = { .property_name = "PropertyList",   .type = "a{say}", .get_cb = handle_get_property_list,   .set_cb = NULL }
12353a5a1b3Sopenharmony_ci};
12453a5a1b3Sopenharmony_ci
12553a5a1b3Sopenharmony_cienum method_handler_index {
12653a5a1b3Sopenharmony_ci    METHOD_HANDLER_MOVE,
12753a5a1b3Sopenharmony_ci    METHOD_HANDLER_KILL,
12853a5a1b3Sopenharmony_ci    METHOD_HANDLER_MAX
12953a5a1b3Sopenharmony_ci};
13053a5a1b3Sopenharmony_ci
13153a5a1b3Sopenharmony_cistatic pa_dbus_arg_info move_args[] = { { "device", "o", "in" } };
13253a5a1b3Sopenharmony_ci
13353a5a1b3Sopenharmony_cistatic pa_dbus_method_handler method_handlers[METHOD_HANDLER_MAX] = {
13453a5a1b3Sopenharmony_ci    [METHOD_HANDLER_MOVE] = {
13553a5a1b3Sopenharmony_ci        .method_name = "Move",
13653a5a1b3Sopenharmony_ci        .arguments = move_args,
13753a5a1b3Sopenharmony_ci        .n_arguments = sizeof(move_args) / sizeof(pa_dbus_arg_info),
13853a5a1b3Sopenharmony_ci        .receive_cb = handle_move },
13953a5a1b3Sopenharmony_ci    [METHOD_HANDLER_KILL] = {
14053a5a1b3Sopenharmony_ci        .method_name = "Kill",
14153a5a1b3Sopenharmony_ci        .arguments = NULL,
14253a5a1b3Sopenharmony_ci        .n_arguments = 0,
14353a5a1b3Sopenharmony_ci        .receive_cb = handle_kill }
14453a5a1b3Sopenharmony_ci};
14553a5a1b3Sopenharmony_ci
14653a5a1b3Sopenharmony_cienum signal_index {
14753a5a1b3Sopenharmony_ci    SIGNAL_DEVICE_UPDATED,
14853a5a1b3Sopenharmony_ci    SIGNAL_SAMPLE_RATE_UPDATED,
14953a5a1b3Sopenharmony_ci    SIGNAL_VOLUME_UPDATED,
15053a5a1b3Sopenharmony_ci    SIGNAL_MUTE_UPDATED,
15153a5a1b3Sopenharmony_ci    SIGNAL_PROPERTY_LIST_UPDATED,
15253a5a1b3Sopenharmony_ci    SIGNAL_STREAM_EVENT,
15353a5a1b3Sopenharmony_ci    SIGNAL_MAX
15453a5a1b3Sopenharmony_ci};
15553a5a1b3Sopenharmony_ci
15653a5a1b3Sopenharmony_cistatic pa_dbus_arg_info device_updated_args[]        = { { "device",        "o",      NULL } };
15753a5a1b3Sopenharmony_cistatic pa_dbus_arg_info sample_rate_updated_args[]   = { { "sample_rate",   "u",      NULL } };
15853a5a1b3Sopenharmony_cistatic pa_dbus_arg_info volume_updated_args[]        = { { "volume",        "au",     NULL } };
15953a5a1b3Sopenharmony_cistatic pa_dbus_arg_info mute_updated_args[]          = { { "muted",         "b",      NULL } };
16053a5a1b3Sopenharmony_cistatic pa_dbus_arg_info property_list_updated_args[] = { { "property_list", "a{say}", NULL } };
16153a5a1b3Sopenharmony_cistatic pa_dbus_arg_info stream_event_args[]          = { { "name",          "s",      NULL }, { "property_list", "a{say}", NULL } };
16253a5a1b3Sopenharmony_ci
16353a5a1b3Sopenharmony_cistatic pa_dbus_signal_info signals[SIGNAL_MAX] = {
16453a5a1b3Sopenharmony_ci    [SIGNAL_DEVICE_UPDATED]        = { .name = "DeviceUpdated",       .arguments = device_updated_args,        .n_arguments = 1 },
16553a5a1b3Sopenharmony_ci    [SIGNAL_SAMPLE_RATE_UPDATED]   = { .name = "SampleRateUpdated",   .arguments = sample_rate_updated_args,   .n_arguments = 1 },
16653a5a1b3Sopenharmony_ci    [SIGNAL_VOLUME_UPDATED]        = { .name = "VolumeUpdated",       .arguments = volume_updated_args,        .n_arguments = 1 },
16753a5a1b3Sopenharmony_ci    [SIGNAL_MUTE_UPDATED]          = { .name = "MuteUpdated",         .arguments = mute_updated_args,          .n_arguments = 1 },
16853a5a1b3Sopenharmony_ci    [SIGNAL_PROPERTY_LIST_UPDATED] = { .name = "PropertyListUpdated", .arguments = property_list_updated_args, .n_arguments = 1 },
16953a5a1b3Sopenharmony_ci    [SIGNAL_STREAM_EVENT]          = { .name = "StreamEvent",         .arguments = stream_event_args,          .n_arguments = sizeof(stream_event_args) / sizeof(pa_dbus_arg_info) }
17053a5a1b3Sopenharmony_ci};
17153a5a1b3Sopenharmony_ci
17253a5a1b3Sopenharmony_cistatic pa_dbus_interface_info stream_interface_info = {
17353a5a1b3Sopenharmony_ci    .name = PA_DBUSIFACE_STREAM_INTERFACE,
17453a5a1b3Sopenharmony_ci    .method_handlers = method_handlers,
17553a5a1b3Sopenharmony_ci    .n_method_handlers = METHOD_HANDLER_MAX,
17653a5a1b3Sopenharmony_ci    .property_handlers = property_handlers,
17753a5a1b3Sopenharmony_ci    .n_property_handlers = PROPERTY_HANDLER_MAX,
17853a5a1b3Sopenharmony_ci    .get_all_properties_cb = handle_get_all,
17953a5a1b3Sopenharmony_ci    .signals = signals,
18053a5a1b3Sopenharmony_ci    .n_signals = SIGNAL_MAX
18153a5a1b3Sopenharmony_ci};
18253a5a1b3Sopenharmony_ci
18353a5a1b3Sopenharmony_cistatic void handle_get_index(DBusConnection *conn, DBusMessage *msg, void *userdata) {
18453a5a1b3Sopenharmony_ci    pa_dbusiface_stream *s = userdata;
18553a5a1b3Sopenharmony_ci    dbus_uint32_t idx;
18653a5a1b3Sopenharmony_ci
18753a5a1b3Sopenharmony_ci    pa_assert(conn);
18853a5a1b3Sopenharmony_ci    pa_assert(msg);
18953a5a1b3Sopenharmony_ci    pa_assert(s);
19053a5a1b3Sopenharmony_ci
19153a5a1b3Sopenharmony_ci    idx = (s->type == STREAM_TYPE_PLAYBACK) ? s->sink_input->index : s->source_output->index;
19253a5a1b3Sopenharmony_ci
19353a5a1b3Sopenharmony_ci    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &idx);
19453a5a1b3Sopenharmony_ci}
19553a5a1b3Sopenharmony_ci
19653a5a1b3Sopenharmony_ci/* The returned string has to be freed with pa_xfree() by the caller. */
19753a5a1b3Sopenharmony_cistatic char *stream_to_string(pa_dbusiface_stream *s) {
19853a5a1b3Sopenharmony_ci    if (s->type == STREAM_TYPE_PLAYBACK)
19953a5a1b3Sopenharmony_ci        return pa_sprintf_malloc("Playback stream %u", (unsigned) s->sink_input->index);
20053a5a1b3Sopenharmony_ci    else
20153a5a1b3Sopenharmony_ci        return pa_sprintf_malloc("Record stream %u", (unsigned) s->source_output->index);
20253a5a1b3Sopenharmony_ci}
20353a5a1b3Sopenharmony_ci
20453a5a1b3Sopenharmony_cistatic void handle_get_driver(DBusConnection *conn, DBusMessage *msg, void *userdata) {
20553a5a1b3Sopenharmony_ci    pa_dbusiface_stream *s = userdata;
20653a5a1b3Sopenharmony_ci    const char *driver = NULL;
20753a5a1b3Sopenharmony_ci
20853a5a1b3Sopenharmony_ci    pa_assert(conn);
20953a5a1b3Sopenharmony_ci    pa_assert(msg);
21053a5a1b3Sopenharmony_ci    pa_assert(s);
21153a5a1b3Sopenharmony_ci
21253a5a1b3Sopenharmony_ci    driver = (s->type == STREAM_TYPE_PLAYBACK) ? s->sink_input->driver : s->source_output->driver;
21353a5a1b3Sopenharmony_ci
21453a5a1b3Sopenharmony_ci    if (!driver) {
21553a5a1b3Sopenharmony_ci        char *str = stream_to_string(s);
21653a5a1b3Sopenharmony_ci
21753a5a1b3Sopenharmony_ci        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "%s doesn't have a driver.", str);
21853a5a1b3Sopenharmony_ci        pa_xfree(str);
21953a5a1b3Sopenharmony_ci
22053a5a1b3Sopenharmony_ci        return;
22153a5a1b3Sopenharmony_ci    }
22253a5a1b3Sopenharmony_ci
22353a5a1b3Sopenharmony_ci    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_STRING, &driver);
22453a5a1b3Sopenharmony_ci}
22553a5a1b3Sopenharmony_ci
22653a5a1b3Sopenharmony_cistatic void handle_get_owner_module(DBusConnection *conn, DBusMessage *msg, void *userdata) {
22753a5a1b3Sopenharmony_ci    pa_dbusiface_stream *s = userdata;
22853a5a1b3Sopenharmony_ci    pa_module *owner_module = NULL;
22953a5a1b3Sopenharmony_ci    const char *object_path = NULL;
23053a5a1b3Sopenharmony_ci
23153a5a1b3Sopenharmony_ci    pa_assert(conn);
23253a5a1b3Sopenharmony_ci    pa_assert(msg);
23353a5a1b3Sopenharmony_ci    pa_assert(s);
23453a5a1b3Sopenharmony_ci
23553a5a1b3Sopenharmony_ci    owner_module = (s->type == STREAM_TYPE_PLAYBACK) ? s->sink_input->module : s->source_output->module;
23653a5a1b3Sopenharmony_ci
23753a5a1b3Sopenharmony_ci    if (!owner_module) {
23853a5a1b3Sopenharmony_ci        char *str = stream_to_string(s);
23953a5a1b3Sopenharmony_ci
24053a5a1b3Sopenharmony_ci        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "%s doesn't have an owner module.", str);
24153a5a1b3Sopenharmony_ci        pa_xfree(str);
24253a5a1b3Sopenharmony_ci
24353a5a1b3Sopenharmony_ci        return;
24453a5a1b3Sopenharmony_ci    }
24553a5a1b3Sopenharmony_ci
24653a5a1b3Sopenharmony_ci    object_path = pa_dbusiface_core_get_module_path(s->core, owner_module);
24753a5a1b3Sopenharmony_ci
24853a5a1b3Sopenharmony_ci    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &object_path);
24953a5a1b3Sopenharmony_ci}
25053a5a1b3Sopenharmony_ci
25153a5a1b3Sopenharmony_cistatic void handle_get_client(DBusConnection *conn, DBusMessage *msg, void *userdata) {
25253a5a1b3Sopenharmony_ci    pa_dbusiface_stream *s = userdata;
25353a5a1b3Sopenharmony_ci    pa_client *client = NULL;
25453a5a1b3Sopenharmony_ci    const char *object_path = NULL;
25553a5a1b3Sopenharmony_ci
25653a5a1b3Sopenharmony_ci    pa_assert(conn);
25753a5a1b3Sopenharmony_ci    pa_assert(msg);
25853a5a1b3Sopenharmony_ci    pa_assert(s);
25953a5a1b3Sopenharmony_ci
26053a5a1b3Sopenharmony_ci    client = (s->type == STREAM_TYPE_PLAYBACK) ? s->sink_input->client : s->source_output->client;
26153a5a1b3Sopenharmony_ci
26253a5a1b3Sopenharmony_ci    if (!client) {
26353a5a1b3Sopenharmony_ci        char *str = stream_to_string(s);
26453a5a1b3Sopenharmony_ci
26553a5a1b3Sopenharmony_ci        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "%s isn't associated to any client.", str);
26653a5a1b3Sopenharmony_ci        pa_xfree(str);
26753a5a1b3Sopenharmony_ci
26853a5a1b3Sopenharmony_ci        return;
26953a5a1b3Sopenharmony_ci    }
27053a5a1b3Sopenharmony_ci
27153a5a1b3Sopenharmony_ci    object_path = pa_dbusiface_core_get_client_path(s->core, client);
27253a5a1b3Sopenharmony_ci
27353a5a1b3Sopenharmony_ci    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &object_path);
27453a5a1b3Sopenharmony_ci}
27553a5a1b3Sopenharmony_ci
27653a5a1b3Sopenharmony_cistatic void handle_get_device(DBusConnection *conn, DBusMessage *msg, void *userdata) {
27753a5a1b3Sopenharmony_ci    pa_dbusiface_stream *s = userdata;
27853a5a1b3Sopenharmony_ci    const char *device = NULL;
27953a5a1b3Sopenharmony_ci
28053a5a1b3Sopenharmony_ci    pa_assert(conn);
28153a5a1b3Sopenharmony_ci    pa_assert(msg);
28253a5a1b3Sopenharmony_ci    pa_assert(s);
28353a5a1b3Sopenharmony_ci
28453a5a1b3Sopenharmony_ci    if (s->type == STREAM_TYPE_PLAYBACK)
28553a5a1b3Sopenharmony_ci        device = pa_dbusiface_core_get_sink_path(s->core, s->sink);
28653a5a1b3Sopenharmony_ci    else
28753a5a1b3Sopenharmony_ci        device = pa_dbusiface_core_get_source_path(s->core, s->source);
28853a5a1b3Sopenharmony_ci
28953a5a1b3Sopenharmony_ci    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &device);
29053a5a1b3Sopenharmony_ci}
29153a5a1b3Sopenharmony_ci
29253a5a1b3Sopenharmony_cistatic void handle_get_sample_format(DBusConnection *conn, DBusMessage *msg, void *userdata) {
29353a5a1b3Sopenharmony_ci    pa_dbusiface_stream *s = userdata;
29453a5a1b3Sopenharmony_ci    dbus_uint32_t sample_format = 0;
29553a5a1b3Sopenharmony_ci
29653a5a1b3Sopenharmony_ci    pa_assert(conn);
29753a5a1b3Sopenharmony_ci    pa_assert(msg);
29853a5a1b3Sopenharmony_ci    pa_assert(s);
29953a5a1b3Sopenharmony_ci
30053a5a1b3Sopenharmony_ci    sample_format = (s->type == STREAM_TYPE_PLAYBACK)
30153a5a1b3Sopenharmony_ci                    ? s->sink_input->sample_spec.format
30253a5a1b3Sopenharmony_ci                    : s->source_output->sample_spec.format;
30353a5a1b3Sopenharmony_ci
30453a5a1b3Sopenharmony_ci    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &sample_format);
30553a5a1b3Sopenharmony_ci}
30653a5a1b3Sopenharmony_ci
30753a5a1b3Sopenharmony_cistatic void handle_get_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata) {
30853a5a1b3Sopenharmony_ci    pa_dbusiface_stream *s = userdata;
30953a5a1b3Sopenharmony_ci
31053a5a1b3Sopenharmony_ci    pa_assert(conn);
31153a5a1b3Sopenharmony_ci    pa_assert(msg);
31253a5a1b3Sopenharmony_ci    pa_assert(s);
31353a5a1b3Sopenharmony_ci
31453a5a1b3Sopenharmony_ci    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &s->sample_rate);
31553a5a1b3Sopenharmony_ci}
31653a5a1b3Sopenharmony_ci
31753a5a1b3Sopenharmony_cistatic void handle_get_channels(DBusConnection *conn, DBusMessage *msg, void *userdata) {
31853a5a1b3Sopenharmony_ci    pa_dbusiface_stream *s = userdata;
31953a5a1b3Sopenharmony_ci    pa_channel_map *channel_map = NULL;
32053a5a1b3Sopenharmony_ci    dbus_uint32_t channels[PA_CHANNELS_MAX];
32153a5a1b3Sopenharmony_ci    unsigned i = 0;
32253a5a1b3Sopenharmony_ci
32353a5a1b3Sopenharmony_ci    pa_assert(conn);
32453a5a1b3Sopenharmony_ci    pa_assert(msg);
32553a5a1b3Sopenharmony_ci    pa_assert(s);
32653a5a1b3Sopenharmony_ci
32753a5a1b3Sopenharmony_ci    channel_map = (s->type == STREAM_TYPE_PLAYBACK) ? &s->sink_input->channel_map : &s->source_output->channel_map;
32853a5a1b3Sopenharmony_ci
32953a5a1b3Sopenharmony_ci    for (i = 0; i < channel_map->channels; ++i)
33053a5a1b3Sopenharmony_ci        channels[i] = channel_map->map[i];
33153a5a1b3Sopenharmony_ci
33253a5a1b3Sopenharmony_ci    pa_dbus_send_basic_array_variant_reply(conn, msg, DBUS_TYPE_UINT32, channels, channel_map->channels);
33353a5a1b3Sopenharmony_ci}
33453a5a1b3Sopenharmony_ci
33553a5a1b3Sopenharmony_cistatic void handle_get_volume(DBusConnection *conn, DBusMessage *msg, void *userdata) {
33653a5a1b3Sopenharmony_ci    pa_dbusiface_stream *s = userdata;
33753a5a1b3Sopenharmony_ci    dbus_uint32_t volume[PA_CHANNELS_MAX];
33853a5a1b3Sopenharmony_ci    unsigned i = 0;
33953a5a1b3Sopenharmony_ci
34053a5a1b3Sopenharmony_ci    pa_assert(conn);
34153a5a1b3Sopenharmony_ci    pa_assert(msg);
34253a5a1b3Sopenharmony_ci    pa_assert(s);
34353a5a1b3Sopenharmony_ci
34453a5a1b3Sopenharmony_ci    if (!s->has_volume) {
34553a5a1b3Sopenharmony_ci        char *str = stream_to_string(s);
34653a5a1b3Sopenharmony_ci
34753a5a1b3Sopenharmony_ci        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "%s doesn't have volume.", str);
34853a5a1b3Sopenharmony_ci        pa_xfree(str);
34953a5a1b3Sopenharmony_ci
35053a5a1b3Sopenharmony_ci        return;
35153a5a1b3Sopenharmony_ci    }
35253a5a1b3Sopenharmony_ci
35353a5a1b3Sopenharmony_ci    for (i = 0; i < s->volume.channels; ++i)
35453a5a1b3Sopenharmony_ci        volume[i] = s->volume.values[i];
35553a5a1b3Sopenharmony_ci
35653a5a1b3Sopenharmony_ci    pa_dbus_send_basic_array_variant_reply(conn, msg, DBUS_TYPE_UINT32, volume, s->volume.channels);
35753a5a1b3Sopenharmony_ci}
35853a5a1b3Sopenharmony_ci
35953a5a1b3Sopenharmony_cistatic void handle_set_volume(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata) {
36053a5a1b3Sopenharmony_ci    pa_dbusiface_stream *s = userdata;
36153a5a1b3Sopenharmony_ci    bool volume_writable = true;
36253a5a1b3Sopenharmony_ci    DBusMessageIter array_iter;
36353a5a1b3Sopenharmony_ci    int stream_channels = 0;
36453a5a1b3Sopenharmony_ci    dbus_uint32_t *volume = NULL;
36553a5a1b3Sopenharmony_ci    int n_volume_entries = 0;
36653a5a1b3Sopenharmony_ci    pa_cvolume new_vol;
36753a5a1b3Sopenharmony_ci    int i = 0;
36853a5a1b3Sopenharmony_ci
36953a5a1b3Sopenharmony_ci    pa_assert(conn);
37053a5a1b3Sopenharmony_ci    pa_assert(msg);
37153a5a1b3Sopenharmony_ci    pa_assert(iter);
37253a5a1b3Sopenharmony_ci    pa_assert(s);
37353a5a1b3Sopenharmony_ci
37453a5a1b3Sopenharmony_ci    volume_writable = (s->type == STREAM_TYPE_PLAYBACK) ? s->sink_input->volume_writable : false;
37553a5a1b3Sopenharmony_ci
37653a5a1b3Sopenharmony_ci    if (!s->has_volume || !volume_writable) {
37753a5a1b3Sopenharmony_ci        char *str = stream_to_string(s);
37853a5a1b3Sopenharmony_ci
37953a5a1b3Sopenharmony_ci        if (!s->has_volume)
38053a5a1b3Sopenharmony_ci            pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "%s doesn't have volume.", str);
38153a5a1b3Sopenharmony_ci        else if (!volume_writable)
38253a5a1b3Sopenharmony_ci            pa_dbus_send_error(conn, msg, DBUS_ERROR_ACCESS_DENIED, "%s has read-only volume.", str);
38353a5a1b3Sopenharmony_ci        pa_xfree(str);
38453a5a1b3Sopenharmony_ci
38553a5a1b3Sopenharmony_ci        return;
38653a5a1b3Sopenharmony_ci    }
38753a5a1b3Sopenharmony_ci
38853a5a1b3Sopenharmony_ci    stream_channels = s->sink_input->channel_map.channels;
38953a5a1b3Sopenharmony_ci
39053a5a1b3Sopenharmony_ci    dbus_message_iter_recurse(iter, &array_iter);
39153a5a1b3Sopenharmony_ci    dbus_message_iter_get_fixed_array(&array_iter, &volume, &n_volume_entries);
39253a5a1b3Sopenharmony_ci
39353a5a1b3Sopenharmony_ci    if (n_volume_entries != stream_channels && n_volume_entries != 1) {
39453a5a1b3Sopenharmony_ci        pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS,
39553a5a1b3Sopenharmony_ci                           "Expected %u volume entries, got %u.", stream_channels, n_volume_entries);
39653a5a1b3Sopenharmony_ci        return;
39753a5a1b3Sopenharmony_ci    }
39853a5a1b3Sopenharmony_ci
39953a5a1b3Sopenharmony_ci    pa_cvolume_init(&new_vol);
40053a5a1b3Sopenharmony_ci    new_vol.channels = n_volume_entries;
40153a5a1b3Sopenharmony_ci
40253a5a1b3Sopenharmony_ci    for (i = 0; i < n_volume_entries; ++i) {
40353a5a1b3Sopenharmony_ci        if (!PA_VOLUME_IS_VALID(volume[i])) {
40453a5a1b3Sopenharmony_ci            pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "Invalid volume: %u", volume[i]);
40553a5a1b3Sopenharmony_ci            return;
40653a5a1b3Sopenharmony_ci        }
40753a5a1b3Sopenharmony_ci        new_vol.values[i] = volume[i];
40853a5a1b3Sopenharmony_ci    }
40953a5a1b3Sopenharmony_ci
41053a5a1b3Sopenharmony_ci    pa_sink_input_set_volume(s->sink_input, &new_vol, true, true);
41153a5a1b3Sopenharmony_ci
41253a5a1b3Sopenharmony_ci    pa_dbus_send_empty_reply(conn, msg);
41353a5a1b3Sopenharmony_ci}
41453a5a1b3Sopenharmony_ci
41553a5a1b3Sopenharmony_cistatic void handle_get_mute(DBusConnection *conn, DBusMessage *msg, void *userdata) {
41653a5a1b3Sopenharmony_ci    pa_dbusiface_stream *s = userdata;
41753a5a1b3Sopenharmony_ci
41853a5a1b3Sopenharmony_ci    pa_assert(conn);
41953a5a1b3Sopenharmony_ci    pa_assert(msg);
42053a5a1b3Sopenharmony_ci    pa_assert(s);
42153a5a1b3Sopenharmony_ci
42253a5a1b3Sopenharmony_ci    if (s->type == STREAM_TYPE_RECORD) {
42353a5a1b3Sopenharmony_ci        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "Record streams don't have mute.");
42453a5a1b3Sopenharmony_ci        return;
42553a5a1b3Sopenharmony_ci    }
42653a5a1b3Sopenharmony_ci
42753a5a1b3Sopenharmony_ci    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_BOOLEAN, &s->mute);
42853a5a1b3Sopenharmony_ci}
42953a5a1b3Sopenharmony_ci
43053a5a1b3Sopenharmony_cistatic void handle_set_mute(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata) {
43153a5a1b3Sopenharmony_ci    pa_dbusiface_stream *s = userdata;
43253a5a1b3Sopenharmony_ci    dbus_bool_t mute = FALSE;
43353a5a1b3Sopenharmony_ci
43453a5a1b3Sopenharmony_ci    pa_assert(conn);
43553a5a1b3Sopenharmony_ci    pa_assert(msg);
43653a5a1b3Sopenharmony_ci    pa_assert(iter);
43753a5a1b3Sopenharmony_ci    pa_assert(s);
43853a5a1b3Sopenharmony_ci
43953a5a1b3Sopenharmony_ci    dbus_message_iter_get_basic(iter, &mute);
44053a5a1b3Sopenharmony_ci
44153a5a1b3Sopenharmony_ci    if (s->type == STREAM_TYPE_RECORD) {
44253a5a1b3Sopenharmony_ci        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "Record streams don't have mute.");
44353a5a1b3Sopenharmony_ci        return;
44453a5a1b3Sopenharmony_ci    }
44553a5a1b3Sopenharmony_ci
44653a5a1b3Sopenharmony_ci    pa_sink_input_set_mute(s->sink_input, mute, true);
44753a5a1b3Sopenharmony_ci
44853a5a1b3Sopenharmony_ci    pa_dbus_send_empty_reply(conn, msg);
44953a5a1b3Sopenharmony_ci}
45053a5a1b3Sopenharmony_ci
45153a5a1b3Sopenharmony_cistatic void handle_get_buffer_latency(DBusConnection *conn, DBusMessage *msg, void *userdata) {
45253a5a1b3Sopenharmony_ci    pa_dbusiface_stream *s = userdata;
45353a5a1b3Sopenharmony_ci    dbus_uint64_t buffer_latency = 0;
45453a5a1b3Sopenharmony_ci
45553a5a1b3Sopenharmony_ci    pa_assert(conn);
45653a5a1b3Sopenharmony_ci    pa_assert(msg);
45753a5a1b3Sopenharmony_ci    pa_assert(s);
45853a5a1b3Sopenharmony_ci
45953a5a1b3Sopenharmony_ci    if (s->type == STREAM_TYPE_PLAYBACK)
46053a5a1b3Sopenharmony_ci        buffer_latency = pa_sink_input_get_latency(s->sink_input, NULL);
46153a5a1b3Sopenharmony_ci    else
46253a5a1b3Sopenharmony_ci        buffer_latency = pa_source_output_get_latency(s->source_output, NULL);
46353a5a1b3Sopenharmony_ci
46453a5a1b3Sopenharmony_ci    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT64, &buffer_latency);
46553a5a1b3Sopenharmony_ci}
46653a5a1b3Sopenharmony_ci
46753a5a1b3Sopenharmony_cistatic void handle_get_device_latency(DBusConnection *conn, DBusMessage *msg, void *userdata) {
46853a5a1b3Sopenharmony_ci    pa_dbusiface_stream *s = userdata;
46953a5a1b3Sopenharmony_ci    dbus_uint64_t device_latency = 0;
47053a5a1b3Sopenharmony_ci
47153a5a1b3Sopenharmony_ci    pa_assert(conn);
47253a5a1b3Sopenharmony_ci    pa_assert(msg);
47353a5a1b3Sopenharmony_ci    pa_assert(s);
47453a5a1b3Sopenharmony_ci
47553a5a1b3Sopenharmony_ci    if (s->type == STREAM_TYPE_PLAYBACK)
47653a5a1b3Sopenharmony_ci        pa_sink_input_get_latency(s->sink_input, &device_latency);
47753a5a1b3Sopenharmony_ci    else
47853a5a1b3Sopenharmony_ci        pa_source_output_get_latency(s->source_output, &device_latency);
47953a5a1b3Sopenharmony_ci
48053a5a1b3Sopenharmony_ci    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT64, &device_latency);
48153a5a1b3Sopenharmony_ci}
48253a5a1b3Sopenharmony_ci
48353a5a1b3Sopenharmony_cistatic void handle_get_resample_method(DBusConnection *conn, DBusMessage *msg, void *userdata) {
48453a5a1b3Sopenharmony_ci    pa_dbusiface_stream *s = userdata;
48553a5a1b3Sopenharmony_ci    const char *resample_method = NULL;
48653a5a1b3Sopenharmony_ci
48753a5a1b3Sopenharmony_ci    pa_assert(conn);
48853a5a1b3Sopenharmony_ci    pa_assert(msg);
48953a5a1b3Sopenharmony_ci    pa_assert(s);
49053a5a1b3Sopenharmony_ci
49153a5a1b3Sopenharmony_ci    if (s->type == STREAM_TYPE_PLAYBACK)
49253a5a1b3Sopenharmony_ci        resample_method = pa_resample_method_to_string(s->sink_input->actual_resample_method);
49353a5a1b3Sopenharmony_ci    else
49453a5a1b3Sopenharmony_ci        resample_method = pa_resample_method_to_string(s->source_output->actual_resample_method);
49553a5a1b3Sopenharmony_ci
49653a5a1b3Sopenharmony_ci    if (!resample_method)
49753a5a1b3Sopenharmony_ci        resample_method = "";
49853a5a1b3Sopenharmony_ci
49953a5a1b3Sopenharmony_ci    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_STRING, &resample_method);
50053a5a1b3Sopenharmony_ci}
50153a5a1b3Sopenharmony_ci
50253a5a1b3Sopenharmony_cistatic void handle_get_property_list(DBusConnection *conn, DBusMessage *msg, void *userdata) {
50353a5a1b3Sopenharmony_ci    pa_dbusiface_stream *s = userdata;
50453a5a1b3Sopenharmony_ci
50553a5a1b3Sopenharmony_ci    pa_assert(conn);
50653a5a1b3Sopenharmony_ci    pa_assert(msg);
50753a5a1b3Sopenharmony_ci    pa_assert(s);
50853a5a1b3Sopenharmony_ci
50953a5a1b3Sopenharmony_ci    pa_dbus_send_proplist_variant_reply(conn, msg, s->proplist);
51053a5a1b3Sopenharmony_ci}
51153a5a1b3Sopenharmony_ci
51253a5a1b3Sopenharmony_cistatic void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata) {
51353a5a1b3Sopenharmony_ci    pa_dbusiface_stream *s = userdata;
51453a5a1b3Sopenharmony_ci    DBusMessage *reply = NULL;
51553a5a1b3Sopenharmony_ci    DBusMessageIter msg_iter;
51653a5a1b3Sopenharmony_ci    DBusMessageIter dict_iter;
51753a5a1b3Sopenharmony_ci    dbus_uint32_t idx = 0;
51853a5a1b3Sopenharmony_ci    const char *driver = NULL;
51953a5a1b3Sopenharmony_ci    pa_module *owner_module = NULL;
52053a5a1b3Sopenharmony_ci    const char *owner_module_path = NULL;
52153a5a1b3Sopenharmony_ci    pa_client *client = NULL;
52253a5a1b3Sopenharmony_ci    const char *client_path = NULL;
52353a5a1b3Sopenharmony_ci    const char *device = NULL;
52453a5a1b3Sopenharmony_ci    dbus_uint32_t sample_format = 0;
52553a5a1b3Sopenharmony_ci    pa_channel_map *channel_map = NULL;
52653a5a1b3Sopenharmony_ci    dbus_uint32_t channels[PA_CHANNELS_MAX];
52753a5a1b3Sopenharmony_ci    dbus_uint32_t volume[PA_CHANNELS_MAX];
52853a5a1b3Sopenharmony_ci    dbus_uint64_t buffer_latency = 0;
52953a5a1b3Sopenharmony_ci    dbus_uint64_t device_latency = 0;
53053a5a1b3Sopenharmony_ci    const char *resample_method = NULL;
53153a5a1b3Sopenharmony_ci    unsigned i = 0;
53253a5a1b3Sopenharmony_ci
53353a5a1b3Sopenharmony_ci    pa_assert(conn);
53453a5a1b3Sopenharmony_ci    pa_assert(msg);
53553a5a1b3Sopenharmony_ci    pa_assert(s);
53653a5a1b3Sopenharmony_ci
53753a5a1b3Sopenharmony_ci    if (s->has_volume) {
53853a5a1b3Sopenharmony_ci        for (i = 0; i < s->volume.channels; ++i)
53953a5a1b3Sopenharmony_ci            volume[i] = s->volume.values[i];
54053a5a1b3Sopenharmony_ci    }
54153a5a1b3Sopenharmony_ci
54253a5a1b3Sopenharmony_ci    if (s->type == STREAM_TYPE_PLAYBACK) {
54353a5a1b3Sopenharmony_ci        idx = s->sink_input->index;
54453a5a1b3Sopenharmony_ci        driver = s->sink_input->driver;
54553a5a1b3Sopenharmony_ci        owner_module = s->sink_input->module;
54653a5a1b3Sopenharmony_ci        client = s->sink_input->client;
54753a5a1b3Sopenharmony_ci        device = pa_dbusiface_core_get_sink_path(s->core, s->sink);
54853a5a1b3Sopenharmony_ci        sample_format = s->sink_input->sample_spec.format;
54953a5a1b3Sopenharmony_ci        channel_map = &s->sink_input->channel_map;
55053a5a1b3Sopenharmony_ci        buffer_latency = pa_sink_input_get_latency(s->sink_input, &device_latency);
55153a5a1b3Sopenharmony_ci        resample_method = pa_resample_method_to_string(s->sink_input->actual_resample_method);
55253a5a1b3Sopenharmony_ci    } else {
55353a5a1b3Sopenharmony_ci        idx = s->source_output->index;
55453a5a1b3Sopenharmony_ci        driver = s->source_output->driver;
55553a5a1b3Sopenharmony_ci        owner_module = s->source_output->module;
55653a5a1b3Sopenharmony_ci        client = s->source_output->client;
55753a5a1b3Sopenharmony_ci        device = pa_dbusiface_core_get_source_path(s->core, s->source);
55853a5a1b3Sopenharmony_ci        sample_format = s->source_output->sample_spec.format;
55953a5a1b3Sopenharmony_ci        channel_map = &s->source_output->channel_map;
56053a5a1b3Sopenharmony_ci        buffer_latency = pa_source_output_get_latency(s->source_output, &device_latency);
56153a5a1b3Sopenharmony_ci        resample_method = pa_resample_method_to_string(s->source_output->actual_resample_method);
56253a5a1b3Sopenharmony_ci    }
56353a5a1b3Sopenharmony_ci    if (owner_module)
56453a5a1b3Sopenharmony_ci        owner_module_path = pa_dbusiface_core_get_module_path(s->core, owner_module);
56553a5a1b3Sopenharmony_ci    if (client)
56653a5a1b3Sopenharmony_ci        client_path = pa_dbusiface_core_get_client_path(s->core, client);
56753a5a1b3Sopenharmony_ci    for (i = 0; i < channel_map->channels; ++i)
56853a5a1b3Sopenharmony_ci        channels[i] = channel_map->map[i];
56953a5a1b3Sopenharmony_ci    if (!resample_method)
57053a5a1b3Sopenharmony_ci        resample_method = "";
57153a5a1b3Sopenharmony_ci
57253a5a1b3Sopenharmony_ci    pa_assert_se((reply = dbus_message_new_method_return(msg)));
57353a5a1b3Sopenharmony_ci
57453a5a1b3Sopenharmony_ci    dbus_message_iter_init_append(reply, &msg_iter);
57553a5a1b3Sopenharmony_ci    pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "{sv}", &dict_iter));
57653a5a1b3Sopenharmony_ci
57753a5a1b3Sopenharmony_ci    pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_INDEX].property_name, DBUS_TYPE_UINT32, &idx);
57853a5a1b3Sopenharmony_ci
57953a5a1b3Sopenharmony_ci    if (driver)
58053a5a1b3Sopenharmony_ci        pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_DRIVER].property_name, DBUS_TYPE_STRING, &driver);
58153a5a1b3Sopenharmony_ci
58253a5a1b3Sopenharmony_ci    if (owner_module)
58353a5a1b3Sopenharmony_ci        pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_OWNER_MODULE].property_name, DBUS_TYPE_OBJECT_PATH, &owner_module_path);
58453a5a1b3Sopenharmony_ci
58553a5a1b3Sopenharmony_ci    if (client)
58653a5a1b3Sopenharmony_ci        pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_CLIENT].property_name, DBUS_TYPE_OBJECT_PATH, &client_path);
58753a5a1b3Sopenharmony_ci
58853a5a1b3Sopenharmony_ci    pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_DEVICE].property_name, DBUS_TYPE_OBJECT_PATH, &device);
58953a5a1b3Sopenharmony_ci    pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_SAMPLE_FORMAT].property_name, DBUS_TYPE_UINT32, &sample_format);
59053a5a1b3Sopenharmony_ci    pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_SAMPLE_RATE].property_name, DBUS_TYPE_UINT32, &s->sample_rate);
59153a5a1b3Sopenharmony_ci    pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_CHANNELS].property_name, DBUS_TYPE_UINT32, channels, channel_map->channels);
59253a5a1b3Sopenharmony_ci
59353a5a1b3Sopenharmony_ci    if (s->has_volume) {
59453a5a1b3Sopenharmony_ci        pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_VOLUME].property_name, DBUS_TYPE_UINT32, volume, s->volume.channels);
59553a5a1b3Sopenharmony_ci        pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_MUTE].property_name, DBUS_TYPE_BOOLEAN, &s->mute);
59653a5a1b3Sopenharmony_ci    }
59753a5a1b3Sopenharmony_ci
59853a5a1b3Sopenharmony_ci    pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_BUFFER_LATENCY].property_name, DBUS_TYPE_UINT64, &buffer_latency);
59953a5a1b3Sopenharmony_ci    pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_DEVICE_LATENCY].property_name, DBUS_TYPE_UINT64, &device_latency);
60053a5a1b3Sopenharmony_ci    pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_RESAMPLE_METHOD].property_name, DBUS_TYPE_STRING, &resample_method);
60153a5a1b3Sopenharmony_ci    pa_dbus_append_proplist_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_PROPERTY_LIST].property_name, s->proplist);
60253a5a1b3Sopenharmony_ci
60353a5a1b3Sopenharmony_ci    pa_assert_se(dbus_message_iter_close_container(&msg_iter, &dict_iter));
60453a5a1b3Sopenharmony_ci    pa_assert_se(dbus_connection_send(conn, reply, NULL));
60553a5a1b3Sopenharmony_ci    dbus_message_unref(reply);
60653a5a1b3Sopenharmony_ci}
60753a5a1b3Sopenharmony_ci
60853a5a1b3Sopenharmony_cistatic void handle_move(DBusConnection *conn, DBusMessage *msg, void *userdata) {
60953a5a1b3Sopenharmony_ci    pa_dbusiface_stream *s = userdata;
61053a5a1b3Sopenharmony_ci    const char *device = NULL;
61153a5a1b3Sopenharmony_ci
61253a5a1b3Sopenharmony_ci    pa_assert(conn);
61353a5a1b3Sopenharmony_ci    pa_assert(msg);
61453a5a1b3Sopenharmony_ci    pa_assert(s);
61553a5a1b3Sopenharmony_ci
61653a5a1b3Sopenharmony_ci    pa_assert_se(dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &device, DBUS_TYPE_INVALID));
61753a5a1b3Sopenharmony_ci
61853a5a1b3Sopenharmony_ci    if (s->type == STREAM_TYPE_PLAYBACK) {
61953a5a1b3Sopenharmony_ci        pa_sink *sink = pa_dbusiface_core_get_sink(s->core, device);
62053a5a1b3Sopenharmony_ci
62153a5a1b3Sopenharmony_ci        if (!sink) {
62253a5a1b3Sopenharmony_ci            pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NOT_FOUND, "%s: No such sink.", device);
62353a5a1b3Sopenharmony_ci            return;
62453a5a1b3Sopenharmony_ci        }
62553a5a1b3Sopenharmony_ci
62653a5a1b3Sopenharmony_ci        if (pa_sink_input_move_to(s->sink_input, sink, true) < 0) {
62753a5a1b3Sopenharmony_ci            pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED,
62853a5a1b3Sopenharmony_ci                               "Moving playback stream %u to sink %s failed.", s->sink_input->index, sink->name);
62953a5a1b3Sopenharmony_ci            return;
63053a5a1b3Sopenharmony_ci        }
63153a5a1b3Sopenharmony_ci    } else {
63253a5a1b3Sopenharmony_ci        pa_source *source = pa_dbusiface_core_get_source(s->core, device);
63353a5a1b3Sopenharmony_ci
63453a5a1b3Sopenharmony_ci        if (!source) {
63553a5a1b3Sopenharmony_ci            pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NOT_FOUND, "%s: No such source.", device);
63653a5a1b3Sopenharmony_ci            return;
63753a5a1b3Sopenharmony_ci        }
63853a5a1b3Sopenharmony_ci
63953a5a1b3Sopenharmony_ci        if (pa_source_output_move_to(s->source_output, source, true) < 0) {
64053a5a1b3Sopenharmony_ci            pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED,
64153a5a1b3Sopenharmony_ci                               "Moving record stream %u to source %s failed.", s->source_output->index, source->name);
64253a5a1b3Sopenharmony_ci            return;
64353a5a1b3Sopenharmony_ci        }
64453a5a1b3Sopenharmony_ci    }
64553a5a1b3Sopenharmony_ci
64653a5a1b3Sopenharmony_ci    pa_dbus_send_empty_reply(conn, msg);
64753a5a1b3Sopenharmony_ci}
64853a5a1b3Sopenharmony_ci
64953a5a1b3Sopenharmony_cistatic void handle_kill(DBusConnection *conn, DBusMessage *msg, void *userdata) {
65053a5a1b3Sopenharmony_ci    pa_dbusiface_stream *s = userdata;
65153a5a1b3Sopenharmony_ci
65253a5a1b3Sopenharmony_ci    pa_assert(conn);
65353a5a1b3Sopenharmony_ci    pa_assert(msg);
65453a5a1b3Sopenharmony_ci    pa_assert(s);
65553a5a1b3Sopenharmony_ci
65653a5a1b3Sopenharmony_ci    if (s->type == STREAM_TYPE_PLAYBACK)
65753a5a1b3Sopenharmony_ci        pa_sink_input_kill(s->sink_input);
65853a5a1b3Sopenharmony_ci    else
65953a5a1b3Sopenharmony_ci        pa_source_output_kill(s->source_output);
66053a5a1b3Sopenharmony_ci
66153a5a1b3Sopenharmony_ci    pa_dbus_send_empty_reply(conn, msg);
66253a5a1b3Sopenharmony_ci}
66353a5a1b3Sopenharmony_ci
66453a5a1b3Sopenharmony_cistatic void check_and_signal_rate(pa_dbusiface_stream *s) {
66553a5a1b3Sopenharmony_ci    DBusMessage *signal_msg = NULL;
66653a5a1b3Sopenharmony_ci    uint32_t new_sample_rate = 0;
66753a5a1b3Sopenharmony_ci
66853a5a1b3Sopenharmony_ci    pa_assert(s);
66953a5a1b3Sopenharmony_ci
67053a5a1b3Sopenharmony_ci    new_sample_rate = (s->type == STREAM_TYPE_PLAYBACK)
67153a5a1b3Sopenharmony_ci                      ? s->sink_input->sample_spec.rate
67253a5a1b3Sopenharmony_ci                      : s->source_output->sample_spec.rate;
67353a5a1b3Sopenharmony_ci
67453a5a1b3Sopenharmony_ci    if (s->sample_rate != new_sample_rate) {
67553a5a1b3Sopenharmony_ci        s->sample_rate = new_sample_rate;
67653a5a1b3Sopenharmony_ci
67753a5a1b3Sopenharmony_ci        pa_assert_se(signal_msg = dbus_message_new_signal(s->path,
67853a5a1b3Sopenharmony_ci                                                          PA_DBUSIFACE_STREAM_INTERFACE,
67953a5a1b3Sopenharmony_ci                                                          signals[SIGNAL_SAMPLE_RATE_UPDATED].name));
68053a5a1b3Sopenharmony_ci        pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_UINT32, &s->sample_rate, DBUS_TYPE_INVALID));
68153a5a1b3Sopenharmony_ci
68253a5a1b3Sopenharmony_ci        pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg);
68353a5a1b3Sopenharmony_ci        dbus_message_unref(signal_msg);
68453a5a1b3Sopenharmony_ci    }
68553a5a1b3Sopenharmony_ci}
68653a5a1b3Sopenharmony_ci
68753a5a1b3Sopenharmony_cistatic pa_hook_result_t move_finish_cb(void *hook_data, void *call_data, void *slot_data) {
68853a5a1b3Sopenharmony_ci    pa_dbusiface_stream *s = slot_data;
68953a5a1b3Sopenharmony_ci    const char *new_device_path = NULL;
69053a5a1b3Sopenharmony_ci    DBusMessage *signal_msg = NULL;
69153a5a1b3Sopenharmony_ci
69253a5a1b3Sopenharmony_ci    if ((s->type == STREAM_TYPE_PLAYBACK && s->sink_input != call_data) ||
69353a5a1b3Sopenharmony_ci        (s->type == STREAM_TYPE_RECORD && s->source_output != call_data))
69453a5a1b3Sopenharmony_ci        return PA_HOOK_OK;
69553a5a1b3Sopenharmony_ci
69653a5a1b3Sopenharmony_ci    if (s->type == STREAM_TYPE_PLAYBACK) {
69753a5a1b3Sopenharmony_ci        pa_sink *new_sink = s->sink_input->sink;
69853a5a1b3Sopenharmony_ci
69953a5a1b3Sopenharmony_ci        if (s->sink != new_sink) {
70053a5a1b3Sopenharmony_ci            pa_sink_unref(s->sink);
70153a5a1b3Sopenharmony_ci            s->sink = pa_sink_ref(new_sink);
70253a5a1b3Sopenharmony_ci
70353a5a1b3Sopenharmony_ci            new_device_path = pa_dbusiface_core_get_sink_path(s->core, new_sink);
70453a5a1b3Sopenharmony_ci
70553a5a1b3Sopenharmony_ci            pa_assert_se(signal_msg = dbus_message_new_signal(s->path,
70653a5a1b3Sopenharmony_ci                                                              PA_DBUSIFACE_STREAM_INTERFACE,
70753a5a1b3Sopenharmony_ci                                                              signals[SIGNAL_DEVICE_UPDATED].name));
70853a5a1b3Sopenharmony_ci            pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &new_device_path, DBUS_TYPE_INVALID));
70953a5a1b3Sopenharmony_ci
71053a5a1b3Sopenharmony_ci            pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg);
71153a5a1b3Sopenharmony_ci            dbus_message_unref(signal_msg);
71253a5a1b3Sopenharmony_ci        }
71353a5a1b3Sopenharmony_ci    } else {
71453a5a1b3Sopenharmony_ci        pa_source *new_source = s->source_output->source;
71553a5a1b3Sopenharmony_ci
71653a5a1b3Sopenharmony_ci        if (s->source != new_source) {
71753a5a1b3Sopenharmony_ci            pa_source_unref(s->source);
71853a5a1b3Sopenharmony_ci            s->source = pa_source_ref(new_source);
71953a5a1b3Sopenharmony_ci
72053a5a1b3Sopenharmony_ci            new_device_path = pa_dbusiface_core_get_source_path(s->core, new_source);
72153a5a1b3Sopenharmony_ci
72253a5a1b3Sopenharmony_ci            pa_assert_se(signal_msg = dbus_message_new_signal(s->path,
72353a5a1b3Sopenharmony_ci                                                              PA_DBUSIFACE_STREAM_INTERFACE,
72453a5a1b3Sopenharmony_ci                                                              signals[SIGNAL_DEVICE_UPDATED].name));
72553a5a1b3Sopenharmony_ci            pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &new_device_path, DBUS_TYPE_INVALID));
72653a5a1b3Sopenharmony_ci
72753a5a1b3Sopenharmony_ci            pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg);
72853a5a1b3Sopenharmony_ci            dbus_message_unref(signal_msg);
72953a5a1b3Sopenharmony_ci        }
73053a5a1b3Sopenharmony_ci    }
73153a5a1b3Sopenharmony_ci
73253a5a1b3Sopenharmony_ci    check_and_signal_rate(s);
73353a5a1b3Sopenharmony_ci
73453a5a1b3Sopenharmony_ci    return PA_HOOK_OK;
73553a5a1b3Sopenharmony_ci}
73653a5a1b3Sopenharmony_ci
73753a5a1b3Sopenharmony_cistatic pa_hook_result_t volume_changed_cb(void *hook_data, void *call_data, void *slot_data) {
73853a5a1b3Sopenharmony_ci    pa_dbusiface_stream *s = slot_data;
73953a5a1b3Sopenharmony_ci    DBusMessage *signal_msg = NULL;
74053a5a1b3Sopenharmony_ci    unsigned i = 0;
74153a5a1b3Sopenharmony_ci
74253a5a1b3Sopenharmony_ci    if ((s->type == STREAM_TYPE_PLAYBACK && s->sink_input != call_data) ||
74353a5a1b3Sopenharmony_ci        (s->type == STREAM_TYPE_RECORD && s->source_output != call_data))
74453a5a1b3Sopenharmony_ci        return PA_HOOK_OK;
74553a5a1b3Sopenharmony_ci
74653a5a1b3Sopenharmony_ci    if (s->type == STREAM_TYPE_PLAYBACK && s->has_volume) {
74753a5a1b3Sopenharmony_ci        pa_cvolume new_volume;
74853a5a1b3Sopenharmony_ci
74953a5a1b3Sopenharmony_ci        pa_sink_input_get_volume(s->sink_input, &new_volume, true);
75053a5a1b3Sopenharmony_ci
75153a5a1b3Sopenharmony_ci        if (!pa_cvolume_equal(&s->volume, &new_volume)) {
75253a5a1b3Sopenharmony_ci            dbus_uint32_t volume[PA_CHANNELS_MAX];
75353a5a1b3Sopenharmony_ci            dbus_uint32_t *volume_ptr = volume;
75453a5a1b3Sopenharmony_ci
75553a5a1b3Sopenharmony_ci            s->volume = new_volume;
75653a5a1b3Sopenharmony_ci
75753a5a1b3Sopenharmony_ci            for (i = 0; i < s->volume.channels; ++i)
75853a5a1b3Sopenharmony_ci                volume[i] = s->volume.values[i];
75953a5a1b3Sopenharmony_ci
76053a5a1b3Sopenharmony_ci            pa_assert_se(signal_msg = dbus_message_new_signal(s->path,
76153a5a1b3Sopenharmony_ci                                                              PA_DBUSIFACE_STREAM_INTERFACE,
76253a5a1b3Sopenharmony_ci                                                              signals[SIGNAL_VOLUME_UPDATED].name));
76353a5a1b3Sopenharmony_ci            pa_assert_se(dbus_message_append_args(signal_msg,
76453a5a1b3Sopenharmony_ci                                                  DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &volume_ptr, s->volume.channels,
76553a5a1b3Sopenharmony_ci                                                  DBUS_TYPE_INVALID));
76653a5a1b3Sopenharmony_ci
76753a5a1b3Sopenharmony_ci            pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg);
76853a5a1b3Sopenharmony_ci            dbus_message_unref(signal_msg);
76953a5a1b3Sopenharmony_ci        }
77053a5a1b3Sopenharmony_ci    }
77153a5a1b3Sopenharmony_ci
77253a5a1b3Sopenharmony_ci    return PA_HOOK_OK;
77353a5a1b3Sopenharmony_ci}
77453a5a1b3Sopenharmony_ci
77553a5a1b3Sopenharmony_cistatic pa_hook_result_t mute_changed_cb(void *hook_data, void *call_data, void *slot_data) {
77653a5a1b3Sopenharmony_ci    pa_dbusiface_stream *s = slot_data;
77753a5a1b3Sopenharmony_ci    DBusMessage *signal_msg = NULL;
77853a5a1b3Sopenharmony_ci
77953a5a1b3Sopenharmony_ci    if ((s->type == STREAM_TYPE_PLAYBACK && s->sink_input != call_data) ||
78053a5a1b3Sopenharmony_ci        (s->type == STREAM_TYPE_RECORD && s->source_output != call_data))
78153a5a1b3Sopenharmony_ci        return PA_HOOK_OK;
78253a5a1b3Sopenharmony_ci
78353a5a1b3Sopenharmony_ci    if (s->type == STREAM_TYPE_PLAYBACK) {
78453a5a1b3Sopenharmony_ci        bool new_mute = false;
78553a5a1b3Sopenharmony_ci
78653a5a1b3Sopenharmony_ci        new_mute = s->sink_input->muted;
78753a5a1b3Sopenharmony_ci
78853a5a1b3Sopenharmony_ci        if (s->mute != new_mute) {
78953a5a1b3Sopenharmony_ci            s->mute = new_mute;
79053a5a1b3Sopenharmony_ci
79153a5a1b3Sopenharmony_ci            pa_assert_se(signal_msg = dbus_message_new_signal(s->path,
79253a5a1b3Sopenharmony_ci                                                              PA_DBUSIFACE_STREAM_INTERFACE,
79353a5a1b3Sopenharmony_ci                                                              signals[SIGNAL_MUTE_UPDATED].name));
79453a5a1b3Sopenharmony_ci            pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_BOOLEAN, &s->mute, DBUS_TYPE_INVALID));
79553a5a1b3Sopenharmony_ci
79653a5a1b3Sopenharmony_ci            pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg);
79753a5a1b3Sopenharmony_ci            dbus_message_unref(signal_msg);
79853a5a1b3Sopenharmony_ci            signal_msg = NULL;
79953a5a1b3Sopenharmony_ci        }
80053a5a1b3Sopenharmony_ci    }
80153a5a1b3Sopenharmony_ci
80253a5a1b3Sopenharmony_ci    return PA_HOOK_OK;
80353a5a1b3Sopenharmony_ci}
80453a5a1b3Sopenharmony_ci
80553a5a1b3Sopenharmony_cistatic pa_hook_result_t proplist_changed_cb(void *hook_data, void *call_data, void *slot_data) {
80653a5a1b3Sopenharmony_ci    pa_dbusiface_stream *s = slot_data;
80753a5a1b3Sopenharmony_ci    DBusMessage *signal_msg = NULL;
80853a5a1b3Sopenharmony_ci    pa_proplist *new_proplist = NULL;
80953a5a1b3Sopenharmony_ci
81053a5a1b3Sopenharmony_ci    if ((s->type == STREAM_TYPE_PLAYBACK && s->sink_input != call_data) ||
81153a5a1b3Sopenharmony_ci        (s->type == STREAM_TYPE_RECORD && s->source_output != call_data))
81253a5a1b3Sopenharmony_ci        return PA_HOOK_OK;
81353a5a1b3Sopenharmony_ci
81453a5a1b3Sopenharmony_ci    new_proplist = (s->type == STREAM_TYPE_PLAYBACK) ? s->sink_input->proplist : s->source_output->proplist;
81553a5a1b3Sopenharmony_ci
81653a5a1b3Sopenharmony_ci    if (!pa_proplist_equal(s->proplist, new_proplist)) {
81753a5a1b3Sopenharmony_ci        DBusMessageIter msg_iter;
81853a5a1b3Sopenharmony_ci
81953a5a1b3Sopenharmony_ci        pa_proplist_update(s->proplist, PA_UPDATE_SET, new_proplist);
82053a5a1b3Sopenharmony_ci
82153a5a1b3Sopenharmony_ci        pa_assert_se(signal_msg = dbus_message_new_signal(s->path,
82253a5a1b3Sopenharmony_ci                                                          PA_DBUSIFACE_STREAM_INTERFACE,
82353a5a1b3Sopenharmony_ci                                                          signals[SIGNAL_PROPERTY_LIST_UPDATED].name));
82453a5a1b3Sopenharmony_ci        dbus_message_iter_init_append(signal_msg, &msg_iter);
82553a5a1b3Sopenharmony_ci        pa_dbus_append_proplist(&msg_iter, s->proplist);
82653a5a1b3Sopenharmony_ci
82753a5a1b3Sopenharmony_ci        pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg);
82853a5a1b3Sopenharmony_ci        dbus_message_unref(signal_msg);
82953a5a1b3Sopenharmony_ci    }
83053a5a1b3Sopenharmony_ci
83153a5a1b3Sopenharmony_ci    return PA_HOOK_OK;
83253a5a1b3Sopenharmony_ci}
83353a5a1b3Sopenharmony_ci
83453a5a1b3Sopenharmony_cistatic pa_hook_result_t state_changed_cb(void *hook_data, void *call_data, void *slot_data) {
83553a5a1b3Sopenharmony_ci    pa_dbusiface_stream *s = slot_data;
83653a5a1b3Sopenharmony_ci
83753a5a1b3Sopenharmony_ci    pa_assert(s);
83853a5a1b3Sopenharmony_ci
83953a5a1b3Sopenharmony_ci    if ((s->type == STREAM_TYPE_PLAYBACK && s->sink_input != call_data) ||
84053a5a1b3Sopenharmony_ci        (s->type == STREAM_TYPE_RECORD && s->source_output != call_data))
84153a5a1b3Sopenharmony_ci        return PA_HOOK_OK;
84253a5a1b3Sopenharmony_ci
84353a5a1b3Sopenharmony_ci    check_and_signal_rate(s);
84453a5a1b3Sopenharmony_ci
84553a5a1b3Sopenharmony_ci    return PA_HOOK_OK;
84653a5a1b3Sopenharmony_ci}
84753a5a1b3Sopenharmony_ci
84853a5a1b3Sopenharmony_cistatic pa_hook_result_t send_event_cb(void *hook_data, void *call_data, void *slot_data) {
84953a5a1b3Sopenharmony_ci    pa_dbusiface_stream *s = slot_data;
85053a5a1b3Sopenharmony_ci    DBusMessage *signal_msg = NULL;
85153a5a1b3Sopenharmony_ci    DBusMessageIter msg_iter;
85253a5a1b3Sopenharmony_ci    const char *name = NULL;
85353a5a1b3Sopenharmony_ci    pa_proplist *property_list = NULL;
85453a5a1b3Sopenharmony_ci
85553a5a1b3Sopenharmony_ci    pa_assert(call_data);
85653a5a1b3Sopenharmony_ci    pa_assert(s);
85753a5a1b3Sopenharmony_ci
85853a5a1b3Sopenharmony_ci    if (s->type == STREAM_TYPE_PLAYBACK) {
85953a5a1b3Sopenharmony_ci        pa_sink_input_send_event_hook_data *data = call_data;
86053a5a1b3Sopenharmony_ci
86153a5a1b3Sopenharmony_ci        if (data->sink_input != s->sink_input)
86253a5a1b3Sopenharmony_ci            return PA_HOOK_OK;
86353a5a1b3Sopenharmony_ci
86453a5a1b3Sopenharmony_ci        name = data->event;
86553a5a1b3Sopenharmony_ci        property_list = data->data;
86653a5a1b3Sopenharmony_ci    } else {
86753a5a1b3Sopenharmony_ci        pa_source_output_send_event_hook_data *data = call_data;
86853a5a1b3Sopenharmony_ci
86953a5a1b3Sopenharmony_ci        if (data->source_output != s->source_output)
87053a5a1b3Sopenharmony_ci            return PA_HOOK_OK;
87153a5a1b3Sopenharmony_ci
87253a5a1b3Sopenharmony_ci        name = data->event;
87353a5a1b3Sopenharmony_ci        property_list = data->data;
87453a5a1b3Sopenharmony_ci    }
87553a5a1b3Sopenharmony_ci
87653a5a1b3Sopenharmony_ci    pa_assert_se(signal_msg = dbus_message_new_signal(s->path,
87753a5a1b3Sopenharmony_ci                                                      PA_DBUSIFACE_STREAM_INTERFACE,
87853a5a1b3Sopenharmony_ci                                                      signals[SIGNAL_STREAM_EVENT].name));
87953a5a1b3Sopenharmony_ci    dbus_message_iter_init_append(signal_msg, &msg_iter);
88053a5a1b3Sopenharmony_ci    pa_assert_se(dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &name));
88153a5a1b3Sopenharmony_ci    pa_dbus_append_proplist(&msg_iter, property_list);
88253a5a1b3Sopenharmony_ci
88353a5a1b3Sopenharmony_ci    pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg);
88453a5a1b3Sopenharmony_ci    dbus_message_unref(signal_msg);
88553a5a1b3Sopenharmony_ci
88653a5a1b3Sopenharmony_ci    return PA_HOOK_OK;
88753a5a1b3Sopenharmony_ci}
88853a5a1b3Sopenharmony_ci
88953a5a1b3Sopenharmony_cipa_dbusiface_stream *pa_dbusiface_stream_new_playback(pa_dbusiface_core *core, pa_sink_input *sink_input) {
89053a5a1b3Sopenharmony_ci    pa_dbusiface_stream *s;
89153a5a1b3Sopenharmony_ci
89253a5a1b3Sopenharmony_ci    pa_assert(core);
89353a5a1b3Sopenharmony_ci    pa_assert(sink_input);
89453a5a1b3Sopenharmony_ci
89553a5a1b3Sopenharmony_ci    s = pa_xnew(pa_dbusiface_stream, 1);
89653a5a1b3Sopenharmony_ci    s->core = core;
89753a5a1b3Sopenharmony_ci    s->sink_input = pa_sink_input_ref(sink_input);
89853a5a1b3Sopenharmony_ci    s->type = STREAM_TYPE_PLAYBACK;
89953a5a1b3Sopenharmony_ci    s->path = pa_sprintf_malloc("%s/%s%u", PA_DBUS_CORE_OBJECT_PATH, PLAYBACK_OBJECT_NAME, sink_input->index);
90053a5a1b3Sopenharmony_ci    s->sink = pa_sink_ref(sink_input->sink);
90153a5a1b3Sopenharmony_ci    s->sample_rate = sink_input->sample_spec.rate;
90253a5a1b3Sopenharmony_ci    s->has_volume = pa_sink_input_is_volume_readable(sink_input);
90353a5a1b3Sopenharmony_ci
90453a5a1b3Sopenharmony_ci    if (s->has_volume)
90553a5a1b3Sopenharmony_ci        pa_sink_input_get_volume(sink_input, &s->volume, true);
90653a5a1b3Sopenharmony_ci    else
90753a5a1b3Sopenharmony_ci        pa_cvolume_init(&s->volume);
90853a5a1b3Sopenharmony_ci
90953a5a1b3Sopenharmony_ci    s->mute = sink_input->muted;
91053a5a1b3Sopenharmony_ci    s->proplist = pa_proplist_copy(sink_input->proplist);
91153a5a1b3Sopenharmony_ci    s->dbus_protocol = pa_dbus_protocol_get(sink_input->core);
91253a5a1b3Sopenharmony_ci    s->send_event_slot = pa_hook_connect(&sink_input->core->hooks[PA_CORE_HOOK_SINK_INPUT_SEND_EVENT],
91353a5a1b3Sopenharmony_ci                                         PA_HOOK_NORMAL,
91453a5a1b3Sopenharmony_ci                                         send_event_cb,
91553a5a1b3Sopenharmony_ci                                         s);
91653a5a1b3Sopenharmony_ci    s->move_finish_slot = pa_hook_connect(&sink_input->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE_FINISH],
91753a5a1b3Sopenharmony_ci                                          PA_HOOK_NORMAL, move_finish_cb, s);
91853a5a1b3Sopenharmony_ci    s->volume_changed_slot = pa_hook_connect(&sink_input->core->hooks[PA_CORE_HOOK_SINK_INPUT_VOLUME_CHANGED],
91953a5a1b3Sopenharmony_ci                                             PA_HOOK_NORMAL, volume_changed_cb, s);
92053a5a1b3Sopenharmony_ci    s->mute_changed_slot = pa_hook_connect(&sink_input->core->hooks[PA_CORE_HOOK_SINK_INPUT_MUTE_CHANGED],
92153a5a1b3Sopenharmony_ci                                           PA_HOOK_NORMAL, mute_changed_cb, s);
92253a5a1b3Sopenharmony_ci    s->proplist_changed_slot = pa_hook_connect(&sink_input->core->hooks[PA_CORE_HOOK_SINK_INPUT_PROPLIST_CHANGED],
92353a5a1b3Sopenharmony_ci                                               PA_HOOK_NORMAL, proplist_changed_cb, s);
92453a5a1b3Sopenharmony_ci    s->state_changed_slot = pa_hook_connect(&sink_input->core->hooks[PA_CORE_HOOK_SINK_INPUT_STATE_CHANGED],
92553a5a1b3Sopenharmony_ci                                            PA_HOOK_NORMAL, state_changed_cb, s);
92653a5a1b3Sopenharmony_ci
92753a5a1b3Sopenharmony_ci    pa_assert_se(pa_dbus_protocol_add_interface(s->dbus_protocol, s->path, &stream_interface_info, s) >= 0);
92853a5a1b3Sopenharmony_ci
92953a5a1b3Sopenharmony_ci    return s;
93053a5a1b3Sopenharmony_ci}
93153a5a1b3Sopenharmony_ci
93253a5a1b3Sopenharmony_cipa_dbusiface_stream *pa_dbusiface_stream_new_record(pa_dbusiface_core *core, pa_source_output *source_output) {
93353a5a1b3Sopenharmony_ci    pa_dbusiface_stream *s;
93453a5a1b3Sopenharmony_ci
93553a5a1b3Sopenharmony_ci    pa_assert(core);
93653a5a1b3Sopenharmony_ci    pa_assert(source_output);
93753a5a1b3Sopenharmony_ci
93853a5a1b3Sopenharmony_ci    s = pa_xnew(pa_dbusiface_stream, 1);
93953a5a1b3Sopenharmony_ci    s->core = core;
94053a5a1b3Sopenharmony_ci    s->source_output = pa_source_output_ref(source_output);
94153a5a1b3Sopenharmony_ci    s->type = STREAM_TYPE_RECORD;
94253a5a1b3Sopenharmony_ci    s->path = pa_sprintf_malloc("%s/%s%u", PA_DBUS_CORE_OBJECT_PATH, RECORD_OBJECT_NAME, source_output->index);
94353a5a1b3Sopenharmony_ci    s->source = pa_source_ref(source_output->source);
94453a5a1b3Sopenharmony_ci    s->sample_rate = source_output->sample_spec.rate;
94553a5a1b3Sopenharmony_ci    pa_cvolume_init(&s->volume);
94653a5a1b3Sopenharmony_ci    s->mute = false;
94753a5a1b3Sopenharmony_ci    s->proplist = pa_proplist_copy(source_output->proplist);
94853a5a1b3Sopenharmony_ci    s->has_volume = false;
94953a5a1b3Sopenharmony_ci    s->dbus_protocol = pa_dbus_protocol_get(source_output->core);
95053a5a1b3Sopenharmony_ci    s->send_event_slot = pa_hook_connect(&source_output->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_SEND_EVENT],
95153a5a1b3Sopenharmony_ci                                         PA_HOOK_NORMAL,
95253a5a1b3Sopenharmony_ci                                         send_event_cb,
95353a5a1b3Sopenharmony_ci                                         s);
95453a5a1b3Sopenharmony_ci    s->move_finish_slot = pa_hook_connect(&source_output->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_FINISH],
95553a5a1b3Sopenharmony_ci                                          PA_HOOK_NORMAL, move_finish_cb, s);
95653a5a1b3Sopenharmony_ci    s->volume_changed_slot = pa_hook_connect(&source_output->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_VOLUME_CHANGED],
95753a5a1b3Sopenharmony_ci                                             PA_HOOK_NORMAL, volume_changed_cb, s);
95853a5a1b3Sopenharmony_ci    s->mute_changed_slot = pa_hook_connect(&source_output->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MUTE_CHANGED],
95953a5a1b3Sopenharmony_ci                                           PA_HOOK_NORMAL, mute_changed_cb, s);
96053a5a1b3Sopenharmony_ci    s->proplist_changed_slot = pa_hook_connect(&source_output->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PROPLIST_CHANGED],
96153a5a1b3Sopenharmony_ci                                               PA_HOOK_NORMAL, proplist_changed_cb, s);
96253a5a1b3Sopenharmony_ci    s->state_changed_slot = pa_hook_connect(&source_output->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_STATE_CHANGED],
96353a5a1b3Sopenharmony_ci                                            PA_HOOK_NORMAL, state_changed_cb, s);
96453a5a1b3Sopenharmony_ci
96553a5a1b3Sopenharmony_ci    pa_assert_se(pa_dbus_protocol_add_interface(s->dbus_protocol, s->path, &stream_interface_info, s) >= 0);
96653a5a1b3Sopenharmony_ci
96753a5a1b3Sopenharmony_ci    return s;
96853a5a1b3Sopenharmony_ci}
96953a5a1b3Sopenharmony_ci
97053a5a1b3Sopenharmony_civoid pa_dbusiface_stream_free(pa_dbusiface_stream *s) {
97153a5a1b3Sopenharmony_ci    pa_assert(s);
97253a5a1b3Sopenharmony_ci
97353a5a1b3Sopenharmony_ci    pa_assert_se(pa_dbus_protocol_remove_interface(s->dbus_protocol, s->path, stream_interface_info.name) >= 0);
97453a5a1b3Sopenharmony_ci
97553a5a1b3Sopenharmony_ci    if (s->type == STREAM_TYPE_PLAYBACK) {
97653a5a1b3Sopenharmony_ci        pa_sink_input_unref(s->sink_input);
97753a5a1b3Sopenharmony_ci        pa_sink_unref(s->sink);
97853a5a1b3Sopenharmony_ci    } else {
97953a5a1b3Sopenharmony_ci        pa_source_output_unref(s->source_output);
98053a5a1b3Sopenharmony_ci        pa_source_unref(s->source);
98153a5a1b3Sopenharmony_ci    }
98253a5a1b3Sopenharmony_ci
98353a5a1b3Sopenharmony_ci    pa_proplist_free(s->proplist);
98453a5a1b3Sopenharmony_ci    pa_dbus_protocol_unref(s->dbus_protocol);
98553a5a1b3Sopenharmony_ci    pa_hook_slot_free(s->send_event_slot);
98653a5a1b3Sopenharmony_ci    pa_hook_slot_free(s->move_finish_slot);
98753a5a1b3Sopenharmony_ci    pa_hook_slot_free(s->volume_changed_slot);
98853a5a1b3Sopenharmony_ci    pa_hook_slot_free(s->mute_changed_slot);
98953a5a1b3Sopenharmony_ci    pa_hook_slot_free(s->proplist_changed_slot);
99053a5a1b3Sopenharmony_ci    pa_hook_slot_free(s->state_changed_slot);
99153a5a1b3Sopenharmony_ci
99253a5a1b3Sopenharmony_ci    pa_xfree(s->path);
99353a5a1b3Sopenharmony_ci    pa_xfree(s);
99453a5a1b3Sopenharmony_ci}
99553a5a1b3Sopenharmony_ci
99653a5a1b3Sopenharmony_ciconst char *pa_dbusiface_stream_get_path(pa_dbusiface_stream *s) {
99753a5a1b3Sopenharmony_ci    pa_assert(s);
99853a5a1b3Sopenharmony_ci
99953a5a1b3Sopenharmony_ci    return s->path;
100053a5a1b3Sopenharmony_ci}
1001