mirror of
				https://github.com/alsa-project/alsa-lib.git
				synced 2025-11-03 09:01:52 -05:00 
			
		
		
		
	Moved aconnect and aseqnet sequencer utilities into the alsa-utils package.
This commit is contained in:
		
							parent
							
								
									7ab9b22d88
								
							
						
					
					
						commit
						62380b0f43
					
				
					 6 changed files with 0 additions and 1144 deletions
				
			
		| 
						 | 
					@ -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.
 | 
					 | 
				
			||||||
| 
						 | 
					@ -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.
 | 
					 | 
				
			||||||
							
								
								
									
										127
									
								
								test/aconnect.1
									
										
									
									
									
								
							
							
						
						
									
										127
									
								
								test/aconnect.1
									
										
									
									
									
								
							| 
						 | 
					@ -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 <iwai@ww.uni-erlangen.de>.
 | 
					 | 
				
			||||||
							
								
								
									
										305
									
								
								test/aconnect.c
									
										
									
									
									
								
							
							
						
						
									
										305
									
								
								test/aconnect.c
									
										
									
									
									
								
							| 
						 | 
					@ -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 <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;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -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 <iwai@ww.uni-erlangen.de>.
 | 
					 | 
				
			||||||
							
								
								
									
										532
									
								
								test/aseqnet.c
									
										
									
									
									
								
							
							
						
						
									
										532
									
								
								test/aseqnet.c
									
										
									
									
									
								
							| 
						 | 
					@ -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 <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;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue