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