git aware version script
[a2jmidid.git] / dbus_iface_control.c
blobde2865d9cc4e690b8b1bf76bb9493ed20253a184
1 /* -*- Mode: C ; c-basic-offset: 2 -*- */
2 /*
3 * ALSA SEQ < - > JACK MIDI bridge
5 * Copyright (c) 2008 Nedko Arnaudov <nedko@arnaudov.name>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include <stdbool.h>
22 #include <dbus/dbus.h>
23 #include <alsa/asoundlib.h>
24 #include <jack/jack.h>
25 #include <jack/midiport.h>
26 #include <jack/ringbuffer.h>
28 #include "dbus_internal.h"
29 #include "a2jmidid.h"
30 #include "log.h"
31 #include "list.h"
32 #include "structs.h"
33 #include "port_thread.h"
35 #define INTERFACE_NAME "org.gna.home.a2jmidid.control"
37 void
38 a2j_dbus_signal_emit_bridge_started()
40 a2j_dbus_signal("/", INTERFACE_NAME, "bridge_started", DBUS_TYPE_INVALID);
43 void
44 a2j_dbus_signal_emit_bridge_stopped()
46 a2j_dbus_signal("/", INTERFACE_NAME, "bridge_stopped", DBUS_TYPE_INVALID);
49 static
50 void
51 a2j_dbus_exit(
52 struct a2j_dbus_method_call * call_ptr)
54 g_keep_walking = false;
57 static
58 void
59 a2j_dbus_start(
60 struct a2j_dbus_method_call * call_ptr)
62 if (!a2j_start())
64 a2j_dbus_error(call_ptr, A2J_DBUS_ERROR_GENERIC, "a2j_start() failed.");
68 static
69 void
70 a2j_dbus_stop(
71 struct a2j_dbus_method_call * call_ptr)
73 if (!a2j_stop())
75 a2j_dbus_error(call_ptr, A2J_DBUS_ERROR_GENERIC, "a2j_stop() failed.");
79 static
80 void
81 a2j_dbus_is_started(
82 struct a2j_dbus_method_call * call_ptr)
84 dbus_bool_t is_started;
86 is_started = a2j_is_started();
88 a2j_dbus_construct_method_return_single(
89 call_ptr,
90 DBUS_TYPE_BOOLEAN,
91 &is_started);
94 static
95 void
96 a2j_dbus_get_jack_client_name(
97 struct a2j_dbus_method_call * call_ptr)
99 const char * jack_client_name;
101 jack_client_name = A2J_JACK_CLIENT_NAME;
103 a2j_dbus_construct_method_return_single(
104 call_ptr,
105 DBUS_TYPE_STRING,
106 &jack_client_name);
109 static
110 void
111 a2j_dbus_map_alsa_to_jack_port(
112 struct a2j_dbus_method_call * call_ptr)
114 DBusError error;
115 dbus_uint32_t client_id;
116 dbus_uint32_t port_id;
117 dbus_bool_t map_playback;
118 snd_seq_addr_t addr;
119 struct a2j_port * port_ptr;
120 const char * direction_string;
121 struct a2j_stream * stream_ptr;
122 const char * jack_port;
124 dbus_error_init(&error);
126 if (!dbus_message_get_args(
127 call_ptr->message,
128 &error,
129 DBUS_TYPE_UINT32, &client_id,
130 DBUS_TYPE_UINT32, &port_id,
131 DBUS_TYPE_BOOLEAN, &map_playback,
132 DBUS_TYPE_INVALID))
134 a2j_dbus_error(call_ptr, A2J_DBUS_ERROR_INVALID_ARGS, "Invalid arguments to method \"%s\"", call_ptr->method_name);
135 dbus_error_free(&error);
136 return;
139 if (!a2j_is_started())
141 a2j_dbus_error(call_ptr, A2J_DBUS_ERROR_BRIDGE_NOT_RUNNING, "Bridge not started");
142 return;
145 addr.client = client_id;
146 addr.port = port_id;
148 if (map_playback)
150 stream_ptr = g_a2j->stream + A2J_PORT_PLAYBACK;
151 direction_string = "playback";
153 else
155 stream_ptr = g_a2j->stream + A2J_PORT_CAPTURE;
156 direction_string = "capture";
159 port_ptr = a2j_find_port_by_addr(stream_ptr, addr);
160 if (port_ptr == NULL)
162 a2j_dbus_error(call_ptr, A2J_DBUS_ERROR_UNKNOWN_PORT, "Unknown ALSA sequencer port %u:%u (%s)", (unsigned int)client_id, (unsigned int)port_id, direction_string);
163 return;
166 jack_port = port_ptr->name;
168 a2j_info("map %u:%u (%s) -> '%s'", (unsigned int)client_id, (unsigned int)port_id, direction_string, jack_port);
170 a2j_dbus_construct_method_return_single(
171 call_ptr,
172 DBUS_TYPE_STRING,
173 &jack_port);
176 static
177 void
178 a2j_dbus_map_jack_port_to_alsa(
179 struct a2j_dbus_method_call * call_ptr)
181 snd_seq_client_info_t * client_info_ptr;
182 snd_seq_port_info_t * port_info_ptr;
183 DBusError error;
184 const char * jack_port;
185 struct a2j_port * port_ptr;
186 const char * client_name;
187 const char * port_name;
188 dbus_uint32_t client_id;
189 dbus_uint32_t port_id;
190 DBusMessageIter iter;
193 snd_seq_client_info_alloca(&client_info_ptr);
194 snd_seq_port_info_alloca(&port_info_ptr);
196 dbus_error_init(&error);
198 if (!dbus_message_get_args(
199 call_ptr->message,
200 &error,
201 DBUS_TYPE_STRING, &jack_port,
202 DBUS_TYPE_INVALID))
204 a2j_dbus_error(call_ptr, A2J_DBUS_ERROR_INVALID_ARGS, "Invalid arguments to method \"%s\"", call_ptr->method_name);
205 dbus_error_free(&error);
206 return;
209 if (!a2j_is_started())
211 a2j_dbus_error(call_ptr, A2J_DBUS_ERROR_BRIDGE_NOT_RUNNING, "Bridge not started");
212 return;
215 port_ptr = a2j_find_port_by_jack_port_name(g_a2j->stream + A2J_PORT_CAPTURE, jack_port);
216 if (port_ptr == NULL)
218 port_ptr = a2j_find_port_by_jack_port_name(g_a2j->stream + A2J_PORT_PLAYBACK, jack_port);
219 if (port_ptr == NULL)
221 a2j_dbus_error(call_ptr, A2J_DBUS_ERROR_UNKNOWN_PORT, "Unknown JACK port '%s'", jack_port);
222 return;
226 if (snd_seq_get_any_client_info(g_a2j->seq, port_ptr->remote.client, client_info_ptr) >= 0)
228 client_name = snd_seq_client_info_get_name(client_info_ptr);
230 else
232 client_name = "";
235 if (snd_seq_get_any_port_info(g_a2j->seq, port_ptr->remote.client, port_ptr->remote.port, port_info_ptr) >= 0)
237 port_name = snd_seq_port_info_get_name(port_info_ptr);
239 else
241 port_name = "";
244 a2j_info("map '%s' -> %u:%u ('%s':'%s')", jack_port, (unsigned int)port_ptr->remote.client, (unsigned int)port_ptr->remote.port, client_name, port_name);
246 client_id = port_ptr->remote.client;
247 port_id = port_ptr->remote.port;
249 call_ptr->reply = dbus_message_new_method_return(call_ptr->message);
250 if (call_ptr->reply == NULL)
252 goto fail;
255 dbus_message_iter_init_append(call_ptr->reply, &iter);
257 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT32, &client_id))
259 goto fail_unref;
262 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT32, &port_id))
264 goto fail_unref;
267 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &client_name))
269 goto fail_unref;
272 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &port_name))
274 goto fail_unref;
277 return;
279 fail_unref:
280 dbus_message_unref(call_ptr->reply);
281 call_ptr->reply = NULL;
283 fail:
284 a2j_error("Ran out of memory trying to construct method return");
287 A2J_DBUS_METHOD_ARGUMENTS_BEGIN(exit)
288 A2J_DBUS_METHOD_ARGUMENTS_END
290 A2J_DBUS_METHOD_ARGUMENTS_BEGIN(start)
291 A2J_DBUS_METHOD_ARGUMENTS_END
293 A2J_DBUS_METHOD_ARGUMENTS_BEGIN(stop)
294 A2J_DBUS_METHOD_ARGUMENTS_END
296 A2J_DBUS_METHOD_ARGUMENTS_BEGIN(is_started)
297 A2J_DBUS_METHOD_ARGUMENT("started", DBUS_TYPE_BOOLEAN_AS_STRING, A2J_DBUS_DIRECTION_OUT)
298 A2J_DBUS_METHOD_ARGUMENTS_END
300 A2J_DBUS_METHOD_ARGUMENTS_BEGIN(get_jack_client_name)
301 A2J_DBUS_METHOD_ARGUMENT("jack_client_name", DBUS_TYPE_STRING_AS_STRING, A2J_DBUS_DIRECTION_OUT)
302 A2J_DBUS_METHOD_ARGUMENTS_END
304 A2J_DBUS_METHOD_ARGUMENTS_BEGIN(map_alsa_to_jack_port)
305 A2J_DBUS_METHOD_ARGUMENT("alsa_client_id", DBUS_TYPE_UINT32_AS_STRING, A2J_DBUS_DIRECTION_IN)
306 A2J_DBUS_METHOD_ARGUMENT("alsa_port_id", DBUS_TYPE_UINT32_AS_STRING, A2J_DBUS_DIRECTION_IN)
307 A2J_DBUS_METHOD_ARGUMENT("map_playback", DBUS_TYPE_BOOLEAN_AS_STRING, A2J_DBUS_DIRECTION_IN)
308 A2J_DBUS_METHOD_ARGUMENT("jack_port_name", DBUS_TYPE_STRING_AS_STRING, A2J_DBUS_DIRECTION_OUT)
309 A2J_DBUS_METHOD_ARGUMENTS_END
311 A2J_DBUS_METHOD_ARGUMENTS_BEGIN(map_jack_port_to_alsa)
312 A2J_DBUS_METHOD_ARGUMENT("jack_port_name", "s", A2J_DBUS_DIRECTION_IN)
313 A2J_DBUS_METHOD_ARGUMENT("alsa_client_id", DBUS_TYPE_UINT32_AS_STRING, A2J_DBUS_DIRECTION_OUT)
314 A2J_DBUS_METHOD_ARGUMENT("alsa_port_id", DBUS_TYPE_UINT32_AS_STRING, A2J_DBUS_DIRECTION_OUT)
315 A2J_DBUS_METHOD_ARGUMENT("alsa_client_name", DBUS_TYPE_STRING_AS_STRING, A2J_DBUS_DIRECTION_OUT)
316 A2J_DBUS_METHOD_ARGUMENT("alsa_port_name", DBUS_TYPE_STRING_AS_STRING, A2J_DBUS_DIRECTION_OUT)
317 A2J_DBUS_METHOD_ARGUMENTS_END
319 A2J_DBUS_METHODS_BEGIN
320 A2J_DBUS_METHOD_DESCRIBE(exit, a2j_dbus_exit)
321 A2J_DBUS_METHOD_DESCRIBE(start, a2j_dbus_start)
322 A2J_DBUS_METHOD_DESCRIBE(stop, a2j_dbus_stop)
323 A2J_DBUS_METHOD_DESCRIBE(is_started, a2j_dbus_is_started)
324 A2J_DBUS_METHOD_DESCRIBE(get_jack_client_name, a2j_dbus_get_jack_client_name)
325 A2J_DBUS_METHOD_DESCRIBE(map_alsa_to_jack_port, a2j_dbus_map_alsa_to_jack_port)
326 A2J_DBUS_METHOD_DESCRIBE(map_jack_port_to_alsa, a2j_dbus_map_jack_port_to_alsa)
327 A2J_DBUS_METHODS_END
329 A2J_DBUS_SIGNAL_ARGUMENTS_BEGIN(bridge_started)
330 A2J_DBUS_SIGNAL_ARGUMENTS_END
332 A2J_DBUS_SIGNAL_ARGUMENTS_BEGIN(bridge_stopped)
333 A2J_DBUS_SIGNAL_ARGUMENTS_END
335 A2J_DBUS_SIGNALS_BEGIN
336 A2J_DBUS_SIGNAL_DESCRIBE(bridge_started)
337 A2J_DBUS_SIGNAL_DESCRIBE(bridge_stopped)
338 A2J_DBUS_SIGNALS_END
340 A2J_DBUS_IFACE_BEGIN(g_a2j_iface_control, INTERFACE_NAME)
341 A2J_DBUS_IFACE_EXPOSE_METHODS
342 A2J_DBUS_IFACE_EXPOSE_SIGNALS
343 A2J_DBUS_IFACE_END