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/xmalloc.h>
30 #include <pulse/timeval.h>
31 #include <pulsecore/log.h>
33 #include "dbus-util.h"
35 struct pa_dbus_wrap_connection
{
36 pa_mainloop_api
*mainloop
;
37 DBusConnection
*connection
;
38 pa_defer_event
* dispatch_event
;
41 static void dispatch_cb(pa_mainloop_api
*ea
, pa_defer_event
*ev
, void *userdata
) {
42 DBusConnection
*conn
= userdata
;
44 if (dbus_connection_dispatch(conn
) == DBUS_DISPATCH_COMPLETE
) {
45 /* no more data to process, disable the deferred */
46 ea
->defer_enable(ev
, 0);
50 /* DBusDispatchStatusFunction callback for the pa mainloop */
51 static void dispatch_status(DBusConnection
*conn
, DBusDispatchStatus status
, void *userdata
) {
52 pa_dbus_wrap_connection
*c
= userdata
;
58 case DBUS_DISPATCH_COMPLETE
:
59 c
->mainloop
->defer_enable(c
->dispatch_event
, 0);
62 case DBUS_DISPATCH_DATA_REMAINS
:
63 case DBUS_DISPATCH_NEED_MEMORY
:
65 c
->mainloop
->defer_enable(c
->dispatch_event
, 1);
70 static pa_io_event_flags_t
get_watch_flags(DBusWatch
*watch
) {
72 pa_io_event_flags_t events
= 0;
76 flags
= dbus_watch_get_flags(watch
);
78 /* no watch flags for disabled watches */
79 if (!dbus_watch_get_enabled(watch
))
80 return PA_IO_EVENT_NULL
;
82 if (flags
& DBUS_WATCH_READABLE
)
83 events
|= PA_IO_EVENT_INPUT
;
84 if (flags
& DBUS_WATCH_WRITABLE
)
85 events
|= PA_IO_EVENT_OUTPUT
;
87 return events
| PA_IO_EVENT_HANGUP
| PA_IO_EVENT_ERROR
;
90 /* pa_io_event_cb_t IO event handler */
91 static void handle_io_event(pa_mainloop_api
*ea
, pa_io_event
*e
, int fd
, pa_io_event_flags_t events
, void *userdata
) {
92 unsigned int flags
= 0;
93 DBusWatch
*watch
= userdata
;
95 #if HAVE_DBUS_WATCH_GET_UNIX_FD
96 pa_assert(fd
== dbus_watch_get_unix_fd(watch
));
98 pa_assert(fd
== dbus_watch_get_fd(watch
));
101 if (!dbus_watch_get_enabled(watch
)) {
102 pa_log_warn("Asked to handle disabled watch: %p %i", (void*) watch
, fd
);
106 if (events
& PA_IO_EVENT_INPUT
)
107 flags
|= DBUS_WATCH_READABLE
;
108 if (events
& PA_IO_EVENT_OUTPUT
)
109 flags
|= DBUS_WATCH_WRITABLE
;
110 if (events
& PA_IO_EVENT_HANGUP
)
111 flags
|= DBUS_WATCH_HANGUP
;
112 if (events
& PA_IO_EVENT_ERROR
)
113 flags
|= DBUS_WATCH_ERROR
;
115 dbus_watch_handle(watch
, flags
);
118 /* pa_time_event_cb_t timer event handler */
119 static void handle_time_event(pa_mainloop_api
*ea
, pa_time_event
* e
, const struct timeval
*tv
, void *userdata
) {
120 DBusTimeout
*timeout
= userdata
;
122 if (dbus_timeout_get_enabled(timeout
)) {
123 struct timeval next
= *tv
;
124 dbus_timeout_handle(timeout
);
126 /* restart it for the next scheduled time */
127 pa_timeval_add(&next
, (pa_usec_t
) dbus_timeout_get_interval(timeout
) * 1000);
128 ea
->time_restart(e
, &next
);
132 /* DBusAddWatchFunction callback for pa mainloop */
133 static dbus_bool_t
add_watch(DBusWatch
*watch
, void *data
) {
134 pa_dbus_wrap_connection
*c
= data
;
140 ev
= c
->mainloop
->io_new(
142 #if HAVE_DBUS_WATCH_GET_UNIX_FD
143 dbus_watch_get_unix_fd(watch
),
145 dbus_watch_get_fd(watch
),
147 get_watch_flags(watch
), handle_io_event
, watch
);
149 dbus_watch_set_data(watch
, ev
, NULL
);
154 /* DBusRemoveWatchFunction callback for pa mainloop */
155 static void remove_watch(DBusWatch
*watch
, void *data
) {
156 pa_dbus_wrap_connection
*c
= data
;
162 if ((ev
= dbus_watch_get_data(watch
)))
163 c
->mainloop
->io_free(ev
);
166 /* DBusWatchToggledFunction callback for pa mainloop */
167 static void toggle_watch(DBusWatch
*watch
, void *data
) {
168 pa_dbus_wrap_connection
*c
= data
;
174 pa_assert_se(ev
= dbus_watch_get_data(watch
));
176 /* get_watch_flags() checks if the watch is enabled */
177 c
->mainloop
->io_enable(ev
, get_watch_flags(watch
));
180 /* DBusAddTimeoutFunction callback for pa mainloop */
181 static dbus_bool_t
add_timeout(DBusTimeout
*timeout
, void *data
) {
182 pa_dbus_wrap_connection
*c
= data
;
189 if (!dbus_timeout_get_enabled(timeout
))
192 pa_gettimeofday(&tv
);
193 pa_timeval_add(&tv
, (pa_usec_t
) dbus_timeout_get_interval(timeout
) * 1000);
195 ev
= c
->mainloop
->time_new(c
->mainloop
, &tv
, handle_time_event
, timeout
);
197 dbus_timeout_set_data(timeout
, ev
, NULL
);
202 /* DBusRemoveTimeoutFunction callback for pa mainloop */
203 static void remove_timeout(DBusTimeout
*timeout
, void *data
) {
204 pa_dbus_wrap_connection
*c
= data
;
210 if ((ev
= dbus_timeout_get_data(timeout
)))
211 c
->mainloop
->time_free(ev
);
214 /* DBusTimeoutToggledFunction callback for pa mainloop */
215 static void toggle_timeout(DBusTimeout
*timeout
, void *data
) {
216 pa_dbus_wrap_connection
*c
= data
;
222 pa_assert_se(ev
= dbus_timeout_get_data(timeout
));
224 if (dbus_timeout_get_enabled(timeout
)) {
227 pa_gettimeofday(&tv
);
228 pa_timeval_add(&tv
, (pa_usec_t
) dbus_timeout_get_interval(timeout
) * 1000);
230 c
->mainloop
->time_restart(ev
, &tv
);
232 c
->mainloop
->time_restart(ev
, NULL
);
235 static void wakeup_main(void *userdata
) {
236 pa_dbus_wrap_connection
*c
= userdata
;
240 /* this will wakeup the mainloop and dispatch events, although
241 * it may not be the cleanest way of accomplishing it */
242 c
->mainloop
->defer_enable(c
->dispatch_event
, 1);
245 pa_dbus_wrap_connection
* pa_dbus_wrap_connection_new(pa_mainloop_api
*m
, DBusBusType type
, DBusError
*error
) {
246 DBusConnection
*conn
;
247 pa_dbus_wrap_connection
*pconn
= NULL
;
249 pa_assert(type
== DBUS_BUS_SYSTEM
|| type
== DBUS_BUS_SESSION
|| type
== DBUS_BUS_STARTER
);
251 if (!(conn
= dbus_bus_get_private(type
, error
)))
254 pconn
= pa_xnew(pa_dbus_wrap_connection
, 1);
256 pconn
->connection
= conn
;
258 dbus_connection_set_exit_on_disconnect(conn
, FALSE
);
259 dbus_connection_set_dispatch_status_function(conn
, dispatch_status
, pconn
, NULL
);
260 dbus_connection_set_watch_functions(conn
, add_watch
, remove_watch
, toggle_watch
, pconn
, NULL
);
261 dbus_connection_set_timeout_functions(conn
, add_timeout
, remove_timeout
, toggle_timeout
, pconn
, NULL
);
262 dbus_connection_set_wakeup_main_function(conn
, wakeup_main
, pconn
, NULL
);
264 pconn
->dispatch_event
= pconn
->mainloop
->defer_new(pconn
->mainloop
, dispatch_cb
, conn
);
269 void pa_dbus_wrap_connection_free(pa_dbus_wrap_connection
* c
) {
272 if (dbus_connection_get_is_connected(c
->connection
)) {
273 dbus_connection_close(c
->connection
);
274 /* must process remaining messages, bit of a kludge to handle
275 * both unload and shutdown */
276 while (dbus_connection_read_write_dispatch(c
->connection
, -1));
279 c
->mainloop
->defer_free(c
->dispatch_event
);
280 dbus_connection_unref(c
->connection
);
284 DBusConnection
* pa_dbus_wrap_connection_get(pa_dbus_wrap_connection
*c
) {
286 pa_assert(c
->connection
);
288 return c
->connection
;
291 int pa_dbus_add_matches(DBusConnection
*c
, DBusError
*error
, ...) {
300 while ((t
= va_arg(ap
, const char*))) {
301 dbus_bus_add_match(c
, t
, error
);
303 if (dbus_error_is_set(error
))
318 pa_assert_se(t
= va_arg(ap
, const char*));
321 dbus_bus_remove_match(c
, t
, &e
);
329 void pa_dbus_remove_matches(DBusConnection
*c
, ...) {
336 dbus_error_init(&error
);
339 while ((t
= va_arg(ap
, const char*))) {
340 dbus_bus_remove_match(c
, t
, &error
);
341 dbus_error_free(&error
);
346 pa_dbus_pending
*pa_dbus_pending_new(
349 DBusPendingCall
*pending
,
357 p
= pa_xnew(pa_dbus_pending
, 1);
360 p
->pending
= pending
;
361 p
->context_data
= context_data
;
362 p
->call_data
= call_data
;
364 PA_LLIST_INIT(pa_dbus_pending
, p
);
369 void pa_dbus_pending_free(pa_dbus_pending
*p
) {
373 dbus_pending_call_cancel(p
->pending
); /* p->pending is freed by cancel() */
376 dbus_message_unref(p
->message
);
381 void pa_dbus_sync_pending_list(pa_dbus_pending
**p
) {
384 while (*p
&& dbus_connection_read_write_dispatch((*p
)->connection
, -1))
388 void pa_dbus_free_pending_list(pa_dbus_pending
**p
) {
394 PA_LLIST_REMOVE(pa_dbus_pending
, *p
, i
);
395 pa_dbus_pending_free(i
);