]> code.delx.au - pulseaudio/blob - src/modules/dbus/iface-stream.c
Merge remote-tracking branch 'mkbosmans/mingw32-build'
[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 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_STRING, &resample_method);
494 }
495
496 static void handle_get_property_list(DBusConnection *conn, DBusMessage *msg, void *userdata) {
497 pa_dbusiface_stream *s = userdata;
498
499 pa_assert(conn);
500 pa_assert(msg);
501 pa_assert(s);
502
503 pa_dbus_send_proplist_variant_reply(conn, msg, s->proplist);
504 }
505
506 static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata) {
507 pa_dbusiface_stream *s = userdata;
508 DBusMessage *reply = NULL;
509 DBusMessageIter msg_iter;
510 DBusMessageIter dict_iter;
511 dbus_uint32_t idx = 0;
512 const char *driver = NULL;
513 pa_module *owner_module = NULL;
514 const char *owner_module_path = NULL;
515 pa_client *client = NULL;
516 const char *client_path = NULL;
517 const char *device = NULL;
518 dbus_uint32_t sample_format = 0;
519 pa_channel_map *channel_map = NULL;
520 dbus_uint32_t channels[PA_CHANNELS_MAX];
521 dbus_uint32_t volume[PA_CHANNELS_MAX];
522 dbus_uint64_t buffer_latency = 0;
523 dbus_uint64_t device_latency = 0;
524 const char *resample_method = NULL;
525 unsigned i = 0;
526
527 pa_assert(conn);
528 pa_assert(msg);
529 pa_assert(s);
530
531 if (s->has_volume) {
532 for (i = 0; i < s->volume.channels; ++i)
533 volume[i] = s->volume.values[i];
534 }
535
536 if (s->type == STREAM_TYPE_PLAYBACK) {
537 idx = s->sink_input->index;
538 driver = s->sink_input->driver;
539 owner_module = s->sink_input->module;
540 client = s->sink_input->client;
541 device = pa_dbusiface_core_get_sink_path(s->core, s->sink);
542 sample_format = s->sink_input->sample_spec.format;
543 channel_map = &s->sink_input->channel_map;
544 buffer_latency = pa_sink_input_get_latency(s->sink_input, &device_latency);
545 resample_method = pa_resample_method_to_string(s->sink_input->actual_resample_method);
546 } else {
547 idx = s->source_output->index;
548 driver = s->source_output->driver;
549 owner_module = s->source_output->module;
550 client = s->source_output->client;
551 device = pa_dbusiface_core_get_source_path(s->core, s->source);
552 sample_format = s->source_output->sample_spec.format;
553 channel_map = &s->source_output->channel_map;
554 buffer_latency = pa_source_output_get_latency(s->source_output, &device_latency);
555 resample_method = pa_resample_method_to_string(s->source_output->actual_resample_method);
556 }
557 if (owner_module)
558 owner_module_path = pa_dbusiface_core_get_module_path(s->core, owner_module);
559 if (client)
560 client_path = pa_dbusiface_core_get_client_path(s->core, client);
561 for (i = 0; i < channel_map->channels; ++i)
562 channels[i] = channel_map->map[i];
563
564 pa_assert_se((reply = dbus_message_new_method_return(msg)));
565
566 dbus_message_iter_init_append(reply, &msg_iter);
567 pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "{sv}", &dict_iter));
568
569 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_INDEX].property_name, DBUS_TYPE_UINT32, &idx);
570
571 if (driver)
572 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_DRIVER].property_name, DBUS_TYPE_STRING, &driver);
573
574 if (owner_module)
575 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_OWNER_MODULE].property_name, DBUS_TYPE_OBJECT_PATH, &owner_module_path);
576
577 if (client)
578 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_CLIENT].property_name, DBUS_TYPE_OBJECT_PATH, &client_path);
579
580 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_DEVICE].property_name, DBUS_TYPE_OBJECT_PATH, &device);
581 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_SAMPLE_FORMAT].property_name, DBUS_TYPE_UINT32, &sample_format);
582 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_SAMPLE_RATE].property_name, DBUS_TYPE_UINT32, &s->sample_rate);
583 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_CHANNELS].property_name, DBUS_TYPE_UINT32, channels, channel_map->channels);
584
585 if (s->has_volume) {
586 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_VOLUME].property_name, DBUS_TYPE_UINT32, volume, s->volume.channels);
587 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_MUTE].property_name, DBUS_TYPE_BOOLEAN, &s->mute);
588 }
589
590 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_BUFFER_LATENCY].property_name, DBUS_TYPE_UINT64, &buffer_latency);
591 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_DEVICE_LATENCY].property_name, DBUS_TYPE_UINT64, &device_latency);
592 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_RESAMPLE_METHOD].property_name, DBUS_TYPE_STRING, &resample_method);
593 pa_dbus_append_proplist_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_PROPERTY_LIST].property_name, s->proplist);
594
595 pa_assert_se(dbus_message_iter_close_container(&msg_iter, &dict_iter));
596 pa_assert_se(dbus_connection_send(conn, reply, NULL));
597 dbus_message_unref(reply);
598 }
599
600 static void handle_move(DBusConnection *conn, DBusMessage *msg, void *userdata) {
601 pa_dbusiface_stream *s = userdata;
602 const char *device = NULL;
603
604 pa_assert(conn);
605 pa_assert(msg);
606 pa_assert(s);
607
608 pa_assert_se(dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &device, DBUS_TYPE_INVALID));
609
610 if (s->type == STREAM_TYPE_PLAYBACK) {
611 pa_sink *sink = pa_dbusiface_core_get_sink(s->core, device);
612
613 if (!sink) {
614 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NOT_FOUND, "%s: No such sink.", device);
615 return;
616 }
617
618 if (pa_sink_input_move_to(s->sink_input, sink, TRUE) < 0) {
619 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED,
620 "Moving playback stream %u to sink %s failed.", s->sink_input->index, sink->name);
621 return;
622 }
623 } else {
624 pa_source *source = pa_dbusiface_core_get_source(s->core, device);
625
626 if (!source) {
627 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NOT_FOUND, "%s: No such source.", device);
628 return;
629 }
630
631 if (pa_source_output_move_to(s->source_output, source, TRUE) < 0) {
632 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED,
633 "Moving record stream %u to source %s failed.", s->source_output->index, source->name);
634 return;
635 }
636 }
637
638 pa_dbus_send_empty_reply(conn, msg);
639 }
640
641 static void handle_kill(DBusConnection *conn, DBusMessage *msg, void *userdata) {
642 pa_dbusiface_stream *s = userdata;
643
644 pa_assert(conn);
645 pa_assert(msg);
646 pa_assert(s);
647
648 if (s->type == STREAM_TYPE_PLAYBACK)
649 pa_sink_input_kill(s->sink_input);
650 else
651 pa_source_output_kill(s->source_output);
652
653 pa_dbus_send_empty_reply(conn, msg);
654 }
655
656 static void subscription_cb(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) {
657 pa_dbusiface_stream *s = userdata;
658 DBusMessage *signal_msg = NULL;
659 const char *new_device_path = NULL;
660 uint32_t new_sample_rate = 0;
661 pa_proplist *new_proplist = NULL;
662 unsigned i = 0;
663
664 pa_assert(c);
665 pa_assert(s);
666
667 if ((s->type == STREAM_TYPE_PLAYBACK && idx != s->sink_input->index)
668 || (s->type == STREAM_TYPE_RECORD && idx != s->source_output->index))
669 return;
670
671 if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) != PA_SUBSCRIPTION_EVENT_CHANGE)
672 return;
673
674 pa_assert(((s->type == STREAM_TYPE_PLAYBACK)
675 && ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK_INPUT))
676 || ((s->type == STREAM_TYPE_RECORD)
677 && ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT)));
678
679 if (s->type == STREAM_TYPE_PLAYBACK) {
680 pa_sink *new_sink = s->sink_input->sink;
681
682 if (s->sink != new_sink) {
683 pa_sink_unref(s->sink);
684 s->sink = pa_sink_ref(new_sink);
685
686 new_device_path = pa_dbusiface_core_get_sink_path(s->core, new_sink);
687
688 pa_assert_se(signal_msg = dbus_message_new_signal(s->path,
689 PA_DBUSIFACE_STREAM_INTERFACE,
690 signals[SIGNAL_DEVICE_UPDATED].name));
691 pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &new_device_path, DBUS_TYPE_INVALID));
692
693 pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg);
694 dbus_message_unref(signal_msg);
695 signal_msg = NULL;
696 }
697 } else {
698 pa_source *new_source = s->source_output->source;
699
700 if (s->source != new_source) {
701 pa_source_unref(s->source);
702 s->source = pa_source_ref(new_source);
703
704 new_device_path = pa_dbusiface_core_get_source_path(s->core, new_source);
705
706 pa_assert_se(signal_msg = dbus_message_new_signal(s->path,
707 PA_DBUSIFACE_STREAM_INTERFACE,
708 signals[SIGNAL_DEVICE_UPDATED].name));
709 pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &new_device_path, DBUS_TYPE_INVALID));
710
711 pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg);
712 dbus_message_unref(signal_msg);
713 signal_msg = NULL;
714 }
715 }
716
717 new_sample_rate = (s->type == STREAM_TYPE_PLAYBACK) ? s->sink_input->sample_spec.rate : s->source_output->sample_spec.rate;
718
719 if (s->sample_rate != new_sample_rate) {
720 s->sample_rate = new_sample_rate;
721
722 pa_assert_se(signal_msg = dbus_message_new_signal(s->path,
723 PA_DBUSIFACE_STREAM_INTERFACE,
724 signals[SIGNAL_SAMPLE_RATE_UPDATED].name));
725 pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_UINT32, &s->sample_rate, DBUS_TYPE_INVALID));
726
727 pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg);
728 dbus_message_unref(signal_msg);
729 signal_msg = NULL;
730 }
731
732 if (s->type == STREAM_TYPE_PLAYBACK) {
733 pa_bool_t new_mute = FALSE;
734
735 if (s->has_volume) {
736 pa_cvolume new_volume;
737
738 pa_sink_input_get_volume(s->sink_input, &new_volume, TRUE);
739
740 if (!pa_cvolume_equal(&s->volume, &new_volume)) {
741 dbus_uint32_t volume[PA_CHANNELS_MAX];
742 dbus_uint32_t *volume_ptr = volume;
743
744 s->volume = new_volume;
745
746 for (i = 0; i < s->volume.channels; ++i)
747 volume[i] = s->volume.values[i];
748
749 pa_assert_se(signal_msg = dbus_message_new_signal(s->path,
750 PA_DBUSIFACE_STREAM_INTERFACE,
751 signals[SIGNAL_VOLUME_UPDATED].name));
752 pa_assert_se(dbus_message_append_args(signal_msg,
753 DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &volume_ptr, s->volume.channels,
754 DBUS_TYPE_INVALID));
755
756 pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg);
757 dbus_message_unref(signal_msg);
758 signal_msg = NULL;
759 }
760 }
761
762 new_mute = pa_sink_input_get_mute(s->sink_input);
763
764 if (s->mute != new_mute) {
765 s->mute = new_mute;
766
767 pa_assert_se(signal_msg = dbus_message_new_signal(s->path,
768 PA_DBUSIFACE_STREAM_INTERFACE,
769 signals[SIGNAL_MUTE_UPDATED].name));
770 pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_BOOLEAN, &s->mute, DBUS_TYPE_INVALID));
771
772 pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg);
773 dbus_message_unref(signal_msg);
774 signal_msg = NULL;
775 }
776 }
777
778 new_proplist = (s->type == STREAM_TYPE_PLAYBACK) ? s->sink_input->proplist : s->source_output->proplist;
779
780 if (!pa_proplist_equal(s->proplist, new_proplist)) {
781 DBusMessageIter msg_iter;
782
783 pa_proplist_update(s->proplist, PA_UPDATE_SET, new_proplist);
784
785 pa_assert_se(signal_msg = dbus_message_new_signal(s->path,
786 PA_DBUSIFACE_STREAM_INTERFACE,
787 signals[SIGNAL_PROPERTY_LIST_UPDATED].name));
788 dbus_message_iter_init_append(signal_msg, &msg_iter);
789 pa_dbus_append_proplist(&msg_iter, s->proplist);
790
791 pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg);
792 dbus_message_unref(signal_msg);
793 signal_msg = NULL;
794 }
795 }
796
797 static pa_hook_result_t send_event_cb(void *hook_data, void *call_data, void *slot_data) {
798 pa_dbusiface_stream *s = slot_data;
799 DBusMessage *signal_msg = NULL;
800 DBusMessageIter msg_iter;
801 const char *name = NULL;
802 pa_proplist *property_list = NULL;
803
804 pa_assert(call_data);
805 pa_assert(s);
806
807 if (s->type == STREAM_TYPE_PLAYBACK) {
808 pa_sink_input_send_event_hook_data *data = call_data;
809
810 if (data->sink_input != s->sink_input)
811 return PA_HOOK_OK;
812
813 name = data->event;
814 property_list = data->data;
815 } else {
816 pa_source_output_send_event_hook_data *data = call_data;
817
818 if (data->source_output != s->source_output)
819 return PA_HOOK_OK;
820
821 name = data->event;
822 property_list = data->data;
823 }
824
825 pa_assert_se(signal_msg = dbus_message_new_signal(s->path,
826 PA_DBUSIFACE_STREAM_INTERFACE,
827 signals[SIGNAL_STREAM_EVENT].name));
828 dbus_message_iter_init_append(signal_msg, &msg_iter);
829 pa_assert_se(dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &name));
830 pa_dbus_append_proplist(&msg_iter, property_list);
831
832 pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg);
833 dbus_message_unref(signal_msg);
834
835 return PA_HOOK_OK;
836 }
837
838 pa_dbusiface_stream *pa_dbusiface_stream_new_playback(pa_dbusiface_core *core, pa_sink_input *sink_input) {
839 pa_dbusiface_stream *s;
840
841 pa_assert(core);
842 pa_assert(sink_input);
843
844 s = pa_xnew(pa_dbusiface_stream, 1);
845 s->core = core;
846 s->sink_input = pa_sink_input_ref(sink_input);
847 s->type = STREAM_TYPE_PLAYBACK;
848 s->path = pa_sprintf_malloc("%s/%s%u", PA_DBUS_CORE_OBJECT_PATH, PLAYBACK_OBJECT_NAME, sink_input->index);
849 s->sink = pa_sink_ref(sink_input->sink);
850 s->sample_rate = sink_input->sample_spec.rate;
851 s->has_volume = pa_sink_input_is_volume_readable(sink_input);
852 s->read_only_volume = s->has_volume ? !pa_sink_input_is_volume_writable(sink_input) : FALSE;
853
854 if (s->has_volume)
855 pa_sink_input_get_volume(sink_input, &s->volume, TRUE);
856 else
857 pa_cvolume_init(&s->volume);
858
859 s->mute = pa_sink_input_get_mute(sink_input);
860 s->proplist = pa_proplist_copy(sink_input->proplist);
861 s->dbus_protocol = pa_dbus_protocol_get(sink_input->core);
862 s->subscription = pa_subscription_new(sink_input->core, PA_SUBSCRIPTION_MASK_SINK_INPUT, subscription_cb, s);
863 s->send_event_slot = pa_hook_connect(&sink_input->core->hooks[PA_CORE_HOOK_SINK_INPUT_SEND_EVENT],
864 PA_HOOK_NORMAL,
865 send_event_cb,
866 s);
867
868 pa_assert_se(pa_dbus_protocol_add_interface(s->dbus_protocol, s->path, &stream_interface_info, s) >= 0);
869
870 return s;
871 }
872
873 pa_dbusiface_stream *pa_dbusiface_stream_new_record(pa_dbusiface_core *core, pa_source_output *source_output) {
874 pa_dbusiface_stream *s;
875
876 pa_assert(core);
877 pa_assert(source_output);
878
879 s = pa_xnew(pa_dbusiface_stream, 1);
880 s->core = core;
881 s->source_output = pa_source_output_ref(source_output);
882 s->type = STREAM_TYPE_RECORD;
883 s->path = pa_sprintf_malloc("%s/%s%u", PA_DBUS_CORE_OBJECT_PATH, RECORD_OBJECT_NAME, source_output->index);
884 s->source = pa_source_ref(source_output->source);
885 s->sample_rate = source_output->sample_spec.rate;
886 pa_cvolume_init(&s->volume);
887 s->mute = FALSE;
888 s->proplist = pa_proplist_copy(source_output->proplist);
889 s->has_volume = FALSE;
890 s->read_only_volume = FALSE;
891 s->dbus_protocol = pa_dbus_protocol_get(source_output->core);
892 s->subscription = pa_subscription_new(source_output->core, PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT, subscription_cb, s);
893 s->send_event_slot = pa_hook_connect(&source_output->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_SEND_EVENT],
894 PA_HOOK_NORMAL,
895 send_event_cb,
896 s);
897
898 pa_assert_se(pa_dbus_protocol_add_interface(s->dbus_protocol, s->path, &stream_interface_info, s) >= 0);
899
900 return s;
901 }
902
903 void pa_dbusiface_stream_free(pa_dbusiface_stream *s) {
904 pa_assert(s);
905
906 pa_assert_se(pa_dbus_protocol_remove_interface(s->dbus_protocol, s->path, stream_interface_info.name) >= 0);
907
908 if (s->type == STREAM_TYPE_PLAYBACK) {
909 pa_sink_input_unref(s->sink_input);
910 pa_sink_unref(s->sink);
911 } else {
912 pa_source_output_unref(s->source_output);
913 pa_source_unref(s->source);
914 }
915
916 pa_proplist_free(s->proplist);
917 pa_dbus_protocol_unref(s->dbus_protocol);
918 pa_subscription_free(s->subscription);
919 pa_hook_slot_free(s->send_event_slot);
920
921 pa_xfree(s->path);
922 pa_xfree(s);
923 }
924
925 const char *pa_dbusiface_stream_get_path(pa_dbusiface_stream *s) {
926 pa_assert(s);
927
928 return s->path;
929 }