root / src / spin / spinBaseContext.cpp @ aeb73a09
History | View | Annotate | Download (38.9 kB)
| 1 |
// -----------------------------------------------------------------------------
|
|---|---|
| 2 |
// | ___ ___ _ _ _ ___ _ |
|
| 3 |
// | / __>| . \| || \ | | __>_ _ ___ ._ _ _ ___ _ _ _ ___ _ _ | |__ |
|
| 4 |
// | \__ \| _/| || | | _>| '_><_> || ' ' |/ ._>| | | |/ . \| '_>| / / |
|
| 5 |
// | <___/|_| |_||_\_| |_| |_| <___||_|_|_|\___.|__/_/ \___/|_| |_\_\ |
|
| 6 |
// | |
|
| 7 |
// |---------------------------------------------------------------------------|
|
| 8 |
//
|
| 9 |
// http://spinframework.sourceforge.net
|
| 10 |
// Copyright (C) 2009 Mike Wozniewski, Zack Settel
|
| 11 |
//
|
| 12 |
// Developed/Maintained by:
|
| 13 |
// Mike Wozniewski (http://www.mikewoz.com)
|
| 14 |
// Zack Settel (http://www.sheefa.net/zack)
|
| 15 |
//
|
| 16 |
// Principle Partners:
|
| 17 |
// Shared Reality Lab, McGill University (http://www.cim.mcgill.ca/sre)
|
| 18 |
// La Societe des Arts Technologiques (http://www.sat.qc.ca)
|
| 19 |
//
|
| 20 |
// Funding by:
|
| 21 |
// NSERC/Canada Council for the Arts - New Media Initiative
|
| 22 |
// Heritage Canada
|
| 23 |
// Ministere du Developpement economique, de l'Innovation et de l'Exportation
|
| 24 |
//
|
| 25 |
// -----------------------------------------------------------------------------
|
| 26 |
// This file is part of the SPIN Framework.
|
| 27 |
//
|
| 28 |
// SPIN Framework is free software: you can redistribute it and/or modify
|
| 29 |
// it under the terms of the GNU Lesser General Public License as published by
|
| 30 |
// the Free Software Foundation, either version 3 of the License, or
|
| 31 |
// (at your option) any later version.
|
| 32 |
//
|
| 33 |
// SPIN Framework is distributed in the hope that it will be useful,
|
| 34 |
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 35 |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 36 |
// GNU Lesser General Public License for more details.
|
| 37 |
//
|
| 38 |
// You should have received a copy of the GNU Lesser General Public License
|
| 39 |
// along with SPIN Framework. If not, see <http://www.gnu.org/licenses/>.
|
| 40 |
// -----------------------------------------------------------------------------
|
| 41 |
|
| 42 |
|
| 43 |
#include <string> |
| 44 |
#include <iostream> |
| 45 |
#include <pthread.h> |
| 46 |
#include <signal.h> |
| 47 |
#include <boost/lexical_cast.hpp> |
| 48 |
|
| 49 |
#include <osgDB/Registry> |
| 50 |
#include <cppintrospection/Type> |
| 51 |
#include <cppintrospection/Value> |
| 52 |
#include <osgUtil/Optimizer> |
| 53 |
#include <osg/Version> |
| 54 |
|
| 55 |
#include <boost/filesystem/operations.hpp> |
| 56 |
#include <boost/filesystem/exception.hpp> |
| 57 |
#ifndef DISABLE_PYTHON
|
| 58 |
#include <boost/python.hpp> |
| 59 |
#endif
|
| 60 |
|
| 61 |
#include <lo/lo.h> |
| 62 |
#include <lo/lo_lowlevel.h> |
| 63 |
|
| 64 |
#include "SceneManager.h" |
| 65 |
#include "spinBaseContext.h" |
| 66 |
#include "spinServerContext.h" |
| 67 |
#include "spinClientContext.h" |
| 68 |
#include "spinUtil.h" |
| 69 |
#include "spinApp.h" |
| 70 |
#include "spinLog.h" |
| 71 |
#include "nodeVisitors.h" |
| 72 |
#include "SoundConnection.h" |
| 73 |
#include "spinDefaults.h" |
| 74 |
#include "config.h" |
| 75 |
|
| 76 |
#ifdef WITH_SPATOSC
|
| 77 |
#include <spatosc/spatosc.h> |
| 78 |
#endif
|
| 79 |
|
| 80 |
|
| 81 |
#define UNUSED(x) ( (void)(x) ) |
| 82 |
|
| 83 |
// TODO: make mutex a static member (perhaps of spinApp)?
|
| 84 |
pthread_mutex_t sceneMutex = PTHREAD_MUTEX_INITIALIZER; |
| 85 |
|
| 86 |
namespace spin
|
| 87 |
{
|
| 88 |
|
| 89 |
/**
|
| 90 |
* All threads need to stop according to the following flag. Note this used to |
| 91 |
* be a public class member, but we have sigHandler, which should be used |
| 92 |
* instead |
| 93 |
*/ |
| 94 |
//namespace {
|
| 95 |
// volatile bool signalStop;
|
| 96 |
//}
|
| 97 |
volatile bool spinBaseContext::signalStop = false; |
| 98 |
|
| 99 |
spinBaseContext::spinBaseContext() : |
| 100 |
lo_infoAddr(NULL),
|
| 101 |
lo_syncAddr(NULL),
|
| 102 |
lo_infoServ_(NULL),
|
| 103 |
lo_tcpRxServer_(NULL),
|
| 104 |
pthreadID(0),
|
| 105 |
doDiscovery_(true),
|
| 106 |
autoPorts_(true),
|
| 107 |
running(false)
|
| 108 |
{
|
| 109 |
using namespace spin_defaults; |
| 110 |
|
| 111 |
signalStop = true;
|
| 112 |
signal(SIGINT, sigHandler); |
| 113 |
|
| 114 |
// set default addresses (can be overridden):
|
| 115 |
lo_infoAddr = lo_address_new(MULTICAST_GROUP, INFO_UDP_PORT); |
| 116 |
//lo_rxAddrs.push_back(lo_address_new(MULTICAST_GROUP, CLIENT_RX_UDP_PORT));
|
| 117 |
//lo_txAddrs_.push_back(lo_address_new(MULTICAST_GROUP, CLIENT_TX_UDP_PORT));
|
| 118 |
lo_syncAddr = lo_address_new(MULTICAST_GROUP, SYNC_UDP_PORT); |
| 119 |
|
| 120 |
|
| 121 |
tcpPort_ = SERVER_TCP_PORT; |
| 122 |
|
| 123 |
// override infoPort based on environment variable:
|
| 124 |
char *infoPortStr = getenv("AS_INFOPORT"); |
| 125 |
if (infoPortStr)
|
| 126 |
{
|
| 127 |
std::string tmpStr = std::string(infoPortStr); |
| 128 |
std::string infoAddr = tmpStr.substr(0, tmpStr.rfind(":")); |
| 129 |
std::string infoPort = tmpStr.substr(tmpStr.find(":") + 1); |
| 130 |
lo_address_free(lo_infoAddr); |
| 131 |
lo_infoAddr = lo_address_new(infoAddr.c_str(), infoPort.c_str()); |
| 132 |
} |
| 133 |
} |
| 134 |
|
| 135 |
spinBaseContext::~spinBaseContext() |
| 136 |
{
|
| 137 |
this->stop();
|
| 138 |
|
| 139 |
std::vector<lo_address>::iterator addrIter; |
| 140 |
for (addrIter = lo_txAddrs_.begin(); addrIter != lo_txAddrs_.end(); ++addrIter)
|
| 141 |
{
|
| 142 |
lo_address_free(*addrIter); |
| 143 |
} |
| 144 |
lo_txAddrs_.clear(); |
| 145 |
|
| 146 |
for (addrIter = lo_rxAddrs_.begin(); addrIter != lo_rxAddrs_.end(); ++addrIter)
|
| 147 |
{
|
| 148 |
lo_address_free(*addrIter); |
| 149 |
} |
| 150 |
lo_rxAddrs_.clear(); |
| 151 |
|
| 152 |
std::vector<lo_server>::iterator servIter; |
| 153 |
for (servIter = lo_rxServs_.begin(); servIter != lo_rxServs_.end(); ++servIter)
|
| 154 |
lo_server_free(*servIter); |
| 155 |
lo_rxServs_.clear(); |
| 156 |
|
| 157 |
lo_address_free(lo_infoAddr); |
| 158 |
lo_address_free(lo_syncAddr); |
| 159 |
|
| 160 |
// stop sceneManager OSC threads:
|
| 161 |
//usleep(100);
|
| 162 |
|
| 163 |
lo_server_free(lo_infoServ_); |
| 164 |
lo_server_free(lo_tcpRxServer_); |
| 165 |
} |
| 166 |
|
| 167 |
void spinBaseContext::debugPrint()
|
| 168 |
{
|
| 169 |
std::cout << "\nSPIN context information:" << std::endl;
|
| 170 |
std::cout << " SceneManager ID:\t\t" << spinApp::Instance().getSceneID() << std::endl;
|
| 171 |
std::cout << " Resources path:\t\t" << spinApp::Instance().sceneManager->resourcesPath << std::endl;
|
| 172 |
std::cout << " SPIN version:\t\t\t" << PACKAGE_VERSION << "" << std::endl; |
| 173 |
std::cout << " OSG version:\t\t\t" << osgGetVersion() << "" << std::endl; |
| 174 |
#ifdef WITH_SPATOSC
|
| 175 |
std::cout << " SpatOSC version:\t\t"<< SPATOSC_VERSION << " (enabled=" << spinApp::Instance().hasAudioRenderer << ")" << std::endl; |
| 176 |
#else
|
| 177 |
std::cout << " SpatOSC version:\t\tDISABLED" << std::endl;
|
| 178 |
#endif
|
| 179 |
|
| 180 |
#ifdef WITH_SHARED_VIDEO
|
| 181 |
std::cout << " sharedvideo enabled?\t\tYES" << std::endl;
|
| 182 |
#else
|
| 183 |
std::cout << " sharedvideo enabled?\t\tNO" << std::endl;
|
| 184 |
#endif
|
| 185 |
std::cout << " My IP address:\t\t" << getMyIPaddress() << std::endl;
|
| 186 |
if (doDiscovery_)
|
| 187 |
{
|
| 188 |
std::cout << " Auto discovery addr:\t\t" << lo_address_get_url(lo_infoAddr);
|
| 189 |
if (lo_address_get_ttl(lo_infoAddr)>0) |
| 190 |
std::cout << " TTL=" << lo_address_get_ttl(lo_infoAddr);
|
| 191 |
std::cout << std::endl; |
| 192 |
} else {
|
| 193 |
std::cout << " Auto discovery addr:\tOFF" << std::endl;
|
| 194 |
} |
| 195 |
std::vector<lo_address>::iterator addrIter; |
| 196 |
for (addrIter = lo_txAddrs_.begin(); addrIter != lo_txAddrs_.end(); ++addrIter)
|
| 197 |
{
|
| 198 |
std::cout << " Sending UDP to:\t\t" << lo_address_get_url(*addrIter);
|
| 199 |
if (lo_address_get_ttl(*addrIter)>0) |
| 200 |
std::cout << " TTL=" << lo_address_get_ttl(*addrIter);
|
| 201 |
std::cout << std::endl; |
| 202 |
} |
| 203 |
std::vector<lo_server>::iterator servIter; |
| 204 |
for (servIter = lo_rxServs_.begin(); servIter != lo_rxServs_.end(); ++servIter)
|
| 205 |
{
|
| 206 |
std::cout << " Receiving UDP on:\t\t" << lo_server_get_url(*servIter) << std::endl;
|
| 207 |
} |
| 208 |
} |
| 209 |
|
| 210 |
void spinBaseContext::addCommandLineOptions(osg::ArgumentParser *arguments)
|
| 211 |
{
|
| 212 |
arguments->getApplicationUsage()->addCommandLineOption("-h or --help", "Display this information"); |
| 213 |
arguments->getApplicationUsage()->addCommandLineOption("--version", "Display the version number and exit."); |
| 214 |
arguments->getApplicationUsage()->addCommandLineOption("--scene-id <id>", "Specify the id of the SPIN scene (Default: default)"); |
| 215 |
arguments->getApplicationUsage()->addCommandLineOption("--disable-discovery", "Disables the multicast discovery service"); |
| 216 |
arguments->getApplicationUsage()->addCommandLineOption("--spatosc <translator> <URL>", "Enables SPIN's internal SpatOSC scene. Example: --spatosc BasicTranslator osc.tcp://localhost:18033"); |
| 217 |
|
| 218 |
// TODO: add discovery addr <host> <port> (defaults is MULTICAST_GROUP:INFO_UDP_PORT)
|
| 219 |
// for a client, this would be --recv-udp-discovery <host> <port>
|
| 220 |
// for a server, this would be --send-udp-discovery <host> <port>
|
| 221 |
} |
| 222 |
|
| 223 |
int spinBaseContext::parseCommandLineOptions(osg::ArgumentParser *arguments)
|
| 224 |
{
|
| 225 |
// if user request help or version write it out to cout and quit.
|
| 226 |
if (arguments->read("-h") || arguments->read("--help")) |
| 227 |
{
|
| 228 |
arguments->getApplicationUsage()->write(std::cout); |
| 229 |
return 0; |
| 230 |
} |
| 231 |
if (arguments->read("--version")) |
| 232 |
{
|
| 233 |
std::cout << VERSION << std::endl; |
| 234 |
return 0; |
| 235 |
} |
| 236 |
|
| 237 |
std::string sceneID;
|
| 238 |
if (arguments->read("--scene-id", sceneID)) |
| 239 |
{
|
| 240 |
spinApp::Instance().setSceneID(sceneID); |
| 241 |
} |
| 242 |
|
| 243 |
if (arguments->read("--disable-discovery")) |
| 244 |
{
|
| 245 |
doDiscovery_ = false;
|
| 246 |
} |
| 247 |
|
| 248 |
// set up SpatOSC:
|
| 249 |
std::string translatorID, translatorType, translatorAddr, translatorPort;
|
| 250 |
int translatorCount = 0; |
| 251 |
while (arguments->read("--spatosc", translatorType, translatorAddr)) |
| 252 |
{
|
| 253 |
#ifdef WITH_SPATOSC
|
| 254 |
translatorID = "translator"+stringify(translatorCount++);
|
| 255 |
spinApp::Instance().audioScene->addTranslator(translatorID, translatorType, translatorAddr); |
| 256 |
spinApp::Instance().hasAudioRenderer = true;
|
| 257 |
#else
|
| 258 |
std::cout << "WARNING: commandline option --spatosc not accepted. This version of SPIN was not built with support for SpatOSC." << std::endl;
|
| 259 |
#endif
|
| 260 |
} |
| 261 |
|
| 262 |
return 1; |
| 263 |
} |
| 264 |
|
| 265 |
void spinBaseContext::setLog(spinLog &log)
|
| 266 |
{
|
| 267 |
std::vector<lo_server>::iterator it; |
| 268 |
for (it = lo_rxServs_.begin(); it != lo_rxServs_.end(); ++it)
|
| 269 |
{
|
| 270 |
lo_server_add_method((*it), NULL, NULL, logCallback, &log); |
| 271 |
} |
| 272 |
} |
| 273 |
|
| 274 |
void spinBaseContext::sigHandler(int signum) |
| 275 |
{
|
| 276 |
std::cout << "SPIN thread caught signal: " << signum << std::endl;
|
| 277 |
|
| 278 |
spinBaseContext::signalStop = true;
|
| 279 |
static int interruptCount = 0; |
| 280 |
const static int MAX_INTERRUPTS = 2; |
| 281 |
++interruptCount; |
| 282 |
if (interruptCount >= MAX_INTERRUPTS)
|
| 283 |
throw std::runtime_error("Got multiple interrupts, exitting rudely"); |
| 284 |
} |
| 285 |
|
| 286 |
void spinBaseContext::setTTL(int ttl) |
| 287 |
{
|
| 288 |
std::vector<lo_address>::iterator addrIter; |
| 289 |
for (addrIter = lo_txAddrs_.begin(); addrIter != lo_txAddrs_.end(); ++addrIter)
|
| 290 |
lo_address_set_ttl((*addrIter), ttl); |
| 291 |
|
| 292 |
lo_address_set_ttl(lo_infoAddr, ttl); |
| 293 |
lo_address_set_ttl(lo_syncAddr, ttl); |
| 294 |
} |
| 295 |
|
| 296 |
void spinBaseContext::addInfoHandler(EventHandler *obs)
|
| 297 |
{
|
| 298 |
infoHandlers.push_back(obs); |
| 299 |
} |
| 300 |
|
| 301 |
void spinBaseContext::removeInfoHandler(EventHandler *obs)
|
| 302 |
{
|
| 303 |
std::vector<EventHandler*>::iterator it; |
| 304 |
for (it=infoHandlers.begin(); it!=infoHandlers.end(); ++it)
|
| 305 |
{
|
| 306 |
if ((*it)==obs)
|
| 307 |
{
|
| 308 |
infoHandlers.erase(it); |
| 309 |
return;
|
| 310 |
} |
| 311 |
} |
| 312 |
} |
| 313 |
void spinBaseContext::removeHandlerForAllEvents(EventHandler *obs)
|
| 314 |
{
|
| 315 |
removeInfoHandler(obs); |
| 316 |
//removeNodeHandler(obs);
|
| 317 |
//removeSceneHandler(obs);
|
| 318 |
} |
| 319 |
|
| 320 |
/**
|
| 321 |
* Startup point of the server's thread. |
| 322 |
*/ |
| 323 |
bool spinBaseContext::startThread( void *(*threadFunction) (void*) ) |
| 324 |
{
|
| 325 |
signalStop = false;
|
| 326 |
|
| 327 |
// create thread:
|
| 328 |
if (pthread_attr_init(&pthreadAttr) < 0) |
| 329 |
{
|
| 330 |
std::cout << "spinBaseContext: could not prepare child thread" << std::endl;
|
| 331 |
return false; |
| 332 |
} |
| 333 |
/*
|
| 334 |
if (pthread_attr_setdetachstate(&pthreadAttr, PTHREAD_CREATE_DETACHED) < 0) |
| 335 |
{
|
| 336 |
std::cout << "spinBaseContext: could not prepare child thread" << std::endl; |
| 337 |
return false; |
| 338 |
} |
| 339 |
*/ |
| 340 |
if (pthread_create( &pthreadID, &pthreadAttr, threadFunction, this) < 0) |
| 341 |
{
|
| 342 |
std::cout << "spinBaseContext: could not create new thread" << std::endl;
|
| 343 |
return false; |
| 344 |
} |
| 345 |
|
| 346 |
//pthread_join(pthreadID, NULL); // if not DETACHED thread
|
| 347 |
|
| 348 |
// wait until the thread gets into it's loop before returning:
|
| 349 |
while (! running )
|
| 350 |
usleep(10);
|
| 351 |
|
| 352 |
return true; |
| 353 |
} |
| 354 |
|
| 355 |
void spinBaseContext::stop()
|
| 356 |
{
|
| 357 |
if (isRunning())
|
| 358 |
signalStop = true;
|
| 359 |
|
| 360 |
if (pthreadID != 0) |
| 361 |
{
|
| 362 |
pthread_join(pthreadID, NULL);
|
| 363 |
} |
| 364 |
|
| 365 |
// wait here until the thread has really exited:
|
| 366 |
while (isRunning())
|
| 367 |
usleep(10);
|
| 368 |
|
| 369 |
} |
| 370 |
|
| 371 |
int spinBaseContext::connectionCallback(const char *path, |
| 372 |
const char *types, |
| 373 |
lo_arg **argv, |
| 374 |
int argc,
|
| 375 |
void * /*data*/, |
| 376 |
void *user_data)
|
| 377 |
{
|
| 378 |
std::string idStr;
|
| 379 |
std::string theMethod;
|
| 380 |
|
| 381 |
// make sure there is at least one argument (ie, a method to call):
|
| 382 |
if (! argc)
|
| 383 |
return 1; |
| 384 |
|
| 385 |
// get the method (argv[0]):
|
| 386 |
if (lo_is_string_type((lo_type) types[0])) |
| 387 |
{
|
| 388 |
theMethod = std::string((char *) argv[0]); |
| 389 |
} |
| 390 |
else
|
| 391 |
return 1; |
| 392 |
|
| 393 |
// get the instance of the connection:
|
| 394 |
SoundConnection *conn = (SoundConnection*) user_data; |
| 395 |
if (! conn)
|
| 396 |
{
|
| 397 |
std::cout << "oscParser: Could not find connection: " << idStr << std::endl;
|
| 398 |
return 1; |
| 399 |
} |
| 400 |
|
| 401 |
// TODO: replace method call with osg::Introspection
|
| 402 |
|
| 403 |
if (theMethod == "stateDump") |
| 404 |
conn->stateDump(); |
| 405 |
else if (theMethod == "debug") |
| 406 |
conn->debug(); |
| 407 |
else if ((argc==2) && (lo_is_numerical_type((lo_type) types[1]))) |
| 408 |
{
|
| 409 |
float value = lo_hires_val((lo_type) types[1], argv[1]); |
| 410 |
|
| 411 |
if (theMethod == "setThru") |
| 412 |
conn->setThru((bool) value);
|
| 413 |
else if (theMethod == "setDistanceEffect") |
| 414 |
conn->setDistanceEffect(value); |
| 415 |
else if (theMethod == "setRolloffEffect") |
| 416 |
conn->setRolloffEffect(value); |
| 417 |
else if (theMethod == "setDopplerEffect") |
| 418 |
conn->setDopplerEffect(value); |
| 419 |
else if (theMethod == "setDiffractionEffect") |
| 420 |
conn->setDiffractionEffect(value); |
| 421 |
else
|
| 422 |
std::cout << "Unknown OSC command: " << path << " " << theMethod << " (with " << argc-1 << " args)" << std::endl; |
| 423 |
} |
| 424 |
else
|
| 425 |
std::cout << "Unknown OSC command: " << path << " " << theMethod << " (with " << argc-1 << " args)" << std::endl; |
| 426 |
return 1; |
| 427 |
} |
| 428 |
|
| 429 |
int spinBaseContext::nodeCallback(const char *path, const char *types, lo_arg **argv, int argc, void * /*data*/, void *user_data) |
| 430 |
{
|
| 431 |
// NOTE: user_data is a t_symbol pointer
|
| 432 |
// FIXME: this method is way too long
|
| 433 |
|
| 434 |
int i;
|
| 435 |
std::string theMethod, nodeStr;
|
| 436 |
cppintrospection::ValueList theArgs; |
| 437 |
|
| 438 |
// make sure there is at least one argument (ie, a method to call):
|
| 439 |
if (! argc)
|
| 440 |
return 1; |
| 441 |
// get the method (argv[0]):
|
| 442 |
if (lo_is_string_type((lo_type)types[0])) |
| 443 |
{
|
| 444 |
theMethod = std::string((char *)argv[0]); |
| 445 |
} |
| 446 |
else
|
| 447 |
return 1; |
| 448 |
t_symbol *s = (t_symbol*) user_data; |
| 449 |
|
| 450 |
if (! s->s_thing)
|
| 451 |
{
|
| 452 |
std::cout << "oscParser: Could not find referenced object named: " << nodeStr << std::endl;
|
| 453 |
return 1; |
| 454 |
} |
| 455 |
|
| 456 |
// get osgInrospection::Value from passed UserData by casting as the proper
|
| 457 |
// referenced object pointer:
|
| 458 |
|
| 459 |
cppintrospection::Value classInstance; |
| 460 |
if (s->s_type == REFERENCED_STATESET)
|
| 461 |
{
|
| 462 |
classInstance = cppintrospection::Value(dynamic_cast<ReferencedStateSet*>(s->s_thing));
|
| 463 |
} |
| 464 |
else
|
| 465 |
{
|
| 466 |
classInstance = cppintrospection::Value(dynamic_cast<ReferencedNode*>(s->s_thing));
|
| 467 |
} |
| 468 |
|
| 469 |
// the getInstanceType() method however, gives us the real type being pointed at:
|
| 470 |
const cppintrospection::Type &classType = classInstance.getInstanceType();
|
| 471 |
|
| 472 |
if (! classType.isDefined())
|
| 473 |
{
|
| 474 |
std::cout << "ERROR: oscParser cound not process message '" << path << ". cppintrospection has no data for that node." << std::endl; |
| 475 |
return 1; |
| 476 |
} |
| 477 |
|
| 478 |
spinApp &spin = spinApp::Instance(); |
| 479 |
|
| 480 |
if (theMethod == "addCronScript") |
| 481 |
{
|
| 482 |
// client or server?
|
| 483 |
if (! lo_is_numerical_type((lo_type)types[1])) |
| 484 |
{
|
| 485 |
std::string s((const char*) argv[1]); |
| 486 |
if (s[0] == 'S' || s[0] == 's') |
| 487 |
{
|
| 488 |
if (! spin.getContext()->isServer())
|
| 489 |
return 0; |
| 490 |
theArgs.push_back(true);
|
| 491 |
} |
| 492 |
else if (s[0] == 'C' || s[0] == 'c') |
| 493 |
{
|
| 494 |
if (spin.getContext()->isServer())
|
| 495 |
{
|
| 496 |
lo_message msg = lo_message_new(); |
| 497 |
for (int i = 0; i < argc; i++) |
| 498 |
{
|
| 499 |
if (lo_is_numerical_type((lo_type) types[i]))
|
| 500 |
{
|
| 501 |
lo_message_add_float(msg, (float) lo_hires_val((lo_type) types[i], argv[i]));
|
| 502 |
} |
| 503 |
else
|
| 504 |
{
|
| 505 |
lo_message_add_string(msg, (const char*) argv[i] ); |
| 506 |
} |
| 507 |
} |
| 508 |
std::vector<lo_address>::iterator addrIter; |
| 509 |
for (addrIter = spin.getContext()->lo_txAddrs_.begin(); addrIter != spin.getContext()->lo_txAddrs_.end(); ++addrIter)
|
| 510 |
{
|
| 511 |
lo_send_message_from((*addrIter), spin.getContext()->lo_infoServ_, path, msg); |
| 512 |
} |
| 513 |
} |
| 514 |
theArgs.push_back(false); // serverSide arg |
| 515 |
} |
| 516 |
else
|
| 517 |
{
|
| 518 |
std::cout << "wrong server / client specifier... must be C or S" << std::endl;
|
| 519 |
} |
| 520 |
|
| 521 |
} |
| 522 |
else
|
| 523 |
{
|
| 524 |
std::cout << "ERROR: client or server specifier for addCronScript is not a char" << std::endl;
|
| 525 |
return 1; |
| 526 |
} |
| 527 |
|
| 528 |
// label
|
| 529 |
if (! lo_is_numerical_type((lo_type)types[2])) |
| 530 |
{
|
| 531 |
theArgs.push_back(std::string((const char*) argv[2])); |
| 532 |
} |
| 533 |
else
|
| 534 |
{
|
| 535 |
std::cout << "ERROR: label for addCronScript is not a string" << std::endl;
|
| 536 |
return 1; |
| 537 |
} |
| 538 |
|
| 539 |
// Script path
|
| 540 |
if (! lo_is_numerical_type((lo_type) types[3])) |
| 541 |
{
|
| 542 |
theArgs.push_back(std::string((const char*) argv[3])); |
| 543 |
} else {
|
| 544 |
std::cout << "ERROR: script path for addCronScript is not a string" << std::endl;
|
| 545 |
return 1; |
| 546 |
} |
| 547 |
|
| 548 |
// frequency
|
| 549 |
if (lo_is_numerical_type((lo_type) types[4])) |
| 550 |
{
|
| 551 |
theArgs.push_back((double) lo_hires_val((lo_type) types[4], argv[4]) ); |
| 552 |
} |
| 553 |
else
|
| 554 |
{
|
| 555 |
std::cout << "ERROR: frequency for addCronScript is not a number" << std::endl;
|
| 556 |
return 1; |
| 557 |
} |
| 558 |
|
| 559 |
// rest of args are comma separated and passed as a string
|
| 560 |
std::stringstream params("");
|
| 561 |
for (i = 5; i < argc; i++) |
| 562 |
{
|
| 563 |
if (lo_is_numerical_type((lo_type) types[i]))
|
| 564 |
{
|
| 565 |
params << ", " << (float) lo_hires_val((lo_type) types[i], argv[i]); |
| 566 |
} |
| 567 |
else
|
| 568 |
{
|
| 569 |
params << ", \"" << (const char*)argv[i] << "\""; |
| 570 |
} |
| 571 |
} |
| 572 |
theArgs.push_back(params.str()); |
| 573 |
} |
| 574 |
else if (theMethod == "addEventScript") |
| 575 |
{
|
| 576 |
// client or server?
|
| 577 |
if (! lo_is_numerical_type((lo_type) types[1])) |
| 578 |
{ /// (lo_type)types[1] == LO_CHAR )
|
| 579 |
std::string s((const char*) argv[1]); |
| 580 |
if (s[0] == 'S' || s[0] == 's') |
| 581 |
{
|
| 582 |
if (! spin.getContext()->isServer())
|
| 583 |
return 0; |
| 584 |
theArgs.push_back(true);
|
| 585 |
} |
| 586 |
else if (s[0] == 'C' || s[0] == 'c') |
| 587 |
{
|
| 588 |
if (spin.getContext()->isServer())
|
| 589 |
{
|
| 590 |
lo_message msg = lo_message_new(); |
| 591 |
for (int i = 0; i < argc; i++) |
| 592 |
{
|
| 593 |
if (lo_is_numerical_type((lo_type) types[i]))
|
| 594 |
{
|
| 595 |
lo_message_add_float(msg, (float) lo_hires_val((lo_type) types[i], argv[i]));
|
| 596 |
} |
| 597 |
else
|
| 598 |
{
|
| 599 |
lo_message_add_string(msg, (const char*) argv[i]); |
| 600 |
} |
| 601 |
} |
| 602 |
std::vector<lo_address>::iterator addrIter; |
| 603 |
for (addrIter = spin.getContext()->lo_txAddrs_.begin(); addrIter != spin.getContext()->lo_txAddrs_.end(); ++addrIter)
|
| 604 |
{
|
| 605 |
lo_send_message_from((*addrIter), spin.getContext()->lo_infoServ_, path, msg); |
| 606 |
} |
| 607 |
} |
| 608 |
theArgs.push_back(false); // serverSide arg |
| 609 |
} |
| 610 |
} |
| 611 |
else
|
| 612 |
{
|
| 613 |
std::cout << "ERROR: client or server specifier for addCronScript is not a char" << std::endl;
|
| 614 |
return 1; |
| 615 |
} |
| 616 |
|
| 617 |
// label
|
| 618 |
if (! lo_is_numerical_type((lo_type) types[2])) { |
| 619 |
theArgs.push_back(std::string((const char*) argv[2])); |
| 620 |
} |
| 621 |
else
|
| 622 |
{
|
| 623 |
std::cout << "ERROR: label for addEventScript is not a string" << std::endl;
|
| 624 |
return 1; |
| 625 |
} |
| 626 |
|
| 627 |
// event method name
|
| 628 |
if (! lo_is_numerical_type((lo_type) types[3])) |
| 629 |
{
|
| 630 |
theArgs.push_back(std::string((const char*) argv[3])); |
| 631 |
} |
| 632 |
else
|
| 633 |
{
|
| 634 |
std::cout << "ERROR: event method name for addEventScript is not a string" << std::endl;
|
| 635 |
return 1; |
| 636 |
} |
| 637 |
|
| 638 |
// Script path
|
| 639 |
if (! lo_is_numerical_type((lo_type) types[4])) |
| 640 |
{
|
| 641 |
theArgs.push_back(std::string((const char*) argv[4])); |
| 642 |
} |
| 643 |
else
|
| 644 |
{
|
| 645 |
std::cout << "ERROR: script path for addEventScript is not a string" << std::endl;
|
| 646 |
return 1; |
| 647 |
} |
| 648 |
|
| 649 |
// rest of args are comma separated and passed as a string
|
| 650 |
std::stringstream params("");
|
| 651 |
for (i = 5; i < argc; i++) |
| 652 |
{
|
| 653 |
if (lo_is_numerical_type((lo_type) types[i]))
|
| 654 |
{
|
| 655 |
params << ", " << (float) lo_hires_val((lo_type) types[i], argv[i]); |
| 656 |
} |
| 657 |
else
|
| 658 |
{
|
| 659 |
params << ", \"" << (const char*) argv[i] << "\""; |
| 660 |
} |
| 661 |
} |
| 662 |
theArgs.push_back(params.str()); |
| 663 |
} |
| 664 |
else
|
| 665 |
{
|
| 666 |
for (i = 1; i < argc; i++) |
| 667 |
{
|
| 668 |
if (lo_is_numerical_type((lo_type)types[i]))
|
| 669 |
{
|
| 670 |
theArgs.push_back((float) lo_hires_val((lo_type)types[i], argv[i]));
|
| 671 |
} |
| 672 |
else
|
| 673 |
{
|
| 674 |
theArgs.push_back((const char*) argv[i]); |
| 675 |
} |
| 676 |
} |
| 677 |
} |
| 678 |
|
| 679 |
if (spin.getContext()->isServer() &&
|
| 680 |
(theMethod == "enableCronScript" || theMethod == "removeCronScript" || |
| 681 |
theMethod == "enableEventScript" || theMethod == "removeEventScript")) |
| 682 |
{
|
| 683 |
lo_message msg = lo_message_new(); |
| 684 |
for (int i = 0; i < argc; i++) |
| 685 |
{
|
| 686 |
if (lo_is_numerical_type((lo_type)types[i]))
|
| 687 |
{
|
| 688 |
lo_message_add_float(msg, (float) lo_hires_val((lo_type)types[i], argv[i]));
|
| 689 |
} |
| 690 |
else
|
| 691 |
{
|
| 692 |
lo_message_add_string(msg, (const char*) argv[i] ); |
| 693 |
} |
| 694 |
} |
| 695 |
std::vector<lo_address>::iterator addrIter; |
| 696 |
for (addrIter = spin.getContext()->lo_txAddrs_.begin(); addrIter != spin.getContext()->lo_txAddrs_.end(); ++addrIter)
|
| 697 |
{
|
| 698 |
lo_send_message_from((*addrIter), spin.getContext()->lo_infoServ_, path, msg); |
| 699 |
} |
| 700 |
} |
| 701 |
|
| 702 |
bool eventScriptCalled = false; |
| 703 |
if ( s->s_type == REFERENCED_NODE )
|
| 704 |
{
|
| 705 |
//printf("calling eventscript...\n");
|
| 706 |
eventScriptCalled = dynamic_cast<ReferencedNode*>(s->s_thing)->callEventScript( theMethod, theArgs );
|
| 707 |
} |
| 708 |
|
| 709 |
if (! eventScriptCalled )
|
| 710 |
{ // if an eventScript was hooked to theMethod, do not execute theMethod. functionality taken over by script
|
| 711 |
// invoke the method on the node, and if it doesn't work, then just forward
|
| 712 |
// the message:
|
| 713 |
|
| 714 |
if (0) // debug print |
| 715 |
{
|
| 716 |
std::cout << "spinBaseContext got node message for: " << s->s_name << " method: " << theMethod << " args:"; |
| 717 |
for (i = 0; i < argc; i++) |
| 718 |
{
|
| 719 |
std::cout << " ";
|
| 720 |
lo_arg_pp((lo_type)types[i], argv[i]); |
| 721 |
} |
| 722 |
std::cout << std::endl; |
| 723 |
} |
| 724 |
|
| 725 |
if (! introspector::invokeMethod(classInstance, classType, theMethod, theArgs))
|
| 726 |
{
|
| 727 |
//std::cout << "Ignoring method '" << theMethod << "' for [" << s->s_name << "], but forwarding message anyway..." << std::endl;
|
| 728 |
// HACK: TODO: fix this
|
| 729 |
if (spin.getContext()->isServer())
|
| 730 |
{
|
| 731 |
lo_message msg = lo_message_new(); |
| 732 |
for (i = 0; i < argc; i++) |
| 733 |
{
|
| 734 |
if (lo_is_numerical_type((lo_type) types[i]))
|
| 735 |
{
|
| 736 |
lo_message_add_float(msg, (float) lo_hires_val((lo_type) types[i], argv[i]));
|
| 737 |
} else {
|
| 738 |
lo_message_add_string(msg, (const char*) argv[i]); |
| 739 |
} |
| 740 |
} |
| 741 |
std::vector<lo_address>::iterator addrIter; |
| 742 |
for (addrIter = spin.getContext()->lo_txAddrs_.begin(); addrIter != spin.getContext()->lo_txAddrs_.end(); ++addrIter)
|
| 743 |
{
|
| 744 |
lo_send_message_from((*addrIter), spin.getContext()->lo_infoServ_, path, msg); |
| 745 |
} |
| 746 |
} |
| 747 |
} |
| 748 |
} |
| 749 |
//pthread_mutex_unlock(&sceneMutex);
|
| 750 |
return 1; |
| 751 |
} |
| 752 |
|
| 753 |
int spinBaseContext::sceneCallback(const char *path, const char *types, lo_arg **argv, int argc, |
| 754 |
void * /*data*/, void * /*user_data*/) |
| 755 |
{
|
| 756 |
if (0) // debug print |
| 757 |
{
|
| 758 |
std::cout << "spinBaseContext got scene message: " << path << " args:"; |
| 759 |
for (unsigned int i=0; i<argc; i++) |
| 760 |
{
|
| 761 |
std::cout << " ";
|
| 762 |
lo_arg_pp((lo_type)types[i], argv[i]); |
| 763 |
} |
| 764 |
std::cout << std::endl; |
| 765 |
} |
| 766 |
|
| 767 |
spinApp &spin = spinApp::Instance(); |
| 768 |
SceneManager *sceneManager = spin.sceneManager; |
| 769 |
|
| 770 |
// make sure there is at least one argument (ie, a method to call):
|
| 771 |
if (!argc) return 1; |
| 772 |
|
| 773 |
// get the method (argv[0]):
|
| 774 |
std::string theMethod;
|
| 775 |
if (lo_is_string_type((lo_type)types[0])) |
| 776 |
theMethod = std::string((char *)argv[0]); |
| 777 |
else
|
| 778 |
return 1; |
| 779 |
|
| 780 |
//pthread_mutex_lock(&sceneMutex);
|
| 781 |
|
| 782 |
// note that args start at argv[1] now:
|
| 783 |
if (theMethod == "debug") |
| 784 |
{
|
| 785 |
if (argc>1) |
| 786 |
{
|
| 787 |
std::string debugType = (const char*)argv[1]; |
| 788 |
if (debugType=="context") |
| 789 |
sceneManager->debugContext(); |
| 790 |
else if (debugType=="nodes") |
| 791 |
sceneManager->debugNodes(); |
| 792 |
else if (debugType=="statesets") |
| 793 |
sceneManager->debugStateSets(); |
| 794 |
else if (debugType=="scenegraph") |
| 795 |
sceneManager->debugSceneGraph(); |
| 796 |
else if (debugType=="spatosc") |
| 797 |
{
|
| 798 |
#ifdef WITH_SPATOSC
|
| 799 |
if (spinApp::Instance().hasAudioRenderer)
|
| 800 |
spinApp::Instance().audioScene->debugPrint(); |
| 801 |
else
|
| 802 |
std::cout << "SpatOSC not enabled for this SPIN application" << std::endl;
|
| 803 |
#endif
|
| 804 |
} |
| 805 |
|
| 806 |
// forward debug message to all clients:
|
| 807 |
SCENE_MSG("ss", "debug", (const char*)argv[1]); |
| 808 |
} |
| 809 |
else
|
| 810 |
{
|
| 811 |
sceneManager->debug(); |
| 812 |
SCENE_MSG("s", "debug"); |
| 813 |
} |
| 814 |
} |
| 815 |
else if (theMethod == "clear") |
| 816 |
sceneManager->clear(); |
| 817 |
else if (theMethod == "clearUsers") |
| 818 |
sceneManager->clearUsers(); |
| 819 |
else if (theMethod == "clearStates") |
| 820 |
sceneManager->clearStates(); |
| 821 |
else if (theMethod == "userRefresh") |
| 822 |
{
|
| 823 |
if (spin.getContext()->isServer())
|
| 824 |
{
|
| 825 |
SCENE_MSG("s", "userRefresh"); |
| 826 |
} |
| 827 |
else
|
| 828 |
{
|
| 829 |
spin.SceneMessage("sss", "createNode", spin.getUserID().c_str(), "UserNode", LO_ARGS_END); |
| 830 |
|
| 831 |
// In the case of a client, we also need to check if the current
|
| 832 |
// userNode is actually attached. The deleteNode / clear / whatever
|
| 833 |
// may have detached it from the scenegraph:
|
| 834 |
if (!sceneManager->worldNode->containsNode(spin.userNode.get()))
|
| 835 |
{
|
| 836 |
std::cout << "calling attach on userNode (newparent=" << spin.userNode->newParent->s_name << std::endl;
|
| 837 |
spin.userNode->newParent = WORLD_SYMBOL; |
| 838 |
spin.userNode->attach(); |
| 839 |
} |
| 840 |
|
| 841 |
// if the server sends a userRefresh, it's possible that it has
|
| 842 |
// only recently come online, so we need to re-subsrcibe:
|
| 843 |
spinClientContext *clientContext = dynamic_cast<spinClientContext*>(spin.getContext());
|
| 844 |
clientContext->subscribe(); |
| 845 |
} |
| 846 |
} |
| 847 |
else if (theMethod == "refresh") |
| 848 |
sceneManager->refreshAll(); |
| 849 |
else if (theMethod == "refreshSubscribers") |
| 850 |
{
|
| 851 |
if (spin.getContext()->isServer())
|
| 852 |
{
|
| 853 |
spinServerContext *server = dynamic_cast<spinServerContext*>(spin.getContext());
|
| 854 |
server->refreshSubscribers(); |
| 855 |
} |
| 856 |
} |
| 857 |
else if (theMethod == "getNodeList") |
| 858 |
sceneManager->sendNodeList("*");
|
| 859 |
else if ((theMethod == "nodeList") && (argc>2)) |
| 860 |
{
|
| 861 |
for (int i = 2; i < argc; i++) |
| 862 |
{
|
| 863 |
if (strcmp((char*) argv[i],"NULL") != 0) |
| 864 |
sceneManager->createNode((char*)argv[i], (char*)argv[1]); |
| 865 |
} |
| 866 |
} |
| 867 |
else if ((theMethod=="stateList") && (argc>2)) |
| 868 |
{
|
| 869 |
for (int i=2; i<argc; i++) |
| 870 |
{
|
| 871 |
if (strcmp((char*) argv[i],"NULL") != 0) |
| 872 |
sceneManager->createStateSet((char*) argv[i], (char*) argv[1]); |
| 873 |
} |
| 874 |
} |
| 875 |
else if ((theMethod == "exportScene") && (argc==3)) |
| 876 |
sceneManager->exportScene((char*) argv[1], (char*) argv[2]); |
| 877 |
else if ((theMethod == "load") && (argc==2)) |
| 878 |
sceneManager->loadXML((char*) argv[1]); |
| 879 |
else if ((theMethod == "save") && (argc==2)) |
| 880 |
sceneManager->saveXML((char*) argv[1]); |
| 881 |
else if ((theMethod == "saveAll") && (argc==2)) |
| 882 |
sceneManager->saveXML((char*) argv[1], true); |
| 883 |
else if ((theMethod == "saveUsers") && (argc==2)) |
| 884 |
sceneManager->saveUsers((char*) argv[1]); |
| 885 |
else if ((theMethod == "createNode") && (argc==3)) |
| 886 |
sceneManager->createNode((char*) argv[1], (char*) argv[2]); |
| 887 |
else if ((theMethod == "createStateSet") && (argc==3)) |
| 888 |
sceneManager->createStateSet((char*) argv[1], (char*) argv[2]); |
| 889 |
else if ((theMethod == "createStateSet") && (argc==2)) |
| 890 |
sceneManager->createStateSet((char*) argv[1]); |
| 891 |
else if ((theMethod == "setWorldStateSet") && (argc==2)) |
| 892 |
sceneManager->setWorldStateSet((char*) argv[1]); |
| 893 |
else if ((theMethod == "deleteNode") && (argc==2)) |
| 894 |
sceneManager->deleteNode((char*) argv[1]); |
| 895 |
else if ((theMethod == "deleteGraph") && (argc==2)) |
| 896 |
sceneManager->deleteGraph((char*) argv[1]); |
| 897 |
else if ((theMethod == "setNotifyLevel") && (argc==2)) |
| 898 |
{
|
| 899 |
int lvl = (int) lo_hires_val((lo_type)types[1], argv[1]); |
| 900 |
if ((lvl>=0) && (lvl<=6)) |
| 901 |
{
|
| 902 |
osg::setNotifyLevel((osg::NotifySeverity)lvl); |
| 903 |
std::cout << "setNotifyLevel " << osg::getNotifyLevel() << std::endl;
|
| 904 |
} |
| 905 |
SCENE_MSG("si", "setNotifyLevel", (int)osg::getNotifyLevel()); |
| 906 |
} |
| 907 |
else if ((theMethod == "optimize") && (argc==2)) |
| 908 |
{
|
| 909 |
osgUtil::Optimizer optimizer; |
| 910 |
if (std::string((char*) argv[1]) == "all") |
| 911 |
{
|
| 912 |
std::cout << "Optimizing scene (all)" << std::endl;
|
| 913 |
pthread_mutex_lock(&sceneMutex); |
| 914 |
optimizer.optimize(sceneManager->worldNode.get(), osgUtil::Optimizer::ALL_OPTIMIZATIONS); |
| 915 |
pthread_mutex_unlock(&sceneMutex); |
| 916 |
} |
| 917 |
else
|
| 918 |
{
|
| 919 |
std::cout << "Optimizing scene" << std::endl;
|
| 920 |
pthread_mutex_lock(&sceneMutex); |
| 921 |
optimizer.optimize(sceneManager->worldNode.get()); |
| 922 |
pthread_mutex_unlock(&sceneMutex); |
| 923 |
} |
| 924 |
SCENE_MSG("ss", "optimize", (char*)argv[1]); |
| 925 |
} |
| 926 |
else if (theMethod == "spatosc") |
| 927 |
{
|
| 928 |
#ifdef WITH_SPATOSC
|
| 929 |
if (spinApp::Instance().hasAudioRenderer)
|
| 930 |
{
|
| 931 |
if ((argc==4) && (std::string((char*)argv[1])=="setDefaultDistanceFactor")) |
| 932 |
{
|
| 933 |
double factor = (double) lo_hires_val((lo_type)types[2], argv[2]); |
| 934 |
bool updateExisting = (bool) lo_hires_val((lo_type)types[3], argv[3]); |
| 935 |
spin.audioScene->setDefaultDistanceFactor(factor, updateExisting); |
| 936 |
} |
| 937 |
if ((argc==4) && (std::string((char*)argv[1])=="setDefaultDopplerFactor")) |
| 938 |
{
|
| 939 |
double factor = (double) lo_hires_val((lo_type)types[2], argv[2]); |
| 940 |
bool updateExisting = (bool) lo_hires_val((lo_type)types[3], argv[3]); |
| 941 |
spin.audioScene->setDefaultDopplerFactor(factor, updateExisting); |
| 942 |
} |
| 943 |
if ((argc==4) && (std::string((char*)argv[1])=="setDefaultRolloffFactor")) |
| 944 |
{
|
| 945 |
double factor = (double) lo_hires_val((lo_type)types[2], argv[2]); |
| 946 |
bool updateExisting = (bool) lo_hires_val((lo_type)types[3], argv[3]); |
| 947 |
spin.audioScene->setDefaultRolloffFactor(factor, updateExisting); |
| 948 |
} |
| 949 |
} |
| 950 |
#endif
|
| 951 |
} |
| 952 |
else
|
| 953 |
{
|
| 954 |
// FIXME: this used to rebroadcast messages that did not match command
|
| 955 |
#if 0
|
| 956 |
spinApp &spin = spinApp::Instance(); |
| 957 |
if (spin.sceneManager->isServer()) |
| 958 |
{
|
| 959 |
lo_message msg = lo_message_new(); |
| 960 |
for (int i=0; i<argc; i++) |
| 961 |
{
|
| 962 |
if (lo_is_numerical_type((lo_type)types[i])) |
| 963 |
{
|
| 964 |
lo_message_add_float(msg, (float) lo_hires_val((lo_type)types[i], argv[i])); |
| 965 |
} else {
|
| 966 |
lo_message_add_string(msg, (const char*) argv[i] ); |
| 967 |
} |
| 968 |
} |
| 969 |
lo_send_message_from(spin.sceneManager->txAddr, spin.sceneManager->txServ, path, msg); |
| 970 |
//std::cout << "Unknown OSC command: " << path << " " << theMethod << " (with " << argc-1 << " args), but forwarding the message anyway." << std::endl; |
| 971 |
} else {
|
| 972 |
//std::cout << "Unknown OSC command: " << path << " " << theMethod << " (with " << argc-1 << " args)" << std::endl; |
| 973 |
} |
| 974 |
#endif |
| 975 |
} |
| 976 |
|
| 977 |
//pthread_mutex_unlock(&sceneMutex);
|
| 978 |
|
| 979 |
return 1; |
| 980 |
} |
| 981 |
|
| 982 |
int spinBaseContext::logCallback(const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data) |
| 983 |
{
|
| 984 |
spinLog *log = (spinLog*) user_data; |
| 985 |
|
| 986 |
*log << path << ' ' << types << ' '; |
| 987 |
for (int i = 0; i < argc; i++) |
| 988 |
{
|
| 989 |
if (lo_is_numerical_type((lo_type) types[i]))
|
| 990 |
{
|
| 991 |
*log << (float) lo_hires_val((lo_type) types[i], argv[i]);
|
| 992 |
} else {
|
| 993 |
*log << (const char*) argv[i]; |
| 994 |
} |
| 995 |
*log << ' ';
|
| 996 |
} |
| 997 |
*log << std::endl; |
| 998 |
|
| 999 |
return 1; |
| 1000 |
} |
| 1001 |
|
| 1002 |
int spinBaseContext::debugCallback(const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data) |
| 1003 |
{
|
| 1004 |
printf("************ oscCallback_debug() got message: %s\n", (char*)path); |
| 1005 |
printf("user_data: %s\n", (char*) user_data); |
| 1006 |
for (int i = 0; i < argc; i++) |
| 1007 |
{
|
| 1008 |
printf("arg %d '%c' ", i, types[i]);
|
| 1009 |
lo_arg_pp((lo_type) types[i], argv[i]); |
| 1010 |
printf("\n");
|
| 1011 |
} |
| 1012 |
printf("\n");
|
| 1013 |
fflush(stdout); |
| 1014 |
return 1; |
| 1015 |
} |
| 1016 |
|
| 1017 |
void spinBaseContext::oscParser_error(int num, const char *msg, const char *path) |
| 1018 |
{
|
| 1019 |
printf("OSC (liblo) error %d in path %s: %s\n", num, path, msg);
|
| 1020 |
fflush(stdout); |
| 1021 |
} |
| 1022 |
|
| 1023 |
void spinBaseContext::createServers()
|
| 1024 |
{
|
| 1025 |
using boost::lexical_cast;
|
| 1026 |
using std::string; |
| 1027 |
|
| 1028 |
lo_tcpRxServer_ = lo_server_new_with_proto(tcpPort_.c_str(), LO_TCP, oscParser_error); |
| 1029 |
if (lo_tcpRxServer_ == 0) |
| 1030 |
{
|
| 1031 |
if (canAutoAssignPorts())
|
| 1032 |
{
|
| 1033 |
// liblo will try a random free port if the default failed
|
| 1034 |
std::cerr << "TCP receiver port " << tcpPort_ << " failed; trying a random port" << std::endl; |
| 1035 |
lo_tcpRxServer_ = lo_server_new_with_proto(NULL, LO_TCP, oscParser_error);
|
| 1036 |
} else {
|
| 1037 |
std::cerr << "TCP receiver port " << tcpPort_ << " failed; SPIN was provided this port manually, so it will not attempt to use a random port. Quitting." << std::endl; |
| 1038 |
exit(0);
|
| 1039 |
} |
| 1040 |
} |
| 1041 |
|
| 1042 |
std::vector<lo_address>::iterator it; |
| 1043 |
for (it = lo_rxAddrs_.begin(); it != lo_rxAddrs_.end(); ++it)
|
| 1044 |
{
|
| 1045 |
lo_server tmpServ; |
| 1046 |
if (isMulticastAddress(lo_address_get_hostname(*it)))
|
| 1047 |
{
|
| 1048 |
tmpServ = lo_server_new_multicast(lo_address_get_hostname(*it), lo_address_get_port(*it), oscParser_error); |
| 1049 |
if (tmpServ == 0) |
| 1050 |
{
|
| 1051 |
std::cerr << "Multicast server creation on port " << lo_address_get_port(*it) << " failed, trying a random port" << std::endl; |
| 1052 |
std::string addr(lo_address_get_hostname(*it));
|
| 1053 |
tmpServ = lo_server_new_multicast(addr.c_str(), NULL, oscParser_error);
|
| 1054 |
lo_address_free(*it); |
| 1055 |
(*it) = lo_address_new(addr.c_str(), lexical_cast<string>(lo_server_get_port(tmpServ)).c_str());
|
| 1056 |
} |
| 1057 |
} |
| 1058 |
else
|
| 1059 |
{
|
| 1060 |
tmpServ = lo_server_new(lo_address_get_port(*it), oscParser_error); |
| 1061 |
if (tmpServ == 0) |
| 1062 |
{
|
| 1063 |
std::cerr << "UDP listener creation on port " << lo_address_get_port(*it) << " failed, trying a random port" << std::endl; |
| 1064 |
tmpServ = lo_server_new(NULL, oscParser_error);
|
| 1065 |
std::string addr(lo_address_get_hostname(*it));
|
| 1066 |
lo_address_free(*it); |
| 1067 |
(*it) = lo_address_new(addr.c_str(), lexical_cast<string>(lo_server_get_port(tmpServ)).c_str());
|
| 1068 |
} |
| 1069 |
} |
| 1070 |
lo_rxServs_.push_back(tmpServ); |
| 1071 |
} |
| 1072 |
|
| 1073 |
// set up infoPort listener thread:
|
| 1074 |
if (isMulticastAddress(lo_address_get_hostname(lo_infoAddr)))
|
| 1075 |
{
|
| 1076 |
lo_infoServ_ = lo_server_new_multicast(lo_address_get_hostname(lo_infoAddr), lo_address_get_port(lo_infoAddr), oscParser_error); |
| 1077 |
if (lo_infoServ_ == 0) |
| 1078 |
{
|
| 1079 |
std::cerr << "Multicast info server creation on port " << lo_address_get_port(lo_infoAddr) <<
|
| 1080 |
" failed, trying a random port" << std::endl;
|
| 1081 |
std::string addr(lo_address_get_hostname(lo_infoAddr));
|
| 1082 |
lo_address_free(lo_infoAddr); |
| 1083 |
lo_infoServ_ = lo_server_new_multicast(addr.c_str(), NULL, oscParser_error);
|
| 1084 |
lo_infoAddr = lo_address_new(addr.c_str(), lexical_cast<string>(lo_server_get_port(lo_infoServ_)).c_str());
|
| 1085 |
} |
| 1086 |
} |
| 1087 |
else if (isBroadcastAddress(lo_address_get_hostname(lo_infoAddr))) |
| 1088 |
{
|
| 1089 |
lo_infoServ_ = lo_server_new(lo_address_get_port(lo_infoAddr), oscParser_error); |
| 1090 |
if (lo_infoServ_ == 0) |
| 1091 |
{
|
| 1092 |
std::cerr << "Info server creation on port " << lo_address_get_port(lo_infoAddr) <<
|
| 1093 |
" failed, trying a random port" << std::endl;
|
| 1094 |
std::string addr(lo_address_get_hostname(lo_infoAddr));
|
| 1095 |
lo_address_free(lo_infoAddr); |
| 1096 |
lo_infoServ_ = lo_server_new(NULL, oscParser_error);
|
| 1097 |
lo_infoAddr = lo_address_new(addr.c_str(), lexical_cast<string>(lo_server_get_port(lo_infoServ_)).c_str());
|
| 1098 |
} |
| 1099 |
int sock = lo_server_get_socket_fd(lo_infoServ_);
|
| 1100 |
int sockopt = 1; |
| 1101 |
setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &sockopt, sizeof(sockopt));
|
| 1102 |
} |
| 1103 |
else
|
| 1104 |
{
|
| 1105 |
lo_infoServ_ = lo_server_new(lo_address_get_port(lo_infoAddr), oscParser_error); |
| 1106 |
if (lo_infoServ_ == 0) |
| 1107 |
{
|
| 1108 |
std::cerr << "Info server creation on port " << lo_address_get_port(lo_infoAddr) <<
|
| 1109 |
" failed, trying a random port" << std::endl;
|
| 1110 |
std::string addr(lo_address_get_hostname(lo_infoAddr));
|
| 1111 |
lo_address_free(lo_infoAddr); |
| 1112 |
lo_infoServ_ = lo_server_new(NULL, oscParser_error);
|
| 1113 |
lo_infoAddr = lo_address_new(addr.c_str(), lexical_cast<string>(lo_server_get_port(lo_infoServ_)).c_str());
|
| 1114 |
} |
| 1115 |
} |
| 1116 |
} |
| 1117 |
|
| 1118 |
} // end of namespace spin
|
| 1119 |
|
