@@ -92,27 +92,27 @@ OSC_HANDLER( add_strip ) | |||||
return 0; | return 0; | ||||
} | } | ||||
OSC_HANDLER( finger ) | |||||
{ | |||||
OSC_DMSG(); | |||||
void | |||||
Mixer::reply_to_finger ( lo_message msg ) | |||||
{ | |||||
int argc = lo_message_get_argc( msg ); | |||||
lo_arg **argv = lo_message_get_argv( msg ); | |||||
OSC::Endpoint *ep = ((OSC::Endpoint*)user_data); | |||||
lo_address reply = lo_address_new_from_url( &argv[0]->s ); | |||||
ep->send( reply, | |||||
"/reply", | |||||
path, | |||||
ep->url(), | |||||
APP_NAME, | |||||
VERSION, | |||||
instance_name ); | |||||
if ( argc < 2 ) | |||||
return; | |||||
lo_address_free( reply ); | |||||
lo_address to = lo_address_new_from_url( &argv[1]->s ); | |||||
return 0; | |||||
} | |||||
osc_endpoint->send( to, | |||||
"/reply", | |||||
"/non/finger", | |||||
osc_endpoint->url(), | |||||
APP_NAME, | |||||
VERSION, | |||||
instance_name ); | |||||
lo_address_free( to ); | |||||
} | |||||
@@ -383,13 +383,14 @@ Mixer::init_osc ( const char *osc_port ) | |||||
printf( "OSC=%s\n", osc_endpoint->url() ); | printf( "OSC=%s\n", osc_endpoint->url() ); | ||||
osc_endpoint->add_method( "/non/finger", "s", OSC_NAME( finger ), osc_endpoint, "" ); | |||||
osc_endpoint->add_method( "/non/mixer/add_strip", "", OSC_NAME( add_strip ), osc_endpoint, "" ); | osc_endpoint->add_method( "/non/mixer/add_strip", "", OSC_NAME( add_strip ), osc_endpoint, "" ); | ||||
// osc_endpoint->start(); | // osc_endpoint->start(); | ||||
/* poll so we can keep OSC handlers running in the GUI thread and avoid extra sync */ | /* poll so we can keep OSC handlers running in the GUI thread and avoid extra sync */ | ||||
Fl::add_timeout( OSC_INTERVAL, check_osc, this ); | Fl::add_timeout( OSC_INTERVAL, check_osc, this ); | ||||
return 0; | |||||
} | } | ||||
void | void | ||||
@@ -95,6 +95,8 @@ public: | |||||
static void check_osc ( void * v ); | static void check_osc ( void * v ); | ||||
void reply_to_finger ( lo_message msg ); | |||||
void announce ( const char *nash_url, const char *process_name ); | void announce ( const char *nash_url, const char *process_name ); | ||||
int init_osc ( const char* osc_port ); | int init_osc ( const char* osc_port ); | ||||
@@ -35,6 +35,22 @@ NSM_Client::NSM_Client ( ) | |||||
int command_open ( const char *name, const char *display_name, const char *client_id, char **out_msg ); | int command_open ( const char *name, const char *display_name, const char *client_id, char **out_msg ); | ||||
int command_save ( char **out_msg ); | int command_save ( char **out_msg ); | ||||
int | |||||
NSM_Client::command_broadcast ( lo_message msg ) | |||||
{ | |||||
int argc = lo_message_get_argc( msg ); | |||||
lo_arg **argv = lo_message_get_argv( msg ); | |||||
if ( argc > 1 && !strcmp( &argv[0]->s, "/non/finger" ) ) | |||||
{ | |||||
mixer->reply_to_finger( msg ); | |||||
return 0; | |||||
} | |||||
else | |||||
return -1; | |||||
} | |||||
int | int | ||||
NSM_Client::command_save ( char **out_msg ) | NSM_Client::command_save ( char **out_msg ) | ||||
@@ -35,4 +35,6 @@ protected: | |||||
int command_save ( char **out_msg ); | int command_save ( char **out_msg ); | ||||
void command_active ( bool active ); | void command_active ( bool active ); | ||||
int command_broadcast ( lo_message msg ); | |||||
}; | }; |
@@ -121,6 +121,16 @@ namespace NSM | |||||
} | } | ||||
} | } | ||||
void | |||||
Client::broadcast ( const char *path, const char *v1 ) | |||||
{ | |||||
if ( nsm_is_active ) | |||||
{ | |||||
lo_send_from( nsm_addr, _server, LO_TT_IMMEDIATE, "/nsm/server/broadcast", "ss", path, v1 ); | |||||
} | |||||
} | |||||
void | void | ||||
Client::check ( int timeout ) | Client::check ( int timeout ) | ||||
{ | { | ||||
@@ -153,6 +163,8 @@ namespace NSM | |||||
lo_server_add_method( _server, "/reply", "ssss", &Client::osc_announce_reply, this ); | lo_server_add_method( _server, "/reply", "ssss", &Client::osc_announce_reply, this ); | ||||
lo_server_add_method( _server, "/nsm/client/open", "sss", &Client::osc_open, this ); | lo_server_add_method( _server, "/nsm/client/open", "sss", &Client::osc_open, this ); | ||||
lo_server_add_method( _server, "/nsm/client/save", "", &Client::osc_save, this ); | lo_server_add_method( _server, "/nsm/client/save", "", &Client::osc_save, this ); | ||||
lo_server_add_method( _server, "/nsm/client/session_is_loaded", "", &Client::osc_session_is_loaded, this ); | |||||
lo_server_add_method( _server, "/nsm/client/broadcast", NULL, &Client::osc_broadcast, this ); | |||||
return 0; | return 0; | ||||
} | } | ||||
@@ -170,7 +182,9 @@ namespace NSM | |||||
lo_server_thread_add_method( _st, "/reply", "ssss", &Client::osc_announce_reply, this ); | lo_server_thread_add_method( _st, "/reply", "ssss", &Client::osc_announce_reply, this ); | ||||
lo_server_thread_add_method( _st, "/nsm/client/open", "sss", &Client::osc_open, this ); | lo_server_thread_add_method( _st, "/nsm/client/open", "sss", &Client::osc_open, this ); | ||||
lo_server_thread_add_method( _st, "/nsm/client/save", "", &Client::osc_save, this ); | lo_server_thread_add_method( _st, "/nsm/client/save", "", &Client::osc_save, this ); | ||||
lo_server_thread_add_method( _st, "/nsm/client/session_is_loaded", "", &Client::osc_session_is_loaded, this ); | |||||
lo_server_thread_add_method( _st, "/nsm/client/broadcast", NULL, &Client::osc_broadcast, this ); | |||||
return 0; | return 0; | ||||
} | } | ||||
@@ -178,6 +192,12 @@ namespace NSM | |||||
/* OSC Message Handlers */ | /* OSC Message Handlers */ | ||||
/************************/ | /************************/ | ||||
int | |||||
Client::osc_broadcast ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ) | |||||
{ | |||||
return ((NSM::Client*)user_data)->command_broadcast( msg ); | |||||
} | |||||
int | int | ||||
Client::osc_save ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ) | Client::osc_save ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ) | ||||
{ | { | ||||
@@ -244,7 +264,7 @@ namespace NSM | |||||
return 0; | return 0; | ||||
} | } | ||||
int | int | ||||
Client::osc_announce_reply ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ) | Client::osc_announce_reply ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ) | ||||
{ | { | ||||
@@ -65,7 +65,9 @@ namespace NSM | |||||
void progress ( float f ); | void progress ( float f ); | ||||
void message( int priority, const char *msg ); | void message( int priority, const char *msg ); | ||||
void announce ( const char *nsm_url, const char *appliction_name, const char *capabilities, const char *process_name ); | void announce ( const char *nsm_url, const char *appliction_name, const char *capabilities, const char *process_name ); | ||||
void broadcast ( const char *path, const char *v1 ); | |||||
/* init without threading */ | /* init without threading */ | ||||
int init ( void ); | int init ( void ); | ||||
/* init with threading */ | /* init with threading */ | ||||
@@ -88,6 +90,9 @@ namespace NSM | |||||
virtual void command_session_is_loaded ( void ) { } | virtual void command_session_is_loaded ( void ) { } | ||||
/* invoked when an unrecognized message is received. Should return 0 if you handled it, -1 otherwise. */ | |||||
virtual int command_broadcast ( lo_message msg ) { return -1; } | |||||
private: | private: | ||||
/* osc handlers */ | /* osc handlers */ | ||||
@@ -96,6 +101,7 @@ namespace NSM | |||||
static int osc_announce_reply ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ); | static int osc_announce_reply ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ); | ||||
static int osc_error ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ); | static int osc_error ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ); | ||||
static int osc_session_is_loaded ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ); | static int osc_session_is_loaded ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ); | ||||
static int osc_broadcast ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ); | |||||
}; | }; | ||||
}; | }; |
@@ -372,15 +372,15 @@ namespace OSC | |||||
switch ( ov->type() ) | switch ( ov->type() ) | ||||
{ | { | ||||
case 'f': | case 'f': | ||||
DMESSAGE( "Adding float %f", ((OSC_Float*)ov)->value() ); | |||||
// DMESSAGE( "Adding float %f", ((OSC_Float*)ov)->value() ); | |||||
lo_message_add_float( m, ((OSC_Float*)ov)->value() ); | lo_message_add_float( m, ((OSC_Float*)ov)->value() ); | ||||
break; | break; | ||||
case 'i': | case 'i': | ||||
DMESSAGE( "Adding int %i", ((OSC_Int*)ov)->value() ); | |||||
// DMESSAGE( "Adding int %i", ((OSC_Int*)ov)->value() ); | |||||
lo_message_add_int32( m, ((OSC_Int*)ov)->value() ); | lo_message_add_int32( m, ((OSC_Int*)ov)->value() ); | ||||
break; | break; | ||||
case 's': | case 's': | ||||
DMESSAGE( "Adding string %s", ((OSC_String*)ov)->value() ); | |||||
// DMESSAGE( "Adding string %s", ((OSC_String*)ov)->value() ); | |||||
lo_message_add_string( m, ((OSC_String*)ov)->value() ); | lo_message_add_string( m, ((OSC_String*)ov)->value() ); | ||||
break; | break; | ||||
default: | default: | ||||
@@ -389,7 +389,7 @@ namespace OSC | |||||
} | } | ||||
} | } | ||||
DMESSAGE( "Path: %s", path ); | |||||
// DMESSAGE( "Path: %s", path ); | |||||
lo_bundle b = lo_bundle_new( LO_TT_IMMEDIATE ); | lo_bundle b = lo_bundle_new( LO_TT_IMMEDIATE ); | ||||
@@ -1451,15 +1451,23 @@ OSC_HANDLER( broadcast ) | |||||
} | } | ||||
} | } | ||||
char *sender_url = lo_address_get_url( lo_message_get_source( msg ) ); | |||||
for ( std::list<Client*>::iterator i = client.begin(); | for ( std::list<Client*>::iterator i = client.begin(); | ||||
i != client.end(); | i != client.end(); | ||||
++i ) | ++i ) | ||||
{ | { | ||||
if ( (*i)->addr != lo_message_get_source( msg ) ) | |||||
if ( ! (*i)->addr ) | |||||
continue; | |||||
char *url = lo_address_get_url( (*i)->addr ); | |||||
if ( strcmp( sender_url, url ) ) | |||||
{ | { | ||||
osc_server->send( (*i)->addr, to_path, new_args ); | |||||
osc_server->send( (*i)->addr, "/nsm/client/broadcast", new_args ); | |||||
} | } | ||||
free( url ); | |||||
} | } | ||||
/* also relay to attached GUI so that the broadcast can be | /* also relay to attached GUI so that the broadcast can be | ||||
@@ -1471,6 +1479,8 @@ OSC_HANDLER( broadcast ) | |||||
osc_server->send( gui_addr, path, new_args ); | osc_server->send( gui_addr, path, new_args ); | ||||
} | } | ||||
free( sender_url ); | |||||
return 0; | return 0; | ||||
} | } | ||||
@@ -81,3 +81,27 @@ NSM_Client::command_open ( const char *name, const char *display_name, const cha | |||||
return 0; | return 0; | ||||
} | } | ||||
void | |||||
NSM_Client::command_session_is_loaded ( void ) | |||||
{ | |||||
MESSAGE( "NSM says session is loaded." ); | |||||
timeline->discover_peers(); | |||||
} | |||||
int | |||||
NSM_Client::command_broadcast ( lo_message msg ) | |||||
{ | |||||
int argc = lo_message_get_argc( msg ); | |||||
lo_arg **argv = lo_message_get_argv( msg ); | |||||
if ( argc > 1 && !strcmp( &argv[0]->s, "/non/finger" ) ) | |||||
{ | |||||
timeline->reply_to_finger( msg ); | |||||
return 0; | |||||
} | |||||
else | |||||
return -1; | |||||
} |
@@ -33,4 +33,7 @@ protected: | |||||
int command_open ( const char *name, const char *display_name, const char *client_id, char **out_msg ); | int command_open ( const char *name, const char *display_name, const char *client_id, char **out_msg ); | ||||
int command_save ( char **out_msg ); | int command_save ( char **out_msg ); | ||||
void command_session_is_loaded ( void ); | |||||
int command_broadcast ( lo_message msg ); | |||||
}; | }; |
@@ -1546,3 +1546,89 @@ Timeline::session_manager_name ( void ) | |||||
{ | { | ||||
return nsm->session_manager_name(); | return nsm->session_manager_name(); | ||||
} | } | ||||
/*******/ | |||||
/* OSC */ | |||||
/*******/ | |||||
const double OSC_INTERVAL = 0.2f; | |||||
void | |||||
Timeline::check_osc ( void * v ) | |||||
{ | |||||
((Timeline*)v)->osc->check(); | |||||
Fl::repeat_timeout( OSC_INTERVAL, &Timeline::check_osc, v ); | |||||
} | |||||
int | |||||
Timeline::init_osc ( const char *osc_port ) | |||||
{ | |||||
osc = new OSC::Endpoint(); | |||||
if ( int r = osc->init( osc_port ) ) | |||||
return r; | |||||
osc->owner = this; | |||||
printf( "OSC=%s\n", osc->url() ); | |||||
osc->add_method( "/reply", NULL, &Timeline::osc_reply, osc, "" ); | |||||
// osc->start(); | |||||
/* poll so we can keep OSC handlers running in the GUI thread and avoid extra sync */ | |||||
Fl::add_timeout( OSC_INTERVAL, &Timeline::check_osc, this ); | |||||
return 0; | |||||
} | |||||
int | |||||
Timeline::osc_reply ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ) | |||||
{ | |||||
OSC_DMSG(); | |||||
if ( argc >= 5 && !strcmp( &argv[0]->s, "/non/finger" ) ) | |||||
{ | |||||
const char *url = &argv[1]->s; | |||||
const char *name = &argv[2]->s; | |||||
const char *version = &argv[3]->s; | |||||
const char *id = &argv[4]->s; | |||||
MESSAGE( "Discovered OSC peer %s (%s) @ %s with ID \"%s\"", name, version, url, id ); | |||||
return 0; | |||||
} | |||||
return -1; | |||||
} | |||||
void | |||||
Timeline::reply_to_finger ( lo_message msg ) | |||||
{ | |||||
int argc = lo_message_get_argc( msg ); | |||||
lo_arg **argv = lo_message_get_argv( msg ); | |||||
if ( argc < 2 ) | |||||
return; | |||||
lo_address reply = lo_address_new_from_url( &argv[1]->s ); | |||||
osc->send( reply, | |||||
"/reply", | |||||
"/non/finger", | |||||
osc->url(), | |||||
APP_NAME, | |||||
VERSION, | |||||
instance_name ); | |||||
lo_address_free( reply ); | |||||
} | |||||
void | |||||
Timeline::discover_peers ( void ) | |||||
{ | |||||
nsm->broadcast( "/non/finger", osc->url() ); | |||||
} | |||||
@@ -87,6 +87,8 @@ class Timeline : public Fl_Single_Window, public RWLock | |||||
{ | { | ||||
static void draw_clip ( void * v, int X, int Y, int W, int H ); | static void draw_clip ( void * v, int X, int Y, int W, int H ); | ||||
OSC::Endpoint *osc; | |||||
int _old_xposition; | int _old_xposition; | ||||
int _old_yposition; | int _old_yposition; | ||||
@@ -228,6 +230,18 @@ public: | |||||
bool command_save ( void ); | bool command_save ( void ); | ||||
void command_quit ( void ); | void command_quit ( void ); | ||||
/* OSC */ | |||||
void discover_peers ( void ); | |||||
static void check_osc ( void * v ); | |||||
int init_osc ( const char *osc_port ); | |||||
static int osc_reply ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data ); | |||||
void reply_to_finger ( lo_message msg ); | |||||
private: | private: | ||||
static void snapshot ( void *v ) { ((Timeline*)v)->snapshot(); } | static void snapshot ( void *v ) { ((Timeline*)v)->snapshot(); } | ||||
@@ -201,6 +201,8 @@ main ( int argc, char **argv ) | |||||
tle->run(); | tle->run(); | ||||
timeline->init_osc( NULL ); | |||||
char *nsm_url = getenv( "NSM_URL" ); | char *nsm_url = getenv( "NSM_URL" ); | ||||
if ( nsm_url ) | if ( nsm_url ) | ||||