+++ /dev/null
-================================================================
- 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.
+++ /dev/null
-================================================================
- 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.
+++ /dev/null
-.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 <iwai@ww.uni-erlangen.de>.
+++ /dev/null
-/*
- * 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 <sys/ioctl.h>
-#include <sys/asoundlib.h>
-
-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;
-}
+++ /dev/null
-.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 <iwai@ww.uni-erlangen.de>.
+++ /dev/null
-/*
- * 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 <netdb.h>
-#include <sys/asoundlib.h>
-#include <getopt.h>
-#include <signal.h>
-
-/*
- * 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;
-}
-