2 This file is part of PulseAudio.
4 Copyright 2006 Lennart Poettering
5 Copyright 2006 Shams E. King
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.
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.
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
29 #include <pulse/rtclock.h>
30 #include <pulse/timeval.h>
31 #include <pulse/utf8.h>
32 #include <pulse/xmalloc.h>
34 #include <pulsecore/core-rtclock.h>
35 #include <pulsecore/core-util.h>
36 #include <pulsecore/log.h>
38 #include "dbus-util.h"
40 struct pa_dbus_wrap_connection
{
41 pa_mainloop_api
*mainloop
;
42 DBusConnection
*connection
;
43 pa_defer_event
* dispatch_event
;
44 pa_bool_t use_rtclock
:1;
48 pa_dbus_wrap_connection
*connection
;
52 static void dispatch_cb(pa_mainloop_api
*ea
, pa_defer_event
*ev
, void *userdata
) {
53 DBusConnection
*conn
= userdata
;
55 if (dbus_connection_dispatch(conn
) == DBUS_DISPATCH_COMPLETE
)
56 /* no more data to process, disable the deferred */
57 ea
->defer_enable(ev
, 0);
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
;
68 case DBUS_DISPATCH_COMPLETE
:
69 c
->mainloop
->defer_enable(c
->dispatch_event
, 0);
72 case DBUS_DISPATCH_DATA_REMAINS
:
73 case DBUS_DISPATCH_NEED_MEMORY
:
75 c
->mainloop
->defer_enable(c
->dispatch_event
, 1);
80 static pa_io_event_flags_t
get_watch_flags(DBusWatch
*watch
) {
82 pa_io_event_flags_t events
= 0;
86 flags
= dbus_watch_get_flags(watch
);
88 /* no watch flags for disabled watches */
89 if (!dbus_watch_get_enabled(watch
))
90 return PA_IO_EVENT_NULL
;
92 if (flags
& DBUS_WATCH_READABLE
)
93 events
|= PA_IO_EVENT_INPUT
;
94 if (flags
& DBUS_WATCH_WRITABLE
)
95 events
|= PA_IO_EVENT_OUTPUT
;
97 return events
| PA_IO_EVENT_HANGUP
| PA_IO_EVENT_ERROR
;
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
;
105 #if HAVE_DBUS_WATCH_GET_UNIX_FD
106 pa_assert(fd
== dbus_watch_get_unix_fd(watch
));
108 pa_assert(fd
== dbus_watch_get_fd(watch
));
111 if (!dbus_watch_get_enabled(watch
)) {
112 pa_log_warn("Asked to handle disabled watch: %p %i", (void*) watch
, fd
);
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
;
125 dbus_watch_handle(watch
, flags
);
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
) {
131 struct timeout_data
*d
= userdata
;
134 pa_assert(d
->connection
);
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
));
144 dbus_timeout_handle(d
->timeout
);
148 /* DBusAddWatchFunction callback for pa mainloop */
149 static dbus_bool_t
add_watch(DBusWatch
*watch
, void *data
) {
150 pa_dbus_wrap_connection
*c
= data
;
156 ev
= c
->mainloop
->io_new(
158 #if HAVE_DBUS_WATCH_GET_UNIX_FD
159 dbus_watch_get_unix_fd(watch
),
161 dbus_watch_get_fd(watch
),
163 get_watch_flags(watch
), handle_io_event
, watch
);
165 dbus_watch_set_data(watch
, ev
, NULL
);
170 /* DBusRemoveWatchFunction callback for pa mainloop */
171 static void remove_watch(DBusWatch
*watch
, void *data
) {
172 pa_dbus_wrap_connection
*c
= data
;
178 if ((ev
= dbus_watch_get_data(watch
)))
179 c
->mainloop
->io_free(ev
);
182 /* DBusWatchToggledFunction callback for pa mainloop */
183 static void toggle_watch(DBusWatch
*watch
, void *data
) {
184 pa_dbus_wrap_connection
*c
= data
;
190 pa_assert_se(ev
= dbus_watch_get_data(watch
));
192 /* get_watch_flags() checks if the watch is enabled */
193 c
->mainloop
->io_enable(ev
, get_watch_flags(watch
));
196 static void time_event_destroy_cb(pa_mainloop_api
*a
, pa_time_event
*e
, void *userdata
) {
200 /* DBusAddTimeoutFunction callback for pa mainloop */
201 static dbus_bool_t
add_timeout(DBusTimeout
*timeout
, void *data
) {
202 pa_dbus_wrap_connection
*c
= data
;
205 struct timeout_data
*d
;
210 if (!dbus_timeout_get_enabled(timeout
))
213 d
= pa_xnew(struct timeout_data
, 1);
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
);
219 dbus_timeout_set_data(timeout
, ev
, NULL
);
224 /* DBusRemoveTimeoutFunction callback for pa mainloop */
225 static void remove_timeout(DBusTimeout
*timeout
, void *data
) {
226 pa_dbus_wrap_connection
*c
= data
;
232 if ((ev
= dbus_timeout_get_data(timeout
)))
233 c
->mainloop
->time_free(ev
);
236 /* DBusTimeoutToggledFunction callback for pa mainloop */
237 static void toggle_timeout(DBusTimeout
*timeout
, void *data
) {
238 struct timeout_data
*d
= data
;
243 pa_assert(d
->connection
);
246 pa_assert_se(ev
= dbus_timeout_get_data(timeout
));
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
));
251 d
->connection
->mainloop
->time_restart(ev
, pa_timeval_rtstore(&tv
, PA_USEC_INVALID
, d
->connection
->use_rtclock
));
254 static void wakeup_main(void *userdata
) {
255 pa_dbus_wrap_connection
*c
= userdata
;
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);
264 pa_dbus_wrap_connection
* pa_dbus_wrap_connection_new(pa_mainloop_api
*m
, pa_bool_t use_rtclock
, DBusBusType type
, DBusError
*error
) {
265 DBusConnection
*conn
;
266 pa_dbus_wrap_connection
*pconn
;
269 pa_assert(type
== DBUS_BUS_SYSTEM
|| type
== DBUS_BUS_SESSION
|| type
== DBUS_BUS_STARTER
);
271 if (!(conn
= dbus_bus_get_private(type
, error
)))
274 pconn
= pa_xnew(pa_dbus_wrap_connection
, 1);
276 pconn
->connection
= conn
;
277 pconn
->use_rtclock
= use_rtclock
;
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
);
285 pconn
->dispatch_event
= pconn
->mainloop
->defer_new(pconn
->mainloop
, dispatch_cb
, conn
);
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
)));
297 pa_dbus_wrap_connection
* pa_dbus_wrap_connection_new_from_existing(
299 pa_bool_t use_rtclock
,
300 DBusConnection
*conn
) {
301 pa_dbus_wrap_connection
*pconn
;
306 pconn
= pa_xnew(pa_dbus_wrap_connection
, 1);
308 pconn
->connection
= dbus_connection_ref(conn
);
309 pconn
->use_rtclock
= use_rtclock
;
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
);
317 pconn
->dispatch_event
= pconn
->mainloop
->defer_new(pconn
->mainloop
, dispatch_cb
, conn
);
322 void pa_dbus_wrap_connection_free(pa_dbus_wrap_connection
* c
) {
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))
333 c
->mainloop
->defer_free(c
->dispatch_event
);
334 dbus_connection_unref(c
->connection
);
338 DBusConnection
* pa_dbus_wrap_connection_get(pa_dbus_wrap_connection
*c
) {
340 pa_assert(c
->connection
);
342 return c
->connection
;
345 int pa_dbus_add_matches(DBusConnection
*c
, DBusError
*error
, ...) {
354 while ((t
= va_arg(ap
, const char*))) {
355 dbus_bus_add_match(c
, t
, error
);
357 if (dbus_error_is_set(error
))
372 pa_assert_se(t
= va_arg(ap
, const char*));
375 dbus_bus_remove_match(c
, t
, &e
);
383 void pa_dbus_remove_matches(DBusConnection
*c
, ...) {
390 dbus_error_init(&error
);
393 while ((t
= va_arg(ap
, const char*))) {
394 dbus_bus_remove_match(c
, t
, &error
);
395 dbus_error_free(&error
);
400 pa_dbus_pending
*pa_dbus_pending_new(
403 DBusPendingCall
*pending
,
411 p
= pa_xnew(pa_dbus_pending
, 1);
414 p
->pending
= pending
;
415 p
->context_data
= context_data
;
416 p
->call_data
= call_data
;
418 PA_LLIST_INIT(pa_dbus_pending
, p
);
423 void pa_dbus_pending_free(pa_dbus_pending
*p
) {
427 dbus_pending_call_cancel(p
->pending
);
428 dbus_pending_call_unref(p
->pending
);
432 dbus_message_unref(p
->message
);
437 void pa_dbus_sync_pending_list(pa_dbus_pending
**p
) {
440 while (*p
&& dbus_connection_read_write_dispatch((*p
)->connection
, -1))
444 void pa_dbus_free_pending_list(pa_dbus_pending
**p
) {
450 PA_LLIST_REMOVE(pa_dbus_pending
, *p
, i
);
451 pa_dbus_pending_free(i
);
455 void pa_dbus_send_error(DBusConnection
*c
, DBusMessage
*in_reply_to
, const char *name
, const char *format
, ...) {
458 DBusMessage
*reply
= NULL
;
461 pa_assert(in_reply_to
);
465 va_start(ap
, format
);
466 message
= pa_vsprintf_malloc(format
, ap
);
468 pa_assert_se((reply
= dbus_message_new_error(in_reply_to
, name
, message
)));
469 pa_assert_se(dbus_connection_send(c
, reply
, NULL
));
471 dbus_message_unref(reply
);
476 void pa_dbus_send_empty_reply(DBusConnection
*c
, DBusMessage
*in_reply_to
) {
477 DBusMessage
*reply
= NULL
;
480 pa_assert(in_reply_to
);
482 pa_assert_se((reply
= dbus_message_new_method_return(in_reply_to
)));
483 pa_assert_se(dbus_connection_send(c
, reply
, NULL
));
484 dbus_message_unref(reply
);
487 void pa_dbus_send_basic_value_reply(DBusConnection
*c
, DBusMessage
*in_reply_to
, int type
, void *data
) {
488 DBusMessage
*reply
= NULL
;
491 pa_assert(in_reply_to
);
492 pa_assert(dbus_type_is_basic(type
));
495 pa_assert_se((reply
= dbus_message_new_method_return(in_reply_to
)));
496 pa_assert_se(dbus_message_append_args(reply
, type
, data
, DBUS_TYPE_INVALID
));
497 pa_assert_se(dbus_connection_send(c
, reply
, NULL
));
498 dbus_message_unref(reply
);
501 static const char *signature_from_basic_type(int type
) {
503 case DBUS_TYPE_BOOLEAN
: return DBUS_TYPE_BOOLEAN_AS_STRING
;
504 case DBUS_TYPE_BYTE
: return DBUS_TYPE_BYTE_AS_STRING
;
505 case DBUS_TYPE_INT16
: return DBUS_TYPE_INT16_AS_STRING
;
506 case DBUS_TYPE_UINT16
: return DBUS_TYPE_UINT16_AS_STRING
;
507 case DBUS_TYPE_INT32
: return DBUS_TYPE_INT32_AS_STRING
;
508 case DBUS_TYPE_UINT32
: return DBUS_TYPE_UINT32_AS_STRING
;
509 case DBUS_TYPE_INT64
: return DBUS_TYPE_INT64_AS_STRING
;
510 case DBUS_TYPE_UINT64
: return DBUS_TYPE_UINT64_AS_STRING
;
511 case DBUS_TYPE_DOUBLE
: return DBUS_TYPE_DOUBLE_AS_STRING
;
512 case DBUS_TYPE_STRING
: return DBUS_TYPE_STRING_AS_STRING
;
513 case DBUS_TYPE_OBJECT_PATH
: return DBUS_TYPE_OBJECT_PATH_AS_STRING
;
514 case DBUS_TYPE_SIGNATURE
: return DBUS_TYPE_SIGNATURE_AS_STRING
;
515 default: pa_assert_not_reached();
519 void pa_dbus_send_basic_variant_reply(DBusConnection
*c
, DBusMessage
*in_reply_to
, int type
, void *data
) {
520 DBusMessage
*reply
= NULL
;
521 DBusMessageIter msg_iter
;
522 DBusMessageIter variant_iter
;
525 pa_assert(in_reply_to
);
526 pa_assert(dbus_type_is_basic(type
));
529 pa_assert_se((reply
= dbus_message_new_method_return(in_reply_to
)));
530 dbus_message_iter_init_append(reply
, &msg_iter
);
531 pa_assert_se(dbus_message_iter_open_container(&msg_iter
,
533 signature_from_basic_type(type
),
535 pa_assert_se(dbus_message_iter_append_basic(&variant_iter
, type
, data
));
536 pa_assert_se(dbus_message_iter_close_container(&msg_iter
, &variant_iter
));
537 pa_assert_se(dbus_connection_send(c
, reply
, NULL
));
538 dbus_message_unref(reply
);
541 /* Note: returns sizeof(char*) for strings, object paths and signatures. */
542 static unsigned basic_type_size(int type
) {
544 case DBUS_TYPE_BOOLEAN
: return sizeof(dbus_bool_t
);
545 case DBUS_TYPE_BYTE
: return 1;
546 case DBUS_TYPE_INT16
: return sizeof(dbus_int16_t
);
547 case DBUS_TYPE_UINT16
: return sizeof(dbus_uint16_t
);
548 case DBUS_TYPE_INT32
: return sizeof(dbus_int32_t
);
549 case DBUS_TYPE_UINT32
: return sizeof(dbus_uint32_t
);
550 case DBUS_TYPE_INT64
: return sizeof(dbus_int64_t
);
551 case DBUS_TYPE_UINT64
: return sizeof(dbus_uint64_t
);
552 case DBUS_TYPE_DOUBLE
: return sizeof(double);
553 case DBUS_TYPE_STRING
:
554 case DBUS_TYPE_OBJECT_PATH
:
555 case DBUS_TYPE_SIGNATURE
: return sizeof(char*);
556 default: pa_assert_not_reached();
560 void pa_dbus_send_basic_array_variant_reply(
562 DBusMessage
*in_reply_to
,
566 DBusMessage
*reply
= NULL
;
567 DBusMessageIter msg_iter
;
570 pa_assert(in_reply_to
);
571 pa_assert(dbus_type_is_basic(item_type
));
572 pa_assert(array
|| n
== 0);
574 pa_assert_se((reply
= dbus_message_new_method_return(in_reply_to
)));
575 dbus_message_iter_init_append(reply
, &msg_iter
);
576 pa_dbus_append_basic_array_variant(&msg_iter
, item_type
, array
, n
);
577 pa_assert_se(dbus_connection_send(c
, reply
, NULL
));
578 dbus_message_unref(reply
);
581 void pa_dbus_send_proplist_variant_reply(DBusConnection
*c
, DBusMessage
*in_reply_to
, pa_proplist
*proplist
) {
582 DBusMessage
*reply
= NULL
;
583 DBusMessageIter msg_iter
;
586 pa_assert(in_reply_to
);
589 pa_assert_se((reply
= dbus_message_new_method_return(in_reply_to
)));
590 dbus_message_iter_init_append(reply
, &msg_iter
);
591 pa_dbus_append_proplist_variant(&msg_iter
, proplist
);
592 pa_assert_se(dbus_connection_send(c
, reply
, NULL
));
593 dbus_message_unref(reply
);
596 void pa_dbus_append_basic_array(DBusMessageIter
*iter
, int item_type
, const void *array
, unsigned n
) {
597 DBusMessageIter array_iter
;
602 pa_assert(dbus_type_is_basic(item_type
));
603 pa_assert(array
|| n
== 0);
605 item_size
= basic_type_size(item_type
);
607 pa_assert_se(dbus_message_iter_open_container(iter
, DBUS_TYPE_ARRAY
, signature_from_basic_type(item_type
), &array_iter
));
609 for (i
= 0; i
< n
; ++i
)
610 pa_assert_se(dbus_message_iter_append_basic(&array_iter
, item_type
, &((uint8_t*) array
)[i
* item_size
]));
612 pa_assert_se(dbus_message_iter_close_container(iter
, &array_iter
));
615 void pa_dbus_append_basic_variant(DBusMessageIter
*iter
, int type
, void *data
) {
616 DBusMessageIter variant_iter
;
619 pa_assert(dbus_type_is_basic(type
));
622 pa_assert_se(dbus_message_iter_open_container(iter
, DBUS_TYPE_VARIANT
, signature_from_basic_type(type
), &variant_iter
));
623 pa_assert_se(dbus_message_iter_append_basic(&variant_iter
, type
, data
));
624 pa_assert_se(dbus_message_iter_close_container(iter
, &variant_iter
));
627 void pa_dbus_append_basic_array_variant(DBusMessageIter
*iter
, int item_type
, const void *array
, unsigned n
) {
628 DBusMessageIter variant_iter
;
629 char *array_signature
;
632 pa_assert(dbus_type_is_basic(item_type
));
633 pa_assert(array
|| n
== 0);
635 array_signature
= pa_sprintf_malloc("a%c", *signature_from_basic_type(item_type
));
637 pa_assert_se(dbus_message_iter_open_container(iter
, DBUS_TYPE_VARIANT
, array_signature
, &variant_iter
));
638 pa_dbus_append_basic_array(&variant_iter
, item_type
, array
, n
);
639 pa_assert_se(dbus_message_iter_close_container(iter
, &variant_iter
));
641 pa_xfree(array_signature
);
644 void pa_dbus_append_basic_variant_dict_entry(DBusMessageIter
*dict_iter
, const char *key
, int type
, void *data
) {
645 DBusMessageIter dict_entry_iter
;
647 pa_assert(dict_iter
);
649 pa_assert(dbus_type_is_basic(type
));
652 pa_assert_se(dbus_message_iter_open_container(dict_iter
, DBUS_TYPE_DICT_ENTRY
, NULL
, &dict_entry_iter
));
653 pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter
, DBUS_TYPE_STRING
, &key
));
654 pa_dbus_append_basic_variant(&dict_entry_iter
, type
, data
);
655 pa_assert_se(dbus_message_iter_close_container(dict_iter
, &dict_entry_iter
));
658 void pa_dbus_append_basic_array_variant_dict_entry(
659 DBusMessageIter
*dict_iter
,
664 DBusMessageIter dict_entry_iter
;
666 pa_assert(dict_iter
);
668 pa_assert(dbus_type_is_basic(item_type
));
669 pa_assert(array
|| n
== 0);
671 pa_assert_se(dbus_message_iter_open_container(dict_iter
, DBUS_TYPE_DICT_ENTRY
, NULL
, &dict_entry_iter
));
672 pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter
, DBUS_TYPE_STRING
, &key
));
673 pa_dbus_append_basic_array_variant(&dict_entry_iter
, item_type
, array
, n
);
674 pa_assert_se(dbus_message_iter_close_container(dict_iter
, &dict_entry_iter
));
677 void pa_dbus_append_proplist(DBusMessageIter
*iter
, pa_proplist
*proplist
) {
678 DBusMessageIter dict_iter
;
679 DBusMessageIter dict_entry_iter
;
680 DBusMessageIter array_iter
;
687 pa_assert_se(dbus_message_iter_open_container(iter
, DBUS_TYPE_ARRAY
, "{say}", &dict_iter
));
689 while ((key
= pa_proplist_iterate(proplist
, &state
))) {
690 const void *value
= NULL
;
693 pa_assert_se(pa_proplist_get(proplist
, key
, &value
, &nbytes
) >= 0);
695 pa_assert_se(dbus_message_iter_open_container(&dict_iter
, DBUS_TYPE_DICT_ENTRY
, NULL
, &dict_entry_iter
));
697 pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter
, DBUS_TYPE_STRING
, &key
));
699 pa_assert_se(dbus_message_iter_open_container(&dict_entry_iter
, DBUS_TYPE_ARRAY
, "y", &array_iter
));
700 pa_assert_se(dbus_message_iter_append_fixed_array(&array_iter
, DBUS_TYPE_BYTE
, &value
, nbytes
));
701 pa_assert_se(dbus_message_iter_close_container(&dict_entry_iter
, &array_iter
));
703 pa_assert_se(dbus_message_iter_close_container(&dict_iter
, &dict_entry_iter
));
706 pa_assert_se(dbus_message_iter_close_container(iter
, &dict_iter
));
709 void pa_dbus_append_proplist_variant(DBusMessageIter
*iter
, pa_proplist
*proplist
) {
710 DBusMessageIter variant_iter
;
715 pa_assert_se(dbus_message_iter_open_container(iter
, DBUS_TYPE_VARIANT
, "a{say}", &variant_iter
));
716 pa_dbus_append_proplist(&variant_iter
, proplist
);
717 pa_assert_se(dbus_message_iter_close_container(iter
, &variant_iter
));
720 void pa_dbus_append_proplist_variant_dict_entry(DBusMessageIter
*dict_iter
, const char *key
, pa_proplist
*proplist
) {
721 DBusMessageIter dict_entry_iter
;
723 pa_assert(dict_iter
);
727 pa_assert_se(dbus_message_iter_open_container(dict_iter
, DBUS_TYPE_DICT_ENTRY
, NULL
, &dict_entry_iter
));
728 pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter
, DBUS_TYPE_STRING
, &key
));
729 pa_dbus_append_proplist_variant(&dict_entry_iter
, proplist
);
730 pa_assert_se(dbus_message_iter_close_container(dict_iter
, &dict_entry_iter
));
733 pa_proplist
*pa_dbus_get_proplist_arg(DBusConnection
*c
, DBusMessage
*msg
, DBusMessageIter
*iter
) {
734 DBusMessageIter dict_iter
;
735 DBusMessageIter dict_entry_iter
;
736 pa_proplist
*proplist
= NULL
;
737 const char *key
= NULL
;
738 const uint8_t *value
= NULL
;
739 int value_length
= 0;
744 pa_assert(pa_streq(dbus_message_iter_get_signature(iter
), "a{say}"));
746 proplist
= pa_proplist_new();
748 dbus_message_iter_recurse(iter
, &dict_iter
);
750 while (dbus_message_iter_get_arg_type(&dict_iter
) != DBUS_TYPE_INVALID
) {
751 dbus_message_iter_recurse(&dict_iter
, &dict_entry_iter
);
753 dbus_message_iter_get_basic(&dict_entry_iter
, &key
);
754 dbus_message_iter_next(&dict_entry_iter
);
756 if (strlen(key
) <= 0 || !pa_ascii_valid(key
)) {
757 pa_dbus_send_error(c
, msg
, DBUS_ERROR_INVALID_ARGS
, "Invalid property list key: '%s'.", key
);
761 dbus_message_iter_get_fixed_array(&dict_entry_iter
, &value
, &value_length
);
763 pa_assert(value_length
>= 0);
765 pa_assert_se(pa_proplist_set(proplist
, key
, value
, value_length
) >= 0);
767 dbus_message_iter_next(&dict_iter
);
770 dbus_message_iter_next(iter
);
776 pa_proplist_free(proplist
);