1/***
2  This file is part of PulseAudio.
3
4  Copyright 2009 Tanu Kaskinen
5  Copyright 2009 Vincent Filali-Ansary <filali.v@azurdigitalnetworks.net>
6
7  PulseAudio is free software; you can redistribute it and/or modify
8  it under the terms of the GNU Lesser General Public License as published
9  by the Free Software Foundation; either version 2.1 of the License,
10  or (at your option) any later version.
11
12  PulseAudio is distributed in the hope that it will be useful, but
13  WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  General Public License for more details.
16
17  You should have received a copy of the GNU Lesser General Public License
18  along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
19***/
20
21#ifdef HAVE_CONFIG_H
22#include <config.h>
23#endif
24
25#include <pulsecore/core-util.h>
26#include <pulsecore/dbus-util.h>
27#include <pulsecore/protocol-dbus.h>
28
29#include "iface-stream.h"
30
31#define PLAYBACK_OBJECT_NAME "playback_stream"
32#define RECORD_OBJECT_NAME "record_stream"
33
34enum stream_type {
35    STREAM_TYPE_PLAYBACK,
36    STREAM_TYPE_RECORD
37};
38
39struct pa_dbusiface_stream {
40    pa_dbusiface_core *core;
41
42    union {
43        pa_sink_input *sink_input;
44        pa_source_output *source_output;
45    };
46    enum stream_type type;
47    char *path;
48    union {
49        pa_sink *sink;
50        pa_source *source;
51    };
52    uint32_t sample_rate;
53    pa_cvolume volume;
54    dbus_bool_t mute;
55    pa_proplist *proplist;
56
57    bool has_volume;
58
59    pa_dbus_protocol *dbus_protocol;
60    pa_hook_slot *send_event_slot;
61    pa_hook_slot *move_finish_slot;
62    pa_hook_slot *volume_changed_slot;
63    pa_hook_slot *mute_changed_slot;
64    pa_hook_slot *proplist_changed_slot;
65    pa_hook_slot *state_changed_slot;
66};
67
68static void handle_get_index(DBusConnection *conn, DBusMessage *msg, void *userdata);
69static void handle_get_driver(DBusConnection *conn, DBusMessage *msg, void *userdata);
70static void handle_get_owner_module(DBusConnection *conn, DBusMessage *msg, void *userdata);
71static void handle_get_client(DBusConnection *conn, DBusMessage *msg, void *userdata);
72static void handle_get_device(DBusConnection *conn, DBusMessage *msg, void *userdata);
73static void handle_get_sample_format(DBusConnection *conn, DBusMessage *msg, void *userdata);
74static void handle_get_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata);
75static void handle_get_channels(DBusConnection *conn, DBusMessage *msg, void *userdata);
76static void handle_get_volume(DBusConnection *conn, DBusMessage *msg, void *userdata);
77static void handle_set_volume(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata);
78static void handle_get_mute(DBusConnection *conn, DBusMessage *msg, void *userdata);
79static void handle_set_mute(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata);
80static void handle_get_buffer_latency(DBusConnection *conn, DBusMessage *msg, void *userdata);
81static void handle_get_device_latency(DBusConnection *conn, DBusMessage *msg, void *userdata);
82static void handle_get_resample_method(DBusConnection *conn, DBusMessage *msg, void *userdata);
83static void handle_get_property_list(DBusConnection *conn, DBusMessage *msg, void *userdata);
84
85static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata);
86
87static void handle_move(DBusConnection *conn, DBusMessage *msg, void *userdata);
88static void handle_kill(DBusConnection *conn, DBusMessage *msg, void *userdata);
89
90enum property_handler_index {
91    PROPERTY_HANDLER_INDEX,
92    PROPERTY_HANDLER_DRIVER,
93    PROPERTY_HANDLER_OWNER_MODULE,
94    PROPERTY_HANDLER_CLIENT,
95    PROPERTY_HANDLER_DEVICE,
96    PROPERTY_HANDLER_SAMPLE_FORMAT,
97    PROPERTY_HANDLER_SAMPLE_RATE,
98    PROPERTY_HANDLER_CHANNELS,
99    PROPERTY_HANDLER_VOLUME,
100    PROPERTY_HANDLER_MUTE,
101    PROPERTY_HANDLER_BUFFER_LATENCY,
102    PROPERTY_HANDLER_DEVICE_LATENCY,
103    PROPERTY_HANDLER_RESAMPLE_METHOD,
104    PROPERTY_HANDLER_PROPERTY_LIST,
105    PROPERTY_HANDLER_MAX
106};
107
108static pa_dbus_property_handler property_handlers[PROPERTY_HANDLER_MAX] = {
109    [PROPERTY_HANDLER_INDEX]           = { .property_name = "Index",          .type = "u",      .get_cb = handle_get_index,           .set_cb = NULL },
110    [PROPERTY_HANDLER_DRIVER]          = { .property_name = "Driver",         .type = "s",      .get_cb = handle_get_driver,          .set_cb = NULL },
111    [PROPERTY_HANDLER_OWNER_MODULE]    = { .property_name = "OwnerModule",    .type = "o",      .get_cb = handle_get_owner_module,    .set_cb = NULL },
112    [PROPERTY_HANDLER_CLIENT]          = { .property_name = "Client",         .type = "o",      .get_cb = handle_get_client,          .set_cb = NULL },
113    [PROPERTY_HANDLER_DEVICE]          = { .property_name = "Device",         .type = "o",      .get_cb = handle_get_device,          .set_cb = NULL },
114    [PROPERTY_HANDLER_SAMPLE_FORMAT]   = { .property_name = "SampleFormat",   .type = "u",      .get_cb = handle_get_sample_format,   .set_cb = NULL },
115    [PROPERTY_HANDLER_SAMPLE_RATE]     = { .property_name = "SampleRate",     .type = "u",      .get_cb = handle_get_sample_rate,     .set_cb = NULL },
116    [PROPERTY_HANDLER_CHANNELS]        = { .property_name = "Channels",       .type = "au",     .get_cb = handle_get_channels,        .set_cb = NULL },
117    [PROPERTY_HANDLER_VOLUME]          = { .property_name = "Volume",         .type = "au",     .get_cb = handle_get_volume,          .set_cb = handle_set_volume },
118    [PROPERTY_HANDLER_MUTE]            = { .property_name = "Mute",           .type = "b",      .get_cb = handle_get_mute,            .set_cb = handle_set_mute },
119    [PROPERTY_HANDLER_BUFFER_LATENCY]  = { .property_name = "BufferLatency",  .type = "t",      .get_cb = handle_get_buffer_latency,  .set_cb = NULL },
120    [PROPERTY_HANDLER_DEVICE_LATENCY]  = { .property_name = "DeviceLatency",  .type = "t",      .get_cb = handle_get_device_latency,  .set_cb = NULL },
121    [PROPERTY_HANDLER_RESAMPLE_METHOD] = { .property_name = "ResampleMethod", .type = "s",      .get_cb = handle_get_resample_method, .set_cb = NULL },
122    [PROPERTY_HANDLER_PROPERTY_LIST]   = { .property_name = "PropertyList",   .type = "a{say}", .get_cb = handle_get_property_list,   .set_cb = NULL }
123};
124
125enum method_handler_index {
126    METHOD_HANDLER_MOVE,
127    METHOD_HANDLER_KILL,
128    METHOD_HANDLER_MAX
129};
130
131static pa_dbus_arg_info move_args[] = { { "device", "o", "in" } };
132
133static pa_dbus_method_handler method_handlers[METHOD_HANDLER_MAX] = {
134    [METHOD_HANDLER_MOVE] = {
135        .method_name = "Move",
136        .arguments = move_args,
137        .n_arguments = sizeof(move_args) / sizeof(pa_dbus_arg_info),
138        .receive_cb = handle_move },
139    [METHOD_HANDLER_KILL] = {
140        .method_name = "Kill",
141        .arguments = NULL,
142        .n_arguments = 0,
143        .receive_cb = handle_kill }
144};
145
146enum signal_index {
147    SIGNAL_DEVICE_UPDATED,
148    SIGNAL_SAMPLE_RATE_UPDATED,
149    SIGNAL_VOLUME_UPDATED,
150    SIGNAL_MUTE_UPDATED,
151    SIGNAL_PROPERTY_LIST_UPDATED,
152    SIGNAL_STREAM_EVENT,
153    SIGNAL_MAX
154};
155
156static pa_dbus_arg_info device_updated_args[]        = { { "device",        "o",      NULL } };
157static pa_dbus_arg_info sample_rate_updated_args[]   = { { "sample_rate",   "u",      NULL } };
158static pa_dbus_arg_info volume_updated_args[]        = { { "volume",        "au",     NULL } };
159static pa_dbus_arg_info mute_updated_args[]          = { { "muted",         "b",      NULL } };
160static pa_dbus_arg_info property_list_updated_args[] = { { "property_list", "a{say}", NULL } };
161static pa_dbus_arg_info stream_event_args[]          = { { "name",          "s",      NULL }, { "property_list", "a{say}", NULL } };
162
163static pa_dbus_signal_info signals[SIGNAL_MAX] = {
164    [SIGNAL_DEVICE_UPDATED]        = { .name = "DeviceUpdated",       .arguments = device_updated_args,        .n_arguments = 1 },
165    [SIGNAL_SAMPLE_RATE_UPDATED]   = { .name = "SampleRateUpdated",   .arguments = sample_rate_updated_args,   .n_arguments = 1 },
166    [SIGNAL_VOLUME_UPDATED]        = { .name = "VolumeUpdated",       .arguments = volume_updated_args,        .n_arguments = 1 },
167    [SIGNAL_MUTE_UPDATED]          = { .name = "MuteUpdated",         .arguments = mute_updated_args,          .n_arguments = 1 },
168    [SIGNAL_PROPERTY_LIST_UPDATED] = { .name = "PropertyListUpdated", .arguments = property_list_updated_args, .n_arguments = 1 },
169    [SIGNAL_STREAM_EVENT]          = { .name = "StreamEvent",         .arguments = stream_event_args,          .n_arguments = sizeof(stream_event_args) / sizeof(pa_dbus_arg_info) }
170};
171
172static pa_dbus_interface_info stream_interface_info = {
173    .name = PA_DBUSIFACE_STREAM_INTERFACE,
174    .method_handlers = method_handlers,
175    .n_method_handlers = METHOD_HANDLER_MAX,
176    .property_handlers = property_handlers,
177    .n_property_handlers = PROPERTY_HANDLER_MAX,
178    .get_all_properties_cb = handle_get_all,
179    .signals = signals,
180    .n_signals = SIGNAL_MAX
181};
182
183static void handle_get_index(DBusConnection *conn, DBusMessage *msg, void *userdata) {
184    pa_dbusiface_stream *s = userdata;
185    dbus_uint32_t idx;
186
187    pa_assert(conn);
188    pa_assert(msg);
189    pa_assert(s);
190
191    idx = (s->type == STREAM_TYPE_PLAYBACK) ? s->sink_input->index : s->source_output->index;
192
193    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &idx);
194}
195
196/* The returned string has to be freed with pa_xfree() by the caller. */
197static char *stream_to_string(pa_dbusiface_stream *s) {
198    if (s->type == STREAM_TYPE_PLAYBACK)
199        return pa_sprintf_malloc("Playback stream %u", (unsigned) s->sink_input->index);
200    else
201        return pa_sprintf_malloc("Record stream %u", (unsigned) s->source_output->index);
202}
203
204static void handle_get_driver(DBusConnection *conn, DBusMessage *msg, void *userdata) {
205    pa_dbusiface_stream *s = userdata;
206    const char *driver = NULL;
207
208    pa_assert(conn);
209    pa_assert(msg);
210    pa_assert(s);
211
212    driver = (s->type == STREAM_TYPE_PLAYBACK) ? s->sink_input->driver : s->source_output->driver;
213
214    if (!driver) {
215        char *str = stream_to_string(s);
216
217        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "%s doesn't have a driver.", str);
218        pa_xfree(str);
219
220        return;
221    }
222
223    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_STRING, &driver);
224}
225
226static void handle_get_owner_module(DBusConnection *conn, DBusMessage *msg, void *userdata) {
227    pa_dbusiface_stream *s = userdata;
228    pa_module *owner_module = NULL;
229    const char *object_path = NULL;
230
231    pa_assert(conn);
232    pa_assert(msg);
233    pa_assert(s);
234
235    owner_module = (s->type == STREAM_TYPE_PLAYBACK) ? s->sink_input->module : s->source_output->module;
236
237    if (!owner_module) {
238        char *str = stream_to_string(s);
239
240        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "%s doesn't have an owner module.", str);
241        pa_xfree(str);
242
243        return;
244    }
245
246    object_path = pa_dbusiface_core_get_module_path(s->core, owner_module);
247
248    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &object_path);
249}
250
251static void handle_get_client(DBusConnection *conn, DBusMessage *msg, void *userdata) {
252    pa_dbusiface_stream *s = userdata;
253    pa_client *client = NULL;
254    const char *object_path = NULL;
255
256    pa_assert(conn);
257    pa_assert(msg);
258    pa_assert(s);
259
260    client = (s->type == STREAM_TYPE_PLAYBACK) ? s->sink_input->client : s->source_output->client;
261
262    if (!client) {
263        char *str = stream_to_string(s);
264
265        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "%s isn't associated to any client.", str);
266        pa_xfree(str);
267
268        return;
269    }
270
271    object_path = pa_dbusiface_core_get_client_path(s->core, client);
272
273    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &object_path);
274}
275
276static void handle_get_device(DBusConnection *conn, DBusMessage *msg, void *userdata) {
277    pa_dbusiface_stream *s = userdata;
278    const char *device = NULL;
279
280    pa_assert(conn);
281    pa_assert(msg);
282    pa_assert(s);
283
284    if (s->type == STREAM_TYPE_PLAYBACK)
285        device = pa_dbusiface_core_get_sink_path(s->core, s->sink);
286    else
287        device = pa_dbusiface_core_get_source_path(s->core, s->source);
288
289    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &device);
290}
291
292static void handle_get_sample_format(DBusConnection *conn, DBusMessage *msg, void *userdata) {
293    pa_dbusiface_stream *s = userdata;
294    dbus_uint32_t sample_format = 0;
295
296    pa_assert(conn);
297    pa_assert(msg);
298    pa_assert(s);
299
300    sample_format = (s->type == STREAM_TYPE_PLAYBACK)
301                    ? s->sink_input->sample_spec.format
302                    : s->source_output->sample_spec.format;
303
304    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &sample_format);
305}
306
307static void handle_get_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata) {
308    pa_dbusiface_stream *s = userdata;
309
310    pa_assert(conn);
311    pa_assert(msg);
312    pa_assert(s);
313
314    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &s->sample_rate);
315}
316
317static void handle_get_channels(DBusConnection *conn, DBusMessage *msg, void *userdata) {
318    pa_dbusiface_stream *s = userdata;
319    pa_channel_map *channel_map = NULL;
320    dbus_uint32_t channels[PA_CHANNELS_MAX];
321    unsigned i = 0;
322
323    pa_assert(conn);
324    pa_assert(msg);
325    pa_assert(s);
326
327    channel_map = (s->type == STREAM_TYPE_PLAYBACK) ? &s->sink_input->channel_map : &s->source_output->channel_map;
328
329    for (i = 0; i < channel_map->channels; ++i)
330        channels[i] = channel_map->map[i];
331
332    pa_dbus_send_basic_array_variant_reply(conn, msg, DBUS_TYPE_UINT32, channels, channel_map->channels);
333}
334
335static void handle_get_volume(DBusConnection *conn, DBusMessage *msg, void *userdata) {
336    pa_dbusiface_stream *s = userdata;
337    dbus_uint32_t volume[PA_CHANNELS_MAX];
338    unsigned i = 0;
339
340    pa_assert(conn);
341    pa_assert(msg);
342    pa_assert(s);
343
344    if (!s->has_volume) {
345        char *str = stream_to_string(s);
346
347        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "%s doesn't have volume.", str);
348        pa_xfree(str);
349
350        return;
351    }
352
353    for (i = 0; i < s->volume.channels; ++i)
354        volume[i] = s->volume.values[i];
355
356    pa_dbus_send_basic_array_variant_reply(conn, msg, DBUS_TYPE_UINT32, volume, s->volume.channels);
357}
358
359static void handle_set_volume(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata) {
360    pa_dbusiface_stream *s = userdata;
361    bool volume_writable = true;
362    DBusMessageIter array_iter;
363    int stream_channels = 0;
364    dbus_uint32_t *volume = NULL;
365    int n_volume_entries = 0;
366    pa_cvolume new_vol;
367    int i = 0;
368
369    pa_assert(conn);
370    pa_assert(msg);
371    pa_assert(iter);
372    pa_assert(s);
373
374    volume_writable = (s->type == STREAM_TYPE_PLAYBACK) ? s->sink_input->volume_writable : false;
375
376    if (!s->has_volume || !volume_writable) {
377        char *str = stream_to_string(s);
378
379        if (!s->has_volume)
380            pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "%s doesn't have volume.", str);
381        else if (!volume_writable)
382            pa_dbus_send_error(conn, msg, DBUS_ERROR_ACCESS_DENIED, "%s has read-only volume.", str);
383        pa_xfree(str);
384
385        return;
386    }
387
388    stream_channels = s->sink_input->channel_map.channels;
389
390    dbus_message_iter_recurse(iter, &array_iter);
391    dbus_message_iter_get_fixed_array(&array_iter, &volume, &n_volume_entries);
392
393    if (n_volume_entries != stream_channels && n_volume_entries != 1) {
394        pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS,
395                           "Expected %u volume entries, got %u.", stream_channels, n_volume_entries);
396        return;
397    }
398
399    pa_cvolume_init(&new_vol);
400    new_vol.channels = n_volume_entries;
401
402    for (i = 0; i < n_volume_entries; ++i) {
403        if (!PA_VOLUME_IS_VALID(volume[i])) {
404            pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "Invalid volume: %u", volume[i]);
405            return;
406        }
407        new_vol.values[i] = volume[i];
408    }
409
410    pa_sink_input_set_volume(s->sink_input, &new_vol, true, true);
411
412    pa_dbus_send_empty_reply(conn, msg);
413}
414
415static void handle_get_mute(DBusConnection *conn, DBusMessage *msg, void *userdata) {
416    pa_dbusiface_stream *s = userdata;
417
418    pa_assert(conn);
419    pa_assert(msg);
420    pa_assert(s);
421
422    if (s->type == STREAM_TYPE_RECORD) {
423        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "Record streams don't have mute.");
424        return;
425    }
426
427    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_BOOLEAN, &s->mute);
428}
429
430static void handle_set_mute(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata) {
431    pa_dbusiface_stream *s = userdata;
432    dbus_bool_t mute = FALSE;
433
434    pa_assert(conn);
435    pa_assert(msg);
436    pa_assert(iter);
437    pa_assert(s);
438
439    dbus_message_iter_get_basic(iter, &mute);
440
441    if (s->type == STREAM_TYPE_RECORD) {
442        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "Record streams don't have mute.");
443        return;
444    }
445
446    pa_sink_input_set_mute(s->sink_input, mute, true);
447
448    pa_dbus_send_empty_reply(conn, msg);
449}
450
451static void handle_get_buffer_latency(DBusConnection *conn, DBusMessage *msg, void *userdata) {
452    pa_dbusiface_stream *s = userdata;
453    dbus_uint64_t buffer_latency = 0;
454
455    pa_assert(conn);
456    pa_assert(msg);
457    pa_assert(s);
458
459    if (s->type == STREAM_TYPE_PLAYBACK)
460        buffer_latency = pa_sink_input_get_latency(s->sink_input, NULL);
461    else
462        buffer_latency = pa_source_output_get_latency(s->source_output, NULL);
463
464    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT64, &buffer_latency);
465}
466
467static void handle_get_device_latency(DBusConnection *conn, DBusMessage *msg, void *userdata) {
468    pa_dbusiface_stream *s = userdata;
469    dbus_uint64_t device_latency = 0;
470
471    pa_assert(conn);
472    pa_assert(msg);
473    pa_assert(s);
474
475    if (s->type == STREAM_TYPE_PLAYBACK)
476        pa_sink_input_get_latency(s->sink_input, &device_latency);
477    else
478        pa_source_output_get_latency(s->source_output, &device_latency);
479
480    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT64, &device_latency);
481}
482
483static void handle_get_resample_method(DBusConnection *conn, DBusMessage *msg, void *userdata) {
484    pa_dbusiface_stream *s = userdata;
485    const char *resample_method = NULL;
486
487    pa_assert(conn);
488    pa_assert(msg);
489    pa_assert(s);
490
491    if (s->type == STREAM_TYPE_PLAYBACK)
492        resample_method = pa_resample_method_to_string(s->sink_input->actual_resample_method);
493    else
494        resample_method = pa_resample_method_to_string(s->source_output->actual_resample_method);
495
496    if (!resample_method)
497        resample_method = "";
498
499    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_STRING, &resample_method);
500}
501
502static void handle_get_property_list(DBusConnection *conn, DBusMessage *msg, void *userdata) {
503    pa_dbusiface_stream *s = userdata;
504
505    pa_assert(conn);
506    pa_assert(msg);
507    pa_assert(s);
508
509    pa_dbus_send_proplist_variant_reply(conn, msg, s->proplist);
510}
511
512static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata) {
513    pa_dbusiface_stream *s = userdata;
514    DBusMessage *reply = NULL;
515    DBusMessageIter msg_iter;
516    DBusMessageIter dict_iter;
517    dbus_uint32_t idx = 0;
518    const char *driver = NULL;
519    pa_module *owner_module = NULL;
520    const char *owner_module_path = NULL;
521    pa_client *client = NULL;
522    const char *client_path = NULL;
523    const char *device = NULL;
524    dbus_uint32_t sample_format = 0;
525    pa_channel_map *channel_map = NULL;
526    dbus_uint32_t channels[PA_CHANNELS_MAX];
527    dbus_uint32_t volume[PA_CHANNELS_MAX];
528    dbus_uint64_t buffer_latency = 0;
529    dbus_uint64_t device_latency = 0;
530    const char *resample_method = NULL;
531    unsigned i = 0;
532
533    pa_assert(conn);
534    pa_assert(msg);
535    pa_assert(s);
536
537    if (s->has_volume) {
538        for (i = 0; i < s->volume.channels; ++i)
539            volume[i] = s->volume.values[i];
540    }
541
542    if (s->type == STREAM_TYPE_PLAYBACK) {
543        idx = s->sink_input->index;
544        driver = s->sink_input->driver;
545        owner_module = s->sink_input->module;
546        client = s->sink_input->client;
547        device = pa_dbusiface_core_get_sink_path(s->core, s->sink);
548        sample_format = s->sink_input->sample_spec.format;
549        channel_map = &s->sink_input->channel_map;
550        buffer_latency = pa_sink_input_get_latency(s->sink_input, &device_latency);
551        resample_method = pa_resample_method_to_string(s->sink_input->actual_resample_method);
552    } else {
553        idx = s->source_output->index;
554        driver = s->source_output->driver;
555        owner_module = s->source_output->module;
556        client = s->source_output->client;
557        device = pa_dbusiface_core_get_source_path(s->core, s->source);
558        sample_format = s->source_output->sample_spec.format;
559        channel_map = &s->source_output->channel_map;
560        buffer_latency = pa_source_output_get_latency(s->source_output, &device_latency);
561        resample_method = pa_resample_method_to_string(s->source_output->actual_resample_method);
562    }
563    if (owner_module)
564        owner_module_path = pa_dbusiface_core_get_module_path(s->core, owner_module);
565    if (client)
566        client_path = pa_dbusiface_core_get_client_path(s->core, client);
567    for (i = 0; i < channel_map->channels; ++i)
568        channels[i] = channel_map->map[i];
569    if (!resample_method)
570        resample_method = "";
571
572    pa_assert_se((reply = dbus_message_new_method_return(msg)));
573
574    dbus_message_iter_init_append(reply, &msg_iter);
575    pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "{sv}", &dict_iter));
576
577    pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_INDEX].property_name, DBUS_TYPE_UINT32, &idx);
578
579    if (driver)
580        pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_DRIVER].property_name, DBUS_TYPE_STRING, &driver);
581
582    if (owner_module)
583        pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_OWNER_MODULE].property_name, DBUS_TYPE_OBJECT_PATH, &owner_module_path);
584
585    if (client)
586        pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_CLIENT].property_name, DBUS_TYPE_OBJECT_PATH, &client_path);
587
588    pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_DEVICE].property_name, DBUS_TYPE_OBJECT_PATH, &device);
589    pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_SAMPLE_FORMAT].property_name, DBUS_TYPE_UINT32, &sample_format);
590    pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_SAMPLE_RATE].property_name, DBUS_TYPE_UINT32, &s->sample_rate);
591    pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_CHANNELS].property_name, DBUS_TYPE_UINT32, channels, channel_map->channels);
592
593    if (s->has_volume) {
594        pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_VOLUME].property_name, DBUS_TYPE_UINT32, volume, s->volume.channels);
595        pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_MUTE].property_name, DBUS_TYPE_BOOLEAN, &s->mute);
596    }
597
598    pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_BUFFER_LATENCY].property_name, DBUS_TYPE_UINT64, &buffer_latency);
599    pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_DEVICE_LATENCY].property_name, DBUS_TYPE_UINT64, &device_latency);
600    pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_RESAMPLE_METHOD].property_name, DBUS_TYPE_STRING, &resample_method);
601    pa_dbus_append_proplist_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_PROPERTY_LIST].property_name, s->proplist);
602
603    pa_assert_se(dbus_message_iter_close_container(&msg_iter, &dict_iter));
604    pa_assert_se(dbus_connection_send(conn, reply, NULL));
605    dbus_message_unref(reply);
606}
607
608static void handle_move(DBusConnection *conn, DBusMessage *msg, void *userdata) {
609    pa_dbusiface_stream *s = userdata;
610    const char *device = NULL;
611
612    pa_assert(conn);
613    pa_assert(msg);
614    pa_assert(s);
615
616    pa_assert_se(dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &device, DBUS_TYPE_INVALID));
617
618    if (s->type == STREAM_TYPE_PLAYBACK) {
619        pa_sink *sink = pa_dbusiface_core_get_sink(s->core, device);
620
621        if (!sink) {
622            pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NOT_FOUND, "%s: No such sink.", device);
623            return;
624        }
625
626        if (pa_sink_input_move_to(s->sink_input, sink, true) < 0) {
627            pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED,
628                               "Moving playback stream %u to sink %s failed.", s->sink_input->index, sink->name);
629            return;
630        }
631    } else {
632        pa_source *source = pa_dbusiface_core_get_source(s->core, device);
633
634        if (!source) {
635            pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NOT_FOUND, "%s: No such source.", device);
636            return;
637        }
638
639        if (pa_source_output_move_to(s->source_output, source, true) < 0) {
640            pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED,
641                               "Moving record stream %u to source %s failed.", s->source_output->index, source->name);
642            return;
643        }
644    }
645
646    pa_dbus_send_empty_reply(conn, msg);
647}
648
649static void handle_kill(DBusConnection *conn, DBusMessage *msg, void *userdata) {
650    pa_dbusiface_stream *s = userdata;
651
652    pa_assert(conn);
653    pa_assert(msg);
654    pa_assert(s);
655
656    if (s->type == STREAM_TYPE_PLAYBACK)
657        pa_sink_input_kill(s->sink_input);
658    else
659        pa_source_output_kill(s->source_output);
660
661    pa_dbus_send_empty_reply(conn, msg);
662}
663
664static void check_and_signal_rate(pa_dbusiface_stream *s) {
665    DBusMessage *signal_msg = NULL;
666    uint32_t new_sample_rate = 0;
667
668    pa_assert(s);
669
670    new_sample_rate = (s->type == STREAM_TYPE_PLAYBACK)
671                      ? s->sink_input->sample_spec.rate
672                      : s->source_output->sample_spec.rate;
673
674    if (s->sample_rate != new_sample_rate) {
675        s->sample_rate = new_sample_rate;
676
677        pa_assert_se(signal_msg = dbus_message_new_signal(s->path,
678                                                          PA_DBUSIFACE_STREAM_INTERFACE,
679                                                          signals[SIGNAL_SAMPLE_RATE_UPDATED].name));
680        pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_UINT32, &s->sample_rate, DBUS_TYPE_INVALID));
681
682        pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg);
683        dbus_message_unref(signal_msg);
684    }
685}
686
687static pa_hook_result_t move_finish_cb(void *hook_data, void *call_data, void *slot_data) {
688    pa_dbusiface_stream *s = slot_data;
689    const char *new_device_path = NULL;
690    DBusMessage *signal_msg = NULL;
691
692    if ((s->type == STREAM_TYPE_PLAYBACK && s->sink_input != call_data) ||
693        (s->type == STREAM_TYPE_RECORD && s->source_output != call_data))
694        return PA_HOOK_OK;
695
696    if (s->type == STREAM_TYPE_PLAYBACK) {
697        pa_sink *new_sink = s->sink_input->sink;
698
699        if (s->sink != new_sink) {
700            pa_sink_unref(s->sink);
701            s->sink = pa_sink_ref(new_sink);
702
703            new_device_path = pa_dbusiface_core_get_sink_path(s->core, new_sink);
704
705            pa_assert_se(signal_msg = dbus_message_new_signal(s->path,
706                                                              PA_DBUSIFACE_STREAM_INTERFACE,
707                                                              signals[SIGNAL_DEVICE_UPDATED].name));
708            pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &new_device_path, DBUS_TYPE_INVALID));
709
710            pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg);
711            dbus_message_unref(signal_msg);
712        }
713    } else {
714        pa_source *new_source = s->source_output->source;
715
716        if (s->source != new_source) {
717            pa_source_unref(s->source);
718            s->source = pa_source_ref(new_source);
719
720            new_device_path = pa_dbusiface_core_get_source_path(s->core, new_source);
721
722            pa_assert_se(signal_msg = dbus_message_new_signal(s->path,
723                                                              PA_DBUSIFACE_STREAM_INTERFACE,
724                                                              signals[SIGNAL_DEVICE_UPDATED].name));
725            pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &new_device_path, DBUS_TYPE_INVALID));
726
727            pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg);
728            dbus_message_unref(signal_msg);
729        }
730    }
731
732    check_and_signal_rate(s);
733
734    return PA_HOOK_OK;
735}
736
737static pa_hook_result_t volume_changed_cb(void *hook_data, void *call_data, void *slot_data) {
738    pa_dbusiface_stream *s = slot_data;
739    DBusMessage *signal_msg = NULL;
740    unsigned i = 0;
741
742    if ((s->type == STREAM_TYPE_PLAYBACK && s->sink_input != call_data) ||
743        (s->type == STREAM_TYPE_RECORD && s->source_output != call_data))
744        return PA_HOOK_OK;
745
746    if (s->type == STREAM_TYPE_PLAYBACK && s->has_volume) {
747        pa_cvolume new_volume;
748
749        pa_sink_input_get_volume(s->sink_input, &new_volume, true);
750
751        if (!pa_cvolume_equal(&s->volume, &new_volume)) {
752            dbus_uint32_t volume[PA_CHANNELS_MAX];
753            dbus_uint32_t *volume_ptr = volume;
754
755            s->volume = new_volume;
756
757            for (i = 0; i < s->volume.channels; ++i)
758                volume[i] = s->volume.values[i];
759
760            pa_assert_se(signal_msg = dbus_message_new_signal(s->path,
761                                                              PA_DBUSIFACE_STREAM_INTERFACE,
762                                                              signals[SIGNAL_VOLUME_UPDATED].name));
763            pa_assert_se(dbus_message_append_args(signal_msg,
764                                                  DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &volume_ptr, s->volume.channels,
765                                                  DBUS_TYPE_INVALID));
766
767            pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg);
768            dbus_message_unref(signal_msg);
769        }
770    }
771
772    return PA_HOOK_OK;
773}
774
775static pa_hook_result_t mute_changed_cb(void *hook_data, void *call_data, void *slot_data) {
776    pa_dbusiface_stream *s = slot_data;
777    DBusMessage *signal_msg = NULL;
778
779    if ((s->type == STREAM_TYPE_PLAYBACK && s->sink_input != call_data) ||
780        (s->type == STREAM_TYPE_RECORD && s->source_output != call_data))
781        return PA_HOOK_OK;
782
783    if (s->type == STREAM_TYPE_PLAYBACK) {
784        bool new_mute = false;
785
786        new_mute = s->sink_input->muted;
787
788        if (s->mute != new_mute) {
789            s->mute = new_mute;
790
791            pa_assert_se(signal_msg = dbus_message_new_signal(s->path,
792                                                              PA_DBUSIFACE_STREAM_INTERFACE,
793                                                              signals[SIGNAL_MUTE_UPDATED].name));
794            pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_BOOLEAN, &s->mute, DBUS_TYPE_INVALID));
795
796            pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg);
797            dbus_message_unref(signal_msg);
798            signal_msg = NULL;
799        }
800    }
801
802    return PA_HOOK_OK;
803}
804
805static pa_hook_result_t proplist_changed_cb(void *hook_data, void *call_data, void *slot_data) {
806    pa_dbusiface_stream *s = slot_data;
807    DBusMessage *signal_msg = NULL;
808    pa_proplist *new_proplist = NULL;
809
810    if ((s->type == STREAM_TYPE_PLAYBACK && s->sink_input != call_data) ||
811        (s->type == STREAM_TYPE_RECORD && s->source_output != call_data))
812        return PA_HOOK_OK;
813
814    new_proplist = (s->type == STREAM_TYPE_PLAYBACK) ? s->sink_input->proplist : s->source_output->proplist;
815
816    if (!pa_proplist_equal(s->proplist, new_proplist)) {
817        DBusMessageIter msg_iter;
818
819        pa_proplist_update(s->proplist, PA_UPDATE_SET, new_proplist);
820
821        pa_assert_se(signal_msg = dbus_message_new_signal(s->path,
822                                                          PA_DBUSIFACE_STREAM_INTERFACE,
823                                                          signals[SIGNAL_PROPERTY_LIST_UPDATED].name));
824        dbus_message_iter_init_append(signal_msg, &msg_iter);
825        pa_dbus_append_proplist(&msg_iter, s->proplist);
826
827        pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg);
828        dbus_message_unref(signal_msg);
829    }
830
831    return PA_HOOK_OK;
832}
833
834static pa_hook_result_t state_changed_cb(void *hook_data, void *call_data, void *slot_data) {
835    pa_dbusiface_stream *s = slot_data;
836
837    pa_assert(s);
838
839    if ((s->type == STREAM_TYPE_PLAYBACK && s->sink_input != call_data) ||
840        (s->type == STREAM_TYPE_RECORD && s->source_output != call_data))
841        return PA_HOOK_OK;
842
843    check_and_signal_rate(s);
844
845    return PA_HOOK_OK;
846}
847
848static pa_hook_result_t send_event_cb(void *hook_data, void *call_data, void *slot_data) {
849    pa_dbusiface_stream *s = slot_data;
850    DBusMessage *signal_msg = NULL;
851    DBusMessageIter msg_iter;
852    const char *name = NULL;
853    pa_proplist *property_list = NULL;
854
855    pa_assert(call_data);
856    pa_assert(s);
857
858    if (s->type == STREAM_TYPE_PLAYBACK) {
859        pa_sink_input_send_event_hook_data *data = call_data;
860
861        if (data->sink_input != s->sink_input)
862            return PA_HOOK_OK;
863
864        name = data->event;
865        property_list = data->data;
866    } else {
867        pa_source_output_send_event_hook_data *data = call_data;
868
869        if (data->source_output != s->source_output)
870            return PA_HOOK_OK;
871
872        name = data->event;
873        property_list = data->data;
874    }
875
876    pa_assert_se(signal_msg = dbus_message_new_signal(s->path,
877                                                      PA_DBUSIFACE_STREAM_INTERFACE,
878                                                      signals[SIGNAL_STREAM_EVENT].name));
879    dbus_message_iter_init_append(signal_msg, &msg_iter);
880    pa_assert_se(dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &name));
881    pa_dbus_append_proplist(&msg_iter, property_list);
882
883    pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg);
884    dbus_message_unref(signal_msg);
885
886    return PA_HOOK_OK;
887}
888
889pa_dbusiface_stream *pa_dbusiface_stream_new_playback(pa_dbusiface_core *core, pa_sink_input *sink_input) {
890    pa_dbusiface_stream *s;
891
892    pa_assert(core);
893    pa_assert(sink_input);
894
895    s = pa_xnew(pa_dbusiface_stream, 1);
896    s->core = core;
897    s->sink_input = pa_sink_input_ref(sink_input);
898    s->type = STREAM_TYPE_PLAYBACK;
899    s->path = pa_sprintf_malloc("%s/%s%u", PA_DBUS_CORE_OBJECT_PATH, PLAYBACK_OBJECT_NAME, sink_input->index);
900    s->sink = pa_sink_ref(sink_input->sink);
901    s->sample_rate = sink_input->sample_spec.rate;
902    s->has_volume = pa_sink_input_is_volume_readable(sink_input);
903
904    if (s->has_volume)
905        pa_sink_input_get_volume(sink_input, &s->volume, true);
906    else
907        pa_cvolume_init(&s->volume);
908
909    s->mute = sink_input->muted;
910    s->proplist = pa_proplist_copy(sink_input->proplist);
911    s->dbus_protocol = pa_dbus_protocol_get(sink_input->core);
912    s->send_event_slot = pa_hook_connect(&sink_input->core->hooks[PA_CORE_HOOK_SINK_INPUT_SEND_EVENT],
913                                         PA_HOOK_NORMAL,
914                                         send_event_cb,
915                                         s);
916    s->move_finish_slot = pa_hook_connect(&sink_input->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE_FINISH],
917                                          PA_HOOK_NORMAL, move_finish_cb, s);
918    s->volume_changed_slot = pa_hook_connect(&sink_input->core->hooks[PA_CORE_HOOK_SINK_INPUT_VOLUME_CHANGED],
919                                             PA_HOOK_NORMAL, volume_changed_cb, s);
920    s->mute_changed_slot = pa_hook_connect(&sink_input->core->hooks[PA_CORE_HOOK_SINK_INPUT_MUTE_CHANGED],
921                                           PA_HOOK_NORMAL, mute_changed_cb, s);
922    s->proplist_changed_slot = pa_hook_connect(&sink_input->core->hooks[PA_CORE_HOOK_SINK_INPUT_PROPLIST_CHANGED],
923                                               PA_HOOK_NORMAL, proplist_changed_cb, s);
924    s->state_changed_slot = pa_hook_connect(&sink_input->core->hooks[PA_CORE_HOOK_SINK_INPUT_STATE_CHANGED],
925                                            PA_HOOK_NORMAL, state_changed_cb, s);
926
927    pa_assert_se(pa_dbus_protocol_add_interface(s->dbus_protocol, s->path, &stream_interface_info, s) >= 0);
928
929    return s;
930}
931
932pa_dbusiface_stream *pa_dbusiface_stream_new_record(pa_dbusiface_core *core, pa_source_output *source_output) {
933    pa_dbusiface_stream *s;
934
935    pa_assert(core);
936    pa_assert(source_output);
937
938    s = pa_xnew(pa_dbusiface_stream, 1);
939    s->core = core;
940    s->source_output = pa_source_output_ref(source_output);
941    s->type = STREAM_TYPE_RECORD;
942    s->path = pa_sprintf_malloc("%s/%s%u", PA_DBUS_CORE_OBJECT_PATH, RECORD_OBJECT_NAME, source_output->index);
943    s->source = pa_source_ref(source_output->source);
944    s->sample_rate = source_output->sample_spec.rate;
945    pa_cvolume_init(&s->volume);
946    s->mute = false;
947    s->proplist = pa_proplist_copy(source_output->proplist);
948    s->has_volume = false;
949    s->dbus_protocol = pa_dbus_protocol_get(source_output->core);
950    s->send_event_slot = pa_hook_connect(&source_output->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_SEND_EVENT],
951                                         PA_HOOK_NORMAL,
952                                         send_event_cb,
953                                         s);
954    s->move_finish_slot = pa_hook_connect(&source_output->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_FINISH],
955                                          PA_HOOK_NORMAL, move_finish_cb, s);
956    s->volume_changed_slot = pa_hook_connect(&source_output->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_VOLUME_CHANGED],
957                                             PA_HOOK_NORMAL, volume_changed_cb, s);
958    s->mute_changed_slot = pa_hook_connect(&source_output->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MUTE_CHANGED],
959                                           PA_HOOK_NORMAL, mute_changed_cb, s);
960    s->proplist_changed_slot = pa_hook_connect(&source_output->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PROPLIST_CHANGED],
961                                               PA_HOOK_NORMAL, proplist_changed_cb, s);
962    s->state_changed_slot = pa_hook_connect(&source_output->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_STATE_CHANGED],
963                                            PA_HOOK_NORMAL, state_changed_cb, s);
964
965    pa_assert_se(pa_dbus_protocol_add_interface(s->dbus_protocol, s->path, &stream_interface_info, s) >= 0);
966
967    return s;
968}
969
970void pa_dbusiface_stream_free(pa_dbusiface_stream *s) {
971    pa_assert(s);
972
973    pa_assert_se(pa_dbus_protocol_remove_interface(s->dbus_protocol, s->path, stream_interface_info.name) >= 0);
974
975    if (s->type == STREAM_TYPE_PLAYBACK) {
976        pa_sink_input_unref(s->sink_input);
977        pa_sink_unref(s->sink);
978    } else {
979        pa_source_output_unref(s->source_output);
980        pa_source_unref(s->source);
981    }
982
983    pa_proplist_free(s->proplist);
984    pa_dbus_protocol_unref(s->dbus_protocol);
985    pa_hook_slot_free(s->send_event_slot);
986    pa_hook_slot_free(s->move_finish_slot);
987    pa_hook_slot_free(s->volume_changed_slot);
988    pa_hook_slot_free(s->mute_changed_slot);
989    pa_hook_slot_free(s->proplist_changed_slot);
990    pa_hook_slot_free(s->state_changed_slot);
991
992    pa_xfree(s->path);
993    pa_xfree(s);
994}
995
996const char *pa_dbusiface_stream_get_path(pa_dbusiface_stream *s) {
997    pa_assert(s);
998
999    return s->path;
1000}
1001