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