more consistent naming of MIDI ports (vs. audio); drop use of ALSA seq client ID...
[jack.git] / tools / netsource.c
blob6e6fadb09bc4fa244a35fded13cf14916ddc4a8d
1 /*
2 NetJack Client
4 Copyright (C) 2008 Marc-Olivier Barre <marco@marcochapeau.org>
5 Copyright (C) 2008 Pieter Palmers <pieterpalmers@users.sourceforge.net>
6 Copyright (C) 2006 Torben Hohn <torbenh@gmx.de>
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 /** @file netsource.c
26 * @brief This client connects a remote slave JACK to a local JACK server assumed to be the master
29 #include "config.h"
31 #include <stdio.h>
32 #include <errno.h>
33 #include <unistd.h>
34 #include <stdlib.h>
35 #include <string.h>
37 #include <netinet/in.h>
38 #include <netdb.h>
40 /* These two required by FreeBSD. */
41 #include <sys/types.h>
42 #include <sys/socket.h>
44 #if HAVE_ALLOCA_H
45 #include <alloca.h>
46 #endif
48 #include <jack/jack.h>
50 #include <net_driver.h>
51 #include <netjack_packet.h>
52 #include <samplerate.h>
54 JSList *capture_ports = NULL;
55 JSList *capture_srcs = NULL;
56 int capture_channels = 0;
57 int capture_channels_audio = 2;
58 int capture_channels_midi = 1;
59 JSList *playback_ports = NULL;
60 JSList *playback_srcs = NULL;
61 int playback_channels = 0;
62 int playback_channels_audio = 2;
63 int playback_channels_midi = 1;
65 int latency = 5;
66 jack_nframes_t factor = 1;
67 int bitdepth = 0;
68 int mtu = 1400;
69 int reply_port = 0;
70 jack_client_t *client;
72 int state_connected = 0;
73 int state_latency = 0;
74 int state_netxruns = 0;
75 int state_currentframe = 0;
78 int outsockfd;
79 int insockfd;
80 struct sockaddr destaddr;
81 struct sockaddr bindaddr;
83 int sync_state;
84 jack_transport_state_t last_transport_state;
86 int framecnt = 0;
88 int cont_miss = 0;
90 /**
91 * This Function allocates all the I/O Ports which are added the lists.
93 void
94 alloc_ports (int n_capture_audio, int n_playback_audio, int n_capture_midi, int n_playback_midi)
97 int port_flags = JackPortIsOutput;
98 int chn;
99 jack_port_t *port;
100 char buf[32];
102 capture_ports = NULL;
103 /* Allocate audio capture channels */
104 for (chn = 0; chn < n_capture_audio; chn++)
106 snprintf (buf, sizeof (buf) - 1, "capture_%u", chn + 1);
107 port = jack_port_register (client, buf, JACK_DEFAULT_AUDIO_TYPE, port_flags, 0);
108 if (!port)
110 printf( "jack_netsource: cannot register %s port\n", buf);
111 break;
113 capture_srcs = jack_slist_append (capture_srcs, src_new (SRC_LINEAR, 1, NULL));
114 capture_ports = jack_slist_append (capture_ports, port);
117 /* Allocate midi capture channels */
118 for (chn = n_capture_audio; chn < n_capture_midi + n_capture_audio; chn++)
120 snprintf (buf, sizeof (buf) - 1, "capture_%u", chn + 1);
121 port = jack_port_register (client, buf, JACK_DEFAULT_MIDI_TYPE, port_flags, 0);
122 if (!port)
124 printf ("jack_netsource: cannot register %s port\n", buf);
125 break;
127 capture_ports = jack_slist_append(capture_ports, port);
130 /* Allocate audio playback channels */
131 port_flags = JackPortIsInput;
132 playback_ports = NULL;
133 for (chn = 0; chn < n_playback_audio; chn++)
135 snprintf (buf, sizeof (buf) - 1, "playback_%u", chn + 1);
136 port = jack_port_register (client, buf, JACK_DEFAULT_AUDIO_TYPE, port_flags, 0);
137 if (!port)
139 printf ("jack_netsource: cannot register %s port\n", buf);
140 break;
142 playback_srcs = jack_slist_append (playback_srcs, src_new (SRC_LINEAR, 1, NULL));
143 playback_ports = jack_slist_append (playback_ports, port);
146 /* Allocate midi playback channels */
147 for (chn = n_playback_audio; chn < n_playback_midi + n_playback_audio; chn++)
149 snprintf (buf, sizeof (buf) - 1, "playback_%u", chn + 1);
150 port = jack_port_register (client, buf, JACK_DEFAULT_MIDI_TYPE, port_flags, 0);
151 if (!port)
153 printf ("jack_netsource: cannot register %s port\n", buf);
154 break;
156 playback_ports = jack_slist_append (playback_ports, port);
161 * The Sync callback... sync state is set elsewhere...
162 * we will see if this is working correctly.
163 * i dont really believe in it yet.
166 sync_cb (jack_transport_state_t state, jack_position_t *pos, void *arg)
168 static int latency_count = 0;
169 int retval = sync_state;
171 if (latency_count) {
172 latency_count--;
173 retval = 0;
176 else if (state == JackTransportStarting && last_transport_state != JackTransportStarting)
178 retval = 0;
179 latency_count = latency - 1;
182 last_transport_state = state;
183 return retval;
187 * The process callback for this JACK application.
188 * It is called by JACK at the appropriate times.
191 process (jack_nframes_t nframes, void *arg)
193 jack_nframes_t net_period = (float) nframes / (float) factor;
195 int rx_bufsize = get_sample_size (bitdepth) * capture_channels * net_period + sizeof (jacknet_packet_header);
196 int tx_bufsize = get_sample_size (bitdepth) * playback_channels * net_period + sizeof (jacknet_packet_header);
198 jack_default_audio_sample_t *buf;
199 jack_port_t *port;
200 JSList *node;
201 channel_t chn;
202 int size, i;
203 const char *porttype;
205 jack_position_t local_trans_pos;
207 uint32_t *packet_buf, *packet_bufX;
209 /* Allocate a buffer where both In and Out Buffer will fit */
210 packet_buf = alloca ((rx_bufsize > tx_bufsize) ? rx_bufsize : tx_bufsize);
212 jacknet_packet_header *pkthdr = (jacknet_packet_header *) packet_buf;
214 packet_bufX = packet_buf + sizeof (jacknet_packet_header) / sizeof (uint32_t);
216 /* ---------- Receive ---------- */
217 if (reply_port)
218 size = netjack_recv (insockfd, (char *) packet_buf, rx_bufsize, MSG_DONTWAIT, mtu);
219 else
220 size = netjack_recv (outsockfd, (char *) packet_buf, rx_bufsize, MSG_DONTWAIT, mtu);
221 packet_header_ntoh (pkthdr);
222 /* Loop till we get the right packet at the right momment */
223 while (size == rx_bufsize && (framecnt - pkthdr->framecnt) > latency)
225 //printf ("Frame %d \tLate packet received with a latency of %d frames (expected frame %d, got frame %d)\n", framecnt, framecnt - pkthdr->framecnt, framecnt - latency, pkthdr->framecnt);
226 //printf ("Frame %d \tLate packet received with a latency of %d frames\n", framecnt, framecnt - pkthdr->framecnt);
228 if (reply_port)
229 size = netjack_recv (insockfd, (char *) packet_buf, rx_bufsize, MSG_DONTWAIT, mtu);
230 else
231 size = netjack_recv (outsockfd, (char *) packet_buf, rx_bufsize, MSG_DONTWAIT, mtu);
232 packet_header_ntoh (pkthdr);
235 /* First alternative : we received what we expected. Render the data
236 * to the JACK ports so it can be played. */
237 if (size == rx_bufsize)
239 if (cont_miss)
241 //printf("Frame %d \tRecovered from dropouts\n", framecnt);
242 cont_miss = 0;
244 render_payload_to_jack_ports (bitdepth, packet_bufX, net_period, capture_ports, capture_srcs, nframes);
246 /* Now evaluate packet header */
247 //if (sync_state != pkthdr->sync_state)
248 // printf ("Frame %d \tSync has been set\n", framecnt);
250 state_currentframe = framecnt;
251 state_latency = framecnt - pkthdr->framecnt;
252 state_connected = 1;
253 sync_state = pkthdr->sync_state;
255 /* Second alternative : we've received something that's not
256 * as big as expected or we missed a packet. We render silence
257 * to the ouput ports */
258 else
260 // Set the counters up.
261 state_currentframe = framecnt;
262 state_latency = framecnt - pkthdr->framecnt;
263 state_netxruns += 1;
265 //printf ("Frame %d \tPacket missed or incomplete (expected: %d bytes, got: %d bytes)\n", framecnt, rx_bufsize, size);
266 //printf ("Frame %d \tPacket missed or incomplete\n", framecnt);
267 cont_miss += 1;
268 chn = 0;
269 node = capture_ports;
270 while (node != NULL)
272 port = (jack_port_t *) node->data;
273 buf = jack_port_get_buffer (port, nframes);
274 porttype = jack_port_type (port);
275 if (strncmp (porttype, JACK_DEFAULT_AUDIO_TYPE, jack_port_type_size ()) == 0)
276 for (i = 0; i < nframes; i++)
277 buf[i] = 0.0;
278 else if (strncmp (porttype, JACK_DEFAULT_MIDI_TYPE, jack_port_type_size ()) == 0)
279 jack_midi_clear_buffer (buf);
280 node = jack_slist_next (node);
281 chn++;
284 /* reset packet_bufX... */
285 packet_bufX = packet_buf + sizeof (jacknet_packet_header) / sizeof (jack_default_audio_sample_t);
287 /* ---------- Send ---------- */
288 render_jack_ports_to_payload (bitdepth, playback_ports, playback_srcs, nframes, packet_bufX, net_period);
290 /* fill in packet hdr */
291 pkthdr->transport_state = jack_transport_query (client, &local_trans_pos);
292 pkthdr->transport_frame = local_trans_pos.frame;
293 pkthdr->framecnt = framecnt;
294 pkthdr->latency = latency;
295 pkthdr->reply_port = reply_port;
296 pkthdr->sample_rate = jack_get_sample_rate (client);
297 pkthdr->period_size = nframes;
299 /* playback for us is capture on the other side */
300 pkthdr->capture_channels_audio = playback_channels_audio;
301 pkthdr->playback_channels_audio = capture_channels_audio;
302 pkthdr->capture_channels_midi = playback_channels_midi;
303 pkthdr->playback_channels_midi = capture_channels_midi;
304 pkthdr->mtu = mtu;
306 packet_header_hton (pkthdr);
307 if (cont_miss < 10)
308 netjack_sendto (outsockfd, (char *) packet_buf, tx_bufsize, 0, &destaddr, sizeof (destaddr), mtu);
309 // else if (cont_miss >= 10 && cont_miss <= 50)
310 // printf ("Frame %d \tToo many packets missed (%d). We have stopped sending data\n", framecnt, cont_miss);
311 else if (cont_miss > 50)
313 state_connected = 0;
314 //printf ("Frame %d \tRealy too many packets missed (%d). Let's reset the counter\n", framecnt, cont_miss);
315 cont_miss = 5;
318 framecnt++;
319 return 0;
323 * This is the shutdown callback for this JACK application.
324 * It is called by JACK if the server ever shuts down or
325 * decides to disconnect the client.
328 void
329 jack_shutdown (void *arg)
331 exit (1);
334 void
335 init_sockaddr_in (struct sockaddr_in *name , const char *hostname , uint16_t port)
337 name->sin_family = AF_INET ;
338 name->sin_port = htons (port);
339 if (hostname)
341 struct hostent *hostinfo = gethostbyname (hostname);
342 if (hostinfo == NULL)
343 fprintf (stderr, "init_sockaddr_in: unknown host: %s.\n", hostname);
344 name->sin_addr = *(struct in_addr *) hostinfo->h_addr ;
346 else
347 name->sin_addr.s_addr = htonl (INADDR_ANY) ;
350 void
351 printUsage ()
353 fprintf (stderr, "usage: jack_netsource -h <host peer> [options]\n"
354 "\n"
355 " -n <jack name> - Reports a different name to jack\n"
356 " -s <server name> - The name of the local jack server\n"
357 " -h <host_peer> - Host name of the slave JACK\n"
358 " -p <port> - UDP port used by the slave JACK\n"
359 " -P <num channels> - Number of audio playback channels\n"
360 " -C <num channels> - Number of audio capture channels\n"
361 " -o <num channels> - Number of midi playback channels\n"
362 " -i <num channels> - Number of midi capture channels\n"
363 " -l <latency> - Network latency in number of NetJack frames\n"
364 " -r <reply port> - Local UDP port to use\n"
365 " -f <downsample ratio> - Downsample data in the wire by this factor\n"
366 " -b <bitdepth> - Set transport to use 16bit or 8bit\n"
367 " -m <mtu> - Assume this mtu for the link\n"
368 "\n");
372 main (int argc, char *argv[])
374 /* Some startup related basics */
375 char *client_name, *server_name = NULL, *peer_ip;
376 int peer_port = 3000;
377 jack_options_t options = JackNullOption;
378 jack_status_t status;
380 /* Torben's famous state variables, aka "the reporting API" ! */
381 int statecopy_connected, statecopy_latency, statecopy_netxruns;
383 /* Argument parsing stuff */
384 extern char *optarg;
385 extern int optind, optopt;
386 int errflg=0, c;
388 if (argc < 3)
390 printUsage ();
391 return 1;
394 client_name = (char *) malloc (sizeof (char) * 9);
395 peer_ip = (char *) malloc (sizeof (char) * 9);
396 sprintf(client_name, "netsource");
397 sprintf(peer_ip, "localhost");
399 while ((c = getopt (argc, argv, ":n:s:h:p:C:P:i:o:l:r:f:b:m:")) != -1)
401 switch (c)
403 case 'n':
404 free(client_name);
405 client_name = (char *) malloc (sizeof (char) * strlen (optarg));
406 strcpy (client_name, optarg);
407 break;
408 case 's':
409 server_name = (char *) malloc (sizeof (char) * strlen (optarg));
410 strcpy (server_name, optarg);
411 options |= JackServerName;
412 break;
413 case 'h':
414 free(peer_ip);
415 peer_ip = (char *) malloc (sizeof (char) * strlen (optarg));
416 strcpy (peer_ip, optarg);
417 break;
418 case 'p':
419 peer_port = atoi (optarg);
420 break;
421 case 'P':
422 playback_channels_audio = atoi (optarg);
423 break;
424 case 'C':
425 capture_channels_audio = atoi (optarg);
426 break;
427 case 'o':
428 playback_channels_midi = atoi (optarg);
429 break;
430 case 'i':
431 capture_channels_midi = atoi (optarg);
432 break;
433 case 'l':
434 latency = atoi (optarg);
435 break;
436 case 'r':
437 reply_port = atoi (optarg);
438 break;
439 case 'f':
440 factor = atoi (optarg);
441 break;
442 case 'b':
443 bitdepth = atoi (optarg);
444 break;
445 case 'm':
446 mtu = atoi (optarg);
447 break;
448 case ':':
449 fprintf (stderr, "Option -%c requires an operand\n", optopt);
450 errflg++;
451 break;
452 case '?':
453 fprintf (stderr, "Unrecognized option: -%c\n", optopt);
454 errflg++;
457 if (errflg)
459 printUsage ();
460 exit (2);
463 capture_channels = capture_channels_audio + capture_channels_midi;
464 playback_channels = playback_channels_audio + playback_channels_midi;
466 outsockfd = socket (PF_INET, SOCK_DGRAM, 0);
467 insockfd = socket (PF_INET, SOCK_DGRAM, 0);
468 init_sockaddr_in ((struct sockaddr_in *) &destaddr, peer_ip, peer_port);
469 if(reply_port)
471 init_sockaddr_in ((struct sockaddr_in *) &bindaddr, NULL, reply_port);
472 bind (insockfd, &bindaddr, sizeof (bindaddr));
475 /* try to become a client of the JACK server */
476 client = jack_client_open (client_name, options, &status, server_name);
477 if (client == NULL)
479 fprintf (stderr, "jack_client_open() failed, status = 0x%2.0x\n"
480 "Is the JACK server running ?\n", status);
481 return 1;
484 /* Set up jack callbacks */
485 jack_set_process_callback (client, process, 0);
486 jack_set_sync_callback (client, sync_cb, 0);
487 jack_on_shutdown (client, jack_shutdown, 0);
489 alloc_ports (capture_channels_audio, playback_channels_audio, capture_channels_midi, playback_channels_midi);
491 jack_nframes_t net_period = (float) jack_get_buffer_size (client) / (float) factor;
492 int rx_bufsize = get_sample_size (bitdepth) * capture_channels * net_period + sizeof (jacknet_packet_header);
493 global_packcache = packet_cache_new (latency + 5, rx_bufsize, mtu);
495 /* tell the JACK server that we are ready to roll */
496 if (jack_activate (client))
498 fprintf (stderr, "Cannot activate client");
499 return 1;
502 /* Now sleep forever... and evaluate the state_ vars */
504 statecopy_connected = 2; // make it report unconnected on start.
505 statecopy_latency = state_latency;
506 statecopy_netxruns = state_netxruns;
508 while (1)
510 sleep (1);
511 if (statecopy_connected != state_connected)
513 statecopy_connected = state_connected;
514 if (statecopy_connected)
516 state_netxruns = 1; // We want to reset the netxrun count on each new connection
517 printf ("Connected :-)\n");
519 else
520 printf ("Not Connected\n");
523 if (statecopy_connected)
525 if (statecopy_netxruns != state_netxruns) {
526 statecopy_netxruns = state_netxruns;
527 printf ("at frame %06d -> total netxruns %d\n", state_currentframe, statecopy_netxruns);
530 else
532 if (statecopy_latency != state_latency)
534 statecopy_latency = state_latency;
535 if (statecopy_latency > 1)
536 printf ("current latency %d\n", statecopy_latency);
541 /* Never reached. Well we will be a GtkApp someday... */
542 packet_cache_free (global_packcache);
543 jack_client_close (client);
544 exit (0);