[netjack] improve deadline handling, to recover from running too fast.
[jack.git] / tools / netsource.c
blobdeecb2d67da99d39019e2f7a75d39acc7f04d915
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 #if HAVE_CELT
55 #include <celt/celt.h>
56 #endif
58 #include <math.h>
60 JSList *capture_ports = NULL;
61 JSList *capture_srcs = NULL;
62 int capture_channels = 0;
63 int capture_channels_audio = 2;
64 int capture_channels_midi = 1;
65 JSList *playback_ports = NULL;
66 JSList *playback_srcs = NULL;
67 int playback_channels = 0;
68 int playback_channels_audio = 2;
69 int playback_channels_midi = 1;
71 int latency = 5;
72 jack_nframes_t factor = 1;
73 int bitdepth = 0;
74 int mtu = 1400;
75 int reply_port = 0;
76 int redundancy = 1;
77 jack_client_t *client;
79 int state_connected = 0;
80 int state_latency = 0;
81 int state_netxruns = 0;
82 int state_currentframe = 0;
83 int state_recv_packet_queue_time = 0;
86 int outsockfd;
87 int insockfd;
88 struct sockaddr destaddr;
89 struct sockaddr bindaddr;
91 int sync_state;
92 jack_transport_state_t last_transport_state;
94 int framecnt = 0;
96 int cont_miss = 0;
98 /**
99 * This Function allocates all the I/O Ports which are added the lists.
101 void
102 alloc_ports (int n_capture_audio, int n_playback_audio, int n_capture_midi, int n_playback_midi)
105 int port_flags = JackPortIsOutput;
106 int chn;
107 jack_port_t *port;
108 char buf[32];
110 capture_ports = NULL;
111 /* Allocate audio capture channels */
112 for (chn = 0; chn < n_capture_audio; chn++)
114 snprintf (buf, sizeof (buf) - 1, "capture_%u", chn + 1);
115 port = jack_port_register (client, buf, JACK_DEFAULT_AUDIO_TYPE, port_flags, 0);
116 if (!port)
118 printf( "jack_netsource: cannot register %s port\n", buf);
119 break;
121 if( bitdepth == 1000 ) {
122 #if HAVE_CELT
123 // XXX: memory leak
124 CELTMode *celt_mode = celt_mode_create( jack_get_sample_rate( client ), 1, jack_get_buffer_size(client), NULL );
125 capture_srcs = jack_slist_append(capture_srcs, celt_decoder_create( celt_mode ) );
126 #endif
127 } else {
128 capture_srcs = jack_slist_append (capture_srcs, src_new (SRC_LINEAR, 1, NULL));
130 capture_ports = jack_slist_append (capture_ports, port);
133 /* Allocate midi capture channels */
134 for (chn = n_capture_audio; chn < n_capture_midi + n_capture_audio; chn++)
136 snprintf (buf, sizeof (buf) - 1, "capture_%u", chn + 1);
137 port = jack_port_register (client, buf, JACK_DEFAULT_MIDI_TYPE, port_flags, 0);
138 if (!port)
140 printf ("jack_netsource: cannot register %s port\n", buf);
141 break;
143 capture_ports = jack_slist_append(capture_ports, port);
146 /* Allocate audio playback channels */
147 port_flags = JackPortIsInput;
148 playback_ports = NULL;
149 for (chn = 0; chn < n_playback_audio; chn++)
151 snprintf (buf, sizeof (buf) - 1, "playback_%u", chn + 1);
152 port = jack_port_register (client, buf, JACK_DEFAULT_AUDIO_TYPE, port_flags, 0);
153 if (!port)
155 printf ("jack_netsource: cannot register %s port\n", buf);
156 break;
158 if( bitdepth == 1000 ) {
159 #if HAVE_CELT
160 // XXX: memory leak
161 CELTMode *celt_mode = celt_mode_create( jack_get_sample_rate (client), 1, jack_get_buffer_size(client), NULL );
162 playback_srcs = jack_slist_append(playback_srcs, celt_encoder_create( celt_mode ) );
163 #endif
164 } else {
165 playback_srcs = jack_slist_append (playback_srcs, src_new (SRC_LINEAR, 1, NULL));
167 playback_ports = jack_slist_append (playback_ports, port);
170 /* Allocate midi playback channels */
171 for (chn = n_playback_audio; chn < n_playback_midi + n_playback_audio; chn++)
173 snprintf (buf, sizeof (buf) - 1, "playback_%u", chn + 1);
174 port = jack_port_register (client, buf, JACK_DEFAULT_MIDI_TYPE, port_flags, 0);
175 if (!port)
177 printf ("jack_netsource: cannot register %s port\n", buf);
178 break;
180 playback_ports = jack_slist_append (playback_ports, port);
185 * The Sync callback... sync state is set elsewhere...
186 * we will see if this is working correctly.
187 * i dont really believe in it yet.
190 sync_cb (jack_transport_state_t state, jack_position_t *pos, void *arg)
192 static int latency_count = 0;
193 int retval = sync_state;
195 if (latency_count) {
196 latency_count--;
197 retval = 0;
200 else if (state == JackTransportStarting && last_transport_state != JackTransportStarting)
202 retval = 0;
203 latency_count = latency - 1;
206 last_transport_state = state;
207 return retval;
210 int deadline_goodness=0;
212 * The process callback for this JACK application.
213 * It is called by JACK at the appropriate times.
216 process (jack_nframes_t nframes, void *arg)
218 jack_nframes_t net_period;
219 int rx_bufsize, tx_bufsize;
221 jack_default_audio_sample_t *buf;
222 jack_port_t *port;
223 JSList *node;
224 channel_t chn;
225 int size, i;
226 const char *porttype;
227 int input_fd;
229 jack_position_t local_trans_pos;
231 uint32_t *packet_buf, *packet_bufX;
232 jack_time_t packet_recv_timestamp;
234 if( bitdepth == 1000 )
235 net_period = factor;
236 else
237 net_period = (float) nframes / (float) factor;
239 rx_bufsize = get_sample_size (bitdepth) * capture_channels * net_period + sizeof (jacknet_packet_header);
240 tx_bufsize = get_sample_size (bitdepth) * playback_channels * net_period + sizeof (jacknet_packet_header);
243 /* Allocate a buffer where both In and Out Buffer will fit */
244 packet_buf = alloca ((rx_bufsize > tx_bufsize) ? rx_bufsize : tx_bufsize);
246 jacknet_packet_header *pkthdr = (jacknet_packet_header *) packet_buf;
249 * ok... SEND code first.
250 * needed some time to find out why latency=0
251 * did not work ;S
255 /* reset packet_bufX... */
256 packet_bufX = packet_buf + sizeof (jacknet_packet_header) / sizeof (jack_default_audio_sample_t);
258 /* ---------- Send ---------- */
259 render_jack_ports_to_payload (bitdepth, playback_ports, playback_srcs, nframes, packet_bufX, net_period);
261 /* fill in packet hdr */
262 pkthdr->transport_state = jack_transport_query (client, &local_trans_pos);
263 pkthdr->transport_frame = local_trans_pos.frame;
264 pkthdr->framecnt = framecnt;
265 pkthdr->latency = latency;
266 pkthdr->reply_port = reply_port;
267 pkthdr->sample_rate = jack_get_sample_rate (client);
268 pkthdr->period_size = nframes;
270 /* playback for us is capture on the other side */
271 pkthdr->capture_channels_audio = playback_channels_audio;
272 pkthdr->playback_channels_audio = capture_channels_audio;
273 pkthdr->capture_channels_midi = playback_channels_midi;
274 pkthdr->playback_channels_midi = capture_channels_midi;
275 pkthdr->mtu = mtu;
276 pkthdr->sync_state = (jack_nframes_t)deadline_goodness;
277 //printf("goodness=%d\n", deadline_goodness );
279 packet_header_hton (pkthdr);
280 if (cont_miss < 3*latency+5) {
281 int r;
282 for( r=0; r<redundancy; r++ )
283 netjack_sendto (outsockfd, (char *) packet_buf, tx_bufsize, 0, &destaddr, sizeof (destaddr), mtu);
285 else if (cont_miss > 50+5*latency)
287 state_connected = 0;
288 packet_cache_reset_master_address( global_packcache );
289 //printf ("Frame %d \tRealy too many packets missed (%d). Let's reset the counter\n", framecnt, cont_miss);
290 cont_miss = 0;
294 * ok... now the RECEIVE code.
298 /* reset packet_bufX... */
299 packet_bufX = packet_buf + sizeof (jacknet_packet_header) / sizeof (jack_default_audio_sample_t);
301 if( reply_port )
302 input_fd = insockfd;
303 else
304 input_fd = outsockfd;
306 // for latency == 0 we can poll.
307 if( latency == 0 ) {
308 jack_time_t deadline = jack_get_microseconds() + 1000000 * jack_get_buffer_size(client)/jack_get_sample_rate(client);
309 // Now loop until we get the right packet.
310 while(1) {
311 if ( ! netjack_poll_deadline( input_fd, deadline ) )
312 break;
314 packet_cache_drain_socket(global_packcache, input_fd);
316 if (packet_cache_get_next_available_framecnt( global_packcache, framecnt - latency, NULL ))
317 break;
319 } else {
320 // normally:
321 // only drain socket.
322 packet_cache_drain_socket(global_packcache, input_fd);
325 size = packet_cache_retreive_packet( global_packcache, framecnt - latency, (char *)packet_buf, rx_bufsize, &packet_recv_timestamp );
326 /* First alternative : we received what we expected. Render the data
327 * to the JACK ports so it can be played. */
328 if (size == rx_bufsize)
330 // calculate how much time there would have been, if this packet was sent at the deadline.
332 int recv_time_offset = (int) (jack_get_microseconds() - packet_recv_timestamp);
333 packet_header_ntoh (pkthdr);
334 deadline_goodness = recv_time_offset - (int)pkthdr->latency;
335 //printf( "deadline goodness = %d ---> off: %d\n", deadline_goodness, recv_time_offset );
337 if (cont_miss)
339 //printf("Frame %d \tRecovered from dropouts\n", framecnt);
340 cont_miss = 0;
342 render_payload_to_jack_ports (bitdepth, packet_bufX, net_period, capture_ports, capture_srcs, nframes);
344 state_currentframe = framecnt;
345 state_recv_packet_queue_time = recv_time_offset;
346 state_connected = 1;
347 sync_state = pkthdr->sync_state;
349 /* Second alternative : we've received something that's not
350 * as big as expected or we missed a packet. We render silence
351 * to the ouput ports */
352 else
354 jack_nframes_t latency_estimate;
355 if( packet_cache_find_latency( global_packcache, framecnt, &latency_estimate ) )
356 //if( (state_latency == 0) || (latency_estimate < state_latency) )
357 state_latency = latency_estimate;
359 // Set the counters up.
360 state_currentframe = framecnt;
361 //state_latency = framecnt - pkthdr->framecnt;
362 state_netxruns += 1;
364 //printf ("Frame %d \tPacket missed or incomplete (expected: %d bytes, got: %d bytes)\n", framecnt, rx_bufsize, size);
365 //printf ("Frame %d \tPacket missed or incomplete\n", framecnt);
366 cont_miss += 1;
367 chn = 0;
368 node = capture_ports;
369 while (node != NULL)
371 port = (jack_port_t *) node->data;
372 buf = jack_port_get_buffer (port, nframes);
373 porttype = jack_port_type (port);
374 if (strncmp (porttype, JACK_DEFAULT_AUDIO_TYPE, jack_port_type_size ()) == 0)
375 for (i = 0; i < nframes; i++)
376 buf[i] = 0.0;
377 else if (strncmp (porttype, JACK_DEFAULT_MIDI_TYPE, jack_port_type_size ()) == 0)
378 jack_midi_clear_buffer (buf);
379 node = jack_slist_next (node);
380 chn++;
384 framecnt++;
385 return 0;
389 * This is the shutdown callback for this JACK application.
390 * It is called by JACK if the server ever shuts down or
391 * decides to disconnect the client.
394 void
395 jack_shutdown (void *arg)
397 exit (1);
400 void
401 init_sockaddr_in (struct sockaddr_in *name , const char *hostname , uint16_t port)
403 name->sin_family = AF_INET ;
404 name->sin_port = htons (port);
405 if (hostname)
407 struct hostent *hostinfo = gethostbyname (hostname);
408 if (hostinfo == NULL)
409 fprintf (stderr, "init_sockaddr_in: unknown host: %s.\n", hostname);
410 name->sin_addr = *(struct in_addr *) hostinfo->h_addr ;
412 else
413 name->sin_addr.s_addr = htonl (INADDR_ANY) ;
416 void
417 printUsage ()
419 fprintf (stderr, "usage: jack_netsource -h <host peer> [options]\n"
420 "\n"
421 " -n <jack name> - Reports a different name to jack\n"
422 " -s <server name> - The name of the local jack server\n"
423 " -h <host_peer> - Host name of the slave JACK\n"
424 " -p <port> - UDP port used by the slave JACK\n"
425 " -P <num channels> - Number of audio playback channels\n"
426 " -C <num channels> - Number of audio capture channels\n"
427 " -o <num channels> - Number of midi playback channels\n"
428 " -i <num channels> - Number of midi capture channels\n"
429 " -l <latency> - Network latency in number of NetJack frames\n"
430 " -r <reply port> - Local UDP port to use\n"
431 " -f <downsample ratio> - Downsample data in the wire by this factor\n"
432 " -b <bitdepth> - Set transport to use 16bit or 8bit\n"
433 " -m <mtu> - Assume this mtu for the link\n"
434 " -c <bytes> - Use Celt and encode <bytes> per channel and packet.\n"
435 " -R <N> - Send out packets N times.\n"
436 "\n");
440 main (int argc, char *argv[])
442 /* Some startup related basics */
443 char *client_name, *server_name = NULL, *peer_ip;
444 int peer_port = 3000;
445 jack_options_t options = JackNullOption;
446 jack_status_t status;
448 /* Torben's famous state variables, aka "the reporting API" ! */
449 /* heh ? these are only the copies of them ;) */
450 int statecopy_connected, statecopy_latency, statecopy_netxruns;
451 jack_nframes_t net_period;
452 /* Argument parsing stuff */
453 extern char *optarg;
454 extern int optind, optopt;
455 int errflg=0, c;
457 if (argc < 3)
459 printUsage ();
460 return 1;
463 client_name = (char *) malloc (sizeof (char) * 10);
464 peer_ip = (char *) malloc (sizeof (char) * 10);
465 sprintf(client_name, "netsource");
466 sprintf(peer_ip, "localhost");
468 while ((c = getopt (argc, argv, ":R:n:s:h:p:C:P:i:o:l:r:f:b:m:c:")) != -1)
470 switch (c)
472 case 'n':
473 free(client_name);
474 client_name = (char *) malloc (sizeof (char) * strlen (optarg)+1);
475 strcpy (client_name, optarg);
476 break;
477 case 's':
478 server_name = (char *) malloc (sizeof (char) * strlen (optarg)+1);
479 strcpy (server_name, optarg);
480 options |= JackServerName;
481 break;
482 case 'h':
483 free(peer_ip);
484 peer_ip = (char *) malloc (sizeof (char) * strlen (optarg)+1);
485 strcpy (peer_ip, optarg);
486 break;
487 case 'p':
488 peer_port = atoi (optarg);
489 break;
490 case 'P':
491 playback_channels_audio = atoi (optarg);
492 break;
493 case 'C':
494 capture_channels_audio = atoi (optarg);
495 break;
496 case 'o':
497 playback_channels_midi = atoi (optarg);
498 break;
499 case 'i':
500 capture_channels_midi = atoi (optarg);
501 break;
502 case 'l':
503 latency = atoi (optarg);
504 break;
505 case 'r':
506 reply_port = atoi (optarg);
507 break;
508 case 'f':
509 factor = atoi (optarg);
510 break;
511 case 'b':
512 bitdepth = atoi (optarg);
513 break;
514 case 'c':
515 #if HAVE_CELT
516 bitdepth = 1000;
517 factor = atoi (optarg);
518 #else
519 printf( "not built with celt supprt\n" );
520 exit(10);
521 #endif
522 break;
523 case 'm':
524 mtu = atoi (optarg);
525 break;
526 case 'R':
527 redundancy = atoi (optarg);
528 break;
529 case ':':
530 fprintf (stderr, "Option -%c requires an operand\n", optopt);
531 errflg++;
532 break;
533 case '?':
534 fprintf (stderr, "Unrecognized option: -%c\n", optopt);
535 errflg++;
538 if (errflg)
540 printUsage ();
541 exit (2);
544 capture_channels = capture_channels_audio + capture_channels_midi;
545 playback_channels = playback_channels_audio + playback_channels_midi;
547 outsockfd = socket (PF_INET, SOCK_DGRAM, 0);
548 insockfd = socket (PF_INET, SOCK_DGRAM, 0);
549 init_sockaddr_in ((struct sockaddr_in *) &destaddr, peer_ip, peer_port);
550 if(reply_port)
552 init_sockaddr_in ((struct sockaddr_in *) &bindaddr, NULL, reply_port);
553 bind (insockfd, &bindaddr, sizeof (bindaddr));
556 /* try to become a client of the JACK server */
557 client = jack_client_open (client_name, options, &status, server_name);
558 if (client == NULL)
560 fprintf (stderr, "jack_client_open() failed, status = 0x%2.0x\n"
561 "Is the JACK server running ?\n", status);
562 return 1;
565 /* Set up jack callbacks */
566 jack_set_process_callback (client, process, 0);
567 jack_set_sync_callback (client, sync_cb, 0);
568 jack_on_shutdown (client, jack_shutdown, 0);
570 alloc_ports (capture_channels_audio, playback_channels_audio, capture_channels_midi, playback_channels_midi);
572 if( bitdepth == 1000 )
573 net_period = factor;
574 else
575 net_period = ceilf((float) jack_get_buffer_size (client) / (float) factor);
577 int rx_bufsize = get_sample_size (bitdepth) * capture_channels * net_period + sizeof (jacknet_packet_header);
578 global_packcache = packet_cache_new (latency + 50, rx_bufsize, mtu);
580 /* tell the JACK server that we are ready to roll */
581 if (jack_activate (client))
583 fprintf (stderr, "Cannot activate client");
584 return 1;
587 /* Now sleep forever... and evaluate the state_ vars */
589 statecopy_connected = 2; // make it report unconnected on start.
590 statecopy_latency = state_latency;
591 statecopy_netxruns = state_netxruns;
593 while (1)
595 sleep (1);
596 if (statecopy_connected != state_connected)
598 statecopy_connected = state_connected;
599 if (statecopy_connected)
601 state_netxruns = 1; // We want to reset the netxrun count on each new connection
602 printf ("Connected :-)\n");
604 else
605 printf ("Not Connected\n");
607 fflush(stdout);
610 if (statecopy_connected)
612 if (statecopy_netxruns != state_netxruns) {
613 statecopy_netxruns = state_netxruns;
614 printf ("at frame %06d -> total netxruns %d (%d%%) queue time= %d\n", state_currentframe,
615 statecopy_netxruns,
616 100*statecopy_netxruns/state_currentframe,
617 state_recv_packet_queue_time);
618 fflush(stdout);
621 else
623 if (statecopy_latency != state_latency)
625 statecopy_latency = state_latency;
626 if (statecopy_latency > 1)
627 printf ("current latency %d\n", statecopy_latency);
628 fflush(stdout);
633 /* Never reached. Well we will be a GtkApp someday... */
634 packet_cache_free (global_packcache);
635 jack_client_close (client);
636 exit (0);