Blame seq/aconnect/aconnect.c

Packit Service a9274b
/*
Packit Service a9274b
 * connect / disconnect two subscriber ports
Packit Service a9274b
 *   ver.0.1.3
Packit Service a9274b
 *
Packit Service a9274b
 * Copyright (C) 1999 Takashi Iwai
Packit Service a9274b
 * 
Packit Service a9274b
 *  This program is free software; you can redistribute it and/or modify
Packit Service a9274b
 *  it under the terms of the GNU General Public License version 2 as
Packit Service a9274b
 *  published by the Free Software Foundation.
Packit Service a9274b
 * 
Packit Service a9274b
 *  This program is distributed in the hope that it will be useful,
Packit Service a9274b
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service a9274b
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service a9274b
 *  GNU General Public License for more details.
Packit Service a9274b
 *
Packit Service a9274b
 */
Packit Service a9274b
Packit Service a9274b
#include <stdio.h>
Packit Service a9274b
#include <ctype.h>
Packit Service a9274b
#include <string.h>
Packit Service a9274b
#include <stdlib.h>
Packit Service a9274b
#include <errno.h>
Packit Service a9274b
#include <fcntl.h>
Packit Service a9274b
#include <getopt.h>
Packit Service a9274b
#include <stdarg.h>
Packit Service a9274b
#include <locale.h>
Packit Service a9274b
#include <sys/ioctl.h>
Packit Service a9274b
#include <alsa/asoundlib.h>
Packit Service a9274b
#include "aconfig.h"
Packit Service a9274b
#include "gettext.h"
Packit Service a9274b
Packit Service a9274b
static void error_handler(const char *file, int line, const char *function, int err, const char *fmt, ...)
Packit Service a9274b
{
Packit Service a9274b
	va_list arg;
Packit Service a9274b
Packit Service a9274b
	if (err == ENOENT)	/* Ignore those misleading "warnings" */
Packit Service a9274b
		return;
Packit Service a9274b
	va_start(arg, fmt);
Packit Service a9274b
	fprintf(stderr, "ALSA lib %s:%i:(%s) ", file, line, function);
Packit Service a9274b
	vfprintf(stderr, fmt, arg);
Packit Service a9274b
	if (err)
Packit Service a9274b
		fprintf(stderr, ": %s", snd_strerror(err));
Packit Service a9274b
	putc('\n', stderr);
Packit Service a9274b
	va_end(arg);
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static void usage(void)
Packit Service a9274b
{
Packit Service a9274b
	printf(_("aconnect - ALSA sequencer connection manager\n"));
Packit Service a9274b
	printf(_("Copyright (C) 1999-2000 Takashi Iwai\n"));
Packit Service a9274b
	printf(_("Usage:\n"));
Packit Service a9274b
	printf(_(" * Connection/disconnection between two ports\n"));
Packit Service a9274b
	printf(_("   aconnect [-options] sender receiver\n"));
Packit Service a9274b
	printf(_("     sender, receiver = client:port pair\n"));
Packit Service a9274b
	printf(_("     -d,--disconnect     disconnect\n"));
Packit Service a9274b
	printf(_("     -e,--exclusive      exclusive connection\n"));
Packit Service a9274b
	printf(_("     -r,--real #         convert real-time-stamp on queue\n"));
Packit Service a9274b
	printf(_("     -t,--tick #         convert tick-time-stamp on queue\n"));
Packit Service a9274b
	printf(_(" * List connected ports (no subscription action)\n"));
Packit Service a9274b
	printf(_("   aconnect -i|-o [-options]\n"));
Packit Service a9274b
	printf(_("     -i,--input          list input (readable) ports\n"));
Packit Service a9274b
	printf(_("     -o,--output         list output (writable) ports\n"));
Packit Service a9274b
	printf(_("     -l,--list           list current connections of each port\n"));
Packit Service a9274b
	printf(_(" * Remove all exported connections\n"));
Packit Service a9274b
	printf(_("     -x, --removeall\n"));
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
/*
Packit Service a9274b
 * check permission (capability) of specified port
Packit Service a9274b
 */
Packit Service a9274b
Packit Service a9274b
#define LIST_INPUT	1
Packit Service a9274b
#define LIST_OUTPUT	2
Packit Service a9274b
Packit Service a9274b
#define perm_ok(pinfo,bits) ((snd_seq_port_info_get_capability(pinfo) & (bits)) == (bits))
Packit Service a9274b
Packit Service a9274b
static int check_permission(snd_seq_port_info_t *pinfo, int perm)
Packit Service a9274b
{
Packit Service a9274b
	if (perm) {
Packit Service a9274b
		if (perm & LIST_INPUT) {
Packit Service a9274b
			if (perm_ok(pinfo, SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ))
Packit Service a9274b
				goto __ok;
Packit Service a9274b
		}
Packit Service a9274b
		if (perm & LIST_OUTPUT) {
Packit Service a9274b
			if (perm_ok(pinfo, SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE))
Packit Service a9274b
				goto __ok;
Packit Service a9274b
		}
Packit Service a9274b
		return 0;
Packit Service a9274b
	}
Packit Service a9274b
 __ok:
Packit Service a9274b
	if (snd_seq_port_info_get_capability(pinfo) & SND_SEQ_PORT_CAP_NO_EXPORT)
Packit Service a9274b
		return 0;
Packit Service a9274b
	return 1;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
/*
Packit Service a9274b
 * list subscribers of specified type
Packit Service a9274b
 */
Packit Service a9274b
static void list_each_subs(snd_seq_t *seq, snd_seq_query_subscribe_t *subs, int type, const char *msg)
Packit Service a9274b
{
Packit Service a9274b
	int count = 0;
Packit Service a9274b
	snd_seq_query_subscribe_set_type(subs, type);
Packit Service a9274b
	snd_seq_query_subscribe_set_index(subs, 0);
Packit Service a9274b
	while (snd_seq_query_port_subscribers(seq, subs) >= 0) {
Packit Service a9274b
		const snd_seq_addr_t *addr;
Packit Service a9274b
		if (count++ == 0)
Packit Service a9274b
			printf("\t%s: ", msg);
Packit Service a9274b
		else
Packit Service a9274b
			printf(", ");
Packit Service a9274b
		addr = snd_seq_query_subscribe_get_addr(subs);
Packit Service a9274b
		printf("%d:%d", addr->client, addr->port);
Packit Service a9274b
		if (snd_seq_query_subscribe_get_exclusive(subs))
Packit Service a9274b
			printf("[ex]");
Packit Service a9274b
		if (snd_seq_query_subscribe_get_time_update(subs))
Packit Service a9274b
			printf("[%s:%d]",
Packit Service a9274b
			       (snd_seq_query_subscribe_get_time_real(subs) ? "real" : "tick"),
Packit Service a9274b
			       snd_seq_query_subscribe_get_queue(subs));
Packit Service a9274b
		snd_seq_query_subscribe_set_index(subs, snd_seq_query_subscribe_get_index(subs) + 1);
Packit Service a9274b
	}
Packit Service a9274b
	if (count > 0)
Packit Service a9274b
		printf("\n");
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
/*
Packit Service a9274b
 * list subscribers
Packit Service a9274b
 */
Packit Service a9274b
static void list_subscribers(snd_seq_t *seq, const snd_seq_addr_t *addr)
Packit Service a9274b
{
Packit Service a9274b
	snd_seq_query_subscribe_t *subs;
Packit Service a9274b
	snd_seq_query_subscribe_alloca(&subs);
Packit Service a9274b
	snd_seq_query_subscribe_set_root(subs, addr);
Packit Service a9274b
	list_each_subs(seq, subs, SND_SEQ_QUERY_SUBS_READ, _("Connecting To"));
Packit Service a9274b
	list_each_subs(seq, subs, SND_SEQ_QUERY_SUBS_WRITE, _("Connected From"));
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
/*
Packit Service a9274b
 * search all ports
Packit Service a9274b
 */
Packit Service a9274b
typedef void (*action_func_t)(snd_seq_t *seq, snd_seq_client_info_t *cinfo, snd_seq_port_info_t *pinfo, int count);
Packit Service a9274b
Packit Service a9274b
static void do_search_port(snd_seq_t *seq, int perm, action_func_t do_action)
Packit Service a9274b
{
Packit Service a9274b
	snd_seq_client_info_t *cinfo;
Packit Service a9274b
	snd_seq_port_info_t *pinfo;
Packit Service a9274b
	int count;
Packit Service a9274b
Packit Service a9274b
	snd_seq_client_info_alloca(&cinfo);
Packit Service a9274b
	snd_seq_port_info_alloca(&pinfo);
Packit Service a9274b
	snd_seq_client_info_set_client(cinfo, -1);
Packit Service a9274b
	while (snd_seq_query_next_client(seq, cinfo) >= 0) {
Packit Service a9274b
		/* reset query info */
Packit Service a9274b
		snd_seq_port_info_set_client(pinfo, snd_seq_client_info_get_client(cinfo));
Packit Service a9274b
		snd_seq_port_info_set_port(pinfo, -1);
Packit Service a9274b
		count = 0;
Packit Service a9274b
		while (snd_seq_query_next_port(seq, pinfo) >= 0) {
Packit Service a9274b
			if (check_permission(pinfo, perm)) {
Packit Service a9274b
				do_action(seq, cinfo, pinfo, count);
Packit Service a9274b
				count++;
Packit Service a9274b
			}
Packit Service a9274b
		}
Packit Service a9274b
	}
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
Packit Service a9274b
static void print_port(snd_seq_t *seq, snd_seq_client_info_t *cinfo,
Packit Service a9274b
		       snd_seq_port_info_t *pinfo, int count)
Packit Service a9274b
{
Packit Service a9274b
	if (! count) {
Packit Service a9274b
		int card = -1, pid = -1;
Packit Service a9274b
Packit Service a9274b
		printf(_("client %d: '%s' [type=%s"),
Packit Service a9274b
		       snd_seq_client_info_get_client(cinfo),
Packit Service a9274b
		       snd_seq_client_info_get_name(cinfo),
Packit Service a9274b
		       (snd_seq_client_info_get_type(cinfo) == SND_SEQ_USER_CLIENT ?
Packit Service a9274b
			_("user") : _("kernel")));
Packit Service a9274b
Packit Service a9274b
#ifdef HAVE_SEQ_CLIENT_INFO_GET_CARD
Packit Service a9274b
		card = snd_seq_client_info_get_card(cinfo);
Packit Service a9274b
#endif
Packit Service a9274b
		if (card != -1)
Packit Service a9274b
			printf(",card=%d", card);
Packit Service a9274b
Packit Service a9274b
#ifdef HAVE_SEQ_CLIENT_INFO_GET_PID
Packit Service a9274b
		pid = snd_seq_client_info_get_pid(cinfo);
Packit Service a9274b
#endif
Packit Service a9274b
		if (pid != -1)
Packit Service a9274b
			printf(",pid=%d", pid);
Packit Service a9274b
		printf("]\n");
Packit Service a9274b
	}
Packit Service a9274b
	printf("  %3d '%-16s'\n",
Packit Service a9274b
	       snd_seq_port_info_get_port(pinfo),
Packit Service a9274b
	       snd_seq_port_info_get_name(pinfo));
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static void print_port_and_subs(snd_seq_t *seq, snd_seq_client_info_t *cinfo,
Packit Service a9274b
				snd_seq_port_info_t *pinfo, int count)
Packit Service a9274b
{
Packit Service a9274b
	print_port(seq, cinfo, pinfo, count);
Packit Service a9274b
	list_subscribers(seq, snd_seq_port_info_get_addr(pinfo));
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
Packit Service a9274b
/*
Packit Service a9274b
 * remove all (exported) connections
Packit Service a9274b
 */
Packit Service a9274b
static void remove_connection(snd_seq_t *seq, snd_seq_client_info_t *cinfo,
Packit Service a9274b
			      snd_seq_port_info_t *pinfo, int count)
Packit Service a9274b
{
Packit Service a9274b
	snd_seq_query_subscribe_t *query;
Packit Service a9274b
	snd_seq_port_info_t *port;
Packit Service a9274b
	snd_seq_port_subscribe_t *subs;
Packit Service a9274b
Packit Service a9274b
	snd_seq_query_subscribe_alloca(&query);
Packit Service a9274b
	snd_seq_query_subscribe_set_root(query, snd_seq_port_info_get_addr(pinfo));
Packit Service a9274b
	snd_seq_query_subscribe_set_type(query, SND_SEQ_QUERY_SUBS_READ);
Packit Service a9274b
	snd_seq_query_subscribe_set_index(query, 0);
Packit Service a9274b
Packit Service a9274b
	snd_seq_port_info_alloca(&port);
Packit Service a9274b
	snd_seq_port_subscribe_alloca(&subs);
Packit Service a9274b
Packit Service a9274b
	while (snd_seq_query_port_subscribers(seq, query) >= 0) {
Packit Service a9274b
		const snd_seq_addr_t *sender = snd_seq_query_subscribe_get_root(query);
Packit Service a9274b
		const snd_seq_addr_t *dest = snd_seq_query_subscribe_get_addr(query);
Packit Service a9274b
Packit Service a9274b
		if (snd_seq_get_any_port_info(seq, dest->client, dest->port, port) < 0 ||
Packit Service a9274b
		    !(snd_seq_port_info_get_capability(port) & SND_SEQ_PORT_CAP_SUBS_WRITE) ||
Packit Service a9274b
		    (snd_seq_port_info_get_capability(port) & SND_SEQ_PORT_CAP_NO_EXPORT)) {
Packit Service a9274b
			snd_seq_query_subscribe_set_index(query, snd_seq_query_subscribe_get_index(query) + 1);
Packit Service a9274b
			continue;
Packit Service a9274b
		}
Packit Service a9274b
		snd_seq_port_subscribe_set_queue(subs, snd_seq_query_subscribe_get_queue(query));
Packit Service a9274b
		snd_seq_port_subscribe_set_sender(subs, sender);
Packit Service a9274b
		snd_seq_port_subscribe_set_dest(subs, dest);
Packit Service a9274b
		if (snd_seq_unsubscribe_port(seq, subs) < 0) {
Packit Service a9274b
			snd_seq_query_subscribe_set_index(query, snd_seq_query_subscribe_get_index(query) + 1);
Packit Service a9274b
		}
Packit Service a9274b
	}
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static void remove_all_connections(snd_seq_t *seq)
Packit Service a9274b
{
Packit Service a9274b
	do_search_port(seq, 0, remove_connection);
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
Packit Service a9274b
/*
Packit Service a9274b
 * main..
Packit Service a9274b
 */
Packit Service a9274b
Packit Service a9274b
enum {
Packit Service a9274b
	SUBSCRIBE, UNSUBSCRIBE, LIST, REMOVE_ALL
Packit Service a9274b
};
Packit Service a9274b
Packit Service a9274b
static const struct option long_option[] = {
Packit Service a9274b
	{"disconnect", 0, NULL, 'd'},
Packit Service a9274b
	{"input", 0, NULL, 'i'},
Packit Service a9274b
	{"output", 0, NULL, 'o'},
Packit Service a9274b
	{"real", 1, NULL, 'r'},
Packit Service a9274b
	{"tick", 1, NULL, 't'},
Packit Service a9274b
	{"exclusive", 0, NULL, 'e'},
Packit Service a9274b
	{"list", 0, NULL, 'l'},
Packit Service a9274b
	{"removeall", 0, NULL, 'x'},
Packit Service a9274b
	{NULL, 0, NULL, 0},
Packit Service a9274b
};
Packit Service a9274b
Packit Service a9274b
int main(int argc, char **argv)
Packit Service a9274b
{
Packit Service a9274b
	int c;
Packit Service a9274b
	snd_seq_t *seq;
Packit Service a9274b
	int queue = 0, convert_time = 0, convert_real = 0, exclusive = 0;
Packit Service a9274b
	int command = SUBSCRIBE;
Packit Service a9274b
	int list_perm = 0;
Packit Service a9274b
	int client;
Packit Service a9274b
	int list_subs = 0;
Packit Service a9274b
	snd_seq_port_subscribe_t *subs;
Packit Service a9274b
	snd_seq_addr_t sender, dest;
Packit Service a9274b
Packit Service a9274b
#ifdef ENABLE_NLS
Packit Service a9274b
	setlocale(LC_ALL, "");
Packit Service a9274b
	textdomain(PACKAGE);
Packit Service a9274b
#endif
Packit Service a9274b
Packit Service a9274b
	while ((c = getopt_long(argc, argv, "dior:t:elx", long_option, NULL)) != -1) {
Packit Service a9274b
		switch (c) {
Packit Service a9274b
		case 'd':
Packit Service a9274b
			command = UNSUBSCRIBE;
Packit Service a9274b
			break;
Packit Service a9274b
		case 'i':
Packit Service a9274b
			command = LIST;
Packit Service a9274b
			list_perm |= LIST_INPUT;
Packit Service a9274b
			break;
Packit Service a9274b
		case 'o':
Packit Service a9274b
			command = LIST;
Packit Service a9274b
			list_perm |= LIST_OUTPUT;
Packit Service a9274b
			break;
Packit Service a9274b
		case 'e':
Packit Service a9274b
			exclusive = 1;
Packit Service a9274b
			break;
Packit Service a9274b
		case 'r':
Packit Service a9274b
			queue = atoi(optarg);
Packit Service a9274b
			convert_time = 1;
Packit Service a9274b
			convert_real = 1;
Packit Service a9274b
			break;
Packit Service a9274b
		case 't':
Packit Service a9274b
			queue = atoi(optarg);
Packit Service a9274b
			convert_time = 1;
Packit Service a9274b
			convert_real = 0;
Packit Service a9274b
			break;
Packit Service a9274b
		case 'l':
Packit Service a9274b
			command = LIST;
Packit Service a9274b
			list_subs = 1;
Packit Service a9274b
			break;
Packit Service a9274b
		case 'x':
Packit Service a9274b
			command = REMOVE_ALL;
Packit Service a9274b
			break;
Packit Service a9274b
		default:
Packit Service a9274b
			usage();
Packit Service a9274b
			exit(1);
Packit Service a9274b
		}
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	if (snd_seq_open(&seq, "default", SND_SEQ_OPEN_DUPLEX, 0) < 0) {
Packit Service a9274b
		fprintf(stderr, _("can't open sequencer\n"));
Packit Service a9274b
		return 1;
Packit Service a9274b
	}
Packit Service a9274b
	
Packit Service a9274b
	snd_lib_error_set_handler(error_handler);
Packit Service a9274b
Packit Service a9274b
	switch (command) {
Packit Service a9274b
	case LIST:
Packit Service a9274b
		do_search_port(seq, list_perm,
Packit Service a9274b
			       list_subs ? print_port_and_subs : print_port);
Packit Service a9274b
		snd_seq_close(seq);
Packit Service a9274b
		return 0;
Packit Service a9274b
	case REMOVE_ALL:
Packit Service a9274b
		remove_all_connections(seq);
Packit Service a9274b
		snd_seq_close(seq);
Packit Service a9274b
		return 0;
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	/* connection or disconnection */
Packit Service a9274b
Packit Service a9274b
	if (optind + 2 > argc) {
Packit Service a9274b
		snd_seq_close(seq);
Packit Service a9274b
		usage();
Packit Service a9274b
		exit(1);
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	if ((client = snd_seq_client_id(seq)) < 0) {
Packit Service a9274b
		snd_seq_close(seq);
Packit Service a9274b
		fprintf(stderr, _("can't get client id\n"));
Packit Service a9274b
		return 1;
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	/* set client info */
Packit Service a9274b
	if (snd_seq_set_client_name(seq, "ALSA Connector") < 0) {
Packit Service a9274b
		snd_seq_close(seq);
Packit Service a9274b
		fprintf(stderr, _("can't set client info\n"));
Packit Service a9274b
		return 1;
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	/* set subscription */
Packit Service a9274b
	if (snd_seq_parse_address(seq, &sender, argv[optind]) < 0) {
Packit Service a9274b
		snd_seq_close(seq);
Packit Service a9274b
		fprintf(stderr, _("invalid sender address %s\n"), argv[optind]);
Packit Service a9274b
		return 1;
Packit Service a9274b
	}
Packit Service a9274b
	if (snd_seq_parse_address(seq, &dest, argv[optind + 1]) < 0) {
Packit Service a9274b
		snd_seq_close(seq);
Packit Service a9274b
		fprintf(stderr, _("invalid destination address %s\n"), argv[optind + 1]);
Packit Service a9274b
		return 1;
Packit Service a9274b
	}
Packit Service a9274b
	snd_seq_port_subscribe_alloca(&subs);
Packit Service a9274b
	snd_seq_port_subscribe_set_sender(subs, &sender);
Packit Service a9274b
	snd_seq_port_subscribe_set_dest(subs, &dest);
Packit Service a9274b
	snd_seq_port_subscribe_set_queue(subs, queue);
Packit Service a9274b
	snd_seq_port_subscribe_set_exclusive(subs, exclusive);
Packit Service a9274b
	snd_seq_port_subscribe_set_time_update(subs, convert_time);
Packit Service a9274b
	snd_seq_port_subscribe_set_time_real(subs, convert_real);
Packit Service a9274b
Packit Service a9274b
	if (command == UNSUBSCRIBE) {
Packit Service a9274b
		if (snd_seq_get_port_subscription(seq, subs) < 0) {
Packit Service a9274b
			snd_seq_close(seq);
Packit Service a9274b
			fprintf(stderr, _("No subscription is found\n"));
Packit Service a9274b
			return 1;
Packit Service a9274b
		}
Packit Service a9274b
		if (snd_seq_unsubscribe_port(seq, subs) < 0) {
Packit Service a9274b
			snd_seq_close(seq);
Packit Service a9274b
			fprintf(stderr, _("Disconnection failed (%s)\n"), snd_strerror(errno));
Packit Service a9274b
			return 1;
Packit Service a9274b
		}
Packit Service a9274b
	} else {
Packit Service a9274b
		if (snd_seq_get_port_subscription(seq, subs) == 0) {
Packit Service a9274b
			snd_seq_close(seq);
Packit Service a9274b
			fprintf(stderr, _("Connection is already subscribed\n"));
Packit Service a9274b
			return 1;
Packit Service a9274b
		}
Packit Service a9274b
		if (snd_seq_subscribe_port(seq, subs) < 0) {
Packit Service a9274b
			snd_seq_close(seq);
Packit Service a9274b
			fprintf(stderr, _("Connection failed (%s)\n"), snd_strerror(errno));
Packit Service a9274b
			return 1;
Packit Service a9274b
		}
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	snd_seq_close(seq);
Packit Service a9274b
Packit Service a9274b
	return 0;
Packit Service a9274b
}