libcm is a C development framework with an emphasis on audio signal processing applications.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

cmDspNet.c 25KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896
  1. #include "cmPrefix.h"
  2. #include "cmGlobal.h"
  3. #include "cmFloatTypes.h"
  4. #include "cmRpt.h"
  5. #include "cmErr.h"
  6. #include "cmCtx.h"
  7. #include "cmMem.h"
  8. #include "cmMallocDebug.h"
  9. #include "cmLinkedHeap.h"
  10. #include "cmFileSys.h"
  11. #include "cmSymTbl.h"
  12. #include "cmJson.h"
  13. #include "cmPrefs.h"
  14. #include "cmDspValue.h"
  15. #include "cmMsgProtocol.h"
  16. #include "cmThread.h"
  17. #include "cmUdpPort.h"
  18. #include "cmUdpNet.h"
  19. #include "cmTime.h"
  20. #include "cmAudioSys.h"
  21. #include "cmProcObj.h"
  22. #include "cmDspCtx.h"
  23. #include "cmDspClass.h"
  24. #include "cmDspStore.h"
  25. #include "cmDspSys.h"
  26. #include "cmDspPreset.h"
  27. #include "cmDspNet.h"
  28. ///============================================================================================
  29. ///============================================================================================
  30. /*
  31. cmDspSysAlloc()
  32. - create the p->netNodeArray[]
  33. - create the p->thH network thread but leave it paused
  34. cmDspSysLoad()
  35. - _cmDspSysNetPreload() - set srcConnList to NULL
  36. - load the progam - this result in calls to _cmDspSysNetCreateSrcConn()
  37. which creates the p->srcConnList.
  38. - _cmDspSysNetSync() - just before exiting the load process go into sync mode:
  39. - initialize the p->netNodeArray[].
  40. - set the srcId of each record in the p->srcConnList.
  41. - start the sync thread
  42. while(1)
  43. {
  44. 1) send connection requests to dst machines
  45. 2) if( connFl = all src conn's have dst id's )
  46. send 'done' to all remote nodes
  47. 3) nodeFl = if have recv'd 'done' from all remote nodes
  48. 4) if connFl && nodeFl
  49. p->syncState = kSyncSuccessDspId;
  50. break;
  51. }
  52. Enable Audio:
  53. - Call reset on all instances
  54. cmDspSysUnload()
  55. - p->syncState = kSyncPreDspId
  56. cmDspSysFree()
  57. - delete p->netNodeArray[]
  58. - delete p->thH network thread
  59. //--------------------------------------------------------
  60. */
  61. ///============================================================================================
  62. // implemented in cmDspSys.c
  63. cmDspInst_t* _cmDspSysInstSymIdToPtr( cmDsp_t* p, unsigned instSymId );
  64. cmDsp_t* _cmDspHandleToPtr( cmDspSysH_t h );
  65. cmDspRC_t _cmDspSysNetSend( cmDsp_t* p, unsigned remoteNetNodeId, unsigned subSelId, unsigned srcId, unsigned dstId, const cmChar_t* errMsg )
  66. {
  67. cmDspRC_t rc = kOkDspRC;
  68. cmDspNetMsg_t m;
  69. memset(&m,0,sizeof(m));
  70. // we should never be sending to ourselves
  71. assert( remoteNetNodeId != cmUdpNetLocalNodeId(p->netH));
  72. // form the error msg
  73. m.asSubIdx = cmDspSys_AsSubIdx_Zero;
  74. m.selId = kNetSyncSelAsId;
  75. m.subSelId = subSelId;
  76. m.srcId = srcId;
  77. m.dstId = dstId;
  78. if( cmUdpNetSendById(p->netH, remoteNetNodeId, &m, sizeof(m) ) == kOkUnRC )
  79. {
  80. //cmSleepUs(p->sendWaitMs*1000);
  81. }
  82. else
  83. {
  84. rc = kNetFailDspRC;
  85. if( errMsg != NULL )
  86. cmErrMsg(&p->err,rc,errMsg);
  87. }
  88. return rc;
  89. }
  90. // set echoFl if the remote node should respond with it's own 'hello' msg
  91. cmDspRC_t _cmDspSysNetSendHello( cmDsp_t* p, unsigned remoteNetNodeId, bool echoFl )
  92. {
  93. return _cmDspSysNetSend(p, remoteNetNodeId, kNetHelloSelAsId, echoFl ? 1 : 0, cmInvalidId, "A network send failed while sending 'hello'." );
  94. }
  95. cmDspRC_t _cmDspSysNetSendSyncError( cmDsp_t* p, cmDspRC_t errRc )
  96. {
  97. cmDspRC_t rc = kOkDspRC;
  98. unsigned i;
  99. // for each non-local node
  100. for(i=0; i<p->netNodeCnt; ++i)
  101. if( p->netNodeArray[i].localFl == false)
  102. {
  103. unsigned remoteNetNodeId = p->netNodeArray[i].id;
  104. cmDspRC_t rc0;
  105. // send the error code in the dstId
  106. if((rc0 = _cmDspSysNetSend(p, remoteNetNodeId, kNetErrSelAsId, cmUdpNetLocalNodeId(p->netH), errRc, "A network send failed while signaling an error." )) != kOkDspRC )
  107. rc = rc0;
  108. }
  109. if( cmThreadPause(p->thH,kPauseThFl) != kOkThRC )
  110. rc = cmErrMsg(&p->err,kThreadFailDspRC,"An attempt to pause the sync. thread failed after signaling an error.");
  111. if( p->netVerbosity > 0 )
  112. cmRptPrintf(p->err.rpt,"Sync:Done - Fail\n");
  113. return rc;
  114. }
  115. bool _cmDspSysNetIsNodeAwake( cmDsp_t* p, unsigned netNodeId )
  116. {
  117. unsigned i;
  118. for(i=0; i<p->netNodeCnt; ++i)
  119. if( p->netNodeArray[i].id == netNodeId )
  120. return p->netNodeArray[i].helloFl;
  121. assert(0); // unknown net node id
  122. return false;
  123. }
  124. bool _cmDspSysNet_AreAllDstIdsResolved( cmDsp_t* p )
  125. {
  126. // check that we have received all dst id req's from each remote node
  127. unsigned i;
  128. for(i=0; i<p->netNodeCnt; ++i)
  129. if( p->netNodeArray[i].localFl == false && p->netNodeArray[i].reqDoneFl==false)
  130. return false;
  131. _cmDspSrcConn_t* rp = p->srcConnList;
  132. // for each src connection which does not yet have a destination id.
  133. for(; rp != NULL; rp = rp->link)
  134. if( rp->dstId == cmInvalidId )
  135. return false;
  136. return true;
  137. }
  138. // send connection requests to the specified remote node
  139. cmDspRC_t _cmDspSysNetSendConnRequests( cmDsp_t* p, unsigned dstNetNodeId )
  140. {
  141. cmDspRC_t rc = kOkDspRC;
  142. _cmDspSrcConn_t* rp = p->srcConnList;
  143. // for each src connection which does not yet have a destination id.
  144. for(; rp != NULL; rp = rp->link)
  145. {
  146. // if this src conn has not been assigned a dstId and it's source node is awake
  147. if( rp->dstId == cmInvalidId && rp->dstNetNodeId==dstNetNodeId && _cmDspSysNetIsNodeAwake(p,rp->dstNetNodeId) )
  148. {
  149. // calc the msg size
  150. unsigned sn0 = strlen(rp->dstInstLabel) + 1;
  151. unsigned sn1 = strlen(rp->dstVarLabel) + 1;
  152. unsigned byteCnt = sizeof(cmDspNetMsg_t) + sn0 + sn1;
  153. // create msg buffer
  154. char buf[ byteCnt ];
  155. memset(buf,0,byteCnt);
  156. // fill in the msg
  157. cmDspNetMsg_t* cp = (cmDspNetMsg_t*)buf;
  158. cp->asSubIdx = cmDspSys_AsSubIdx_Zero;
  159. cp->selId = kNetSyncSelAsId;
  160. cp->subSelId = kNetDstIdReqSelAsId;
  161. cp->srcId = rp->srcId;
  162. cp->dstId = cmInvalidId;
  163. char* dp = buf + sizeof(*cp);
  164. memcpy(dp,rp->dstInstLabel,sn0);
  165. dp += sn0;
  166. memcpy(dp,rp->dstVarLabel,sn1);
  167. dp += sn1;
  168. assert(dp == buf + byteCnt );
  169. // send the msg
  170. if( cmUdpNetSendById(p->netH, rp->dstNetNodeId, buf, byteCnt ) != kOkUnRC )
  171. {
  172. rc = cmErrMsg(&p->err,kNetFailDspRC,"A network send failed while registering remote nodes.");
  173. goto errLabel;
  174. }
  175. if( p->netVerbosity > 1 )
  176. cmRptPrintf(p->err.rpt,"Sync: send req to %i\n",rp->dstNetNodeId);
  177. //cmSleepUs(p->sendWaitMs*1000); // wait between transmissions
  178. }
  179. }
  180. errLabel:
  181. if( rc != kOkDspRC )
  182. _cmDspSysNetSendSyncError(p,rc);
  183. return rc;
  184. }
  185. // Return true when the 'doneFl' on all nodes has been set.
  186. // The doneFl is cleared on the beginning of the sync. process.
  187. // The doneFl is set as each remote node signals that it has
  188. // all of the dstId's that it needs by sending kNetDoneSelAsId
  189. // messages.
  190. bool _cmDspSysNetCheckNetNodeStatus( cmDsp_t* p )
  191. {
  192. unsigned i;
  193. for(i=0; i<p->netNodeCnt; ++i)
  194. if( p->netNodeArray[i].doneFl == false )
  195. return false;
  196. return true;
  197. }
  198. // Send kNetDoneSelAsId msgs to all remote nodes to indicate that
  199. // this node has all of it's dstId's.
  200. cmDspRC_t _cmDspSysNetSendSyncDone( cmDsp_t* p )
  201. {
  202. cmDspRC_t rc = kOkDspRC;
  203. unsigned i;
  204. // broadcast the sync 'done' msg to each non-local node
  205. if( p->netDoneSentFl )
  206. return rc;
  207. for(i=0; i<p->netNodeCnt; ++i)
  208. if( p->netNodeArray[i].localFl == false )
  209. {
  210. if((rc = _cmDspSysNetSend(p, p->netNodeArray[i].id, kNetDoneSelAsId, cmInvalidId, cmInvalidId, "A network send failed while signaling sync. completion." )) != kOkDspRC )
  211. goto errLabel;
  212. }
  213. // create the src connection map
  214. _cmDspSrcConn_t* sp = p->srcConnList;
  215. if( sp != NULL && p->srcConnMapCnt == 0 )
  216. {
  217. if( p->netVerbosity > 0 )
  218. cmRptPrintf(p->err.rpt,"Sync:Creating src map\n");
  219. // get the count of src nodes
  220. unsigned n;
  221. for(n=0; sp != NULL; sp = sp->link )
  222. ++n;
  223. // allocate the srcConnMap
  224. p->srcConnMap = cmLhResizeNZ( p->ctx.lhH, _cmDspSrcConn_t*, p->srcConnMap, n );
  225. p->srcConnMapCnt = n;
  226. // load the srcConnMap
  227. for(sp = p->srcConnList; sp != NULL; sp = sp->link )
  228. {
  229. assert( sp->srcId < n );
  230. p->srcConnMap[ sp->srcId ] = sp;
  231. }
  232. }
  233. // create the dst connection map
  234. _cmDspDstConn_t* dp = p->dstConnList;
  235. if( dp != NULL && p->dstConnMapCnt == 0 )
  236. {
  237. if( p->netVerbosity > 0 )
  238. cmRptPrintf(p->err.rpt,"Sync:Creating dst map\n");
  239. unsigned n;
  240. // get the count of dst nodes
  241. for(n=0; dp != NULL; dp = dp->link )
  242. ++n;
  243. // allocate the dstConnMap
  244. p->dstConnMap = cmLhResizeNZ( p->ctx.lhH, _cmDspDstConn_t*, p->dstConnMap, n );
  245. p->dstConnMapCnt = n;
  246. // load the dstConnMap
  247. for(dp = p->dstConnList; dp != NULL; dp = dp->link )
  248. {
  249. assert( dp->dstId < n );
  250. p->dstConnMap[ dp->dstId ] = dp;
  251. }
  252. }
  253. p->netDoneSentFl = true;
  254. if( p->netVerbosity > 0 )
  255. cmRptPrintf(p->err.rpt,"Sync: Done Sent\n",i);
  256. errLabel:
  257. if( rc != kOkDspRC )
  258. _cmDspSysNetSendSyncError(p,rc);
  259. return rc;
  260. }
  261. // Sync thread callback function
  262. bool _cmDspSysNetSyncThreadCb( void* param )
  263. {
  264. cmDsp_t* p = (cmDsp_t*)param;
  265. bool connFl = true; //
  266. bool nodeFl = true;
  267. // receive a group of waiting messages from remote nodes
  268. // WARNING: calling cmUdpNetReceive() here means that the audio engine cannot be
  269. // enabled - otherwise this thread and the audio system thread will simultaneously
  270. // attempt to read the UDP port. This will result in unsafe thread conflicts.
  271. if( cmUdpNetReceive(p->netH, NULL ) != kOkUnRC )
  272. {
  273. cmErrMsg(&p->err,kNetFailDspRC,"UDP Net receive failed during sync. mode.");
  274. _cmDspSysNetSendSyncError(p,kNetFailDspRC);
  275. }
  276. // check if all the src connections have been assigned dst id's
  277. connFl = _cmDspSysNet_AreAllDstIdsResolved(p);
  278. // if all the src connections have dst id's then send a 'done' signal
  279. // to all other nodes so that they know this node is ready to leave
  280. // sync mode
  281. if( connFl )
  282. {
  283. if( _cmDspSysNetSendSyncDone(p) != kOkDspRC )
  284. goto errLabel;
  285. }
  286. // prevent the thread from burning too much time
  287. cmSleepUs(p->sendWaitMs*1000);
  288. // check if all nodes have completed transmission to this node
  289. nodeFl = _cmDspSysNetCheckNetNodeStatus(p);
  290. // if the connections have all been setup and all the net nodes have
  291. // received a 'done' signal
  292. if( connFl && nodeFl )
  293. {
  294. // mark the sync as complete
  295. p->syncState = kSyncSuccessDspId;
  296. // the sync. is done - pause this thread
  297. if( cmThreadPause( p->thH, kPauseThFl ) != kOkThRC )
  298. cmErrMsg(&p->err,kThreadFailDspRC,"The attempt to pause the sync. thread upon completion failed.");
  299. if( p->netVerbosity > 0 )
  300. cmRptPrintf(p->err.rpt,"Sync Done!\n");
  301. }
  302. errLabel:
  303. return true;
  304. }
  305. // During DSP network allocation and connection this function is called
  306. // to register remote instance/var targets.
  307. _cmDspSrcConn_t* _cmDspSysNetCreateSrcConn( cmDsp_t* p, unsigned dstNetNodeId, const cmChar_t* dstInstLabel, const cmChar_t* dstVarLabel )
  308. {
  309. if( dstNetNodeId == cmUdpNetLocalNodeId(p->netH) )
  310. {
  311. cmErrMsg(&p->err,kNetFailDspRC,"Cannot connect a network node (node:%s inst:%s label:%s)to itself.",cmStringNullGuard(cmUdpNetNodeIdToLabel(p->netH,dstNetNodeId)),cmStringNullGuard(dstInstLabel),cmStringNullGuard(dstVarLabel));
  312. return NULL;
  313. }
  314. // register the remote node
  315. _cmDspSrcConn_t* rp = cmLhAllocZ( p->ctx.lhH, _cmDspSrcConn_t, 1 );
  316. rp->dstNetNodeId = dstNetNodeId;
  317. rp->dstInstLabel = cmLhAllocStr( p->ctx.lhH, dstInstLabel );
  318. rp->dstVarLabel = cmLhAllocStr( p->ctx.lhH, dstVarLabel );
  319. rp->link = p->srcConnList;
  320. p->srcConnList = rp;
  321. if( p->netVerbosity > 1 )
  322. cmRptPrintf(p->err.rpt,"Sync: create src for %i\n", dstNetNodeId );
  323. return rp;
  324. }
  325. // This function is called in response to receiving a connection request on the
  326. // dst machine. It sends a dstId to match the srcId provided by the src machine.
  327. cmDspRC_t _cmDspSysNetSendDstConnId( cmDsp_t* p, unsigned srcNetNodeId, unsigned srcId, unsigned dstId )
  328. {
  329. cmDspRC_t rc = kOkDspRC;
  330. if((rc = _cmDspSysNetSend(p, srcNetNodeId, kNetDstIdSelAsId, srcId, dstId, "A network send failed while sending a dst. id." )) == kOkDspRC )
  331. {
  332. if( p->netVerbosity > 1 )
  333. cmRptPrintf(p->err.rpt,"Sync:Sent dst id to %i\n",srcNetNodeId);
  334. }
  335. return rc;
  336. }
  337. // Handle 'hello' messages
  338. cmDspRC_t _cmDspSysNetReceiveHello( cmDsp_t* p, unsigned remoteNetNodeId, bool echoFl )
  339. {
  340. cmDspRC_t rc = kOkDspRC;
  341. unsigned i;
  342. for(i=0; i<p->netNodeCnt; ++i)
  343. if( p->netNodeArray[i].id == remoteNetNodeId )
  344. {
  345. p->netNodeArray[i].helloFl = true;
  346. // if echo was requested then respond ...
  347. if( echoFl )
  348. {
  349. // ... but the remote node should not respond - because we already know about it
  350. _cmDspSysNetSendHello(p,remoteNetNodeId,false);
  351. }
  352. if( p->netVerbosity > 0 )
  353. cmRptPrintf(p->err.rpt,"Sync:hello from %i\n",remoteNetNodeId);
  354. // send connection requests to the remote net node
  355. if((rc = _cmDspSysNetSendConnRequests(p, remoteNetNodeId )) == kOkDspRC )
  356. {
  357. // send 'req done' msg
  358. rc = _cmDspSysNetSend(p, remoteNetNodeId, kNetDstIdReqDoneAsId, 0, cmInvalidId, "A network send failed while sending 'dst req done'." );
  359. }
  360. return rc;
  361. }
  362. return cmErrMsg(&p->err,kNetFailDspRC,"Received a 'hello' message from an unknown remote network node (id=%i).",remoteNetNodeId);
  363. }
  364. cmDspRC_t _cmDspSysNetReceiveReqDone( cmDsp_t* p, unsigned remoteNetNodeId )
  365. {
  366. unsigned i;
  367. for(i=0; i<p->netNodeCnt; ++i)
  368. if( p->netNodeArray[i].id == remoteNetNodeId )
  369. {
  370. p->netNodeArray[i].reqDoneFl = true;
  371. if( p->netVerbosity > 0 )
  372. cmRptPrintf(p->err.rpt,"Sync: Req Done from %i\n",remoteNetNodeId);
  373. return kOkDspRC;
  374. }
  375. return cmErrMsg(&p->err,kNetFailDspRC,"Received a 'req done' message from an unknown remote network node (id=%i).",remoteNetNodeId);
  376. }
  377. // given a srcNetNodeId/srcId return the associated dst connection
  378. _cmDspDstConn_t* _cmDspSysNetSrcIdToDstConn( cmDsp_t* p, unsigned srcNetNodeId, unsigned srcId )
  379. {
  380. _cmDspDstConn_t* rp = p->dstConnList;
  381. for(; rp != NULL; rp = rp->link )
  382. if( rp->srcNetNodeId == srcNetNodeId && rp->srcId == srcId )
  383. return rp;
  384. return NULL;
  385. }
  386. // Handle kNetSyncSelAsId messages.
  387. // Called on the dst machine to receive a src connection request
  388. cmDspRC_t _cmDspSysNetReceiveSrcConnRequest( cmDsp_t* p, const cmDspNetMsg_t* msg, unsigned srcNetNodeId )
  389. {
  390. cmDspRC_t rc = kOkDspRC;
  391. _cmDspDstConn_t* rp;
  392. // if a dstId has not already been assigned to this src
  393. if((rp = _cmDspSysNetSrcIdToDstConn(p, srcNetNodeId, msg->srcId )) == NULL )
  394. {
  395. if( p->netVerbosity > 1 )
  396. cmRptPrintf(p->err.rpt,"Sync:Rcvd src conn request from %i\n",srcNetNodeId);
  397. cmDspInst_t* instPtr = NULL;
  398. const cmDspVar_t* varPtr;
  399. const cmChar_t* instLabel = (const cmChar_t*)(msg+1);
  400. const cmChar_t* varLabel = instLabel + strlen(instLabel) + 1;
  401. // get the symbols assoc'd with the dst inst/var
  402. unsigned instSymId = cmSymTblId(p->ctx.stH,instLabel);
  403. unsigned varSymId = cmSymTblId(p->ctx.stH,varLabel);
  404. assert( instSymId != cmInvalidId );
  405. // find the dst inst
  406. if((instPtr = _cmDspSysInstSymIdToPtr(p,instSymId)) == NULL )
  407. {
  408. rc = cmErrMsg(&p->err,kInstNotFoundDspRC,"The instance associated with '%s' was not found.",cmStringNullGuard(instLabel));
  409. goto errLabel;
  410. }
  411. // find dst var
  412. if((varPtr = cmDspVarSymbolToPtr(&p->ctx, instPtr, varSymId, kInDsvFl )) == NULL )
  413. {
  414. rc = cmErrMsg(&p->err,kVarNotFoundDspRC,"The variable '%s' on the instance '%s' was not found.",cmStringNullGuard(varLabel),cmStringNullGuard(instLabel));
  415. goto errLabel;
  416. }
  417. // register the new dst connection
  418. rp = cmLhAllocZ( p->ctx.lhH, _cmDspDstConn_t, 1 );
  419. rp->srcNetNodeId = srcNetNodeId;
  420. rp->srcId = msg->srcId;
  421. rp->dstId = p->nextDstId++;
  422. rp->dstInst = instPtr;
  423. rp->dstVarId = varPtr->constId;
  424. rp->link = p->dstConnList;
  425. p->dstConnList = rp;
  426. }
  427. assert( rp != NULL );
  428. // send the dstId associated with this connection back to the source
  429. if((rc = _cmDspSysNetSendDstConnId(p,srcNetNodeId,msg->srcId,rp->dstId)) != kOkDspRC )
  430. goto errLabel;
  431. errLabel:
  432. if( rc != kOkDspRC )
  433. _cmDspSysNetSendSyncError(p,rc);
  434. return rc;
  435. }
  436. cmDspRC_t _cmDspSysNetReceiveDstId(cmDsp_t* p, const cmDspNetMsg_t* msg, unsigned remoteNetNodeId)
  437. {
  438. cmDspRC_t rc;
  439. _cmDspSrcConn_t* sp = p->srcConnList;
  440. for(; sp != NULL; sp = sp->link )
  441. if( msg->srcId == sp->srcId )
  442. {
  443. sp->dstId = msg->dstId;
  444. return kOkDspRC;
  445. }
  446. rc = cmErrMsg(&p->err,kNetNodeNotFoundDspRC,"The src id %i associated with the dst id %i could not be found.",msg->srcId,msg->dstId);
  447. _cmDspSysNetSendSyncError(p,rc);
  448. return rc;
  449. }
  450. // Handle kNetDoneSelAsId messages.
  451. cmDspRC_t _cmDspSysNetReceiveRemoteSyncDone( cmDsp_t* p, const cmDspNetMsg_t* msg, unsigned remoteNetNodeId )
  452. {
  453. cmDspRC_t rc = kOkDspRC;
  454. unsigned i;
  455. for(i=0; i<p->netNodeCnt; ++i)
  456. if( p->netNodeArray[i].id == remoteNetNodeId )
  457. {
  458. p->netNodeArray[i].doneFl = true;
  459. if( p->netVerbosity > 0 )
  460. cmRptPrintf(p->err.rpt,"Sync: Rcvd done from %i\n",remoteNetNodeId);
  461. break;
  462. }
  463. return rc;
  464. }
  465. // Handle kNetErrSelAsId messages
  466. cmDspRC_t _cmDspSysNetReceiveRemoteSyncError( cmDsp_t* p, const cmDspNetMsg_t* msg, unsigned remoteNetNodeId )
  467. {
  468. cmDspRC_t rc = kOkDspRC;
  469. if( p->netVerbosity > 0 )
  470. cmRptPrintf(p->err.rpt,"Sync: Rcvd error from %i\n",remoteNetNodeId);
  471. if( cmThreadPause(p->thH,kPauseThFl) != kOkThRC )
  472. rc = cmErrMsg(&p->err,kThreadFailDspRC,"The attempt to pause the thread due to a remote error failed.");
  473. return rc;
  474. }
  475. // Verifify that a net node id is valid.
  476. cmDspRC_t _cmDspSysNetValidateNetNodeId( cmDsp_t* p, unsigned netNodeId )
  477. {
  478. cmDspRC_t rc = kOkDspRC;
  479. unsigned i;
  480. for(i=0; i<p->netNodeCnt; ++i)
  481. if( p->netNodeArray[i].id == netNodeId )
  482. break;
  483. if( i == p->netNodeCnt )
  484. rc = cmErrMsg(&p->err,kNetNodeNotFoundDspRC,"A message arrived from a unknown net node (id=%i).",netNodeId);
  485. return rc;
  486. }
  487. ///============================================================================================
  488. // main hooks to the DSP system
  489. // called by cmDspSysInitialize()
  490. cmDspRC_t _cmDspSysNetAlloc( cmDsp_t* p )
  491. {
  492. if((p->netNodeCnt = cmUdpNetNodeCount(p->netH)) != 0)
  493. p->netNodeArray = cmMemAllocZ(_cmDspNetNode_t, p->netNodeCnt );
  494. if( cmThreadCreate(&p->thH,_cmDspSysNetSyncThreadCb,p, p->err.rpt) != kOkThRC )
  495. return cmErrMsg(&p->err,kThreadFailDspRC,"The network syncronization thread create failed.");
  496. p->sendWaitMs = 10;
  497. p->syncState = kSyncPreDspId;
  498. p->netVerbosity = 1;
  499. return kOkDspRC;
  500. }
  501. // called by cmDspSysFinalize()
  502. cmDspRC_t _cmDspSysNetFree( cmDsp_t* p )
  503. {
  504. cmMemFree(p->netNodeArray);
  505. if( cmThreadDestroy(&p->thH) != kOkThRC )
  506. cmErrMsg(&p->err,kThreadFailDspRC,"The network syncrhonization thread destroy failed.");
  507. return kOkDspRC;
  508. }
  509. // called by cmDspSysLoad()
  510. cmDspRC_t _cmDspSysNetPreLoad( cmDsp_t* p )
  511. {
  512. p->srcConnList = NULL;
  513. return kOkDspRC;
  514. }
  515. // called by cmDspSysUnload()
  516. cmDspRC_t _cmDspSysNetUnload( cmDsp_t* p )
  517. {
  518. if( cmUdpNetEnableListen(p->netH, false ) != kOkUnRC )
  519. return cmErrMsg(&p->err,kNetFailDspRC,"The network failed to exit 'listening' mode.");
  520. p->syncState = kSyncPreDspId;
  521. p->nextDstId = 0;
  522. p->dstConnList = NULL;
  523. p->srcConnMap = NULL;
  524. p->srcConnMapCnt = 0;
  525. p->dstConnMap = NULL;
  526. p->dstConnMapCnt = 0;
  527. p->netDoneSentFl = false;
  528. return kOkDspRC;
  529. }
  530. // Call this function to enter 'sync' mode.
  531. cmDspRC_t _cmDspSysNetSync( cmDsp_t* p )
  532. {
  533. cmDspRC_t rc = kOkDspRC;
  534. unsigned localNodeId = cmUdpNetLocalNodeId(p->netH);
  535. unsigned i;
  536. // if there is no network then there is nothing to do
  537. if( p->netNodeCnt == 0 )
  538. {
  539. p->syncState = kSyncSuccessDspId;
  540. return kOkDspRC;
  541. }
  542. p->syncState = kSyncPendingDspId;
  543. // be sure the sync thread is paused before continuing
  544. if( cmThreadPause(p->thH, kPauseThFl | kWaitThFl ) != kOkThRC )
  545. {
  546. rc = cmErrMsg(&p->err,kThreadFailDspRC,"The network sync thread could not be paused prior to initialization.");
  547. goto errLabel;
  548. }
  549. // initialize the netNodeArry[]
  550. for(i=0; i<p->netNodeCnt; ++i)
  551. {
  552. p->netNodeArray[i].id = cmUdpNetNodeId(p->netH,i);
  553. p->netNodeArray[i].localFl = p->netNodeArray[i].id == localNodeId;
  554. p->netNodeArray[i].doneFl = p->netNodeArray[i].localFl;
  555. p->netNodeArray[i].helloFl = false;
  556. p->netNodeArray[i].reqDoneFl = false;
  557. p->netNodeArray[i].doneFl = false;
  558. assert( p->netNodeArray[i].id != cmInvalidId );
  559. }
  560. // initialize the src connection array - this array was created when the
  561. // DSP instance network was formed
  562. _cmDspSrcConn_t* rp = p->srcConnList;
  563. for(i=0; rp != NULL; rp = rp->link,++i)
  564. {
  565. rp->srcId = i;
  566. rp->dstId = cmInvalidId;
  567. }
  568. // clear the dst conn records
  569. _cmDspDstConn_t* dp = p->dstConnList;
  570. while( dp!=NULL)
  571. {
  572. _cmDspDstConn_t* np = dp->link;
  573. cmLhFree(p->ctx.lhH,dp);
  574. dp = np;
  575. }
  576. // clear the connection maps
  577. p->srcConnMapCnt = 0;
  578. p->dstConnMapCnt = 0;
  579. p->netDoneSentFl = false;
  580. // enter listening mode
  581. if( cmUdpNetEnableListen(p->netH, true ) != kOkUnRC )
  582. {
  583. rc = cmErrMsg(&p->err,kNetFailDspRC,"The network failed to go into 'listening' mode.");
  584. goto errLabel;
  585. }
  586. // start the sync process
  587. if( cmThreadPause(p->thH,0) != kOkThRC )
  588. {
  589. rc = cmErrMsg(&p->err,kThreadFailDspRC,"The network sync thread could not be un-paused prior to begin synchronization.");
  590. goto errLabel;
  591. }
  592. // broadcast 'hello' to all remote listeners and request that they respond with their own 'hello'.
  593. for(i=0; i<p->netNodeCnt; ++i)
  594. if( p->netNodeArray[i].localFl == false )
  595. if((rc = _cmDspSysNetSendHello(p,p->netNodeArray[i].id,true)) != kOkDspRC )
  596. goto errLabel;
  597. if( p->netVerbosity > 0 )
  598. cmRptPrintf(p->err.rpt,"Sync:Entering sync loop\n");
  599. errLabel:
  600. if( rc != kOkDspRC )
  601. p->syncState = kSyncFailDspId;
  602. return rc;
  603. }
  604. cmDspRC_t _cmDspSysNetRecvEvent( cmDsp_t* p, const void* msgPtr, unsigned msgByteCnt )
  605. {
  606. cmDspNetMsg_t* m = (cmDspNetMsg_t*)msgPtr;
  607. cmRC_t rc = cmOkRC;
  608. //bool jsFl = false;
  609. // if the value associated with this msg is a mtx then set
  610. // its mtx data area pointer to just after the msg header.
  611. if( cmDsvIsJson(&m->value) )
  612. {
  613. //rc = cmDsvDeserializeJson(&m->value,p->jsH);
  614. assert(0);
  615. //jsFl = true;
  616. }
  617. else
  618. rc = cmDsvDeserializeInPlace(&m->value,msgByteCnt-sizeof(cmDspNetMsg_t));
  619. if( rc != kOkDsvRC )
  620. rc = cmErrMsg(&p->err,kInvalidStateDspRC,"Deserialize failed on network event message.");
  621. else
  622. {
  623. assert( m->dstId < p->dstConnMapCnt );
  624. // form the event
  625. cmDspEvt_t e;
  626. e.flags = 0;
  627. e.srcInstPtr = NULL;
  628. e.srcVarId = cmInvalidId;
  629. e.valuePtr = &m->value;
  630. e.dstVarId = p->dstConnMap[ m->dstId ]->dstVarId;
  631. e.dstDataPtr = NULL;
  632. cmDspInst_t* instPtr = p->dstConnMap[ m->dstId ]->dstInst;
  633. assert(instPtr != NULL );
  634. // send the event
  635. if( instPtr->recvFunc != NULL )
  636. rc = instPtr->recvFunc(&p->ctx,instPtr,&e);
  637. }
  638. //if( jsFl )
  639. // cmJsonClearTree(p->jsH);
  640. return rc;
  641. }
  642. // Called from cmAudDsp.c:_cmAdUdpNetCallback() to to send an incoming msg to the DSP system.
  643. cmDspRC_t _cmDspSysNetRecv( cmDsp_t* p, const cmDspNetMsg_t* msg, unsigned msgByteCnt, unsigned remoteNetNodeId )
  644. {
  645. assert( msg->selId == kNetSyncSelAsId );
  646. cmDspRC_t rc = kOkDspRC;
  647. switch( msg->subSelId )
  648. {
  649. case kNetHelloSelAsId:
  650. rc = _cmDspSysNetReceiveHello(p,remoteNetNodeId,msg->srcId!=0);
  651. break;
  652. case kNetDstIdReqSelAsId:
  653. rc = _cmDspSysNetReceiveSrcConnRequest(p,msg,remoteNetNodeId);
  654. break;
  655. case kNetDstIdReqDoneAsId:
  656. rc = _cmDspSysNetReceiveReqDone(p,remoteNetNodeId);
  657. break;
  658. case kNetDstIdSelAsId:
  659. rc = _cmDspSysNetReceiveDstId(p,msg,remoteNetNodeId);
  660. break;
  661. case kNetDoneSelAsId:
  662. rc = _cmDspSysNetReceiveRemoteSyncDone(p,msg,remoteNetNodeId);
  663. break;
  664. case kNetErrSelAsId:
  665. rc = _cmDspSysNetReceiveRemoteSyncError(p,msg,remoteNetNodeId);
  666. break;
  667. case kNetEvtSelAsId:
  668. rc = _cmDspSysNetRecvEvent(p, msg, msgByteCnt );
  669. break;
  670. default:
  671. cmErrMsg(&p->err,kNetFailDspRC,"Unexpected message type 'selId=%i' received by the network sync. message dispatcher.",msg->selId);
  672. break;
  673. }
  674. return rc;
  675. }
  676. cmDspRC_t _cmDspSysNetSendEvent( cmDspSysH_t h, unsigned dstNetNodeId, unsigned dstId, const cmDspEvt_t* evt )
  677. {
  678. cmDsp_t* p = _cmDspHandleToPtr(h);
  679. unsigned bufByteCnt = sizeof(cmDspNetMsg_t);
  680. unsigned dataByteCnt = 0;
  681. if( evt->valuePtr != NULL )
  682. dataByteCnt = cmDsvSerialDataByteCount(evt->valuePtr);
  683. bufByteCnt += dataByteCnt;
  684. char buf[ bufByteCnt ];
  685. cmDspNetMsg_t* hdr = (cmDspNetMsg_t*)buf;
  686. hdr->asSubIdx = cmDspSys_AsSubIdx_Zero;
  687. hdr->selId = kNetSyncSelAsId;
  688. hdr->subSelId = kNetEvtSelAsId;
  689. hdr->srcId = cmInvalidId;
  690. hdr->dstId = dstId;
  691. if( evt->valuePtr == NULL )
  692. cmDsvSetNull(&hdr->value);
  693. else
  694. {
  695. // this function relies on the 'ne->value' field being the last field in the 'hdr'.
  696. if( cmDsvSerialize( evt->valuePtr, &hdr->value, sizeof(cmDspValue_t) + dataByteCnt) != kOkDsvRC )
  697. return cmErrMsg(&p->err,kSerializeFailMsgRC,"An attempt to serialize a network event msg failed.");
  698. }
  699. if( cmUdpNetSendById(p->netH, dstNetNodeId, &buf, bufByteCnt ) != kOkUnRC )
  700. return cmErrMsg(&p->err,kNetFailDspRC,"A network send failed while sending a DSP event message.");
  701. return kOkDspRC;
  702. }