]> code.delx.au - pulseaudio/blob - src/modules/dbus/iface-stream.c
1cff95e0c3fb7694dca78c72c45582cc6f72813c
[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 bool 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 bool 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 bool 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 }