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>
32 #include <pulsecore/core-util.h>
33 #include <pulsecore/log.h>
35 #include "dbus-util.h"
37 struct pa_dbus_wrap_connection
{
38 pa_mainloop_api
*mainloop
;
39 DBusConnection
*connection
;
40 pa_defer_event
* dispatch_event
;
43 static void dispatch_cb(pa_mainloop_api
*ea
, pa_defer_event
*ev
, void *userdata
) {
44 DBusConnection
*conn
= userdata
;
46 if (dbus_connection_dispatch(conn
) == DBUS_DISPATCH_COMPLETE
) {
47 /* no more data to process, disable the deferred */
48 ea
->defer_enable(ev
, 0);
52 /* DBusDispatchStatusFunction callback for the pa mainloop */
53 static void dispatch_status(DBusConnection
*conn
, DBusDispatchStatus status
, void *userdata
) {
54 pa_dbus_wrap_connection
*c
= userdata
;
60 case DBUS_DISPATCH_COMPLETE
:
61 c
->mainloop
->defer_enable(c
->dispatch_event
, 0);
64 case DBUS_DISPATCH_DATA_REMAINS
:
65 case DBUS_DISPATCH_NEED_MEMORY
:
67 c
->mainloop
->defer_enable(c
->dispatch_event
, 1);
72 static pa_io_event_flags_t
get_watch_flags(DBusWatch
*watch
) {
74 pa_io_event_flags_t events
= 0;
78 flags
= dbus_watch_get_flags(watch
);
80 /* no watch flags for disabled watches */
81 if (!dbus_watch_get_enabled(watch
))
82 return PA_IO_EVENT_NULL
;
84 if (flags
& DBUS_WATCH_READABLE
)
85 events
|= PA_IO_EVENT_INPUT
;
86 if (flags
& DBUS_WATCH_WRITABLE
)
87 events
|= PA_IO_EVENT_OUTPUT
;
89 return events
| PA_IO_EVENT_HANGUP
| PA_IO_EVENT_ERROR
;
92 /* pa_io_event_cb_t IO event handler */
93 static void handle_io_event(pa_mainloop_api
*ea
, pa_io_event
*e
, int fd
, pa_io_event_flags_t events
, void *userdata
) {
94 unsigned int flags
= 0;
95 DBusWatch
*watch
= userdata
;
97 #if HAVE_DBUS_WATCH_GET_UNIX_FD
98 pa_assert(fd
== dbus_watch_get_unix_fd(watch
));
100 pa_assert(fd
== dbus_watch_get_fd(watch
));
103 if (!dbus_watch_get_enabled(watch
)) {
104 pa_log_warn("Asked to handle disabled watch: %p %i", (void*) watch
, fd
);
108 if (events
& PA_IO_EVENT_INPUT
)
109 flags
|= DBUS_WATCH_READABLE
;
110 if (events
& PA_IO_EVENT_OUTPUT
)
111 flags
|= DBUS_WATCH_WRITABLE
;
112 if (events
& PA_IO_EVENT_HANGUP
)
113 flags
|= DBUS_WATCH_HANGUP
;
114 if (events
& PA_IO_EVENT_ERROR
)
115 flags
|= DBUS_WATCH_ERROR
;
117 dbus_watch_handle(watch
, flags
);
120 /* pa_time_event_cb_t timer event handler */
121 static void handle_time_event(pa_mainloop_api
*ea
, pa_time_event
* e
, const struct timeval
*tv
, void *userdata
) {
122 DBusTimeout
*timeout
= userdata
;
124 if (dbus_timeout_get_enabled(timeout
)) {
125 struct timeval next
= *tv
;
126 dbus_timeout_handle(timeout
);
128 /* restart it for the next scheduled time */
129 pa_timeval_add(&next
, (pa_usec_t
) dbus_timeout_get_interval(timeout
) * 1000);
130 ea
->time_restart(e
, &next
);
134 /* DBusAddWatchFunction callback for pa mainloop */
135 static dbus_bool_t
add_watch(DBusWatch
*watch
, void *data
) {
136 pa_dbus_wrap_connection
*c
= data
;
142 ev
= c
->mainloop
->io_new(
144 #if HAVE_DBUS_WATCH_GET_UNIX_FD
145 dbus_watch_get_unix_fd(watch
),
147 dbus_watch_get_fd(watch
),
149 get_watch_flags(watch
), handle_io_event
, watch
);
151 dbus_watch_set_data(watch
, ev
, NULL
);
156 /* DBusRemoveWatchFunction callback for pa mainloop */
157 static void remove_watch(DBusWatch
*watch
, void *data
) {
158 pa_dbus_wrap_connection
*c
= data
;
164 if ((ev
= dbus_watch_get_data(watch
)))
165 c
->mainloop
->io_free(ev
);
168 /* DBusWatchToggledFunction callback for pa mainloop */
169 static void toggle_watch(DBusWatch
*watch
, void *data
) {
170 pa_dbus_wrap_connection
*c
= data
;
176 pa_assert_se(ev
= dbus_watch_get_data(watch
));
178 /* get_watch_flags() checks if the watch is enabled */
179 c
->mainloop
->io_enable(ev
, get_watch_flags(watch
));
182 /* DBusAddTimeoutFunction callback for pa mainloop */
183 static dbus_bool_t
add_timeout(DBusTimeout
*timeout
, void *data
) {
184 pa_dbus_wrap_connection
*c
= data
;
191 if (!dbus_timeout_get_enabled(timeout
))
194 pa_gettimeofday(&tv
);
195 pa_timeval_add(&tv
, (pa_usec_t
) dbus_timeout_get_interval(timeout
) * 1000);
197 ev
= c
->mainloop
->time_new(c
->mainloop
, &tv
, handle_time_event
, timeout
);
199 dbus_timeout_set_data(timeout
, ev
, NULL
);
204 /* DBusRemoveTimeoutFunction callback for pa mainloop */
205 static void remove_timeout(DBusTimeout
*timeout
, void *data
) {
206 pa_dbus_wrap_connection
*c
= data
;
212 if ((ev
= dbus_timeout_get_data(timeout
)))
213 c
->mainloop
->time_free(ev
);
216 /* DBusTimeoutToggledFunction callback for pa mainloop */
217 static void toggle_timeout(DBusTimeout
*timeout
, void *data
) {
218 pa_dbus_wrap_connection
*c
= data
;
224 pa_assert_se(ev
= dbus_timeout_get_data(timeout
));
226 if (dbus_timeout_get_enabled(timeout
)) {
229 pa_gettimeofday(&tv
);
230 pa_timeval_add(&tv
, (pa_usec_t
) dbus_timeout_get_interval(timeout
) * 1000);
232 c
->mainloop
->time_restart(ev
, &tv
);
234 c
->mainloop
->time_restart(ev
, NULL
);
237 static void wakeup_main(void *userdata
) {
238 pa_dbus_wrap_connection
*c
= userdata
;
242 /* this will wakeup the mainloop and dispatch events, although
243 * it may not be the cleanest way of accomplishing it */
244 c
->mainloop
->defer_enable(c
->dispatch_event
, 1);
247 pa_dbus_wrap_connection
* pa_dbus_wrap_connection_new(pa_mainloop_api
*m
, DBusBusType type
, DBusError
*error
) {
248 DBusConnection
*conn
;
249 pa_dbus_wrap_connection
*pconn
;
252 pa_assert(type
== DBUS_BUS_SYSTEM
|| type
== DBUS_BUS_SESSION
|| type
== DBUS_BUS_STARTER
);
254 if (!(conn
= dbus_bus_get_private(type
, error
)))
257 pconn
= pa_xnew(pa_dbus_wrap_connection
, 1);
259 pconn
->connection
= conn
;
261 dbus_connection_set_exit_on_disconnect(conn
, FALSE
);
262 dbus_connection_set_dispatch_status_function(conn
, dispatch_status
, pconn
, NULL
);
263 dbus_connection_set_watch_functions(conn
, add_watch
, remove_watch
, toggle_watch
, pconn
, NULL
);
264 dbus_connection_set_timeout_functions(conn
, add_timeout
, remove_timeout
, toggle_timeout
, pconn
, NULL
);
265 dbus_connection_set_wakeup_main_function(conn
, wakeup_main
, pconn
, NULL
);
267 pconn
->dispatch_event
= pconn
->mainloop
->defer_new(pconn
->mainloop
, dispatch_cb
, conn
);
269 pa_log_debug("Successfully connected to D-Bus %s bus %s as %s",
270 type
== DBUS_BUS_SYSTEM
? "system" : (type
== DBUS_BUS_SESSION
? "session" : "starter"),
271 pa_strnull((id
= dbus_connection_get_server_id(conn
))),
272 pa_strnull(dbus_bus_get_unique_name(conn
)));
279 pa_dbus_wrap_connection
* pa_dbus_wrap_connection_new_from_existing(pa_mainloop_api
*m
, DBusConnection
*conn
) {
280 pa_dbus_wrap_connection
*pconn
;
285 pconn
= pa_xnew(pa_dbus_wrap_connection
, 1);
287 pconn
->connection
= dbus_connection_ref(conn
);
289 dbus_connection_set_exit_on_disconnect(conn
, FALSE
);
290 dbus_connection_set_dispatch_status_function(conn
, dispatch_status
, pconn
, NULL
);
291 dbus_connection_set_watch_functions(conn
, add_watch
, remove_watch
, toggle_watch
, pconn
, NULL
);
292 dbus_connection_set_timeout_functions(conn
, add_timeout
, remove_timeout
, toggle_timeout
, pconn
, NULL
);
293 dbus_connection_set_wakeup_main_function(conn
, wakeup_main
, pconn
, NULL
);
295 pconn
->dispatch_event
= pconn
->mainloop
->defer_new(pconn
->mainloop
, dispatch_cb
, conn
);
300 void pa_dbus_wrap_connection_free(pa_dbus_wrap_connection
* c
) {
303 if (dbus_connection_get_is_connected(c
->connection
)) {
304 dbus_connection_close(c
->connection
);
305 /* must process remaining messages, bit of a kludge to handle
306 * both unload and shutdown */
307 while (dbus_connection_read_write_dispatch(c
->connection
, -1))
311 c
->mainloop
->defer_free(c
->dispatch_event
);
312 dbus_connection_unref(c
->connection
);
316 DBusConnection
* pa_dbus_wrap_connection_get(pa_dbus_wrap_connection
*c
) {
318 pa_assert(c
->connection
);
320 return c
->connection
;
323 int pa_dbus_add_matches(DBusConnection
*c
, DBusError
*error
, ...) {
332 while ((t
= va_arg(ap
, const char*))) {
333 dbus_bus_add_match(c
, t
, error
);
335 if (dbus_error_is_set(error
))
350 pa_assert_se(t
= va_arg(ap
, const char*));
353 dbus_bus_remove_match(c
, t
, &e
);
361 void pa_dbus_remove_matches(DBusConnection
*c
, ...) {
368 dbus_error_init(&error
);
371 while ((t
= va_arg(ap
, const char*))) {
372 dbus_bus_remove_match(c
, t
, &error
);
373 dbus_error_free(&error
);
378 pa_dbus_pending
*pa_dbus_pending_new(
381 DBusPendingCall
*pending
,
389 p
= pa_xnew(pa_dbus_pending
, 1);
392 p
->pending
= pending
;
393 p
->context_data
= context_data
;
394 p
->call_data
= call_data
;
396 PA_LLIST_INIT(pa_dbus_pending
, p
);
401 void pa_dbus_pending_free(pa_dbus_pending
*p
) {
405 dbus_pending_call_cancel(p
->pending
);
406 dbus_pending_call_unref(p
->pending
);
410 dbus_message_unref(p
->message
);
415 void pa_dbus_sync_pending_list(pa_dbus_pending
**p
) {
418 while (*p
&& dbus_connection_read_write_dispatch((*p
)->connection
, -1))
422 void pa_dbus_free_pending_list(pa_dbus_pending
**p
) {
428 PA_LLIST_REMOVE(pa_dbus_pending
, *p
, i
);
429 pa_dbus_pending_free(i
);