Imported Upstream version 1.0.28
[platform/upstream/alsa-utils.git] / seq / aseqnet / aseqnet.c
1 /*
2  * network server/client for ALSA sequencer
3  *   ver.0.1
4  *
5  * Copyright (C) 1999-2000 Takashi Iwai
6  * 
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  * 
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  */
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <ctype.h>
21 #include <string.h>
22 #include <netinet/in.h>
23 #include <sys/socket.h>
24 #include <netdb.h>
25 #include <locale.h>
26 #include <alsa/asoundlib.h>
27 #include <getopt.h>
28 #include <signal.h>
29 #include <assert.h>
30 #include "aconfig.h"
31 #include "gettext.h"
32
33 /*
34  * prototypes
35  */
36 static void usage(void);
37 static void init_buf(void);
38 static void init_pollfds(void);
39 static void close_files(void);
40 static void init_seq(char *source, char *dest);
41 static int get_port(char *service);
42 static void sigterm_exit(int sig);
43 static void init_server(int port);
44 static void init_client(char *server, int port);
45 static void do_loop(void);
46 static int copy_local_to_remote(void);
47 static int copy_remote_to_local(int fd);
48
49 /*
50  * default TCP port number
51  */
52 #define DEFAULT_PORT    40002
53
54 /*
55  * local input buffer
56  */
57 static char *readbuf;
58 static int max_rdlen;
59 static char *writebuf;
60 static int cur_wrlen, max_wrlen;
61
62 #define MAX_BUF_EVENTS  200
63 #define MAX_CONNECTION  10
64
65 static snd_seq_t *handle;
66 static struct pollfd *seqifds = NULL;
67 static struct pollfd *seqofds = NULL;
68 static struct pollfd *pollfds = NULL;
69 static int seqifds_count = 0;
70 static int seqofds_count = 0;
71 static int pollfds_count = 0;
72 static int sockfd, netfd[MAX_CONNECTION] = {[0 ... MAX_CONNECTION-1] = -1};
73 static int max_connection;
74 static int cur_connected;
75 static int seq_port;
76
77 static int server_mode;
78 static int verbose = 0;
79 static int info = 0;
80
81
82 /*
83  * main routine
84  */
85
86 static const struct option long_option[] = {
87         {"port", 1, NULL, 'p'},
88         {"source", 1, NULL, 's'},
89         {"dest", 1, NULL, 'd'},
90         {"help", 0, NULL, 'h'},
91         {"verbose", 0, NULL, 'v'},
92         {"info", 0, NULL, 'i'},
93         {NULL, 0, NULL, 0},
94 };
95
96 int main(int argc, char **argv)
97 {
98         int c;
99         int port = DEFAULT_PORT;
100         char *source = NULL, *dest = NULL;
101
102 #ifdef ENABLE_NLS
103         setlocale(LC_ALL, "");
104         textdomain(PACKAGE);
105 #endif
106
107         while ((c = getopt_long(argc, argv, "p:s:d:vi", long_option, NULL)) != -1) {
108                 switch (c) {
109                 case 'p':
110                         if (isdigit(*optarg))
111                                 port = atoi(optarg);
112                         else
113                                 port = get_port(optarg);
114                         break;
115                 case 's':
116                         source = optarg;
117                         break;
118                 case 'd':
119                         dest = optarg;
120                         break;
121                 case 'v':
122                         verbose++;
123                         break;
124                 case 'i':
125                         info++;
126                         break;
127                 default:
128                         usage();
129                         exit(1);
130                 }
131         }
132
133         signal(SIGINT, sigterm_exit);
134         signal(SIGTERM, sigterm_exit);
135
136         init_buf();
137         init_seq(source, dest);
138
139         if (optind >= argc) {
140                 server_mode = 1;
141                 max_connection = MAX_CONNECTION;
142                 init_pollfds();
143                 init_server(port);
144         } else {
145                 server_mode = 0;
146                 max_connection = 1;
147                 init_pollfds();
148                 init_client(argv[optind], port);
149         }
150
151         do_loop();
152
153         close_files();
154
155         return 0;
156 }
157
158
159 /*
160  * print usage
161  */
162 static void usage(void)
163 {
164         printf(_("aseqnet - network client/server on ALSA sequencer\n"));
165         printf(_("  Copyright (C) 1999 Takashi Iwai\n"));
166         printf(_("usage:\n"));
167         printf(_("  server mode: aseqnet [-options]\n"));
168         printf(_("  client mode: aseqnet [-options] server_host\n"));
169         printf(_("options:\n"));
170         printf(_("  -p,--port # : specify TCP port (digit or service name)\n"));
171         printf(_("  -s,--source addr : read from given addr (client:port)\n"));
172         printf(_("  -d,--dest addr : write to given addr (client:port)\n"));
173         printf(_("  -v, --verbose : print verbose messages\n"));
174         printf(_("  -i, --info : print certain received events\n"));
175 }
176
177
178 /*
179  * allocate and initialize buffers
180  */
181 static void init_buf(void)
182 {
183         max_wrlen = MAX_BUF_EVENTS * sizeof(snd_seq_event_t);
184         max_rdlen = MAX_BUF_EVENTS * sizeof(snd_seq_event_t);
185         writebuf = malloc(max_wrlen);
186         readbuf = malloc(max_rdlen);
187         if (writebuf == NULL || readbuf == NULL) {
188                 fprintf(stderr, _("can't malloc\n"));
189                 exit(1);
190         }
191         memset(writebuf, 0, max_wrlen);
192         memset(readbuf, 0, max_rdlen);
193         cur_wrlen = 0;
194 }
195
196 /*
197  * allocate and initialize poll array
198  */
199 static void init_pollfds(void)
200 {
201         pollfds_count = seqifds_count + seqofds_count + 1 + max_connection;
202         pollfds = (struct pollfd *)calloc(pollfds_count, sizeof(struct pollfd));
203         assert(pollfds);
204 }
205
206 /*
207  * close all files
208  */
209 static void close_files(void)
210 {
211         int i;
212         if (verbose)
213                 fprintf(stderr, _("closing files..\n"));
214         for (i = 0; i < max_connection; i++) {
215                 if (netfd[i] >= 0)
216                         close(netfd[i]);
217         }
218         if (sockfd >= 0)
219                 close(sockfd);
220 }
221
222
223 /*
224  * initialize sequencer
225  */
226 static void init_seq(char *source, char *dest)
227 {
228         snd_seq_addr_t addr;
229         int err, counti, counto;
230
231         if (snd_seq_open(&handle, "default", SND_SEQ_OPEN_DUPLEX, 0) < 0) {
232                 perror("snd_seq_open");
233                 exit(1);
234         }
235         if (seqifds)
236                 free(seqifds);
237         if (seqofds)
238                 free(seqofds);
239         counti = seqifds_count = snd_seq_poll_descriptors_count(handle, POLLIN);
240         assert(counti > 0);
241         counto = seqofds_count = snd_seq_poll_descriptors_count(handle, POLLOUT);
242         assert(counto > 0);
243         seqifds = (struct pollfd *)calloc(counti, sizeof(struct pollfd));
244         assert(seqifds);
245         seqofds = (struct pollfd *)calloc(counto, sizeof(struct pollfd));
246         assert(seqofds);
247         err = snd_seq_poll_descriptors(handle, seqifds, counti, POLLIN);
248         assert(err == counti);
249         err = snd_seq_poll_descriptors(handle, seqofds, counto, POLLOUT);
250         assert(err == counto);
251
252         snd_seq_nonblock(handle, 1);
253
254         /* set client info */
255         if (server_mode)
256                 snd_seq_set_client_name(handle, "Net Server");
257         else
258                 snd_seq_set_client_name(handle, "Net Client");
259
260         /* create a port */
261         seq_port = snd_seq_create_simple_port(handle, "Network",
262                                               SND_SEQ_PORT_CAP_READ |
263                                               SND_SEQ_PORT_CAP_WRITE |
264                                               SND_SEQ_PORT_CAP_SUBS_READ |
265                                               SND_SEQ_PORT_CAP_SUBS_WRITE,
266                                               SND_SEQ_PORT_TYPE_MIDI_GENERIC);
267         if (seq_port < 0) {
268                 perror("create seq port");
269                 exit(1);
270         }
271         if (verbose)
272                 fprintf(stderr, _("sequencer opened: %d:%d\n"),
273                         snd_seq_client_id(handle), seq_port);
274
275         /* explicit subscriptions */
276         if (source) {
277                 /* read subscription */
278                 if (snd_seq_parse_address(handle, &addr, source) < 0) {
279                         fprintf(stderr, _("invalid source address %s\n"), source);
280                         exit(1);
281                 }
282                 if (snd_seq_connect_from(handle, seq_port, addr.client, addr.port)) {
283                         perror("read subscription");
284                         exit(1);
285                 }
286         }
287         if (dest) {
288                 /* write subscription */
289                 if (snd_seq_parse_address(handle, &addr, dest) < 0) {
290                         fprintf(stderr, _("invalid destination address %s\n"), dest);
291                         exit(1);
292                 }
293                 if (snd_seq_connect_to(handle, seq_port, addr.client, addr.port)) {
294                         perror("write subscription");
295                         exit(1);
296                 }
297         }
298 }
299
300
301 /*
302  * convert from string to TCP port number
303  */
304 static int get_port(char *service)
305 {
306         struct servent *sp;
307
308         if ((sp = getservbyname(service, "tcp")) == NULL){
309                 fprintf(stderr, _("service '%s' is not found in /etc/services\n"), service);
310                 return -1;
311         }
312         return sp->s_port;
313 }
314
315 /*
316  * signal handler
317  */
318 static void sigterm_exit(int sig)
319 {
320         close_files();
321         exit(1);
322 }
323
324
325 /*
326  * initialize network server
327  */
328 static void init_server(int port)
329 {
330         int i;
331         int curstate = 1;
332         struct sockaddr_in addr;
333
334         memset(&addr, 0, sizeof(addr));
335
336         addr.sin_family = AF_INET;
337         addr.sin_addr.s_addr = INADDR_ANY;
338         addr.sin_port = htons(port);
339
340         sockfd = socket(AF_INET, SOCK_STREAM, 0);
341         if (sockfd < 0)  {
342                 perror("create socket");
343                 exit(1);
344         }
345         setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &curstate, sizeof(curstate));
346         /* the return value is ignored.. */
347
348         if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0)  {
349                 perror("can't bind");
350                 exit(1);
351         }
352
353         if (listen(sockfd, 5) < 0)  {
354                 perror("can't listen");
355                 exit(1);
356         }
357
358         cur_connected = 0;
359         for (i = 0; i < max_connection; i++)
360                 netfd[i] = -1;
361 }
362
363 /*
364  * start connection on server
365  */
366 static void start_connection(void)
367 {
368         struct sockaddr_in addr;
369         int i;
370         socklen_t addr_len;
371
372         for (i = 0; i < max_connection; i++) {
373                 if (netfd[i] < 0)
374                         break;
375         }
376         if (i >= max_connection) {
377                 fprintf(stderr, _("too many connections!\n"));
378                 exit(1);
379         }
380         memset(&addr, 0, sizeof(addr));
381         addr_len = sizeof(addr);
382         netfd[i] = accept(sockfd, (struct sockaddr *)&addr, &addr_len);
383         if (netfd[i] < 0) {
384                 perror("accept");
385                 exit(1);
386         }
387         if (verbose)
388                 fprintf(stderr, _("accepted[%d]\n"), netfd[i]);
389         cur_connected++;
390 }
391
392 /*
393  * initialize network client
394  */
395 static void init_client(char *server, int port)
396 {
397         struct sockaddr_in addr;
398         struct hostent *host;
399         int curstate = 1;
400         int fd;
401
402         if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0){
403                 perror("create socket");
404                 exit(1);
405         }
406         if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &curstate, sizeof(curstate)) < 0) {
407                 perror("setsockopt");
408                 exit(1);
409         }
410         if ((host = gethostbyname(server)) == NULL){
411                 fprintf(stderr, _("can't get address %s\n"), server);
412                 exit(1);
413         }
414         addr.sin_port = htons(port);
415         addr.sin_family = AF_INET;
416         memcpy(&addr.sin_addr, host->h_addr, host->h_length);
417         if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
418                 perror("connect");
419                 exit(1);
420         }
421         if (verbose)
422                 fprintf(stderr, _("ok.. connected\n"));
423         netfd[0] = fd;
424         cur_connected = 1;
425 }
426
427 /*
428  * event loop
429  */
430 static void do_loop(void)
431 {
432         int i, rc, width;
433         int seqifd_ptr, sockfd_ptr = -1, netfd_ptr;
434
435         for (;;) {
436                 memset(pollfds, 0, pollfds_count * sizeof(struct pollfd));
437                 seqifd_ptr = 0;
438                 memcpy(pollfds, seqifds, sizeof(*seqifds)*(width = seqifds_count));
439                 if (server_mode) {
440                         sockfd_ptr = width;
441                         pollfds[width].fd = sockfd;
442                         pollfds[width].events = POLLIN;
443                         width++;
444                 }
445                 netfd_ptr = width;
446                 for (i = 0; i < max_connection; i++) {
447                         if (netfd[i] >= 0) {
448                                 pollfds[width].fd = netfd[i];
449                                 pollfds[width].events = POLLIN;
450                                 width++;
451                         }
452                 }
453                 do {
454                         rc = poll(pollfds, width, -1);
455                 } while (rc <= 0 && errno == EINTR);
456                 if (rc <= 0) {
457                         perror("poll");
458                         exit(1);
459                 }
460                 if (server_mode) {
461                         if (pollfds[sockfd_ptr].revents & (POLLIN|POLLOUT))
462                                 start_connection();
463                 }
464                 for (i = 0; i < seqifds_count; i++)
465                         if (pollfds[seqifd_ptr + i].revents & (POLLIN|POLLOUT)) {
466                                 if (copy_local_to_remote())
467                                         return;
468                                 break;
469                         }
470                 for (i = 0; i < max_connection; i++) {
471                         if (netfd[i] < 0)
472                                 continue;
473                         if (pollfds[netfd_ptr + i].revents & (POLLIN|POLLOUT)) {
474                                 if (copy_remote_to_local(netfd[i])) {
475                                         netfd[i] = -1;
476                                         cur_connected--;
477                                         if (cur_connected <= 0)
478                                                 return;
479                                 }
480                         }
481                 }
482         }
483 }
484
485
486 /*
487  * flush write buffer - send data to the socket
488  */
489 static void flush_writebuf(void)
490 {
491         if (cur_wrlen) {
492                 int i;
493                 for (i = 0; i < max_connection; i++) {
494                         if (netfd[i] >= 0)
495                                 write(netfd[i], writebuf, cur_wrlen);
496                 }
497                 cur_wrlen = 0;
498         }
499 }
500
501 /*
502  * get space from write buffer
503  */
504 static char *get_writebuf(int len)
505 {
506         char *buf;
507         if (cur_wrlen + len >= max_wrlen)
508                 flush_writebuf();
509         buf = writebuf + cur_wrlen;
510         cur_wrlen += len;
511         return buf;
512 }
513
514 static void print_event(snd_seq_event_t *ev)
515 {
516         switch (ev->type) {
517         case SND_SEQ_EVENT_CONTROLLER: 
518                 printf(_("Channel %2d: Control event : %5d\n"),
519                         ev->data.control.channel, ev->data.control.value);
520                 break;
521         case SND_SEQ_EVENT_PITCHBEND:
522                 printf(_("Channel %2d: Pitchbender   : %5d\n"), 
523                         ev->data.control.channel, ev->data.control.value);
524                 break;
525         case SND_SEQ_EVENT_NOTEON:
526                 printf(_("Channel %2d: Note On event : %5d\n"),
527                         ev->data.control.channel, ev->data.note.note);
528                 break;
529         case SND_SEQ_EVENT_NOTEOFF: 
530                 printf(_("Channel %2d: Note Off event: %5d\n"),
531                        ev->data.control.channel, ev->data.note.note);           
532                 break;
533         }
534 }
535
536 #define EVENT_PACKET_SIZE       32
537
538 /*
539  * copy events from sequencer to port(s)
540  */
541 static int copy_local_to_remote(void)
542 {
543         int rc;
544         snd_seq_event_t *ev;
545         char *buf;
546
547         while ((rc = snd_seq_event_input(handle, &ev)) >= 0 && ev) {
548                 if (ev->type >= SND_SEQ_EVENT_CLIENT_START &&
549                     ! snd_seq_ev_is_variable_type(ev)) {
550                         snd_seq_free_event(ev);
551                         continue;
552                 }
553                 if (snd_seq_ev_is_variable(ev)) {
554                         int len;
555                         len = EVENT_PACKET_SIZE + ev->data.ext.len;
556                         buf = get_writebuf(len);
557                         memcpy(buf, ev, sizeof(snd_seq_event_t));
558                         memcpy(buf + EVENT_PACKET_SIZE, ev->data.ext.ptr, ev->data.ext.len);
559                 } else {
560                         buf = get_writebuf(EVENT_PACKET_SIZE);
561                         memcpy(buf, ev, EVENT_PACKET_SIZE);
562                 }
563                 if (info)
564                         print_event(ev);
565                 snd_seq_free_event(ev);
566         }
567         flush_writebuf();
568         return 0;
569 }
570
571 /*
572  * copy events from a port to sequencer
573  */
574 static int copy_remote_to_local(int fd)
575 {
576         int count;
577         char *buf;
578         snd_seq_event_t *ev;
579
580         count = read(fd, readbuf, MAX_BUF_EVENTS * sizeof(snd_seq_event_t));
581         buf = readbuf;
582
583         if (count == 0) {
584                 if (verbose)
585                         fprintf(stderr, _("disconnected\n"));
586                 return 1;
587         }
588
589         while (count > 0) {
590                 ev = (snd_seq_event_t*)buf;
591                 buf += EVENT_PACKET_SIZE;
592                 count -= EVENT_PACKET_SIZE;
593                 if (snd_seq_ev_is_variable(ev) && ev->data.ext.len > 0) {
594                         ev->data.ext.ptr = buf;
595                         buf += ev->data.ext.len;
596                         count -= ev->data.ext.len;
597                 }
598                 snd_seq_ev_set_direct(ev);
599                 snd_seq_ev_set_source(ev, seq_port);
600                 snd_seq_ev_set_subs(ev);
601                 if (info)
602                         print_event(ev);
603                 snd_seq_event_output(handle, ev);
604         }
605
606         snd_seq_drain_output(handle);
607         return 0;
608 }
609