4 This file is part of PulseAudio.
6 PulseAudio is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published
8 by the Free Software Foundation; either version 2 of the License,
9 or (at your option) any later version.
11 PulseAudio is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with PulseAudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
27 #include <pulsecore/log.h>
28 #include <pulsecore/props.h>
29 #include <pulse/xmalloc.h>
31 #include "dbus-util.h"
33 struct pa_dbus_connection {
36 DBusConnection *connection;
37 const char *property_name;
38 pa_defer_event* dispatch_event;
41 static void dispatch_cb(pa_mainloop_api *ea, pa_defer_event *ev, void *userdata)
43 DBusConnection *conn = (DBusConnection *) userdata;
44 if (dbus_connection_dispatch(conn) == DBUS_DISPATCH_COMPLETE) {
45 /* no more data to process, disable the deferred */
46 ea->defer_enable(ev, 0);
50 /* DBusDispatchStatusFunction callback for the pa mainloop */
51 static void dispatch_status(DBusConnection *conn, DBusDispatchStatus status,
54 pa_dbus_connection *c = (pa_dbus_connection*) userdata;
56 case DBUS_DISPATCH_COMPLETE:
57 c->core->mainloop->defer_enable(c->dispatch_event, 0);
59 case DBUS_DISPATCH_DATA_REMAINS:
60 case DBUS_DISPATCH_NEED_MEMORY:
62 c->core->mainloop->defer_enable(c->dispatch_event, 1);
67 static pa_io_event_flags_t
68 get_watch_flags(DBusWatch *watch)
70 unsigned int flags = dbus_watch_get_flags(watch);
71 pa_io_event_flags_t events = PA_IO_EVENT_HANGUP | PA_IO_EVENT_ERROR;
73 /* no watch flags for disabled watches */
74 if (!dbus_watch_get_enabled(watch))
75 return PA_IO_EVENT_NULL;
77 if (flags & DBUS_WATCH_READABLE)
78 events |= PA_IO_EVENT_INPUT;
79 if (flags & DBUS_WATCH_WRITABLE)
80 events |= PA_IO_EVENT_OUTPUT;
85 static void timeval_next(struct timeval *tv, int millint)
87 /* number of seconds in the milli-second interval */
88 tv->tv_sec += (millint / 1000);
89 /* milliseconds minus the seconds portion, converted to microseconds */
90 tv->tv_usec += (millint - tv->tv_sec * 1000) * 1000;
93 /* pa_io_event_cb_t IO event handler */
94 static void handle_io_event(PA_GCC_UNUSED pa_mainloop_api *ea, pa_io_event *e,
95 int fd, pa_io_event_flags_t events, void *userdata)
97 unsigned int flags = 0;
98 DBusWatch *watch = (DBusWatch*) userdata;
100 assert(fd == dbus_watch_get_fd(watch));
102 if (!dbus_watch_get_enabled(watch)) {
103 pa_log_warn(__FILE__": Asked to handle disabled watch: %p %i",
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,
122 const struct timeval *tv, void *userdata)
124 DBusTimeout *timeout = (DBusTimeout*) 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 timeval_next(&next, dbus_timeout_get_interval(timeout));
132 ea->time_restart(e, &next);
136 /* DBusAddWatchFunction callback for pa mainloop */
137 static dbus_bool_t add_watch(DBusWatch *watch, void *data)
140 pa_core *c = (pa_core*) data;
142 ev = c->mainloop->io_new(c->mainloop, dbus_watch_get_fd(watch),
143 get_watch_flags(watch),
144 handle_io_event, (void*) watch);
148 /* dbus_watch_set_data(watch, (void*) ev, c->mainloop->io_free); */
149 dbus_watch_set_data(watch, (void*) ev, NULL);
154 /* DBusRemoveWatchFunction callback for pa mainloop */
155 static void remove_watch(DBusWatch *watch, void *data)
157 pa_core *c = (pa_core*) data;
158 pa_io_event *ev = (pa_io_event*) dbus_watch_get_data(watch);
162 c->mainloop->io_free(ev);
165 /* DBusWatchToggledFunction callback for pa mainloop */
166 static void toggle_watch(DBusWatch *watch, void *data)
168 pa_core *c = (pa_core*) data;
169 pa_io_event *ev = (pa_io_event*) dbus_watch_get_data(watch);
171 /* get_watch_flags() checks if the watch is enabled */
172 c->mainloop->io_enable(ev, get_watch_flags(watch));
175 /* DBusAddTimeoutFunction callback for pa mainloop */
176 static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data)
180 pa_core *c = (pa_core*) data;
182 if (!dbus_timeout_get_enabled(timeout))
185 if (gettimeofday(&tv, NULL) < 0)
188 timeval_next(&tv, dbus_timeout_get_interval(timeout));
190 ev = c->mainloop->time_new(c->mainloop, &tv, handle_time_event,
195 /* dbus_timeout_set_data(timeout, (void*) ev, c->mainloop->time_free); */
196 dbus_timeout_set_data(timeout, (void*) ev, NULL);
201 /* DBusRemoveTimeoutFunction callback for pa mainloop */
202 static void remove_timeout(DBusTimeout *timeout, void *data)
204 pa_core *c = (pa_core*) data;
205 pa_time_event *ev = (pa_time_event*) dbus_timeout_get_data(timeout);
209 c->mainloop->time_free(ev);
212 /* DBusTimeoutToggledFunction callback for pa mainloop */
213 static void toggle_timeout(DBusTimeout *timeout, void *data)
216 pa_core *c = (pa_core*) data;
217 pa_time_event *ev = (pa_time_event*) dbus_timeout_get_data(timeout);
219 gettimeofday(&tv, NULL);
220 if (dbus_timeout_get_enabled(timeout)) {
221 timeval_next(&tv, dbus_timeout_get_interval(timeout));
222 c->mainloop->time_restart(ev, &tv);
224 /* set it to expire one second ago */
226 c->mainloop->time_restart(ev, &tv);
231 pa_dbus_connection_free(pa_dbus_connection *c)
234 assert(!dbus_connection_get_is_connected(c->connection));
236 /* already disconnected, just free */
237 pa_property_remove(c->core, c->property_name);
238 c->core->mainloop->defer_free(c->dispatch_event);
239 dbus_connection_unref(c->connection);
244 wakeup_main(void *userdata)
246 pa_dbus_connection *c = (pa_dbus_connection*) userdata;
247 /* this will wakeup the mainloop and dispatch events, although
248 * it may not be the cleanest way of accomplishing it */
249 c->core->mainloop->defer_enable(c->dispatch_event, 1);
252 static pa_dbus_connection* pa_dbus_connection_new(pa_core* c, DBusConnection *conn, const char* name)
254 pa_dbus_connection *pconn = pa_xmalloc(sizeof(pa_dbus_connection));
258 pconn->property_name = name;
259 pconn->connection = conn;
260 pconn->dispatch_event = c->mainloop->defer_new(c->mainloop, dispatch_cb,
263 pa_property_set(c, name, pconn);
268 DBusConnection* pa_dbus_connection_get(pa_dbus_connection *c)
270 assert(c && c->connection);
271 return c->connection;
274 void pa_dbus_connection_unref(pa_dbus_connection *c)
278 /* non-zero refcount, still outstanding refs */
282 /* refcount is zero */
283 if (dbus_connection_get_is_connected(c->connection)) {
284 /* disconnect as we have no more internal references */
285 dbus_connection_close(c->connection);
286 /* must process remaining messages, bit of a kludge to
287 * handle both unload and shutdown */
288 while(dbus_connection_read_write_dispatch(c->connection, -1));
290 pa_dbus_connection_free(c);
293 pa_dbus_connection* pa_dbus_connection_ref(pa_dbus_connection *c)
302 pa_dbus_connection* pa_dbus_bus_get(pa_core *c, DBusBusType type,
306 DBusConnection *conn;
307 pa_dbus_connection *pconn;
308 static const char sysname[] = "dbus-connection-system";
309 static const char sessname[] = "dbus-connection-session";
310 static const char startname[] = "dbus-connection-starter";
313 case DBUS_BUS_SYSTEM:
316 case DBUS_BUS_SESSION:
319 case DBUS_BUS_STARTER:
323 assert(0); /* never reached */
327 if ((pconn = pa_property_get(c, name)))
328 return pa_dbus_connection_ref(pconn);
331 conn = dbus_bus_get_private(type, error);
332 if (conn == NULL || dbus_error_is_set(error)) {
336 pconn = pa_dbus_connection_new(c, conn, name);
338 /* don't exit on disconnect */
339 dbus_connection_set_exit_on_disconnect(conn, FALSE);
340 /* set up the DBUS call backs */
341 dbus_connection_set_dispatch_status_function(conn, dispatch_status,
342 (void*) pconn, NULL);
343 dbus_connection_set_watch_functions(conn,
348 dbus_connection_set_timeout_functions(conn,
353 dbus_connection_set_wakeup_main_function(conn, wakeup_main, pconn, NULL);