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