Files
veejay/veejay-current/veejay-server/libplugger/oscservit.c
Niels Elburg bd1b0bd613 livido in place / copy mode host side, channel handling
git-svn-id: svn://code.dyne.org/veejay/trunk@1427 eb8d1916-c9e9-0310-b8de-cf0c9472ead5
2010-05-02 16:42:04 +00:00

625 lines
14 KiB
C

#ifndef OSC_SERVER_H
#define OSC_SERVER_H
/* veejay - Linux VeeJay
* (C) 2002-2006 Niels Elburg <nelburg@looze.net>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
a/. * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <config.h>
#include <stdarg.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <libvjmem/vjmem.h>
#include <libvjmsg/vj-common.h>
#include <libvevo/libvevo.h>
#include <veejay/vims.h>
#include <veejay/veejay.h>
#include <lo/lo.h>
#include <ctype.h>
#include <vevosample/vevosample.h>
#include <libvjmem/vjmem.h>
//@ client side implementation
#ifdef STRICT_CHECKING
#include <assert.h>
#endif
#include <veejay/oscservit.h>
typedef struct {
int seq;
void *caller;
void *instance;
} plugin_data_t;
typedef struct
{
lo_server_thread st;
char *url;
int port;
// void *events;
} osc_recv_t;
void error_handler( int num, const char *msg, const char *path )
{
veejay_msg(0,"Liblo server error %d in path %s: %s",num,path,msg );
}
static char *osc_create_path( const char *base, const char *path )
{
int n = strlen(base) + strlen(path) + 2;
char *res = (char*) vj_malloc(n);
bzero(res,n);
sprintf(res,"%s/%s", base,path);
return res;
}
static char *osc_fx_pair_str( const char *base, const char *key )
{
int n = strlen(base) + strlen(key) + 2;
char *res = (char*) vj_malloc(n);
bzero(res,n);
snprintf( res,n, "%s/%s", base,key);
return res;
}
static char *vevo_str_to_liblo( const char *format )
{
int n = strlen(format);
if( n <= 0 )
return NULL;
char *res = (char*) vj_malloc( n );
int k = 0;
bzero(res,n );
while(*format)
{
if(*format=='d' || *format=='s')
res[k++] = (*format == 'd' ? 'i' : 's');
*format++;
}
return res;
}
static char make_valid_char_( const char c )
{
const char *invalid = " #*,?[]{}";
int k = 0;
char o = '_';
char r = c;
for( k = 0; k < 8 ; k ++ )
{
if ( c == invalid[k] || isspace((unsigned char)c))
return o;
char l = tolower(c);
if(l)
r = l;
}
return r;
}
char *veejay_valid_osc_name( const char *in )
{
int n = strlen( in );
int k;
char *res = strdup( in );
for( k = 0; k < n ; k ++ )
{
res[k] = make_valid_char_( in[k] );
}
return res;
}
void veejay_osc_del_methods( void *user_data, void *osc_space,void *vevo_port, void *fx_instance )
{
veejay_t *info = (veejay_t*) user_data;
osc_recv_t *s = (osc_recv_t*) info->osc_server;
char **keys = vevo_list_properties( osc_space );
int i;
int error;
for( i = 0; keys[i] != NULL ; i ++ )
{
void *event_port = NULL;
error = vevo_property_get( osc_space, keys[i],0,&event_port );
#ifdef STRICT_CHECKING
assert( error == VEVO_NO_ERROR );
#endif
void *ptr = NULL;
error = vevo_property_get( event_port, "userdata",0, &ptr );
#ifdef STRICT_CHECKING
assert(error == VEVO_NO_ERROR );
assert( ptr != NULL );
#endif
char *types = get_str_vevo( event_port, "format" );
lo_server_thread_del_method( s->st, keys[i], types );
free(keys[i]);
if(types)
free(types);
free(ptr);
}
free(keys);
}
//@ fallback handler!
int osc_rest_handler( const char *path, const char *types,
lo_arg **argv, int argc, void *data, void *user_data )
{
veejay_msg(0, "Incoming OSC Path '%s' not recognized", path );
return 0;
}
char *osc_get_uri(void *data)
{
lo_address a = lo_message_get_source(data);
char *uri = lo_address_get_url(a);
return uri;
}
//@ plugin handler!
int osc_plugin_handler( const char *path, const char *types,
lo_arg **argv, int argc, void *data, void *user_data )
{
plugin_data_t *pd = (plugin_data_t*) user_data;
veejay_t *info = pd->caller;
veejay_lock(info,__FUNCTION__);
char *uri = osc_get_uri( data );
free(uri);
veejay_msg(0, "%s: client '%s', %s" , __FUNCTION__, uri,path );
// char *uri = osc_get_uri( data );
// veejay_set_current_client( info, uri );
// free(uri);
char *required_format = plug_get_osc_format( pd->instance, pd->seq );
if( strcmp( required_format , types ) != 0 )
{
veejay_msg(0, "Plugin Path %s wrong format '%s' , need '%s'",
path,types, required_format );
veejay_unlock(info,__FUNCTION__ );
return 0;
}
int n_elem = strlen(required_format);
#ifdef STRICT_CHECKING
assert( n_elem == argc );
#endif
int k;
if( types[0] == 'i' )
{
int32_t *elements = (int32_t*) vj_malloc(sizeof(int32_t) * n_elem );
for( k = 0; k < n_elem; k ++ )
elements[k] = argv[k]->i32;
plug_set_parameter( pd->instance, pd->seq, n_elem, (void*)elements );
free(elements);
veejay_unlock( info ,__FUNCTION__ );
return 0;
}
else if( types[0] == 'd' )
{
double *elements = (double*) vj_malloc(sizeof(double) * n_elem );
for( k = 0; k < n_elem; k ++ )
elements[k] = argv[k]->d;
plug_set_parameter( pd->instance, pd->seq, n_elem, (void*) elements );
free(elements);
veejay_unlock( info ,__FUNCTION__ );
return 0;
}
else if( types[0] == 's' )
{
char **strs = vj_malloc(sizeof(char*) * n_elem );
for( k = 0; k < n_elem; k ++ )
strs[k] = strdup( (char*) &argv[k]->s );
plug_set_parameter( pd->instance,pd->seq, n_elem, (void*) strs );
for( k = 0; k < n_elem; k ++ )
if(strs[k]) free(strs[k]);
veejay_unlock( info ,__FUNCTION__ );
return 0;
}
veejay_unlock( info ,__FUNCTION__ );
return 1; //@ try another method
}
int osc_veejay_handler( const char *path, const char *types,
lo_arg **argv, int argc, void *data, void *user_data )
{
plugin_data_t *pd = (plugin_data_t*) user_data;
veejay_t *info = pd->caller;
veejay_lock( info ,__FUNCTION__ );
char *uri = osc_get_uri( data );
veejay_set_current_client( info, uri );
veejay_msg(0, "%s: client '%s', %s" , __FUNCTION__, uri,path );
// format of KEY in path!!
free(uri);
if( veejay_osc_property_calls_event( pd->instance,
path,
types,
argv,
data ))
{
veejay_unlock( info ,__FUNCTION__ );
return 0;
}
veejay_unlock( info ,__FUNCTION__ );
return 1; //@ try another method
}
int osc_sample_handler( const char *path, const char *types,
lo_arg **argv, int argc, void *data, void *user_data )
{
plugin_data_t *pd = (plugin_data_t*) user_data;
veejay_t *info = pd->caller;
veejay_lock( info ,__FUNCTION__ );
char *uri = osc_get_uri( data );
veejay_set_current_client( info, uri );
veejay_msg(0, "%s: client '%s', path %s" , __FUNCTION__, uri ,path);
// format of KEY in path!!
free(uri);
if( sample_osc_property_calls_event( pd->instance,
path,
types,
argv,
data ))
{
veejay_unlock( info ,__FUNCTION__ );
return 0;
}
veejay_msg(0, "%s: %s continues", __FUNCTION__, path );
char *required_format = sample_property_format_osc( pd->instance, path );
if(required_format == NULL )
{
veejay_msg(0, "Plugin Path %s wrong format '%s' , need '%s'",
path,types, required_format );
veejay_unlock( info ,__FUNCTION__ );
return 0;
}
if( strcmp( required_format , types ) != 0 )
{
veejay_msg(0, "Sample Path %s wrong format '%s' , need '%s'",
path,types, required_format );
veejay_unlock( info ,__FUNCTION__ );
return 0;
}
int n_elem = strlen(required_format);
#ifdef STRICT_CHECKING
assert( n_elem == argc );
#endif
int k;
free(required_format);
if( types[0] == 'i' )
{
int32_t *elements = (int32_t*) vj_malloc(sizeof(int32_t) * n_elem );
for( k = 0; k < n_elem; k ++ )
elements[k] = argv[k]->i32;
sample_set_property_from_path( pd->instance, path,n_elem, (void*)elements );
free(elements);
veejay_unlock( info ,__FUNCTION__ );
return 0;
}
else if( types[0] == 'd' )
{
double *elements = (double*) vj_malloc(sizeof(double) * n_elem );
for( k = 0; k < n_elem; k ++ )
elements[k] = argv[k]->d;
sample_set_property_from_path( pd->instance, path,n_elem, (void*)elements );
free(elements);
veejay_unlock( info ,__FUNCTION__ );
return 0;
}
else if( types[0] == 's' )
{
char **strs = vj_malloc(sizeof(char*) * n_elem );
for( k = 0; k < n_elem; k ++ )
strs[k] = strdup( (char*) &argv[k]->s );
sample_set_property_from_path( pd->instance, path, n_elem, (void*)strs );
for( k = 0; k < n_elem; k ++ )
if(strs[k]) free(strs[k]);
veejay_unlock( info ,__FUNCTION__ );
return 0;
}
else if( types[0] == 'h' )
{
uint64_t *elements = vj_malloc(sizeof(uint64_t) * n_elem );
for( k = 0; k < n_elem; k ++ )
elements[k] = argv[k]->h;
sample_set_property_from_path( pd->instance, path, n_elem,(void*) elements );
veejay_unlock( info ,__FUNCTION__ );
return 0;
}
veejay_unlock( info ,__FUNCTION__ );
return 1;
}
void veejay_osc_add_sample_generic_events(void *user_data, void *osc_port, void *vevo_port, const char *base, int fx)
{
veejay_t *info = (veejay_t*) user_data;
osc_recv_t *s = (osc_recv_t*) info->osc_server;
osc_add_sample_generic_events( s->st, user_data,osc_port,vevo_port,base,fx );
}
void veejay_osc_add_sample_nonstream_events(void *user_data, void *osc_port, void *vevo_port, const char *base)
{
veejay_t *info = (veejay_t*) user_data;
osc_recv_t *s = (osc_recv_t*) info->osc_server;
osc_add_sample_nonstream_events( s->st, user_data,osc_port,vevo_port,base );
}
void veejay_osc_namespace_events(void *user_data, const char *base)
{
veejay_t *info = (veejay_t*) user_data;
osc_recv_t *s = (osc_recv_t*) info->osc_server;
osc_add_veejay_events( s->st, user_data, info->osc_namespace,base );
}
void *veejay_new_osc_server( void *data, const char *port )
{
osc_recv_t *s = (osc_recv_t*) vj_malloc(sizeof( osc_recv_t));
s->st = lo_server_thread_new( port, error_handler );
lo_server_thread_start( s->st );
s->url = lo_server_thread_get_url( s->st );
s->port = lo_server_thread_get_port( s->st );
veejay_msg( 0, "OSC server '%s' ready",s->url );
return (void*) s;
}
char *veejay_osc_server_get_addr( void *data )
{
osc_recv_t *s = (osc_recv_t*) data;
return s->url;
}
int veejay_osc_server_get_port( void *data )
{
osc_recv_t *s = (osc_recv_t*) data;
return s->port;
}
static int servit_new_event(
void *userdata,
void *osc_space,
void *instance,
const char *base,
const char *key,
const char *fmt,
const char **args,
const char *descr,
vevo_event_f *func,
int extra_token,
void *ptemplate,
lo_method_handler method )
{
veejay_t *info = (veejay_t*) userdata;
osc_recv_t *s = (osc_recv_t*) info->osc_server;
#ifdef STRICT_CHECKING
void *p = (void*) vevo_port_new( VEVO_ANONYMOUS_PORT,__FUNCTION__,__LINE__ );
#else
void *p = (void*) vevo_port_new( VEVO_ANONYMOUS_PORT );
#endif
int error;
if( func )
{
error = vevo_property_set( p, "func", VEVO_ATOM_TYPE_VOIDPTR,1,&func );
#ifdef STRICT_CHECKING
assert( error == VEVO_NO_ERROR );
#endif
}
if( fmt == NULL )
error = vevo_property_set( p, "format", VEVO_ATOM_TYPE_STRING,0,NULL );
else
error = vevo_property_set( p, "format", VEVO_ATOM_TYPE_STRING,1, &fmt );
#ifdef STRICT_CHECKING
assert( error == VEVO_NO_ERROR );
#endif
if( descr == NULL )
error = vevo_property_set(p, "description",VEVO_ATOM_TYPE_STRING,0, NULL );
else
error = vevo_property_set(p, "description", VEVO_ATOM_TYPE_STRING,1, &descr );
#ifdef STRICT_CHECKING
assert( error == VEVO_NO_ERROR );
#endif
if( ptemplate )
{
error = vevo_property_set( p, "parent", VEVO_ATOM_TYPE_VOIDPTR,1,&ptemplate );
#ifdef STRICT_CHECKING
assert( error == VEVO_NO_ERROR );
#endif
}
/* if( extra_token >= 0)
{
error = vevo_property_set(p, "ref", VEVO_ATOM_TYPE_INT,1, &extra_token );
#ifdef STRICT_CHECKING
assert( error == VEVO_NO_ERROR );
#endif
}*/
if( args )
{
int i;
for( i = 0;i < 4; i ++ )
{
if(args[i])
{
char index[10];
sprintf(index,"help_%d",i);
error = vevo_property_set( p, index, VEVO_ATOM_TYPE_STRING,1,&(args[i]) );
#ifdef STRICT_CHECKING
assert( error == VEVO_NO_ERROR );
#endif
}
}
}
plugin_data_t *pd = (plugin_data_t*) vj_malloc(sizeof(plugin_data_t));
pd->seq = extra_token;
pd->caller = userdata;
pd->instance = instance;
error = vevo_property_set( p,
"userdata",
VEVO_ATOM_TYPE_VOIDPTR,
1,
&pd );
#ifdef STRICT_CHECKING
assert( error == VEVO_NO_ERROR );
#endif
char *tmp_path = NULL;
if( base)
tmp_path = osc_create_path( base, key );
else
tmp_path = strdup(key);
char *my_path = veejay_valid_osc_name( tmp_path );
error = vevo_property_set( osc_space,
my_path,
VEVO_ATOM_TYPE_PORTPTR,
1,
&p );
#ifdef STRICT_CHECKING
assert( error == VEVO_NO_ERROR );
#endif
lo_server_thread_add_method(
s->st,
my_path,
fmt,
method,
(void*) pd );
free(my_path);
free(tmp_path);
return VEVO_NO_ERROR;
}
int vevosample_new_event(
void *userdata,
void *osc_space,
void *instance,
const char *base,
const char *key,
const char *fmt,
const char **args,
const char *descr,
vevo_event_f *func,
int extra_token)
{
return servit_new_event( userdata,osc_space,instance,base,key,fmt,args,descr,func,extra_token,NULL,
osc_sample_handler );
}
int veejay_new_event(
void *userdata,
void *osc_space,
void *instance,
const char *base,
const char *key,
const char *fmt,
const char **args,
const char *descr,
vevo_event_f *func,
int extra_token)
{
return servit_new_event( userdata,osc_space,instance,base,key,fmt,args,descr,func,extra_token,NULL,
osc_veejay_handler );
}
int plugin_new_event(
void *userdata,
void *osc_space,
void *instance,
const char *base,
const char *key,
const char *fmt,
const char **args,
const char *descr,
vevo_event_f *func,
int extra_token,
void *ptempl )
{
return servit_new_event( userdata,osc_space,instance,base,key,fmt,args,descr,func,extra_token,ptempl,
osc_plugin_handler );
}
void veejay_free_osc_server( void *dosc )
{
osc_recv_t *s = (osc_recv_t*) dosc;
lo_server_thread_stop( s->st );
lo_server_thread_free( s->st );
free(s->url);
// vevo_port_free( s->events );
free(s);
s = NULL;
}
#endif