4 This file is part of PulseAudio.
6 Copyright 2006 Lennart Poettering
7 Copyright 2006 Shams E. King
9 PulseAudio is free software; you can redistribute it and/or modify
10 it under the terms of the GNU Lesser General Public License as published
11 by the Free Software Foundation; either version 2 of the License,
12 or (at your option) any later version.
14 PulseAudio is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 General Public License for more details.
19 You should have received a copy of the GNU Lesser General Public License
20 along with PulseAudio; if not, write to the Free Software
21 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/props.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_GCC_UNUSED 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
, 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
, 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
, 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_property_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_property_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_property_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
);