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>
32 #include <pulsecore/shared.h>
34 #include "dbus-util.h"
36 struct pa_dbus_connection
{
40 DBusConnection
*connection
;
41 const char *property_name
;
42 pa_defer_event
* dispatch_event
;
45 static void dispatch_cb(pa_mainloop_api
*ea
, pa_defer_event
*ev
, void *userdata
) {
46 DBusConnection
*conn
= userdata
;
48 if (dbus_connection_dispatch(conn
) == DBUS_DISPATCH_COMPLETE
) {
49 /* no more data to process, disable the deferred */
50 ea
->defer_enable(ev
, 0);
54 /* DBusDispatchStatusFunction callback for the pa mainloop */
55 static void dispatch_status(DBusConnection
*conn
, DBusDispatchStatus status
, void *userdata
) {
56 pa_dbus_connection
*c
= userdata
;
62 case DBUS_DISPATCH_COMPLETE
:
63 c
->core
->mainloop
->defer_enable(c
->dispatch_event
, 0);
66 case DBUS_DISPATCH_DATA_REMAINS
:
67 case DBUS_DISPATCH_NEED_MEMORY
:
69 c
->core
->mainloop
->defer_enable(c
->dispatch_event
, 1);
74 static pa_io_event_flags_t
get_watch_flags(DBusWatch
*watch
) {
76 pa_io_event_flags_t events
= 0;
80 flags
= dbus_watch_get_flags(watch
);
82 /* no watch flags for disabled watches */
83 if (!dbus_watch_get_enabled(watch
))
84 return PA_IO_EVENT_NULL
;
86 if (flags
& DBUS_WATCH_READABLE
)
87 events
|= PA_IO_EVENT_INPUT
;
88 if (flags
& DBUS_WATCH_WRITABLE
)
89 events
|= PA_IO_EVENT_OUTPUT
;
91 return events
| PA_IO_EVENT_HANGUP
| PA_IO_EVENT_ERROR
;
94 /* pa_io_event_cb_t IO event handler */
95 static void handle_io_event(pa_mainloop_api
*ea
, pa_io_event
*e
, int fd
, pa_io_event_flags_t events
, void *userdata
) {
96 unsigned int flags
= 0;
97 DBusWatch
*watch
= userdata
;
99 #if HAVE_DBUS_WATCH_GET_UNIX_FD
100 pa_assert(fd
== dbus_watch_get_unix_fd(watch
));
102 pa_assert(fd
== dbus_watch_get_fd(watch
));
105 if (!dbus_watch_get_enabled(watch
)) {
106 pa_log_warn("Asked to handle disabled watch: %p %i", (void*) watch
, fd
);
110 if (events
& PA_IO_EVENT_INPUT
)
111 flags
|= DBUS_WATCH_READABLE
;
112 if (events
& PA_IO_EVENT_OUTPUT
)
113 flags
|= DBUS_WATCH_WRITABLE
;
114 if (events
& PA_IO_EVENT_HANGUP
)
115 flags
|= DBUS_WATCH_HANGUP
;
116 if (events
& PA_IO_EVENT_ERROR
)
117 flags
|= DBUS_WATCH_ERROR
;
119 dbus_watch_handle(watch
, flags
);
122 /* pa_time_event_cb_t timer event handler */
123 static void handle_time_event(pa_mainloop_api
*ea
, pa_time_event
* e
, const struct timeval
*tv
, void *userdata
) {
124 DBusTimeout
*timeout
= userdata
;
126 if (dbus_timeout_get_enabled(timeout
)) {
127 struct timeval next
= *tv
;
128 dbus_timeout_handle(timeout
);
130 /* restart it for the next scheduled time */
131 pa_timeval_add(&next
, (pa_usec_t
) dbus_timeout_get_interval(timeout
) * 1000);
132 ea
->time_restart(e
, &next
);
136 /* DBusAddWatchFunction callback for pa mainloop */
137 static dbus_bool_t
add_watch(DBusWatch
*watch
, void *data
) {
138 pa_core
*c
= PA_CORE(data
);
144 ev
= c
->mainloop
->io_new(
146 #if HAVE_DBUS_WATCH_GET_UNIX_FD
147 dbus_watch_get_unix_fd(watch
),
149 dbus_watch_get_fd(watch
),
151 get_watch_flags(watch
), handle_io_event
, watch
);
153 dbus_watch_set_data(watch
, ev
, NULL
);
158 /* DBusRemoveWatchFunction callback for pa mainloop */
159 static void remove_watch(DBusWatch
*watch
, void *data
) {
160 pa_core
*c
= PA_CORE(data
);
166 if ((ev
= dbus_watch_get_data(watch
)))
167 c
->mainloop
->io_free(ev
);
170 /* DBusWatchToggledFunction callback for pa mainloop */
171 static void toggle_watch(DBusWatch
*watch
, void *data
) {
172 pa_core
*c
= PA_CORE(data
);
176 pa_core_assert_ref(c
);
178 pa_assert_se(ev
= dbus_watch_get_data(watch
));
180 /* get_watch_flags() checks if the watch is enabled */
181 c
->mainloop
->io_enable(ev
, get_watch_flags(watch
));
184 /* DBusAddTimeoutFunction callback for pa mainloop */
185 static dbus_bool_t
add_timeout(DBusTimeout
*timeout
, void *data
) {
186 pa_core
*c
= PA_CORE(data
);
193 if (!dbus_timeout_get_enabled(timeout
))
196 pa_gettimeofday(&tv
);
197 pa_timeval_add(&tv
, (pa_usec_t
) dbus_timeout_get_interval(timeout
) * 1000);
199 ev
= c
->mainloop
->time_new(c
->mainloop
, &tv
, handle_time_event
, timeout
);
201 dbus_timeout_set_data(timeout
, ev
, NULL
);
206 /* DBusRemoveTimeoutFunction callback for pa mainloop */
207 static void remove_timeout(DBusTimeout
*timeout
, void *data
) {
208 pa_core
*c
= PA_CORE(data
);
214 if ((ev
= dbus_timeout_get_data(timeout
)))
215 c
->mainloop
->time_free(ev
);
218 /* DBusTimeoutToggledFunction callback for pa mainloop */
219 static void toggle_timeout(DBusTimeout
*timeout
, void *data
) {
220 pa_core
*c
= PA_CORE(data
);
226 pa_assert_se(ev
= dbus_timeout_get_data(timeout
));
228 if (dbus_timeout_get_enabled(timeout
)) {
231 pa_gettimeofday(&tv
);
232 pa_timeval_add(&tv
, (pa_usec_t
) dbus_timeout_get_interval(timeout
) * 1000);
234 c
->mainloop
->time_restart(ev
, &tv
);
236 c
->mainloop
->time_restart(ev
, NULL
);
239 static void wakeup_main(void *userdata
) {
240 pa_dbus_connection
*c
= userdata
;
244 /* this will wakeup the mainloop and dispatch events, although
245 * it may not be the cleanest way of accomplishing it */
246 c
->core
->mainloop
->defer_enable(c
->dispatch_event
, 1);
249 static pa_dbus_connection
* pa_dbus_connection_new(pa_core
* c
, DBusConnection
*conn
, const char* name
) {
250 pa_dbus_connection
*pconn
;
252 pconn
= pa_xnew(pa_dbus_connection
, 1);
253 PA_REFCNT_INIT(pconn
);
255 pconn
->property_name
= name
;
256 pconn
->connection
= conn
;
257 pconn
->dispatch_event
= c
->mainloop
->defer_new(c
->mainloop
, dispatch_cb
, conn
);
259 pa_shared_set(c
, name
, pconn
);
264 DBusConnection
* pa_dbus_connection_get(pa_dbus_connection
*c
){
266 pa_assert(PA_REFCNT_VALUE(c
) > 0);
267 pa_assert(c
->connection
);
269 return c
->connection
;
272 void pa_dbus_connection_unref(pa_dbus_connection
*c
) {
274 pa_assert(PA_REFCNT_VALUE(c
) > 0);
276 if (PA_REFCNT_DEC(c
) > 0)
279 if (dbus_connection_get_is_connected(c
->connection
)) {
280 dbus_connection_close(c
->connection
);
281 /* must process remaining messages, bit of a kludge to handle
282 * both unload and shutdown */
283 while (dbus_connection_read_write_dispatch(c
->connection
, -1));
286 /* already disconnected, just free */
287 pa_shared_remove(c
->core
, c
->property_name
);
288 c
->core
->mainloop
->defer_free(c
->dispatch_event
);
289 dbus_connection_unref(c
->connection
);
293 pa_dbus_connection
* pa_dbus_connection_ref(pa_dbus_connection
*c
) {
295 pa_assert(PA_REFCNT_VALUE(c
) > 0);
302 pa_dbus_connection
* pa_dbus_bus_get(pa_core
*c
, DBusBusType type
, DBusError
*error
) {
304 static const char *const prop_name
[] = {
305 [DBUS_BUS_SESSION
] = "dbus-connection-session",
306 [DBUS_BUS_SYSTEM
] = "dbus-connection-system",
307 [DBUS_BUS_STARTER
] = "dbus-connection-starter"
309 DBusConnection
*conn
;
310 pa_dbus_connection
*pconn
;
312 pa_assert(type
== DBUS_BUS_SYSTEM
|| type
== DBUS_BUS_SESSION
|| type
== DBUS_BUS_STARTER
);
314 if ((pconn
= pa_shared_get(c
, prop_name
[type
])))
315 return pa_dbus_connection_ref(pconn
);
317 if (!(conn
= dbus_bus_get_private(type
, error
)))
320 pconn
= pa_dbus_connection_new(c
, conn
, prop_name
[type
]);
322 dbus_connection_set_exit_on_disconnect(conn
, FALSE
);
323 dbus_connection_set_dispatch_status_function(conn
, dispatch_status
, pconn
, NULL
);
324 dbus_connection_set_watch_functions(conn
, add_watch
, remove_watch
, toggle_watch
, c
, NULL
);
325 dbus_connection_set_timeout_functions(conn
, add_timeout
, remove_timeout
, toggle_timeout
, c
, NULL
);
326 dbus_connection_set_wakeup_main_function(conn
, wakeup_main
, pconn
, NULL
);
331 int pa_dbus_add_matches(DBusConnection
*c
, DBusError
*error
, ...) {
340 while ((t
= va_arg(ap
, const char*))) {
341 dbus_bus_add_match(c
, t
, error
);
343 if (dbus_error_is_set(error
))
358 pa_assert_se(t
= va_arg(ap
, const char*));
361 dbus_bus_remove_match(c
, t
, &e
);
369 void pa_dbus_remove_matches(DBusConnection
*c
, ...) {
376 dbus_error_init(&error
);
379 while ((t
= va_arg(ap
, const char*))) {
380 dbus_bus_remove_match(c
, t
, &error
);
381 dbus_error_free(&error
);
386 pa_dbus_pending
*pa_dbus_pending_new(DBusMessage
*m
, DBusPendingCall
*pending
, void *context_data
, void *call_data
) {
391 p
= pa_xnew(pa_dbus_pending
, 1);
393 p
->pending
= pending
;
394 p
->context_data
= context_data
;
395 p
->call_data
= call_data
;
397 PA_LLIST_INIT(pa_dbus_pending
, p
);
402 void pa_dbus_pending_free(pa_dbus_pending
*p
) {
406 dbus_pending_call_cancel(p
->pending
); /* p->pending is freed by cancel() */
410 dbus_message_unref(p
->message
);
415 void pa_dbus_sync_pending_list(pa_dbus_pending
**p
) {
419 dbus_pending_call_block((*p
)->pending
);
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
);