]> 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 stream_channels = s->sink_input->channel_map.channels;
385
386 dbus_message_iter_recurse(iter, &array_iter);
387 dbus_message_iter_get_fixed_array(&array_iter, &volume, &n_volume_entries);
388
389 if (n_volume_entries != stream_channels && n_volume_entries != 1) {
390 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS,
391 "Expected %u volume entries, got %u.", stream_channels, n_volume_entries);
392 return;
393 }
394
395 pa_cvolume_init(&new_vol);
396 new_vol.channels = n_volume_entries;
397
398 for (i = 0; i < n_volume_entries; ++i) {
399 if (!PA_VOLUME_IS_VALID(volume[i])) {
400 pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "Invalid volume: %u", volume[i]);
401 return;
402 }
403 new_vol.values[i] = volume[i];
404 }
405
406 pa_sink_input_set_volume(s->sink_input, &new_vol, TRUE, TRUE);
407
408 pa_dbus_send_empty_reply(conn, msg);
409 }
410
411 static void handle_get_mute(DBusConnection *conn, DBusMessage *msg, void *userdata) {
412 pa_dbusiface_stream *s = userdata;
413
414 pa_assert(conn);
415 pa_assert(msg);
416 pa_assert(s);
417
418 if (s->type == STREAM_TYPE_RECORD) {
419 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "Record streams don't have mute.");
420 return;
421 }
422
423 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_BOOLEAN, &s->mute);
424 }
425
426 static void handle_set_mute(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata) {
427 pa_dbusiface_stream *s = userdata;
428 dbus_bool_t mute = FALSE;
429
430 pa_assert(conn);
431 pa_assert(msg);
432 pa_assert(iter);
433 pa_assert(s);
434
435 dbus_message_iter_get_basic(iter, &mute);
436
437 if (s->type == STREAM_TYPE_RECORD) {
438 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "Record streams don't have mute.");
439 return;
440 }
441
442 pa_sink_input_set_mute(s->sink_input, mute, TRUE);
443
444 pa_dbus_send_empty_reply(conn, msg);
445 };
446
447 static void handle_get_buffer_latency(DBusConnection *conn, DBusMessage *msg, void *userdata) {
448 pa_dbusiface_stream *s = userdata;
449 dbus_uint64_t buffer_latency = 0;
450
451 pa_assert(conn);
452 pa_assert(msg);
453 pa_assert(s);
454
455 if (s->type == STREAM_TYPE_PLAYBACK)
456 buffer_latency = pa_sink_input_get_latency(s->sink_input, NULL);
457 else
458 buffer_latency = pa_source_output_get_latency(s->source_output, NULL);
459
460 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT64, &buffer_latency);
461 }
462
463 static void handle_get_device_latency(DBusConnection *conn, DBusMessage *msg, void *userdata) {
464 pa_dbusiface_stream *s = userdata;
465 dbus_uint64_t device_latency = 0;
466
467 pa_assert(conn);
468 pa_assert(msg);
469 pa_assert(s);
470
471 if (s->type == STREAM_TYPE_PLAYBACK)
472 pa_sink_input_get_latency(s->sink_input, &device_latency);
473 else
474 pa_source_output_get_latency(s->source_output, &device_latency);
475
476 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT64, &device_latency);
477 }
478
479 static void handle_get_resample_method(DBusConnection *conn, DBusMessage *msg, void *userdata) {
480 pa_dbusiface_stream *s = userdata;
481 const char *resample_method = NULL;
482
483 pa_assert(conn);
484 pa_assert(msg);
485 pa_assert(s);
486
487 if (s->type == STREAM_TYPE_PLAYBACK)
488 resample_method = pa_resample_method_to_string(s->sink_input->actual_resample_method);
489 else
490 resample_method = pa_resample_method_to_string(s->source_output->actual_resample_method);
491
492 if (!resample_method)
493 resample_method = "";
494
495 pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_STRING, &resample_method);
496 }
497
498 static void handle_get_property_list(DBusConnection *conn, DBusMessage *msg, void *userdata) {
499 pa_dbusiface_stream *s = userdata;
500
501 pa_assert(conn);
502 pa_assert(msg);
503 pa_assert(s);
504
505 pa_dbus_send_proplist_variant_reply(conn, msg, s->proplist);
506 }
507
508 static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata) {
509 pa_dbusiface_stream *s = userdata;
510 DBusMessage *reply = NULL;
511 DBusMessageIter msg_iter;
512 DBusMessageIter dict_iter;
513 dbus_uint32_t idx = 0;
514 const char *driver = NULL;
515 pa_module *owner_module = NULL;
516 const char *owner_module_path = NULL;
517 pa_client *client = NULL;
518 const char *client_path = NULL;
519 const char *device = NULL;
520 dbus_uint32_t sample_format = 0;
521 pa_channel_map *channel_map = NULL;
522 dbus_uint32_t channels[PA_CHANNELS_MAX];
523 dbus_uint32_t volume[PA_CHANNELS_MAX];
524 dbus_uint64_t buffer_latency = 0;
525 dbus_uint64_t device_latency = 0;
526 const char *resample_method = NULL;
527 unsigned i = 0;
528
529 pa_assert(conn);
530 pa_assert(msg);
531 pa_assert(s);
532
533 if (s->has_volume) {
534 for (i = 0; i < s->volume.channels; ++i)
535 volume[i] = s->volume.values[i];
536 }
537
538 if (s->type == STREAM_TYPE_PLAYBACK) {
539 idx = s->sink_input->index;
540 driver = s->sink_input->driver;
541 owner_module = s->sink_input->module;
542 client = s->sink_input->client;
543 device = pa_dbusiface_core_get_sink_path(s->core, s->sink);
544 sample_format = s->sink_input->sample_spec.format;
545 channel_map = &s->sink_input->channel_map;
546 buffer_latency = pa_sink_input_get_latency(s->sink_input, &device_latency);
547 resample_method = pa_resample_method_to_string(s->sink_input->actual_resample_method);
548 } else {
549 idx = s->source_output->index;
550 driver = s->source_output->driver;
551 owner_module = s->source_output->module;
552 client = s->source_output->client;
553 device = pa_dbusiface_core_get_source_path(s->core, s->source);
554 sample_format = s->source_output->sample_spec.format;
555 channel_map = &s->source_output->channel_map;
556 buffer_latency = pa_source_output_get_latency(s->source_output, &device_latency);
557 resample_method = pa_resample_method_to_string(s->source_output->actual_resample_method);
558 }
559 if (owner_module)
560 owner_module_path = pa_dbusiface_core_get_module_path(s->core, owner_module);
561 if (client)
562 client_path = pa_dbusiface_core_get_client_path(s->core, client);
563 for (i = 0; i < channel_map->channels; ++i)
564 channels[i] = channel_map->map[i];
565 if (!resample_method)
566 resample_method = "";
567
568 pa_assert_se((reply = dbus_message_new_method_return(msg)));
569
570 dbus_message_iter_init_append(reply, &msg_iter);
571 pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "{sv}", &dict_iter));
572
573 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_INDEX].property_name, DBUS_TYPE_UINT32, &idx);
574
575 if (driver)
576 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_DRIVER].property_name, DBUS_TYPE_STRING, &driver);
577
578 if (owner_module)
579 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_OWNER_MODULE].property_name, DBUS_TYPE_OBJECT_PATH, &owner_module_path);
580
581 if (client)
582 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_CLIENT].property_name, DBUS_TYPE_OBJECT_PATH, &client_path);
583
584 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_DEVICE].property_name, DBUS_TYPE_OBJECT_PATH, &device);
585 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_SAMPLE_FORMAT].property_name, DBUS_TYPE_UINT32, &sample_format);
586 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_SAMPLE_RATE].property_name, DBUS_TYPE_UINT32, &s->sample_rate);
587 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_CHANNELS].property_name, DBUS_TYPE_UINT32, channels, channel_map->channels);
588
589 if (s->has_volume) {
590 pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_VOLUME].property_name, DBUS_TYPE_UINT32, volume, s->volume.channels);
591 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_MUTE].property_name, DBUS_TYPE_BOOLEAN, &s->mute);
592 }
593
594 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_BUFFER_LATENCY].property_name, DBUS_TYPE_UINT64, &buffer_latency);
595 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_DEVICE_LATENCY].property_name, DBUS_TYPE_UINT64, &device_latency);
596 pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_RESAMPLE_METHOD].property_name, DBUS_TYPE_STRING, &resample_method);
597 pa_dbus_append_proplist_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_PROPERTY_LIST].property_name, s->proplist);
598
599 pa_assert_se(dbus_message_iter_close_container(&msg_iter, &dict_iter));
600 pa_assert_se(dbus_connection_send(conn, reply, NULL));
601 dbus_message_unref(reply);
602 }
603
604 static void handle_move(DBusConnection *conn, DBusMessage *msg, void *userdata) {
605 pa_dbusiface_stream *s = userdata;
606 const char *device = NULL;
607
608 pa_assert(conn);
609 pa_assert(msg);
610 pa_assert(s);
611
612 pa_assert_se(dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &device, DBUS_TYPE_INVALID));
613
614 if (s->type == STREAM_TYPE_PLAYBACK) {
615 pa_sink *sink = pa_dbusiface_core_get_sink(s->core, device);
616
617 if (!sink) {
618 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NOT_FOUND, "%s: No such sink.", device);
619 return;
620 }
621
622 if (pa_sink_input_move_to(s->sink_input, sink, TRUE) < 0) {
623 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED,
624 "Moving playback stream %u to sink %s failed.", s->sink_input->index, sink->name);
625 return;
626 }
627 } else {
628 pa_source *source = pa_dbusiface_core_get_source(s->core, device);
629
630 if (!source) {
631 pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NOT_FOUND, "%s: No such source.", device);
632 return;
633 }
634
635 if (pa_source_output_move_to(s->source_output, source, TRUE) < 0) {
636 pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED,
637 "Moving record stream %u to source %s failed.", s->source_output->index, source->name);
638 return;
639 }
640 }
641
642 pa_dbus_send_empty_reply(conn, msg);
643 }
644
645 static void handle_kill(DBusConnection *conn, DBusMessage *msg, void *userdata) {
646 pa_dbusiface_stream *s = userdata;
647
648 pa_assert(conn);
649 pa_assert(msg);
650 pa_assert(s);
651
652 if (s->type == STREAM_TYPE_PLAYBACK)
653 pa_sink_input_kill(s->sink_input);
654 else
655 pa_source_output_kill(s->source_output);
656
657 pa_dbus_send_empty_reply(conn, msg);
658 }
659
660 static void subscription_cb(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) {
661 pa_dbusiface_stream *s = userdata;
662 DBusMessage *signal_msg = NULL;
663 const char *new_device_path = NULL;
664 uint32_t new_sample_rate = 0;
665 pa_proplist *new_proplist = NULL;
666 unsigned i = 0;
667
668 pa_assert(c);
669 pa_assert(s);
670
671 if ((s->type == STREAM_TYPE_PLAYBACK && idx != s->sink_input->index)
672 || (s->type == STREAM_TYPE_RECORD && idx != s->source_output->index))
673 return;
674
675 if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) != PA_SUBSCRIPTION_EVENT_CHANGE)
676 return;
677
678 pa_assert(((s->type == STREAM_TYPE_PLAYBACK)
679 && ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK_INPUT))
680 || ((s->type == STREAM_TYPE_RECORD)
681 && ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT)));
682
683 if (s->type == STREAM_TYPE_PLAYBACK) {
684 pa_sink *new_sink = s->sink_input->sink;
685
686 if (s->sink != new_sink) {
687 pa_sink_unref(s->sink);
688 s->sink = pa_sink_ref(new_sink);
689
690 new_device_path = pa_dbusiface_core_get_sink_path(s->core, new_sink);
691
692 pa_assert_se(signal_msg = dbus_message_new_signal(s->path,
693 PA_DBUSIFACE_STREAM_INTERFACE,
694 signals[SIGNAL_DEVICE_UPDATED].name));
695 pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &new_device_path, DBUS_TYPE_INVALID));
696
697 pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg);
698 dbus_message_unref(signal_msg);
699 signal_msg = NULL;
700 }
701 } else {
702 pa_source *new_source = s->source_output->source;
703
704 if (s->source != new_source) {
705 pa_source_unref(s->source);
706 s->source = pa_source_ref(new_source);
707
708 new_device_path = pa_dbusiface_core_get_source_path(s->core, new_source);
709
710 pa_assert_se(signal_msg = dbus_message_new_signal(s->path,
711 PA_DBUSIFACE_STREAM_INTERFACE,
712 signals[SIGNAL_DEVICE_UPDATED].name));
713 pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &new_device_path, DBUS_TYPE_INVALID));
714
715 pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg);
716 dbus_message_unref(signal_msg);
717 signal_msg = NULL;
718 }
719 }
720
721 new_sample_rate = (s->type == STREAM_TYPE_PLAYBACK) ? s->sink_input->sample_spec.rate : s->source_output->sample_spec.rate;
722
723 if (s->sample_rate != new_sample_rate) {
724 s->sample_rate = new_sample_rate;
725
726 pa_assert_se(signal_msg = dbus_message_new_signal(s->path,
727 PA_DBUSIFACE_STREAM_INTERFACE,
728 signals[SIGNAL_SAMPLE_RATE_UPDATED].name));
729 pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_UINT32, &s->sample_rate, DBUS_TYPE_INVALID));
730
731 pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg);
732 dbus_message_unref(signal_msg);
733 signal_msg = NULL;
734 }
735
736 if (s->type == STREAM_TYPE_PLAYBACK) {
737 pa_bool_t new_mute = FALSE;
738
739 if (s->has_volume) {
740 pa_cvolume new_volume;
741
742 pa_sink_input_get_volume(s->sink_input, &new_volume, TRUE);
743
744 if (!pa_cvolume_equal(&s->volume, &new_volume)) {
745 dbus_uint32_t volume[PA_CHANNELS_MAX];
746 dbus_uint32_t *volume_ptr = volume;
747
748 s->volume = new_volume;
749
750 for (i = 0; i < s->volume.channels; ++i)
751 volume[i] = s->volume.values[i];
752
753 pa_assert_se(signal_msg = dbus_message_new_signal(s->path,
754 PA_DBUSIFACE_STREAM_INTERFACE,
755 signals[SIGNAL_VOLUME_UPDATED].name));
756 pa_assert_se(dbus_message_append_args(signal_msg,
757 DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &volume_ptr, s->volume.channels,
758 DBUS_TYPE_INVALID));
759
760 pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg);
761 dbus_message_unref(signal_msg);
762 signal_msg = NULL;
763 }
764 }
765
766 new_mute = pa_sink_input_get_mute(s->sink_input);
767
768 if (s->mute != new_mute) {
769 s->mute = new_mute;
770
771 pa_assert_se(signal_msg = dbus_message_new_signal(s->path,
772 PA_DBUSIFACE_STREAM_INTERFACE,
773 signals[SIGNAL_MUTE_UPDATED].name));
774 pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_BOOLEAN, &s->mute, DBUS_TYPE_INVALID));
775
776 pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg);
777 dbus_message_unref(signal_msg);
778 signal_msg = NULL;
779 }
780 }
781
782 new_proplist = (s->type == STREAM_TYPE_PLAYBACK) ? s->sink_input->proplist : s->source_output->proplist;
783
784 if (!pa_proplist_equal(s->proplist, new_proplist)) {
785 DBusMessageIter msg_iter;
786
787 pa_proplist_update(s->proplist, PA_UPDATE_SET, new_proplist);
788
789 pa_assert_se(signal_msg = dbus_message_new_signal(s->path,
790 PA_DBUSIFACE_STREAM_INTERFACE,
791 signals[SIGNAL_PROPERTY_LIST_UPDATED].name));
792 dbus_message_iter_init_append(signal_msg, &msg_iter);
793 pa_dbus_append_proplist(&msg_iter, s->proplist);
794
795 pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg);
796 dbus_message_unref(signal_msg);
797 signal_msg = NULL;
798 }
799 }
800
801 static pa_hook_result_t send_event_cb(void *hook_data, void *call_data, void *slot_data) {
802 pa_dbusiface_stream *s = slot_data;
803 DBusMessage *signal_msg = NULL;
804 DBusMessageIter msg_iter;
805 const char *name = NULL;
806 pa_proplist *property_list = NULL;
807
808 pa_assert(call_data);
809 pa_assert(s);
810
811 if (s->type == STREAM_TYPE_PLAYBACK) {
812 pa_sink_input_send_event_hook_data *data = call_data;
813
814 if (data->sink_input != s->sink_input)
815 return PA_HOOK_OK;
816
817 name = data->event;
818 property_list = data->data;
819 } else {
820 pa_source_output_send_event_hook_data *data = call_data;
821
822 if (data->source_output != s->source_output)
823 return PA_HOOK_OK;
824
825 name = data->event;
826 property_list = data->data;
827 }
828
829 pa_assert_se(signal_msg = dbus_message_new_signal(s->path,
830 PA_DBUSIFACE_STREAM_INTERFACE,
831 signals[SIGNAL_STREAM_EVENT].name));
832 dbus_message_iter_init_append(signal_msg, &msg_iter);
833 pa_assert_se(dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &name));
834 pa_dbus_append_proplist(&msg_iter, property_list);
835
836 pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg);
837 dbus_message_unref(signal_msg);
838
839 return PA_HOOK_OK;
840 }
841
842 pa_dbusiface_stream *pa_dbusiface_stream_new_playback(pa_dbusiface_core *core, pa_sink_input *sink_input) {
843 pa_dbusiface_stream *s;
844
845 pa_assert(core);
846 pa_assert(sink_input);
847
848 s = pa_xnew(pa_dbusiface_stream, 1);
849 s->core = core;
850 s->sink_input = pa_sink_input_ref(sink_input);
851 s->type = STREAM_TYPE_PLAYBACK;
852 s->path = pa_sprintf_malloc("%s/%s%u", PA_DBUS_CORE_OBJECT_PATH, PLAYBACK_OBJECT_NAME, sink_input->index);
853 s->sink = pa_sink_ref(sink_input->sink);
854 s->sample_rate = sink_input->sample_spec.rate;
855 s->has_volume = pa_sink_input_is_volume_readable(sink_input);
856 s->read_only_volume = s->has_volume ? !pa_sink_input_is_volume_writable(sink_input) : FALSE;
857
858 if (s->has_volume)
859 pa_sink_input_get_volume(sink_input, &s->volume, TRUE);
860 else
861 pa_cvolume_init(&s->volume);
862
863 s->mute = pa_sink_input_get_mute(sink_input);
864 s->proplist = pa_proplist_copy(sink_input->proplist);
865 s->dbus_protocol = pa_dbus_protocol_get(sink_input->core);
866 s->subscription = pa_subscription_new(sink_input->core, PA_SUBSCRIPTION_MASK_SINK_INPUT, subscription_cb, s);
867 s->send_event_slot = pa_hook_connect(&sink_input->core->hooks[PA_CORE_HOOK_SINK_INPUT_SEND_EVENT],
868 PA_HOOK_NORMAL,
869 send_event_cb,
870 s);
871
872 pa_assert_se(pa_dbus_protocol_add_interface(s->dbus_protocol, s->path, &stream_interface_info, s) >= 0);
873
874 return s;
875 }
876
877 pa_dbusiface_stream *pa_dbusiface_stream_new_record(pa_dbusiface_core *core, pa_source_output *source_output) {
878 pa_dbusiface_stream *s;
879
880 pa_assert(core);
881 pa_assert(source_output);
882
883 s = pa_xnew(pa_dbusiface_stream, 1);
884 s->core = core;
885 s->source_output = pa_source_output_ref(source_output);
886 s->type = STREAM_TYPE_RECORD;
887 s->path = pa_sprintf_malloc("%s/%s%u", PA_DBUS_CORE_OBJECT_PATH, RECORD_OBJECT_NAME, source_output->index);
888 s->source = pa_source_ref(source_output->source);
889 s->sample_rate = source_output->sample_spec.rate;
890 pa_cvolume_init(&s->volume);
891 s->mute = FALSE;
892 s->proplist = pa_proplist_copy(source_output->proplist);
893 s->has_volume = FALSE;
894 s->read_only_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 }