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/xmalloc.h>
33 #include <pulsecore/core-rtclock.h>
34 #include <pulsecore/core-util.h>
35 #include <pulsecore/log.h>
37 #include "dbus-util.h"
39 struct pa_dbus_wrap_connection
{
40 pa_mainloop_api
*mainloop
;
41 DBusConnection
*connection
;
42 pa_defer_event
* dispatch_event
;
43 pa_bool_t use_rtclock
:1;
47 pa_dbus_wrap_connection
*c
;
51 static void dispatch_cb(pa_mainloop_api
*ea
, pa_defer_event
*ev
, void *userdata
) {
52 DBusConnection
*conn
= userdata
;
54 if (dbus_connection_dispatch(conn
) == DBUS_DISPATCH_COMPLETE
) {
55 /* no more data to process, disable the deferred */
56 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
;
136 if (dbus_timeout_get_enabled(d
->timeout
)) {
137 dbus_timeout_handle(d
->timeout
);
139 /* restart it for the next scheduled time */
140 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
));
144 /* DBusAddWatchFunction callback for pa mainloop */
145 static dbus_bool_t
add_watch(DBusWatch
*watch
, void *data
) {
146 pa_dbus_wrap_connection
*c
= data
;
152 ev
= c
->mainloop
->io_new(
154 #if HAVE_DBUS_WATCH_GET_UNIX_FD
155 dbus_watch_get_unix_fd(watch
),
157 dbus_watch_get_fd(watch
),
159 get_watch_flags(watch
), handle_io_event
, watch
);
161 dbus_watch_set_data(watch
, ev
, NULL
);
166 /* DBusRemoveWatchFunction callback for pa mainloop */
167 static void remove_watch(DBusWatch
*watch
, void *data
) {
168 pa_dbus_wrap_connection
*c
= data
;
174 if ((ev
= dbus_watch_get_data(watch
)))
175 c
->mainloop
->io_free(ev
);
178 /* DBusWatchToggledFunction callback for pa mainloop */
179 static void toggle_watch(DBusWatch
*watch
, void *data
) {
180 pa_dbus_wrap_connection
*c
= data
;
186 pa_assert_se(ev
= dbus_watch_get_data(watch
));
188 /* get_watch_flags() checks if the watch is enabled */
189 c
->mainloop
->io_enable(ev
, get_watch_flags(watch
));
192 static void time_event_destroy_cb(pa_mainloop_api
*a
, pa_time_event
*e
, void *userdata
) {
196 /* DBusAddTimeoutFunction callback for pa mainloop */
197 static dbus_bool_t
add_timeout(DBusTimeout
*timeout
, void *data
) {
198 pa_dbus_wrap_connection
*c
= data
;
201 struct timeout_data
*d
;
206 if (!dbus_timeout_get_enabled(timeout
))
209 d
= pa_xnew(struct timeout_data
, 1);
211 d
->timeout
= timeout
;
212 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
);
213 c
->mainloop
->time_set_destroy(ev
, time_event_destroy_cb
);
215 dbus_timeout_set_data(timeout
, ev
, NULL
);
220 /* DBusRemoveTimeoutFunction callback for pa mainloop */
221 static void remove_timeout(DBusTimeout
*timeout
, void *data
) {
222 pa_dbus_wrap_connection
*c
= data
;
228 if ((ev
= dbus_timeout_get_data(timeout
)))
229 c
->mainloop
->time_free(ev
);
232 /* DBusTimeoutToggledFunction callback for pa mainloop */
233 static void toggle_timeout(DBusTimeout
*timeout
, void *data
) {
234 struct timeout_data
*d
= data
;
242 pa_assert_se(ev
= dbus_timeout_get_data(timeout
));
244 if (dbus_timeout_get_enabled(timeout
)) {
245 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
));
247 d
->c
->mainloop
->time_restart(ev
, pa_timeval_rtstore(&tv
, PA_USEC_INVALID
, d
->c
->use_rtclock
));
250 static void wakeup_main(void *userdata
) {
251 pa_dbus_wrap_connection
*c
= userdata
;
255 /* this will wakeup the mainloop and dispatch events, although
256 * it may not be the cleanest way of accomplishing it */
257 c
->mainloop
->defer_enable(c
->dispatch_event
, 1);
260 pa_dbus_wrap_connection
* pa_dbus_wrap_connection_new(pa_mainloop_api
*m
, pa_bool_t use_rtclock
, DBusBusType type
, DBusError
*error
) {
261 DBusConnection
*conn
;
262 pa_dbus_wrap_connection
*pconn
;
265 pa_assert(type
== DBUS_BUS_SYSTEM
|| type
== DBUS_BUS_SESSION
|| type
== DBUS_BUS_STARTER
);
267 if (!(conn
= dbus_bus_get_private(type
, error
)))
270 pconn
= pa_xnew(pa_dbus_wrap_connection
, 1);
272 pconn
->connection
= conn
;
273 pconn
->use_rtclock
= use_rtclock
;
275 dbus_connection_set_exit_on_disconnect(conn
, FALSE
);
276 dbus_connection_set_dispatch_status_function(conn
, dispatch_status
, pconn
, NULL
);
277 dbus_connection_set_watch_functions(conn
, add_watch
, remove_watch
, toggle_watch
, pconn
, NULL
);
278 dbus_connection_set_timeout_functions(conn
, add_timeout
, remove_timeout
, toggle_timeout
, pconn
, NULL
);
279 dbus_connection_set_wakeup_main_function(conn
, wakeup_main
, pconn
, NULL
);
281 pconn
->dispatch_event
= pconn
->mainloop
->defer_new(pconn
->mainloop
, dispatch_cb
, conn
);
283 pa_log_debug("Successfully connected to D-Bus %s bus %s as %s",
284 type
== DBUS_BUS_SYSTEM
? "system" : (type
== DBUS_BUS_SESSION
? "session" : "starter"),
285 pa_strnull((id
= dbus_connection_get_server_id(conn
))),
286 pa_strnull(dbus_bus_get_unique_name(conn
)));
293 void pa_dbus_wrap_connection_free(pa_dbus_wrap_connection
* c
) {
296 if (dbus_connection_get_is_connected(c
->connection
)) {
297 dbus_connection_close(c
->connection
);
298 /* must process remaining messages, bit of a kludge to handle
299 * both unload and shutdown */
300 while (dbus_connection_read_write_dispatch(c
->connection
, -1))
304 c
->mainloop
->defer_free(c
->dispatch_event
);
305 dbus_connection_unref(c
->connection
);
309 DBusConnection
* pa_dbus_wrap_connection_get(pa_dbus_wrap_connection
*c
) {
311 pa_assert(c
->connection
);
313 return c
->connection
;
316 int pa_dbus_add_matches(DBusConnection
*c
, DBusError
*error
, ...) {
325 while ((t
= va_arg(ap
, const char*))) {
326 dbus_bus_add_match(c
, t
, error
);
328 if (dbus_error_is_set(error
))
343 pa_assert_se(t
= va_arg(ap
, const char*));
346 dbus_bus_remove_match(c
, t
, &e
);
354 void pa_dbus_remove_matches(DBusConnection
*c
, ...) {
361 dbus_error_init(&error
);
364 while ((t
= va_arg(ap
, const char*))) {
365 dbus_bus_remove_match(c
, t
, &error
);
366 dbus_error_free(&error
);
371 pa_dbus_pending
*pa_dbus_pending_new(
374 DBusPendingCall
*pending
,
382 p
= pa_xnew(pa_dbus_pending
, 1);
385 p
->pending
= pending
;
386 p
->context_data
= context_data
;
387 p
->call_data
= call_data
;
389 PA_LLIST_INIT(pa_dbus_pending
, p
);
394 void pa_dbus_pending_free(pa_dbus_pending
*p
) {
398 dbus_pending_call_cancel(p
->pending
);
399 dbus_pending_call_unref(p
->pending
);
403 dbus_message_unref(p
->message
);
408 void pa_dbus_sync_pending_list(pa_dbus_pending
**p
) {
411 while (*p
&& dbus_connection_read_write_dispatch((*p
)->connection
, -1))
415 void pa_dbus_free_pending_list(pa_dbus_pending
**p
) {
421 PA_LLIST_REMOVE(pa_dbus_pending
, *p
, i
);
422 pa_dbus_pending_free(i
);