/* TUIO C++ Library Copyright (c) 2005-2017 Martin Kaltenbrunner This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3.0 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. */ #include "TuioServer.h" #include "UdpSender.h" using namespace TUIO; using namespace osc; TuioServer::TuioServer() :full_update (false) ,periodic_update (false) ,objectProfileEnabled (true) ,cursorProfileEnabled (true) ,blobProfileEnabled (true) ,source_name (NULL) { OscSender *oscsend = new UdpSender(); initialize(oscsend); } TuioServer::TuioServer(const char *host, int port) :full_update (false) ,periodic_update (false) ,objectProfileEnabled (true) ,cursorProfileEnabled (true) ,blobProfileEnabled (true) ,source_name (NULL) { OscSender *oscsend = new UdpSender(host,port); initialize(oscsend); } TuioServer::TuioServer(OscSender *oscsend) :full_update (false) ,periodic_update (false) ,objectProfileEnabled (true) ,cursorProfileEnabled (true) ,blobProfileEnabled (true) ,source_name (NULL) { initialize(oscsend); } void TuioServer::initialize(OscSender *oscsend) { senderList.push_back(oscsend); int size = oscsend->getBufferSize(); oscBuffer = new char[size]; oscPacket = new osc::OutboundPacketStream(oscBuffer,size); fullBuffer = new char[size]; fullPacket = new osc::OutboundPacketStream(oscBuffer,size); objectUpdateTime = TuioTime(currentFrameTime); cursorUpdateTime = TuioTime(currentFrameTime); blobUpdateTime = TuioTime(currentFrameTime); if (cursorProfileEnabled) sendEmptyCursorBundle(); if (objectProfileEnabled) sendEmptyObjectBundle(); if (blobProfileEnabled) sendEmptyBlobBundle(); invert_x = false; invert_y = false; invert_a = false; } TuioServer::~TuioServer() { initFrame(TuioTime::getSessionTime()); stopUntouchedMovingCursors(); stopUntouchedMovingObjects(); stopUntouchedMovingBlobs(); initFrame(TuioTime::getSessionTime()); removeUntouchedStoppedCursors(); removeUntouchedStoppedObjects(); removeUntouchedStoppedBlobs(); if (cursorProfileEnabled) sendEmptyCursorBundle(); if (objectProfileEnabled) sendEmptyObjectBundle(); if (blobProfileEnabled) sendEmptyBlobBundle(); delete []oscBuffer; delete oscPacket; delete []fullBuffer; delete fullPacket; if (source_name) delete[] source_name; for (unsigned int i=0;iisLocal()) && (senderList.size()==1)) { setSourceName(source_name); }*/ // resize packets to smallest transport method unsigned int size = sender->getBufferSize(); if (sizeCapacity()) { osc::OutboundPacketStream *temp = oscPacket; oscPacket = new osc::OutboundPacketStream(oscBuffer,size); delete temp; temp = fullPacket; fullPacket = new osc::OutboundPacketStream(oscBuffer,size); delete temp; } senderList.push_back(sender); } void TuioServer::deliverOscPacket(osc::OutboundPacketStream *packet) { for (unsigned int i=0;isendOscPacket(packet); } void TuioServer::setSourceName(const char *name, const char *ip) { if (!source_name) source_name = new char[256]; sprintf(source_name,"%s@%s",name,ip); } void TuioServer::setSourceName(const char *src) { if (!source_name) source_name = new char[256]; /*if (senderList[0]->isLocal()) { sprintf(source_name,"%s",src); } else {*/ char hostname[64]; char *source_addr = NULL; struct hostent *hp = NULL; struct in_addr *addr = NULL; gethostname(hostname, 64); hp = gethostbyname(hostname); if (hp==NULL) { sprintf(hostname, "%s.local", hostname); hp = gethostbyname(hostname); } if (hp!=NULL) { for (int i = 0; hp->h_addr_list[i] != 0; ++i) { addr = (struct in_addr *)(hp->h_addr_list[i]); //std::cout << inet_ntoa(*addr) << std::endl; source_addr = inet_ntoa(*addr); } } else { //generate a random internet address srand ( (unsigned int)time(NULL) ); int32 r = rand(); addr = (struct in_addr*)&r; source_addr = inet_ntoa(*addr); } sprintf(source_name,"%s@%s",src,source_addr); //} std::cout << "tuio/src " << source_name << std::endl; } void TuioServer::commitFrame() { TuioManager::commitFrame(); if(updateObject) { startObjectBundle(); for (std::list::iterator tuioObject = objectList.begin(); tuioObject!=objectList.end(); tuioObject++) { // start a new packet if we exceed the packet capacity if ((oscPacket->Capacity()-oscPacket->Size())getTuioTime()==currentFrameTime)) addObjectMessage(tobj); } objectUpdateTime = TuioTime(currentFrameTime); sendObjectBundle(currentFrame); } else if (objectProfileEnabled && periodic_update) { TuioTime timeCheck = currentFrameTime - objectUpdateTime; if(timeCheck.getSeconds()>=update_interval) { objectUpdateTime = TuioTime(currentFrameTime); startObjectBundle(); if (full_update) { for (std::list::iterator tuioObject = objectList.begin(); tuioObject!=objectList.end(); tuioObject++) { // start a new packet if we exceed the packet capacity if ((oscPacket->Capacity()-oscPacket->Size())::iterator tuioCursor = cursorList.begin(); tuioCursor!=cursorList.end(); tuioCursor++) { // start a new packet if we exceed the packet capacity if ((oscPacket->Capacity()-oscPacket->Size())getTuioTime()==currentFrameTime)) addCursorMessage(tcur); } cursorUpdateTime = TuioTime(currentFrameTime); sendCursorBundle(currentFrame); } else if (cursorProfileEnabled && periodic_update) { TuioTime timeCheck = currentFrameTime - cursorUpdateTime; if(timeCheck.getSeconds()>=update_interval) { cursorUpdateTime = TuioTime(currentFrameTime); startCursorBundle(); if (full_update) { for (std::list::iterator tuioCursor = cursorList.begin(); tuioCursor!=cursorList.end(); tuioCursor++) { // start a new packet if we exceed the packet capacity if ((oscPacket->Capacity()-oscPacket->Size())::iterator tuioBlob =blobList.begin(); tuioBlob!=blobList.end(); tuioBlob++) { // start a new packet if we exceed the packet capacity if ((oscPacket->Capacity()-oscPacket->Size())getTuioTime()==currentFrameTime)) addBlobMessage(tblb); } blobUpdateTime = TuioTime(currentFrameTime); sendBlobBundle(currentFrame); } else if (blobProfileEnabled && periodic_update) { TuioTime timeCheck = currentFrameTime - blobUpdateTime; if(timeCheck.getSeconds()>=update_interval) { blobUpdateTime = TuioTime(currentFrameTime); startBlobBundle(); if (full_update) { for (std::list::iterator tuioBlob =blobList.begin(); tuioBlob!=blobList.end(); tuioBlob++) { // start a new packet if we exceed the packet capacity if ((oscPacket->Capacity()-oscPacket->Size())Clear(); (*oscPacket) << osc::BeginBundleImmediate; if (source_name) (*oscPacket) << osc::BeginMessage( "/tuio/2Dcur") << "source" << source_name << osc::EndMessage; (*oscPacket) << osc::BeginMessage( "/tuio/2Dcur") << "alive" << osc::EndMessage; (*oscPacket) << osc::BeginMessage( "/tuio/2Dcur") << "fseq" << -1 << osc::EndMessage; (*oscPacket) << osc::EndBundle; deliverOscPacket( oscPacket ); } void TuioServer::startCursorBundle() { oscPacket->Clear(); (*oscPacket) << osc::BeginBundleImmediate; if (source_name) (*oscPacket) << osc::BeginMessage( "/tuio/2Dcur") << "source" << source_name << osc::EndMessage; (*oscPacket) << osc::BeginMessage( "/tuio/2Dcur") << "alive"; for (std::list::iterator tuioCursor = cursorList.begin(); tuioCursor!=cursorList.end(); tuioCursor++) { /*if ((*tuioCursor)->getTuioState()!=TUIO_ADDED)*/ (*oscPacket) << (int32)((*tuioCursor)->getSessionID()); } (*oscPacket) << osc::EndMessage; } void TuioServer::addCursorMessage(TuioCursor *tcur) { //if (tcur->getTuioState()==TUIO_ADDED) return; float xpos = tcur->getX(); float xvel = tcur->getXSpeed(); if (invert_x) { xpos = 1 - xpos; xvel = -1 * xvel; } float ypos = tcur->getY(); float yvel = tcur->getYSpeed(); if (invert_y) { ypos = 1 - ypos; yvel = -1 * yvel; } (*oscPacket) << osc::BeginMessage( "/tuio/2Dcur") << "set"; (*oscPacket) << (int32)(tcur->getSessionID()) << xpos << ypos; (*oscPacket) << xvel << yvel << tcur->getMotionAccel(); (*oscPacket) << osc::EndMessage; } void TuioServer::sendCursorBundle(long fseq) { (*oscPacket) << osc::BeginMessage( "/tuio/2Dcur") << "fseq" << (int32)fseq << osc::EndMessage; (*oscPacket) << osc::EndBundle; deliverOscPacket( oscPacket ); } void TuioServer::sendEmptyObjectBundle() { oscPacket->Clear(); (*oscPacket) << osc::BeginBundleImmediate; if (source_name) (*oscPacket) << osc::BeginMessage( "/tuio/2Dobj") << "source" << source_name << osc::EndMessage; (*oscPacket) << osc::BeginMessage( "/tuio/2Dobj") << "alive" << osc::EndMessage; (*oscPacket) << osc::BeginMessage( "/tuio/2Dobj") << "fseq" << -1 << osc::EndMessage; (*oscPacket) << osc::EndBundle; deliverOscPacket( oscPacket ); } void TuioServer::startObjectBundle() { oscPacket->Clear(); (*oscPacket) << osc::BeginBundleImmediate; if (source_name) (*oscPacket) << osc::BeginMessage( "/tuio/2Dobj") << "source" << source_name << osc::EndMessage; (*oscPacket) << osc::BeginMessage( "/tuio/2Dobj") << "alive"; for (std::list::iterator tuioObject = objectList.begin(); tuioObject!=objectList.end(); tuioObject++) { (*oscPacket) << (int32)((*tuioObject)->getSessionID()); } (*oscPacket) << osc::EndMessage; } void TuioServer::addObjectMessage(TuioObject *tobj) { float xpos = tobj->getX(); float xvel = tobj->getXSpeed(); if (invert_x) { xpos = 1 - xpos; xvel = -1 * xvel; } float ypos = tobj->getY(); float yvel = tobj->getYSpeed(); if (invert_y) { ypos = 1 - ypos; yvel = -1 * yvel; } float angle = tobj->getAngle(); float rvel = tobj->getRotationSpeed(); if (invert_a) { angle = 2.0f*(float)M_PI - angle; rvel = -1 * rvel; } (*oscPacket) << osc::BeginMessage( "/tuio/2Dobj") << "set"; (*oscPacket) << (int32)(tobj->getSessionID()) << tobj->getSymbolID() << xpos << ypos << angle; (*oscPacket) << xvel << yvel << rvel << tobj->getMotionAccel() << tobj->getRotationAccel(); (*oscPacket) << osc::EndMessage; } void TuioServer::sendObjectBundle(long fseq) { (*oscPacket) << osc::BeginMessage( "/tuio/2Dobj") << "fseq" << (int32)fseq << osc::EndMessage; (*oscPacket) << osc::EndBundle; deliverOscPacket( oscPacket ); } void TuioServer::sendEmptyBlobBundle() { oscPacket->Clear(); (*oscPacket) << osc::BeginBundleImmediate; if (source_name) (*oscPacket) << osc::BeginMessage( "/tuio/2Dblb") << "source" << source_name << osc::EndMessage; (*oscPacket) << osc::BeginMessage( "/tuio/2Dblb") << "alive" << osc::EndMessage; (*oscPacket) << osc::BeginMessage( "/tuio/2Dblb") << "fseq" << -1 << osc::EndMessage; (*oscPacket) << osc::EndBundle; deliverOscPacket( oscPacket ); } void TuioServer::startBlobBundle() { oscPacket->Clear(); (*oscPacket) << osc::BeginBundleImmediate; if (source_name) (*oscPacket) << osc::BeginMessage( "/tuio/2Dblb") << "source" << source_name << osc::EndMessage; (*oscPacket) << osc::BeginMessage( "/tuio/2Dblb") << "alive"; for (std::list::iterator tuioBlob = blobList.begin(); tuioBlob!=blobList.end(); tuioBlob++) { /*if ((*tuioBlob)->getTuioState()!=TUIO_ADDED)*/ (*oscPacket) << (int32)((*tuioBlob)->getSessionID()); } (*oscPacket) << osc::EndMessage; } void TuioServer::addBlobMessage(TuioBlob *tblb) { //if (tblb->getTuioState()==TUIO_ADDED) return; float xpos = tblb->getX(); float xvel = tblb->getXSpeed(); if (invert_x) { xpos = 1 - xpos; xvel = -1 * xvel; } float ypos = tblb->getY(); float yvel = tblb->getYSpeed(); if (invert_y) { ypos = 1 - ypos; yvel = -1 * yvel; } float angle = tblb->getAngle(); float rvel = tblb->getRotationSpeed(); if (invert_a) { angle = 2.0f*(float)M_PI - angle; rvel = -1 * rvel; } (*oscPacket) << osc::BeginMessage( "/tuio/2Dblb") << "set"; (*oscPacket) << (int32)(tblb->getSessionID()) << xpos << ypos << angle << tblb->getWidth() << tblb->getHeight() << tblb->getArea(); (*oscPacket) << xvel << yvel << rvel << tblb->getMotionAccel() << tblb->getRotationAccel(); (*oscPacket) << osc::EndMessage; } void TuioServer::sendBlobBundle(long fseq) { (*oscPacket) << osc::BeginMessage( "/tuio/2Dblb") << "fseq" << (int32)fseq << osc::EndMessage; (*oscPacket) << osc::EndBundle; deliverOscPacket( oscPacket ); } void TuioServer::sendFullMessages() { // prepare the cursor packet fullPacket->Clear(); (*fullPacket) << osc::BeginBundleImmediate; if (source_name) (*fullPacket) << osc::BeginMessage( "/tuio/2Dcur") << "source" << source_name << osc::EndMessage; // add the cursor alive message (*fullPacket) << osc::BeginMessage( "/tuio/2Dcur") << "alive"; for (std::list::iterator tuioCursor = cursorList.begin(); tuioCursor!=cursorList.end(); tuioCursor++) (*fullPacket) << (int32)((*tuioCursor)->getSessionID()); (*fullPacket) << osc::EndMessage; // add all current cursor set messages for (std::list::iterator tuioCursor = cursorList.begin(); tuioCursor!=cursorList.end(); tuioCursor++) { // start a new packet if we exceed the packet capacity if ((fullPacket->Capacity()-fullPacket->Size())Clear(); (*fullPacket) << osc::BeginBundleImmediate; if (source_name) (*fullPacket) << osc::BeginMessage( "/tuio/2Dcur") << "source" << source_name << osc::EndMessage; // add the cursor alive message (*fullPacket) << osc::BeginMessage( "/tuio/2Dcur") << "alive"; for (std::list::iterator tuioCursor = cursorList.begin(); tuioCursor!=cursorList.end(); tuioCursor++) (*fullPacket) << (int32)((*tuioCursor)->getSessionID()); (*fullPacket) << osc::EndMessage; } float xpos = (*tuioCursor)->getX(); float xvel = (*tuioCursor)->getXSpeed(); if (invert_x) { xpos = 1 - xpos; xvel = -1 * xvel; } float ypos = (*tuioCursor)->getY(); float yvel = (*tuioCursor)->getYSpeed(); if (invert_y) { ypos = 1 - ypos; yvel = -1 * yvel; } // add the actual cursor set message (*fullPacket) << osc::BeginMessage( "/tuio/2Dcur") << "set"; (*fullPacket) << (int32)((*tuioCursor)->getSessionID()) << xpos << ypos; (*fullPacket) << xvel << yvel <<(*tuioCursor)->getMotionAccel(); (*fullPacket) << osc::EndMessage; } // add the immediate fseq message and send the cursor packet (*fullPacket) << osc::BeginMessage( "/tuio/2Dcur") << "fseq" << -1 << osc::EndMessage; (*fullPacket) << osc::EndBundle; deliverOscPacket( fullPacket ); // prepare the object packet fullPacket->Clear(); (*fullPacket) << osc::BeginBundleImmediate; if (source_name) (*fullPacket) << osc::BeginMessage( "/tuio/2Dobj") << "source" << source_name << osc::EndMessage; // add the object alive message (*fullPacket) << osc::BeginMessage( "/tuio/2Dobj") << "alive"; for (std::list::iterator tuioObject = objectList.begin(); tuioObject!=objectList.end(); tuioObject++) (*fullPacket) << (int32)((*tuioObject)->getSessionID()); (*fullPacket) << osc::EndMessage; for (std::list::iterator tuioObject = objectList.begin(); tuioObject!=objectList.end(); tuioObject++) { // start a new packet if we exceed the packet capacity if ((fullPacket->Capacity()-fullPacket->Size())Clear(); (*fullPacket) << osc::BeginBundleImmediate; if (source_name) (*fullPacket) << osc::BeginMessage( "/tuio/2Dobj") << "source" << source_name << osc::EndMessage; // add the object alive message (*fullPacket) << osc::BeginMessage( "/tuio/2Dobj") << "alive"; for (std::list::iterator tuioObject = objectList.begin(); tuioObject!=objectList.end(); tuioObject++) (*fullPacket) << (int32)((*tuioObject)->getSessionID()); (*fullPacket) << osc::EndMessage; } float xpos = (*tuioObject)->getX(); float xvel = (*tuioObject)->getXSpeed(); if (invert_x) { xpos = 1 - xpos; xvel = -1 * xvel; } float ypos = (*tuioObject)->getY(); float yvel = (*tuioObject)->getYSpeed(); if (invert_y) { ypos = 1 - ypos; yvel = -1 * yvel; } float angle = (*tuioObject)->getAngle(); float rvel = (*tuioObject)->getRotationSpeed(); if (invert_a) { angle = 2.0f*(float)M_PI - angle; rvel = -1 * rvel; } // add the actual object set message (*fullPacket) << osc::BeginMessage( "/tuio/2Dobj") << "set"; (*fullPacket) << (int32)((*tuioObject)->getSessionID()) << (*tuioObject)->getSymbolID() << xpos << ypos << angle; (*fullPacket) << xvel << yvel << rvel << (*tuioObject)->getMotionAccel() << (*tuioObject)->getRotationAccel(); (*fullPacket) << osc::EndMessage; } // add the immediate fseq message and send the object packet (*fullPacket) << osc::BeginMessage( "/tuio/2Dobj") << "fseq" << -1 << osc::EndMessage; (*fullPacket) << osc::EndBundle; deliverOscPacket( fullPacket ); // prepare the blob packet fullPacket->Clear(); (*fullPacket) << osc::BeginBundleImmediate; if (source_name) (*fullPacket) << osc::BeginMessage( "/tuio/2Dblb") << "source" << source_name << osc::EndMessage; // add the object alive message (*fullPacket) << osc::BeginMessage( "/tuio/2Dblb") << "alive"; for (std::list::iterator tuioBlob = blobList.begin(); tuioBlob!=blobList.end(); tuioBlob++) (*fullPacket) << (int32)((*tuioBlob)->getSessionID()); (*fullPacket) << osc::EndMessage; for (std::list::iterator tuioBlob = blobList.begin(); tuioBlob!=blobList.end(); tuioBlob++) { // start a new packet if we exceed the packet capacity if ((fullPacket->Capacity()-fullPacket->Size())Clear(); (*fullPacket) << osc::BeginBundleImmediate; if (source_name) (*fullPacket) << osc::BeginMessage( "/tuio/2Dblb") << "source" << source_name << osc::EndMessage; // add the blob alive message (*fullPacket) << osc::BeginMessage( "/tuio/2Dblb") << "alive"; for (std::list::iterator tuioBlob = blobList.begin(); tuioBlob!=blobList.end(); tuioBlob++) (*fullPacket) << (int32)((*tuioBlob)->getSessionID()); (*fullPacket) << osc::EndMessage; } float xpos = (*tuioBlob)->getX(); float xvel = (*tuioBlob)->getXSpeed(); if (invert_x) { xpos = 1 - xpos; xvel = -1 * xvel; } float ypos = (*tuioBlob)->getY(); float yvel = (*tuioBlob)->getYSpeed(); if (invert_y) { ypos = 1 - ypos; yvel = -1 * yvel; } float angle = (*tuioBlob)->getAngle(); float rvel = (*tuioBlob)->getRotationSpeed(); if (invert_a) { angle = 2.0f*(float)M_PI - angle; rvel = -1 * rvel; } // add the actual blob set message (*fullPacket) << osc::BeginMessage( "/tuio/2Dblb") << "set"; (*fullPacket) << (int32)((*tuioBlob)->getSessionID()) << xpos << ypos << angle << (*tuioBlob)->getWidth() << (*tuioBlob)->getHeight() << (*tuioBlob)->getArea(); (*fullPacket) << xvel << yvel << rvel << (*tuioBlob)->getMotionAccel() << (*tuioBlob)->getRotationAccel(); (*fullPacket) << osc::EndMessage; } // add the immediate fseq message and send the blob packet (*fullPacket) << osc::BeginMessage( "/tuio/2Dblb") << "fseq" << -1 << osc::EndMessage; (*fullPacket) << osc::EndBundle; deliverOscPacket( fullPacket ); }