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
*c
;
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);
61 /* DBusDispatchStatusFunction callback for the pa mainloop */
62 static void dispatch_status(DBusConnection
*conn
, DBusDispatchStatus status
, void *userdata
) {
63 pa_dbus_wrap_connection
*c
= userdata
;
69 case DBUS_DISPATCH_COMPLETE
:
70 c
->mainloop
->defer_enable(c
->dispatch_event
, 0);
73 case DBUS_DISPATCH_DATA_REMAINS
:
74 case DBUS_DISPATCH_NEED_MEMORY
:
76 c
->mainloop
->defer_enable(c
->dispatch_event
, 1);
81 static pa_io_event_flags_t
get_watch_flags(DBusWatch
*watch
) {
83 pa_io_event_flags_t events
= 0;
87 flags
= dbus_watch_get_flags(watch
);
89 /* no watch flags for disabled watches */
90 if (!dbus_watch_get_enabled(watch
))
91 return PA_IO_EVENT_NULL
;
93 if (flags
& DBUS_WATCH_READABLE
)
94 events
|= PA_IO_EVENT_INPUT
;
95 if (flags
& DBUS_WATCH_WRITABLE
)
96 events
|= PA_IO_EVENT_OUTPUT
;
98 return events
| PA_IO_EVENT_HANGUP
| PA_IO_EVENT_ERROR
;
101 /* pa_io_event_cb_t IO event handler */
102 static void handle_io_event(pa_mainloop_api
*ea
, pa_io_event
*e
, int fd
, pa_io_event_flags_t events
, void *userdata
) {
103 unsigned int flags
= 0;
104 DBusWatch
*watch
= userdata
;
106 #if HAVE_DBUS_WATCH_GET_UNIX_FD
107 pa_assert(fd
== dbus_watch_get_unix_fd(watch
));
109 pa_assert(fd
== dbus_watch_get_fd(watch
));
112 if (!dbus_watch_get_enabled(watch
)) {
113 pa_log_warn("Asked to handle disabled watch: %p %i", (void*) watch
, fd
);
117 if (events
& PA_IO_EVENT_INPUT
)
118 flags
|= DBUS_WATCH_READABLE
;
119 if (events
& PA_IO_EVENT_OUTPUT
)
120 flags
|= DBUS_WATCH_WRITABLE
;
121 if (events
& PA_IO_EVENT_HANGUP
)
122 flags
|= DBUS_WATCH_HANGUP
;
123 if (events
& PA_IO_EVENT_ERROR
)
124 flags
|= DBUS_WATCH_ERROR
;
126 dbus_watch_handle(watch
, flags
);
129 /* pa_time_event_cb_t timer event handler */
130 static void handle_time_event(pa_mainloop_api
*ea
, pa_time_event
* e
, const struct timeval
*t
, void *userdata
) {
132 struct timeout_data
*d
= userdata
;
137 if (dbus_timeout_get_enabled(d
->timeout
)) {
138 dbus_timeout_handle(d
->timeout
);
140 /* restart it for the next scheduled time */
141 ea
->time_restart(e
, pa_timeval_rtstore(&tv
, pa_timeval_load(t
) + dbus_timeout_get_interval(d
->timeout
) * PA_USEC_PER_MSEC
, d
->c
->use_rtclock
));
145 /* DBusAddWatchFunction callback for pa mainloop */
146 static dbus_bool_t
add_watch(DBusWatch
*watch
, void *data
) {
147 pa_dbus_wrap_connection
*c
= data
;
153 ev
= c
->mainloop
->io_new(
155 #if HAVE_DBUS_WATCH_GET_UNIX_FD
156 dbus_watch_get_unix_fd(watch
),
158 dbus_watch_get_fd(watch
),
160 get_watch_flags(watch
), handle_io_event
, watch
);
162 dbus_watch_set_data(watch
, ev
, NULL
);
167 /* DBusRemoveWatchFunction callback for pa mainloop */
168 static void remove_watch(DBusWatch
*watch
, void *data
) {
169 pa_dbus_wrap_connection
*c
= data
;
175 if ((ev
= dbus_watch_get_data(watch
)))
176 c
->mainloop
->io_free(ev
);
179 /* DBusWatchToggledFunction callback for pa mainloop */
180 static void toggle_watch(DBusWatch
*watch
, void *data
) {
181 pa_dbus_wrap_connection
*c
= data
;
187 pa_assert_se(ev
= dbus_watch_get_data(watch
));
189 /* get_watch_flags() checks if the watch is enabled */
190 c
->mainloop
->io_enable(ev
, get_watch_flags(watch
));
193 static void time_event_destroy_cb(pa_mainloop_api
*a
, pa_time_event
*e
, void *userdata
) {
197 /* DBusAddTimeoutFunction callback for pa mainloop */
198 static dbus_bool_t
add_timeout(DBusTimeout
*timeout
, void *data
) {
199 pa_dbus_wrap_connection
*c
= data
;
202 struct timeout_data
*d
;
207 if (!dbus_timeout_get_enabled(timeout
))
210 d
= pa_xnew(struct timeout_data
, 1);
212 d
->timeout
= timeout
;
213 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
);
214 c
->mainloop
->time_set_destroy(ev
, time_event_destroy_cb
);
216 dbus_timeout_set_data(timeout
, ev
, NULL
);
221 /* DBusRemoveTimeoutFunction callback for pa mainloop */
222 static void remove_timeout(DBusTimeout
*timeout
, void *data
) {
223 pa_dbus_wrap_connection
*c
= data
;
229 if ((ev
= dbus_timeout_get_data(timeout
)))
230 c
->mainloop
->time_free(ev
);
233 /* DBusTimeoutToggledFunction callback for pa mainloop */
234 static void toggle_timeout(DBusTimeout
*timeout
, void *data
) {
235 struct timeout_data
*d
= data
;
243 pa_assert_se(ev
= dbus_timeout_get_data(timeout
));
245 if (dbus_timeout_get_enabled(timeout
)) {
246 d
->c
->mainloop
->time_restart(ev
, pa_timeval_rtstore(&tv
, pa_rtclock_now() + dbus_timeout_get_interval(timeout
) * PA_USEC_PER_MSEC
, d
->c
->use_rtclock
));
248 d
->c
->mainloop
->time_restart(ev
, pa_timeval_rtstore(&tv
, PA_USEC_INVALID
, d
->c
->use_rtclock
));
251 static void wakeup_main(void *userdata
) {
252 pa_dbus_wrap_connection
*c
= userdata
;
256 /* this will wakeup the mainloop and dispatch events, although
257 * it may not be the cleanest way of accomplishing it */
258 c
->mainloop
->defer_enable(c
->dispatch_event
, 1);
261 pa_dbus_wrap_connection
* pa_dbus_wrap_connection_new(pa_mainloop_api
*m
, pa_bool_t use_rtclock
, DBusBusType type
, DBusError
*error
) {
262 DBusConnection
*conn
;
263 pa_dbus_wrap_connection
*pconn
;
266 pa_assert(type
== DBUS_BUS_SYSTEM
|| type
== DBUS_BUS_SESSION
|| type
== DBUS_BUS_STARTER
);
268 if (!(conn
= dbus_bus_get_private(type
, error
)))
271 pconn
= pa_xnew(pa_dbus_wrap_connection
, 1);
273 pconn
->connection
= conn
;
274 pconn
->use_rtclock
= use_rtclock
;
276 dbus_connection_set_exit_on_disconnect(conn
, FALSE
);
277 dbus_connection_set_dispatch_status_function(conn
, dispatch_status
, pconn
, NULL
);
278 dbus_connection_set_watch_functions(conn
, add_watch
, remove_watch
, toggle_watch
, pconn
, NULL
);
279 dbus_connection_set_timeout_functions(conn
, add_timeout
, remove_timeout
, toggle_timeout
, pconn
, NULL
);
280 dbus_connection_set_wakeup_main_function(conn
, wakeup_main
, pconn
, NULL
);
282 pconn
->dispatch_event
= pconn
->mainloop
->defer_new(pconn
->mainloop
, dispatch_cb
, conn
);
284 pa_log_debug("Successfully connected to D-Bus %s bus %s as %s",
285 type
== DBUS_BUS_SYSTEM
? "system" : (type
== DBUS_BUS_SESSION
? "session" : "starter"),
286 pa_strnull((id
= dbus_connection_get_server_id(conn
))),
287 pa_strnull(dbus_bus_get_unique_name(conn
)));
294 pa_dbus_wrap_connection
* pa_dbus_wrap_connection_new_from_existing(pa_mainloop_api
*m
, pa_bool_t use_rtclock
, DBusConnection
*conn
) {
295 pa_dbus_wrap_connection
*pconn
;
300 pconn
= pa_xnew(pa_dbus_wrap_connection
, 1);
302 pconn
->connection
= dbus_connection_ref(conn
);
303 pconn
->use_rtclock
= use_rtclock
;
305 dbus_connection_set_exit_on_disconnect(conn
, FALSE
);
306 dbus_connection_set_dispatch_status_function(conn
, dispatch_status
, pconn
, NULL
);
307 dbus_connection_set_watch_functions(conn
, add_watch
, remove_watch
, toggle_watch
, pconn
, NULL
);
308 dbus_connection_set_timeout_functions(conn
, add_timeout
, remove_timeout
, toggle_timeout
, pconn
, NULL
);
309 dbus_connection_set_wakeup_main_function(conn
, wakeup_main
, pconn
, NULL
);
311 pconn
->dispatch_event
= pconn
->mainloop
->defer_new(pconn
->mainloop
, dispatch_cb
, conn
);
316 void pa_dbus_wrap_connection_free(pa_dbus_wrap_connection
* c
) {
319 if (dbus_connection_get_is_connected(c
->connection
)) {
320 dbus_connection_close(c
->connection
);
321 /* must process remaining messages, bit of a kludge to handle
322 * both unload and shutdown */
323 while (dbus_connection_read_write_dispatch(c
->connection
, -1))
327 c
->mainloop
->defer_free(c
->dispatch_event
);
328 dbus_connection_unref(c
->connection
);
332 DBusConnection
* pa_dbus_wrap_connection_get(pa_dbus_wrap_connection
*c
) {
334 pa_assert(c
->connection
);
336 return c
->connection
;
339 int pa_dbus_add_matches(DBusConnection
*c
, DBusError
*error
, ...) {
348 while ((t
= va_arg(ap
, const char*))) {
349 dbus_bus_add_match(c
, t
, error
);
351 if (dbus_error_is_set(error
))
366 pa_assert_se(t
= va_arg(ap
, const char*));
369 dbus_bus_remove_match(c
, t
, &e
);
377 void pa_dbus_remove_matches(DBusConnection
*c
, ...) {
384 dbus_error_init(&error
);
387 while ((t
= va_arg(ap
, const char*))) {
388 dbus_bus_remove_match(c
, t
, &error
);
389 dbus_error_free(&error
);
394 pa_dbus_pending
*pa_dbus_pending_new(
397 DBusPendingCall
*pending
,
405 p
= pa_xnew(pa_dbus_pending
, 1);
408 p
->pending
= pending
;
409 p
->context_data
= context_data
;
410 p
->call_data
= call_data
;
412 PA_LLIST_INIT(pa_dbus_pending
, p
);
417 void pa_dbus_pending_free(pa_dbus_pending
*p
) {
421 dbus_pending_call_cancel(p
->pending
);
422 dbus_pending_call_unref(p
->pending
);
426 dbus_message_unref(p
->message
);
431 void pa_dbus_sync_pending_list(pa_dbus_pending
**p
) {
434 while (*p
&& dbus_connection_read_write_dispatch((*p
)->connection
, -1))
438 void pa_dbus_free_pending_list(pa_dbus_pending
**p
) {
444 PA_LLIST_REMOVE(pa_dbus_pending
, *p
, i
);
445 pa_dbus_pending_free(i
);
449 void pa_dbus_send_error(DBusConnection
*c
, DBusMessage
*in_reply_to
, const char *name
, const char *message
) {
450 DBusMessage
*reply
= NULL
;
453 pa_assert(in_reply_to
);
457 pa_assert_se((reply
= dbus_message_new_error(in_reply_to
, name
, message
)));
458 pa_assert_se(dbus_connection_send(c
, reply
, NULL
));
460 dbus_message_unref(reply
);
463 void pa_dbus_send_empty_reply(DBusConnection
*c
, DBusMessage
*in_reply_to
) {
464 DBusMessage
*reply
= NULL
;
467 pa_assert(in_reply_to
);
469 pa_assert_se((reply
= dbus_message_new_method_return(in_reply_to
)));
470 pa_assert_se(dbus_connection_send(c
, reply
, NULL
));
471 dbus_message_unref(reply
);
474 void pa_dbus_send_basic_value_reply(DBusConnection
*c
, DBusMessage
*in_reply_to
, int type
, void *data
) {
475 DBusMessage
*reply
= NULL
;
478 pa_assert(in_reply_to
);
479 pa_assert(dbus_type_is_basic(type
));
482 pa_assert_se((reply
= dbus_message_new_method_return(in_reply_to
)));
483 pa_assert_se(dbus_message_append_args(reply
, type
, data
, DBUS_TYPE_INVALID
));
484 pa_assert_se(dbus_connection_send(c
, reply
, NULL
));
485 dbus_message_unref(reply
);
488 static const char *signature_from_basic_type(int type
) {
490 case DBUS_TYPE_BOOLEAN
: return DBUS_TYPE_BOOLEAN_AS_STRING
;
491 case DBUS_TYPE_BYTE
: return DBUS_TYPE_BYTE_AS_STRING
;
492 case DBUS_TYPE_INT16
: return DBUS_TYPE_INT16_AS_STRING
;
493 case DBUS_TYPE_UINT16
: return DBUS_TYPE_UINT16_AS_STRING
;
494 case DBUS_TYPE_INT32
: return DBUS_TYPE_INT32_AS_STRING
;
495 case DBUS_TYPE_UINT32
: return DBUS_TYPE_UINT32_AS_STRING
;
496 case DBUS_TYPE_INT64
: return DBUS_TYPE_INT64_AS_STRING
;
497 case DBUS_TYPE_UINT64
: return DBUS_TYPE_UINT64_AS_STRING
;
498 case DBUS_TYPE_DOUBLE
: return DBUS_TYPE_DOUBLE_AS_STRING
;
499 case DBUS_TYPE_STRING
: return DBUS_TYPE_STRING_AS_STRING
;
500 case DBUS_TYPE_OBJECT_PATH
: return DBUS_TYPE_OBJECT_PATH_AS_STRING
;
501 case DBUS_TYPE_SIGNATURE
: return DBUS_TYPE_SIGNATURE_AS_STRING
;
502 default: pa_assert_not_reached();
506 void pa_dbus_send_basic_variant_reply(DBusConnection
*c
, DBusMessage
*in_reply_to
, int type
, void *data
) {
507 DBusMessage
*reply
= NULL
;
508 DBusMessageIter msg_iter
;
509 DBusMessageIter variant_iter
;
512 pa_assert(in_reply_to
);
513 pa_assert(dbus_type_is_basic(type
));
516 pa_assert_se((reply
= dbus_message_new_method_return(in_reply_to
)));
517 dbus_message_iter_init_append(reply
, &msg_iter
);
518 pa_assert_se(dbus_message_iter_open_container(&msg_iter
, DBUS_TYPE_VARIANT
, signature_from_basic_type(type
), &variant_iter
));
519 pa_assert_se(dbus_message_iter_append_basic(&variant_iter
, type
, data
));
520 pa_assert_se(dbus_message_iter_close_container(&msg_iter
, &variant_iter
));
521 pa_assert_se(dbus_connection_send(c
, reply
, NULL
));
522 dbus_message_unref(reply
);
525 /* Note: returns sizeof(char*) for strings, object paths and signatures. */
526 static unsigned basic_type_size(int type
) {
528 case DBUS_TYPE_BOOLEAN
: return sizeof(dbus_bool_t
);
529 case DBUS_TYPE_BYTE
: return 1;
530 case DBUS_TYPE_INT16
: return sizeof(dbus_int16_t
);
531 case DBUS_TYPE_UINT16
: return sizeof(dbus_uint16_t
);
532 case DBUS_TYPE_INT32
: return sizeof(dbus_int32_t
);
533 case DBUS_TYPE_UINT32
: return sizeof(dbus_uint32_t
);
534 case DBUS_TYPE_INT64
: return sizeof(dbus_int64_t
);
535 case DBUS_TYPE_UINT64
: return sizeof(dbus_uint64_t
);
536 case DBUS_TYPE_DOUBLE
: return sizeof(double);
537 case DBUS_TYPE_STRING
:
538 case DBUS_TYPE_OBJECT_PATH
:
539 case DBUS_TYPE_SIGNATURE
: return sizeof(char*);
540 default: pa_assert_not_reached();
544 void pa_dbus_send_basic_array_variant_reply(DBusConnection
*c
, DBusMessage
*in_reply_to
, int item_type
, void *array
, unsigned n
) {
545 DBusMessage
*reply
= NULL
;
546 DBusMessageIter msg_iter
;
549 pa_assert(in_reply_to
);
550 pa_assert(dbus_type_is_basic(item_type
));
551 pa_assert(array
|| n
== 0);
553 pa_assert_se((reply
= dbus_message_new_method_return(in_reply_to
)));
554 dbus_message_iter_init_append(reply
, &msg_iter
);
555 pa_dbus_append_basic_array_variant(&msg_iter
, item_type
, array
, n
);
556 pa_assert_se(dbus_connection_send(c
, reply
, NULL
));
557 dbus_message_unref(reply
);
560 void pa_dbus_append_basic_array(DBusMessageIter
*iter
, int item_type
, const void *array
, unsigned n
) {
561 DBusMessageIter array_iter
;
566 pa_assert(dbus_type_is_basic(item_type
));
567 pa_assert(array
|| n
== 0);
569 item_size
= basic_type_size(item_type
);
571 pa_assert_se(dbus_message_iter_open_container(iter
, DBUS_TYPE_ARRAY
, signature_from_basic_type(item_type
), &array_iter
));
573 for (i
= 0; i
< n
; ++i
)
574 pa_assert_se(dbus_message_iter_append_basic(&array_iter
, item_type
, &((uint8_t*) array
)[i
* item_size
]));
576 pa_assert_se(dbus_message_iter_close_container(iter
, &array_iter
));
579 void pa_dbus_append_basic_variant(DBusMessageIter
*iter
, int type
, void *data
) {
580 DBusMessageIter variant_iter
;
583 pa_assert(dbus_type_is_basic(type
));
586 pa_assert_se(dbus_message_iter_open_container(iter
, DBUS_TYPE_VARIANT
, signature_from_basic_type(type
), &variant_iter
));
587 pa_assert_se(dbus_message_iter_append_basic(&variant_iter
, type
, data
));
588 pa_assert_se(dbus_message_iter_close_container(iter
, &variant_iter
));
591 void pa_dbus_append_basic_array_variant(DBusMessageIter
*iter
, int item_type
, const void *array
, unsigned n
) {
592 DBusMessageIter variant_iter
;
593 char *array_signature
;
596 pa_assert(dbus_type_is_basic(item_type
));
597 pa_assert(array
|| n
== 0);
599 array_signature
= pa_sprintf_malloc("a%c", *signature_from_basic_type(item_type
));
601 pa_assert_se(dbus_message_iter_open_container(iter
, DBUS_TYPE_VARIANT
, array_signature
, &variant_iter
));
602 pa_dbus_append_basic_array(&variant_iter
, item_type
, array
, n
);
603 pa_assert_se(dbus_message_iter_close_container(iter
, &variant_iter
));
605 pa_xfree(array_signature
);
608 void pa_dbus_append_basic_variant_dict_entry(DBusMessageIter
*dict_iter
, const char *key
, int type
, void *data
) {
609 DBusMessageIter dict_entry_iter
;
611 pa_assert(dict_iter
);
613 pa_assert(dbus_type_is_basic(type
));
616 pa_assert_se(dbus_message_iter_open_container(dict_iter
, DBUS_TYPE_DICT_ENTRY
, NULL
, &dict_entry_iter
));
617 pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter
, DBUS_TYPE_STRING
, &key
));
618 pa_dbus_append_basic_variant(&dict_entry_iter
, type
, data
);
619 pa_assert_se(dbus_message_iter_close_container(dict_iter
, &dict_entry_iter
));
622 void pa_dbus_append_basic_array_variant_dict_entry(DBusMessageIter
*dict_iter
, const char *key
, int item_type
, const void *array
, unsigned n
) {
623 DBusMessageIter dict_entry_iter
;
625 pa_assert(dict_iter
);
627 pa_assert(dbus_type_is_basic(item_type
));
628 pa_assert(array
|| n
== 0);
630 pa_assert_se(dbus_message_iter_open_container(dict_iter
, DBUS_TYPE_DICT_ENTRY
, NULL
, &dict_entry_iter
));
631 pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter
, DBUS_TYPE_STRING
, &key
));
632 pa_dbus_append_basic_array_variant(&dict_entry_iter
, item_type
, array
, n
);
633 pa_assert_se(dbus_message_iter_close_container(dict_iter
, &dict_entry_iter
));
636 int pa_dbus_get_basic_set_property_arg(DBusConnection
*c
, DBusMessage
*msg
, int type
, void *data
) {
637 DBusMessageIter msg_iter
;
638 DBusMessageIter variant_iter
;
642 pa_assert(dbus_type_is_basic(type
));
645 /* Skip the interface and property name arguments. */
646 if (!dbus_message_iter_init(msg
, &msg_iter
) || !dbus_message_iter_next(&msg_iter
) || !dbus_message_iter_next(&msg_iter
)) {
647 pa_dbus_send_error(c
, msg
, DBUS_ERROR_INVALID_ARGS
, "Too few arguments.");
651 if (dbus_message_iter_get_arg_type(&msg_iter
) != DBUS_TYPE_VARIANT
) {
652 pa_dbus_send_error(c
, msg
, DBUS_ERROR_INVALID_ARGS
, "Message argument isn't a variant.");
656 dbus_message_iter_recurse(&msg_iter
, &variant_iter
);
658 if (dbus_message_iter_get_arg_type(&variant_iter
) != type
) {
659 pa_dbus_send_error(c
, msg
, DBUS_ERROR_INVALID_ARGS
, "Variant has wrong contained type.");
663 dbus_message_iter_get_basic(&variant_iter
, data
);
668 int pa_dbus_get_basic_arg(DBusConnection
*c
, DBusMessage
*msg
, DBusMessageIter
*iter
, int type
, void *data
) {
672 pa_assert(dbus_type_is_basic(type
));
675 if (dbus_message_iter_get_arg_type(iter
) != type
) {
676 pa_dbus_send_error(c
, msg
, DBUS_ERROR_INVALID_ARGS
, "Wrong argument type or too few arguments.");
680 dbus_message_iter_get_basic(iter
, data
);
685 int pa_dbus_get_fixed_array_arg(DBusConnection
*c
, DBusMessage
*msg
, DBusMessageIter
*iter
, int item_type
, void *array
, unsigned *n
) {
686 DBusMessageIter array_iter
;
692 pa_assert(dbus_type_is_fixed(item_type
));
696 if (dbus_message_iter_get_arg_type(iter
) != DBUS_TYPE_ARRAY
) {
697 pa_dbus_send_error(c
, msg
, DBUS_ERROR_INVALID_ARGS
, "Wrong argument type or too few arguments. An array was expected.");
701 if (dbus_message_iter_get_element_type(iter
) != item_type
) {
702 pa_dbus_send_error(c
, msg
, DBUS_ERROR_INVALID_ARGS
, "Wrong array element type.");
706 dbus_message_iter_recurse(iter
, &array_iter
);
708 dbus_message_iter_get_fixed_array(&array_iter
, array
, &signed_n
);
710 pa_assert(signed_n
>= 0);
717 pa_proplist
*pa_dbus_get_proplist_arg(DBusConnection
*c
, DBusMessage
*msg
, DBusMessageIter
*iter
) {
718 DBusMessageIter dict_iter
;
719 pa_proplist
*proplist
= NULL
;
721 const uint8_t *value
;
728 if (dbus_message_iter_get_arg_type(iter
) != DBUS_TYPE_ARRAY
) {
729 pa_dbus_send_error(c
, msg
, DBUS_ERROR_INVALID_ARGS
, "Wrong argument type or too few arguments. An array was expected.");
733 if (dbus_message_iter_get_element_type(iter
) != DBUS_TYPE_DICT_ENTRY
) {
734 pa_dbus_send_error(c
, msg
, DBUS_ERROR_INVALID_ARGS
, "Wrong array element type. A dict entry was expected.");
738 proplist
= pa_proplist_new();
740 dbus_message_iter_recurse(iter
, &dict_iter
);
742 while (dbus_message_iter_has_next(&dict_iter
)) {
743 if (dbus_message_iter_get_arg_type(&dict_iter
) != DBUS_TYPE_STRING
) {
744 pa_dbus_send_error(c
, msg
, DBUS_ERROR_INVALID_ARGS
, "Wrong dict key type. A string was expected.");
748 dbus_message_iter_get_basic(&dict_iter
, &key
);
750 if (strlen(key
) <= 0 || !pa_ascii_valid(key
)) {
751 pa_dbus_send_error(c
, msg
, DBUS_ERROR_INVALID_ARGS
, "Invalid property list key.");
755 if (dbus_message_iter_get_arg_type(&dict_iter
) != DBUS_TYPE_ARRAY
) {
756 pa_dbus_send_error(c
, msg
, DBUS_ERROR_INVALID_ARGS
, "Wrong dict value type. An array was expected.");
760 if (dbus_message_iter_get_element_type(&dict_iter
) != DBUS_TYPE_BYTE
) {
761 pa_dbus_send_error(c
, msg
, DBUS_ERROR_INVALID_ARGS
, "Wrong dict value item type. A byte was expected.");
765 dbus_message_iter_get_fixed_array(&dict_iter
, &value
, &value_length
);
767 pa_assert(value_length
>= 0);
769 pa_assert_se(pa_proplist_set(proplist
, key
, value
, value_length
) >= 0);
776 pa_proplist_free(proplist
);