Add copyright notices to all relevant files. (based on svn log)
[profile/ivi/pulseaudio.git] / src / modules / dbus-util.c
1 /* $Id$ */
2
3 /***
4   This file is part of PulseAudio.
5
6   Copyright 2006 Lennart Poettering
7   Copyright 2006 Shams E. King
8
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.
13
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.
18
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
22   USA.
23 ***/
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 #include <assert.h>
30 #include <pulsecore/log.h>
31 #include <pulsecore/props.h>
32 #include <pulse/xmalloc.h>
33 #include <pulse/timeval.h>
34
35 #include "dbus-util.h"
36
37 struct pa_dbus_connection {
38     int refcount;
39     pa_core *core;
40     DBusConnection *connection;
41     const char *property_name;
42     pa_defer_event* dispatch_event;
43 };
44
45 static void dispatch_cb(pa_mainloop_api *ea, pa_defer_event *ev, void *userdata)
46 {
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);
51     }
52 }
53
54 /* DBusDispatchStatusFunction callback for the pa mainloop */
55 static void dispatch_status(DBusConnection *conn, DBusDispatchStatus status,
56                             void *userdata)
57 {
58     pa_dbus_connection *c = (pa_dbus_connection*) userdata;
59     switch(status) {
60         case DBUS_DISPATCH_COMPLETE:
61             c->core->mainloop->defer_enable(c->dispatch_event, 0);
62             break;
63         case DBUS_DISPATCH_DATA_REMAINS:
64         case DBUS_DISPATCH_NEED_MEMORY:
65         default:
66             c->core->mainloop->defer_enable(c->dispatch_event, 1);
67             break;
68     }
69 }
70
71 static pa_io_event_flags_t
72 get_watch_flags(DBusWatch *watch)
73 {
74     unsigned int flags = dbus_watch_get_flags(watch);
75     pa_io_event_flags_t events = PA_IO_EVENT_HANGUP | PA_IO_EVENT_ERROR;
76
77     /* no watch flags for disabled watches */
78     if (!dbus_watch_get_enabled(watch))
79         return PA_IO_EVENT_NULL;
80
81     if (flags & DBUS_WATCH_READABLE)
82         events |= PA_IO_EVENT_INPUT;
83     if (flags & DBUS_WATCH_WRITABLE)
84         events |= PA_IO_EVENT_OUTPUT;
85
86     return events;
87 }
88
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)
92 {
93     unsigned int flags = 0;
94     DBusWatch *watch = (DBusWatch*) userdata;
95
96     assert(fd == dbus_watch_get_fd(watch));
97
98     if (!dbus_watch_get_enabled(watch)) {
99         pa_log_warn("Asked to handle disabled watch: %p %i",
100                     (void *) watch, fd);
101         return;
102     }
103
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;
112
113     dbus_watch_handle(watch, flags);
114 }
115
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)
119 {
120     DBusTimeout *timeout = (DBusTimeout*) userdata;
121
122     if (dbus_timeout_get_enabled(timeout)) {
123         struct timeval next = *tv;
124         dbus_timeout_handle(timeout);
125
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);
129     }
130 }
131
132 /* DBusAddWatchFunction callback for pa mainloop */
133 static dbus_bool_t add_watch(DBusWatch *watch, void *data)
134 {
135     pa_io_event *ev;
136     pa_core *c = (pa_core*) data;
137
138     ev = c->mainloop->io_new(c->mainloop, dbus_watch_get_fd(watch),
139                              get_watch_flags(watch),
140                              handle_io_event, (void*) watch);
141     if (NULL == ev)
142         return FALSE;
143
144     /* dbus_watch_set_data(watch, (void*) ev, c->mainloop->io_free); */
145     dbus_watch_set_data(watch, (void*) ev, NULL);
146
147     return TRUE;
148 }
149
150 /* DBusRemoveWatchFunction callback for pa mainloop */
151 static void remove_watch(DBusWatch *watch, void *data)
152 {
153     pa_core *c = (pa_core*) data;
154     pa_io_event *ev = (pa_io_event*) dbus_watch_get_data(watch);
155
156     /* free the event */
157     if (NULL != ev)
158         c->mainloop->io_free(ev);
159 }
160
161 /* DBusWatchToggledFunction callback for pa mainloop */
162 static void toggle_watch(DBusWatch *watch, void *data)
163 {
164     pa_core *c = (pa_core*) data;
165     pa_io_event *ev = (pa_io_event*) dbus_watch_get_data(watch);
166
167     /* get_watch_flags() checks if the watch is enabled */
168     c->mainloop->io_enable(ev, get_watch_flags(watch));
169 }
170
171 /* DBusAddTimeoutFunction callback for pa mainloop */
172 static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data)
173 {
174     struct timeval tv;
175     pa_time_event *ev;
176     pa_core *c = (pa_core*) data;
177
178     if (!dbus_timeout_get_enabled(timeout))
179         return FALSE;
180
181     if (!pa_gettimeofday(&tv))
182         return -1;
183
184     pa_timeval_add(&tv, dbus_timeout_get_interval(timeout) * 1000);
185
186     ev = c->mainloop->time_new(c->mainloop, &tv, handle_time_event,
187                                (void*) timeout);
188     if (NULL == ev)
189         return FALSE;
190
191     /* dbus_timeout_set_data(timeout, (void*) ev, c->mainloop->time_free); */
192     dbus_timeout_set_data(timeout, (void*) ev, NULL);
193
194     return TRUE;
195 }
196
197 /* DBusRemoveTimeoutFunction callback for pa mainloop */
198 static void remove_timeout(DBusTimeout *timeout, void *data)
199 {
200     pa_core *c = (pa_core*) data;
201     pa_time_event *ev = (pa_time_event*) dbus_timeout_get_data(timeout);
202
203     /* free the event */
204     if (NULL != ev)
205         c->mainloop->time_free(ev);
206 }
207
208 /* DBusTimeoutToggledFunction callback for pa mainloop */
209 static void toggle_timeout(DBusTimeout *timeout, void *data)
210 {
211     struct timeval tv;
212     pa_core *c = (pa_core*) data;
213     pa_time_event *ev = (pa_time_event*) dbus_timeout_get_data(timeout);
214
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);
219     } else {
220         /* disable the timeout */
221         c->mainloop->time_restart(ev, NULL);
222     }
223 }
224
225 static void
226 pa_dbus_connection_free(pa_dbus_connection *c)
227 {
228     assert(c);
229     assert(!dbus_connection_get_is_connected(c->connection));
230
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);
235     pa_xfree(c);
236 }
237
238 static void
239 wakeup_main(void *userdata)
240 {
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);
245 }
246
247 static pa_dbus_connection* pa_dbus_connection_new(pa_core* c, DBusConnection *conn, const char* name)
248 {
249     pa_dbus_connection *pconn = pa_xnew(pa_dbus_connection, 1);
250
251     pconn->refcount = 1;
252     pconn->core = c;
253     pconn->property_name = name;
254     pconn->connection = conn;
255     pconn->dispatch_event = c->mainloop->defer_new(c->mainloop, dispatch_cb,
256                                                    (void*) conn);
257
258     pa_property_set(c, name, pconn);
259
260     return pconn;
261 }
262
263 DBusConnection* pa_dbus_connection_get(pa_dbus_connection *c)
264 {
265     assert(c && c->connection);
266     return c->connection;
267 }
268
269 void pa_dbus_connection_unref(pa_dbus_connection *c)
270 {
271     assert(c);
272
273     /* non-zero refcount, still outstanding refs */
274     if (--(c->refcount))
275         return;
276
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));
284     }
285     pa_dbus_connection_free(c);
286 }
287
288 pa_dbus_connection* pa_dbus_connection_ref(pa_dbus_connection *c)
289 {
290     assert(c);
291
292     ++(c->refcount);
293
294     return c;
295 }
296
297 pa_dbus_connection* pa_dbus_bus_get(pa_core *c, DBusBusType type,
298                                     DBusError *error)
299 {
300     const char* name;
301     DBusConnection *conn;
302     pa_dbus_connection *pconn;
303
304     switch (type) {
305         case DBUS_BUS_SYSTEM:
306             name = "dbus-connection-system";
307             break;
308         case DBUS_BUS_SESSION:
309             name = "dbus-connection-session";
310             break;
311         case DBUS_BUS_STARTER:
312             name = "dbus-connection-starter";
313             break;
314         default:
315             assert(0); /* never reached */
316             break;
317     }
318
319     if ((pconn = pa_property_get(c, name)))
320         return pa_dbus_connection_ref(pconn);
321
322     /* else */
323     conn = dbus_bus_get_private(type, error);
324     if (conn == NULL || dbus_error_is_set(error)) {
325         return NULL;
326     }
327
328     pconn = pa_dbus_connection_new(c, conn, name);
329
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,
336                                         add_watch,
337                                         remove_watch,
338                                         toggle_watch,
339                                         (void*) c, NULL);
340     dbus_connection_set_timeout_functions(conn,
341                                           add_timeout,
342                                           remove_timeout,
343                                           toggle_timeout,
344                                           (void*) c, NULL);
345     dbus_connection_set_wakeup_main_function(conn, wakeup_main, pconn, NULL);
346
347     return pconn;
348 }