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 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
27 #include <pulse/xmalloc.h>
28 #include <pulse/timeval.h>
29 #include <pulsecore/log.h>
30 #include <pulsecore/shared.h>
32 #include "dbus-util.h"
34 struct pa_dbus_connection
{
38 DBusConnection
*connection
;
39 const char *property_name
;
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_connection
*c
= userdata
;
60 case DBUS_DISPATCH_COMPLETE
:
61 c
->core
->mainloop
->defer_enable(c
->dispatch_event
, 0);
64 case DBUS_DISPATCH_DATA_REMAINS
:
65 case DBUS_DISPATCH_NEED_MEMORY
:
67 c
->core
->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_core
*c
= PA_CORE(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_core
*c
= PA_CORE(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_core
*c
= PA_CORE(data
);
174 pa_core_assert_ref(c
);
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_core
*c
= PA_CORE(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_core
*c
= PA_CORE(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_core
*c
= PA_CORE(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_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
->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
) {
248 pa_dbus_connection
*pconn
;
250 pconn
= pa_xnew(pa_dbus_connection
, 1);
251 PA_REFCNT_INIT(pconn
);
253 pconn
->property_name
= name
;
254 pconn
->connection
= conn
;
255 pconn
->dispatch_event
= c
->mainloop
->defer_new(c
->mainloop
, dispatch_cb
, conn
);
257 pa_shared_set(c
, name
, pconn
);
262 DBusConnection
* pa_dbus_connection_get(pa_dbus_connection
*c
){
264 pa_assert(PA_REFCNT_VALUE(c
) > 0);
265 pa_assert(c
->connection
);
267 return c
->connection
;
270 void pa_dbus_connection_unref(pa_dbus_connection
*c
) {
272 pa_assert(PA_REFCNT_VALUE(c
) > 0);
274 if (PA_REFCNT_DEC(c
) > 0)
277 if (dbus_connection_get_is_connected(c
->connection
)) {
278 dbus_connection_close(c
->connection
);
279 /* must process remaining messages, bit of a kludge to handle
280 * both unload and shutdown */
281 while (dbus_connection_read_write_dispatch(c
->connection
, -1));
284 /* already disconnected, just free */
285 pa_shared_remove(c
->core
, c
->property_name
);
286 c
->core
->mainloop
->defer_free(c
->dispatch_event
);
287 dbus_connection_unref(c
->connection
);
291 pa_dbus_connection
* pa_dbus_connection_ref(pa_dbus_connection
*c
) {
293 pa_assert(PA_REFCNT_VALUE(c
) > 0);
300 pa_dbus_connection
* pa_dbus_bus_get(pa_core
*c
, DBusBusType type
, DBusError
*error
) {
302 static const char *const prop_name
[] = {
303 [DBUS_BUS_SESSION
] = "dbus-connection-session",
304 [DBUS_BUS_SYSTEM
] = "dbus-connection-system",
305 [DBUS_BUS_STARTER
] = "dbus-connection-starter"
307 DBusConnection
*conn
;
308 pa_dbus_connection
*pconn
;
310 pa_assert(type
== DBUS_BUS_SYSTEM
|| type
== DBUS_BUS_SESSION
|| type
== DBUS_BUS_STARTER
);
312 if ((pconn
= pa_shared_get(c
, prop_name
[type
])))
313 return pa_dbus_connection_ref(pconn
);
315 if (!(conn
= dbus_bus_get_private(type
, error
)))
318 pconn
= pa_dbus_connection_new(c
, conn
, prop_name
[type
]);
320 dbus_connection_set_exit_on_disconnect(conn
, FALSE
);
321 dbus_connection_set_dispatch_status_function(conn
, dispatch_status
, pconn
, NULL
);
322 dbus_connection_set_watch_functions(conn
, add_watch
, remove_watch
, toggle_watch
, c
, NULL
);
323 dbus_connection_set_timeout_functions(conn
, add_timeout
, remove_timeout
, toggle_timeout
, c
, NULL
);
324 dbus_connection_set_wakeup_main_function(conn
, wakeup_main
, pconn
, NULL
);