From 62380b0f4367c1031b3005909bcb3f6152b9af7a Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 4 Jan 2000 12:38:59 +0000 Subject: [PATCH] Moved aconnect and aseqnet sequencer utilities into the alsa-utils package. --- test/README.aconnect | 50 ---- test/README.aseqnet | 52 ----- test/aconnect.1 | 127 ----------- test/aconnect.c | 305 ------------------------- test/aseqnet.1 | 78 ------- test/aseqnet.c | 532 ------------------------------------------- 6 files changed, 1144 deletions(-) delete mode 100644 test/README.aconnect delete mode 100644 test/README.aseqnet delete mode 100644 test/aconnect.1 delete mode 100644 test/aconnect.c delete mode 100644 test/aseqnet.1 delete mode 100644 test/aseqnet.c diff --git a/test/README.aconnect b/test/README.aconnect deleted file mode 100644 index a2839ab0..00000000 --- a/test/README.aconnect +++ /dev/null @@ -1,50 +0,0 @@ -================================================================ - aconnect - control subscriptions - ver.0.1.3 - Copyright (C) 1999-2000 Takashi Iwai -================================================================ - -aconnect is a utility to control subscriptions of two ports as the -third "manager" client. - -For example, the following connects two ports, from 64:0 to 65:0. - - % aconnect 64:0 65:0 - -To disconnect the existing subscription, use -d option. - - % aconnect -d 64:0 65:0 - -To see which port is available as input port, run the following -command: - - % aconnect -i - client 0: 'System' [group=system] [type=kernel] - 0 'Timer ' [group=system] - 1 'Announce ' [group=system] - client 64: '0: MIDI Synth' [group=] [type=kernel] - 0 'card 0: synth-midi: 0' [group=device] - -Similary, to see the output ports, use -o flag. - - % aconnect -o - client 64: '0: MIDI Synth' [group=] [type=kernel] - 0 'card 0: synth-midi: 0' [group=device] - client 65: 'AWE Wave Table Synth : 0' [group=device] [type=kernel] - 0 'Emu8000 port 0 ' [group=device] - 1 'Emu8000 port 1 ' [group=device] - 2 'Emu8000 port 2 ' [group=device] - 3 'Emu8000 port 3 ' [group=device] - -Some ports may have permission for its own group. -In such a case, change the group of aconnect to the appropriate one by -using -g option. - -The option -l together with -i or -o shows subscribers for each port. - -Ports are connected exclusively when the option -e is specified. - -For modifying time-stamp with a queue, use -r or -t option followed by -a queue index which updates the time-stamp. Former uses real-time queue, -while the latter uses tick queue. The queue must be used (not necessarily -owned) by the receiver client. diff --git a/test/README.aseqnet b/test/README.aseqnet deleted file mode 100644 index 65d70671..00000000 --- a/test/README.aseqnet +++ /dev/null @@ -1,52 +0,0 @@ -================================================================ - ALSA sequencer connectors over network - ver.0.1 - Copyright (C) 1999-2000 Takashi Iwai -================================================================ - -* ASEQNET - -aseqnet is a sequencer client which sends/receives events over -network. Suppose two hosts (hostA and hostB) connected by network. -You need to run ALSA system on both hosts. Then, start aseqnet as a -server on hostA: - - hostA% aseqnet - sequencer opened: 128:0 - -A user client 128 with port 0 was opened. (The client number may -vary.) At next, start client on hostB. The argument is the hostname -where server is running. - - hostB% aseqnet hostA - sequencer opened: 132:0 - -Now events sent to hostA:128:0 is transferred to hostB:132:0, and vice -versa. - -You can connect these ports arbitrary to other sequencer ports. -For example, connect hostB:132:0 to a MIDI output device 65:0. The -aconnect utility can be used for this: - - hostB% aconnect 132:0 65:0 - -Events to hostA:128:0 will be delivered indirectly to hostB:65:0. -You'll hear MIDI sounds as following: - - hostA% pmidi -p 128:0 foo.mid - -The multiple clients may exist simultaneously. If hostC is connected -as a client to hostA, events from from hostA are sent to all connected -network clients, hostB and hostC. However, only one connection is -allowed from a client to a server. - -To disconnect network, stop all clients before server by ctrl-C or -sending signal to them. The server will automatically quit. - -The available options are: - - -p port : specify the TCP port number or TCP service name. - Default value is 9009 (I don't know it's allowed..) - -s addr : explicit read-subscription to the given address - (client:addr). - -d addr : explicit write-subscription to the given address. diff --git a/test/aconnect.1 b/test/aconnect.1 deleted file mode 100644 index b47b4c2b..00000000 --- a/test/aconnect.1 +++ /dev/null @@ -1,127 +0,0 @@ -.TH aconnect 1 "January 1, 2000" -.LO 1 -.SH NAME -aconnect \- ALSA sequencer connection manager - -.SH SYNOPSIS -.B aconnect -[\-d] [-options] sender receiver -.br -.B aconnect -\-i|-o [-options] - -.SH DESCRIPTION -.B aconnect -is a utility to connect and disconnect two existing ports on ALSA sequencer -system. -The ports with the arbitrary subscription permission, such as created -by -.B aseqview(1), -can be connected to any (MIDI) device ports using -.B aconnect. -For example, to connect from port 64:0 to 65:0, run as follows: -.IP "" 4 -% aconnect 64:0 65:0 -.PP -The connection is one-way, and the whole data to the sender port (64:0) -is redirected to the receiver port (65:0). When another port (e.g. 65:1) -is attached to the same sender port, the data is sent to both receiver -ports. -For disconnection, use -.B \-d -option. -.IP "" 4 -% aconnect -d 64:0 65:0 -.PP -Another function of -.B aconnect -is to list the present ports -on the given condition. -The input ports, which may become -.I sender -ports, can be listed with -.B \-i -option. -.IP "" 4 -% aconnect -i -.br -client 0: 'System' [group=system] [type=kernel] -.in +4 -0 'Timer ' [group=system] -.br -1 'Announce ' [group=system] -.in -4 -client 64: '0: MIDI Synth' [group=] [type=kernel] -.in +4 -0 'card 0: synth-midi: 0' [group=device] -.in -4 -.PP -Similary, to see the output ports, use -.B \-o -flag. - -.SH OPTIONS -.SS CONNNECTION MANAGEMENT -.TP -.B \-d, --disconnect -Disconnect the given subscription. -.TP -.B \-e, --exclusive -Connect ports with exclusvie mode. -Both sender and receiver ports can be no longer connected by any other ports. -.TP -.B \-r, --real queue -Convert time-stamps of event packets to the current value of the given -.I real-time -queue. -This is option is, however, not so useful, since -the receiver port must use (not necessarily own) the specified queue. -.TP -.B \-t, --tick queue -Like -.B -r -option, but -time-stamps are converted to the current value of the given -.I tick -queue. -.TP -.B \-g, --group name -Specify the group name that -.B aconnect -uses. -Some ports may have special permissions, so that only the same group -may subscribe to them. In such a case, -.B aconnect -can fake the group name -with this option. - -.SS LIST PORTS -.TP -.B \-i, --input -List existing input (readable) ports. -This option is exclusive to -.B \-o. -.TP -.B \-o, --output -List existing output (writable) ports. -This option is exclusive to -.B \-i. -.TP -.B \-l, --list -List the current connection status. The connected and connecting ports -from/to each port are listed together. -The suffix flag -.B [ex] -means the connection is exclusive. -The suffix flag -.B [real:#] -and -.B [tick:#] -mean the connection includes real-time and tick conversion on the listed -queue, respectively. - -.SH "SEE ALSO" -aseqnet(1), aseqview(1) - -.SH AUTHOR -Takashi Iwai . diff --git a/test/aconnect.c b/test/aconnect.c deleted file mode 100644 index 935e88ca..00000000 --- a/test/aconnect.c +++ /dev/null @@ -1,305 +0,0 @@ -/* - * 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 -#include -#include -#include -#include -#include -#include -#include -#include - -static void usage(void) -{ - fprintf(stderr, "aconnect - ALSA sequencer connection manager\n"); - fprintf(stderr, "Copyright (C) 1999-2000 Takashi Iwai\n"); - fprintf(stderr, "Usage:\n"); - fprintf(stderr, " * Connection/disconnection betwen two ports\n"); - fprintf(stderr, " aconnect [-options] sender receiver\n"); - fprintf(stderr, " sender, receiver = client:port pair\n"); - fprintf(stderr, " -d,--disconnect disconnect\n"); - fprintf(stderr, " -e,--exclusive exclusive connection\n"); - fprintf(stderr, " -r,--real # convert real-time-stamp on queue\n"); - fprintf(stderr, " -t,--tick # convert tick-time-stamp on queue\n"); - fprintf(stderr, " -g,--group name set the group name\n"); - fprintf(stderr, " * List connected ports (no subscription action)\n"); - fprintf(stderr, " aconnect -i|-o [-options]\n"); - fprintf(stderr, " -i,--input list input (readable) ports\n"); - fprintf(stderr, " -o,--output list output (writable) ports\n"); - fprintf(stderr, " -g,--group name specify the group name\n"); - fprintf(stderr, " -l,--list list current connections of each port\n"); -} - -/* - * parse command line to client:port - */ -static int parse_address(snd_seq_addr_t *addr, char *arg) -{ - char *p; - - if (! isdigit(*arg)) - return -1; - if ((p = strpbrk(arg, ":.")) == NULL) - return -1; - addr->client = atoi(arg); - addr->port = atoi(p + 1); - return 0; -} - -/* - * check permission (capability) of specified port - */ -static int check_permission(snd_seq_port_info_t *pinfo, char *group, int perm) -{ - if ((pinfo->capability & perm) == perm && - ! (pinfo->capability & SND_SEQ_PORT_CAP_NO_EXPORT)) - return 1; - if (*group && strcmp(pinfo->group, group) == 0 && - (pinfo->cap_group & perm) == perm && - ! (pinfo->cap_group & SND_SEQ_PORT_CAP_NO_EXPORT)) - return 1; - return 0; -} - -/* - * list subscribers of specified type - */ -static void list_each_subs(snd_seq_t *seq, snd_seq_query_subs_t *subs, int type, char *msg) -{ - subs->type = type; - subs->index = 0; - while (snd_seq_query_port_subscribers(seq, subs) >= 0) { - if (subs->index == 0) - printf("\t%s: ", msg); - else - printf(", "); - printf("%d:%d", subs->addr.client, subs->addr.port); - if (subs->exclusive) - printf("[ex]"); - if (subs->convert_time) - printf("[%s:%d]", - (subs->realtime ? "real" : "tick"), - subs->queue); - subs->index++; - } - if (subs->index) - printf("\n"); -} - -/* - * list subscribers - */ -static void list_subscribers(snd_seq_t *seq, int client, int port) -{ - snd_seq_query_subs_t subs; - memset(&subs, 0, sizeof(subs)); - subs.client = client; - subs.port = port; - list_each_subs(seq, &subs, SND_SEQ_QUERY_SUBS_READ, "Connecting To"); - list_each_subs(seq, &subs, SND_SEQ_QUERY_SUBS_WRITE, "Connected From"); -} - -/* - * list all ports - */ -static void list_ports(snd_seq_t *seq, char *group, int perm, int list_subs) -{ - snd_seq_client_info_t cinfo; - snd_seq_port_info_t pinfo; - int client_printed; - - cinfo.client = -1; - cinfo.name[0] = 0; - cinfo.group[0] = 0; - while (snd_seq_query_next_client(seq, &cinfo) >= 0) { - /* reset query info */ - pinfo.client = cinfo.client; - pinfo.port = -1; - pinfo.name[0] = 0; - strncpy(pinfo.group, group, sizeof(pinfo.group)); - client_printed = 0; - while (snd_seq_query_next_port(seq, &pinfo) >= 0) { - if (check_permission(&pinfo, group, perm)) { - if (! client_printed) { - printf("client %d: '%s' [group=%s] [type=%s]\n", - cinfo.client, cinfo.name, cinfo.group, - (cinfo.type == USER_CLIENT ? "user" : "kernel")); - client_printed = 1; - } - printf(" %3d '%-16s' [group=%s]\n", pinfo.port, pinfo.name, pinfo.group); - if (list_subs) - list_subscribers(seq, pinfo.client, pinfo.port); - } - /* reset query names */ - pinfo.name[0] = 0; - strncpy(pinfo.group, group, sizeof(pinfo.group)); - } - /* reset query names */ - cinfo.name[0] = 0; - cinfo.group[0] = 0; - } -} - - -enum { - SUBSCRIBE, UNSUBSCRIBE, LIST_INPUT, LIST_OUTPUT -}; - -static struct option long_option[] = { - {"disconnect", 0, NULL, 'd'}, - {"input", 0, NULL, 'i'}, - {"output", 0, NULL, 'o'}, - {"group", 1, NULL, 'g'}, - {"real", 1, NULL, 'r'}, - {"tick", 1, NULL, 't'}, - {"exclusive", 0, NULL, 'e'}, - {"list", 0, NULL, 'l'}, - {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; - char *group = ""; - int client; - int list_subs = 0; - snd_seq_client_info_t cinfo; - snd_seq_port_subscribe_t subs; - - while ((c = getopt_long(argc, argv, "diog:r:t:el", long_option, NULL)) != -1) { - switch (c) { - case 'd': - command = UNSUBSCRIBE; - break; - case 'i': - command = LIST_INPUT; - break; - case 'o': - command = LIST_OUTPUT; - break; - case 'g': - group = optarg; - 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; - default: - usage(); - exit(1); - } - } - - if (snd_seq_open(&seq, SND_SEQ_OPEN) < 0) { - fprintf(stderr, "can't open sequencer\n"); - return 1; - } - - if (command == LIST_INPUT) { - list_ports(seq, group, SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ, list_subs); - snd_seq_close(seq); - return 0; - } else if (command == LIST_OUTPUT) { - list_ports(seq, group, SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE, list_subs); - snd_seq_close(seq); - return 0; - } - - 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 */ - memset(&cinfo, 0, sizeof(cinfo)); - cinfo.client = client; - cinfo.type = USER_CLIENT; - strcpy(cinfo.name, "ALSA Connector"); - strncpy(cinfo.group, group, sizeof(cinfo.group) - 1); - if (snd_seq_set_client_info(seq, &cinfo) < 0) { - snd_seq_close(seq); - fprintf(stderr, "can't set client info\n"); - return 0; - } - - /* set subscription */ - memset(&subs, 0, sizeof(subs)); - if (parse_address(&subs.sender, argv[optind]) < 0) { - fprintf(stderr, "invalid sender address %s\n", argv[optind]); - return 1; - } - if (parse_address(&subs.dest, argv[optind + 1]) < 0) { - fprintf(stderr, "invalid destination address %s\n", argv[optind + 1]); - return 1; - } - subs.queue = queue; - subs.exclusive = exclusive; - subs.convert_time = convert_time; - subs.realtime = 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; -} diff --git a/test/aseqnet.1 b/test/aseqnet.1 deleted file mode 100644 index f53a3b1b..00000000 --- a/test/aseqnet.1 +++ /dev/null @@ -1,78 +0,0 @@ -.TH aseqnet 1 "January 1, 2000" -.LO 1 -.SH NAME -aseqnet \- ALSA sequencer connectors over network - -.SH SYNOPSIS -.B aseqnet -[remotehost] - -.SH DESCRIPTION -.B aseqnet -is an ALSA sequencer client which sends and receives event packets -over network. -Suppose two hosts connected by network, -.I hostA -as a server -and -.I hostB -as a client. -The ALSA sequencer system must be running on both hosts. -For creating the server port, run the following on hostA: -.IP "" 4 -hostA% aseqnet -.br -sequencer opened: 128:0 -.PP -Then a user client 128 with port 0 was opened on hostA. -(The client number may vary.) -For creating the (network-)client port, run -.B aseqnet -with the hostname of the server: -.IP "" 4 -hostB% aseqnet hostA -.br -sequencer opened: 132:0 -.PP -Now all events sent to hostA:128:0 are transferred to hostB:132:0, and vice -versa. -.PP -The ports created by -.B aseqnet -can be connected arbitrary to other sequencer ports via -.B aconnect(1). -For example, to connect hostB:132:0 to a MIDI output device 65:0: -.IP "" 4 -hostB% aconnect 132:0 65:0 -.PP -Then events to hostA:128:0 will be delivered to hostB:65:0. -The following command plays MIDI on -.I hostB. -.IP "" 4 -hostA% pmidi -p 128:0 foo.mid -.PP -The multiple clients may exist simultaneously. If -.I hostC -is connected as a client to hostA, events from from hostA are sent -to all connected network clients, i.e. hostB and hostC. -However, only one connection is allowed from a client to a server. -.PP -To disconnect network, stop all clients before server by ctrl-C or -sending signal to them. The server will automatically quit. - -.SH OPTIONS -.TP -.B \-p port -Specify the TCP port number or TCP service name. -.TP -.B \-s addr -Subscribe to the given address for read automatically. -.TP -.B \-d addr -Subscribe to the given address for write automatically. - -.SH "SEE ALSO" -aconnect(1), pmidi(1) - -.SH AUTHOR -Takashi Iwai . diff --git a/test/aseqnet.c b/test/aseqnet.c deleted file mode 100644 index 37ea64a8..00000000 --- a/test/aseqnet.c +++ /dev/null @@ -1,532 +0,0 @@ -/* - * 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 -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * prototypes - */ -static void usage(void); -static void init_buf(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 9009 - -/* - * 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 10 - -static snd_seq_t *handle; -static int seqfd, 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; - - -/* - * main routine - */ - -static struct option long_option[] = { - {"port", 1, NULL, 'p'}, - {"source", 1, NULL, 's'}, - {"dest", 1, NULL, 'd'}, - {"help", 0, NULL, 'h'}, - {NULL, 0, NULL, 0}, -}; - -int main(int argc, char **argv) -{ - int c; - int port = DEFAULT_PORT; - char *source = NULL, *dest = NULL; - - while ((c = getopt_long(argc, argv, "p:s:d:", 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; - 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_server(port); - } else { - server_mode = 0; - max_connection = 1; - init_client(argv[optind], port); - } - - do_loop(); - - close_files(); - - return 0; -} - - -/* - * print usage - */ -static void usage(void) -{ - fprintf(stderr, "aseqnet - network client/server on ALSA sequencer\n"); - fprintf(stderr, " Copyright (C) 1999 Takashi Iwai\n"); - fprintf(stderr, "usage:\n"); - fprintf(stderr, " server mode: aseqnet [-options]\n"); - fprintf(stderr, " client mode: aseqnet [-options] server_host\n"); - fprintf(stderr, "options:\n"); - fprintf(stderr, " -p,--port # : sepcify TCP port (digit or service name)\n"); - fprintf(stderr, " -s,--source addr : read from given addr (client:port)\n"); - fprintf(stderr, " -d,--dest addr : write to given addr (client:port)\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; -} - -/* - * parse client:port argument - */ -static int parse_addr(snd_seq_addr_t *addr, char *arg) -{ - char *p; - - if (! isdigit(*arg)) - return -1; - if ((p = strpbrk(arg, ":.")) == NULL) - return -1; - addr->client = atoi(arg); - addr->port = atoi(p + 1); - return 0; -} - - -/* - * close all files - */ -static void close_files(void) -{ - int i; -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; - - if (snd_seq_open(&handle, SND_SEQ_OPEN) < 0) { - perror("snd_seq_open"); - exit(1); - } - seqfd = snd_seq_file_descriptor(handle); - snd_seq_block_mode(handle, 0); - - /* 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); - } - fprintf(stderr, "sequencer opened: %d:%d\n", - snd_seq_client_id(handle), seq_port); - - /* explicit subscriptions */ - if (source) { - /* read subscription */ - if (parse_addr(&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 (parse_addr(&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, "%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; - 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) { - fprintf(stderr, "can't create a socket\n"); - exit(1); - } - - if (bind(sockfd, &addr, sizeof(addr)) < 0) { - fprintf(stderr, "can't bind address\n"); - exit(1); - } - - if (listen(sockfd, 5) < 0) { - fprintf(stderr, "can't listen on socket\n"); - 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; - int 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) { - fprintf(stderr, "can't accept\n"); - exit(1); - } - 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 fd; - - if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0){ - fprintf(stderr, "can't create socket\n"); - 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, &addr, sizeof(addr)) < 0) { - fprintf(stderr,"can't connect\n"); - exit(1); - } - fprintf(stderr, "ok.. connected\n"); - netfd[0] = fd; - cur_connected = 1; -} - -/* - * set file descriptor - */ -static void set_fd(int fd, fd_set *p, int *width) -{ - FD_SET(fd, p); - if (fd >= *width) - *width = fd + 1; -} - -/* - * event loop - */ -static void do_loop(void) -{ - fd_set rfd; - int i, rc, width; - - for (;;) { - FD_ZERO(&rfd); - width = 0; - set_fd(seqfd, &rfd, &width); - if (server_mode) - set_fd(sockfd, &rfd, &width); - for (i = 0; i < max_connection; i++) { - if (netfd[i] >= 0) - set_fd(netfd[i], &rfd, &width); - } - rc = select(width, &rfd, NULL, NULL, NULL); - if (rc <= 0) - exit(1); - if (server_mode) { - if (FD_ISSET(sockfd, &rfd)) - start_connection(); - } - if (FD_ISSET(seqfd, &rfd)) { - if (copy_local_to_remote()) - break; - } - for (i = 0; i < max_connection; i++) { - if (netfd[i] < 0) - continue; - if (FD_ISSET(netfd[i], &rfd)) { - 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; -} - -/* - * 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_free_event(ev); - continue; - } - if (snd_seq_ev_is_variable(ev)) { - int len; - len = sizeof(snd_seq_event_t) + ev->data.ext.len; - buf = get_writebuf(len); - memcpy(buf, ev, sizeof(snd_seq_event_t)); - memcpy(buf + sizeof(snd_seq_event_t), ev->data.ext.ptr, ev->data.ext.len); - } else { - buf = get_writebuf(sizeof(snd_seq_event_t)); - memcpy(buf, ev, sizeof(snd_seq_event_t)); - } - } - 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) { - fprintf(stderr, "disconnected\n"); - return 1; - } - - while (count > 0) { - ev = snd_seq_create_event(); - if (ev == NULL) { - fprintf(stderr, "can't malloc\n"); - exit(1); - } - memcpy(ev, buf, sizeof(snd_seq_event_t)); - buf += sizeof(snd_seq_event_t); - count -= sizeof(snd_seq_event_t); - if (snd_seq_ev_is_variable(ev) && ev->data.ext.len > 0) { - ev->data.ext.ptr = malloc(ev->data.ext.len); - if (ev->data.ext.ptr == NULL) { - fprintf(stderr, "can't malloc\n"); - exit(1); - } - memcpy(ev->data.ext.ptr, buf, ev->data.ext.len); - 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); - snd_seq_event_output(handle, ev); - snd_seq_free_event(ev); - } - - snd_seq_flush_output(handle); - return 0; -} - -- 2.47.1