]> code.delx.au - pulseaudio/blob - src/modules/jack/module-jackdbus-detect.c
Remove unnecessary #includes
[pulseaudio] / src / modules / jack / module-jackdbus-detect.c
1 /***
2 This file is part of PulseAudio.
3
4 Written by David Henningsson <david.henningsson@canonical.com>
5 Copyright 2010 Canonical Ltd.
6
7 Some code taken from other parts of PulseAudio, these are
8 Copyright 2006-2009 Lennart Poettering
9
10 PulseAudio is free software; you can redistribute it and/or modify
11 it under the terms of the GNU Lesser General Public License as published
12 by the Free Software Foundation; either version 2.1 of the License,
13 or (at your option) any later version.
14
15 PulseAudio is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 General Public License for more details.
19
20 You should have received a copy of the GNU Lesser General Public License
21 along with PulseAudio; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
23 USA.
24 ***/
25
26 #ifdef HAVE_CONFIG_H
27 #include <config.h>
28 #endif
29
30 #include <pulse/xmalloc.h>
31
32 #include <pulsecore/log.h>
33 #include <pulsecore/modargs.h>
34 #include <pulsecore/core-util.h>
35 #include <pulsecore/dbus-shared.h>
36
37 #include "module-jackdbus-detect-symdef.h"
38
39 PA_MODULE_AUTHOR("David Henningsson");
40 PA_MODULE_DESCRIPTION("Adds JACK sink/source ports when JACK is started");
41 PA_MODULE_LOAD_ONCE(TRUE);
42 PA_MODULE_VERSION(PACKAGE_VERSION);
43 PA_MODULE_USAGE("connect=<connect ports?>");
44
45 #define JACK_SERVICE_NAME "org.jackaudio.service"
46 #define JACK_INTERFACE_NAME "org.jackaudio.JackControl"
47 #define JACK_INTERFACE_PATH "/org/jackaudio/Controller"
48
49 #define SERVICE_FILTER \
50 "type='signal'," \
51 "sender='" DBUS_SERVICE_DBUS "'," \
52 "interface='" DBUS_INTERFACE_DBUS "'," \
53 "member='NameOwnerChanged'," \
54 "arg0='" JACK_SERVICE_NAME "'"
55
56 #define RUNNING_FILTER(_a) \
57 "type='signal'," \
58 "sender='" JACK_SERVICE_NAME "'," \
59 "interface='" JACK_INTERFACE_NAME "'," \
60 "member='" _a "'"
61
62 static const char* const valid_modargs[] = {
63 "connect",
64 NULL
65 };
66
67 #define JACK_SS_SINK 0
68 #define JACK_SS_SOURCE 1
69 #define JACK_SS_COUNT 2
70
71 static const char* const modnames[JACK_SS_COUNT] = {
72 "module-jack-sink",
73 "module-jack-source"
74 };
75
76
77 struct userdata {
78 pa_module *module;
79 pa_core *core;
80 pa_dbus_connection *connection;
81 pa_bool_t filter_added, match_added;
82 pa_bool_t is_service_started;
83 pa_bool_t autoconnect_ports;
84 /* Using index here protects us from module unloading without us knowing */
85 int jack_module_index[JACK_SS_COUNT];
86 };
87
88
89 static void ensure_ports_stopped(struct userdata* u) {
90 int i;
91 pa_assert(u);
92
93 for (i = 0; i < JACK_SS_COUNT; i++)
94 if (u->jack_module_index[i]) {
95 pa_module_unload_request_by_index(u->core, u->jack_module_index[i], TRUE);
96 u->jack_module_index[i] = 0;
97 pa_log_info("Stopped %s.", modnames[i]);
98 }
99 }
100
101 static void ensure_ports_started(struct userdata* u) {
102 int i;
103 pa_assert(u);
104
105 for (i = 0; i < JACK_SS_COUNT; i++)
106 if (!u->jack_module_index[i]) {
107 char* args;
108 pa_module* m;
109 args = pa_sprintf_malloc("connect=%s", pa_yes_no(u->autoconnect_ports));
110 m = pa_module_load(u->core, modnames[i], args);
111 pa_xfree(args);
112
113 if (m) {
114 pa_log_info("Successfully started %s.", modnames[i]);
115 u->jack_module_index[i] = m->index;
116 }
117 else
118 pa_log_info("Failed to start %s.", modnames[i]);
119 }
120 }
121
122
123 static pa_bool_t check_service_started(struct userdata* u) {
124 DBusError error;
125 DBusMessage *m = NULL, *reply = NULL;
126 pa_bool_t new_status = FALSE;
127 dbus_bool_t call_result;
128 pa_assert(u);
129
130 dbus_error_init(&error);
131
132 /* Just a safety check; it isn't such a big deal if the name disappears just after the call. */
133 if (!dbus_bus_name_has_owner(pa_dbus_connection_get(u->connection),
134 JACK_SERVICE_NAME, &error)) {
135 pa_log_debug("jackdbus isn't running.");
136 goto finish;
137 }
138
139 if (!(m = dbus_message_new_method_call(JACK_SERVICE_NAME, JACK_INTERFACE_PATH, JACK_INTERFACE_NAME, "IsStarted"))) {
140 pa_log("Failed to allocate IsStarted() method call.");
141 goto finish;
142 }
143
144 if (!(reply = dbus_connection_send_with_reply_and_block(pa_dbus_connection_get(u->connection), m, -1, &error))) {
145 pa_log("IsStarted() call failed: %s: %s", error.name, error.message);
146 goto finish;
147 }
148
149 if (!dbus_message_get_args(reply, &error, DBUS_TYPE_BOOLEAN, &call_result, DBUS_TYPE_INVALID)) {
150 pa_log("IsStarted() call return failed: %s: %s", error.name, error.message);
151 goto finish;
152 }
153
154 new_status = call_result;
155
156 finish:
157 if (m)
158 dbus_message_unref(m);
159 if (reply)
160 dbus_message_unref(reply);
161
162 dbus_error_free(&error);
163 if (new_status)
164 ensure_ports_started(u);
165 else
166 ensure_ports_stopped(u);
167 u->is_service_started = new_status;
168 return new_status;
169 }
170
171 static DBusHandlerResult dbus_filter_handler(DBusConnection *c, DBusMessage *s, void *userdata) {
172 struct userdata *u = NULL;
173 DBusError error;
174
175 pa_assert(userdata);
176 u = ((pa_module*) userdata)->userdata;
177 pa_assert(u);
178
179 dbus_error_init(&error);
180
181 if (dbus_message_is_signal(s, DBUS_INTERFACE_DBUS, "NameOwnerChanged")) {
182 const char *name, *old, *new;
183 if (!dbus_message_get_args(s, &error,
184 DBUS_TYPE_STRING, &name,
185 DBUS_TYPE_STRING, &old,
186 DBUS_TYPE_STRING, &new,
187 DBUS_TYPE_INVALID))
188 goto finish;
189 if (strcmp(name, JACK_SERVICE_NAME))
190 goto finish;
191
192 ensure_ports_stopped(u);
193 check_service_started(u);
194 }
195
196 else if (dbus_message_is_signal(s, JACK_INTERFACE_NAME, "ServerStarted")) {
197 ensure_ports_stopped(u);
198 check_service_started(u);
199 }
200
201 else if (dbus_message_is_signal(s, JACK_INTERFACE_NAME, "ServerStopped")) {
202 ensure_ports_stopped(u);
203 }
204
205 finish:
206 dbus_error_free(&error);
207 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
208 }
209
210 int pa__init(pa_module *m) {
211 DBusError error;
212 pa_dbus_connection *connection = NULL;
213 struct userdata *u = NULL;
214 pa_modargs *ma;
215
216 pa_assert(m);
217
218 dbus_error_init(&error);
219
220 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
221 pa_log("Failed to parse module arguments");
222 goto fail;
223 }
224
225 m->userdata = u = pa_xnew0(struct userdata, 1);
226 u->core = m->core;
227 u->module = m;
228 u->autoconnect_ports = TRUE;
229
230 if (pa_modargs_get_value_boolean(ma, "connect", &u->autoconnect_ports) < 0) {
231 pa_log("Failed to parse connect= argument.");
232 goto fail;
233 }
234
235 if (!(connection = pa_dbus_bus_get(m->core, DBUS_BUS_SESSION, &error)) || dbus_error_is_set(&error)) {
236
237 if (connection)
238 pa_dbus_connection_unref(connection);
239
240 pa_log_error("Unable to contact D-Bus session bus: %s: %s", error.name, error.message);
241 goto fail;
242 }
243 u->connection = connection;
244
245 if (!dbus_connection_add_filter(pa_dbus_connection_get(connection), dbus_filter_handler, m, NULL)) {
246 pa_log_error("Unable to add D-Bus filter");
247 goto fail;
248 }
249 u->filter_added = 1;
250
251 if (pa_dbus_add_matches(
252 pa_dbus_connection_get(connection), &error, SERVICE_FILTER,
253 RUNNING_FILTER("ServerStarted"), RUNNING_FILTER("ServerStopped"), NULL) < 0) {
254 pa_log_error("Unable to subscribe to signals: %s: %s", error.name, error.message);
255 goto fail;
256 }
257 u->match_added = 1;
258
259 check_service_started(u);
260
261 return 0;
262
263 fail:
264 if (ma)
265 pa_modargs_free(ma);
266
267 dbus_error_free(&error);
268 pa__done(m);
269
270 return -1;
271 }
272
273 void pa__done(pa_module *m) {
274 struct userdata *u;
275
276 pa_assert(m);
277
278 if (!(u = m->userdata))
279 return;
280
281 ensure_ports_stopped(u);
282
283 if (u->match_added) {
284 pa_dbus_remove_matches(
285 pa_dbus_connection_get(u->connection), SERVICE_FILTER,
286 RUNNING_FILTER("ServerStarted"), RUNNING_FILTER("ServerStopped"), NULL);
287 }
288
289 if (u->filter_added) {
290 dbus_connection_remove_filter(pa_dbus_connection_get(u->connection), dbus_filter_handler, m);
291 }
292
293 if (u->connection) {
294 pa_dbus_connection_unref(u->connection);
295 }
296
297 pa_xfree(u);
298 }