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 }