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
30 #include <pulsecore/log.h>
31 #include <pulsecore/props.h>
32 #include <pulse/xmalloc.h>
33 #include <pulse/timeval.h>
35 #include "dbus-util.h"
37 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
)
47 DBusConnection
*conn
= (DBusConnection
*) 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
,
58 pa_dbus_connection
*c
= (pa_dbus_connection
*) userdata
;
60 case DBUS_DISPATCH_COMPLETE
:
61 c
->core
->mainloop
->defer_enable(c
->dispatch_event
, 0);
63 case DBUS_DISPATCH_DATA_REMAINS
:
64 case DBUS_DISPATCH_NEED_MEMORY
:
66 c
->core
->mainloop
->defer_enable(c
->dispatch_event
, 1);
71 static pa_io_event_flags_t
72 get_watch_flags(DBusWatch
*watch
)
74 unsigned int flags
= dbus_watch_get_flags(watch
);
75 pa_io_event_flags_t events
= PA_IO_EVENT_HANGUP
| PA_IO_EVENT_ERROR
;
77 /* no watch flags for disabled watches */
78 if (!dbus_watch_get_enabled(watch
))
79 return PA_IO_EVENT_NULL
;
81 if (flags
& DBUS_WATCH_READABLE
)
82 events
|= PA_IO_EVENT_INPUT
;
83 if (flags
& DBUS_WATCH_WRITABLE
)
84 events
|= PA_IO_EVENT_OUTPUT
;
89 /* pa_io_event_cb_t IO event handler */
90 static void handle_io_event(PA_GCC_UNUSED pa_mainloop_api
*ea
, pa_io_event
*e
,
91 int fd
, pa_io_event_flags_t events
, void *userdata
)
93 unsigned int flags
= 0;
94 DBusWatch
*watch
= (DBusWatch
*) userdata
;
96 assert(fd
== dbus_watch_get_fd(watch
));
98 if (!dbus_watch_get_enabled(watch
)) {
99 pa_log_warn("Asked to handle disabled watch: %p %i",
104 if (events
& PA_IO_EVENT_INPUT
)
105 flags
|= DBUS_WATCH_READABLE
;
106 if (events
& PA_IO_EVENT_OUTPUT
)
107 flags
|= DBUS_WATCH_WRITABLE
;
108 if (events
& PA_IO_EVENT_HANGUP
)
109 flags
|= DBUS_WATCH_HANGUP
;
110 if (events
& PA_IO_EVENT_ERROR
)
111 flags
|= DBUS_WATCH_ERROR
;
113 dbus_watch_handle(watch
, flags
);
116 /* pa_time_event_cb_t timer event handler */
117 static void handle_time_event(pa_mainloop_api
*ea
, pa_time_event
* e
,
118 const struct timeval
*tv
, void *userdata
)
120 DBusTimeout
*timeout
= (DBusTimeout
*) 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
, 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
)
136 pa_core
*c
= (pa_core
*) data
;
138 ev
= c
->mainloop
->io_new(c
->mainloop
, dbus_watch_get_fd(watch
),
139 get_watch_flags(watch
),
140 handle_io_event
, (void*) watch
);
144 /* dbus_watch_set_data(watch, (void*) ev, c->mainloop->io_free); */
145 dbus_watch_set_data(watch
, (void*) ev
, NULL
);
150 /* DBusRemoveWatchFunction callback for pa mainloop */
151 static void remove_watch(DBusWatch
*watch
, void *data
)
153 pa_core
*c
= (pa_core
*) data
;
154 pa_io_event
*ev
= (pa_io_event
*) dbus_watch_get_data(watch
);
158 c
->mainloop
->io_free(ev
);
161 /* DBusWatchToggledFunction callback for pa mainloop */
162 static void toggle_watch(DBusWatch
*watch
, void *data
)
164 pa_core
*c
= (pa_core
*) data
;
165 pa_io_event
*ev
= (pa_io_event
*) dbus_watch_get_data(watch
);
167 /* get_watch_flags() checks if the watch is enabled */
168 c
->mainloop
->io_enable(ev
, get_watch_flags(watch
));
171 /* DBusAddTimeoutFunction callback for pa mainloop */
172 static dbus_bool_t
add_timeout(DBusTimeout
*timeout
, void *data
)
176 pa_core
*c
= (pa_core
*) data
;
178 if (!dbus_timeout_get_enabled(timeout
))
181 if (!pa_gettimeofday(&tv
))
184 pa_timeval_add(&tv
, dbus_timeout_get_interval(timeout
) * 1000);
186 ev
= c
->mainloop
->time_new(c
->mainloop
, &tv
, handle_time_event
,
191 /* dbus_timeout_set_data(timeout, (void*) ev, c->mainloop->time_free); */
192 dbus_timeout_set_data(timeout
, (void*) ev
, NULL
);
197 /* DBusRemoveTimeoutFunction callback for pa mainloop */
198 static void remove_timeout(DBusTimeout
*timeout
, void *data
)
200 pa_core
*c
= (pa_core
*) data
;
201 pa_time_event
*ev
= (pa_time_event
*) dbus_timeout_get_data(timeout
);
205 c
->mainloop
->time_free(ev
);
208 /* DBusTimeoutToggledFunction callback for pa mainloop */
209 static void toggle_timeout(DBusTimeout
*timeout
, void *data
)
212 pa_core
*c
= (pa_core
*) data
;
213 pa_time_event
*ev
= (pa_time_event
*) dbus_timeout_get_data(timeout
);
215 if (dbus_timeout_get_enabled(timeout
)) {
216 pa_gettimeofday(&tv
);
217 pa_timeval_add(&tv
, dbus_timeout_get_interval(timeout
) * 1000);
218 c
->mainloop
->time_restart(ev
, &tv
);
220 /* disable the timeout */
221 c
->mainloop
->time_restart(ev
, NULL
);
226 pa_dbus_connection_free(pa_dbus_connection
*c
)
229 assert(!dbus_connection_get_is_connected(c
->connection
));
231 /* already disconnected, just free */
232 pa_property_remove(c
->core
, c
->property_name
);
233 c
->core
->mainloop
->defer_free(c
->dispatch_event
);
234 dbus_connection_unref(c
->connection
);
239 wakeup_main(void *userdata
)
241 pa_dbus_connection
*c
= (pa_dbus_connection
*) userdata
;
242 /* this will wakeup the mainloop and dispatch events, although
243 * it may not be the cleanest way of accomplishing it */
244 c
->core
->mainloop
->defer_enable(c
->dispatch_event
, 1);
247 static pa_dbus_connection
* pa_dbus_connection_new(pa_core
* c
, DBusConnection
*conn
, const char* name
)
249 pa_dbus_connection
*pconn
= pa_xnew(pa_dbus_connection
, 1);
253 pconn
->property_name
= name
;
254 pconn
->connection
= conn
;
255 pconn
->dispatch_event
= c
->mainloop
->defer_new(c
->mainloop
, dispatch_cb
,
258 pa_property_set(c
, name
, pconn
);
263 DBusConnection
* pa_dbus_connection_get(pa_dbus_connection
*c
)
265 assert(c
&& c
->connection
);
266 return c
->connection
;
269 void pa_dbus_connection_unref(pa_dbus_connection
*c
)
273 /* non-zero refcount, still outstanding refs */
277 /* refcount is zero */
278 if (dbus_connection_get_is_connected(c
->connection
)) {
279 /* disconnect as we have no more internal references */
280 dbus_connection_close(c
->connection
);
281 /* must process remaining messages, bit of a kludge to
282 * handle both unload and shutdown */
283 while(dbus_connection_read_write_dispatch(c
->connection
, -1));
285 pa_dbus_connection_free(c
);
288 pa_dbus_connection
* pa_dbus_connection_ref(pa_dbus_connection
*c
)
297 pa_dbus_connection
* pa_dbus_bus_get(pa_core
*c
, DBusBusType type
,
301 DBusConnection
*conn
;
302 pa_dbus_connection
*pconn
;
305 case DBUS_BUS_SYSTEM
:
306 name
= "dbus-connection-system";
308 case DBUS_BUS_SESSION
:
309 name
= "dbus-connection-session";
311 case DBUS_BUS_STARTER
:
312 name
= "dbus-connection-starter";
315 assert(0); /* never reached */
319 if ((pconn
= pa_property_get(c
, name
)))
320 return pa_dbus_connection_ref(pconn
);
323 conn
= dbus_bus_get_private(type
, error
);
324 if (conn
== NULL
|| dbus_error_is_set(error
)) {
328 pconn
= pa_dbus_connection_new(c
, conn
, name
);
330 /* don't exit on disconnect */
331 dbus_connection_set_exit_on_disconnect(conn
, FALSE
);
332 /* set up the DBUS call backs */
333 dbus_connection_set_dispatch_status_function(conn
, dispatch_status
,
334 (void*) pconn
, NULL
);
335 dbus_connection_set_watch_functions(conn
,
340 dbus_connection_set_timeout_functions(conn
,
345 dbus_connection_set_wakeup_main_function(conn
, wakeup_main
, pconn
, NULL
);