⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 aconnect.c

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

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -