int main (int argc, char *argv[]) { /* Some startup related basics */ char *client_name, *server_name = NULL, *peer_ip; int peer_port = 3000; jack_options_t options = JackNullOption; jack_status_t status; #ifdef WIN32 WSADATA wsa; int rc = WSAStartup(MAKEWORD(2, 0), &wsa); #endif /* Torben's famous state variables, aka "the reporting API" ! */ /* heh ? these are only the copies of them ;) */ int statecopy_connected, statecopy_latency, statecopy_netxruns; jack_nframes_t net_period; /* Argument parsing stuff */ extern char *optarg; extern int optind, optopt; int errflg = 0, c; if (argc < 3) { printUsage (); return 1; } client_name = (char *) malloc (sizeof (char) * 10); peer_ip = (char *) malloc (sizeof (char) * 10); sprintf(client_name, "netjack"); sprintf(peer_ip, "localhost"); while ((c = getopt (argc, argv, ":h:H:o:i:O:I:n:p:r:B:b:c:m:R:e:N:s:P:")) != -1) { switch (c) { case 'h': printUsage(); exit (0); break; case 'H': free(peer_ip); peer_ip = (char *) malloc (sizeof (char) * strlen (optarg) + 1); strcpy (peer_ip, optarg); break; case 'o': playback_channels_audio = atoi (optarg); break; case 'i': capture_channels_audio = atoi (optarg); break; case 'O': playback_channels_midi = atoi (optarg); break; case 'I': capture_channels_midi = atoi (optarg); break; case 'n': latency = atoi (optarg); break; case 'p': peer_port = atoi (optarg); break; case 'r': reply_port = atoi (optarg); break; case 'B': bind_port = atoi (optarg); break; case 'f': factor = atoi (optarg); printf("This feature is deprecated and will be removed in future netjack versions. CELT offers a superiour way to conserve bandwidth"); break; case 'b': bitdepth = atoi (optarg); break; case 'c': #if HAVE_CELT bitdepth = 1000; factor = atoi (optarg); #else printf( "not built with celt support\n" ); exit(10); #endif break; case 'P': #if HAVE_OPUS bitdepth = 999; factor = atoi (optarg); #else printf( "not built with opus support\n" ); exit(10); #endif break; case 'm': mtu = atoi (optarg); break; case 'R': redundancy = atoi (optarg); break; case 'e': dont_htonl_floats = 1; break; case 'N': free(client_name); client_name = (char *) malloc (sizeof (char) * strlen (optarg) + 1); strcpy (client_name, optarg); break; case 's': server_name = (char *) malloc (sizeof (char) * strlen (optarg) + 1); strcpy (server_name, optarg); options |= JackServerName; break; case ':': fprintf (stderr, "Option -%c requires an operand\n", optopt); errflg++; break; case '?': fprintf (stderr, "Unrecognized option: -%c\n", optopt); errflg++; } } if (errflg) { printUsage (); exit (2); } capture_channels = capture_channels_audio + capture_channels_midi; playback_channels = playback_channels_audio + playback_channels_midi; outsockfd = socket (AF_INET, SOCK_DGRAM, 0); insockfd = socket (AF_INET, SOCK_DGRAM, 0); if ((outsockfd == -1) || (insockfd == -1)) { fprintf (stderr, "cant open sockets\n" ); return 1; } init_sockaddr_in ((struct sockaddr_in *) &destaddr, peer_ip, peer_port); if (bind_port) { init_sockaddr_in ((struct sockaddr_in *) &bindaddr, NULL, bind_port); if( bind (outsockfd, &bindaddr, sizeof (bindaddr)) ) { fprintf (stderr, "bind failure\n" ); } } if (reply_port) { init_sockaddr_in ((struct sockaddr_in *) &bindaddr, NULL, reply_port); if( bind (insockfd, &bindaddr, sizeof (bindaddr)) ) { fprintf (stderr, "bind failure\n" ); } } /* try to become a client of the JACK server */ client = jack_client_open (client_name, options, &status, server_name); if (client == NULL) { fprintf (stderr, "jack_client_open() failed, status = 0x%2.0x\n" "Is the JACK server running ?\n", status); return 1; } /* Set up jack callbacks */ jack_set_process_callback (client, process, 0); jack_set_sync_callback (client, sync_cb, 0); jack_set_freewheel_callback (client, freewheel_cb, 0); jack_on_shutdown (client, jack_shutdown, 0); alloc_ports (capture_channels_audio, playback_channels_audio, capture_channels_midi, playback_channels_midi); if( bitdepth == 1000 || bitdepth == 999) net_period = (factor * jack_get_buffer_size(client) * 1024 / jack_get_sample_rate(client) / 8) & (~1) ; else net_period = ceilf((float) jack_get_buffer_size (client) / (float) factor); int rx_bufsize = get_sample_size (bitdepth) * capture_channels * net_period + sizeof (jacknet_packet_header); packcache = packet_cache_new (latency + 50, rx_bufsize, mtu); /* tell the JACK server that we are ready to roll */ if (jack_activate (client)) { fprintf (stderr, "Cannot activate client"); return 1; } /* Now sleep forever... and evaluate the state_ vars */ signal( SIGTERM, sigterm_handler ); signal( SIGINT, sigterm_handler ); statecopy_connected = 2; // make it report unconnected on start. statecopy_latency = state_latency; statecopy_netxruns = state_netxruns; while ( !quit ) { #ifdef WIN32 Sleep (1000); #else sleep(1); #endif if (statecopy_connected != state_connected) { statecopy_connected = state_connected; if (statecopy_connected) { state_netxruns = 1; // We want to reset the netxrun count on each new connection printf ("Connected :-)\n"); } else printf ("Not Connected\n"); fflush(stdout); } if (statecopy_connected) { if (statecopy_netxruns != state_netxruns) { statecopy_netxruns = state_netxruns; printf ("%s: at frame %06d -> total netxruns %d (%d%%) queue time= %d\n", client_name, state_currentframe, statecopy_netxruns, 100 * statecopy_netxruns / state_currentframe, state_recv_packet_queue_time); fflush(stdout); } } else { if (statecopy_latency != state_latency) { statecopy_latency = state_latency; if (statecopy_latency > 1) printf ("current latency %d\n", statecopy_latency); fflush(stdout); } } } jack_client_close (client); packet_cache_free (packcache); exit (0); }
int netjack_startup( netjack_driver_state_t *netj ) { int first_pack_len; struct sockaddr_in address; // Now open the socket, and wait for the first packet to arrive... netj->sockfd = socket (AF_INET, SOCK_DGRAM, 0); #ifdef WIN32 if (netj->sockfd == INVALID_SOCKET) #else if (netj->sockfd == -1) #endif { jack_info ("socket error"); return -1; } address.sin_family = AF_INET; address.sin_port = htons(netj->listen_port); address.sin_addr.s_addr = htonl(INADDR_ANY); if (bind (netj->sockfd, (struct sockaddr *) &address, sizeof (address)) < 0) { jack_info("bind error"); return -1; } netj->outsockfd = socket (AF_INET, SOCK_DGRAM, 0); #ifdef WIN32 if (netj->outsockfd == INVALID_SOCKET) #else if (netj->outsockfd == -1) #endif { jack_info ("socket error"); return -1; } netj->srcaddress_valid = 0; if (netj->use_autoconfig) { jacknet_packet_header *first_packet = alloca (sizeof (jacknet_packet_header)); #ifdef WIN32 int address_size = sizeof( struct sockaddr_in ); #else socklen_t address_size = sizeof (struct sockaddr_in); #endif //jack_info ("Waiting for an incoming packet !!!"); //jack_info ("*** IMPORTANT *** Dont connect a client to jackd until the driver is attached to a clock source !!!"); while(1) { if( ! netjack_poll( netj->sockfd, 1000 ) ) { jack_info ("Waiting aborted"); return -1; } first_pack_len = recvfrom (netj->sockfd, (char *)first_packet, sizeof (jacknet_packet_header), 0, (struct sockaddr*) & netj->syncsource_address, &address_size); #ifdef WIN32 if( first_pack_len == -1 ) { first_pack_len = sizeof(jacknet_packet_header); break; } #else if (first_pack_len == sizeof (jacknet_packet_header)) break; #endif } netj->srcaddress_valid = 1; if (first_pack_len == sizeof (jacknet_packet_header)) { packet_header_ntoh (first_packet); jack_info ("AutoConfig Override !!!"); if (netj->sample_rate != first_packet->sample_rate) { jack_info ("AutoConfig Override: Master JACK sample rate = %d", first_packet->sample_rate); netj->sample_rate = first_packet->sample_rate; } if (netj->period_size != first_packet->period_size) { jack_info ("AutoConfig Override: Master JACK period size is %d", first_packet->period_size); netj->period_size = first_packet->period_size; } if (netj->capture_channels_audio != first_packet->capture_channels_audio) { jack_info ("AutoConfig Override: capture_channels_audio = %d", first_packet->capture_channels_audio); netj->capture_channels_audio = first_packet->capture_channels_audio; } if (netj->capture_channels_midi != first_packet->capture_channels_midi) { jack_info ("AutoConfig Override: capture_channels_midi = %d", first_packet->capture_channels_midi); netj->capture_channels_midi = first_packet->capture_channels_midi; } if (netj->playback_channels_audio != first_packet->playback_channels_audio) { jack_info ("AutoConfig Override: playback_channels_audio = %d", first_packet->playback_channels_audio); netj->playback_channels_audio = first_packet->playback_channels_audio; } if (netj->playback_channels_midi != first_packet->playback_channels_midi) { jack_info ("AutoConfig Override: playback_channels_midi = %d", first_packet->playback_channels_midi); netj->playback_channels_midi = first_packet->playback_channels_midi; } netj->mtu = first_packet->mtu; jack_info ("MTU is set to %d bytes", first_packet->mtu); netj->latency = first_packet->latency; } } netj->capture_channels = netj->capture_channels_audio + netj->capture_channels_midi; netj->playback_channels = netj->playback_channels_audio + netj->playback_channels_midi; if( (netj->capture_channels * netj->period_size * netj->latency * 4) > 100000000 ) { jack_error( "autoconfig requests more than 100MB packet cache... bailing out" ); exit(1); } if( netj->playback_channels > 1000 ) { jack_error( "autoconfig requests more than 1000 playback channels... bailing out" ); exit(1); } if( netj->mtu < (2*sizeof( jacknet_packet_header )) ) { jack_error( "bullshit mtu requested by autoconfig" ); exit(1); } if( netj->sample_rate == 0 ) { jack_error( "sample_rate 0 requested by autoconfig" ); exit(1); } // After possible Autoconfig: do all calculations... netj->period_usecs = (jack_time_t) floor ((((float) netj->period_size) / (float)netj->sample_rate) * 1000000.0f); if( netj->latency == 0 ) netj->deadline_offset = 50*netj->period_usecs; else netj->deadline_offset = netj->period_usecs + 10*netj->latency*netj->period_usecs/100; if( netj->bitdepth == CELT_MODE ) { // celt mode. // TODO: this is a hack. But i dont want to change the packet header. netj->resample_factor = (netj->resample_factor * netj->period_size * 1024 / netj->sample_rate / 8)&(~1); netj->resample_factor_up = (netj->resample_factor_up * netj->period_size * 1024 / netj->sample_rate / 8)&(~1); netj->net_period_down = netj->resample_factor; netj->net_period_up = netj->resample_factor_up; } else { netj->net_period_down = (float) netj->period_size / (float) netj->resample_factor; netj->net_period_up = (float) netj->period_size / (float) netj->resample_factor_up; } netj->rx_bufsize = sizeof (jacknet_packet_header) + netj->net_period_down * netj->capture_channels * get_sample_size (netj->bitdepth); netj->packcache = packet_cache_new (netj->latency + 50, netj->rx_bufsize, netj->mtu); netj->expected_framecnt_valid = 0; netj->num_lost_packets = 0; netj->next_deadline_valid = 0; netj->deadline_goodness = 0; netj->time_to_deadline = 0; // Special handling for latency=0 if( netj->latency == 0 ) netj->resync_threshold = 0; else netj->resync_threshold = MIN( 15, netj->latency-1 ); netj->running_free = 0; return 0; }