예제 #1
0
lo_address lo_address_new_from_url(const char *url)
{
    lo_address a;
    int protocol;
    char *host, *port, *proto;

    if (!url || !*url) {
        return NULL;
    }

    protocol = lo_url_get_protocol_id(url);
    if (protocol == LO_UDP || protocol == LO_TCP) {
        host = lo_url_get_hostname(url);
        port = lo_url_get_port(url);
        a = lo_address_new_with_proto(protocol, host, port);
        if(host) free(host);
        if(port) free(port);
#ifndef WIN32
    } else if (protocol == LO_UNIX) {
        port = lo_url_get_path(url);
        a = lo_address_new_with_proto(LO_UNIX, NULL, port);
        if(port) free(port);
#endif
    } else {
        proto = lo_url_get_protocol(url);
        fprintf(stderr, PACKAGE_NAME ": protocol '%s' not supported by this "
                "version\n", proto);
        if(proto) free(proto);

        return NULL;
    }

    return a;
}
예제 #2
0
int main(int argc, const char *argv[])
{
    printf("Usage: lo_benchmk_client [n_addrs]\n"
           "  n_addrs is number of paths, default is 20\n"
           "  end n_addrs with t for TCP, e.g. 20t\n");
    if (argc == 2) {
        n_addrs = atoi(argv[1]);
        printf("n_addrs is %d\n", n_addrs);
        use_tcp = (strchr(argv[1], 't') != NULL);
    }

    // create address for server
    server = lo_address_new_with_proto(use_tcp ? LO_TCP : LO_UDP,
                                       "localhost", "8000");

    // create client
    lo_server client = lo_server_new_with_proto("8001",
                               use_tcp ? LO_TCP : LO_UDP, NULL);

    // make addresses and register them with server
    addresses = (char **) malloc(sizeof(char **) * n_addrs);
    for (int i = 0; i < n_addrs; i++) {
        char path[100];
        sprintf(path, "/benchmark/%d", i);
        addresses[i] = (char *) malloc(strlen(path));
        strcpy(addresses[i], path);
        lo_server_add_method(client, path, "i", &handler, NULL);
    }

    lo_send(server, addresses[msg_count % n_addrs], "i", msg_count);
    while (1) {
        lo_server_recv_noblock(client, 0);
    }
}
예제 #3
0
//ctrl+c etc
static void signal_handler(int sig)
{
	shutdown_in_progress=1;
	process_enabled=0;

	fprintf(stderr,"\nterminate signal %d received.\n",sig);

	if(close_on_incomp==0)
	{
		fprintf(stderr,"telling sender to pause.\n");

		//lo_address loa = lo_address_new(sender_host,sender_port);
		lo_address loa = lo_address_new_with_proto(lo_proto, sender_host,sender_port);

		lo_message msg=lo_message_new();
		lo_send_message (loa, "/pause", msg);
		lo_message_free(msg);
	}

	usleep(1000);

	fprintf(stderr,"cleaning up...");

	lo_server_thread_free(lo_st);
	rb_free(rb);
	rb_free(rb_helper);

	fprintf(stderr,"done.\n");
	
	fflush(stderr);

	exit(0);
}
예제 #4
0
//================================================================
void osc_error_handler(int num, const char *msg, const char *path)
{
	if(close_on_incomp==1 && shutdown_in_progress==0)
	{
		fprintf(stderr,"/!\\ liblo server error %d: %s %s\n", num, path, msg);

		fprintf(stderr,"telling sender to pause.\n");

		//lo_address loa=lo_address_new(sender_host,sender_port);
		lo_address loa=lo_address_new_with_proto(lo_proto, sender_host,sender_port);

		lo_message msg=lo_message_new();
		lo_send_message(loa, "/pause", msg);
		lo_message_free(msg);

		io_quit("incompatible_jack_settings");

		fprintf(stderr,"cleaning up...");

		jack_client_close(client);
		//lo_server_thread_free(lo_st);
		jack_ringbuffer_free(rb);
		jack_ringbuffer_free(rb_helper);
		fprintf(stderr," done.\n");

		exit(1);
	}
	else if(shutdown_in_progress==0)
	{
		fprintf(stderr,"\r/!\\ liblo server error %d: %s %s\n", num, path, msg);
		//should be a param
	}
}//end osc_error_handler
예제 #5
0
파일: Osc.cpp 프로젝트: EQ4/MRP
int OscTransmitter::addAddress(const char * host, const char * port, int proto)
{
	lo_address addr = lo_address_new_with_proto(proto, host, port);
	
	if(addr == 0)
		return -1;
	addresses_.push_back(addr);
	
	return (int)addresses_.size() - 1;
}
예제 #6
0
int main(int argc, const char * argv[])
{
    int tcpflag = 1;
    printf("Usage: lo_bndlsend [u] (u means use UDP)\n");
    if (argc == 2) {
        tcpflag = (strchr(argv[1], 'u') == NULL);
    }
    printf("tcpflag %d\n", tcpflag);
    sleep(2); // allow some time for server to start

    client = lo_address_new_with_proto(tcpflag ? LO_TCP : LO_UDP,
                                       "localhost", "8100");
    printf("client: %p\n", client);
    char s[128];
    
    lo_timetag now;
    lo_timetag_now(&now);
    lo_timetag timetag;
    
    for (int i = 9; i >= 5; i--) {
        // make the bundle
        timetag_add(&timetag, now, 2 + i * 0.1);
        lo_bundle bndl = lo_bundle_new(timetag);

        // make first message
        sprintf(s, "an arbitrary string at 2.%d", i);
        lo_message msg1 = make_message(1000 + i, s);
        // add the message to the bundle
        lo_bundle_add_message(bndl, "/xyz/msg1", msg1);

        // make second message
        sprintf(s, "another arbitrary string at 2.%d", i);
        lo_message msg2 = make_message(2000 + i, s);
        // add the message to the bundle
        lo_bundle_add_message(bndl, "/abcdefg/msg2", msg2);

        // send it
        lo_send_bundle(client, bndl);
    }

    send_nested(now, 3.0, 0.0, 3000);
    send_nested(now, 3.1, 3.2, 4000);
    sleep(1); // make sure messages go out
    lo_address_free(client);
    sleep(1); // time to clean up socketsa
    printf("OSCSEND DONE\n");
    return 0;
}
예제 #7
0
//================================================================
//ctrl+c etc
static void signal_handler(int sig)
{
	fprintf(stderr,"\nterminate signal %d received.\n",sig);

	io_quit("terminated");

	shutdown_in_progress=1;
	process_enabled=0;

	if(close_on_incomp==0)
	{
		fprintf(stderr,"telling sender to pause.\n");

		//lo_address loa=lo_address_new(sender_host,sender_port);
		lo_address loa=lo_address_new_with_proto(lo_proto, sender_host,sender_port);

		lo_message msg=lo_message_new();
		lo_send_message(loa, "/pause", msg);
		lo_message_free(msg);
	}

	fprintf(stderr,"cleaning up...");

	jack_deactivate(client);

	int index=0;
	while(ioPortArray[index]!=NULL && index<input_port_count)
	{
		jack_port_unregister(client,ioPortArray[index]);
		index++;
	}

	jack_client_close(client);
//      lo_server_thread_free(lo_st);
	jack_ringbuffer_free(rb);
	jack_ringbuffer_free(rb_helper);

	fprintf(stderr," done.\n");

	exit(0);
}//end signal_handler
예제 #8
0
Client::Client( const std::string &host, int port, Proto proto /* = PROTO_UDP */ )
{
	std::string portStr = boost::lexical_cast< std::string >( port );
	mAddress = lo_address_new_with_proto( proto, host.c_str(), portStr.c_str() );
}
예제 #9
0
lo_address lo_address_new(const char *host, const char *port)
{
    return lo_address_new_with_proto(LO_UDP, host ,port);
}
예제 #10
0
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);
}
예제 #11
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
예제 #12
0
//================================================================
// /audio
//handler for audio messages
int osc_audio_handler(const char *path, const char *types, lo_arg **argv, int argc,
	void *data, void *user_data)
{
	if(shutdown_in_progress==1 || not_yet_ready==1)
	{
		return 0;
	}

	//init to 0, increment before use
	msg_received_counter++;

	gettimeofday(&tv, NULL);

	//first blob is at data_offset+1 (one-based)
	int data_offset=4;

	//ignore first n channels/blobs
	data_offset+=channel_offset;

	message_number_prev=message_number;

	//the messages are numbered sequentially. first msg is numberd 1
	message_number=argv[0]->h;

	if(message_number_prev<message_number-1)
	{
		fprintf(stderr,"\ngap in message sequence! possibly lost %" PRId64" message(s) on the way.\n"
			,message_number-message_number_prev-1);
		fflush(stderr);
	}

	//total args count minus metadata args count = number of blobs
	input_port_count=argc-data_offset;

	//only process useful number of channels
	port_count=fmin(input_port_count,output_port_count);

	if(port_count < 1)
	{
		fprintf(stderr,"channel offset %d >= available input channels %d! (nothing to receive). shutting down...\n"
			,channel_offset
			,channel_offset+input_port_count);
		fflush(stderr);
		shutdown_in_progress=1;
		return 0;
	}

	//check sample rate and period size if sender (re)started or values not yet initialized (=no /offer received)
	if(message_number_prev>message_number || message_number==1 || remote_sample_rate==0 || remote_period_size==0 )
	{
		lo_address loa;

		if(use_tcp==1)
		{
			lo_address loa_=lo_message_get_source(data);
			loa=lo_address_new_with_proto(lo_proto,lo_address_get_hostname(loa_),remote_tcp_server_port);
		}
		else
		{
			loa=lo_message_get_source(data);
		}

		strcpy(sender_host,lo_address_get_hostname(loa));
		strcpy(sender_port,lo_address_get_port(loa));

		//option --rebuff
		if(rebuffer_on_restart==1)
		{
			uint64_t can_read_count=jack_ringbuffer_read_space(rb);
			pre_buffer_counter=fmax(0,(float)can_read_count/(float)bytes_per_sample/(float)period_size/(float)port_count);
			//start buffering
			process_enabled=0;
		}
		else
		{
			pre_buffer_counter=0;
		}

		remote_sample_rate=argv[3]->i;

		if(sample_rate!=remote_sample_rate)
		{
			if(close_on_incomp==0)
			{
				//sending deny will tell sender to stop/quit
				lo_message msg=lo_message_new();


				lo_message_add_float(msg,format_version);
				lo_message_add_int32(msg,sample_rate);
// /deny as reply to /audio should be the same as for /deny as reply to /offer
//will need change of /audio (add format, bytes_per_sample)
///////
				lo_message_add_int32(msg,99);

				lo_send_message(loa, "/deny", msg);
				lo_message_free(msg);

				fprintf(stderr,"\ndenying transmission from %s:%s\n(incompatible JACK settings on sender: SR: %d). telling sender to stop.\n",
					lo_address_get_hostname(loa),lo_address_get_port(loa),remote_sample_rate
				);
				fflush(stderr);

				message_number=0;
				message_number_prev=0;
				remote_sample_rate=0;
				remote_period_size=0;
				//pre_buffer_counter=0;
			}
			else
			{
				lo_address loa;

				if(use_tcp==1)
				{
					lo_address loa_=lo_message_get_source(data);
					loa=lo_address_new_with_proto(lo_proto,lo_address_get_hostname(loa_),remote_tcp_server_port);
				}
				else
				{
					loa=lo_message_get_source(data);
				}

				fprintf(stderr,"\ndenying transmission from %s:%s\nincompatible JACK settings on sender: SR: %d.\nshutting down (see option --close)...\n",
					lo_address_get_hostname(loa),lo_address_get_port(loa),remote_sample_rate
				);
				fflush(stderr);

				shutdown_in_progress=1;
				return 0;
			}
		}

		remote_period_size=lo_blob_datasize((lo_blob)argv[0+data_offset])/bytes_per_sample;

		if(shutup==0 && quiet==0)
		{
			fprintf(stderr,"\nsender was (re)started. ");

			lo_address loa=lo_message_get_source(data);
			fprintf(stderr,"receiving from %s:%s\n",lo_address_get_hostname(loa),lo_address_get_port(loa));
		}

		io_simple("/sender_restarted");

		if(shutup==0 && quiet==0)
		{
			if(remote_period_size!=period_size)
			{
				fprintf(stderr,"sender period size: %d samples (%.3f x local)\n\n",remote_period_size,(float)remote_period_size/period_size);
			}
			else
			{
				fprintf(stderr,"equal sender and receiver period size\n\n");
			}

			fflush(stderr);
		}

	}//end if "no-offer init" was needed

	remote_xrun_counter=argv[1]->h;

	lo_timetag tt=argv[2]->t;

	double msg_time=tt.sec+(double)tt.frac/1000000;
	double msg_time_prev=tt_prev.sec+(double)tt_prev.frac/1000000;
//unused for now
//	double time_now=tv.tv_sec+(double)tv.tv_usec/1000000;

	time_interval=msg_time-msg_time_prev;

	time_interval_sum+=time_interval;
	time_interval_avg=(float)time_interval_sum/msg_received_counter;

	tt_prev=tt;

	//reset avg calc, check and reset after use
	if(msg_received_counter>=avg_calc_interval)
	{
		msg_received_counter=0;
		time_interval_sum=0;
	}

	if(pre_buffer_counter>=pre_buffer_size && process_enabled==0)
	{
		//if buffer filled, start to output audio in process()
		process_enabled=1;
	}

	int mc_period_bytes=period_size*bytes_per_sample*port_count;

	//check if a whole mc period can be written to the ringbuffer
	uint64_t can_write_count=jack_ringbuffer_write_space(rb);
	if(can_write_count < mc_period_bytes)
	{
			buffer_overflow_counter++;
			/////////////////
			if(shutup==0 && quiet==0)
			{
				fprintf(stderr,"\rBUFFER OVERFLOW! this is bad -----%s","\033[0J");
			}
			return 0;
	}

	//========================================
	//new: support different period sizes on sender / receiver (still need same SR)
	//this needs more tests and optimization
	if(period_size==remote_period_size)
	{
		int i;
		//don't read more channels than we have outputs
		for(i=0;i < port_count;i++)
		{
			//get blob (=one period of one channel)
			unsigned char *data=lo_blob_dataptr((lo_blob)argv[i+data_offset]);
			//fprintf(stderr,"size %d\n",lo_blob_datasize((lo_blob)argv[i+data_offset]));

			//write to ringbuffer
			//==========================================
			//int cnt=
			jack_ringbuffer_write(rb, (void *) data, 
				period_size*bytes_per_sample);
		}
		pre_buffer_counter++;
	}
	else if(period_size>remote_period_size)
	{
		int i;
		//don't read more channels than we have outputs
		for(i=0;i < port_count;i++)
		{
			//get blob (=one period of one channel)
			unsigned char *data=lo_blob_dataptr((lo_blob)argv[i+data_offset]);
			//fprintf(stderr,"size %d\n",lo_blob_datasize((lo_blob)argv[i+data_offset]));

			//write to temporary ringbuffer until there is enough data
			//==========================================
			//int cnt=
			jack_ringbuffer_write(rb_helper, (void *) data, 
				remote_period_size*bytes_per_sample);
		}

		//if enough data collected for one larger multichannel period

		while(jack_ringbuffer_read_space(rb_helper)	>=mc_period_bytes
		&& jack_ringbuffer_write_space(rb)		>=mc_period_bytes)
		{
			//transfer from helper to main ringbuffer
			unsigned char* data;
			data=malloc(				mc_period_bytes);
			//store orig pointer
			unsigned char* orig_data=data;
			jack_ringbuffer_read(rb_helper,data,	mc_period_bytes);

			for(i=0;i < port_count;i++)
			{
				int k;
				for(k=0;k<(period_size/remote_period_size);k++)
				{
					//reset pointer
					data=orig_data;
					//position in helper buffer for next sample for main buffer
					data+=	k*remote_period_size*bytes_per_sample*port_count
							+ i*remote_period_size*bytes_per_sample;

					//write one channel snipped (remote_period_size) to main buffer
					//int w=
					jack_ringbuffer_write(rb,(void *)data,remote_period_size*bytes_per_sample);
				}
			}
			data=orig_data;
			free(data);

			pre_buffer_counter++;
		}
	}
	else if(period_size<remote_period_size)
	{
		int k;
		for(k=0;k<(remote_period_size/period_size);k++)
		{

			int i;
			//don't read more channels than we have outputs
			for(i=0;i < port_count;i++)
			{
				//get blob (=one period of one channel)
				unsigned char *data=lo_blob_dataptr((lo_blob)argv[i+data_offset]);
				//fprintf(stderr,"size %d\n",lo_blob_datasize((lo_blob)argv[i+data_offset]));

				//write to ringbuffer
				//==========================================
				data+=k*period_size*bytes_per_sample;

				//int cnt=
				jack_ringbuffer_write(rb, (void *) data, 
					period_size*bytes_per_sample);
			}
			pre_buffer_counter++;
		}
	}

	return 0;
}//end osc_audio_handler
예제 #13
0
//================================================================
// /offer
//sender offers audio
int osc_offer_handler(const char *path, const char *types, lo_arg **argv, int argc,
	void *data, void *user_data)
{
	if(shutdown_in_progress==1 || not_yet_ready==1)
	{
		return 0;
	}

	float offered_format_version=argv[0]->f;

	int offered_sample_rate=argv[1]->i;
	int offered_bytes_per_sample=argv[2]->i;
	int offered_period_size=argv[3]->i;

//unused here
//	int offered_channel_count=argv[4]->i;
//	float offered_data_rate=argv[5]->f;
//	uint64_t request_counter=argv[6]->h;

	lo_message msg=lo_message_new();

	//send back to host that offered audio
	//lo_address loa=lo_message_get_source(data);

	lo_address loa;

	if(use_tcp==1)
	{
		lo_address loa_=lo_message_get_source(data);
		loa=lo_address_new_with_proto(lo_proto,lo_address_get_hostname(loa_),remote_tcp_server_port);
	}
	else
	{
		loa=lo_message_get_source(data);
	}

	//check if compatible with sender
	//could check more stuff (channel count, data rate, sender host/port, ...)
	if(
		offered_sample_rate==sample_rate
		&& offered_bytes_per_sample==bytes_per_sample
		&& offered_format_version==format_version

		//new: support non-matching period sizes
		//&& offered_period_size==period_size
	)
	{
		remote_sample_rate=sample_rate;
		remote_period_size=offered_period_size;

		strcpy(sender_host,lo_address_get_hostname(loa));
		strcpy(sender_port,lo_address_get_port(loa));

		//sending accept will tell the sender to start transmission
		lo_send_message(loa, "/accept", msg);

		/*
		fprintf(stderr,"\nreceiving from %s:%s",
			lo_address_get_hostname(loa),lo_address_get_port(loa));
		*/

		starting_transmission=1;
	}
	//data is incompatible, handle depending on --close
	else if(close_on_incomp==0)
	{
		//sending deny will tell sender to stop/quit
		lo_message_add_float(msg,format_version);
		lo_message_add_int32(msg,sample_rate);
		lo_message_add_int32(msg,bytes_per_sample);
		lo_send_message(loa, "/deny", msg);

		fprintf(stderr,"\ndenying transmission from %s:%s\nincompatible JACK settings or format version on sender:\nformat version: %.2f\nSR: %d\nbytes per sample: %d\ntelling sender to stop.\n",
			lo_address_get_hostname(loa),lo_address_get_port(loa),offered_format_version,offered_sample_rate,offered_bytes_per_sample
		);

		//shutting down is not a good strategy for the receiver in this case
		//shutdown_in_progress=1;
	}
	else
	{
		fprintf(stderr,"\ndenying transmission from %s:%s\nincompatible JACK settings or format version on sender\nformat version: %.2f\nSR: %d\nshutting down... (see option --close)\n",
			lo_address_get_hostname(loa),lo_address_get_port(loa),offered_format_version,offered_sample_rate
		);

		shutdown_in_progress=1;
	}

	lo_message_free(msg);

	fflush(stderr);

	return 0;
} //end osc_offer_handler
예제 #14
0
int main()
{
    lo_blob btest = lo_blob_new(sizeof(testdata), testdata);
    lo_server_thread st, sta, stb;
    lo_server s = lo_server_new(NULL, error);
    lo_bundle b;
    lo_message m1, m2;
    char *server_url, *path, *protocol, *host, *port;
    const char *host2, *port2;
    lo_address a;
    uint8_t midi_data[4] = {0xff, 0xf7, 0xAA, 0x00};
    union end_test32 et32;
    union end_test64 et64;
    lo_timetag tt = {0x1, 0x80000000}, sched;
    int count;
    int proto;
    char cmd[256];

    test_deserialise();

    sta = lo_server_thread_new("7591", error);
    stb = lo_server_thread_new("7591", rep_error);
    if (stb) {
	fprintf(stderr, "FAILED: create bad server thread object!\n");
	exit(1);
    }
    lo_server_thread_free(sta);

    /* leak check */
    st = lo_server_thread_new(NULL, error);
    lo_server_thread_start(st);
#ifdef WIN32
    Sleep(4);
#else
    usleep(4000);
#endif
    lo_server_thread_stop(st);
    lo_server_thread_free(st);
    st = lo_server_thread_new(NULL, error);
    lo_server_thread_start(st);
    lo_server_thread_stop(st);
    lo_server_thread_free(st);
    st = lo_server_thread_new(NULL, error);
    lo_server_thread_free(st);
    st = lo_server_thread_new(NULL, error);
    lo_server_thread_free(st);
    st = lo_server_thread_new(NULL, error);

    a = lo_address_new_from_url("osc://localhost/");
    TEST(a != NULL);
    lo_address_free(a);

    a = lo_address_new_from_url("osc.://localhost/");
    TEST(a == NULL);


    atexit(exitcheck);

    printf("type tests\n");
    TEST(sizeof(float) == sizeof(int32_t));
    TEST(sizeof(double) == sizeof(int64_t));

    et32.i = 0x23242526U;
    et32.i = lo_htoo32(et32.i);
    if (et32.c[0] != 0x23 || et32.c[1] != 0x24 || et32.c[2] != 0x25 ||
	et32.c[3] != 0x26) {
	fprintf(stderr, "failed 32bit endian conversion test\n");
	fprintf(stderr, "0x23242526 -> %X\n", et32.i);
	exit(1);
    } else {
	printf("passed 32bit endian conversion test\n");
    }

    et64.i = 0x232425262728292AULL;
    et64.i = lo_htoo64(et64.i);
    if (et64.c[0] != 0x23 || et64.c[1] != 0x24 || et64.c[2] != 0x25 ||
	et64.c[3] != 0x26 || et64.c[4] != 0x27 || et64.c[5] != 0x28 ||
	et64.c[6] != 0x29 || et64.c[7] != 0x2A) {
	fprintf(stderr, "failed 64bit endian conversion\n");
	fprintf(stderr, "0x232425262728292A -> %llX\n", (long long unsigned int)et64.i);
	exit(1);
    } else {
	printf("passed 64bit endian conversion\n");
    }
    printf("\n");

    /* OSC URL tests */
    path = lo_url_get_path("osc.udp://localhost:9999/a/path/is/here");
    if (strcmp(path, "/a/path/is/here")) {
	printf("failed lo_url_get_path() test1\n");
	printf("'%s' != '/a/path/is/here'\n", path);
	exit(1);
    } else {
	printf("passed lo_url_get_path() test1\n");
    }
    free(path);

    protocol = lo_url_get_protocol("osc.udp://localhost:9999/a/path/is/here");
    if (strcmp(protocol, "udp")) {
	printf("failed lo_url_get_protocol() test1\n");
	printf("'%s' != 'udp'\n", protocol);
	exit(1);
    } else {
	printf("passed lo_url_get_protocol() test1\n");
    }
    free(protocol);

    protocol = lo_url_get_protocol("osc.tcp://localhost:9999/a/path/is/here");
    if (strcmp(protocol, "tcp")) {
	printf("failed lo_url_get_protocol() test2\n");
	printf("'%s' != 'tcp'\n", protocol);
	exit(1);
    } else {
	printf("passed lo_url_get_protocol() test2\n");
    }
    free(protocol);
    
    protocol = lo_url_get_protocol("osc.udp://[::ffff:localhost]:9999/a/path/is/here");
    if (strcmp(protocol, "udp")) {
	printf("failed lo_url_get_protocol() test1 (IPv6)\n");
	printf("'%s' != 'udp'\n", protocol);
	exit(1);
    } else {
	printf("passed lo_url_get_protocol() test1 (IPv6)\n");
    }
    free(protocol);

    proto = lo_url_get_protocol_id("osc.udp://localhost:9999/a/path/is/here");
    if (proto != LO_UDP) {
	printf("failed lo_url_get_protocol_id() test1\n");
	printf("'%d' != LO_UDP\n", proto);
	exit(1);
    } else {
	printf("passed lo_url_get_protocol_id() test1\n");
    }

    proto = lo_url_get_protocol_id("osc.tcp://localhost:9999/a/path/is/here");
    if (proto != LO_TCP) {
	printf("failed lo_url_get_protocol_id() test2\n");
	printf("'%d' != LO_TCP\n", proto);
	exit(1);
    } else {
	printf("passed lo_url_get_protocol_id() test2\n");
    }
    
    proto = lo_url_get_protocol_id("osc.invalid://localhost:9999/a/path/is/here");
    if (proto != -1) {
	printf("failed lo_url_get_protocol_id() test3\n");
	printf("'%d' != -1\n", proto);
	exit(1);
    } else {
	printf("passed lo_url_get_protocol_id() test3\n");
    }
    
    proto = lo_url_get_protocol_id("osc.udp://[::ffff:localhost]:9999/a/path/is/here");
    if (proto != LO_UDP) {
	printf("failed lo_url_get_protocol_id() test1 (IPv6)\n");
	printf("'%d' != LO_UDP\n", proto);
	exit(1);
    } else {
	printf("passed lo_url_get_protocol_id() test1 (IPv6)\n");
    }

    host = lo_url_get_hostname("osc.udp://foo.example.com:9999/a/path/is/here");
    if (strcmp(host, "foo.example.com")) {
	printf("failed lo_url_get_hostname() test1\n");
	printf("'%s' != 'foo.example.com'\n", host);
	exit(1);
    } else {
	printf("passed lo_url_get_hostname() test1\n");
    }
    free(host);

    host = lo_url_get_hostname("osc.udp://[0000::::0001]:9999/a/path/is/here");
    if (strcmp(host, "0000::::0001")) {
	printf("failed lo_url_get_hostname() test2 (IPv6)\n");
	printf("'%s' != '0000::::0001'\n", host);
	exit(1);
    } else {
	printf("passed lo_url_get_hostname() test2 (IPv6)\n");
    }
    free(host);

    port = lo_url_get_port("osc.udp://localhost:9999/a/path/is/here");
    if (strcmp(port, "9999")) {
	printf("failed lo_url_get_port() test1\n");
	printf("'%s' != '9999'\n", port);
	exit(1);
    } else {
	printf("passed lo_url_get_port() test1\n");
    }
    free(port);
    
    port = lo_url_get_port("osc.udp://[::ffff:127.0.0.1]:9999/a/path/is/here");
    if (strcmp(port, "9999")) {
	printf("failed lo_url_get_port() test1 (IPv6)\n");
	printf("'%s' != '9999'\n", port);
	exit(1);
    } else {
	printf("passed lo_url_get_port() test1 (IPv6)\n");
    }
    free(port);
    printf("\n");
    
    
    
    
    
    a = lo_address_new_from_url("osc.tcp://foo.example.com:9999/");
    host2 = lo_address_get_hostname(a);
    if (strcmp(host2, "foo.example.com")) {
	printf("failed lo_address_get_hostname() test\n");
	printf("'%s' != 'foo.example.com'\n", host2);
	exit(1);
    } else {
	printf("passed lo_address_get_hostname() test\n");
    }

    port2 = lo_address_get_port(a);
    if (strcmp(port2, "9999")) {
	printf("failed lo_address_get_port() test\n");
	printf("'%s' != '9999'\n", port2);
	exit(1);
    } else {
	printf("passed lo_address_get_port() test\n");
    }

    proto = lo_address_get_protocol(a);
    if (proto != LO_TCP) {
	printf("failed lo_address_get_protocol() test\n");
	printf("'%d' != '%d'\n", proto, LO_TCP);
	exit(1);
    } else {
	printf("passed lo_address_get_protocol() test\n");
    }

    server_url = lo_address_get_url(a);
    if (strcmp(server_url, "osc.tcp://foo.example.com:9999/")) {
	printf("failed lo_address_get_url() test\n");
	printf("'%s' != '%s'\n", server_url, "osc.tcp://foo.example.com:9999/");
	exit(1);
    } else {
	printf("passed lo_address_get_url() test\n");
    }
    free(server_url);
    lo_address_free( a );
    printf("\n");
    

    /* Test blod sizes */
    if (lo_blob_datasize(btest) != 5 || lo_blobsize(btest) != 12) {
	printf("blob is %d (%d) bytes long, should be 5 (12)\n",
               lo_blob_datasize(btest), lo_blobsize(btest));
	lo_arg_pp(LO_BLOB, btest);
	printf(" <- blob\n");
	exit(1);
    }
    
    
    
    /* Server method handler tests */
    server_url = lo_server_thread_get_url(st);
    a = lo_address_new_from_url(server_url);
    printf("Server URL: %s\n", server_url);
    free(server_url);

    /* add method that will match the path /foo/bar, with two numbers, coerced
     * to float and int */

    lo_server_thread_add_method(st, "/foo/bar", "fi", foo_handler, lo_server_thread_get_server(st));

    lo_server_thread_add_method(st, "/reply", "s", reply_handler, NULL);

    lo_server_thread_add_method(st, "/lotsofformats", "fisbmhtdSccTFNI",
				lots_handler, NULL);

    lo_server_thread_add_method(st, "/coerce", "dfhiSs",
				coerce_handler, NULL);

    lo_server_thread_add_method(st, "/bundle", NULL,
				bundle_handler, NULL);
    lo_server_thread_add_method(st, "/timestamp", NULL,
				timestamp_handler, NULL);
    lo_server_thread_add_method(st, "/jitter", "ti",
				jitter_handler, NULL);

    lo_server_thread_add_method(st, "/pattern/foo", NULL,
				pattern_handler, "foo");
    lo_server_thread_add_method(st, "/pattern/bar", NULL,
				pattern_handler, "bar");
    lo_server_thread_add_method(st, "/pattern/baz", NULL,
				pattern_handler, "baz");

    lo_server_thread_add_method(st, "/subtest", "i",
				subtest_handler, st);

    lo_server_thread_add_method(st, "/subtest-reply", "i",
				subtest_reply_handler, NULL);

    /* add method that will match any path and args */
    lo_server_thread_add_method(st, NULL, NULL, generic_handler, NULL);

    /* add method that will match the path /quit with no args */
    lo_server_thread_add_method(st, "/quit", "", quit_handler, NULL);

    /* check that the thread restarts */
    lo_server_thread_start(st);
    lo_server_thread_stop(st);
    lo_server_thread_start(st);

    if (lo_send(a, "/foo/bar", "ff", 0.12345678f, 23.0f) == -1) {
	printf("OSC error A %d: %s\n", lo_address_errno(a), lo_address_errstr(a));
	exit(1);
    }

    if (lo_send(a, "/foo/bar", "ff", 0.12345678f, 23.0f) == -1) {
	printf("OSC error B %d: %s\n", lo_address_errno(a), lo_address_errstr(a));
	exit(1);
    }

    test_validation(a);
    test_multicast(st);

    lo_send(a, "/", "i", 242);
    lo_send(a, "/pattern/", "i", 243);

#ifndef _MSC_VER  /* MS compiler refuses to compile this case */
    lo_send(a, "/bar", "ff", 0.12345678f, 1.0/0.0);
#endif
    lo_send(a, "/lotsofformats", "fisbmhtdSccTFNI", 0.12345678f, 123, "123",
	    btest, midi_data, 0x0123456789abcdefULL, tt, 0.9999, "sym",
	    'X', 'Y');
    lo_send(a, "/coerce", "fdihsS", 0.1f, 0.2, 123, 124LL, "aaa", "bbb");
    lo_send(a, "/coerce", "ffffss", 0.1f, 0.2f, 123.0, 124.0, "aaa", "bbb");
    lo_send(a, "/coerce", "ddddSS", 0.1, 0.2, 123.0, 124.0, "aaa", "bbb");
    lo_send(a, "/a/b/c/d", "sfsff", "one", 0.12345678f, "three",
	    -0.00000023001f, 1.0);
    lo_send(a, "/a/b/c/d", "b", btest);

    TEST(test_varargs(a, "/lotsofformats", "fisbmhtdSccTFNI", 0.12345678f, 123,
                      "123", btest, midi_data, 0x0123456789abcdefULL, tt,
                      0.9999, "sym", 'X', 'Y', LO_ARGS_END) == 0);

#ifdef __GNUC__
    // Note: Lack of support for variable-argument macros in non-GCC compilers
    //       does not allow us to test for these conditions.

    // too many args
    TEST(test_varargs(a, "/lotsofformats", "f", 0.12345678f, 123,
                      "123", btest, midi_data, 0x0123456789abcdefULL, tt,
                      0.9999, "sym", 'X', 'Y', LO_ARGS_END) != 0);
    // too many types
    TEST(test_varargs(a, "/lotsofformats", "fisbmhtdSccTFNI", 0.12345678f, 123,
                      "123", btest, midi_data, 0x0123456789abcdefULL, tt, 0.5,
                      LO_ARGS_END) != 0);
#endif

    // test lo_message_add
    m1 = lo_message_new();
    TEST(lo_message_add(m1, "fisbmhtdSccTFNI", 0.12345678f, 123, "123",
                        btest, midi_data, 0x0123456789abcdefULL, tt, 0.9999, "sym",
                        'X', 'Y') == 0);
    lo_send_message(a, "/lotsofformats", m1);
    lo_message_free(m1);
 
    lo_blob_free(btest);

    lo_send(a, "/pattern/*", "s", "a");
    lo_send(a, "/pattern/ba[rz]", "s", "b");

    server_url = lo_server_thread_get_url(st);
    sprintf(cmd, "." PATHDELIM "subtest %s &", server_url);
    if (system(cmd) != 0) {
	fprintf(stderr, "Cannot execute subtest command\n");
	exit(1);
    }
    system(cmd);
    free(server_url);

#ifdef WIN32
    Sleep(2000);
#else
    sleep(2);
#endif
    TEST(reply_count == 3);
    TEST(pattern_count == 5);
    TEST(subtest_count == 2);
    TEST(subtest_reply_count == 22);
    printf("\n");

    {
        lo_timetag t = {10,0xFFFFFFFC};
        b = lo_bundle_new(t);
    }
    m1 = lo_message_new();
    lo_message_add_string(m1, "abcdefghijklmnopqrstuvwxyz");
    lo_message_add_string(m1, "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
    lo_bundle_add_message(b, "/bundle", m1);
    lo_send_bundle(a, b);

    /* This should be safe for multiple copies of the same message. */
    lo_bundle_free_messages(b);

    {
        lo_timetag t = {1,2};
        b = lo_bundle_new(t);
    }
    m1 = lo_message_new();
    lo_message_add_int32(m1, 23);
    lo_message_add_string(m1, "23");
    lo_bundle_add_message(b, "/bundle", m1);
    m2 = lo_message_new();
    lo_message_add_string(m2, "24");
    lo_message_add_int32(m2, 24);
    lo_bundle_add_message(b, "/bundle", m2);
    lo_bundle_add_message(b, "/bundle", m1);

/* 
    lo_send_bundle(a, b);
    if (a->errnum) {
	printf("error %d: %s\n", a->errnum, a->errstr);
	exit(1);
    }
*/
    TEST(lo_send_bundle(a, b) == 88);

    /* Test freeing out-of-order copies of messages in a bundle. */
    lo_bundle_free_messages(b);

    {
        lo_timetag t = {10,0xFFFFFFFE};
        b = lo_bundle_new(t);
    }
    m1 = lo_message_new();
    lo_message_add_string(m1, "abcdefghijklmnopqrstuvwxyz");
    lo_message_add_string(m1, "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
    lo_bundle_add_message(b, "/bundle", m1);
    lo_send_bundle(a, b);
    lo_message_free(m1);
    lo_bundle_free(b);

    lo_timetag_now(&sched);

    sched.sec += 5;
    b = lo_bundle_new(sched);
    m1 = lo_message_new();
    lo_message_add_string(m1, "future");
    lo_message_add_string(m1, "time");
    lo_message_add_string(m1, "test");
    lo_bundle_add_message(b, "/bundle", m1);

    lo_send_bundle(a, b);
    lo_message_free(m1);
    lo_bundle_free(b);

    lo_send_timestamped(a, sched, "/bundle", "s", "lo_send_timestamped() test");

    /* test bundle timestamp ends up in message struct (and doesn't end up in
       unbundled messages) */
    lo_timetag_now(&sched);    
    lo_send_timestamped(a, sched, "/timestamp", "it", 1, sched);
    lo_send(a, "/timestamp", "it", 0, sched);

#define JITTER_ITS 25
    /* jitter tests */
    {
	lo_timetag stamps[JITTER_ITS];
	lo_timetag now;
	int i;

	for (i=0; i<JITTER_ITS; i++) {
	    lo_timetag_now(&now);
	    stamps[i] = now;
	    stamps[i].sec += 1;
	    stamps[i].frac = rand();
	    lo_send_timestamped(a, stamps[i], "/jitter", "ti", stamps[i], i);
	}
    }

#ifdef WIN32
    Sleep(2000);
#else
    sleep(2);
#endif

    lo_address_free(a);

    TEST(lo_server_thread_events_pending(st));

    while (lo_server_thread_events_pending(st)) {
	printf("pending events, wait...\n");
#ifdef WIN32
	fflush(stdout);
	Sleep(1000);
#else
	sleep(1);
#endif
    }
    
    TEST(bundle_count == 7);
    printf("\n");

    printf("bundle timing jitter results:\n"
	   "max jitter = %fs\n"
	   "avg jitter = %fs\n"
           "min jitter = %fs\n\n",
           jitter_max, jitter_total/(float)jitter_count, jitter_min);

    server_url = lo_server_get_url(s);

    lo_server_add_method(s, NULL, NULL, generic_handler, NULL);
    a = lo_address_new_from_url(server_url);
    TEST(lo_server_recv_noblock(s, 0) == 0);
    printf("Testing noblock API on %s\n", server_url);
    lo_send(a, "/non-block-test", "f", 23.0);

    count = 0;
    while (!lo_server_recv_noblock(s, 10) && count++ < 1000) { }
    if (count >= 1000) {
	printf("lo_server_recv_noblock() test failed\n");

	exit(1);
    }

    /* Delete methods */
    lo_server_thread_del_method(st, "/coerce", "dfhiSs");
    lo_server_del_method(s, NULL, NULL);

    lo_address_free(a);
    lo_server_free(s);
    free(server_url);

#ifndef WIN32
    { /* UNIX domain tests */
	lo_address ua;
	lo_server us;
	char *addr;

	unlink("/tmp/testlo.osc");
	us = lo_server_new_with_proto("/tmp/testlo.osc", LO_UNIX, error);
	ua = lo_address_new_from_url("osc.unix:///tmp/testlo.osc");
	TEST(lo_server_get_protocol(us) == LO_UNIX);
	TEST(lo_send(ua, "/unix", "f", 23.0) == 16);
	TEST(lo_server_recv(us) == 16);
	addr = lo_server_get_url(us);
	TEST(!strcmp("osc.unix:////tmp/testlo.osc", addr));
	free(addr);
	lo_address_free(ua);
	ua = lo_address_new_with_proto(LO_UNIX, NULL, "/tmp/testlo.osc");
	TEST(lo_send(ua, "/unix", "f", 23.0) == 16);
	TEST(lo_server_recv(us) == 16);
	lo_server_free(us);
	lo_address_free(ua);
    }
#endif

    { /* TCP tests */
	lo_address ta;
	lo_server ts;
	char *addr;

	ts = lo_server_new_with_proto(NULL, LO_TCP, error);
	addr = lo_server_get_url(ts);
	ta = lo_address_new_from_url(addr);
	if (lo_address_errno(ta)) {
	    printf("err: %s\n", lo_address_errstr(ta));
	    exit(1);
	}
	TEST(lo_server_get_protocol(ts) == LO_TCP);
	TEST(lo_send(ta, "/tcp", "f", 23.0) == 16);
	TEST(lo_send(ta, "/tcp", "f", 23.0) == 16);
	TEST(lo_server_recv(ts) == 16);
	TEST(lo_server_recv(ts) == 16);
	free(addr);
	lo_server_free(ts);
	lo_address_free(ta);
    }

    server_url = lo_server_thread_get_url(st);
    a = lo_address_new_from_url(server_url);
    /* exit */
    lo_send(a, "/quit", NULL);
    lo_address_free(a);

    while (!done) {
#ifdef WIN32
    Sleep(1);
#else
	usleep(1000);
#endif
    }

    lo_server_thread_free(st);
    free(server_url);


    return 0;
}