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