libcm is a C development framework with an emphasis on audio signal processing applications.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

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. }