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