int main (int argc, char *argv[]) { ////////////////////////////////////////////// //will be removed // sample_rate=44100; sample_rate=48000; // period_size=2048; period_size=4096; // period_size=256; //period_size=128; bytes_per_sample=4; //osc const char *listenPort; //command line options parsing //http://www.gnu.org/software/libc/manual/html_node/Using-Getopt.html static struct option long_options[] = { {"help", no_argument, 0, 'h'}, {"version", no_argument, 0, 'v'}, {"loinfo", no_argument, 0, 'x'}, {"out", required_argument, 0, 'o'}, {"offset", required_argument, 0, 'f'}, {"16", no_argument, 0, 'y'}, {"max", required_argument, 0, 'm'},//max (allocate) buffer {"update", required_argument, 0, 'u'},//screen info update every nth cycle {"limit", required_argument, 0, 'l'},//test, stop after n processed {0, 0, 0, 0} }; //print program header if(argc>1 && strcmp(argv[1],"--version")) { print_header("audio_post_send"); } if (argc - optind < 1) { fprintf (stderr, "Missing arguments, see --help.\n\n"); exit(1); } int opt; //do until command line options parsed while (1) { /* getopt_long stores the option index here. */ int option_index = 0; opt = getopt_long (argc, argv, "", long_options, &option_index); /* Detect the end of the options. */ if (opt == -1) { break; } switch (opt) { case 0: /* If this option set a flag, do nothing else now. */ if (long_options[option_index].flag != 0) { break; } case 'h': print_help(); break; case 'v': print_version(); break; case 'x': check_lo_props(1); return 1; case 'o': output_port_count=atoi(optarg); if(output_port_count>max_channel_count) { fprintf(stderr,"*** limiting playback ports to %d, sry\n",max_channel_count); output_port_count=max_channel_count; } port_count=fmin(input_port_count,output_port_count); break; case 'f': channel_offset=atoi(optarg); break; case 'm': //min 1 MB max_buffer_size=fmax(1,(uint64_t)atoll(optarg)*1000*1000); break; case 'u': update_display_every_nth_cycle=fmax(1,(uint64_t)atoll(optarg)); break; case 'l': receive_max=fmax(1,(uint64_t)atoll(optarg)); test_mode=1; fprintf(stderr,"*** limiting number of messages: %" PRId64 "\n",receive_max); break; case '?': //invalid commands /* getopt_long already printed an error message. */ fprintf (stderr, "Wrong arguments, see --help.\n\n"); exit(1); break; default: break; } //end switch op }//end while(1) //remaining non optional parameters listening port, remote host, remote port if(argc-optind != 3) { fprintf (stderr, "Wrong arguments, see --help.\n\n"); exit(1); } if(check_lo_props(0)>0) { return 1; } if(have_libjack()!=0) { fprintf(stderr,"/!\\ libjack not found (JACK not installed?). this is fatal: audio_post_send needs JACK to run.\n"); //io_quit("nolibjack"); exit(1); } listenPort=argv[optind]; //tcp target remote_tcp_host=argv[optind+1]; remote_tcp_port=argv[optind+2]; loa_tcp = lo_address_new_with_proto(LO_TCP, remote_tcp_host, remote_tcp_port); //initialize time gettimeofday(&tv, NULL); tt_prev.sec=tv.tv_sec; tt_prev.frac=tv.tv_usec; //print startup info fprintf(stderr,"listening on UDP port: %s\n",listenPort); //udp/tcp use the same port for now fprintf(stderr,"started TCP server on port: %s\n",listenPort); fprintf(stderr,"channels (forward): %d\n",output_port_count); fprintf(stderr,"channel offset: %d\n",channel_offset); fprintf(stderr, "TCP target: %s:%s\n",remote_tcp_host,remote_tcp_port); fprintf(stderr, "period size (TCP forward): %d samples\n",period_size); fprintf(stderr, "delay between TCP sends: %d ms\n",delay_between_tcp_sends); fprintf(stderr, "delay between TCP retries on broken connection: %d ms\n",delay_between_tcp_retries); //ringbuffer size bytes uint64_t rb_size; //use as given via param --max or: if(max_buffer_size==0) { //default //10 MB . . max_buffer_size=10000000; } // rb_size=max_buffer_size; fprintf(stderr,"allocated buffer size: %" PRId64 " bytes (%.2f MB)\n",max_buffer_size,(float)max_buffer_size/1000/1000); //==================================== //main ringbuffer osc blobs -> jack output rb = rb_new (rb_size); //helper ringbuffer: used when remote period size < local period size rb_helper = rb_new (rb_size); if(rb==NULL) { fprintf(stderr,"could not create a ringbuffer with that size.\n"); fprintf(stderr,"try --max <smaller size>.\n"); exit(1); } /* install a signal handler to properly quits jack client */ #ifndef _WIN signal(SIGQUIT, signal_handler); signal(SIGHUP, signal_handler); #endif signal(SIGTERM, signal_handler); signal(SIGINT, signal_handler); //add osc hooks & start UDP server registerOSCMessagePatterns(listenPort); lo_server_thread_start(lo_st); //start TCP server, for forwarding to final receiver lo_st_tcp = lo_server_thread_new_with_proto(listenPort, LO_TCP, error); lo_server_thread_start(lo_st_tcp); fflush(stderr); /* keep running until the Ctrl+C */ while(1) { //possibly clean shutdown without any glitches if(shutdown_in_progress==1) { signal_handler(42); } //if tcp message could not be sent if(process()<0) { //wait x and update info int i; for(i=0;i<delay_between_tcp_retries;i++) { usleep(1000); print_info(); } } else { //wait y and update info int i; for(i=0;i<delay_between_tcp_sends;i++) { usleep(1000); print_info(); } } } exit (0); }
//================================================================ int main(int argc, char *argv[]) { //jack const char **ports; //jack_options_t options = JackNullOption; jack_status_t status; //options struct was here if(argc-optind<1) { print_header("jack_audio_receive"); fprintf(stderr, "Missing arguments, see --help.\n\n"); exit(1); } int opt; //do until command line options parsed while(1) { /* getopt_long stores the option index here. */ int option_index=0; opt=getopt_long(argc, argv, "", long_options, &option_index); /* Detect the end of the options. */ if(opt==-1) { break; } switch(opt) { case 0: /* If this option set a flag, do nothing else now. */ if(long_options[option_index].flag!=0) { break; } case 'h': print_header("jack_audio_receive"); print_help(); break; case 'v': print_version(); break; case 'x': print_header("jack_audio_receive"); check_lo_props(1); return 1; case 'o': output_port_count=atoi(optarg); if(output_port_count>max_channel_count) { output_port_count=max_channel_count; } port_count=fmin(input_port_count,output_port_count); break; case 'f': channel_offset=atoi(optarg); break; case 'y': bytes_per_sample=2; break; case 'n': client_name=optarg; break; case 's': server_name=optarg; jack_opts |= JackServerName; break; case 'b': pre_buffer_size=fmax(1,(uint64_t)atoll(optarg)); break; case 'm': max_buffer_size=fmax(1,(uint64_t)atoll(optarg)); break; case 'u': update_display_every_nth_cycle=fmax(1,(uint64_t)atoll(optarg)); break; case 'l': receive_max=fmax(1,(uint64_t)atoll(optarg)); test_mode=1; break; case 'a': io_host=optarg; break; case 'c': io_port=optarg; break; case 't': use_tcp=1; remote_tcp_server_port=optarg; break; case '?': //invalid commands /* getopt_long already printed an error message. */ print_header("jack_audio_receive"); fprintf(stderr, "Wrong arguments, see --help.\n\n"); exit(1); break; default: break; } //end switch op }//end while(1) //remaining non optional parameters listening port if(argc-optind!=1) { print_header("jack_audio_receive"); fprintf(stderr, "Wrong arguments, see --help.\n\n"); exit(1); } localPort=argv[optind]; //for commuication with a gui / other controller / visualizer loio=lo_address_new_with_proto(LO_UDP, io_host, io_port); //if was set to use random port if(atoi(localPort)==0) { //for lo_server_thread_new_with_proto localPort=NULL; } //add osc hooks & start osc server early (~right after cmdline parsing) registerOSCMessagePatterns(localPort); lo_server_thread_start(lo_st); //read back port (in case of random) //could use //int lo_server_thread_get_port(lo_server_thread st) const char *osc_server_url=lo_server_get_url(lo_server_thread_get_server(lo_st)); localPort=lo_url_get_port(osc_server_url); //int lport=lo_server_thread_get_port(lo_st); //notify osc gui if(io_()) { lo_message msgio=lo_message_new(); lo_message_add_float(msgio, version); lo_message_add_float(msgio, format_version); lo_send_message(loio, "/startup", msgio); lo_message_free(msgio); } if(check_lo_props(0)>0) { return 1; } if(use_tcp==1) { lo_proto=LO_TCP; } if(shutup==0) { print_header("jack_audio_receive"); if(output_port_count>max_channel_count) { fprintf(stderr,"/!\\ limiting playback ports to %d, sry\n",max_channel_count); } if(test_mode==1) { fprintf(stderr,"/!\\ limiting number of messages: %" PRId64 "\n",receive_max); } } //check for default jack server env var char *evar=getenv("JACK_DEFAULT_SERVER"); if(evar==NULL || strlen(evar)<1) { #ifndef _WIN unsetenv("JACK_DEFAULT_SERVER"); #endif } else if(server_name==NULL) { //use env var if no server was given with --sname server_name=evar; } if(server_name==NULL || strlen(server_name)<=0) { server_name="default"; } if(client_name==NULL) { client_name="receive"; } if(have_libjack()!=0) { fprintf(stderr,"/!\\ libjack not found (JACK not installed?). this is fatal: jack_audio_receive needs JACK to run.\n"); io_quit("nolibjack"); exit(1); } //initialize time gettimeofday(&tv, NULL); tt_prev.sec=tv.tv_sec; tt_prev.frac=tv.tv_usec; //create an array of input ports ioPortArray=(jack_port_t**) malloc(output_port_count * sizeof(jack_port_t*)); //open a client connection to the JACK server client=jack_client_open(client_name, jack_opts, &status, server_name); if(client==NULL) { fprintf(stderr,"jack_client_open() failed, status = 0x%2.0x\n", status); if(status & JackServerFailed) { fprintf(stderr,"Unable to connect to JACK server.\n"); io_quit("nojack"); } exit(1); } if(use_tcp==1) { if(shutup==0) { fprintf(stderr,"receiving on TCP port: %s\n",localPort); } } else { if(shutup==0) { fprintf(stderr,"receiving on UDP port: %s\n",localPort); } } client_name=jack_get_client_name(client); if(shutup==0) { fprintf(stderr,"started JACK client '%s' on server '%s'\n",client_name,server_name); if(status & JackNameNotUnique) { fprintf(stderr, "/!\\ name '%s' was automatically assigned\n", client_name); } } if(status & JackNameNotUnique) { io_simple("/client_name_changed"); } //print startup info read_jack_properties(); if(shutup==0) { print_common_jack_properties(); fprintf(stderr,"channels (playback): %d\n",output_port_count); fprintf(stderr,"channel offset: %d\n",channel_offset); print_bytes_per_sample(); fprintf(stderr,"multi-channel period size: %d bytes\n", output_port_count*period_size*bytes_per_sample ); char *strat="fill with zero (silence)"; if(zero_on_underflow==0) { strat="re-use last available period"; } fprintf(stderr,"underflow strategy: %s\n",strat); if(rebuffer_on_restart==1) { fprintf(stderr,"rebuffer on sender restart: yes\n"); } else { fprintf(stderr,"rebuffer on sender restart: no\n"); } if(rebuffer_on_underflow==1) { fprintf(stderr,"rebuffer on underflow: yes\n"); } else { fprintf(stderr,"rebuffer on underflow: no\n"); } if(allow_remote_buffer_control==1) { fprintf(stderr,"allow external buffer control: yes\n"); } else { fprintf(stderr,"allow external buffer control: no\n"); } if(close_on_incomp==1) { fprintf(stderr,"shutdown receiver when incompatible data received: yes\n"); } else { fprintf(stderr,"shutdown receiver when incompatible data received: no\n"); } }//end cond. print char buf[64]; format_seconds(buf,(float)pre_buffer_size*period_size/(float)sample_rate); uint64_t rb_size_pre=pre_buffer_size*output_port_count*period_size*bytes_per_sample; if(shutup==0) { fprintf(stderr,"initial buffer size: %" PRId64 " mc periods (%s, %" PRId64 " bytes, %.2f MB)\n", pre_buffer_size, buf, rb_size_pre, (float)rb_size_pre/1000/1000 ); } buf[0]='\0'; //ringbuffer size bytes uint64_t rb_size; //ringbuffer mc periods int max_buffer_mc_periods; //max given as param (user knows best. if pre=max, overflows are likely) if(max_buffer_size>0) { max_buffer_mc_periods=fmax(pre_buffer_size,max_buffer_size); rb_size=max_buffer_mc_periods *output_port_count*period_size*bytes_per_sample; } else //"auto" { //make max buffer 0.5 seconds larger than pre buffer max_buffer_mc_periods=pre_buffer_size+ceil(0.5*(float)sample_rate/period_size); rb_size=max_buffer_mc_periods *output_port_count*period_size*bytes_per_sample; } max_buffer_size=max_buffer_mc_periods; format_seconds(buf,(float)max_buffer_mc_periods*period_size/sample_rate); if(shutup==0) { fprintf(stderr,"allocated buffer size: %" PRId64 " mc periods (%s, %" PRId64 " bytes, %.2f MB)\n", max_buffer_size, buf, rb_size, (float)rb_size/1000/1000 ); } buf[0]='\0'; io_dump_config(); //==================================== //main ringbuffer osc blobs -> jack output rb=jack_ringbuffer_create(rb_size); //helper ringbuffer: used when remote period size < local period size rb_helper=jack_ringbuffer_create(rb_size); if(rb==NULL) { fprintf(stderr,"could not create a ringbuffer with that size.\n"); fprintf(stderr,"try --max <smaller size>.\n"); io_quit("ringbuffer_too_large"); exit(1); } //JACK will call process() for every cycle (given by JACK) //NULL could be config/data struct jack_set_process_callback(client, process, NULL); jack_set_xrun_callback(client, xrun_handler, NULL); //register hook to know when JACK shuts down or the connection //was lost (i.e. client zombified) jack_on_shutdown(client, jack_shutdown_handler, 0); // Register each output port int port; for(port=0; port<output_port_count; port ++) { // Create port name char* portName; if(asprintf(&portName, "output_%d", (port+1)) < 0) { fprintf(stderr,"Could not create portname for port %d", port); io_quit("port_error"); exit(1); } // Register the output port ioPortArray[port]=jack_port_register(client, portName, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); if(ioPortArray[port]==NULL) { fprintf(stderr,"Could not create output port %d\n", (port+1)); io_quit("port_error"); exit(1); } } /* Tell the JACK server that we are ready to roll. Our * process() callback will start running now. */ if(jack_activate(client)) { fprintf(stderr, "cannot activate client"); io_quit("cannot_activate_client"); exit(1); } /* Connect the ports. You can't do this before the client is * activated, because we can't make connections to clients * that aren't running. Note the confusing (but necessary) * orientation of the driver backend ports: playback ports are * "input" to the backend, and capture ports are "output" from * it. */ //prevent to get physical midi ports const char* pat="audio"; ports=jack_get_ports(client, NULL, pat, JackPortIsPhysical|JackPortIsInput); if(ports==NULL) { if(shutup==0) { fprintf(stderr,"no physical playback ports\n"); } //exit(1); } if(autoconnect==1) { fprintf(stderr, "\n"); int j=0; int i; for(i=0;i<output_port_count;i++) { if(ports[i]!=NULL && ioPortArray[j]!=NULL && jack_port_name(ioPortArray[j])!=NULL) { if(!jack_connect(client, jack_port_name(ioPortArray[j]), ports[i])) { if(shutup==0) { fprintf(stderr, "autoconnect: %s -> %s\n", jack_port_name(ioPortArray[j]),ports[i] ); } io_simple_string_double("/autoconnect",jack_port_name(ioPortArray[j]),ports[i]); j++; } else { if(shutup==0) { fprintf(stderr, "autoconnect: failed: %s -> %s\n", jack_port_name(ioPortArray[j]),ports[i] ); } } } else { //no more playback ports break; } }//end for all output ports if(shutup==0) { fprintf(stderr, "\n"); } } free(ports); fflush(stderr); /* install a signal handler to properly quits jack client */ #ifndef _WIN signal(SIGQUIT, signal_handler); signal(SIGHUP, signal_handler); #endif signal(SIGTERM, signal_handler); signal(SIGINT, signal_handler); if(use_tcp==1) { //10 MB max int desired_max_tcp_size=10000000; lo_server s=lo_server_thread_get_server(lo_st); int ret_set_size=lo_server_max_msg_size(s, desired_max_tcp_size); if(shutup==0) { printf("set tcp max size return: %d\n",ret_set_size); io_simple("/tcp_max_size_xxxx"); } } not_yet_ready=0; io_simple("/start_main_loop"); //run possibly forever until not interrupted by any means while(1) { //possibly clean shutdown without any glitches if(shutdown_in_progress==1) { signal_handler(42); } #ifdef WIN_ Sleep(1000); #else sleep(1); #endif } exit(0); }//end main