website/index.html: Extend Feedback section (codeberg.org)
[a2jmidid.git] / dbus_iface_control.c
blob1928b01948661ce9aa86dacb77ddb4533bf9983a
1 /* -*- Mode: C ; c-basic-offset: 2 -*- */
2 /*
3 * ALSA SEQ < - > JACK MIDI bridge
5 * Copyright (c) 2008,2009 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"
34 #include "conf.h"
36 #define INTERFACE_NAME "org.gna.home.a2jmidid.control"
38 void
39 a2j_dbus_signal_emit_bridge_started(void)
41 a2j_dbus_signal("/", INTERFACE_NAME, "bridge_started", DBUS_TYPE_INVALID);
44 void
45 a2j_dbus_signal_emit_bridge_stopped(void)
47 a2j_dbus_signal("/", INTERFACE_NAME, "bridge_stopped", DBUS_TYPE_INVALID);
50 static
51 void
52 a2j_dbus_exit(
53 struct a2j_dbus_method_call * call_ptr)
55 g_keep_walking = false;
56 a2j_dbus_construct_method_return_void(call_ptr);
59 static void a2j_dbus_set_hw_export(struct a2j_dbus_method_call * call_ptr)
61 DBusError error;
62 dbus_bool_t hw_export;
64 if (a2j_is_started())
66 a2j_dbus_error(call_ptr, A2J_DBUS_ERROR_BRIDGE_RUNNING, "Bridge is started");
67 return;
70 dbus_error_init(&error);
72 if (!dbus_message_get_args(
73 call_ptr->message,
74 &error,
75 DBUS_TYPE_BOOLEAN, &hw_export,
76 DBUS_TYPE_INVALID))
78 a2j_dbus_error(call_ptr, A2J_DBUS_ERROR_INVALID_ARGS, "Invalid arguments to method \"%s\"", call_ptr->method_name);
79 dbus_error_free(&error);
80 return;
83 g_a2j_export_hw_ports = hw_export;
85 a2j_info("Hardware ports %s be exported.", g_a2j_export_hw_ports ? "will": "will not");
87 a2j_dbus_construct_method_return_void(call_ptr);
90 static void a2j_dbus_get_hw_export(struct a2j_dbus_method_call * call_ptr)
92 dbus_bool_t hw_export;
94 hw_export = g_a2j_export_hw_ports;
96 a2j_dbus_construct_method_return_single(
97 call_ptr,
98 DBUS_TYPE_BOOLEAN,
99 &hw_export);
102 static void a2j_dbus_get_disable_port_uniqueness(struct a2j_dbus_method_call * call_ptr)
104 dbus_bool_t disable_port_uniqueness;
106 disable_port_uniqueness = g_disable_port_uniqueness;
108 a2j_dbus_construct_method_return_single(
109 call_ptr,
110 DBUS_TYPE_BOOLEAN,
111 &disable_port_uniqueness);
114 static void a2j_dbus_set_disable_port_uniqueness(struct a2j_dbus_method_call * call_ptr)
116 DBusError error;
117 dbus_bool_t disable_port_uniqueness;
119 if (a2j_is_started())
121 a2j_dbus_error(call_ptr, A2J_DBUS_ERROR_BRIDGE_RUNNING, "Bridge is started");
122 return;
125 dbus_error_init(&error);
127 if (!dbus_message_get_args(
128 call_ptr->message,
129 &error,
130 DBUS_TYPE_BOOLEAN, &disable_port_uniqueness,
131 DBUS_TYPE_INVALID))
133 a2j_dbus_error(call_ptr, A2J_DBUS_ERROR_INVALID_ARGS, "Invalid arguments to method \"%s\"", call_ptr->method_name);
134 dbus_error_free(&error);
135 return;
138 g_disable_port_uniqueness = disable_port_uniqueness;
140 a2j_info("Unique port names %s.", g_disable_port_uniqueness ? "disabled": "enabled");
142 a2j_dbus_construct_method_return_void(call_ptr);
145 static
146 void
147 a2j_dbus_start(
148 struct a2j_dbus_method_call * call_ptr)
150 if (!a2j_start())
152 a2j_dbus_error(call_ptr, A2J_DBUS_ERROR_GENERIC, "a2j_start() failed.");
154 else
156 a2j_dbus_construct_method_return_void(call_ptr);
160 static
161 void
162 a2j_dbus_stop(
163 struct a2j_dbus_method_call * call_ptr)
165 if (!a2j_stop())
167 a2j_dbus_error(call_ptr, A2J_DBUS_ERROR_GENERIC, "a2j_stop() failed.");
169 else
171 a2j_dbus_construct_method_return_void(call_ptr);
175 static
176 void
177 a2j_dbus_is_started(
178 struct a2j_dbus_method_call * call_ptr)
180 dbus_bool_t is_started;
182 is_started = a2j_is_started();
184 a2j_dbus_construct_method_return_single(
185 call_ptr,
186 DBUS_TYPE_BOOLEAN,
187 &is_started);
190 static
191 void
192 a2j_dbus_get_jack_client_name(
193 struct a2j_dbus_method_call * call_ptr)
195 const char * jack_client_name;
197 jack_client_name = A2J_JACK_CLIENT_NAME;
199 a2j_dbus_construct_method_return_single(
200 call_ptr,
201 DBUS_TYPE_STRING,
202 &jack_client_name);
205 static
206 void
207 a2j_dbus_map_alsa_to_jack_port(
208 struct a2j_dbus_method_call * call_ptr)
210 DBusError error;
211 dbus_uint32_t client_id;
212 dbus_uint32_t port_id;
213 dbus_bool_t map_playback;
214 snd_seq_addr_t addr;
215 struct a2j_port * port_ptr;
216 const char * direction_string;
217 struct a2j_stream * stream_ptr;
218 const char * jack_port;
220 dbus_error_init(&error);
222 if (!dbus_message_get_args(
223 call_ptr->message,
224 &error,
225 DBUS_TYPE_UINT32, &client_id,
226 DBUS_TYPE_UINT32, &port_id,
227 DBUS_TYPE_BOOLEAN, &map_playback,
228 DBUS_TYPE_INVALID))
230 a2j_dbus_error(call_ptr, A2J_DBUS_ERROR_INVALID_ARGS, "Invalid arguments to method \"%s\"", call_ptr->method_name);
231 dbus_error_free(&error);
232 return;
235 if (!a2j_is_started())
237 a2j_dbus_error(call_ptr, A2J_DBUS_ERROR_BRIDGE_NOT_RUNNING, "Bridge not started");
238 return;
241 addr.client = client_id;
242 addr.port = port_id;
244 if (map_playback)
246 stream_ptr = g_a2j->stream + A2J_PORT_PLAYBACK;
247 direction_string = "playback";
249 else
251 stream_ptr = g_a2j->stream + A2J_PORT_CAPTURE;
252 direction_string = "capture";
255 port_ptr = a2j_find_port_by_addr(stream_ptr, addr);
256 if (port_ptr == NULL)
258 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);
259 return;
262 jack_port = port_ptr->name;
264 a2j_info("map %u:%u (%s) -> '%s'", (unsigned int)client_id, (unsigned int)port_id, direction_string, jack_port);
266 a2j_dbus_construct_method_return_single(
267 call_ptr,
268 DBUS_TYPE_STRING,
269 &jack_port);
272 static
273 void
274 a2j_dbus_map_jack_port_to_alsa(
275 struct a2j_dbus_method_call * call_ptr)
277 snd_seq_client_info_t * client_info_ptr;
278 snd_seq_port_info_t * port_info_ptr;
279 DBusError error;
280 const char * jack_port;
281 struct a2j_port * port_ptr;
282 const char * client_name;
283 const char * port_name;
284 dbus_uint32_t client_id;
285 dbus_uint32_t port_id;
286 DBusMessageIter iter;
289 snd_seq_client_info_alloca(&client_info_ptr);
290 snd_seq_port_info_alloca(&port_info_ptr);
292 dbus_error_init(&error);
294 if (!dbus_message_get_args(
295 call_ptr->message,
296 &error,
297 DBUS_TYPE_STRING, &jack_port,
298 DBUS_TYPE_INVALID))
300 a2j_dbus_error(call_ptr, A2J_DBUS_ERROR_INVALID_ARGS, "Invalid arguments to method \"%s\"", call_ptr->method_name);
301 dbus_error_free(&error);
302 return;
305 if (!a2j_is_started())
307 a2j_dbus_error(call_ptr, A2J_DBUS_ERROR_BRIDGE_NOT_RUNNING, "Bridge not started");
308 return;
311 port_ptr = a2j_find_port_by_jack_port_name(g_a2j->stream + A2J_PORT_CAPTURE, jack_port);
312 if (port_ptr == NULL)
314 port_ptr = a2j_find_port_by_jack_port_name(g_a2j->stream + A2J_PORT_PLAYBACK, jack_port);
315 if (port_ptr == NULL)
317 a2j_dbus_error(call_ptr, A2J_DBUS_ERROR_UNKNOWN_PORT, "Unknown JACK port '%s'", jack_port);
318 return;
322 if (snd_seq_get_any_client_info(g_a2j->seq, port_ptr->remote.client, client_info_ptr) >= 0)
324 client_name = snd_seq_client_info_get_name(client_info_ptr);
326 else
328 client_name = "";
331 if (snd_seq_get_any_port_info(g_a2j->seq, port_ptr->remote.client, port_ptr->remote.port, port_info_ptr) >= 0)
333 port_name = snd_seq_port_info_get_name(port_info_ptr);
335 else
337 port_name = "";
340 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);
342 client_id = port_ptr->remote.client;
343 port_id = port_ptr->remote.port;
345 call_ptr->reply = dbus_message_new_method_return(call_ptr->message);
346 if (call_ptr->reply == NULL)
348 goto fail;
351 dbus_message_iter_init_append(call_ptr->reply, &iter);
353 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT32, &client_id))
355 goto fail_unref;
358 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT32, &port_id))
360 goto fail_unref;
363 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &client_name))
365 goto fail_unref;
368 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &port_name))
370 goto fail_unref;
373 return;
375 fail_unref:
376 dbus_message_unref(call_ptr->reply);
377 call_ptr->reply = NULL;
379 fail:
380 a2j_error("Ran out of memory trying to construct method return");
383 A2J_DBUS_METHOD_ARGUMENTS_BEGIN(exit)
384 A2J_DBUS_METHOD_ARGUMENTS_END
386 A2J_DBUS_METHOD_ARGUMENTS_BEGIN(start)
387 A2J_DBUS_METHOD_ARGUMENTS_END
389 A2J_DBUS_METHOD_ARGUMENTS_BEGIN(stop)
390 A2J_DBUS_METHOD_ARGUMENTS_END
392 A2J_DBUS_METHOD_ARGUMENTS_BEGIN(is_started)
393 A2J_DBUS_METHOD_ARGUMENT("started", DBUS_TYPE_BOOLEAN_AS_STRING, A2J_DBUS_DIRECTION_OUT)
394 A2J_DBUS_METHOD_ARGUMENTS_END
396 A2J_DBUS_METHOD_ARGUMENTS_BEGIN(get_jack_client_name)
397 A2J_DBUS_METHOD_ARGUMENT("jack_client_name", DBUS_TYPE_STRING_AS_STRING, A2J_DBUS_DIRECTION_OUT)
398 A2J_DBUS_METHOD_ARGUMENTS_END
400 A2J_DBUS_METHOD_ARGUMENTS_BEGIN(map_alsa_to_jack_port)
401 A2J_DBUS_METHOD_ARGUMENT("alsa_client_id", DBUS_TYPE_UINT32_AS_STRING, A2J_DBUS_DIRECTION_IN)
402 A2J_DBUS_METHOD_ARGUMENT("alsa_port_id", DBUS_TYPE_UINT32_AS_STRING, A2J_DBUS_DIRECTION_IN)
403 A2J_DBUS_METHOD_ARGUMENT("map_playback", DBUS_TYPE_BOOLEAN_AS_STRING, A2J_DBUS_DIRECTION_IN)
404 A2J_DBUS_METHOD_ARGUMENT("jack_port_name", DBUS_TYPE_STRING_AS_STRING, A2J_DBUS_DIRECTION_OUT)
405 A2J_DBUS_METHOD_ARGUMENTS_END
407 A2J_DBUS_METHOD_ARGUMENTS_BEGIN(map_jack_port_to_alsa)
408 A2J_DBUS_METHOD_ARGUMENT("jack_port_name", "s", A2J_DBUS_DIRECTION_IN)
409 A2J_DBUS_METHOD_ARGUMENT("alsa_client_id", DBUS_TYPE_UINT32_AS_STRING, A2J_DBUS_DIRECTION_OUT)
410 A2J_DBUS_METHOD_ARGUMENT("alsa_port_id", DBUS_TYPE_UINT32_AS_STRING, A2J_DBUS_DIRECTION_OUT)
411 A2J_DBUS_METHOD_ARGUMENT("alsa_client_name", DBUS_TYPE_STRING_AS_STRING, A2J_DBUS_DIRECTION_OUT)
412 A2J_DBUS_METHOD_ARGUMENT("alsa_port_name", DBUS_TYPE_STRING_AS_STRING, A2J_DBUS_DIRECTION_OUT)
413 A2J_DBUS_METHOD_ARGUMENTS_END
415 A2J_DBUS_METHOD_ARGUMENTS_BEGIN(set_hw_export)
416 A2J_DBUS_METHOD_ARGUMENT("hw_export", DBUS_TYPE_BOOLEAN_AS_STRING, A2J_DBUS_DIRECTION_IN)
417 A2J_DBUS_METHOD_ARGUMENTS_END
419 A2J_DBUS_METHOD_ARGUMENTS_BEGIN(get_hw_export)
420 A2J_DBUS_METHOD_ARGUMENT("hw_export", DBUS_TYPE_BOOLEAN_AS_STRING, A2J_DBUS_DIRECTION_OUT)
421 A2J_DBUS_METHOD_ARGUMENTS_END
423 A2J_DBUS_METHOD_ARGUMENTS_BEGIN(set_disable_port_uniqueness)
424 A2J_DBUS_METHOD_ARGUMENT("disable_port_uniqueness", DBUS_TYPE_BOOLEAN_AS_STRING, A2J_DBUS_DIRECTION_IN)
425 A2J_DBUS_METHOD_ARGUMENTS_END
427 A2J_DBUS_METHOD_ARGUMENTS_BEGIN(get_disable_port_uniqueness)
428 A2J_DBUS_METHOD_ARGUMENT("disable_port_uniqueness", DBUS_TYPE_BOOLEAN_AS_STRING, A2J_DBUS_DIRECTION_OUT)
429 A2J_DBUS_METHOD_ARGUMENTS_END
431 A2J_DBUS_METHODS_BEGIN
432 A2J_DBUS_METHOD_DESCRIBE(exit, a2j_dbus_exit)
433 A2J_DBUS_METHOD_DESCRIBE(start, a2j_dbus_start)
434 A2J_DBUS_METHOD_DESCRIBE(stop, a2j_dbus_stop)
435 A2J_DBUS_METHOD_DESCRIBE(is_started, a2j_dbus_is_started)
436 A2J_DBUS_METHOD_DESCRIBE(get_jack_client_name, a2j_dbus_get_jack_client_name)
437 A2J_DBUS_METHOD_DESCRIBE(map_alsa_to_jack_port, a2j_dbus_map_alsa_to_jack_port)
438 A2J_DBUS_METHOD_DESCRIBE(map_jack_port_to_alsa, a2j_dbus_map_jack_port_to_alsa)
439 A2J_DBUS_METHOD_DESCRIBE(set_hw_export, a2j_dbus_set_hw_export)
440 A2J_DBUS_METHOD_DESCRIBE(get_hw_export, a2j_dbus_get_hw_export)
441 A2J_DBUS_METHOD_DESCRIBE(set_disable_port_uniqueness, a2j_dbus_set_disable_port_uniqueness)
442 A2J_DBUS_METHOD_DESCRIBE(get_disable_port_uniqueness, a2j_dbus_get_disable_port_uniqueness)
443 A2J_DBUS_METHODS_END
445 A2J_DBUS_SIGNAL_ARGUMENTS_BEGIN(bridge_started)
446 A2J_DBUS_SIGNAL_ARGUMENTS_END
448 A2J_DBUS_SIGNAL_ARGUMENTS_BEGIN(bridge_stopped)
449 A2J_DBUS_SIGNAL_ARGUMENTS_END
451 A2J_DBUS_SIGNALS_BEGIN
452 A2J_DBUS_SIGNAL_DESCRIBE(bridge_started)
453 A2J_DBUS_SIGNAL_DESCRIBE(bridge_stopped)
454 A2J_DBUS_SIGNALS_END
456 A2J_DBUS_IFACE_BEGIN(g_a2j_iface_control, INTERFACE_NAME)
457 A2J_DBUS_IFACE_EXPOSE_METHODS
458 A2J_DBUS_IFACE_EXPOSE_SIGNALS
459 A2J_DBUS_IFACE_END