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

📄 aseqnet.c

📁 ALSA驱动的一些调试测试工具
💻 C
字号:
/* * network server/client for ALSA sequencer *   ver.0.1 * * Copyright (C) 1999-2000 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 <stdlib.h>#include <ctype.h>#include <string.h>#include <netinet/in.h>#include <sys/socket.h>#include <netdb.h>#include <locale.h>#include <alsa/asoundlib.h>#include <getopt.h>#include <signal.h>#include <assert.h>#include "aconfig.h"#include "gettext.h"/* * prototypes */static void usage(void);static void init_buf(void);static void init_pollfds(void);static void close_files(void);static void init_seq(char *source, char *dest);static int get_port(char *service);static void sigterm_exit(int sig);static void init_server(int port);static void init_client(char *server, int port);static void do_loop(void);static int copy_local_to_remote(void);static int copy_remote_to_local(int fd);/* * default TCP port number */#define DEFAULT_PORT	40002/* * local input buffer */static char *readbuf;static int max_rdlen;static char *writebuf;static int cur_wrlen, max_wrlen;#define MAX_BUF_EVENTS	200#define MAX_CONNECTION	10static snd_seq_t *handle;static struct pollfd *seqifds = NULL;static struct pollfd *seqofds = NULL;static struct pollfd *pollfds = NULL;static int seqifds_count = 0;static int seqofds_count = 0;static int pollfds_count = 0;static int sockfd, netfd[MAX_CONNECTION] = {[0 ... MAX_CONNECTION-1] = -1};static int max_connection;static int cur_connected;static int seq_port;static int server_mode;static int verbose = 0;static int info = 0;/* * main routine */static const struct option long_option[] = {	{"port", 1, NULL, 'p'},	{"source", 1, NULL, 's'},	{"dest", 1, NULL, 'd'},	{"help", 0, NULL, 'h'},	{"verbose", 0, NULL, 'v'},	{"info", 0, NULL, 'i'},	{NULL, 0, NULL, 0},};int main(int argc, char **argv){	int c;	int port = DEFAULT_PORT;	char *source = NULL, *dest = NULL;#ifdef ENABLE_NLS	setlocale(LC_ALL, "");	textdomain(PACKAGE);#endif	while ((c = getopt_long(argc, argv, "p:s:d:vi", long_option, NULL)) != -1) {		switch (c) {		case 'p':			if (isdigit(*optarg))				port = atoi(optarg);			else				port = get_port(optarg);			break;		case 's':			source = optarg;			break;		case 'd':			dest = optarg;			break;		case 'v':			verbose++;			break;		case 'i':			info++;			break;		default:			usage();			exit(1);		}	}	signal(SIGINT, sigterm_exit);	signal(SIGTERM, sigterm_exit);	init_buf();	init_seq(source, dest);	if (optind >= argc) {		server_mode = 1;		max_connection = MAX_CONNECTION;		init_pollfds();		init_server(port);	} else {		server_mode = 0;		max_connection = 1;		init_pollfds();		init_client(argv[optind], port);	}	do_loop();	close_files();	return 0;}/* * print usage */static void usage(void){	printf(_("aseqnet - network client/server on ALSA sequencer\n"));	printf(_("  Copyright (C) 1999 Takashi Iwai\n"));	printf(_("usage:\n"));	printf(_("  server mode: aseqnet [-options]\n"));	printf(_("  client mode: aseqnet [-options] server_host\n"));	printf(_("options:\n"));	printf(_("  -p,--port # : sepcify TCP port (digit or service name)\n"));	printf(_("  -s,--source addr : read from given addr (client:port)\n"));	printf(_("  -d,--dest addr : write to given addr (client:port)\n"));	printf(_("  -v, --verbose : print verbose messages\n"));	printf(_("  -i, --info : print certain received events\n"));}/* * allocate and initialize buffers */static void init_buf(void){	max_wrlen = MAX_BUF_EVENTS * sizeof(snd_seq_event_t);	max_rdlen = MAX_BUF_EVENTS * sizeof(snd_seq_event_t);	writebuf = malloc(max_wrlen);	readbuf = malloc(max_rdlen);	if (writebuf == NULL || readbuf == NULL) {		fprintf(stderr, _("can't malloc\n"));		exit(1);	}	memset(writebuf, 0, max_wrlen);	memset(readbuf, 0, max_rdlen);	cur_wrlen = 0;}/* * allocate and initialize poll array */static void init_pollfds(void){	pollfds_count = seqifds_count + seqofds_count + 1 + max_connection;	pollfds = (struct pollfd *)calloc(pollfds_count, sizeof(struct pollfd));	assert(pollfds);}/* * close all files */static void close_files(void){	int i;	if (verbose)		fprintf(stderr, _("closing files..\n"));	for (i = 0; i < max_connection; i++) {		if (netfd[i] >= 0)			close(netfd[i]);	}	if (sockfd >= 0)		close(sockfd);}/* * initialize sequencer */static void init_seq(char *source, char *dest){	snd_seq_addr_t addr;	int err, counti, counto;	if (snd_seq_open(&handle, "default", SND_SEQ_OPEN_DUPLEX, 0) < 0) {		perror("snd_seq_open");		exit(1);	}	if (seqifds)		free(seqifds);	if (seqofds)		free(seqofds);	counti = seqifds_count = snd_seq_poll_descriptors_count(handle, POLLIN);	assert(counti > 0);	counto = seqofds_count = snd_seq_poll_descriptors_count(handle, POLLOUT);	assert(counto > 0);	seqifds = (struct pollfd *)calloc(counti, sizeof(struct pollfd));	assert(seqifds);	seqofds = (struct pollfd *)calloc(counto, sizeof(struct pollfd));	assert(seqofds);	err = snd_seq_poll_descriptors(handle, seqifds, counti, POLLIN);	assert(err == counti);	err = snd_seq_poll_descriptors(handle, seqofds, counto, POLLOUT);	assert(err == counto);	snd_seq_nonblock(handle, 1);	/* set client info */	if (server_mode)		snd_seq_set_client_name(handle, "Net Server");	else		snd_seq_set_client_name(handle, "Net Client");	/* create a port */	seq_port = snd_seq_create_simple_port(handle, "Network",					      SND_SEQ_PORT_CAP_READ |					      SND_SEQ_PORT_CAP_WRITE |					      SND_SEQ_PORT_CAP_SUBS_READ |					      SND_SEQ_PORT_CAP_SUBS_WRITE,					      SND_SEQ_PORT_TYPE_MIDI_GENERIC);	if (seq_port < 0) {		perror("create seq port");		exit(1);	}	if (verbose)		fprintf(stderr, _("sequencer opened: %d:%d\n"),			snd_seq_client_id(handle), seq_port);	/* explicit subscriptions */	if (source) {		/* read subscription */		if (snd_seq_parse_address(handle, &addr, source) < 0) {			fprintf(stderr, _("invalid source address %s\n"), source);			exit(1);		}		if (snd_seq_connect_from(handle, seq_port, addr.client, addr.port)) {			perror("read subscription");			exit(1);		}	}	if (dest) {		/* write subscription */		if (snd_seq_parse_address(handle, &addr, dest) < 0) {			fprintf(stderr, _("invalid destination address %s\n"), dest);			exit(1);		}		if (snd_seq_connect_to(handle, seq_port, addr.client, addr.port)) {			perror("write subscription");			exit(1);		}	}}/* * convert from string to TCP port number */static int get_port(char *service){	struct servent *sp;	if ((sp = getservbyname(service, "tcp")) == NULL){		fprintf(stderr, _("service '%s' is not found in /etc/services\n"), service);		return -1;	}	return sp->s_port;}/* * signal handler */static void sigterm_exit(int sig){	close_files();	exit(1);}/* * initialize network server */static void init_server(int port){	int i;	int curstate = 1;	struct sockaddr_in addr;	memset(&addr, 0, sizeof(addr));	addr.sin_family = AF_INET;	addr.sin_addr.s_addr = INADDR_ANY;	addr.sin_port = htons(port);	sockfd = socket(AF_INET, SOCK_STREAM, 0);	if (sockfd < 0)  {		perror("create socket");		exit(1);	}	setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &curstate, sizeof(curstate));	/* the return value is ignored.. */	if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0)  {		perror("can't bind");		exit(1);	}	if (listen(sockfd, 5) < 0)  {		perror("can't listen");		exit(1);	}	cur_connected = 0;	for (i = 0; i < max_connection; i++)		netfd[i] = -1;}/* * start connection on server */static void start_connection(void){	struct sockaddr_in addr;	int i;	socklen_t addr_len;	for (i = 0; i < max_connection; i++) {		if (netfd[i] < 0)			break;	}	if (i >= max_connection) {		fprintf(stderr, _("too many connections!\n"));		exit(1);	}	memset(&addr, 0, sizeof(addr));	addr_len = sizeof(addr);	netfd[i] = accept(sockfd, (struct sockaddr *)&addr, &addr_len);	if (netfd[i] < 0) {		perror("accept");		exit(1);	}	if (verbose)		fprintf(stderr, _("accepted[%d]\n"), netfd[i]);	cur_connected++;}/* * initialize network client */static void init_client(char *server, int port){	struct sockaddr_in addr;	struct hostent *host;	int curstate = 1;	int fd;	if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0){		perror("create socket");		exit(1);	}	if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &curstate, sizeof(curstate)) < 0) {		perror("setsockopt");		exit(1);	}	if ((host = gethostbyname(server)) == NULL){		fprintf(stderr, _("can't get address %s\n"), server);		exit(1);	}	addr.sin_port = htons(port);	addr.sin_family = AF_INET;	memcpy(&addr.sin_addr, host->h_addr, host->h_length);	if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {		perror("connect");		exit(1);	}	if (verbose)		fprintf(stderr, _("ok.. connected\n"));	netfd[0] = fd;	cur_connected = 1;}/* * event loop */static void do_loop(void){	int i, rc, width;	int seqifd_ptr, sockfd_ptr = -1, netfd_ptr;	for (;;) {		memset(pollfds, 0, pollfds_count * sizeof(struct pollfd));		seqifd_ptr = 0;		memcpy(pollfds, seqifds, sizeof(*seqifds)*(width = seqifds_count));		if (server_mode) {			sockfd_ptr = width;			pollfds[width].fd = sockfd;			pollfds[width].events = POLLIN;			width++;		}		netfd_ptr = width;		for (i = 0; i < max_connection; i++) {			if (netfd[i] >= 0) {				pollfds[width].fd = netfd[i];				pollfds[width].events = POLLIN;				width++;			}		}		do {			rc = poll(pollfds, width, -1);		} while (rc <= 0 && errno == EINTR);		if (rc <= 0) {			perror("poll");			exit(1);		}		if (server_mode) {			if (pollfds[sockfd_ptr].revents & (POLLIN|POLLOUT))				start_connection();		}		for (i = 0; i < seqifds_count; i++)			if (pollfds[seqifd_ptr + i].revents & (POLLIN|POLLOUT)) {				if (copy_local_to_remote())					return;				break;			}		for (i = 0; i < max_connection; i++) {			if (netfd[i] < 0)				continue;			if (pollfds[netfd_ptr + i].revents & (POLLIN|POLLOUT)) {				if (copy_remote_to_local(netfd[i])) {					netfd[i] = -1;					cur_connected--;					if (cur_connected <= 0)						return;				}			}		}	}}/* * flush write buffer - send data to the socket */static void flush_writebuf(void){	if (cur_wrlen) {		int i;		for (i = 0; i < max_connection; i++) {			if (netfd[i] >= 0)				write(netfd[i], writebuf, cur_wrlen);		}		cur_wrlen = 0;	}}/* * get space from write buffer */static char *get_writebuf(int len){	char *buf;	if (cur_wrlen + len >= max_wrlen)		flush_writebuf();	buf = writebuf + cur_wrlen;	cur_wrlen += len;	return buf;}static void print_event(snd_seq_event_t *ev){	switch (ev->type) {	case SND_SEQ_EVENT_CONTROLLER: 		printf(_("Channel %2d: Control event : %5d\n"),			ev->data.control.channel, ev->data.control.value);		break;	case SND_SEQ_EVENT_PITCHBEND:		printf(_("Channel %2d: Pitchbender   : %5d\n"), 			ev->data.control.channel, ev->data.control.value);		break;	case SND_SEQ_EVENT_NOTEON:		printf(_("Channel %2d: Note On event : %5d\n"),			ev->data.control.channel, ev->data.note.note);		break;	case SND_SEQ_EVENT_NOTEOFF: 		printf(_("Channel %2d: Note Off event: %5d\n"),		       ev->data.control.channel, ev->data.note.note);           		break;	}}#define EVENT_PACKET_SIZE	32/* * copy events from sequencer to port(s) */static int copy_local_to_remote(void){	int rc;	snd_seq_event_t *ev;	char *buf;	while ((rc = snd_seq_event_input(handle, &ev)) >= 0 && ev) {		if (ev->type >= SND_SEQ_EVENT_CLIENT_START &&		    ! snd_seq_ev_is_variable_type(ev)) {			snd_seq_free_event(ev);			continue;		}		if (snd_seq_ev_is_variable(ev)) {			int len;			len = EVENT_PACKET_SIZE + ev->data.ext.len;			buf = get_writebuf(len);			memcpy(buf, ev, sizeof(snd_seq_event_t));			memcpy(buf + EVENT_PACKET_SIZE, ev->data.ext.ptr, ev->data.ext.len);		} else {			buf = get_writebuf(EVENT_PACKET_SIZE);			memcpy(buf, ev, EVENT_PACKET_SIZE);		}		if (info)			print_event(ev);		snd_seq_free_event(ev);	}	flush_writebuf();	return 0;}/* * copy events from a port to sequencer */static int copy_remote_to_local(int fd){	int count;	char *buf;	snd_seq_event_t *ev;	count = read(fd, readbuf, MAX_BUF_EVENTS * sizeof(snd_seq_event_t));	buf = readbuf;	if (count == 0) {		if (verbose)			fprintf(stderr, _("disconnected\n"));		return 1;	}	while (count > 0) {		ev = (snd_seq_event_t*)buf;		buf += EVENT_PACKET_SIZE;		count -= EVENT_PACKET_SIZE;		if (snd_seq_ev_is_variable(ev) && ev->data.ext.len > 0) {			ev->data.ext.ptr = buf;			buf += ev->data.ext.len;			count -= ev->data.ext.len;		}		snd_seq_ev_set_direct(ev);		snd_seq_ev_set_source(ev, seq_port);		snd_seq_ev_set_subs(ev);		if (info)			print_event(ev);		snd_seq_event_output(handle, ev);	}	snd_seq_drain_output(handle);	return 0;}

⌨️ 快捷键说明

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