TuioClient.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567
  1. /*
  2. TUIO C++ Library - part of the reacTIVision project
  3. http://reactivision.sourceforge.net/
  4. Copyright (c) 2005-2009 Martin Kaltenbrunner <[email protected]>
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  16. */
  17. #include "TuioClient.h"
  18. using namespace TUIO;
  19. using namespace osc;
  20. #ifndef WIN32
  21. static void* ClientThreadFunc( void* obj )
  22. #else
  23. static DWORD WINAPI ClientThreadFunc( LPVOID obj )
  24. #endif
  25. {
  26. static_cast<TuioClient*>(obj)->socket->Run();
  27. return 0;
  28. };
  29. void TuioClient::lockObjectList() {
  30. if(!connected) return;
  31. #ifndef WIN32
  32. pthread_mutex_lock(&objectMutex);
  33. #else
  34. WaitForSingleObject(objectMutex, INFINITE);
  35. #endif
  36. }
  37. void TuioClient::unlockObjectList() {
  38. if(!connected) return;
  39. #ifndef WIN32
  40. pthread_mutex_unlock(&objectMutex);
  41. #else
  42. ReleaseMutex(objectMutex);
  43. #endif
  44. }
  45. void TuioClient::lockCursorList() {
  46. if(!connected) return;
  47. #ifndef WIN32
  48. pthread_mutex_lock(&cursorMutex);
  49. #else
  50. WaitForSingleObject(cursorMutex, INFINITE);
  51. #endif
  52. }
  53. void TuioClient::unlockCursorList() {
  54. if(!connected) return;
  55. #ifndef WIN32
  56. pthread_mutex_unlock(&cursorMutex);
  57. #else
  58. ReleaseMutex(cursorMutex);
  59. #endif
  60. }
  61. TuioClient::TuioClient(int port)
  62. : socket (NULL)
  63. , currentFrame(-1)
  64. , maxCursorID (-1)
  65. , thread (NULL)
  66. , locked (false)
  67. , connected (false)
  68. {
  69. try {
  70. socket = new UdpListeningReceiveSocket(IpEndpointName( IpEndpointName::ANY_ADDRESS, port ), this );
  71. } catch (std::exception &e) {
  72. std::cerr << "could not bind to UDP port " << port << std::endl;
  73. socket = NULL;
  74. }
  75. if (socket!=NULL) {
  76. if (!socket->IsBound()) {
  77. delete socket;
  78. socket = NULL;
  79. } else std::cout << "listening to TUIO messages on UDP port " << port << std::endl;
  80. }
  81. }
  82. TuioClient::~TuioClient() {
  83. delete socket;
  84. }
  85. void TuioClient::ProcessBundle( const ReceivedBundle& b, const IpEndpointName& remoteEndpoint) {
  86. try {
  87. for( ReceivedBundle::const_iterator i = b.ElementsBegin(); i != b.ElementsEnd(); ++i ){
  88. if( i->IsBundle() )
  89. ProcessBundle( ReceivedBundle(*i), remoteEndpoint);
  90. else
  91. ProcessMessage( ReceivedMessage(*i), remoteEndpoint);
  92. }
  93. } catch (MalformedBundleException& e) {
  94. std::cerr << "malformed OSC bundle: " << e.what() << std::endl;
  95. }
  96. }
  97. void TuioClient::ProcessMessage( const ReceivedMessage& msg, const IpEndpointName& remoteEndpoint) {
  98. try {
  99. ReceivedMessageArgumentStream args = msg.ArgumentStream();
  100. ReceivedMessage::const_iterator arg = msg.ArgumentsBegin();
  101. if( strcmp( msg.AddressPattern(), "/tuio/2Dobj" ) == 0 ){
  102. const char* cmd;
  103. args >> cmd;
  104. if (strcmp(cmd,"set")==0) {
  105. int32 s_id, c_id;
  106. float xpos, ypos, angle, xspeed, yspeed, rspeed, maccel, raccel;
  107. args >> s_id >> c_id >> xpos >> ypos >> angle >> xspeed >> yspeed >> rspeed >> maccel >> raccel;
  108. lockObjectList();
  109. std::list<TuioObject*>::iterator tobj;
  110. for (tobj=objectList.begin(); tobj!= objectList.end(); tobj++)
  111. if((*tobj)->getSessionID()==(long)s_id) break;
  112. if (tobj == objectList.end()) {
  113. TuioObject *addObject = new TuioObject((long)s_id,(int)c_id,xpos,ypos,angle);
  114. frameObjects.push_back(addObject);
  115. } else if ( ((*tobj)->getX()!=xpos) || ((*tobj)->getY()!=ypos) || ((*tobj)->getAngle()!=angle) || ((*tobj)->getXSpeed()!=xspeed) || ((*tobj)->getYSpeed()!=yspeed) || ((*tobj)->getRotationSpeed()!=rspeed) || ((*tobj)->getMotionAccel()!=maccel) || ((*tobj)->getRotationAccel()!=raccel) ) {
  116. TuioObject *updateObject = new TuioObject((long)s_id,(*tobj)->getSymbolID(),xpos,ypos,angle);
  117. updateObject->update(xpos,ypos,angle,xspeed,yspeed,rspeed,maccel,raccel);
  118. frameObjects.push_back(updateObject);
  119. }
  120. unlockObjectList();
  121. } else if (strcmp(cmd,"alive")==0) {
  122. int32 s_id;
  123. aliveObjectList.clear();
  124. while(!args.Eos()) {
  125. args >> s_id;
  126. aliveObjectList.push_back((long)s_id);
  127. }
  128. } else if (strcmp(cmd,"fseq")==0) {
  129. int32 fseq;
  130. args >> fseq;
  131. bool lateFrame = false;
  132. if (fseq>0) {
  133. if (fseq>currentFrame) currentTime = TuioTime::getSessionTime();
  134. if ((fseq>=currentFrame) || ((currentFrame-fseq)>100)) currentFrame = fseq;
  135. else lateFrame = true;
  136. } else if ((TuioTime::getSessionTime().getTotalMilliseconds()-currentTime.getTotalMilliseconds())>100) {
  137. currentTime = TuioTime::getSessionTime();
  138. }
  139. if (!lateFrame) {
  140. lockObjectList();
  141. //find the removed objects first
  142. for (std::list<TuioObject*>::iterator tobj=objectList.begin(); tobj != objectList.end(); tobj++) {
  143. std::list<long>::iterator iter = find(aliveObjectList.begin(), aliveObjectList.end(), (*tobj)->getSessionID());
  144. if (iter == aliveObjectList.end()) {
  145. (*tobj)->remove(currentTime);
  146. frameObjects.push_back(*tobj);
  147. }
  148. }
  149. unlockObjectList();
  150. for (std::list<TuioObject*>::iterator iter=frameObjects.begin(); iter != frameObjects.end(); iter++) {
  151. TuioObject *tobj = (*iter);
  152. TuioObject *frameObject = NULL;
  153. switch (tobj->getTuioState()) {
  154. case TUIO_REMOVED:
  155. frameObject = tobj;
  156. frameObject->remove(currentTime);
  157. for (std::list<TuioListener*>::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++)
  158. (*listener)->removeTuioObject(frameObject);
  159. lockObjectList();
  160. for (std::list<TuioObject*>::iterator delobj=objectList.begin(); delobj!=objectList.end(); delobj++) {
  161. if((*delobj)->getSessionID()==frameObject->getSessionID()) {
  162. objectList.erase(delobj);
  163. break;
  164. }
  165. }
  166. unlockObjectList();
  167. break;
  168. case TUIO_ADDED:
  169. lockObjectList();
  170. frameObject = new TuioObject(currentTime,tobj->getSessionID(),tobj->getSymbolID(),tobj->getX(),tobj->getY(),tobj->getAngle());
  171. objectList.push_back(frameObject);
  172. unlockObjectList();
  173. for (std::list<TuioListener*>::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++)
  174. (*listener)->addTuioObject(frameObject);
  175. break;
  176. default:
  177. lockObjectList();
  178. std::list<TuioObject*>::iterator iter;
  179. for (iter=objectList.begin(); iter != objectList.end(); iter++) {
  180. if((*iter)->getSessionID()==tobj->getSessionID()) {
  181. frameObject = (*iter);
  182. break;
  183. }
  184. }
  185. if(iter==objectList.end()) break;
  186. if ( (tobj->getX()!=frameObject->getX() && tobj->getXSpeed()==0) || (tobj->getY()!=frameObject->getY() && tobj->getYSpeed()==0) )
  187. frameObject->update(currentTime,tobj->getX(),tobj->getY(),tobj->getAngle());
  188. else
  189. frameObject->update(currentTime,tobj->getX(),tobj->getY(),tobj->getAngle(),tobj->getXSpeed(),tobj->getYSpeed(),tobj->getRotationSpeed(),tobj->getMotionAccel(),tobj->getRotationAccel());
  190. unlockObjectList();
  191. for (std::list<TuioListener*>::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++)
  192. (*listener)->updateTuioObject(frameObject);
  193. }
  194. delete tobj;
  195. }
  196. for (std::list<TuioListener*>::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++)
  197. (*listener)->refresh(currentTime);
  198. } else {
  199. for (std::list<TuioObject*>::iterator iter=frameObjects.begin(); iter != frameObjects.end(); iter++) {
  200. TuioObject *tobj = (*iter);
  201. delete tobj;
  202. }
  203. }
  204. frameObjects.clear();
  205. }
  206. } else if( strcmp( msg.AddressPattern(), "/tuio/2Dcur" ) == 0 ) {
  207. const char* cmd;
  208. args >> cmd;
  209. if (strcmp(cmd,"set")==0) {
  210. int32 s_id;
  211. float xpos, ypos, xspeed, yspeed, maccel;
  212. args >> s_id >> xpos >> ypos >> xspeed >> yspeed >> maccel;
  213. lockCursorList();
  214. std::list<TuioCursor*>::iterator tcur;
  215. for (tcur=cursorList.begin(); tcur!= cursorList.end(); tcur++)
  216. if((*tcur)->getSessionID()==(long)s_id) break;
  217. if (tcur==cursorList.end()) {
  218. TuioCursor *addCursor = new TuioCursor((long)s_id,-1,xpos,ypos);
  219. frameCursors.push_back(addCursor);
  220. } else if ( ((*tcur)->getX()!=xpos) || ((*tcur)->getY()!=ypos) || ((*tcur)->getXSpeed()!=xspeed) || ((*tcur)->getYSpeed()!=yspeed) || ((*tcur)->getMotionAccel()!=maccel) ) {
  221. TuioCursor *updateCursor = new TuioCursor((long)s_id,(*tcur)->getCursorID(),xpos,ypos);
  222. updateCursor->update(xpos,ypos,xspeed,yspeed,maccel);
  223. frameCursors.push_back(updateCursor);
  224. }
  225. unlockCursorList();
  226. } else if (strcmp(cmd,"alive")==0) {
  227. int32 s_id;
  228. aliveCursorList.clear();
  229. while(!args.Eos()) {
  230. args >> s_id;
  231. aliveCursorList.push_back((long)s_id);
  232. }
  233. } else if( strcmp( cmd, "fseq" ) == 0 ){
  234. int32 fseq;
  235. args >> fseq;
  236. bool lateFrame = false;
  237. if (fseq>0) {
  238. if (fseq>currentFrame) currentTime = TuioTime::getSessionTime();
  239. if ((fseq>=currentFrame) || ((currentFrame-fseq)>100)) currentFrame = fseq;
  240. else lateFrame = true;
  241. } else if ((TuioTime::getSessionTime().getTotalMilliseconds()-currentTime.getTotalMilliseconds())>100) {
  242. currentTime = TuioTime::getSessionTime();
  243. }
  244. if (!lateFrame) {
  245. lockCursorList();
  246. // find the removed cursors first
  247. for (std::list<TuioCursor*>::iterator tcur=cursorList.begin(); tcur != cursorList.end(); tcur++) {
  248. std::list<long>::iterator iter = find(aliveCursorList.begin(), aliveCursorList.end(), (*tcur)->getSessionID());
  249. if (iter == aliveCursorList.end()) {
  250. (*tcur)->remove(currentTime);
  251. frameCursors.push_back(*tcur);
  252. }
  253. }
  254. unlockCursorList();
  255. for (std::list<TuioCursor*>::iterator iter=frameCursors.begin(); iter != frameCursors.end(); iter++) {
  256. TuioCursor *tcur = (*iter);
  257. int c_id = -1;
  258. TuioCursor *frameCursor = NULL;
  259. switch (tcur->getTuioState()) {
  260. case TUIO_REMOVED:
  261. frameCursor = tcur;
  262. frameCursor->remove(currentTime);
  263. for (std::list<TuioListener*>::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++)
  264. (*listener)->removeTuioCursor(frameCursor);
  265. lockCursorList();
  266. for (std::list<TuioCursor*>::iterator delcur=cursorList.begin(); delcur!=cursorList.end(); delcur++) {
  267. if((*delcur)->getSessionID()==frameCursor->getSessionID()) {
  268. cursorList.erase(delcur);
  269. break;
  270. }
  271. }
  272. if (frameCursor->getCursorID()==maxCursorID) {
  273. maxCursorID = -1;
  274. delete frameCursor;
  275. if (cursorList.size()>0) {
  276. std::list<TuioCursor*>::iterator clist;
  277. for (clist=cursorList.begin(); clist != cursorList.end(); clist++) {
  278. c_id = (*clist)->getCursorID();
  279. if (c_id>maxCursorID) maxCursorID=c_id;
  280. }
  281. freeCursorBuffer.clear();
  282. for (std::list<TuioCursor*>::iterator flist=freeCursorList.begin(); flist != freeCursorList.end(); flist++) {
  283. TuioCursor *freeCursor = (*flist);
  284. if (freeCursor->getCursorID()>maxCursorID) delete freeCursor;
  285. else freeCursorBuffer.push_back(freeCursor);
  286. }
  287. freeCursorList = freeCursorBuffer;
  288. } else {
  289. for (std::list<TuioCursor*>::iterator flist=freeCursorList.begin(); flist != freeCursorList.end(); flist++) {
  290. TuioCursor *freeCursor = (*flist);
  291. delete freeCursor;
  292. }
  293. freeCursorList.clear();
  294. }
  295. } else if (frameCursor->getCursorID()<maxCursorID) {
  296. freeCursorList.push_back(frameCursor);
  297. }
  298. unlockCursorList();
  299. break;
  300. case TUIO_ADDED:
  301. lockCursorList();
  302. c_id = (int)cursorList.size();
  303. if (((int)(cursorList.size())<=maxCursorID) && ((int)(freeCursorList.size())>0)) {
  304. std::list<TuioCursor*>::iterator closestCursor = freeCursorList.begin();
  305. for(std::list<TuioCursor*>::iterator iter = freeCursorList.begin();iter!= freeCursorList.end(); iter++) {
  306. if((*iter)->getDistance(tcur)<(*closestCursor)->getDistance(tcur)) closestCursor = iter;
  307. }
  308. TuioCursor *freeCursor = (*closestCursor);
  309. c_id = freeCursor->getCursorID();
  310. freeCursorList.erase(closestCursor);
  311. delete freeCursor;
  312. } else maxCursorID = c_id;
  313. frameCursor = new TuioCursor(currentTime,tcur->getSessionID(),c_id,tcur->getX(),tcur->getY());
  314. cursorList.push_back(frameCursor);
  315. delete tcur;
  316. unlockCursorList();
  317. for (std::list<TuioListener*>::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++)
  318. (*listener)->addTuioCursor(frameCursor);
  319. break;
  320. default:
  321. lockCursorList();
  322. std::list<TuioCursor*>::iterator iter;
  323. for (iter=cursorList.begin(); iter != cursorList.end(); iter++) {
  324. if((*iter)->getSessionID()==tcur->getSessionID()) {
  325. frameCursor = (*iter);
  326. break;
  327. }
  328. }
  329. if ( (tcur->getX()!=frameCursor->getX() && tcur->getXSpeed()==0) || (tcur->getY()!=frameCursor->getY() && tcur->getYSpeed()==0) )
  330. frameCursor->update(currentTime,tcur->getX(),tcur->getY());
  331. else
  332. frameCursor->update(currentTime,tcur->getX(),tcur->getY(),tcur->getXSpeed(),tcur->getYSpeed(),tcur->getMotionAccel());
  333. delete tcur;
  334. unlockCursorList();
  335. for (std::list<TuioListener*>::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++)
  336. (*listener)->updateTuioCursor(frameCursor);
  337. }
  338. }
  339. for (std::list<TuioListener*>::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++)
  340. (*listener)->refresh(currentTime);
  341. } else {
  342. for (std::list<TuioCursor*>::iterator iter=frameCursors.begin(); iter != frameCursors.end(); iter++) {
  343. TuioCursor *tcur = (*iter);
  344. delete tcur;
  345. }
  346. }
  347. frameCursors.clear();
  348. }
  349. }
  350. } catch( Exception& e ){
  351. std::cerr << "error parsing TUIO message: "<< msg.AddressPattern() << " - " << e.what() << std::endl;
  352. }
  353. }
  354. void TuioClient::ProcessPacket( const char *data, int size, const IpEndpointName& remoteEndpoint ) {
  355. try {
  356. ReceivedPacket p( data, size );
  357. if(p.IsBundle()) ProcessBundle( ReceivedBundle(p), remoteEndpoint);
  358. else ProcessMessage( ReceivedMessage(p), remoteEndpoint);
  359. } catch (MalformedBundleException& e) {
  360. std::cerr << "malformed OSC bundle: " << e.what() << std::endl;
  361. }
  362. }
  363. void TuioClient::connect(bool lk) {
  364. #ifndef WIN32
  365. /*pthread_mutexattr_settype(&attr_p, PTHREAD_MUTEX_RECURSIVE);
  366. pthread_mutex_init(&cursorMutex,&attr_p);
  367. pthread_mutex_init(&objectMutex,&attr_p);*/
  368. pthread_mutex_init(&cursorMutex,NULL);
  369. pthread_mutex_init(&objectMutex,NULL);
  370. #else
  371. cursorMutex = CreateMutex(NULL,FALSE,"cursorMutex");
  372. objectMutex = CreateMutex(NULL,FALSE,"objectMutex");
  373. #endif
  374. if (socket==NULL) return;
  375. TuioTime::initSession();
  376. currentTime.reset();
  377. locked = lk;
  378. if (!locked) {
  379. #ifndef WIN32
  380. pthread_create(&thread , NULL, ClientThreadFunc, this);
  381. #else
  382. DWORD threadId;
  383. thread = CreateThread( 0, 0, ClientThreadFunc, this, 0, &threadId );
  384. #endif
  385. } else socket->Run();
  386. connected = true;
  387. unlockCursorList();
  388. unlockObjectList();
  389. }
  390. void TuioClient::disconnect() {
  391. if (socket==NULL) return;
  392. socket->Break();
  393. if (!locked) {
  394. #ifdef WIN32
  395. if( thread ) CloseHandle( thread );
  396. #endif
  397. thread = 0;
  398. locked = false;
  399. }
  400. #ifndef WIN32
  401. pthread_mutex_destroy(&cursorMutex);
  402. pthread_mutex_destroy(&objectMutex);
  403. #else
  404. CloseHandle(cursorMutex);
  405. CloseHandle(objectMutex);
  406. #endif
  407. aliveObjectList.clear();
  408. aliveCursorList.clear();
  409. for (std::list<TuioObject*>::iterator iter=objectList.begin(); iter != objectList.end(); iter++)
  410. delete (*iter);
  411. objectList.clear();
  412. for (std::list<TuioCursor*>::iterator iter=cursorList.begin(); iter != cursorList.end(); iter++)
  413. delete (*iter);
  414. cursorList.clear();
  415. for (std::list<TuioCursor*>::iterator iter=freeCursorList.begin(); iter != freeCursorList.end(); iter++)
  416. delete(*iter);
  417. freeCursorList.clear();
  418. connected = false;
  419. }
  420. void TuioClient::addTuioListener(TuioListener *listener) {
  421. listenerList.push_back(listener);
  422. }
  423. void TuioClient::removeTuioListener(TuioListener *listener) {
  424. std::list<TuioListener*>::iterator result = find(listenerList.begin(),listenerList.end(),listener);
  425. if (result!=listenerList.end()) listenerList.remove(listener);
  426. }
  427. TuioObject* TuioClient::getTuioObject(long s_id) {
  428. lockObjectList();
  429. for (std::list<TuioObject*>::iterator iter=objectList.begin(); iter != objectList.end(); iter++) {
  430. if((*iter)->getSessionID()==s_id) {
  431. unlockObjectList();
  432. return (*iter);
  433. }
  434. }
  435. unlockObjectList();
  436. return NULL;
  437. }
  438. TuioCursor* TuioClient::getTuioCursor(long s_id) {
  439. lockCursorList();
  440. for (std::list<TuioCursor*>::iterator iter=cursorList.begin(); iter != cursorList.end(); iter++) {
  441. if((*iter)->getSessionID()==s_id) {
  442. unlockCursorList();
  443. return (*iter);
  444. }
  445. }
  446. unlockCursorList();
  447. return NULL;
  448. }
  449. std::list<TuioObject*> TuioClient::getTuioObjects() {
  450. lockObjectList();
  451. std::list<TuioObject*> listBuffer = objectList;
  452. unlockObjectList();
  453. return listBuffer;
  454. }
  455. std::list<TuioCursor*> TuioClient::getTuioCursors() {
  456. lockCursorList();
  457. std::list<TuioCursor*> listBuffer = cursorList;
  458. unlockCursorList();
  459. return listBuffer;
  460. }