TuioClient.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566
  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&) {
  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. if( strcmp( msg.AddressPattern(), "/tuio/2Dobj" ) == 0 ){
  101. const char* cmd;
  102. args >> cmd;
  103. if (strcmp(cmd,"set")==0) {
  104. int32 s_id, c_id;
  105. float xpos, ypos, angle, xspeed, yspeed, rspeed, maccel, raccel;
  106. args >> s_id >> c_id >> xpos >> ypos >> angle >> xspeed >> yspeed >> rspeed >> maccel >> raccel;
  107. lockObjectList();
  108. std::list<TuioObject*>::iterator tobj;
  109. for (tobj=objectList.begin(); tobj!= objectList.end(); tobj++)
  110. if((*tobj)->getSessionID()==(long)s_id) break;
  111. if (tobj == objectList.end()) {
  112. TuioObject *addObject = new TuioObject((long)s_id,(int)c_id,xpos,ypos,angle);
  113. frameObjects.push_back(addObject);
  114. } 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) ) {
  115. TuioObject *updateObject = new TuioObject((long)s_id,(*tobj)->getSymbolID(),xpos,ypos,angle);
  116. updateObject->update(xpos,ypos,angle,xspeed,yspeed,rspeed,maccel,raccel);
  117. frameObjects.push_back(updateObject);
  118. }
  119. unlockObjectList();
  120. } else if (strcmp(cmd,"alive")==0) {
  121. int32 s_id;
  122. aliveObjectList.clear();
  123. while(!args.Eos()) {
  124. args >> s_id;
  125. aliveObjectList.push_back((long)s_id);
  126. }
  127. } else if (strcmp(cmd,"fseq")==0) {
  128. int32 fseq;
  129. args >> fseq;
  130. bool lateFrame = false;
  131. if (fseq>0) {
  132. if (fseq>currentFrame) currentTime = TuioTime::getSessionTime();
  133. if ((fseq>=currentFrame) || ((currentFrame-fseq)>100)) currentFrame = fseq;
  134. else lateFrame = true;
  135. } else if ((TuioTime::getSessionTime().getTotalMilliseconds()-currentTime.getTotalMilliseconds())>100) {
  136. currentTime = TuioTime::getSessionTime();
  137. }
  138. if (!lateFrame) {
  139. lockObjectList();
  140. //find the removed objects first
  141. for (std::list<TuioObject*>::iterator tobj=objectList.begin(); tobj != objectList.end(); tobj++) {
  142. std::list<long>::iterator iter = find(aliveObjectList.begin(), aliveObjectList.end(), (*tobj)->getSessionID());
  143. if (iter == aliveObjectList.end()) {
  144. (*tobj)->remove(currentTime);
  145. frameObjects.push_back(*tobj);
  146. }
  147. }
  148. unlockObjectList();
  149. for (std::list<TuioObject*>::iterator iter=frameObjects.begin(); iter != frameObjects.end(); iter++) {
  150. TuioObject *tobj = (*iter);
  151. TuioObject *frameObject = NULL;
  152. switch (tobj->getTuioState()) {
  153. case TUIO_REMOVED:
  154. frameObject = tobj;
  155. frameObject->remove(currentTime);
  156. for (std::list<TuioListener*>::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++)
  157. (*listener)->removeTuioObject(frameObject);
  158. lockObjectList();
  159. for (std::list<TuioObject*>::iterator delobj=objectList.begin(); delobj!=objectList.end(); delobj++) {
  160. if((*delobj)->getSessionID()==frameObject->getSessionID()) {
  161. objectList.erase(delobj);
  162. break;
  163. }
  164. }
  165. unlockObjectList();
  166. break;
  167. case TUIO_ADDED:
  168. lockObjectList();
  169. frameObject = new TuioObject(currentTime,tobj->getSessionID(),tobj->getSymbolID(),tobj->getX(),tobj->getY(),tobj->getAngle());
  170. objectList.push_back(frameObject);
  171. unlockObjectList();
  172. for (std::list<TuioListener*>::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++)
  173. (*listener)->addTuioObject(frameObject);
  174. break;
  175. default:
  176. lockObjectList();
  177. std::list<TuioObject*>::iterator iter;
  178. for (iter=objectList.begin(); iter != objectList.end(); iter++) {
  179. if((*iter)->getSessionID()==tobj->getSessionID()) {
  180. frameObject = (*iter);
  181. break;
  182. }
  183. }
  184. if(iter==objectList.end()) break;
  185. if ( (tobj->getX()!=frameObject->getX() && tobj->getXSpeed()==0) || (tobj->getY()!=frameObject->getY() && tobj->getYSpeed()==0) )
  186. frameObject->update(currentTime,tobj->getX(),tobj->getY(),tobj->getAngle());
  187. else
  188. frameObject->update(currentTime,tobj->getX(),tobj->getY(),tobj->getAngle(),tobj->getXSpeed(),tobj->getYSpeed(),tobj->getRotationSpeed(),tobj->getMotionAccel(),tobj->getRotationAccel());
  189. unlockObjectList();
  190. for (std::list<TuioListener*>::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++)
  191. (*listener)->updateTuioObject(frameObject);
  192. }
  193. delete tobj;
  194. }
  195. for (std::list<TuioListener*>::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++)
  196. (*listener)->refresh(currentTime);
  197. } else {
  198. for (std::list<TuioObject*>::iterator iter=frameObjects.begin(); iter != frameObjects.end(); iter++) {
  199. TuioObject *tobj = (*iter);
  200. delete tobj;
  201. }
  202. }
  203. frameObjects.clear();
  204. }
  205. } else if( strcmp( msg.AddressPattern(), "/tuio/2Dcur" ) == 0 ) {
  206. const char* cmd;
  207. args >> cmd;
  208. if (strcmp(cmd,"set")==0) {
  209. int32 s_id;
  210. float xpos, ypos, xspeed, yspeed, maccel;
  211. args >> s_id >> xpos >> ypos >> xspeed >> yspeed >> maccel;
  212. lockCursorList();
  213. std::list<TuioCursor*>::iterator tcur;
  214. for (tcur=cursorList.begin(); tcur!= cursorList.end(); tcur++)
  215. if((*tcur)->getSessionID()==(long)s_id) break;
  216. if (tcur==cursorList.end()) {
  217. TuioCursor *addCursor = new TuioCursor((long)s_id,-1,xpos,ypos);
  218. frameCursors.push_back(addCursor);
  219. } else if ( ((*tcur)->getX()!=xpos) || ((*tcur)->getY()!=ypos) || ((*tcur)->getXSpeed()!=xspeed) || ((*tcur)->getYSpeed()!=yspeed) || ((*tcur)->getMotionAccel()!=maccel) ) {
  220. TuioCursor *updateCursor = new TuioCursor((long)s_id,(*tcur)->getCursorID(),xpos,ypos);
  221. updateCursor->update(xpos,ypos,xspeed,yspeed,maccel);
  222. frameCursors.push_back(updateCursor);
  223. }
  224. unlockCursorList();
  225. } else if (strcmp(cmd,"alive")==0) {
  226. int32 s_id;
  227. aliveCursorList.clear();
  228. while(!args.Eos()) {
  229. args >> s_id;
  230. aliveCursorList.push_back((long)s_id);
  231. }
  232. } else if( strcmp( cmd, "fseq" ) == 0 ){
  233. int32 fseq;
  234. args >> fseq;
  235. bool lateFrame = false;
  236. if (fseq>0) {
  237. if (fseq>currentFrame) currentTime = TuioTime::getSessionTime();
  238. if ((fseq>=currentFrame) || ((currentFrame-fseq)>100)) currentFrame = fseq;
  239. else lateFrame = true;
  240. } else if ((TuioTime::getSessionTime().getTotalMilliseconds()-currentTime.getTotalMilliseconds())>100) {
  241. currentTime = TuioTime::getSessionTime();
  242. }
  243. if (!lateFrame) {
  244. lockCursorList();
  245. // find the removed cursors first
  246. for (std::list<TuioCursor*>::iterator tcur=cursorList.begin(); tcur != cursorList.end(); tcur++) {
  247. std::list<long>::iterator iter = find(aliveCursorList.begin(), aliveCursorList.end(), (*tcur)->getSessionID());
  248. if (iter == aliveCursorList.end()) {
  249. (*tcur)->remove(currentTime);
  250. frameCursors.push_back(*tcur);
  251. }
  252. }
  253. unlockCursorList();
  254. for (std::list<TuioCursor*>::iterator iter=frameCursors.begin(); iter != frameCursors.end(); iter++) {
  255. TuioCursor *tcur = (*iter);
  256. int c_id = -1;
  257. TuioCursor *frameCursor = NULL;
  258. switch (tcur->getTuioState()) {
  259. case TUIO_REMOVED:
  260. frameCursor = tcur;
  261. frameCursor->remove(currentTime);
  262. for (std::list<TuioListener*>::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++)
  263. (*listener)->removeTuioCursor(frameCursor);
  264. lockCursorList();
  265. for (std::list<TuioCursor*>::iterator delcur=cursorList.begin(); delcur!=cursorList.end(); delcur++) {
  266. if((*delcur)->getSessionID()==frameCursor->getSessionID()) {
  267. cursorList.erase(delcur);
  268. break;
  269. }
  270. }
  271. if (frameCursor->getCursorID()==maxCursorID) {
  272. maxCursorID = -1;
  273. delete frameCursor;
  274. if (cursorList.size()>0) {
  275. std::list<TuioCursor*>::iterator clist;
  276. for (clist=cursorList.begin(); clist != cursorList.end(); clist++) {
  277. c_id = (*clist)->getCursorID();
  278. if (c_id>maxCursorID) maxCursorID=c_id;
  279. }
  280. freeCursorBuffer.clear();
  281. for (std::list<TuioCursor*>::iterator flist=freeCursorList.begin(); flist != freeCursorList.end(); flist++) {
  282. TuioCursor *freeCursor = (*flist);
  283. if (freeCursor->getCursorID()>maxCursorID) delete freeCursor;
  284. else freeCursorBuffer.push_back(freeCursor);
  285. }
  286. freeCursorList = freeCursorBuffer;
  287. } else {
  288. for (std::list<TuioCursor*>::iterator flist=freeCursorList.begin(); flist != freeCursorList.end(); flist++) {
  289. TuioCursor *freeCursor = (*flist);
  290. delete freeCursor;
  291. }
  292. freeCursorList.clear();
  293. }
  294. } else if (frameCursor->getCursorID()<maxCursorID) {
  295. freeCursorList.push_back(frameCursor);
  296. }
  297. unlockCursorList();
  298. break;
  299. case TUIO_ADDED:
  300. lockCursorList();
  301. c_id = (int)cursorList.size();
  302. if (((int)(cursorList.size())<=maxCursorID) && ((int)(freeCursorList.size())>0)) {
  303. std::list<TuioCursor*>::iterator closestCursor = freeCursorList.begin();
  304. for(std::list<TuioCursor*>::iterator iter = freeCursorList.begin();iter!= freeCursorList.end(); iter++) {
  305. if((*iter)->getDistance(tcur)<(*closestCursor)->getDistance(tcur)) closestCursor = iter;
  306. }
  307. TuioCursor *freeCursor = (*closestCursor);
  308. c_id = freeCursor->getCursorID();
  309. freeCursorList.erase(closestCursor);
  310. delete freeCursor;
  311. } else maxCursorID = c_id;
  312. frameCursor = new TuioCursor(currentTime,tcur->getSessionID(),c_id,tcur->getX(),tcur->getY());
  313. cursorList.push_back(frameCursor);
  314. delete tcur;
  315. unlockCursorList();
  316. for (std::list<TuioListener*>::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++)
  317. (*listener)->addTuioCursor(frameCursor);
  318. break;
  319. default:
  320. lockCursorList();
  321. std::list<TuioCursor*>::iterator iter;
  322. for (iter=cursorList.begin(); iter != cursorList.end(); iter++) {
  323. if((*iter)->getSessionID()==tcur->getSessionID()) {
  324. frameCursor = (*iter);
  325. break;
  326. }
  327. }
  328. if ( (tcur->getX()!=frameCursor->getX() && tcur->getXSpeed()==0) || (tcur->getY()!=frameCursor->getY() && tcur->getYSpeed()==0) )
  329. frameCursor->update(currentTime,tcur->getX(),tcur->getY());
  330. else
  331. frameCursor->update(currentTime,tcur->getX(),tcur->getY(),tcur->getXSpeed(),tcur->getYSpeed(),tcur->getMotionAccel());
  332. delete tcur;
  333. unlockCursorList();
  334. for (std::list<TuioListener*>::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++)
  335. (*listener)->updateTuioCursor(frameCursor);
  336. }
  337. }
  338. for (std::list<TuioListener*>::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++)
  339. (*listener)->refresh(currentTime);
  340. } else {
  341. for (std::list<TuioCursor*>::iterator iter=frameCursors.begin(); iter != frameCursors.end(); iter++) {
  342. TuioCursor *tcur = (*iter);
  343. delete tcur;
  344. }
  345. }
  346. frameCursors.clear();
  347. }
  348. }
  349. } catch( Exception& e ){
  350. std::cerr << "error parsing TUIO message: "<< msg.AddressPattern() << " - " << e.what() << std::endl;
  351. }
  352. }
  353. void TuioClient::ProcessPacket( const char *data, int size, const IpEndpointName& remoteEndpoint ) {
  354. try {
  355. ReceivedPacket p( data, size );
  356. if(p.IsBundle()) ProcessBundle( ReceivedBundle(p), remoteEndpoint);
  357. else ProcessMessage( ReceivedMessage(p), remoteEndpoint);
  358. } catch (MalformedBundleException& e) {
  359. std::cerr << "malformed OSC bundle: " << e.what() << std::endl;
  360. }
  361. }
  362. void TuioClient::connect(bool lk) {
  363. #ifndef WIN32
  364. /*pthread_mutexattr_settype(&attr_p, PTHREAD_MUTEX_RECURSIVE);
  365. pthread_mutex_init(&cursorMutex,&attr_p);
  366. pthread_mutex_init(&objectMutex,&attr_p);*/
  367. pthread_mutex_init(&cursorMutex,NULL);
  368. pthread_mutex_init(&objectMutex,NULL);
  369. #else
  370. cursorMutex = CreateMutex(NULL,FALSE,L"cursorMutex");
  371. objectMutex = CreateMutex(NULL,FALSE,L"objectMutex");
  372. #endif
  373. if (socket==NULL) return;
  374. TuioTime::initSession();
  375. currentTime.reset();
  376. locked = lk;
  377. if (!locked) {
  378. #ifndef WIN32
  379. pthread_create(&thread , NULL, ClientThreadFunc, this);
  380. #else
  381. DWORD threadId;
  382. thread = CreateThread( 0, 0, ClientThreadFunc, this, 0, &threadId );
  383. #endif
  384. } else socket->Run();
  385. connected = true;
  386. unlockCursorList();
  387. unlockObjectList();
  388. }
  389. void TuioClient::disconnect() {
  390. if (socket==NULL) return;
  391. socket->Break();
  392. if (!locked) {
  393. #ifdef WIN32
  394. if( thread ) CloseHandle( thread );
  395. #endif
  396. thread = 0;
  397. locked = false;
  398. }
  399. #ifndef WIN32
  400. pthread_mutex_destroy(&cursorMutex);
  401. pthread_mutex_destroy(&objectMutex);
  402. #else
  403. CloseHandle(cursorMutex);
  404. CloseHandle(objectMutex);
  405. #endif
  406. aliveObjectList.clear();
  407. aliveCursorList.clear();
  408. for (std::list<TuioObject*>::iterator iter=objectList.begin(); iter != objectList.end(); iter++)
  409. delete (*iter);
  410. objectList.clear();
  411. for (std::list<TuioCursor*>::iterator iter=cursorList.begin(); iter != cursorList.end(); iter++)
  412. delete (*iter);
  413. cursorList.clear();
  414. for (std::list<TuioCursor*>::iterator iter=freeCursorList.begin(); iter != freeCursorList.end(); iter++)
  415. delete(*iter);
  416. freeCursorList.clear();
  417. connected = false;
  418. }
  419. void TuioClient::addTuioListener(TuioListener *listener) {
  420. listenerList.push_back(listener);
  421. }
  422. void TuioClient::removeTuioListener(TuioListener *listener) {
  423. std::list<TuioListener*>::iterator result = find(listenerList.begin(),listenerList.end(),listener);
  424. if (result!=listenerList.end()) listenerList.remove(listener);
  425. }
  426. TuioObject* TuioClient::getTuioObject(long s_id) {
  427. lockObjectList();
  428. for (std::list<TuioObject*>::iterator iter=objectList.begin(); iter != objectList.end(); iter++) {
  429. if((*iter)->getSessionID()==s_id) {
  430. unlockObjectList();
  431. return (*iter);
  432. }
  433. }
  434. unlockObjectList();
  435. return NULL;
  436. }
  437. TuioCursor* TuioClient::getTuioCursor(long s_id) {
  438. lockCursorList();
  439. for (std::list<TuioCursor*>::iterator iter=cursorList.begin(); iter != cursorList.end(); iter++) {
  440. if((*iter)->getSessionID()==s_id) {
  441. unlockCursorList();
  442. return (*iter);
  443. }
  444. }
  445. unlockCursorList();
  446. return NULL;
  447. }
  448. std::list<TuioObject*> TuioClient::getTuioObjects() {
  449. lockObjectList();
  450. std::list<TuioObject*> listBuffer = objectList;
  451. unlockObjectList();
  452. return listBuffer;
  453. }
  454. std::list<TuioCursor*> TuioClient::getTuioCursors() {
  455. lockCursorList();
  456. std::list<TuioCursor*> listBuffer = cursorList;
  457. unlockCursorList();
  458. return listBuffer;
  459. }