153a5a1b3Sopenharmony_ci/***
253a5a1b3Sopenharmony_ci  This file is part of PulseAudio.
353a5a1b3Sopenharmony_ci
453a5a1b3Sopenharmony_ci  Copyright 2009 Tanu Kaskinen
553a5a1b3Sopenharmony_ci
653a5a1b3Sopenharmony_ci  PulseAudio is free software; you can redistribute it and/or modify
753a5a1b3Sopenharmony_ci  it under the terms of the GNU Lesser General Public License as published
853a5a1b3Sopenharmony_ci  by the Free Software Foundation; either version 2.1 of the License,
953a5a1b3Sopenharmony_ci  or (at your option) any later version.
1053a5a1b3Sopenharmony_ci
1153a5a1b3Sopenharmony_ci  PulseAudio is distributed in the hope that it will be useful, but
1253a5a1b3Sopenharmony_ci  WITHOUT ANY WARRANTY; without even the implied warranty of
1353a5a1b3Sopenharmony_ci  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1453a5a1b3Sopenharmony_ci  General Public License for more details.
1553a5a1b3Sopenharmony_ci
1653a5a1b3Sopenharmony_ci  You should have received a copy of the GNU Lesser General Public License
1753a5a1b3Sopenharmony_ci  along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
1853a5a1b3Sopenharmony_ci***/
1953a5a1b3Sopenharmony_ci
2053a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H
2153a5a1b3Sopenharmony_ci#include <config.h>
2253a5a1b3Sopenharmony_ci#endif
2353a5a1b3Sopenharmony_ci
2453a5a1b3Sopenharmony_ci#include <pulsecore/core-util.h>
2553a5a1b3Sopenharmony_ci#include <pulsecore/dbus-util.h>
2653a5a1b3Sopenharmony_ci#include <pulsecore/namereg.h>
2753a5a1b3Sopenharmony_ci#include <pulsecore/protocol-dbus.h>
2853a5a1b3Sopenharmony_ci
2953a5a1b3Sopenharmony_ci#include "iface-sample.h"
3053a5a1b3Sopenharmony_ci
3153a5a1b3Sopenharmony_ci#define OBJECT_NAME "sample"
3253a5a1b3Sopenharmony_ci
3353a5a1b3Sopenharmony_cistruct pa_dbusiface_sample {
3453a5a1b3Sopenharmony_ci    pa_dbusiface_core *core;
3553a5a1b3Sopenharmony_ci
3653a5a1b3Sopenharmony_ci    pa_scache_entry *sample;
3753a5a1b3Sopenharmony_ci    char *path;
3853a5a1b3Sopenharmony_ci    pa_proplist *proplist;
3953a5a1b3Sopenharmony_ci
4053a5a1b3Sopenharmony_ci    pa_hook_slot *sample_cache_changed_slot;
4153a5a1b3Sopenharmony_ci
4253a5a1b3Sopenharmony_ci    pa_dbus_protocol *dbus_protocol;
4353a5a1b3Sopenharmony_ci};
4453a5a1b3Sopenharmony_ci
4553a5a1b3Sopenharmony_cistatic void handle_get_index(DBusConnection *conn, DBusMessage *msg, void *userdata);
4653a5a1b3Sopenharmony_cistatic void handle_get_name(DBusConnection *conn, DBusMessage *msg, void *userdata);
4753a5a1b3Sopenharmony_cistatic void handle_get_sample_format(DBusConnection *conn, DBusMessage *msg, void *userdata);
4853a5a1b3Sopenharmony_cistatic void handle_get_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata);
4953a5a1b3Sopenharmony_cistatic void handle_get_channels(DBusConnection *conn, DBusMessage *msg, void *userdata);
5053a5a1b3Sopenharmony_cistatic void handle_get_default_volume(DBusConnection *conn, DBusMessage *msg, void *userdata);
5153a5a1b3Sopenharmony_cistatic void handle_get_duration(DBusConnection *conn, DBusMessage *msg, void *userdata);
5253a5a1b3Sopenharmony_cistatic void handle_get_bytes(DBusConnection *conn, DBusMessage *msg, void *userdata);
5353a5a1b3Sopenharmony_cistatic void handle_get_property_list(DBusConnection *conn, DBusMessage *msg, void *userdata);
5453a5a1b3Sopenharmony_ci
5553a5a1b3Sopenharmony_cistatic void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata);
5653a5a1b3Sopenharmony_ci
5753a5a1b3Sopenharmony_cistatic void handle_play(DBusConnection *conn, DBusMessage *msg, void *userdata);
5853a5a1b3Sopenharmony_cistatic void handle_play_to_sink(DBusConnection *conn, DBusMessage *msg, void *userdata);
5953a5a1b3Sopenharmony_cistatic void handle_remove(DBusConnection *conn, DBusMessage *msg, void *userdata);
6053a5a1b3Sopenharmony_ci
6153a5a1b3Sopenharmony_cienum property_handler_index {
6253a5a1b3Sopenharmony_ci    PROPERTY_HANDLER_INDEX,
6353a5a1b3Sopenharmony_ci    PROPERTY_HANDLER_NAME,
6453a5a1b3Sopenharmony_ci    PROPERTY_HANDLER_SAMPLE_FORMAT,
6553a5a1b3Sopenharmony_ci    PROPERTY_HANDLER_SAMPLE_RATE,
6653a5a1b3Sopenharmony_ci    PROPERTY_HANDLER_CHANNELS,
6753a5a1b3Sopenharmony_ci    PROPERTY_HANDLER_DEFAULT_VOLUME,
6853a5a1b3Sopenharmony_ci    PROPERTY_HANDLER_DURATION,
6953a5a1b3Sopenharmony_ci    PROPERTY_HANDLER_BYTES,
7053a5a1b3Sopenharmony_ci    PROPERTY_HANDLER_PROPERTY_LIST,
7153a5a1b3Sopenharmony_ci    PROPERTY_HANDLER_MAX
7253a5a1b3Sopenharmony_ci};
7353a5a1b3Sopenharmony_ci
7453a5a1b3Sopenharmony_cistatic pa_dbus_property_handler property_handlers[PROPERTY_HANDLER_MAX] = {
7553a5a1b3Sopenharmony_ci    [PROPERTY_HANDLER_INDEX]          = { .property_name = "Index",         .type = "u",      .get_cb = handle_get_index,          .set_cb = NULL },
7653a5a1b3Sopenharmony_ci    [PROPERTY_HANDLER_NAME]           = { .property_name = "Name",          .type = "s",      .get_cb = handle_get_name,           .set_cb = NULL },
7753a5a1b3Sopenharmony_ci    [PROPERTY_HANDLER_SAMPLE_FORMAT]  = { .property_name = "SampleFormat",  .type = "u",      .get_cb = handle_get_sample_format,  .set_cb = NULL },
7853a5a1b3Sopenharmony_ci    [PROPERTY_HANDLER_SAMPLE_RATE]    = { .property_name = "SampleRate",    .type = "u",      .get_cb = handle_get_sample_rate,    .set_cb = NULL },
7953a5a1b3Sopenharmony_ci    [PROPERTY_HANDLER_CHANNELS]       = { .property_name = "Channels",      .type = "au",     .get_cb = handle_get_channels,       .set_cb = NULL },
8053a5a1b3Sopenharmony_ci    [PROPERTY_HANDLER_DEFAULT_VOLUME] = { .property_name = "DefaultVolume", .type = "au",     .get_cb = handle_get_default_volume, .set_cb = NULL },
8153a5a1b3Sopenharmony_ci    [PROPERTY_HANDLER_DURATION]       = { .property_name = "Duration",      .type = "t",      .get_cb = handle_get_duration,       .set_cb = NULL },
8253a5a1b3Sopenharmony_ci    [PROPERTY_HANDLER_BYTES]          = { .property_name = "Bytes",         .type = "u",      .get_cb = handle_get_bytes,          .set_cb = NULL },
8353a5a1b3Sopenharmony_ci    [PROPERTY_HANDLER_PROPERTY_LIST]  = { .property_name = "PropertyList",  .type = "a{say}", .get_cb = handle_get_property_list,  .set_cb = NULL }
8453a5a1b3Sopenharmony_ci};
8553a5a1b3Sopenharmony_ci
8653a5a1b3Sopenharmony_cienum method_handler_index {
8753a5a1b3Sopenharmony_ci    METHOD_HANDLER_PLAY,
8853a5a1b3Sopenharmony_ci    METHOD_HANDLER_PLAY_TO_SINK,
8953a5a1b3Sopenharmony_ci    METHOD_HANDLER_REMOVE,
9053a5a1b3Sopenharmony_ci    METHOD_HANDLER_MAX
9153a5a1b3Sopenharmony_ci};
9253a5a1b3Sopenharmony_ci
9353a5a1b3Sopenharmony_cistatic pa_dbus_arg_info play_args[] = { { "volume", "u", "in" }, { "property_list", "a{say}", "in" } };
9453a5a1b3Sopenharmony_cistatic pa_dbus_arg_info play_to_sink_args[] = { { "sink",          "o",      "in" },
9553a5a1b3Sopenharmony_ci                                                { "volume",        "u",      "in" },
9653a5a1b3Sopenharmony_ci                                                { "property_list", "a{say}", "in" } };
9753a5a1b3Sopenharmony_ci
9853a5a1b3Sopenharmony_cistatic pa_dbus_method_handler method_handlers[METHOD_HANDLER_MAX] = {
9953a5a1b3Sopenharmony_ci    [METHOD_HANDLER_PLAY] = {
10053a5a1b3Sopenharmony_ci        .method_name = "Play",
10153a5a1b3Sopenharmony_ci        .arguments = play_args,
10253a5a1b3Sopenharmony_ci        .n_arguments = sizeof(play_args) / sizeof(pa_dbus_arg_info),
10353a5a1b3Sopenharmony_ci        .receive_cb = handle_play },
10453a5a1b3Sopenharmony_ci    [METHOD_HANDLER_PLAY_TO_SINK] = {
10553a5a1b3Sopenharmony_ci        .method_name = "PlayToSink",
10653a5a1b3Sopenharmony_ci        .arguments = play_to_sink_args,
10753a5a1b3Sopenharmony_ci        .n_arguments = sizeof(play_to_sink_args) / sizeof(pa_dbus_arg_info),
10853a5a1b3Sopenharmony_ci        .receive_cb = handle_play_to_sink },
10953a5a1b3Sopenharmony_ci    [METHOD_HANDLER_REMOVE] = {
11053a5a1b3Sopenharmony_ci        .method_name = "Remove",
11153a5a1b3Sopenharmony_ci        .arguments = NULL,
11253a5a1b3Sopenharmony_ci        .n_arguments = 0,
11353a5a1b3Sopenharmony_ci        .receive_cb = handle_remove }
11453a5a1b3Sopenharmony_ci};
11553a5a1b3Sopenharmony_ci
11653a5a1b3Sopenharmony_cienum signal_index {
11753a5a1b3Sopenharmony_ci    SIGNAL_PROPERTY_LIST_UPDATED,
11853a5a1b3Sopenharmony_ci    SIGNAL_MAX
11953a5a1b3Sopenharmony_ci};
12053a5a1b3Sopenharmony_ci
12153a5a1b3Sopenharmony_cistatic pa_dbus_arg_info property_list_updated_args[] = { { "property_list", "a{say}", NULL } };
12253a5a1b3Sopenharmony_ci
12353a5a1b3Sopenharmony_cistatic pa_dbus_signal_info signals[SIGNAL_MAX] = {
12453a5a1b3Sopenharmony_ci    [SIGNAL_PROPERTY_LIST_UPDATED] = { .name = "PropertyListUpdated", .arguments = property_list_updated_args, .n_arguments = 1 }
12553a5a1b3Sopenharmony_ci};
12653a5a1b3Sopenharmony_ci
12753a5a1b3Sopenharmony_cistatic pa_dbus_interface_info sample_interface_info = {
12853a5a1b3Sopenharmony_ci    .name = PA_DBUSIFACE_SAMPLE_INTERFACE,
12953a5a1b3Sopenharmony_ci    .method_handlers = method_handlers,
13053a5a1b3Sopenharmony_ci    .n_method_handlers = METHOD_HANDLER_MAX,
13153a5a1b3Sopenharmony_ci    .property_handlers = property_handlers,
13253a5a1b3Sopenharmony_ci    .n_property_handlers = PROPERTY_HANDLER_MAX,
13353a5a1b3Sopenharmony_ci    .get_all_properties_cb = handle_get_all,
13453a5a1b3Sopenharmony_ci    .signals = signals,
13553a5a1b3Sopenharmony_ci    .n_signals = SIGNAL_MAX
13653a5a1b3Sopenharmony_ci};
13753a5a1b3Sopenharmony_ci
13853a5a1b3Sopenharmony_cistatic void handle_get_index(DBusConnection *conn, DBusMessage *msg, void *userdata) {
13953a5a1b3Sopenharmony_ci    pa_dbusiface_sample *s = userdata;
14053a5a1b3Sopenharmony_ci    dbus_uint32_t idx = 0;
14153a5a1b3Sopenharmony_ci
14253a5a1b3Sopenharmony_ci    pa_assert(conn);
14353a5a1b3Sopenharmony_ci    pa_assert(msg);
14453a5a1b3Sopenharmony_ci    pa_assert(s);
14553a5a1b3Sopenharmony_ci
14653a5a1b3Sopenharmony_ci    idx = s->sample->index;
14753a5a1b3Sopenharmony_ci
14853a5a1b3Sopenharmony_ci    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &idx);
14953a5a1b3Sopenharmony_ci}
15053a5a1b3Sopenharmony_ci
15153a5a1b3Sopenharmony_cistatic void handle_get_name(DBusConnection *conn, DBusMessage *msg, void *userdata) {
15253a5a1b3Sopenharmony_ci    pa_dbusiface_sample *s = userdata;
15353a5a1b3Sopenharmony_ci
15453a5a1b3Sopenharmony_ci    pa_assert(conn);
15553a5a1b3Sopenharmony_ci    pa_assert(msg);
15653a5a1b3Sopenharmony_ci    pa_assert(s);
15753a5a1b3Sopenharmony_ci
15853a5a1b3Sopenharmony_ci    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_STRING, &s->sample->name);
15953a5a1b3Sopenharmony_ci}
16053a5a1b3Sopenharmony_ci
16153a5a1b3Sopenharmony_cistatic void handle_get_sample_format(DBusConnection *conn, DBusMessage *msg, void *userdata) {
16253a5a1b3Sopenharmony_ci    pa_dbusiface_sample *s = userdata;
16353a5a1b3Sopenharmony_ci    dbus_uint32_t sample_format = 0;
16453a5a1b3Sopenharmony_ci
16553a5a1b3Sopenharmony_ci    pa_assert(conn);
16653a5a1b3Sopenharmony_ci    pa_assert(msg);
16753a5a1b3Sopenharmony_ci    pa_assert(s);
16853a5a1b3Sopenharmony_ci
16953a5a1b3Sopenharmony_ci    if (!s->sample->memchunk.memblock) {
17053a5a1b3Sopenharmony_ci        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY,
17153a5a1b3Sopenharmony_ci                           "Sample %s isn't loaded into memory yet, so its sample format is unknown.", s->sample->name);
17253a5a1b3Sopenharmony_ci        return;
17353a5a1b3Sopenharmony_ci    }
17453a5a1b3Sopenharmony_ci
17553a5a1b3Sopenharmony_ci    sample_format = s->sample->sample_spec.format;
17653a5a1b3Sopenharmony_ci
17753a5a1b3Sopenharmony_ci    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &sample_format);
17853a5a1b3Sopenharmony_ci}
17953a5a1b3Sopenharmony_ci
18053a5a1b3Sopenharmony_cistatic void handle_get_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata) {
18153a5a1b3Sopenharmony_ci    pa_dbusiface_sample *s = userdata;
18253a5a1b3Sopenharmony_ci    dbus_uint32_t sample_rate = 0;
18353a5a1b3Sopenharmony_ci
18453a5a1b3Sopenharmony_ci    pa_assert(conn);
18553a5a1b3Sopenharmony_ci    pa_assert(msg);
18653a5a1b3Sopenharmony_ci    pa_assert(s);
18753a5a1b3Sopenharmony_ci
18853a5a1b3Sopenharmony_ci    if (!s->sample->memchunk.memblock) {
18953a5a1b3Sopenharmony_ci        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY,
19053a5a1b3Sopenharmony_ci                           "Sample %s isn't loaded into memory yet, so its sample rate is unknown.", s->sample->name);
19153a5a1b3Sopenharmony_ci        return;
19253a5a1b3Sopenharmony_ci    }
19353a5a1b3Sopenharmony_ci
19453a5a1b3Sopenharmony_ci    sample_rate = s->sample->sample_spec.rate;
19553a5a1b3Sopenharmony_ci
19653a5a1b3Sopenharmony_ci    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &sample_rate);
19753a5a1b3Sopenharmony_ci}
19853a5a1b3Sopenharmony_ci
19953a5a1b3Sopenharmony_cistatic void handle_get_channels(DBusConnection *conn, DBusMessage *msg, void *userdata) {
20053a5a1b3Sopenharmony_ci    pa_dbusiface_sample *s = userdata;
20153a5a1b3Sopenharmony_ci    dbus_uint32_t channels[PA_CHANNELS_MAX];
20253a5a1b3Sopenharmony_ci    unsigned i = 0;
20353a5a1b3Sopenharmony_ci
20453a5a1b3Sopenharmony_ci    pa_assert(conn);
20553a5a1b3Sopenharmony_ci    pa_assert(msg);
20653a5a1b3Sopenharmony_ci    pa_assert(s);
20753a5a1b3Sopenharmony_ci
20853a5a1b3Sopenharmony_ci    if (!s->sample->memchunk.memblock) {
20953a5a1b3Sopenharmony_ci        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY,
21053a5a1b3Sopenharmony_ci                           "Sample %s isn't loaded into memory yet, so its channel map is unknown.", s->sample->name);
21153a5a1b3Sopenharmony_ci        return;
21253a5a1b3Sopenharmony_ci    }
21353a5a1b3Sopenharmony_ci
21453a5a1b3Sopenharmony_ci    for (i = 0; i < s->sample->channel_map.channels; ++i)
21553a5a1b3Sopenharmony_ci        channels[i] = s->sample->channel_map.map[i];
21653a5a1b3Sopenharmony_ci
21753a5a1b3Sopenharmony_ci    pa_dbus_send_basic_array_variant_reply(conn, msg, DBUS_TYPE_UINT32, channels, s->sample->channel_map.channels);
21853a5a1b3Sopenharmony_ci}
21953a5a1b3Sopenharmony_ci
22053a5a1b3Sopenharmony_cistatic void handle_get_default_volume(DBusConnection *conn, DBusMessage *msg, void *userdata) {
22153a5a1b3Sopenharmony_ci    pa_dbusiface_sample *s = userdata;
22253a5a1b3Sopenharmony_ci    dbus_uint32_t default_volume[PA_CHANNELS_MAX];
22353a5a1b3Sopenharmony_ci    unsigned i = 0;
22453a5a1b3Sopenharmony_ci
22553a5a1b3Sopenharmony_ci    pa_assert(conn);
22653a5a1b3Sopenharmony_ci    pa_assert(msg);
22753a5a1b3Sopenharmony_ci    pa_assert(s);
22853a5a1b3Sopenharmony_ci
22953a5a1b3Sopenharmony_ci    if (!s->sample->volume_is_set) {
23053a5a1b3Sopenharmony_ci        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY,
23153a5a1b3Sopenharmony_ci                           "Sample %s doesn't have default volume stored.", s->sample->name);
23253a5a1b3Sopenharmony_ci        return;
23353a5a1b3Sopenharmony_ci    }
23453a5a1b3Sopenharmony_ci
23553a5a1b3Sopenharmony_ci    for (i = 0; i < s->sample->volume.channels; ++i)
23653a5a1b3Sopenharmony_ci        default_volume[i] = s->sample->volume.values[i];
23753a5a1b3Sopenharmony_ci
23853a5a1b3Sopenharmony_ci    pa_dbus_send_basic_array_variant_reply(conn, msg, DBUS_TYPE_UINT32, default_volume, s->sample->volume.channels);
23953a5a1b3Sopenharmony_ci}
24053a5a1b3Sopenharmony_ci
24153a5a1b3Sopenharmony_cistatic void handle_get_duration(DBusConnection *conn, DBusMessage *msg, void *userdata) {
24253a5a1b3Sopenharmony_ci    pa_dbusiface_sample *s = userdata;
24353a5a1b3Sopenharmony_ci    dbus_uint64_t duration = 0;
24453a5a1b3Sopenharmony_ci
24553a5a1b3Sopenharmony_ci    pa_assert(conn);
24653a5a1b3Sopenharmony_ci    pa_assert(msg);
24753a5a1b3Sopenharmony_ci    pa_assert(s);
24853a5a1b3Sopenharmony_ci
24953a5a1b3Sopenharmony_ci    if (!s->sample->memchunk.memblock) {
25053a5a1b3Sopenharmony_ci        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY,
25153a5a1b3Sopenharmony_ci                           "Sample %s isn't loaded into memory yet, so its duration is unknown.", s->sample->name);
25253a5a1b3Sopenharmony_ci        return;
25353a5a1b3Sopenharmony_ci    }
25453a5a1b3Sopenharmony_ci
25553a5a1b3Sopenharmony_ci    duration = pa_bytes_to_usec(s->sample->memchunk.length, &s->sample->sample_spec);
25653a5a1b3Sopenharmony_ci
25753a5a1b3Sopenharmony_ci    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT64, &duration);
25853a5a1b3Sopenharmony_ci}
25953a5a1b3Sopenharmony_ci
26053a5a1b3Sopenharmony_cistatic void handle_get_bytes(DBusConnection *conn, DBusMessage *msg, void *userdata) {
26153a5a1b3Sopenharmony_ci    pa_dbusiface_sample *s = userdata;
26253a5a1b3Sopenharmony_ci    dbus_uint32_t bytes = 0;
26353a5a1b3Sopenharmony_ci
26453a5a1b3Sopenharmony_ci    pa_assert(conn);
26553a5a1b3Sopenharmony_ci    pa_assert(msg);
26653a5a1b3Sopenharmony_ci    pa_assert(s);
26753a5a1b3Sopenharmony_ci
26853a5a1b3Sopenharmony_ci    if (!s->sample->memchunk.memblock) {
26953a5a1b3Sopenharmony_ci        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY,
27053a5a1b3Sopenharmony_ci                           "Sample %s isn't loaded into memory yet, so its size is unknown.", s->sample->name);
27153a5a1b3Sopenharmony_ci        return;
27253a5a1b3Sopenharmony_ci    }
27353a5a1b3Sopenharmony_ci
27453a5a1b3Sopenharmony_ci    bytes = s->sample->memchunk.length;
27553a5a1b3Sopenharmony_ci
27653a5a1b3Sopenharmony_ci    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &bytes);
27753a5a1b3Sopenharmony_ci}
27853a5a1b3Sopenharmony_ci
27953a5a1b3Sopenharmony_cistatic void handle_get_property_list(DBusConnection *conn, DBusMessage *msg, void *userdata) {
28053a5a1b3Sopenharmony_ci    pa_dbusiface_sample *s = userdata;
28153a5a1b3Sopenharmony_ci
28253a5a1b3Sopenharmony_ci    pa_assert(conn);
28353a5a1b3Sopenharmony_ci    pa_assert(msg);
28453a5a1b3Sopenharmony_ci    pa_assert(s);
28553a5a1b3Sopenharmony_ci
28653a5a1b3Sopenharmony_ci    pa_dbus_send_proplist_variant_reply(conn, msg, s->proplist);
28753a5a1b3Sopenharmony_ci}
28853a5a1b3Sopenharmony_ci
28953a5a1b3Sopenharmony_cistatic void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata) {
29053a5a1b3Sopenharmony_ci    pa_dbusiface_sample *s = userdata;
29153a5a1b3Sopenharmony_ci    DBusMessage *reply = NULL;
29253a5a1b3Sopenharmony_ci    DBusMessageIter msg_iter;
29353a5a1b3Sopenharmony_ci    DBusMessageIter dict_iter;
29453a5a1b3Sopenharmony_ci    dbus_uint32_t idx = 0;
29553a5a1b3Sopenharmony_ci    dbus_uint32_t sample_format = 0;
29653a5a1b3Sopenharmony_ci    dbus_uint32_t sample_rate = 0;
29753a5a1b3Sopenharmony_ci    dbus_uint32_t channels[PA_CHANNELS_MAX];
29853a5a1b3Sopenharmony_ci    dbus_uint32_t default_volume[PA_CHANNELS_MAX];
29953a5a1b3Sopenharmony_ci    dbus_uint64_t duration = 0;
30053a5a1b3Sopenharmony_ci    dbus_uint32_t bytes = 0;
30153a5a1b3Sopenharmony_ci    unsigned i = 0;
30253a5a1b3Sopenharmony_ci
30353a5a1b3Sopenharmony_ci    pa_assert(conn);
30453a5a1b3Sopenharmony_ci    pa_assert(msg);
30553a5a1b3Sopenharmony_ci    pa_assert(s);
30653a5a1b3Sopenharmony_ci
30753a5a1b3Sopenharmony_ci    idx = s->sample->index;
30853a5a1b3Sopenharmony_ci    if (s->sample->memchunk.memblock) {
30953a5a1b3Sopenharmony_ci        sample_format = s->sample->sample_spec.format;
31053a5a1b3Sopenharmony_ci        sample_rate = s->sample->sample_spec.rate;
31153a5a1b3Sopenharmony_ci        for (i = 0; i < s->sample->channel_map.channels; ++i)
31253a5a1b3Sopenharmony_ci            channels[i] = s->sample->channel_map.map[i];
31353a5a1b3Sopenharmony_ci        duration = pa_bytes_to_usec(s->sample->memchunk.length, &s->sample->sample_spec);
31453a5a1b3Sopenharmony_ci        bytes = s->sample->memchunk.length;
31553a5a1b3Sopenharmony_ci    }
31653a5a1b3Sopenharmony_ci    if (s->sample->volume_is_set) {
31753a5a1b3Sopenharmony_ci        for (i = 0; i < s->sample->volume.channels; ++i)
31853a5a1b3Sopenharmony_ci            default_volume[i] = s->sample->volume.values[i];
31953a5a1b3Sopenharmony_ci    }
32053a5a1b3Sopenharmony_ci
32153a5a1b3Sopenharmony_ci    pa_assert_se((reply = dbus_message_new_method_return(msg)));
32253a5a1b3Sopenharmony_ci
32353a5a1b3Sopenharmony_ci    dbus_message_iter_init_append(reply, &msg_iter);
32453a5a1b3Sopenharmony_ci    pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "{sv}", &dict_iter));
32553a5a1b3Sopenharmony_ci
32653a5a1b3Sopenharmony_ci    pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_INDEX].property_name, DBUS_TYPE_UINT32, &idx);
32753a5a1b3Sopenharmony_ci    pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_NAME].property_name, DBUS_TYPE_STRING, &s->sample->name);
32853a5a1b3Sopenharmony_ci
32953a5a1b3Sopenharmony_ci    if (s->sample->memchunk.memblock) {
33053a5a1b3Sopenharmony_ci        pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_SAMPLE_FORMAT].property_name, DBUS_TYPE_UINT32, &sample_format);
33153a5a1b3Sopenharmony_ci        pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_SAMPLE_RATE].property_name, DBUS_TYPE_UINT32, &sample_rate);
33253a5a1b3Sopenharmony_ci        pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_CHANNELS].property_name, DBUS_TYPE_UINT32, channels, s->sample->channel_map.channels);
33353a5a1b3Sopenharmony_ci    }
33453a5a1b3Sopenharmony_ci
33553a5a1b3Sopenharmony_ci    if (s->sample->volume_is_set)
33653a5a1b3Sopenharmony_ci        pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_DEFAULT_VOLUME].property_name, DBUS_TYPE_UINT32, default_volume, s->sample->volume.channels);
33753a5a1b3Sopenharmony_ci
33853a5a1b3Sopenharmony_ci    if (s->sample->memchunk.memblock) {
33953a5a1b3Sopenharmony_ci        pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_DURATION].property_name, DBUS_TYPE_UINT64, &duration);
34053a5a1b3Sopenharmony_ci        pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_BYTES].property_name, DBUS_TYPE_UINT32, &bytes);
34153a5a1b3Sopenharmony_ci    }
34253a5a1b3Sopenharmony_ci
34353a5a1b3Sopenharmony_ci    pa_dbus_append_proplist_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_PROPERTY_LIST].property_name, s->proplist);
34453a5a1b3Sopenharmony_ci
34553a5a1b3Sopenharmony_ci    pa_assert_se(dbus_message_iter_close_container(&msg_iter, &dict_iter));
34653a5a1b3Sopenharmony_ci    pa_assert_se(dbus_connection_send(conn, reply, NULL));
34753a5a1b3Sopenharmony_ci    dbus_message_unref(reply);
34853a5a1b3Sopenharmony_ci}
34953a5a1b3Sopenharmony_ci
35053a5a1b3Sopenharmony_cistatic void handle_play(DBusConnection *conn, DBusMessage *msg, void *userdata) {
35153a5a1b3Sopenharmony_ci    pa_dbusiface_sample *s = userdata;
35253a5a1b3Sopenharmony_ci    DBusMessageIter msg_iter;
35353a5a1b3Sopenharmony_ci    dbus_uint32_t volume = 0;
35453a5a1b3Sopenharmony_ci    pa_proplist *property_list = NULL;
35553a5a1b3Sopenharmony_ci
35653a5a1b3Sopenharmony_ci    pa_assert(conn);
35753a5a1b3Sopenharmony_ci    pa_assert(msg);
35853a5a1b3Sopenharmony_ci    pa_assert(s);
35953a5a1b3Sopenharmony_ci
36053a5a1b3Sopenharmony_ci    pa_assert_se(dbus_message_iter_init(msg, &msg_iter));
36153a5a1b3Sopenharmony_ci    dbus_message_iter_get_basic(&msg_iter, &volume);
36253a5a1b3Sopenharmony_ci
36353a5a1b3Sopenharmony_ci    pa_assert_se(dbus_message_iter_next(&msg_iter));
36453a5a1b3Sopenharmony_ci    if (!(property_list = pa_dbus_get_proplist_arg(conn, msg, &msg_iter)))
36553a5a1b3Sopenharmony_ci        return;
36653a5a1b3Sopenharmony_ci
36753a5a1b3Sopenharmony_ci    if (!PA_VOLUME_IS_VALID(volume)) {
36853a5a1b3Sopenharmony_ci        pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "Invalid volume.");
36953a5a1b3Sopenharmony_ci        goto finish;
37053a5a1b3Sopenharmony_ci    }
37153a5a1b3Sopenharmony_ci
37253a5a1b3Sopenharmony_ci    if (!s->sample->core->default_sink) {
37353a5a1b3Sopenharmony_ci        pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED,
37453a5a1b3Sopenharmony_ci                           "Can't play sample %s, because there are no sinks available.", s->sample->name);
37553a5a1b3Sopenharmony_ci        goto finish;
37653a5a1b3Sopenharmony_ci    }
37753a5a1b3Sopenharmony_ci
37853a5a1b3Sopenharmony_ci    if (pa_scache_play_item(s->sample->core,
37953a5a1b3Sopenharmony_ci                            s->sample->name,
38053a5a1b3Sopenharmony_ci                            s->sample->core->default_sink,
38153a5a1b3Sopenharmony_ci                            volume,
38253a5a1b3Sopenharmony_ci                            property_list,
38353a5a1b3Sopenharmony_ci                            NULL) < 0) {
38453a5a1b3Sopenharmony_ci        pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "Playing sample %s failed.", s->sample->name);
38553a5a1b3Sopenharmony_ci        goto finish;
38653a5a1b3Sopenharmony_ci    }
38753a5a1b3Sopenharmony_ci
38853a5a1b3Sopenharmony_ci    pa_dbus_send_empty_reply(conn, msg);
38953a5a1b3Sopenharmony_ci
39053a5a1b3Sopenharmony_cifinish:
39153a5a1b3Sopenharmony_ci    if (property_list)
39253a5a1b3Sopenharmony_ci        pa_proplist_free(property_list);
39353a5a1b3Sopenharmony_ci}
39453a5a1b3Sopenharmony_ci
39553a5a1b3Sopenharmony_cistatic void handle_play_to_sink(DBusConnection *conn, DBusMessage *msg, void *userdata) {
39653a5a1b3Sopenharmony_ci    pa_dbusiface_sample *s = userdata;
39753a5a1b3Sopenharmony_ci    DBusMessageIter msg_iter;
39853a5a1b3Sopenharmony_ci    const char *sink_path = NULL;
39953a5a1b3Sopenharmony_ci    dbus_uint32_t volume = 0;
40053a5a1b3Sopenharmony_ci    pa_proplist *property_list = NULL;
40153a5a1b3Sopenharmony_ci    pa_sink *sink = NULL;
40253a5a1b3Sopenharmony_ci
40353a5a1b3Sopenharmony_ci    pa_assert(conn);
40453a5a1b3Sopenharmony_ci    pa_assert(msg);
40553a5a1b3Sopenharmony_ci    pa_assert(s);
40653a5a1b3Sopenharmony_ci
40753a5a1b3Sopenharmony_ci    pa_assert_se(dbus_message_iter_init(msg, &msg_iter));
40853a5a1b3Sopenharmony_ci    dbus_message_iter_get_basic(&msg_iter, &sink_path);
40953a5a1b3Sopenharmony_ci
41053a5a1b3Sopenharmony_ci    pa_assert_se(dbus_message_iter_next(&msg_iter));
41153a5a1b3Sopenharmony_ci    dbus_message_iter_get_basic(&msg_iter, &volume);
41253a5a1b3Sopenharmony_ci
41353a5a1b3Sopenharmony_ci    pa_assert_se(dbus_message_iter_next(&msg_iter));
41453a5a1b3Sopenharmony_ci    if (!(property_list = pa_dbus_get_proplist_arg(conn, msg, &msg_iter)))
41553a5a1b3Sopenharmony_ci        return;
41653a5a1b3Sopenharmony_ci
41753a5a1b3Sopenharmony_ci    if (!(sink = pa_dbusiface_core_get_sink(s->core, sink_path))) {
41853a5a1b3Sopenharmony_ci        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NOT_FOUND, "%s: No such sink.", sink_path);
41953a5a1b3Sopenharmony_ci        goto finish;
42053a5a1b3Sopenharmony_ci    }
42153a5a1b3Sopenharmony_ci
42253a5a1b3Sopenharmony_ci    if (!PA_VOLUME_IS_VALID(volume)) {
42353a5a1b3Sopenharmony_ci        pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "Invalid volume.");
42453a5a1b3Sopenharmony_ci        goto finish;
42553a5a1b3Sopenharmony_ci    }
42653a5a1b3Sopenharmony_ci
42753a5a1b3Sopenharmony_ci    if (pa_scache_play_item(s->sample->core, s->sample->name, sink, volume, property_list, NULL) < 0) {
42853a5a1b3Sopenharmony_ci        pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "Playing sample %s failed.", s->sample->name);
42953a5a1b3Sopenharmony_ci        goto finish;
43053a5a1b3Sopenharmony_ci    }
43153a5a1b3Sopenharmony_ci
43253a5a1b3Sopenharmony_ci    pa_dbus_send_empty_reply(conn, msg);
43353a5a1b3Sopenharmony_ci
43453a5a1b3Sopenharmony_cifinish:
43553a5a1b3Sopenharmony_ci    if (property_list)
43653a5a1b3Sopenharmony_ci        pa_proplist_free(property_list);
43753a5a1b3Sopenharmony_ci}
43853a5a1b3Sopenharmony_ci
43953a5a1b3Sopenharmony_cistatic void handle_remove(DBusConnection *conn, DBusMessage *msg, void *userdata) {
44053a5a1b3Sopenharmony_ci    pa_dbusiface_sample *s = userdata;
44153a5a1b3Sopenharmony_ci
44253a5a1b3Sopenharmony_ci    pa_assert(conn);
44353a5a1b3Sopenharmony_ci    pa_assert(msg);
44453a5a1b3Sopenharmony_ci    pa_assert(s);
44553a5a1b3Sopenharmony_ci
44653a5a1b3Sopenharmony_ci    if (pa_scache_remove_item(s->sample->core, s->sample->name) < 0) {
44753a5a1b3Sopenharmony_ci        pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "Removing sample %s failed.", s->sample->name);
44853a5a1b3Sopenharmony_ci        return;
44953a5a1b3Sopenharmony_ci    }
45053a5a1b3Sopenharmony_ci
45153a5a1b3Sopenharmony_ci    pa_dbus_send_empty_reply(conn, msg);
45253a5a1b3Sopenharmony_ci}
45353a5a1b3Sopenharmony_ci
45453a5a1b3Sopenharmony_cistatic pa_hook_result_t sample_cache_changed_cb(void *hook_data, void *call_data, void *slot_data) {
45553a5a1b3Sopenharmony_ci    pa_dbusiface_sample *sample_iface = slot_data;
45653a5a1b3Sopenharmony_ci    pa_scache_entry *sample = call_data;
45753a5a1b3Sopenharmony_ci    DBusMessage *signal_msg;
45853a5a1b3Sopenharmony_ci
45953a5a1b3Sopenharmony_ci    pa_assert(sample);
46053a5a1b3Sopenharmony_ci    pa_assert(sample_iface);
46153a5a1b3Sopenharmony_ci
46253a5a1b3Sopenharmony_ci    if (sample_iface->sample != sample)
46353a5a1b3Sopenharmony_ci        return PA_HOOK_OK;
46453a5a1b3Sopenharmony_ci
46553a5a1b3Sopenharmony_ci    if (!pa_proplist_equal(sample_iface->proplist, sample_iface->sample->proplist)) {
46653a5a1b3Sopenharmony_ci        DBusMessageIter msg_iter;
46753a5a1b3Sopenharmony_ci
46853a5a1b3Sopenharmony_ci        pa_proplist_update(sample_iface->proplist, PA_UPDATE_SET, sample_iface->sample->proplist);
46953a5a1b3Sopenharmony_ci
47053a5a1b3Sopenharmony_ci        pa_assert_se(signal_msg = dbus_message_new_signal(sample_iface->path,
47153a5a1b3Sopenharmony_ci                                                          PA_DBUSIFACE_SAMPLE_INTERFACE,
47253a5a1b3Sopenharmony_ci                                                          signals[SIGNAL_PROPERTY_LIST_UPDATED].name));
47353a5a1b3Sopenharmony_ci        dbus_message_iter_init_append(signal_msg, &msg_iter);
47453a5a1b3Sopenharmony_ci        pa_dbus_append_proplist(&msg_iter, sample_iface->proplist);
47553a5a1b3Sopenharmony_ci
47653a5a1b3Sopenharmony_ci        pa_dbus_protocol_send_signal(sample_iface->dbus_protocol, signal_msg);
47753a5a1b3Sopenharmony_ci        dbus_message_unref(signal_msg);
47853a5a1b3Sopenharmony_ci    }
47953a5a1b3Sopenharmony_ci
48053a5a1b3Sopenharmony_ci    return PA_HOOK_OK;
48153a5a1b3Sopenharmony_ci}
48253a5a1b3Sopenharmony_ci
48353a5a1b3Sopenharmony_cipa_dbusiface_sample *pa_dbusiface_sample_new(pa_dbusiface_core *core, pa_scache_entry *sample) {
48453a5a1b3Sopenharmony_ci    pa_dbusiface_sample *s = NULL;
48553a5a1b3Sopenharmony_ci
48653a5a1b3Sopenharmony_ci    pa_assert(core);
48753a5a1b3Sopenharmony_ci    pa_assert(sample);
48853a5a1b3Sopenharmony_ci
48953a5a1b3Sopenharmony_ci    s = pa_xnew0(pa_dbusiface_sample, 1);
49053a5a1b3Sopenharmony_ci    s->core = core;
49153a5a1b3Sopenharmony_ci    s->sample = sample;
49253a5a1b3Sopenharmony_ci    s->path = pa_sprintf_malloc("%s/%s%u", PA_DBUS_CORE_OBJECT_PATH, OBJECT_NAME, sample->index);
49353a5a1b3Sopenharmony_ci    s->proplist = pa_proplist_copy(sample->proplist);
49453a5a1b3Sopenharmony_ci    s->dbus_protocol = pa_dbus_protocol_get(sample->core);
49553a5a1b3Sopenharmony_ci    s->sample_cache_changed_slot = pa_hook_connect(&sample->core->hooks[PA_CORE_HOOK_SAMPLE_CACHE_CHANGED],
49653a5a1b3Sopenharmony_ci                                                   PA_HOOK_NORMAL, sample_cache_changed_cb, s);
49753a5a1b3Sopenharmony_ci
49853a5a1b3Sopenharmony_ci    pa_assert_se(pa_dbus_protocol_add_interface(s->dbus_protocol, s->path, &sample_interface_info, s) >= 0);
49953a5a1b3Sopenharmony_ci
50053a5a1b3Sopenharmony_ci    return s;
50153a5a1b3Sopenharmony_ci}
50253a5a1b3Sopenharmony_ci
50353a5a1b3Sopenharmony_civoid pa_dbusiface_sample_free(pa_dbusiface_sample *s) {
50453a5a1b3Sopenharmony_ci    pa_assert(s);
50553a5a1b3Sopenharmony_ci
50653a5a1b3Sopenharmony_ci    pa_assert_se(pa_dbus_protocol_remove_interface(s->dbus_protocol, s->path, sample_interface_info.name) >= 0);
50753a5a1b3Sopenharmony_ci
50853a5a1b3Sopenharmony_ci    pa_hook_slot_free(s->sample_cache_changed_slot);
50953a5a1b3Sopenharmony_ci    pa_proplist_free(s->proplist);
51053a5a1b3Sopenharmony_ci    pa_dbus_protocol_unref(s->dbus_protocol);
51153a5a1b3Sopenharmony_ci
51253a5a1b3Sopenharmony_ci    pa_xfree(s->path);
51353a5a1b3Sopenharmony_ci    pa_xfree(s);
51453a5a1b3Sopenharmony_ci}
51553a5a1b3Sopenharmony_ci
51653a5a1b3Sopenharmony_ciconst char *pa_dbusiface_sample_get_path(pa_dbusiface_sample *s) {
51753a5a1b3Sopenharmony_ci    pa_assert(s);
51853a5a1b3Sopenharmony_ci
51953a5a1b3Sopenharmony_ci    return s->path;
52053a5a1b3Sopenharmony_ci}
521