]> code.delx.au - pulseaudio/blob - src/pulsecore/dbus-util.c
remap: Change remapping function argument type from void to int16_t / float as approp...
[pulseaudio] / src / pulsecore / dbus-util.c
1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2006 Lennart Poettering
5 Copyright 2006 Shams E. King
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 <stdarg.h>
28
29 #include <pulse/rtclock.h>
30 #include <pulse/timeval.h>
31 #include <pulse/utf8.h>
32 #include <pulse/xmalloc.h>
33
34 #include <pulsecore/core-rtclock.h>
35 #include <pulsecore/core-util.h>
36 #include <pulsecore/log.h>
37
38 #include "dbus-util.h"
39
40 struct pa_dbus_wrap_connection {
41 pa_mainloop_api *mainloop;
42 DBusConnection *connection;
43 pa_defer_event* dispatch_event;
44 bool use_rtclock:1;
45 };
46
47 struct timeout_data {
48 pa_dbus_wrap_connection *connection;
49 DBusTimeout *timeout;
50 };
51
52 static void dispatch_cb(pa_mainloop_api *ea, pa_defer_event *ev, void *userdata) {
53 DBusConnection *conn = userdata;
54
55 if (dbus_connection_dispatch(conn) == DBUS_DISPATCH_COMPLETE)
56 /* no more data to process, disable the deferred */
57 ea->defer_enable(ev, 0);
58 }
59
60 /* DBusDispatchStatusFunction callback for the pa mainloop */
61 static void dispatch_status(DBusConnection *conn, DBusDispatchStatus status, void *userdata) {
62 pa_dbus_wrap_connection *c = userdata;
63
64 pa_assert(c);
65
66 switch(status) {
67
68 case DBUS_DISPATCH_COMPLETE:
69 c->mainloop->defer_enable(c->dispatch_event, 0);
70 break;
71
72 case DBUS_DISPATCH_DATA_REMAINS:
73 case DBUS_DISPATCH_NEED_MEMORY:
74 default:
75 c->mainloop->defer_enable(c->dispatch_event, 1);
76 break;
77 }
78 }
79
80 static pa_io_event_flags_t get_watch_flags(DBusWatch *watch) {
81 unsigned int flags;
82 pa_io_event_flags_t events = 0;
83
84 pa_assert(watch);
85
86 flags = dbus_watch_get_flags(watch);
87
88 /* no watch flags for disabled watches */
89 if (!dbus_watch_get_enabled(watch))
90 return PA_IO_EVENT_NULL;
91
92 if (flags & DBUS_WATCH_READABLE)
93 events |= PA_IO_EVENT_INPUT;
94 if (flags & DBUS_WATCH_WRITABLE)
95 events |= PA_IO_EVENT_OUTPUT;
96
97 return events | PA_IO_EVENT_HANGUP | PA_IO_EVENT_ERROR;
98 }
99
100 /* pa_io_event_cb_t IO event handler */
101 static void handle_io_event(pa_mainloop_api *ea, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata) {
102 unsigned int flags = 0;
103 DBusWatch *watch = userdata;
104
105 #if HAVE_DBUS_WATCH_GET_UNIX_FD
106 pa_assert(fd == dbus_watch_get_unix_fd(watch));
107 #else
108 pa_assert(fd == dbus_watch_get_fd(watch));
109 #endif
110
111 if (!dbus_watch_get_enabled(watch)) {
112 pa_log_warn("Asked to handle disabled watch: %p %i", (void*) watch, fd);
113 return;
114 }
115
116 if (events & PA_IO_EVENT_INPUT)
117 flags |= DBUS_WATCH_READABLE;
118 if (events & PA_IO_EVENT_OUTPUT)
119 flags |= DBUS_WATCH_WRITABLE;
120 if (events & PA_IO_EVENT_HANGUP)
121 flags |= DBUS_WATCH_HANGUP;
122 if (events & PA_IO_EVENT_ERROR)
123 flags |= DBUS_WATCH_ERROR;
124
125 dbus_watch_handle(watch, flags);
126 }
127
128 /* pa_time_event_cb_t timer event handler */
129 static void handle_time_event(pa_mainloop_api *ea, pa_time_event* e, const struct timeval *t, void *userdata) {
130 struct timeval tv;
131 struct timeout_data *d = userdata;
132
133 pa_assert(d);
134 pa_assert(d->connection);
135
136 if (dbus_timeout_get_enabled(d->timeout)) {
137 /* Restart it for the next scheduled time. We do this before
138 * calling dbus_timeout_handle() to make sure that the time
139 * event is still around. */
140 ea->time_restart(e, pa_timeval_rtstore(&tv,
141 pa_timeval_load(t) + dbus_timeout_get_interval(d->timeout) * PA_USEC_PER_MSEC,
142 d->connection->use_rtclock));
143
144 dbus_timeout_handle(d->timeout);
145 }
146 }
147
148 /* DBusAddWatchFunction callback for pa mainloop */
149 static dbus_bool_t add_watch(DBusWatch *watch, void *data) {
150 pa_dbus_wrap_connection *c = data;
151 pa_io_event *ev;
152
153 pa_assert(watch);
154 pa_assert(c);
155
156 ev = c->mainloop->io_new(
157 c->mainloop,
158 #if HAVE_DBUS_WATCH_GET_UNIX_FD
159 dbus_watch_get_unix_fd(watch),
160 #else
161 dbus_watch_get_fd(watch),
162 #endif
163 get_watch_flags(watch), handle_io_event, watch);
164
165 dbus_watch_set_data(watch, ev, NULL);
166
167 return TRUE;
168 }
169
170 /* DBusRemoveWatchFunction callback for pa mainloop */
171 static void remove_watch(DBusWatch *watch, void *data) {
172 pa_dbus_wrap_connection *c = data;
173 pa_io_event *ev;
174
175 pa_assert(watch);
176 pa_assert(c);
177
178 if ((ev = dbus_watch_get_data(watch)))
179 c->mainloop->io_free(ev);
180 }
181
182 /* DBusWatchToggledFunction callback for pa mainloop */
183 static void toggle_watch(DBusWatch *watch, void *data) {
184 pa_dbus_wrap_connection *c = data;
185 pa_io_event *ev;
186
187 pa_assert(watch);
188 pa_assert(c);
189
190 pa_assert_se(ev = dbus_watch_get_data(watch));
191
192 /* get_watch_flags() checks if the watch is enabled */
193 c->mainloop->io_enable(ev, get_watch_flags(watch));
194 }
195
196 static void time_event_destroy_cb(pa_mainloop_api *a, pa_time_event *e, void *userdata) {
197 pa_xfree(userdata);
198 }
199
200 /* DBusAddTimeoutFunction callback for pa mainloop */
201 static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data) {
202 pa_dbus_wrap_connection *c = data;
203 pa_time_event *ev;
204 struct timeval tv;
205 struct timeout_data *d;
206
207 pa_assert(timeout);
208 pa_assert(c);
209
210 if (!dbus_timeout_get_enabled(timeout))
211 return FALSE;
212
213 d = pa_xnew(struct timeout_data, 1);
214 d->connection = c;
215 d->timeout = timeout;
216 ev = c->mainloop->time_new(c->mainloop, pa_timeval_rtstore(&tv, pa_rtclock_now() + dbus_timeout_get_interval(timeout) * PA_USEC_PER_MSEC, c->use_rtclock), handle_time_event, d);
217 c->mainloop->time_set_destroy(ev, time_event_destroy_cb);
218
219 dbus_timeout_set_data(timeout, ev, NULL);
220
221 return TRUE;
222 }
223
224 /* DBusRemoveTimeoutFunction callback for pa mainloop */
225 static void remove_timeout(DBusTimeout *timeout, void *data) {
226 pa_dbus_wrap_connection *c = data;
227 pa_time_event *ev;
228
229 pa_assert(timeout);
230 pa_assert(c);
231
232 if ((ev = dbus_timeout_get_data(timeout)))
233 c->mainloop->time_free(ev);
234 }
235
236 /* DBusTimeoutToggledFunction callback for pa mainloop */
237 static void toggle_timeout(DBusTimeout *timeout, void *data) {
238 struct timeout_data *d = data;
239 pa_time_event *ev;
240 struct timeval tv;
241
242 pa_assert(d);
243 pa_assert(d->connection);
244 pa_assert(timeout);
245
246 pa_assert_se(ev = dbus_timeout_get_data(timeout));
247
248 if (dbus_timeout_get_enabled(timeout))
249 d->connection->mainloop->time_restart(ev, pa_timeval_rtstore(&tv, pa_rtclock_now() + dbus_timeout_get_interval(timeout) * PA_USEC_PER_MSEC, d->connection->use_rtclock));
250 else
251 d->connection->mainloop->time_restart(ev, pa_timeval_rtstore(&tv, PA_USEC_INVALID, d->connection->use_rtclock));
252 }
253
254 static void wakeup_main(void *userdata) {
255 pa_dbus_wrap_connection *c = userdata;
256
257 pa_assert(c);
258
259 /* this will wakeup the mainloop and dispatch events, although
260 * it may not be the cleanest way of accomplishing it */
261 c->mainloop->defer_enable(c->dispatch_event, 1);
262 }
263
264 pa_dbus_wrap_connection* pa_dbus_wrap_connection_new(pa_mainloop_api *m, bool use_rtclock, DBusBusType type, DBusError *error) {
265 DBusConnection *conn;
266 pa_dbus_wrap_connection *pconn;
267 char *id;
268
269 pa_assert(type == DBUS_BUS_SYSTEM || type == DBUS_BUS_SESSION || type == DBUS_BUS_STARTER);
270
271 if (!(conn = dbus_bus_get_private(type, error)))
272 return NULL;
273
274 pconn = pa_xnew(pa_dbus_wrap_connection, 1);
275 pconn->mainloop = m;
276 pconn->connection = conn;
277 pconn->use_rtclock = use_rtclock;
278
279 dbus_connection_set_exit_on_disconnect(conn, FALSE);
280 dbus_connection_set_dispatch_status_function(conn, dispatch_status, pconn, NULL);
281 dbus_connection_set_watch_functions(conn, add_watch, remove_watch, toggle_watch, pconn, NULL);
282 dbus_connection_set_timeout_functions(conn, add_timeout, remove_timeout, toggle_timeout, pconn, NULL);
283 dbus_connection_set_wakeup_main_function(conn, wakeup_main, pconn, NULL);
284
285 pconn->dispatch_event = pconn->mainloop->defer_new(pconn->mainloop, dispatch_cb, conn);
286
287 pa_log_debug("Successfully connected to D-Bus %s bus %s as %s",
288 type == DBUS_BUS_SYSTEM ? "system" : (type == DBUS_BUS_SESSION ? "session" : "starter"),
289 pa_strnull((id = dbus_connection_get_server_id(conn))),
290 pa_strnull(dbus_bus_get_unique_name(conn)));
291
292 dbus_free(id);
293
294 return pconn;
295 }
296
297 pa_dbus_wrap_connection* pa_dbus_wrap_connection_new_from_existing(
298 pa_mainloop_api *m,
299 bool use_rtclock,
300 DBusConnection *conn) {
301 pa_dbus_wrap_connection *pconn;
302
303 pa_assert(m);
304 pa_assert(conn);
305
306 pconn = pa_xnew(pa_dbus_wrap_connection, 1);
307 pconn->mainloop = m;
308 pconn->connection = dbus_connection_ref(conn);
309 pconn->use_rtclock = use_rtclock;
310
311 dbus_connection_set_exit_on_disconnect(conn, FALSE);
312 dbus_connection_set_dispatch_status_function(conn, dispatch_status, pconn, NULL);
313 dbus_connection_set_watch_functions(conn, add_watch, remove_watch, toggle_watch, pconn, NULL);
314 dbus_connection_set_timeout_functions(conn, add_timeout, remove_timeout, toggle_timeout, pconn, NULL);
315 dbus_connection_set_wakeup_main_function(conn, wakeup_main, pconn, NULL);
316
317 pconn->dispatch_event = pconn->mainloop->defer_new(pconn->mainloop, dispatch_cb, conn);
318
319 return pconn;
320 }
321
322 void pa_dbus_wrap_connection_free(pa_dbus_wrap_connection* c) {
323 pa_assert(c);
324
325 if (dbus_connection_get_is_connected(c->connection)) {
326 dbus_connection_close(c->connection);
327 /* must process remaining messages, bit of a kludge to handle
328 * both unload and shutdown */
329 while (dbus_connection_read_write_dispatch(c->connection, -1))
330 ;
331 }
332
333 c->mainloop->defer_free(c->dispatch_event);
334 dbus_connection_unref(c->connection);
335 pa_xfree(c);
336 }
337
338 DBusConnection* pa_dbus_wrap_connection_get(pa_dbus_wrap_connection *c) {
339 pa_assert(c);
340 pa_assert(c->connection);
341
342 return c->connection;
343 }
344
345 int pa_dbus_add_matches(DBusConnection *c, DBusError *error, ...) {
346 const char *t;
347 va_list ap;
348 unsigned k = 0;
349
350 pa_assert(c);
351 pa_assert(error);
352
353 va_start(ap, error);
354 while ((t = va_arg(ap, const char*))) {
355 dbus_bus_add_match(c, t, error);
356
357 if (dbus_error_is_set(error))
358 goto fail;
359
360 k++;
361 }
362 va_end(ap);
363 return 0;
364
365 fail:
366
367 va_end(ap);
368 va_start(ap, error);
369 for (; k > 0; k--) {
370 pa_assert_se(t = va_arg(ap, const char*));
371 dbus_bus_remove_match(c, t, NULL);
372 }
373 va_end(ap);
374
375 return -1;
376 }
377
378 void pa_dbus_remove_matches(DBusConnection *c, ...) {
379 const char *t;
380 va_list ap;
381
382 pa_assert(c);
383
384 va_start(ap, c);
385 while ((t = va_arg(ap, const char*)))
386 dbus_bus_remove_match(c, t, NULL);
387 va_end(ap);
388 }
389
390 pa_dbus_pending *pa_dbus_pending_new(
391 DBusConnection *c,
392 DBusMessage *m,
393 DBusPendingCall *pending,
394 void *context_data,
395 void *call_data) {
396
397 pa_dbus_pending *p;
398
399 pa_assert(pending);
400
401 p = pa_xnew(pa_dbus_pending, 1);
402 p->connection = c;
403 p->message = m;
404 p->pending = pending;
405 p->context_data = context_data;
406 p->call_data = call_data;
407
408 PA_LLIST_INIT(pa_dbus_pending, p);
409
410 return p;
411 }
412
413 void pa_dbus_pending_free(pa_dbus_pending *p) {
414 pa_assert(p);
415
416 if (p->pending) {
417 dbus_pending_call_cancel(p->pending);
418 dbus_pending_call_unref(p->pending);
419 }
420
421 if (p->message)
422 dbus_message_unref(p->message);
423
424 pa_xfree(p);
425 }
426
427 void pa_dbus_sync_pending_list(pa_dbus_pending **p) {
428 pa_assert(p);
429
430 while (*p && dbus_connection_read_write_dispatch((*p)->connection, -1))
431 ;
432 }
433
434 void pa_dbus_free_pending_list(pa_dbus_pending **p) {
435 pa_dbus_pending *i;
436
437 pa_assert(p);
438
439 while ((i = *p)) {
440 PA_LLIST_REMOVE(pa_dbus_pending, *p, i);
441 pa_dbus_pending_free(i);
442 }
443 }
444
445 const char *pa_dbus_get_error_message(DBusMessage *m) {
446 const char *message;
447
448 pa_assert(m);
449 pa_assert(dbus_message_get_type(m) == DBUS_MESSAGE_TYPE_ERROR);
450
451 if (dbus_message_get_signature(m)[0] != 's')
452 return "<no explanation>";
453
454 pa_assert_se(dbus_message_get_args(m, NULL, DBUS_TYPE_STRING, &message, DBUS_TYPE_INVALID));
455
456 return message;
457 }
458
459 void pa_dbus_send_error(DBusConnection *c, DBusMessage *in_reply_to, const char *name, const char *format, ...) {
460 va_list ap;
461 char *message;
462 DBusMessage *reply = NULL;
463
464 pa_assert(c);
465 pa_assert(in_reply_to);
466 pa_assert(name);
467 pa_assert(format);
468
469 va_start(ap, format);
470 message = pa_vsprintf_malloc(format, ap);
471 va_end(ap);
472 pa_assert_se((reply = dbus_message_new_error(in_reply_to, name, message)));
473 pa_assert_se(dbus_connection_send(c, reply, NULL));
474
475 dbus_message_unref(reply);
476
477 pa_xfree(message);
478 }
479
480 void pa_dbus_send_empty_reply(DBusConnection *c, DBusMessage *in_reply_to) {
481 DBusMessage *reply = NULL;
482
483 pa_assert(c);
484 pa_assert(in_reply_to);
485
486 pa_assert_se((reply = dbus_message_new_method_return(in_reply_to)));
487 pa_assert_se(dbus_connection_send(c, reply, NULL));
488 dbus_message_unref(reply);
489 }
490
491 void pa_dbus_send_basic_value_reply(DBusConnection *c, DBusMessage *in_reply_to, int type, void *data) {
492 DBusMessage *reply = NULL;
493
494 pa_assert(c);
495 pa_assert(in_reply_to);
496 pa_assert(dbus_type_is_basic(type));
497 pa_assert(data);
498
499 pa_assert_se((reply = dbus_message_new_method_return(in_reply_to)));
500 pa_assert_se(dbus_message_append_args(reply, type, data, DBUS_TYPE_INVALID));
501 pa_assert_se(dbus_connection_send(c, reply, NULL));
502 dbus_message_unref(reply);
503 }
504
505 static const char *signature_from_basic_type(int type) {
506 switch (type) {
507 case DBUS_TYPE_BOOLEAN: return DBUS_TYPE_BOOLEAN_AS_STRING;
508 case DBUS_TYPE_BYTE: return DBUS_TYPE_BYTE_AS_STRING;
509 case DBUS_TYPE_INT16: return DBUS_TYPE_INT16_AS_STRING;
510 case DBUS_TYPE_UINT16: return DBUS_TYPE_UINT16_AS_STRING;
511 case DBUS_TYPE_INT32: return DBUS_TYPE_INT32_AS_STRING;
512 case DBUS_TYPE_UINT32: return DBUS_TYPE_UINT32_AS_STRING;
513 case DBUS_TYPE_INT64: return DBUS_TYPE_INT64_AS_STRING;
514 case DBUS_TYPE_UINT64: return DBUS_TYPE_UINT64_AS_STRING;
515 case DBUS_TYPE_DOUBLE: return DBUS_TYPE_DOUBLE_AS_STRING;
516 case DBUS_TYPE_STRING: return DBUS_TYPE_STRING_AS_STRING;
517 case DBUS_TYPE_OBJECT_PATH: return DBUS_TYPE_OBJECT_PATH_AS_STRING;
518 case DBUS_TYPE_SIGNATURE: return DBUS_TYPE_SIGNATURE_AS_STRING;
519 default: pa_assert_not_reached();
520 }
521 }
522
523 void pa_dbus_send_basic_variant_reply(DBusConnection *c, DBusMessage *in_reply_to, int type, void *data) {
524 DBusMessage *reply = NULL;
525 DBusMessageIter msg_iter;
526 DBusMessageIter variant_iter;
527
528 pa_assert(c);
529 pa_assert(in_reply_to);
530 pa_assert(dbus_type_is_basic(type));
531 pa_assert(data);
532
533 pa_assert_se((reply = dbus_message_new_method_return(in_reply_to)));
534 dbus_message_iter_init_append(reply, &msg_iter);
535 pa_assert_se(dbus_message_iter_open_container(&msg_iter,
536 DBUS_TYPE_VARIANT,
537 signature_from_basic_type(type),
538 &variant_iter));
539 pa_assert_se(dbus_message_iter_append_basic(&variant_iter, type, data));
540 pa_assert_se(dbus_message_iter_close_container(&msg_iter, &variant_iter));
541 pa_assert_se(dbus_connection_send(c, reply, NULL));
542 dbus_message_unref(reply);
543 }
544
545 /* Note: returns sizeof(char*) for strings, object paths and signatures. */
546 static unsigned basic_type_size(int type) {
547 switch (type) {
548 case DBUS_TYPE_BOOLEAN: return sizeof(dbus_bool_t);
549 case DBUS_TYPE_BYTE: return 1;
550 case DBUS_TYPE_INT16: return sizeof(dbus_int16_t);
551 case DBUS_TYPE_UINT16: return sizeof(dbus_uint16_t);
552 case DBUS_TYPE_INT32: return sizeof(dbus_int32_t);
553 case DBUS_TYPE_UINT32: return sizeof(dbus_uint32_t);
554 case DBUS_TYPE_INT64: return sizeof(dbus_int64_t);
555 case DBUS_TYPE_UINT64: return sizeof(dbus_uint64_t);
556 case DBUS_TYPE_DOUBLE: return sizeof(double);
557 case DBUS_TYPE_STRING:
558 case DBUS_TYPE_OBJECT_PATH:
559 case DBUS_TYPE_SIGNATURE: return sizeof(char*);
560 default: pa_assert_not_reached();
561 }
562 }
563
564 void pa_dbus_send_basic_array_variant_reply(
565 DBusConnection *c,
566 DBusMessage *in_reply_to,
567 int item_type,
568 void *array,
569 unsigned n) {
570 DBusMessage *reply = NULL;
571 DBusMessageIter msg_iter;
572
573 pa_assert(c);
574 pa_assert(in_reply_to);
575 pa_assert(dbus_type_is_basic(item_type));
576 pa_assert(array || n == 0);
577
578 pa_assert_se((reply = dbus_message_new_method_return(in_reply_to)));
579 dbus_message_iter_init_append(reply, &msg_iter);
580 pa_dbus_append_basic_array_variant(&msg_iter, item_type, array, n);
581 pa_assert_se(dbus_connection_send(c, reply, NULL));
582 dbus_message_unref(reply);
583 }
584
585 void pa_dbus_send_proplist_variant_reply(DBusConnection *c, DBusMessage *in_reply_to, pa_proplist *proplist) {
586 DBusMessage *reply = NULL;
587 DBusMessageIter msg_iter;
588
589 pa_assert(c);
590 pa_assert(in_reply_to);
591 pa_assert(proplist);
592
593 pa_assert_se((reply = dbus_message_new_method_return(in_reply_to)));
594 dbus_message_iter_init_append(reply, &msg_iter);
595 pa_dbus_append_proplist_variant(&msg_iter, proplist);
596 pa_assert_se(dbus_connection_send(c, reply, NULL));
597 dbus_message_unref(reply);
598 }
599
600 void pa_dbus_append_basic_array(DBusMessageIter *iter, int item_type, const void *array, unsigned n) {
601 DBusMessageIter array_iter;
602 unsigned i;
603 unsigned item_size;
604
605 pa_assert(iter);
606 pa_assert(dbus_type_is_basic(item_type));
607 pa_assert(array || n == 0);
608
609 item_size = basic_type_size(item_type);
610
611 pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, signature_from_basic_type(item_type), &array_iter));
612
613 for (i = 0; i < n; ++i)
614 pa_assert_se(dbus_message_iter_append_basic(&array_iter, item_type, &((uint8_t*) array)[i * item_size]));
615
616 pa_assert_se(dbus_message_iter_close_container(iter, &array_iter));
617 }
618
619 void pa_dbus_append_basic_variant(DBusMessageIter *iter, int type, void *data) {
620 DBusMessageIter variant_iter;
621
622 pa_assert(iter);
623 pa_assert(dbus_type_is_basic(type));
624 pa_assert(data);
625
626 pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, signature_from_basic_type(type), &variant_iter));
627 pa_assert_se(dbus_message_iter_append_basic(&variant_iter, type, data));
628 pa_assert_se(dbus_message_iter_close_container(iter, &variant_iter));
629 }
630
631 void pa_dbus_append_basic_array_variant(DBusMessageIter *iter, int item_type, const void *array, unsigned n) {
632 DBusMessageIter variant_iter;
633 char *array_signature;
634
635 pa_assert(iter);
636 pa_assert(dbus_type_is_basic(item_type));
637 pa_assert(array || n == 0);
638
639 array_signature = pa_sprintf_malloc("a%c", *signature_from_basic_type(item_type));
640
641 pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, array_signature, &variant_iter));
642 pa_dbus_append_basic_array(&variant_iter, item_type, array, n);
643 pa_assert_se(dbus_message_iter_close_container(iter, &variant_iter));
644
645 pa_xfree(array_signature);
646 }
647
648 void pa_dbus_append_basic_variant_dict_entry(DBusMessageIter *dict_iter, const char *key, int type, void *data) {
649 DBusMessageIter dict_entry_iter;
650
651 pa_assert(dict_iter);
652 pa_assert(key);
653 pa_assert(dbus_type_is_basic(type));
654 pa_assert(data);
655
656 pa_assert_se(dbus_message_iter_open_container(dict_iter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_entry_iter));
657 pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter, DBUS_TYPE_STRING, &key));
658 pa_dbus_append_basic_variant(&dict_entry_iter, type, data);
659 pa_assert_se(dbus_message_iter_close_container(dict_iter, &dict_entry_iter));
660 }
661
662 void pa_dbus_append_basic_array_variant_dict_entry(
663 DBusMessageIter *dict_iter,
664 const char *key,
665 int item_type,
666 const void *array,
667 unsigned n) {
668 DBusMessageIter dict_entry_iter;
669
670 pa_assert(dict_iter);
671 pa_assert(key);
672 pa_assert(dbus_type_is_basic(item_type));
673 pa_assert(array || n == 0);
674
675 pa_assert_se(dbus_message_iter_open_container(dict_iter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_entry_iter));
676 pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter, DBUS_TYPE_STRING, &key));
677 pa_dbus_append_basic_array_variant(&dict_entry_iter, item_type, array, n);
678 pa_assert_se(dbus_message_iter_close_container(dict_iter, &dict_entry_iter));
679 }
680
681 void pa_dbus_append_proplist(DBusMessageIter *iter, pa_proplist *proplist) {
682 DBusMessageIter dict_iter;
683 DBusMessageIter dict_entry_iter;
684 DBusMessageIter array_iter;
685 void *state = NULL;
686 const char *key;
687
688 pa_assert(iter);
689 pa_assert(proplist);
690
691 pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "{say}", &dict_iter));
692
693 while ((key = pa_proplist_iterate(proplist, &state))) {
694 const void *value = NULL;
695 size_t nbytes;
696
697 pa_assert_se(pa_proplist_get(proplist, key, &value, &nbytes) >= 0);
698
699 pa_assert_se(dbus_message_iter_open_container(&dict_iter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_entry_iter));
700
701 pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter, DBUS_TYPE_STRING, &key));
702
703 pa_assert_se(dbus_message_iter_open_container(&dict_entry_iter, DBUS_TYPE_ARRAY, "y", &array_iter));
704 pa_assert_se(dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE, &value, nbytes));
705 pa_assert_se(dbus_message_iter_close_container(&dict_entry_iter, &array_iter));
706
707 pa_assert_se(dbus_message_iter_close_container(&dict_iter, &dict_entry_iter));
708 }
709
710 pa_assert_se(dbus_message_iter_close_container(iter, &dict_iter));
711 }
712
713 void pa_dbus_append_proplist_variant(DBusMessageIter *iter, pa_proplist *proplist) {
714 DBusMessageIter variant_iter;
715
716 pa_assert(iter);
717 pa_assert(proplist);
718
719 pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a{say}", &variant_iter));
720 pa_dbus_append_proplist(&variant_iter, proplist);
721 pa_assert_se(dbus_message_iter_close_container(iter, &variant_iter));
722 }
723
724 void pa_dbus_append_proplist_variant_dict_entry(DBusMessageIter *dict_iter, const char *key, pa_proplist *proplist) {
725 DBusMessageIter dict_entry_iter;
726
727 pa_assert(dict_iter);
728 pa_assert(key);
729 pa_assert(proplist);
730
731 pa_assert_se(dbus_message_iter_open_container(dict_iter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_entry_iter));
732 pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter, DBUS_TYPE_STRING, &key));
733 pa_dbus_append_proplist_variant(&dict_entry_iter, proplist);
734 pa_assert_se(dbus_message_iter_close_container(dict_iter, &dict_entry_iter));
735 }
736
737 pa_proplist *pa_dbus_get_proplist_arg(DBusConnection *c, DBusMessage *msg, DBusMessageIter *iter) {
738 DBusMessageIter dict_iter;
739 DBusMessageIter dict_entry_iter;
740 pa_proplist *proplist = NULL;
741 const char *key = NULL;
742 const uint8_t *value = NULL;
743 int value_length = 0;
744
745 pa_assert(c);
746 pa_assert(msg);
747 pa_assert(iter);
748 pa_assert(pa_streq(dbus_message_iter_get_signature(iter), "a{say}"));
749
750 proplist = pa_proplist_new();
751
752 dbus_message_iter_recurse(iter, &dict_iter);
753
754 while (dbus_message_iter_get_arg_type(&dict_iter) != DBUS_TYPE_INVALID) {
755 dbus_message_iter_recurse(&dict_iter, &dict_entry_iter);
756
757 dbus_message_iter_get_basic(&dict_entry_iter, &key);
758 dbus_message_iter_next(&dict_entry_iter);
759
760 if (strlen(key) <= 0 || !pa_ascii_valid(key)) {
761 pa_dbus_send_error(c, msg, DBUS_ERROR_INVALID_ARGS, "Invalid property list key: '%s'.", key);
762 goto fail;
763 }
764
765 dbus_message_iter_get_fixed_array(&dict_entry_iter, &value, &value_length);
766
767 pa_assert(value_length >= 0);
768
769 pa_assert_se(pa_proplist_set(proplist, key, value, value_length) >= 0);
770
771 dbus_message_iter_next(&dict_iter);
772 }
773
774 dbus_message_iter_next(iter);
775
776 return proplist;
777
778 fail:
779 if (proplist)
780 pa_proplist_free(proplist);
781
782 return NULL;
783 }