2 * connect / disconnect two subscriber ports
5 * Copyright (C) 1999 Takashi Iwai
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
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.
27 #include <sys/ioctl.h>
28 #include <alsa/asoundlib.h>
32 static void error_handler(const char *file, int line, const char *function, int err, const char *fmt, ...)
36 if (err == ENOENT) /* Ignore those misleading "warnings" */
39 fprintf(stderr, "ALSA lib %s:%i:(%s) ", file, line, function);
40 vfprintf(stderr, fmt, arg);
42 fprintf(stderr, ": %s", snd_strerror(err));
47 static void usage(void)
49 printf(_("aconnect - ALSA sequencer connection manager\n"));
50 printf(_("Copyright (C) 1999-2000 Takashi Iwai\n"));
51 printf(_("Usage:\n"));
52 printf(_(" * Connection/disconnection between two ports\n"));
53 printf(_(" aconnect [-options] sender receiver\n"));
54 printf(_(" sender, receiver = client:port pair\n"));
55 printf(_(" -d,--disconnect disconnect\n"));
56 printf(_(" -e,--exclusive exclusive connection\n"));
57 printf(_(" -r,--real # convert real-time-stamp on queue\n"));
58 printf(_(" -t,--tick # convert tick-time-stamp on queue\n"));
59 printf(_(" * List connected ports (no subscription action)\n"));
60 printf(_(" aconnect -i|-o [-options]\n"));
61 printf(_(" -i,--input list input (readable) ports\n"));
62 printf(_(" -o,--output list output (writable) ports\n"));
63 printf(_(" -l,--list list current connections of each port\n"));
64 printf(_(" * Remove all exported connections\n"));
65 printf(_(" -x, --removeall\n"));
69 * check permission (capability) of specified port
75 #define perm_ok(pinfo,bits) ((snd_seq_port_info_get_capability(pinfo) & (bits)) == (bits))
77 static int check_permission(snd_seq_port_info_t *pinfo, int perm)
80 if (perm & LIST_INPUT) {
81 if (perm_ok(pinfo, SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ))
84 if (perm & LIST_OUTPUT) {
85 if (perm_ok(pinfo, SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE))
91 if (snd_seq_port_info_get_capability(pinfo) & SND_SEQ_PORT_CAP_NO_EXPORT)
97 * list subscribers of specified type
99 static void list_each_subs(snd_seq_t *seq, snd_seq_query_subscribe_t *subs, int type, const char *msg)
102 snd_seq_query_subscribe_set_type(subs, type);
103 snd_seq_query_subscribe_set_index(subs, 0);
104 while (snd_seq_query_port_subscribers(seq, subs) >= 0) {
105 const snd_seq_addr_t *addr;
107 printf("\t%s: ", msg);
110 addr = snd_seq_query_subscribe_get_addr(subs);
111 printf("%d:%d", addr->client, addr->port);
112 if (snd_seq_query_subscribe_get_exclusive(subs))
114 if (snd_seq_query_subscribe_get_time_update(subs))
116 (snd_seq_query_subscribe_get_time_real(subs) ? "real" : "tick"),
117 snd_seq_query_subscribe_get_queue(subs));
118 snd_seq_query_subscribe_set_index(subs, snd_seq_query_subscribe_get_index(subs) + 1);
127 static void list_subscribers(snd_seq_t *seq, const snd_seq_addr_t *addr)
129 snd_seq_query_subscribe_t *subs;
130 snd_seq_query_subscribe_alloca(&subs);
131 snd_seq_query_subscribe_set_root(subs, addr);
132 list_each_subs(seq, subs, SND_SEQ_QUERY_SUBS_READ, _("Connecting To"));
133 list_each_subs(seq, subs, SND_SEQ_QUERY_SUBS_WRITE, _("Connected From"));
139 typedef void (*action_func_t)(snd_seq_t *seq, snd_seq_client_info_t *cinfo, snd_seq_port_info_t *pinfo, int count);
141 static void do_search_port(snd_seq_t *seq, int perm, action_func_t do_action)
143 snd_seq_client_info_t *cinfo;
144 snd_seq_port_info_t *pinfo;
147 snd_seq_client_info_alloca(&cinfo);
148 snd_seq_port_info_alloca(&pinfo);
149 snd_seq_client_info_set_client(cinfo, -1);
150 while (snd_seq_query_next_client(seq, cinfo) >= 0) {
151 /* reset query info */
152 snd_seq_port_info_set_client(pinfo, snd_seq_client_info_get_client(cinfo));
153 snd_seq_port_info_set_port(pinfo, -1);
155 while (snd_seq_query_next_port(seq, pinfo) >= 0) {
156 if (check_permission(pinfo, perm)) {
157 do_action(seq, cinfo, pinfo, count);
165 static void print_port(snd_seq_t *seq, snd_seq_client_info_t *cinfo,
166 snd_seq_port_info_t *pinfo, int count)
169 printf(_("client %d: '%s' [type=%s]\n"),
170 snd_seq_client_info_get_client(cinfo),
171 snd_seq_client_info_get_name(cinfo),
172 (snd_seq_client_info_get_type(cinfo) == SND_SEQ_USER_CLIENT ?
173 _("user") : _("kernel")));
175 printf(" %3d '%-16s'\n",
176 snd_seq_port_info_get_port(pinfo),
177 snd_seq_port_info_get_name(pinfo));
180 static void print_port_and_subs(snd_seq_t *seq, snd_seq_client_info_t *cinfo,
181 snd_seq_port_info_t *pinfo, int count)
183 print_port(seq, cinfo, pinfo, count);
184 list_subscribers(seq, snd_seq_port_info_get_addr(pinfo));
189 * remove all (exported) connections
191 static void remove_connection(snd_seq_t *seq, snd_seq_client_info_t *cinfo,
192 snd_seq_port_info_t *pinfo, int count)
194 snd_seq_query_subscribe_t *query;
196 snd_seq_query_subscribe_alloca(&query);
197 snd_seq_query_subscribe_set_root(query, snd_seq_port_info_get_addr(pinfo));
199 snd_seq_query_subscribe_set_type(query, SND_SEQ_QUERY_SUBS_READ);
200 snd_seq_query_subscribe_set_index(query, 0);
201 for (; snd_seq_query_port_subscribers(seq, query) >= 0;
202 snd_seq_query_subscribe_set_index(query, snd_seq_query_subscribe_get_index(query) + 1)) {
203 snd_seq_port_info_t *port;
204 snd_seq_port_subscribe_t *subs;
205 const snd_seq_addr_t *sender = snd_seq_query_subscribe_get_root(query);
206 const snd_seq_addr_t *dest = snd_seq_query_subscribe_get_addr(query);
207 snd_seq_port_info_alloca(&port);
208 if (snd_seq_get_any_port_info(seq, dest->client, dest->port, port) < 0)
210 if (!(snd_seq_port_info_get_capability(port) & SND_SEQ_PORT_CAP_SUBS_WRITE))
212 if (snd_seq_port_info_get_capability(port) & SND_SEQ_PORT_CAP_NO_EXPORT)
214 snd_seq_port_subscribe_alloca(&subs);
215 snd_seq_port_subscribe_set_queue(subs, snd_seq_query_subscribe_get_queue(query));
216 snd_seq_port_subscribe_set_sender(subs, sender);
217 snd_seq_port_subscribe_set_dest(subs, dest);
218 snd_seq_unsubscribe_port(seq, subs);
221 snd_seq_query_subscribe_set_type(query, SND_SEQ_QUERY_SUBS_WRITE);
222 snd_seq_query_subscribe_set_index(query, 0);
223 for (; snd_seq_query_port_subscribers(seq, query) >= 0;
224 snd_seq_query_subscribe_set_index(query, snd_seq_query_subscribe_get_index(query) + 1)) {
225 snd_seq_port_info_t *port;
226 snd_seq_port_subscribe_t *subs;
227 const snd_seq_addr_t *dest = snd_seq_query_subscribe_get_root(query);
228 const snd_seq_addr_t *sender = snd_seq_query_subscribe_get_addr(query);
229 snd_seq_port_info_alloca(&port);
230 if (snd_seq_get_any_port_info(seq, sender->client, sender->port, port) < 0)
232 if (!(snd_seq_port_info_get_capability(port) & SND_SEQ_PORT_CAP_SUBS_READ))
234 if (snd_seq_port_info_get_capability(port) & SND_SEQ_PORT_CAP_NO_EXPORT)
236 snd_seq_port_subscribe_alloca(&subs);
237 snd_seq_port_subscribe_set_queue(subs, snd_seq_query_subscribe_get_queue(query));
238 snd_seq_port_subscribe_set_sender(subs, sender);
239 snd_seq_port_subscribe_set_dest(subs, dest);
240 snd_seq_unsubscribe_port(seq, subs);
244 static void remove_all_connections(snd_seq_t *seq)
246 do_search_port(seq, 0, remove_connection);
255 SUBSCRIBE, UNSUBSCRIBE, LIST, REMOVE_ALL
258 static struct option long_option[] = {
259 {"disconnect", 0, NULL, 'd'},
260 {"input", 0, NULL, 'i'},
261 {"output", 0, NULL, 'o'},
262 {"real", 1, NULL, 'r'},
263 {"tick", 1, NULL, 't'},
264 {"exclusive", 0, NULL, 'e'},
265 {"list", 0, NULL, 'l'},
266 {"removeall", 0, NULL, 'x'},
270 int main(int argc, char **argv)
274 int queue = 0, convert_time = 0, convert_real = 0, exclusive = 0;
275 int command = SUBSCRIBE;
279 snd_seq_port_subscribe_t *subs;
280 snd_seq_addr_t sender, dest;
283 setlocale(LC_ALL, "");
287 while ((c = getopt_long(argc, argv, "dior:t:elx", long_option, NULL)) != -1) {
290 command = UNSUBSCRIBE;
294 list_perm |= LIST_INPUT;
298 list_perm |= LIST_OUTPUT;
304 queue = atoi(optarg);
309 queue = atoi(optarg);
317 command = REMOVE_ALL;
325 if (snd_seq_open(&seq, "default", SND_SEQ_OPEN_DUPLEX, 0) < 0) {
326 fprintf(stderr, _("can't open sequencer\n"));
330 snd_lib_error_set_handler(error_handler);
334 do_search_port(seq, list_perm,
335 list_subs ? print_port_and_subs : print_port);
339 remove_all_connections(seq);
344 /* connection or disconnection */
346 if (optind + 2 > argc) {
352 if ((client = snd_seq_client_id(seq)) < 0) {
354 fprintf(stderr, _("can't get client id\n"));
358 /* set client info */
359 if (snd_seq_set_client_name(seq, "ALSA Connector") < 0) {
361 fprintf(stderr, _("can't set client info\n"));
365 /* set subscription */
366 if (snd_seq_parse_address(seq, &sender, argv[optind]) < 0) {
368 fprintf(stderr, _("invalid sender address %s\n"), argv[optind]);
371 if (snd_seq_parse_address(seq, &dest, argv[optind + 1]) < 0) {
373 fprintf(stderr, _("invalid destination address %s\n"), argv[optind + 1]);
376 snd_seq_port_subscribe_alloca(&subs);
377 snd_seq_port_subscribe_set_sender(subs, &sender);
378 snd_seq_port_subscribe_set_dest(subs, &dest);
379 snd_seq_port_subscribe_set_queue(subs, queue);
380 snd_seq_port_subscribe_set_exclusive(subs, exclusive);
381 snd_seq_port_subscribe_set_time_update(subs, convert_time);
382 snd_seq_port_subscribe_set_time_real(subs, convert_real);
384 if (command == UNSUBSCRIBE) {
385 if (snd_seq_get_port_subscription(seq, subs) < 0) {
387 fprintf(stderr, _("No subscription is found\n"));
390 if (snd_seq_unsubscribe_port(seq, subs) < 0) {
392 fprintf(stderr, _("Disconnection failed (%s)\n"), snd_strerror(errno));
396 if (snd_seq_get_port_subscription(seq, subs) == 0) {
398 fprintf(stderr, _("Connection is already subscribed\n"));
401 if (snd_seq_subscribe_port(seq, subs) < 0) {
403 fprintf(stderr, _("Connection failed (%s)\n"), snd_strerror(errno));