Esempio n. 1
0
File: Osc.cpp Progetto: EQ4/MRP
int OscReceiver::handler(const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *data)
{
	bool matched = false;
	
	string pathString(path);	
	
	if(useThru_)
	{
		// Rebroadcast any matching messages
		
		if(!pathString.compare(0, thruPrefix_.length(), thruPrefix_))
			lo_send_message(thruAddress_, path, msg);
	}
	
	// Check if the incoming message matches the global prefix for this program.  If not, discard it.
	if(pathString.compare(0, globalPrefix_.length(), globalPrefix_))
	{
		cout << "OSC message '" << path << "' received\n";
		return 1;
	}
	
	// Lock the mutex so the list of listeners doesn't change midway through
	pthread_mutex_lock(&oscListenerMutex_);
	
	// Now remove the global prefix and compare the rest of the message to the registered handlers.
	multimap<string, OscHandler*>::iterator it;
	pair<multimap<string, OscHandler*>::iterator,multimap<string, OscHandler*>::iterator> ret;
	string truncatedPath = pathString.substr(globalPrefix_.length(), 
											 pathString.length() - globalPrefix_.length());
	ret = noteListeners_.equal_range(truncatedPath);
	
	it = ret.first;
	while(it != ret.second)
	{
		OscHandler *object = (*it++).second;
		
#ifdef DEBUG_MESSAGES
		cout << "Matched OSC path '" << path << "' to handler " << object << endl;
#endif
		object->oscHandlerMethod(truncatedPath.c_str(), types, argc, argv, data);
		matched = true;
	}
	
	pthread_mutex_unlock(&oscListenerMutex_);
	
	if(matched)		// This message has been handled
		return 0;
	
	printf("Unhandled OSC path: <%s>\n", path);
	
#ifdef DEBUG_MESSAGES
    for (int i=0; i<argc; i++) {
		printf("arg %d '%c' ", i, types[i]);
		lo_arg_pp((lo_type)types[i], argv[i]);
		printf("\n");
    }
#endif
	
    return 1;
}
Esempio n. 2
0
/**
 * catch any incoming messages.
 * Returning 1 means that the message has not been fully handled
 * and the server should try other methods
 */
int OscReceiver::generic_handler(const char *path, const char *types, lo_arg **argv,
                    int argc, void *data, void *user_data)
{
    Message message;
    message.appendString(path);
    OscReceiver *context = static_cast<OscReceiver *>(user_data);
    if (context->debug_)
        printf("path: <%s>\n", path);
    for (int i = 0; i < argc; i++)
    {
        if (context->debug_)
        {
            printf("arg %d '%c' ", i, types[i]);
            lo_arg_pp(static_cast<lo_type>(types[i]), argv[i]);
            printf("\n");
            fflush(stdout);
        }
        switch (types[i])
        {
            case 'i':
                message.appendInt(argv[i]->i);
                break;
            case 'f':
                message.appendFloat(argv[i]->f);
                break;
            case 's':
                message.appendString(static_cast<const char *>(&argv[i]->s));
                break;
            case 'c':
                if (Logger::isEnabledFor(NOTICE))
                {
                    std::ostringstream os;
                    os << "OscReceiver::" << __FUNCTION__ << ": ";
                    os << "Tempi does not support char values, so we cast the incoming char to int.";
                    Logger::log(NOTICE, os);
                }
                message.appendInt((Int) argv[i]->c);
                break;
            case 'd':
                message.appendFloat(argv[i]->d);
                break;
            case 'T':
                message.appendBoolean(true);
                break;
            case 'F':
                message.appendBoolean(false);
                break;
            default:
                {
                    std::ostringstream os;
                    os << "OscReceiver::" << __FUNCTION__ << ": cannot handle lo arg type " << types[i] << std::endl;
                    Logger::log(ERROR, os);
                    break;
                }
        }
    }
    // TODO: time OSC messages so that timing be exact.
    context->messages_.push_back(message);
    return 1;
}
Esempio n. 3
0
int messageHandler(const char* cPath, const char* types, lo_arg** argv, int argc, void* data, void* user_data) {
	int i;
	std::string path = cPath;

	std::cout << "path: <" << path << ">" << std::endl;
    for (i = 0; i < argc; i++) {
		std::cout << "arg " << i << " '" << types[i] << "' ";
        lo_arg_pp((lo_type)types[i], argv[i]);
		std::cout << std::endl;
    }
    return 1;
}
Esempio n. 4
0
static int osc_message ( const char *path, const char * /*types*/,
	lo_arg **argv, int /*argc*/, void *data, void * /*user_data*/ )
{
	QMutexLocker locker(&g_oscMutex);

#ifdef CONFIG_DEBUG_0
	printf("osc_message: path \"%s\"", path);
	for (int i = 0; i < argc; ++i) {
		printf(", arg %d '%c' ", i, types[i]);
		lo_arg_pp(lo_type(types[i]), argv[i]);
	}
	printf(", data %p, user_data %p\n", data, user_data);
#endif

	if (::strncmp(path, "/dssi", 5))
		return 1;

	const QString sPath = path;
	const QString& sLabel = sPath.section('/', 2, 2);
	DssiEditor *pDssiEditor = osc_find_editor(sLabel);
	if (pDssiEditor == NULL)
		return 1;

	if (pDssiEditor->busy > 0)
		return 1;

	lo_message message = lo_message(data);
	lo_address source  = lo_message_get_source(message);
	
	const QString& sMethod = sPath.section('/', 3, 3);

	if (sMethod == "update")
		return osc_update(pDssiEditor, argv, source);
	else
	if (sMethod == "configure")
		return osc_configure(pDssiEditor, argv);
	else
	if (sMethod == "control")
		return osc_control(pDssiEditor, argv);
	else
	if (sMethod == "program")
		return osc_program(pDssiEditor, argv);
	else
	if (sMethod == "midi")
		return osc_midi(pDssiEditor, argv);
	else
	if (sMethod == "exiting")
		return osc_exiting(pDssiEditor);

	return 1;
}
Esempio n. 5
0
int messageHandler(const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data)
{
	int i;

	printf("%s %s", path, types);

	for(i=0; i<argc; i++) {
		printf(" ");
		lo_arg_pp((lo_type)types[i], argv[i]);
	}
	printf("\n");

	return 0;
}
Esempio n. 6
0
int generic_handler(const char *path, const char *types, lo_arg **argv,
		    int argc, lo_message msg, void *user_data) {
    int i;
    int sz = lo_message_length(msg, path);
    printf("path: <%s> size: %d\n", path, sz);
    for (i=0; i<argc; i++) {
      printf("arg %d '%c' ", i, types[i]);
      lo_arg_pp(types[i], argv[i]);
      printf("\n");
    }
    printf("\n");

    return 1;
}
Esempio n. 7
0
int generic_handler(const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data)
{
    int i;
	
    printf("path: <%s>\n", path);
    for (i=0; i<argc; i++) {
	printf("arg %d '%c' ", i, types[i]);
	lo_arg_pp(types[i], argv[i]);
	printf("\n");
    }
    printf("\n");
    fflush(stdout);
    return 1;
}
Esempio n. 8
0
int osc_handler_generic( const char *path, const char *types, lo_arg ** argv, int argc, void *data, void *user_data)
{
	if( osc_debug)
	{
		int i;
		printf("path: <%s>\n", path);
		for (i = 0; i < argc; i++)
		{
			printf("arg %d '%c' ", i, types[i]);
			lo_arg_pp((lo_type)types[i], argv[i]);
			printf("\n");
		}
	}

	return 1;
}
Esempio n. 9
0
int
debug_handler (const char *path, const char *types, lo_arg ** argv,
	       int argc, void *data, void *user_data)
{
  int i;

  printf ("Warning: unhandled OSC message in GUI:\n");
  for (i = 0; i < argc; ++i)
    {
      printf ("arg  %d : type : %c \n", i, types[i]);
      lo_arg_pp ((lo_type) types[i], argv[i]);

    }

  printf ("path is %s\n", path);
  return 1;
}
Esempio n. 10
0
/* catch any incoming messages and display them. returning 1 means that the 
 *  * message has not been fully handled and the server should try other methods */
int OscReceiver::genericHandler(const char *path, 
        const char *types, lo_arg **argv, 
        int argc, void * /*data*/, void * /*user_data*/) 
{ 
    //OscReceiver *context = static_cast<OscReceiver*>(user_data);
    printf("path: <%s>\n", path); 
    for (int i = 0; i < argc; ++i) 
    { 
        printf("arg %d '%c' ", i, types[i]); 
        lo_arg_pp(static_cast<lo_type>(types[i]), argv[i]); 
        printf("\n"); 
    } 
    printf("\n"); 
    fflush(stdout); 

    return 1; 
} 
Esempio n. 11
0
int
osc_debug_handler(const char *path, const char *types, lo_arg **argv,
                  int argc, lo_message msg, void *user_data)
{
    int i;

    GDB_MESSAGE(GDB_OSC, " warning: unhandled OSC message to <%s>:\n", path);

    for (i = 0; i < argc; ++i) {
        fprintf(stderr, "arg %d: type '%c': ", i, types[i]);
fflush(stderr);
        lo_arg_pp((lo_type)types[i], argv[i]);  /* -FIX- Ack, mixing stderr and stdout... */
        fprintf(stdout, "\n");
fflush(stdout);
    }

    return 1;  /* try any other handlers */
}
Esempio n. 12
0
File: Osc.cpp Progetto: EQ4/MRP
void OscTransmitter::sendMessage(const char * path, const char * type, const lo_message& message)
{
    if(debugMessages_) {
        cout << path << " " << type << " ";

        int argc = lo_message_get_argc(message);
        lo_arg **argv = lo_message_get_argv(message);
        for (int i=0; i<argc; i++) {
            lo_arg_pp((lo_type)type[i], argv[i]);
            cout << " ";
        }
        cout << endl;
    }
    
	// Send message to everyone who's currently listening
	for(vector<lo_address>::iterator it = addresses_.begin(); it != addresses_.end(); it++) {
		lo_send_message(*it, path, message);
	}
}
Esempio n. 13
0
inline int lo_generic_handler(const char *path, const char *types, lo_arg **argv,
			      int argc, lo_message msg, void *user_data)
{
    int i;

    printf("--- OSC Message ---\n");
    printf("from host: %s\n", lo_address_get_hostname(lo_message_get_source(msg)));
    printf("from port: %s\n", lo_address_get_port(lo_message_get_source(msg)));
    printf("path: <%s>\n", path);

    for (i=0; i<argc; i++) {
	printf("arg %d '%c' ", i, types[i]);
	lo_arg_pp((lo_type)types[i], argv[i]);
	printf("\n");
    }

    printf("\n");
    fflush(stdout);

    return 1;
}
Esempio n. 14
0
File: osc.c Progetto: cmeon/touchwax
/* catch any incoming messages and display them. returning 1 means that the
 * message has not been fully handled and the server should try other methods */
int generic_handler(const char *path, const char *types, lo_arg ** argv,
                    int argc, void *data, void *user_data)
{
    int i;

    //printf("path: <%s>\n", path);
#ifdef __ANDROID__
    __android_log_print(ANDROID_LOG_DEBUG, "osc.c", "path: <%s>\n", path);
#endif

    for (i = 0; i < argc; i++) {
#ifdef __ANDROID__       
        __android_log_print(ANDROID_LOG_DEBUG, "osc.c", "arg %d '%c' ", i, types[i]);
#endif
        lo_arg_pp((lo_type)types[i], argv[i]);
        //printf("\n");
    }
    //printf("\n");
    //fflush(stdout);

    return 1;
}
Esempio n. 15
0
int wxSpinTreeCtrl_liblo_callback(const char *path, const char *types, lo_arg **argv, int argc, void * WXUNUSED(data), void *user_data)
{
    // DEBUG PRINT:

    printf("wxSpinTreeCtrl got spin message: %s", path);
    for (int i=0; i<argc; i++) {
        printf(" ");
        lo_arg_pp((lo_type) types[i], argv[i]);
    }
    printf("\n");


    if (!argc)
    {
        std::cout << "ERROR: got message for " << path << " without any method or arguments" << std::endl;
        return 1;
    }

    // check that the treeCtrl was provided as user_data
    wxSpinTreeCtrl *treeCtrl = (wxSpinTreeCtrl*) user_data;
    if (! treeCtrl)
        return 1;


    // WARNING: this callback will match ANY path, so we must manually check
    // if it is within the SPIN namespace, and if it matches the sceneID:
    // TODO: replace this with node/scene callbacks!!!
    /*
    std::string spinToken, sceneString, nodeString;
    std::istringstream pathstream(path);
    pathstream.get(); // ignore leading slash
    getline(pathstream, spinToken, '/');
    getline(pathstream, sceneString, '/');
    getline(pathstream, nodeString, '/');

    if ((spinToken!="SPIN") || !spin::wildcardMatch(sceneString.c_str(), spin::spinApp::Instance().getSceneID().c_str()) )
    {
        std::cout << "Warning: wxSpinTreeCtrl is ignoring message: " << path << std::endl;
        return 1;
    }
     */
    // get the method (argv[0]):
    std::string theMethod;
    if (lo_is_string_type((lo_type) types[0]))
    {
        theMethod = std::string((char *) argv[0]);
    }
    else
        return 0;

    // SCENE MESSAGES:
    if (1)//(nodeString.empty())
    {
        if ((theMethod=="nodeList") && (argc>2))
        {
            for (int i = 2; i < argc; ++i)
            {
                if (strcmp((char*) argv[i], "NULL") != 0) treeCtrl->addNode((char*) argv[i]);
            }
        }
        else if ((theMethod=="createNode") && (argc==3))
        {
            treeCtrl->addNode((char*) argv[1]);
        }
        else if ((theMethod=="deleteNode") && (argc==2))
        {
            treeCtrl->removeNode((char*) argv[1]);
        }
        else if (theMethod=="refresh")
        {
            treeCtrl->Refresh();
        }
        else if (theMethod=="clear")
        {
            treeCtrl->Refresh();
            treeCtrl->SelectNode(NULL);
        }
        else if ((theMethod=="parentChange") && (argc==3))
        {
            //std::cout << "got parentChange for node " << (char*)argv[1] << ". New parent: " << (char*)argv[2] << std::endl;
            //treeCtrl->removeNode((char*) argv[1]);
            //treeCtrl->addNode((char*) argv[1]);
            treeCtrl->addNode((char*)argv[1]);

        }
    }
/*
    // NODE MESSAGES:
    else
    {
        if ((theMethod=="setParent") && (argc==2))
        {
            treeCtrl->removeNode(nodeString.c_str());
            treeCtrl->addNode(nodeString.c_str());
        }
    }
*/
    return 1;
}
Esempio n. 16
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;
}