1 /* -*- Mode: C ; c-basic-offset: 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
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"
33 #include "port_thread.h"
36 #define INTERFACE_NAME "org.gna.home.a2jmidid.control"
39 a2j_dbus_signal_emit_bridge_started()
41 a2j_dbus_signal("/", INTERFACE_NAME
, "bridge_started", DBUS_TYPE_INVALID
);
45 a2j_dbus_signal_emit_bridge_stopped()
47 a2j_dbus_signal("/", INTERFACE_NAME
, "bridge_stopped", DBUS_TYPE_INVALID
);
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
)
62 dbus_bool_t hw_export
;
66 a2j_dbus_error(call_ptr
, A2J_DBUS_ERROR_BRIDGE_RUNNING
, "Bridge is started");
70 dbus_error_init(&error
);
72 if (!dbus_message_get_args(
75 DBUS_TYPE_BOOLEAN
, &hw_export
,
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
);
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(
105 struct a2j_dbus_method_call
* call_ptr
)
109 a2j_dbus_error(call_ptr
, A2J_DBUS_ERROR_GENERIC
, "a2j_start() failed.");
113 a2j_dbus_construct_method_return_void(call_ptr
);
120 struct a2j_dbus_method_call
* call_ptr
)
124 a2j_dbus_error(call_ptr
, A2J_DBUS_ERROR_GENERIC
, "a2j_stop() failed.");
128 a2j_dbus_construct_method_return_void(call_ptr
);
135 struct a2j_dbus_method_call
* call_ptr
)
137 dbus_bool_t is_started
;
139 is_started
= a2j_is_started();
141 a2j_dbus_construct_method_return_single(
149 a2j_dbus_get_jack_client_name(
150 struct a2j_dbus_method_call
* call_ptr
)
152 const char * jack_client_name
;
154 jack_client_name
= A2J_JACK_CLIENT_NAME
;
156 a2j_dbus_construct_method_return_single(
164 a2j_dbus_map_alsa_to_jack_port(
165 struct a2j_dbus_method_call
* call_ptr
)
168 dbus_uint32_t client_id
;
169 dbus_uint32_t port_id
;
170 dbus_bool_t map_playback
;
172 struct a2j_port
* port_ptr
;
173 const char * direction_string
;
174 struct a2j_stream
* stream_ptr
;
175 const char * jack_port
;
177 dbus_error_init(&error
);
179 if (!dbus_message_get_args(
182 DBUS_TYPE_UINT32
, &client_id
,
183 DBUS_TYPE_UINT32
, &port_id
,
184 DBUS_TYPE_BOOLEAN
, &map_playback
,
187 a2j_dbus_error(call_ptr
, A2J_DBUS_ERROR_INVALID_ARGS
, "Invalid arguments to method \"%s\"", call_ptr
->method_name
);
188 dbus_error_free(&error
);
192 if (!a2j_is_started())
194 a2j_dbus_error(call_ptr
, A2J_DBUS_ERROR_BRIDGE_NOT_RUNNING
, "Bridge not started");
198 addr
.client
= client_id
;
203 stream_ptr
= g_a2j
->stream
+ A2J_PORT_PLAYBACK
;
204 direction_string
= "playback";
208 stream_ptr
= g_a2j
->stream
+ A2J_PORT_CAPTURE
;
209 direction_string
= "capture";
212 port_ptr
= a2j_find_port_by_addr(stream_ptr
, addr
);
213 if (port_ptr
== NULL
)
215 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
);
219 jack_port
= port_ptr
->name
;
221 a2j_info("map %u:%u (%s) -> '%s'", (unsigned int)client_id
, (unsigned int)port_id
, direction_string
, jack_port
);
223 a2j_dbus_construct_method_return_single(
231 a2j_dbus_map_jack_port_to_alsa(
232 struct a2j_dbus_method_call
* call_ptr
)
234 snd_seq_client_info_t
* client_info_ptr
;
235 snd_seq_port_info_t
* port_info_ptr
;
237 const char * jack_port
;
238 struct a2j_port
* port_ptr
;
239 const char * client_name
;
240 const char * port_name
;
241 dbus_uint32_t client_id
;
242 dbus_uint32_t port_id
;
243 DBusMessageIter iter
;
246 snd_seq_client_info_alloca(&client_info_ptr
);
247 snd_seq_port_info_alloca(&port_info_ptr
);
249 dbus_error_init(&error
);
251 if (!dbus_message_get_args(
254 DBUS_TYPE_STRING
, &jack_port
,
257 a2j_dbus_error(call_ptr
, A2J_DBUS_ERROR_INVALID_ARGS
, "Invalid arguments to method \"%s\"", call_ptr
->method_name
);
258 dbus_error_free(&error
);
262 if (!a2j_is_started())
264 a2j_dbus_error(call_ptr
, A2J_DBUS_ERROR_BRIDGE_NOT_RUNNING
, "Bridge not started");
268 port_ptr
= a2j_find_port_by_jack_port_name(g_a2j
->stream
+ A2J_PORT_CAPTURE
, jack_port
);
269 if (port_ptr
== NULL
)
271 port_ptr
= a2j_find_port_by_jack_port_name(g_a2j
->stream
+ A2J_PORT_PLAYBACK
, jack_port
);
272 if (port_ptr
== NULL
)
274 a2j_dbus_error(call_ptr
, A2J_DBUS_ERROR_UNKNOWN_PORT
, "Unknown JACK port '%s'", jack_port
);
279 if (snd_seq_get_any_client_info(g_a2j
->seq
, port_ptr
->remote
.client
, client_info_ptr
) >= 0)
281 client_name
= snd_seq_client_info_get_name(client_info_ptr
);
288 if (snd_seq_get_any_port_info(g_a2j
->seq
, port_ptr
->remote
.client
, port_ptr
->remote
.port
, port_info_ptr
) >= 0)
290 port_name
= snd_seq_port_info_get_name(port_info_ptr
);
297 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
);
299 client_id
= port_ptr
->remote
.client
;
300 port_id
= port_ptr
->remote
.port
;
302 call_ptr
->reply
= dbus_message_new_method_return(call_ptr
->message
);
303 if (call_ptr
->reply
== NULL
)
308 dbus_message_iter_init_append(call_ptr
->reply
, &iter
);
310 if (!dbus_message_iter_append_basic(&iter
, DBUS_TYPE_UINT32
, &client_id
))
315 if (!dbus_message_iter_append_basic(&iter
, DBUS_TYPE_UINT32
, &port_id
))
320 if (!dbus_message_iter_append_basic(&iter
, DBUS_TYPE_STRING
, &client_name
))
325 if (!dbus_message_iter_append_basic(&iter
, DBUS_TYPE_STRING
, &port_name
))
333 dbus_message_unref(call_ptr
->reply
);
334 call_ptr
->reply
= NULL
;
337 a2j_error("Ran out of memory trying to construct method return");
340 A2J_DBUS_METHOD_ARGUMENTS_BEGIN(exit
)
341 A2J_DBUS_METHOD_ARGUMENTS_END
343 A2J_DBUS_METHOD_ARGUMENTS_BEGIN(start
)
344 A2J_DBUS_METHOD_ARGUMENTS_END
346 A2J_DBUS_METHOD_ARGUMENTS_BEGIN(stop
)
347 A2J_DBUS_METHOD_ARGUMENTS_END
349 A2J_DBUS_METHOD_ARGUMENTS_BEGIN(is_started
)
350 A2J_DBUS_METHOD_ARGUMENT("started", DBUS_TYPE_BOOLEAN_AS_STRING
, A2J_DBUS_DIRECTION_OUT
)
351 A2J_DBUS_METHOD_ARGUMENTS_END
353 A2J_DBUS_METHOD_ARGUMENTS_BEGIN(get_jack_client_name
)
354 A2J_DBUS_METHOD_ARGUMENT("jack_client_name", DBUS_TYPE_STRING_AS_STRING
, A2J_DBUS_DIRECTION_OUT
)
355 A2J_DBUS_METHOD_ARGUMENTS_END
357 A2J_DBUS_METHOD_ARGUMENTS_BEGIN(map_alsa_to_jack_port
)
358 A2J_DBUS_METHOD_ARGUMENT("alsa_client_id", DBUS_TYPE_UINT32_AS_STRING
, A2J_DBUS_DIRECTION_IN
)
359 A2J_DBUS_METHOD_ARGUMENT("alsa_port_id", DBUS_TYPE_UINT32_AS_STRING
, A2J_DBUS_DIRECTION_IN
)
360 A2J_DBUS_METHOD_ARGUMENT("map_playback", DBUS_TYPE_BOOLEAN_AS_STRING
, A2J_DBUS_DIRECTION_IN
)
361 A2J_DBUS_METHOD_ARGUMENT("jack_port_name", DBUS_TYPE_STRING_AS_STRING
, A2J_DBUS_DIRECTION_OUT
)
362 A2J_DBUS_METHOD_ARGUMENTS_END
364 A2J_DBUS_METHOD_ARGUMENTS_BEGIN(map_jack_port_to_alsa
)
365 A2J_DBUS_METHOD_ARGUMENT("jack_port_name", "s", A2J_DBUS_DIRECTION_IN
)
366 A2J_DBUS_METHOD_ARGUMENT("alsa_client_id", DBUS_TYPE_UINT32_AS_STRING
, A2J_DBUS_DIRECTION_OUT
)
367 A2J_DBUS_METHOD_ARGUMENT("alsa_port_id", DBUS_TYPE_UINT32_AS_STRING
, A2J_DBUS_DIRECTION_OUT
)
368 A2J_DBUS_METHOD_ARGUMENT("alsa_client_name", DBUS_TYPE_STRING_AS_STRING
, A2J_DBUS_DIRECTION_OUT
)
369 A2J_DBUS_METHOD_ARGUMENT("alsa_port_name", DBUS_TYPE_STRING_AS_STRING
, A2J_DBUS_DIRECTION_OUT
)
370 A2J_DBUS_METHOD_ARGUMENTS_END
372 A2J_DBUS_METHOD_ARGUMENTS_BEGIN(set_hw_export
)
373 A2J_DBUS_METHOD_ARGUMENT("hw_export", DBUS_TYPE_BOOLEAN_AS_STRING
, A2J_DBUS_DIRECTION_IN
)
374 A2J_DBUS_METHOD_ARGUMENTS_END
376 A2J_DBUS_METHOD_ARGUMENTS_BEGIN(get_hw_export
)
377 A2J_DBUS_METHOD_ARGUMENT("hw_export", DBUS_TYPE_BOOLEAN_AS_STRING
, A2J_DBUS_DIRECTION_OUT
)
378 A2J_DBUS_METHOD_ARGUMENTS_END
380 A2J_DBUS_METHODS_BEGIN
381 A2J_DBUS_METHOD_DESCRIBE(exit
, a2j_dbus_exit
)
382 A2J_DBUS_METHOD_DESCRIBE(start
, a2j_dbus_start
)
383 A2J_DBUS_METHOD_DESCRIBE(stop
, a2j_dbus_stop
)
384 A2J_DBUS_METHOD_DESCRIBE(is_started
, a2j_dbus_is_started
)
385 A2J_DBUS_METHOD_DESCRIBE(get_jack_client_name
, a2j_dbus_get_jack_client_name
)
386 A2J_DBUS_METHOD_DESCRIBE(map_alsa_to_jack_port
, a2j_dbus_map_alsa_to_jack_port
)
387 A2J_DBUS_METHOD_DESCRIBE(map_jack_port_to_alsa
, a2j_dbus_map_jack_port_to_alsa
)
388 A2J_DBUS_METHOD_DESCRIBE(set_hw_export
, a2j_dbus_set_hw_export
)
389 A2J_DBUS_METHOD_DESCRIBE(get_hw_export
, a2j_dbus_get_hw_export
)
392 A2J_DBUS_SIGNAL_ARGUMENTS_BEGIN(bridge_started
)
393 A2J_DBUS_SIGNAL_ARGUMENTS_END
395 A2J_DBUS_SIGNAL_ARGUMENTS_BEGIN(bridge_stopped
)
396 A2J_DBUS_SIGNAL_ARGUMENTS_END
398 A2J_DBUS_SIGNALS_BEGIN
399 A2J_DBUS_SIGNAL_DESCRIBE(bridge_started
)
400 A2J_DBUS_SIGNAL_DESCRIBE(bridge_stopped
)
403 A2J_DBUS_IFACE_BEGIN(g_a2j_iface_control
, INTERFACE_NAME
)
404 A2J_DBUS_IFACE_EXPOSE_METHODS
405 A2J_DBUS_IFACE_EXPOSE_SIGNALS