tarina

git clone https://git.tarina.org/tarina
Log | Files | Refs | README | LICENSE

aconnect.c (11172B)


      1 /*
      2  * connect / disconnect two subscriber ports
      3  *   ver.0.1.3
      4  *
      5  * Copyright (C) 1999 Takashi Iwai
      6  * 
      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.
     10  * 
     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.
     15  *
     16  */
     17 
     18 #include <stdio.h>
     19 #include <ctype.h>
     20 #include <string.h>
     21 #include <stdlib.h>
     22 #include <errno.h>
     23 #include <fcntl.h>
     24 #include <getopt.h>
     25 #include <stdarg.h>
     26 #include <locale.h>
     27 #include <sys/ioctl.h>
     28 #include <alsa/asoundlib.h>
     29 #include "aconfig.h"
     30 #include "gettext.h"
     31 
     32 static void error_handler(const char *file, int line, const char *function, int err, const char *fmt, ...)
     33 {
     34 	va_list arg;
     35 
     36 	if (err == ENOENT)	/* Ignore those misleading "warnings" */
     37 		return;
     38 	va_start(arg, fmt);
     39 	fprintf(stderr, "ALSA lib %s:%i:(%s) ", file, line, function);
     40 	vfprintf(stderr, fmt, arg);
     41 	if (err)
     42 		fprintf(stderr, ": %s", snd_strerror(err));
     43 	putc('\n', stderr);
     44 	va_end(arg);
     45 }
     46 
     47 static void usage(void)
     48 {
     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"));
     66 }
     67 
     68 /*
     69  * check permission (capability) of specified port
     70  */
     71 
     72 #define LIST_INPUT	1
     73 #define LIST_OUTPUT	2
     74 
     75 #define perm_ok(pinfo,bits) ((snd_seq_port_info_get_capability(pinfo) & (bits)) == (bits))
     76 
     77 static int check_permission(snd_seq_port_info_t *pinfo, int perm)
     78 {
     79 	if (perm) {
     80 		if (perm & LIST_INPUT) {
     81 			if (perm_ok(pinfo, SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ))
     82 				goto __ok;
     83 		}
     84 		if (perm & LIST_OUTPUT) {
     85 			if (perm_ok(pinfo, SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE))
     86 				goto __ok;
     87 		}
     88 		return 0;
     89 	}
     90  __ok:
     91 	if (snd_seq_port_info_get_capability(pinfo) & SND_SEQ_PORT_CAP_NO_EXPORT)
     92 		return 0;
     93 	return 1;
     94 }
     95 
     96 /*
     97  * list subscribers of specified type
     98  */
     99 static void list_each_subs(snd_seq_t *seq, snd_seq_query_subscribe_t *subs, int type, const char *msg)
    100 {
    101 	int count = 0;
    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;
    106 		if (count++ == 0)
    107 			printf("\t%s: ", msg);
    108 		else
    109 			printf(", ");
    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))
    113 			printf("[ex]");
    114 		if (snd_seq_query_subscribe_get_time_update(subs))
    115 			printf("[%s:%d]",
    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);
    119 	}
    120 	if (count > 0)
    121 		printf("\n");
    122 }
    123 
    124 /*
    125  * list subscribers
    126  */
    127 static void list_subscribers(snd_seq_t *seq, const snd_seq_addr_t *addr)
    128 {
    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"));
    134 }
    135 
    136 /*
    137  * search all ports
    138  */
    139 typedef void (*action_func_t)(snd_seq_t *seq, snd_seq_client_info_t *cinfo, snd_seq_port_info_t *pinfo, int count);
    140 
    141 static void do_search_port(snd_seq_t *seq, int perm, action_func_t do_action)
    142 {
    143 	snd_seq_client_info_t *cinfo;
    144 	snd_seq_port_info_t *pinfo;
    145 	int count;
    146 
    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);
    154 		count = 0;
    155 		while (snd_seq_query_next_port(seq, pinfo) >= 0) {
    156 			if (check_permission(pinfo, perm)) {
    157 				do_action(seq, cinfo, pinfo, count);
    158 				count++;
    159 			}
    160 		}
    161 	}
    162 }
    163 
    164 
    165 static void print_port(snd_seq_t *seq, snd_seq_client_info_t *cinfo,
    166 		       snd_seq_port_info_t *pinfo, int count)
    167 {
    168 	if (! count) {
    169 		int card = -1, pid = -1;
    170 
    171 		printf(_("client %d: '%s' [type=%s"),
    172 		       snd_seq_client_info_get_client(cinfo),
    173 		       snd_seq_client_info_get_name(cinfo),
    174 		       (snd_seq_client_info_get_type(cinfo) == SND_SEQ_USER_CLIENT ?
    175 			_("user") : _("kernel")));
    176 
    177 #ifdef HAVE_SEQ_CLIENT_INFO_GET_CARD
    178 		card = snd_seq_client_info_get_card(cinfo);
    179 #endif
    180 		if (card != -1)
    181 			printf(",card=%d", card);
    182 
    183 #ifdef HAVE_SEQ_CLIENT_INFO_GET_PID
    184 		pid = snd_seq_client_info_get_pid(cinfo);
    185 #endif
    186 		if (pid != -1)
    187 			printf(",pid=%d", pid);
    188 		printf("]\n");
    189 	}
    190 	printf("  %3d '%-16s'\n",
    191 	       snd_seq_port_info_get_port(pinfo),
    192 	       snd_seq_port_info_get_name(pinfo));
    193 }
    194 
    195 static void print_port_and_subs(snd_seq_t *seq, snd_seq_client_info_t *cinfo,
    196 				snd_seq_port_info_t *pinfo, int count)
    197 {
    198 	print_port(seq, cinfo, pinfo, count);
    199 	list_subscribers(seq, snd_seq_port_info_get_addr(pinfo));
    200 }
    201 
    202 
    203 /*
    204  * remove all (exported) connections
    205  */
    206 static void remove_connection(snd_seq_t *seq, snd_seq_client_info_t *cinfo,
    207 			      snd_seq_port_info_t *pinfo, int count)
    208 {
    209 	snd_seq_query_subscribe_t *query;
    210 	snd_seq_port_info_t *port;
    211 	snd_seq_port_subscribe_t *subs;
    212 
    213 	snd_seq_query_subscribe_alloca(&query);
    214 	snd_seq_query_subscribe_set_root(query, snd_seq_port_info_get_addr(pinfo));
    215 	snd_seq_query_subscribe_set_type(query, SND_SEQ_QUERY_SUBS_READ);
    216 	snd_seq_query_subscribe_set_index(query, 0);
    217 
    218 	snd_seq_port_info_alloca(&port);
    219 	snd_seq_port_subscribe_alloca(&subs);
    220 
    221 	while (snd_seq_query_port_subscribers(seq, query) >= 0) {
    222 		const snd_seq_addr_t *sender = snd_seq_query_subscribe_get_root(query);
    223 		const snd_seq_addr_t *dest = snd_seq_query_subscribe_get_addr(query);
    224 
    225 		if (snd_seq_get_any_port_info(seq, dest->client, dest->port, port) < 0 ||
    226 		    !(snd_seq_port_info_get_capability(port) & SND_SEQ_PORT_CAP_SUBS_WRITE) ||
    227 		    (snd_seq_port_info_get_capability(port) & SND_SEQ_PORT_CAP_NO_EXPORT)) {
    228 			snd_seq_query_subscribe_set_index(query, snd_seq_query_subscribe_get_index(query) + 1);
    229 			continue;
    230 		}
    231 		snd_seq_port_subscribe_set_queue(subs, snd_seq_query_subscribe_get_queue(query));
    232 		snd_seq_port_subscribe_set_sender(subs, sender);
    233 		snd_seq_port_subscribe_set_dest(subs, dest);
    234 		if (snd_seq_unsubscribe_port(seq, subs) < 0) {
    235 			snd_seq_query_subscribe_set_index(query, snd_seq_query_subscribe_get_index(query) + 1);
    236 		}
    237 	}
    238 }
    239 
    240 static void remove_all_connections(snd_seq_t *seq)
    241 {
    242 	do_search_port(seq, 0, remove_connection);
    243 }
    244 
    245 
    246 /*
    247  * main..
    248  */
    249 
    250 enum {
    251 	SUBSCRIBE, UNSUBSCRIBE, LIST, REMOVE_ALL
    252 };
    253 
    254 static const struct option long_option[] = {
    255 	{"disconnect", 0, NULL, 'd'},
    256 	{"input", 0, NULL, 'i'},
    257 	{"output", 0, NULL, 'o'},
    258 	{"real", 1, NULL, 'r'},
    259 	{"tick", 1, NULL, 't'},
    260 	{"exclusive", 0, NULL, 'e'},
    261 	{"list", 0, NULL, 'l'},
    262 	{"removeall", 0, NULL, 'x'},
    263 	{NULL, 0, NULL, 0},
    264 };
    265 
    266 int main(int argc, char **argv)
    267 {
    268 	int c;
    269 	snd_seq_t *seq;
    270 	int queue = 0, convert_time = 0, convert_real = 0, exclusive = 0;
    271 	int command = SUBSCRIBE;
    272 	int list_perm = 0;
    273 	int client;
    274 	int list_subs = 0;
    275 	snd_seq_port_subscribe_t *subs;
    276 	snd_seq_addr_t sender, dest;
    277 
    278 #ifdef ENABLE_NLS
    279 	setlocale(LC_ALL, "");
    280 	textdomain(PACKAGE);
    281 #endif
    282 
    283 	while ((c = getopt_long(argc, argv, "dior:t:elx", long_option, NULL)) != -1) {
    284 		switch (c) {
    285 		case 'd':
    286 			command = UNSUBSCRIBE;
    287 			break;
    288 		case 'i':
    289 			command = LIST;
    290 			list_perm |= LIST_INPUT;
    291 			break;
    292 		case 'o':
    293 			command = LIST;
    294 			list_perm |= LIST_OUTPUT;
    295 			break;
    296 		case 'e':
    297 			exclusive = 1;
    298 			break;
    299 		case 'r':
    300 			queue = atoi(optarg);
    301 			convert_time = 1;
    302 			convert_real = 1;
    303 			break;
    304 		case 't':
    305 			queue = atoi(optarg);
    306 			convert_time = 1;
    307 			convert_real = 0;
    308 			break;
    309 		case 'l':
    310 			command = LIST;
    311 			list_subs = 1;
    312 			break;
    313 		case 'x':
    314 			command = REMOVE_ALL;
    315 			break;
    316 		default:
    317 			usage();
    318 			exit(1);
    319 		}
    320 	}
    321 
    322 	if (snd_seq_open(&seq, "default", SND_SEQ_OPEN_DUPLEX, 0) < 0) {
    323 		fprintf(stderr, _("can't open sequencer\n"));
    324 		return 1;
    325 	}
    326 	
    327 	snd_lib_error_set_handler(error_handler);
    328 
    329 	switch (command) {
    330 	case LIST:
    331 		do_search_port(seq, list_perm,
    332 			       list_subs ? print_port_and_subs : print_port);
    333 		snd_seq_close(seq);
    334 		return 0;
    335 	case REMOVE_ALL:
    336 		remove_all_connections(seq);
    337 		snd_seq_close(seq);
    338 		return 0;
    339 	}
    340 
    341 	/* connection or disconnection */
    342 
    343 	if (optind + 2 > argc) {
    344 		snd_seq_close(seq);
    345 		usage();
    346 		exit(1);
    347 	}
    348 
    349 	if ((client = snd_seq_client_id(seq)) < 0) {
    350 		snd_seq_close(seq);
    351 		fprintf(stderr, _("can't get client id\n"));
    352 		return 1;
    353 	}
    354 
    355 	/* set client info */
    356 	if (snd_seq_set_client_name(seq, "ALSA Connector") < 0) {
    357 		snd_seq_close(seq);
    358 		fprintf(stderr, _("can't set client info\n"));
    359 		return 1;
    360 	}
    361 
    362 	/* set subscription */
    363 	if (snd_seq_parse_address(seq, &sender, argv[optind]) < 0) {
    364 		snd_seq_close(seq);
    365 		fprintf(stderr, _("invalid sender address %s\n"), argv[optind]);
    366 		return 1;
    367 	}
    368 	if (snd_seq_parse_address(seq, &dest, argv[optind + 1]) < 0) {
    369 		snd_seq_close(seq);
    370 		fprintf(stderr, _("invalid destination address %s\n"), argv[optind + 1]);
    371 		return 1;
    372 	}
    373 	snd_seq_port_subscribe_alloca(&subs);
    374 	snd_seq_port_subscribe_set_sender(subs, &sender);
    375 	snd_seq_port_subscribe_set_dest(subs, &dest);
    376 	snd_seq_port_subscribe_set_queue(subs, queue);
    377 	snd_seq_port_subscribe_set_exclusive(subs, exclusive);
    378 	snd_seq_port_subscribe_set_time_update(subs, convert_time);
    379 	snd_seq_port_subscribe_set_time_real(subs, convert_real);
    380 
    381 	if (command == UNSUBSCRIBE) {
    382 		if (snd_seq_get_port_subscription(seq, subs) < 0) {
    383 			snd_seq_close(seq);
    384 			fprintf(stderr, _("No subscription is found\n"));
    385 			return 1;
    386 		}
    387 		if (snd_seq_unsubscribe_port(seq, subs) < 0) {
    388 			snd_seq_close(seq);
    389 			fprintf(stderr, _("Disconnection failed (%s)\n"), snd_strerror(errno));
    390 			return 1;
    391 		}
    392 	} else {
    393 		if (snd_seq_get_port_subscription(seq, subs) == 0) {
    394 			snd_seq_close(seq);
    395 			fprintf(stderr, _("Connection is already subscribed\n"));
    396 			return 1;
    397 		}
    398 		if (snd_seq_subscribe_port(seq, subs) < 0) {
    399 			snd_seq_close(seq);
    400 			fprintf(stderr, _("Connection failed (%s)\n"), snd_strerror(errno));
    401 			return 1;
    402 		}
    403 	}
    404 
    405 	snd_seq_close(seq);
    406 
    407 	return 0;
    408 }