]> code.delx.au - pulseaudio/blob - src/modules/jack/module-jackdbus-detect.c
Whitespace cleanup: Remove tabs
[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(
44 "channels=<number of channels> "
45 "connect=<connect ports?>");
46
47 #define JACK_SERVICE_NAME "org.jackaudio.service"
48 #define JACK_INTERFACE_NAME "org.jackaudio.JackControl"
49 #define JACK_INTERFACE_PATH "/org/jackaudio/Controller"
50
51 #define SERVICE_FILTER \
52 "type='signal'," \
53 "sender='" DBUS_SERVICE_DBUS "'," \
54 "interface='" DBUS_INTERFACE_DBUS "'," \
55 "member='NameOwnerChanged'," \
56 "arg0='" JACK_SERVICE_NAME "'"
57
58 #define RUNNING_FILTER(_a) \
59 "type='signal'," \
60 "sender='" JACK_SERVICE_NAME "'," \
61 "interface='" JACK_INTERFACE_NAME "'," \
62 "member='" _a "'"
63
64 static const char* const valid_modargs[] = {
65 "channels",
66 "connect",
67 NULL
68 };
69
70 #define JACK_SS_SINK 0
71 #define JACK_SS_SOURCE 1
72 #define JACK_SS_COUNT 2
73
74 static const char* const modnames[JACK_SS_COUNT] = {
75 "module-jack-sink",
76 "module-jack-source"
77 };
78
79
80 struct userdata {
81 pa_module *module;
82 pa_core *core;
83 pa_dbus_connection *connection;
84 pa_bool_t filter_added, match_added;
85 pa_bool_t is_service_started;
86 pa_bool_t autoconnect_ports;
87 uint32_t channels;
88 /* Using index here protects us from module unloading without us knowing */
89 int jack_module_index[JACK_SS_COUNT];
90 };
91
92
93 static void ensure_ports_stopped(struct userdata* u) {
94 int i;
95 pa_assert(u);
96
97 for (i = 0; i < JACK_SS_COUNT; i++)
98 if (u->jack_module_index[i]) {
99 pa_module_unload_request_by_index(u->core, u->jack_module_index[i], TRUE);
100 u->jack_module_index[i] = 0;
101 pa_log_info("Stopped %s.", modnames[i]);
102 }
103 }
104
105 static void ensure_ports_started(struct userdata* u) {
106 int i;
107 pa_assert(u);
108
109 for (i = 0; i < JACK_SS_COUNT; i++)
110 if (!u->jack_module_index[i]) {
111 char* args;
112 pa_module* m;
113 if (u->channels > 0) {
114 args = pa_sprintf_malloc("connect=%s channels=%" PRIu32, pa_yes_no(u->autoconnect_ports), u->channels);
115 } else {
116 args = pa_sprintf_malloc("connect=%s", pa_yes_no(u->autoconnect_ports));
117 }
118 m = pa_module_load(u->core, modnames[i], args);
119 pa_xfree(args);
120
121 if (m) {
122 pa_log_info("Successfully started %s.", modnames[i]);
123 u->jack_module_index[i] = m->index;
124 }
125 else
126 pa_log_info("Failed to start %s.", modnames[i]);
127 }
128 }
129
130
131 static pa_bool_t check_service_started(struct userdata* u) {
132 DBusError error;
133 DBusMessage *m = NULL, *reply = NULL;
134 pa_bool_t new_status = FALSE;
135 dbus_bool_t call_result;
136 pa_assert(u);
137
138 dbus_error_init(&error);
139
140 /* Just a safety check; it isn't such a big deal if the name disappears just after the call. */
141 if (!dbus_bus_name_has_owner(pa_dbus_connection_get(u->connection),
142 JACK_SERVICE_NAME, &error)) {
143 pa_log_debug("jackdbus isn't running.");
144 goto finish;
145 }
146
147 if (!(m = dbus_message_new_method_call(JACK_SERVICE_NAME, JACK_INTERFACE_PATH, JACK_INTERFACE_NAME, "IsStarted"))) {
148 pa_log("Failed to allocate IsStarted() method call.");
149 goto finish;
150 }
151
152 if (!(reply = dbus_connection_send_with_reply_and_block(pa_dbus_connection_get(u->connection), m, -1, &error))) {
153 pa_log("IsStarted() call failed: %s: %s", error.name, error.message);
154 goto finish;
155 }
156
157 if (!dbus_message_get_args(reply, &error, DBUS_TYPE_BOOLEAN, &call_result, DBUS_TYPE_INVALID)) {
158 pa_log("IsStarted() call return failed: %s: %s", error.name, error.message);
159 goto finish;
160 }
161
162 new_status = call_result;
163
164 finish:
165 if (m)
166 dbus_message_unref(m);
167 if (reply)
168 dbus_message_unref(reply);
169
170 dbus_error_free(&error);
171 if (new_status)
172 ensure_ports_started(u);
173 else
174 ensure_ports_stopped(u);
175 u->is_service_started = new_status;
176 return new_status;
177 }
178
179 static DBusHandlerResult dbus_filter_handler(DBusConnection *c, DBusMessage *s, void *userdata) {
180 struct userdata *u = NULL;
181 DBusError error;
182
183 pa_assert(userdata);
184 u = ((pa_module*) userdata)->userdata;
185 pa_assert(u);
186
187 dbus_error_init(&error);
188
189 if (dbus_message_is_signal(s, DBUS_INTERFACE_DBUS, "NameOwnerChanged")) {
190 const char *name, *old, *new;
191 if (!dbus_message_get_args(s, &error,
192 DBUS_TYPE_STRING, &name,
193 DBUS_TYPE_STRING, &old,
194 DBUS_TYPE_STRING, &new,
195 DBUS_TYPE_INVALID))
196 goto finish;
197 if (!pa_streq(name, JACK_SERVICE_NAME))
198 goto finish;
199
200 ensure_ports_stopped(u);
201 check_service_started(u);
202 }
203
204 else if (dbus_message_is_signal(s, JACK_INTERFACE_NAME, "ServerStarted")) {
205 ensure_ports_stopped(u);
206 check_service_started(u);
207 }
208
209 else if (dbus_message_is_signal(s, JACK_INTERFACE_NAME, "ServerStopped")) {
210 ensure_ports_stopped(u);
211 }
212
213 finish:
214 dbus_error_free(&error);
215 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
216 }
217
218 int pa__init(pa_module *m) {
219 DBusError error;
220 pa_dbus_connection *connection = NULL;
221 struct userdata *u = NULL;
222 pa_modargs *ma;
223
224 pa_assert(m);
225
226 dbus_error_init(&error);
227
228 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
229 pa_log("Failed to parse module arguments");
230 goto fail;
231 }
232
233 m->userdata = u = pa_xnew0(struct userdata, 1);
234 u->core = m->core;
235 u->module = m;
236 u->autoconnect_ports = TRUE;
237 u->channels = 0;
238
239 if (pa_modargs_get_value_boolean(ma, "connect", &u->autoconnect_ports) < 0) {
240 pa_log("Failed to parse connect= argument.");
241 goto fail;
242 }
243
244 if (pa_modargs_get_value_u32(ma, "channels", &u->channels) < 0 || u->channels > PA_CHANNELS_MAX) {
245 pa_log("Failed to parse channels= argument.");
246 goto fail;
247 }
248
249 if (!(connection = pa_dbus_bus_get(m->core, DBUS_BUS_SESSION, &error)) || dbus_error_is_set(&error)) {
250
251 if (connection)
252 pa_dbus_connection_unref(connection);
253
254 pa_log_error("Unable to contact D-Bus session bus: %s: %s", error.name, error.message);
255 goto fail;
256 }
257 u->connection = connection;
258
259 if (!dbus_connection_add_filter(pa_dbus_connection_get(connection), dbus_filter_handler, m, NULL)) {
260 pa_log_error("Unable to add D-Bus filter");
261 goto fail;
262 }
263 u->filter_added = 1;
264
265 if (pa_dbus_add_matches(
266 pa_dbus_connection_get(connection), &error, SERVICE_FILTER,
267 RUNNING_FILTER("ServerStarted"), RUNNING_FILTER("ServerStopped"), NULL) < 0) {
268 pa_log_error("Unable to subscribe to signals: %s: %s", error.name, error.message);
269 goto fail;
270 }
271 u->match_added = 1;
272
273 check_service_started(u);
274
275 pa_modargs_free(ma);
276 return 0;
277
278 fail:
279 if (ma)
280 pa_modargs_free(ma);
281
282 dbus_error_free(&error);
283 pa__done(m);
284
285 return -1;
286 }
287
288 void pa__done(pa_module *m) {
289 struct userdata *u;
290
291 pa_assert(m);
292
293 if (!(u = m->userdata))
294 return;
295
296 ensure_ports_stopped(u);
297
298 if (u->match_added) {
299 pa_dbus_remove_matches(
300 pa_dbus_connection_get(u->connection), SERVICE_FILTER,
301 RUNNING_FILTER("ServerStarted"), RUNNING_FILTER("ServerStopped"), NULL);
302 }
303
304 if (u->filter_added) {
305 dbus_connection_remove_filter(pa_dbus_connection_get(u->connection), dbus_filter_handler, m);
306 }
307
308 if (u->connection) {
309 pa_dbus_connection_unref(u->connection);
310 }
311
312 pa_xfree(u);
313 }