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.

cmDevCfg.c 39KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501
  1. #include "cmGlobal.h"
  2. #include "cmFloatTypes.h"
  3. #include "cmRpt.h"
  4. #include "cmErr.h"
  5. #include "cmCtx.h"
  6. #include "cmMem.h"
  7. #include "cmMallocDebug.h"
  8. #include "cmLinkedHeap.h"
  9. #include "cmFileSys.h"
  10. #include "cmJson.h"
  11. #include "cmText.h"
  12. #include "cmThread.h"
  13. #include "cmMidi.h"
  14. #include "cmMidiPort.h"
  15. #include "cmAudioPort.h"
  16. #include "cmUdpPort.h"
  17. #include "cmRtSysMsg.h"
  18. #include "cmRtNet.h"
  19. #include "cmRtSys.h"
  20. #include "cmDevCfg.h"
  21. cmDevCfgH_t cmDevCfgNullHandle = cmSTATIC_NULL_HANDLE;
  22. typedef struct cmDcmCfg_str
  23. {
  24. cmChar_t* dcLabelStr; // the cfg label
  25. unsigned cfgId; // unique among all cfg's assigned to a loc
  26. cmTypeDcmId_t typeId; // the cfg type id (e.g. midi, audio, net, ...)
  27. cmChar_t* descStr; // summary description string
  28. // NOTE: any fields added to this structure, type generic (above)
  29. // or type specific (below), must be explicitely duplicated in cmDevCfgLocStore().
  30. union
  31. {
  32. cmDcmMidi_t m;
  33. cmDcmAudio_t a;
  34. cmDcmNet_t n;
  35. } u;
  36. struct cmDcmCfg_str* next;
  37. struct cmDcmCfg_str* prev;
  38. } cmDcmCfg_t;
  39. typedef struct
  40. {
  41. cmTypeDcmId_t tid; // Type Id for this map or tInvalidDcmTId if the record is not active.
  42. unsigned cfgId; // cfgId of the cfg recd assoc'd with this map
  43. cmDcmCfg_t* cfg; // pointer to the cfg recd assoc'd with this map (cfg->cfgId == cmDcmMap_t.cfgId)
  44. } cmDcmMap_t;
  45. typedef struct
  46. {
  47. bool activeFl;
  48. cmDcmMap_t* map;
  49. unsigned mapCnt;
  50. } cmDcmApp_t;
  51. typedef struct cmDcmLoc_str
  52. {
  53. cmChar_t* labelStr;
  54. cmDcmApp_t* app;
  55. unsigned appCnt;
  56. cmDcmCfg_t* cfg;
  57. struct cmDcmLoc_str* next;
  58. struct cmDcmLoc_str* prev;
  59. } cmDcmLoc_t;
  60. typedef struct
  61. {
  62. cmErr_t err;
  63. cmCtx_t* ctx;
  64. cmDcmLoc_t* loc;
  65. cmDcmLoc_t* clp;
  66. cmChar_t* fn;
  67. } cmDcm_t;
  68. cmDcm_t* _cmDcmHandleToPtr( cmDevCfgH_t h )
  69. {
  70. cmDcm_t* p = (cmDcm_t*)h.h;
  71. assert( p!=NULL );
  72. return p;
  73. }
  74. const cmChar_t* _cmDcmTrimLabel( cmDcm_t*p, const cmChar_t* s, const cmChar_t* title )
  75. {
  76. if( s == NULL )
  77. {
  78. cmErrMsg(&p->err,kBlankLabelDcRC,"A blank '%s' label was encountered.",title);
  79. return NULL;
  80. }
  81. while( *s && isspace(*s) )
  82. ++s;
  83. if( strlen(s) == 0 )
  84. {
  85. cmErrMsg(&p->err,kBlankLabelDcRC,"An empty '%s' label was encountered.",title);
  86. return NULL;
  87. }
  88. return s;
  89. }
  90. void _cmDcmFreeMidi( cmDcmMidi_t* r )
  91. {
  92. cmMemFree(r->devLabelStr);
  93. cmMemFree(r->portLabelStr);
  94. }
  95. void _cmDcmDuplMidi( cmDcmMidi_t* d, const cmDcmMidi_t* s )
  96. {
  97. d->devLabelStr = cmMemAllocStr(s->devLabelStr);
  98. d->portLabelStr = cmMemAllocStr(s->portLabelStr);
  99. d->inputFl = s->inputFl;
  100. d->devIdx = s->devIdx;
  101. d->portIdx = s->portIdx;
  102. }
  103. void _cmDcmFreeAudio( cmDcmAudio_t* r )
  104. {
  105. cmMemFree(r->inDevLabelStr);
  106. cmMemFree(r->outDevLabelStr);
  107. }
  108. void _cmDcmDuplAudio( cmDcmAudio_t* d, const cmDcmAudio_t* s )
  109. {
  110. d->inDevLabelStr = cmMemAllocStr(s->inDevLabelStr);
  111. d->outDevLabelStr = cmMemAllocStr(s->outDevLabelStr);
  112. d->rtSysArgs = s->rtSysArgs;
  113. }
  114. void _cmDcmFreeNet( cmDcmNet_t* r )
  115. {
  116. cmMemFree(r->sockAddr);
  117. }
  118. void _cmDcmDuplNet( cmDcmNet_t* d, const cmDcmNet_t* s )
  119. {
  120. d->sockAddr = cmMemAllocStr(s->sockAddr);
  121. d->portNumber = s->portNumber;
  122. d->activeFl = s->activeFl;
  123. }
  124. void _cmDcmFreeCfg( cmDcm_t* p, cmDcmLoc_t* lp, cmDcmCfg_t* cp )
  125. {
  126. // unlink the cfg recd
  127. if( cp->prev == NULL )
  128. lp->cfg = cp->next;
  129. else
  130. cp->prev->next = cp->next;
  131. if( cp->next != NULL )
  132. cp->next->prev = cp->prev;
  133. cmMemFree(cp->dcLabelStr);
  134. cmMemFree(cp->descStr);
  135. switch( cp->typeId )
  136. {
  137. case kMidiDcmTId: _cmDcmFreeMidi(&cp->u.m); break;
  138. case kAudioDcmTId: _cmDcmFreeAudio(&cp->u.a); break;
  139. case kNetDcmTId: _cmDcmFreeNet(&cp->u.n); break;
  140. default:
  141. assert(0);
  142. break;
  143. }
  144. cmMemFree(cp);
  145. }
  146. void _cmDcmFreeLoc( cmDcm_t* p, cmDcmLoc_t* lp )
  147. {
  148. unsigned i;
  149. // unlink the loc recd
  150. if( lp->prev == NULL )
  151. p->loc = lp->next;
  152. else
  153. lp->prev->next = lp->next;
  154. if( lp->next != NULL )
  155. lp->next->prev = lp->prev;
  156. // free each app
  157. for(i=0; i<lp->appCnt; ++i)
  158. cmMemFree(lp->app[i].map);
  159. cmMemFree(lp->app);
  160. cmMemFree(lp->labelStr);
  161. while( lp->cfg != NULL )
  162. _cmDcmFreeCfg(p,lp,lp->cfg);
  163. cmMemFree(lp);
  164. }
  165. void _cmDcmFreeAllLocs( cmDcm_t* p )
  166. {
  167. while( p->loc != NULL )
  168. _cmDcmFreeLoc(p,p->loc);
  169. p->clp = NULL;
  170. }
  171. cmDcRC_t _cmDcmFree( cmDcm_t* p )
  172. {
  173. cmDcRC_t rc = kOkDcRC;
  174. _cmDcmFreeAllLocs(p);
  175. cmMemFree(p->fn);
  176. cmMemFree(p);
  177. return rc;
  178. }
  179. cmDcmLoc_t* _cmDcmFindLoc( cmDcm_t* p, const cmChar_t* labelStr )
  180. {
  181. cmDcmLoc_t* lp = p->loc;
  182. for(; lp!=NULL; lp=lp->next)
  183. if(strcmp(lp->labelStr,labelStr) == 0)
  184. return lp;
  185. return NULL;
  186. }
  187. cmDcRC_t _cmDcmNewLoc( cmDcm_t* p, const cmChar_t* labelStr, cmDcmLoc_t** locRef)
  188. {
  189. cmDcmLoc_t* lp;
  190. assert(locRef != NULL);
  191. *locRef = NULL;
  192. // verify and condition the label
  193. if((labelStr = _cmDcmTrimLabel(p,labelStr,"location")) == NULL )
  194. return cmErrLastRC(&p->err);
  195. // verify that the label is not already in use
  196. if((lp = _cmDcmFindLoc(p,labelStr)) != NULL )
  197. return cmErrMsg(&p->err,kDuplLabelDcRC,"The location label '%s' is already in use.",labelStr);
  198. // create a new loc recd
  199. lp = cmMemAllocZ(cmDcmLoc_t,1);
  200. lp->labelStr = cmMemAllocStr(labelStr);
  201. // if the cur loc is not current set - then prepend loc
  202. if( p->clp == NULL )
  203. {
  204. lp->prev = NULL;
  205. lp->next = p->loc;
  206. if( p->loc == NULL )
  207. p->loc = lp;
  208. else
  209. p->loc->prev = lp;
  210. }
  211. else // otherwise insert loc after the cur loc
  212. {
  213. lp->prev = p->clp;
  214. lp->next = p->clp->next;
  215. if( p->clp->next != NULL )
  216. p->clp->next->prev = lp;
  217. p->clp->next = lp;
  218. }
  219. // make the new loc the current loc
  220. p->clp = lp;
  221. *locRef = lp;
  222. return kOkDcRC;
  223. }
  224. cmDcRC_t _cmDevCfgRead( cmDcm_t* p, cmJsonH_t jsH, const cmJsonNode_t* rootObjPtr );
  225. cmDcRC_t _cmDevCfgReadFile( cmDcm_t* p, const cmChar_t* fn )
  226. {
  227. cmDcRC_t rc = kOkDcRC;
  228. cmJsonH_t jsH = cmJsonNullHandle;
  229. // initialize the JSON tree from the preferences file
  230. if( cmJsonInitializeFromFile( &jsH, fn, p->ctx ) != kOkJsRC )
  231. {
  232. rc = cmErrMsg(&p->err,kJsonFailDcRC,"JSON initialization from '%s' failed.",cmStringNullGuard(fn));
  233. goto errLabel;
  234. }
  235. if((rc = _cmDevCfgRead(p, jsH, cmJsonRoot(jsH))) != kOkJsRC )
  236. goto errLabel;
  237. errLabel:
  238. if( cmJsonFinalize(&jsH) != kOkJsRC )
  239. cmErrMsg(&p->err,kJsonFailDcRC,"JSON finalization failed following dev cfg read.");
  240. return rc;
  241. }
  242. cmDcRC_t cmDevCfgAlloc( cmCtx_t* c, cmDevCfgH_t* hp, const cmChar_t* fn )
  243. {
  244. cmDcRC_t rc;
  245. cmDcmLoc_t* lp;
  246. if((rc = cmDevCfgFree(hp)) != kOkDcRC )
  247. return rc;
  248. cmDcm_t* p = cmMemAllocZ(cmDcm_t,1);
  249. cmErrSetup(&p->err,&c->rpt,"cmDevCfg");
  250. p->ctx = c;
  251. if( fn != NULL )
  252. {
  253. p->fn = cmMemAllocStr(fn);
  254. if( cmFsIsFile(fn) )
  255. {
  256. // if the file read fails then reset and go with the default empty setup.
  257. if(_cmDevCfgReadFile(p,fn) != kOkDcRC )
  258. _cmDcmFreeAllLocs(p);
  259. }
  260. }
  261. // if the location array is empty then create a default location
  262. if( p->loc == NULL )
  263. {
  264. if((rc = _cmDcmNewLoc(p,"Default", &lp)) != kOkDcRC )
  265. goto errLabel;
  266. }
  267. hp->h = p;
  268. errLabel:
  269. if( rc != kOkDcRC )
  270. _cmDcmFree(p);
  271. return rc;
  272. }
  273. cmDcRC_t cmDevCfgFree( cmDevCfgH_t* hp )
  274. {
  275. cmDcRC_t rc = kOkDcRC;
  276. if( hp == NULL || cmDevCfgIsValid(*hp) == false )
  277. return rc;
  278. cmDcm_t* p = _cmDcmHandleToPtr(*hp);
  279. if((rc = _cmDcmFree(p)) != kOkDcRC )
  280. return rc;
  281. hp->h = NULL;
  282. return rc;
  283. }
  284. bool cmDevCfgIsValid( cmDevCfgH_t h )
  285. { return h.h != NULL; }
  286. unsigned cmDevCfgCount( cmDevCfgH_t h, cmTypeDcmId_t typeId )
  287. {
  288. unsigned n = 0;
  289. cmDcm_t* p = _cmDcmHandleToPtr(h);
  290. assert( p->clp != NULL);
  291. const cmDcmCfg_t* cp = p->clp->cfg;
  292. for(; cp!= NULL; cp=cp->next)
  293. if( cp->typeId == typeId )
  294. ++n;
  295. return n;
  296. }
  297. cmDcmCfg_t* _cmDevCfgIndexToPtr( cmDcm_t* p, cmTypeDcmId_t typeId, unsigned index, bool errFl )
  298. {
  299. unsigned n = 0;
  300. assert( p->clp != NULL);
  301. cmDcmCfg_t* cp = p->clp->cfg;
  302. for(; cp!= NULL; cp=cp->next)
  303. if( cp->typeId == typeId )
  304. {
  305. if( n == index )
  306. return cp;
  307. ++n;
  308. }
  309. if( errFl )
  310. cmErrMsg(&p->err,kInvalidCfgIdxDcRC,"The cfg index %i is not valid in location '%s'.",cmStringNullGuard(p->clp->labelStr));
  311. return NULL;
  312. }
  313. const cmChar_t* cmDevCfgLabel( cmDevCfgH_t h, cmTypeDcmId_t typeId, unsigned index )
  314. {
  315. cmDcm_t* p = _cmDcmHandleToPtr(h);
  316. cmDcmCfg_t* cp;
  317. if((cp = _cmDevCfgIndexToPtr(p,typeId,index,false)) == NULL )
  318. return NULL;
  319. return cp->dcLabelStr;
  320. }
  321. const cmChar_t* cmDevCfgDesc( cmDevCfgH_t h, cmTypeDcmId_t typeId, unsigned index )
  322. {
  323. cmDcm_t* p = _cmDcmHandleToPtr(h);
  324. cmDcmCfg_t* cp;
  325. if((cp = _cmDevCfgIndexToPtr(p,typeId,index,false)) == NULL )
  326. return NULL;
  327. return cp->descStr;
  328. }
  329. cmDcmCfg_t* _cmDcmCfgLabelToPtr( cmDcm_t* p, cmTypeDcmId_t typeId, const cmChar_t* label, bool errFl )
  330. {
  331. assert( p->clp != NULL);
  332. cmDcmCfg_t* cp = p->clp->cfg;
  333. for(; cp!= NULL; cp=cp->next)
  334. if( cp->typeId == typeId )
  335. {
  336. if( strcmp(cp->dcLabelStr,label) == 0 )
  337. return cp;
  338. }
  339. if( errFl )
  340. cmErrMsg(&p->err,kLabelNotFoundDcRC, "The cfg label '%s' was not found.",cmStringNullGuard(label));
  341. return NULL;
  342. }
  343. unsigned cmDevCfgLabelToIndex( cmDevCfgH_t h, cmTypeDcmId_t typeId, const cmChar_t* label )
  344. {
  345. unsigned n = 0;
  346. cmDcm_t* p = _cmDcmHandleToPtr(h);
  347. assert( p->clp != NULL);
  348. const cmDcmCfg_t* cp = p->clp->cfg;
  349. for(; cp!= NULL; cp=cp->next)
  350. if( cp->typeId == typeId )
  351. {
  352. if( strcmp(cp->dcLabelStr,label) == 0 )
  353. return n;
  354. ++n;
  355. }
  356. return cmInvalidIdx;
  357. }
  358. cmDcmCfg_t* _cmDcmFindOrCreateCfg( cmDcm_t* p, cmTypeDcmId_t typeId, const cmChar_t* dcLabelStr )
  359. {
  360. assert( p->clp != NULL );
  361. cmDcmCfg_t* cp;
  362. // validate the label
  363. if( (dcLabelStr=_cmDcmTrimLabel(p,dcLabelStr,"cfg")) == NULL )
  364. return NULL;
  365. // if the cfg recd already exists then return it
  366. if((cp = _cmDcmCfgLabelToPtr(p, typeId, dcLabelStr, false )) != NULL )
  367. return cp;
  368. unsigned newCfgId = 0;
  369. // use ep to track the end of the list
  370. cmDcmCfg_t* ep = NULL;
  371. // find the max cfgId used by this loc
  372. cp = p->clp->cfg;
  373. for(; cp!=NULL; cp=cp->next)
  374. {
  375. if( cp->cfgId > newCfgId )
  376. newCfgId = cp->cfgId;
  377. ep = cp;
  378. }
  379. // add one to the max cfgId to create a unique cfgId
  380. newCfgId += 1;
  381. // allocate a new cfg recd
  382. cp = cmMemAllocZ(cmDcmCfg_t,1);
  383. cp->dcLabelStr = cmMemAllocStr(dcLabelStr);
  384. cp->cfgId = newCfgId;
  385. cp->typeId = typeId;
  386. // link to the end of the loc's cfg list
  387. if( ep == NULL )
  388. p->clp->cfg = cp;
  389. else
  390. {
  391. ep->next = cp;
  392. cp->prev = ep;
  393. }
  394. return cp;
  395. }
  396. void _cmDcmDisconnectMap( cmDcmMap_t* mp )
  397. {
  398. mp->tid = kInvalidDcmTId;
  399. mp->cfgId = cmInvalidId;
  400. mp->cfg = NULL;
  401. }
  402. cmDcRC_t cmDevCfgDeleteCfg( cmDevCfgH_t h, cmTypeDcmId_t typeId, const cmChar_t* dcLabelStr )
  403. {
  404. cmDcmCfg_t* cp;
  405. cmDcm_t* p = _cmDcmHandleToPtr(h);
  406. unsigned i,j;
  407. // locate the cfg to delete
  408. if((cp = _cmDcmCfgLabelToPtr(p,typeId,dcLabelStr,true)) == NULL )
  409. return cmErrLastRC(&p->err);
  410. // for every app in the current location ...
  411. for(i=0; i<p->clp->appCnt; ++i)
  412. {
  413. cmDcmApp_t* ap = p->clp->app + i;
  414. // ... disconnect any maps to this cfg
  415. if( ap->activeFl && ap->map != NULL )
  416. for(j=0; j<ap->mapCnt; ++j)
  417. if( ap->map[j].cfgId == cp->cfgId )
  418. _cmDcmDisconnectMap(ap->map + j );
  419. }
  420. // unlink and release the cfg recd
  421. _cmDcmFreeCfg(p,p->clp,cp);
  422. return kOkDcRC;
  423. }
  424. cmDcRC_t cmDevCfgCreateMap( cmDevCfgH_t h, cmTypeDcmId_t typeId, const cmChar_t* dcLabelStr, unsigned usrAppId, unsigned usrMapId )
  425. {
  426. cmDcRC_t rc = kOkDcRC;
  427. cmDcm_t* p = _cmDcmHandleToPtr(h);
  428. cmDcmCfg_t* cp;
  429. // locate the cfg to map to
  430. if((cp = _cmDcmCfgLabelToPtr(p,typeId,dcLabelStr,true)) == NULL )
  431. return cmErrLastRC(&p->err);
  432. // if usrAppId references a new app
  433. if( usrAppId >= p->clp->appCnt )
  434. {
  435. p->clp->appCnt = usrAppId + 1;
  436. p->clp->app = cmMemResizePZ(cmDcmApp_t,p->clp->app,p->clp->appCnt);
  437. }
  438. cmDcmApp_t* ap = p->clp->app + usrAppId;
  439. // if usrMapId ref's a new map
  440. if( usrMapId >= ap->mapCnt )
  441. {
  442. ap->mapCnt = usrMapId+1;
  443. ap->map = cmMemResizePZ(cmDcmMap_t,ap->map,ap->mapCnt);
  444. }
  445. cmDcmMap_t* mp = ap->map + usrMapId;
  446. mp->tid = typeId;
  447. mp->cfgId = cp->cfgId;
  448. mp->cfg = cp;
  449. return rc;
  450. }
  451. cmDcmMap_t* _cmDcmFindMap( cmDcm_t* p, cmTypeDcmId_t typeId, unsigned usrAppId, unsigned usrMapId, bool activeFl )
  452. {
  453. if( usrAppId >= p->clp->appCnt )
  454. {
  455. cmErrMsg(&p->err,kInvalidUserAppIdRC,"The user app. id %i is out of range %i in location '%s'.",usrAppId,p->clp->appCnt,cmStringNullGuard(p->clp->labelStr));
  456. goto errLabel;
  457. }
  458. cmDcmApp_t* ap = p->clp->app + usrAppId;
  459. if( usrMapId >= ap->mapCnt )
  460. {
  461. cmErrMsg(&p->err,kInvalidUserMapIdRC,"The user map id %i is out of range %i in location '%s'.",usrMapId,ap->mapCnt,cmStringNullGuard(p->clp->labelStr));
  462. goto errLabel;
  463. }
  464. if( activeFl && (ap->map[usrMapId].tid == kInvalidDcmTId || ap->map[usrMapId].cfg == NULL))
  465. {
  466. cmErrMsg(&p->err,kInvalidUserMapIdRC,"The user map id %i inactive in location '%s'.",usrMapId,cmStringNullGuard(p->clp->labelStr));
  467. goto errLabel;
  468. }
  469. return ap->map + usrMapId;
  470. errLabel:
  471. return NULL;
  472. }
  473. cmDcRC_t cmDevCfgDeleteMap( cmDevCfgH_t h, cmTypeDcmId_t typeId, unsigned usrAppId, unsigned usrMapId )
  474. {
  475. cmDcm_t* p = _cmDcmHandleToPtr(h);
  476. cmDcmMap_t* mp;
  477. if((mp = _cmDcmFindMap(p,typeId,usrAppId,usrMapId,false)) == NULL )
  478. return cmErrLastRC(&p->err);
  479. _cmDcmDisconnectMap( mp );
  480. return kOkDcRC;
  481. }
  482. cmDcRC_t cmDevCfgNameMidiPort(
  483. cmDevCfgH_t h,
  484. const cmChar_t* dcLabelStr,
  485. const cmChar_t* devLabelStr,
  486. const cmChar_t* portLabelStr,
  487. bool inputFl )
  488. {
  489. cmDcm_t* p = _cmDcmHandleToPtr(h);
  490. cmDcmCfg_t* cp;
  491. unsigned midiDevIdx;
  492. unsigned midiPortIdx;
  493. // validate the label
  494. if((dcLabelStr = _cmDcmTrimLabel(p,dcLabelStr,"MIDI cfg")) == NULL)
  495. return cmErrLastRC(&p->err);
  496. // verify that the device label is valid
  497. if((midiDevIdx = cmMpDeviceNameToIndex( devLabelStr )) == cmInvalidIdx )
  498. return cmErrMsg(&p->err, kInvalidArgDcRC,"The MIDI device name '%s' is not valid.",devLabelStr);
  499. // verify that the port label is valid
  500. if((midiPortIdx = cmMpDevicePortNameToIndex( midiDevIdx, inputFl ? kInMpFl : kOutMpFl, portLabelStr )) == cmInvalidIdx )
  501. return cmErrMsg(&p->err, kInvalidArgDcRC,"The MIDI port name '%s' is not valid on the device '%s'.",portLabelStr,devLabelStr);
  502. // if dcLabelStr is already in use for this location and type then update
  503. // the assoc'd recd otherwise create a new one.
  504. if((cp = _cmDcmFindOrCreateCfg(p,kMidiDcmTId, dcLabelStr)) == NULL )
  505. return cmErrLastRC(&p->err);
  506. cp->u.m.label = cp->dcLabelStr;
  507. cp->u.m.devLabelStr = cmMemResizeStr(cp->u.m.devLabelStr,devLabelStr);
  508. cp->u.m.portLabelStr = cmMemResizeStr(cp->u.m.portLabelStr,portLabelStr);
  509. cp->u.m.inputFl = inputFl;
  510. cp->u.m.devIdx = midiDevIdx;
  511. cp->u.m.portIdx = midiPortIdx;
  512. cp->descStr = cmTsPrintfP(cp->descStr,"%s %s %s",inputFl?"Input":"Output",devLabelStr,portLabelStr);
  513. return kOkDcRC;
  514. }
  515. const cmDcmMidi_t* cmDevCfgMidiCfg( cmDevCfgH_t h, unsigned cfgIdx )
  516. {
  517. cmDcm_t* p = _cmDcmHandleToPtr(h);
  518. cmDcmCfg_t* cp;
  519. if((cp = _cmDevCfgIndexToPtr(p, kMidiDcmTId, cfgIdx, true )) == NULL )
  520. return NULL;
  521. return &cp->u.m;
  522. }
  523. const cmDcmMidi_t* cmDevCfgMidiDevMap( cmDevCfgH_t h, unsigned usrAppId, unsigned usrMapId )
  524. {
  525. cmDcm_t* p = _cmDcmHandleToPtr(h);
  526. cmDcmMap_t* mp;
  527. if((mp =_cmDcmFindMap(p,kMidiDcmTId, usrAppId, usrMapId, true )) == NULL )
  528. return NULL;
  529. return &mp->cfg->u.m;
  530. }
  531. const cmDcmMidi_t* cmDevCfgMidiCfgFromLabel( cmDevCfgH_t h, const cmChar_t* cfgLabel )
  532. {
  533. cmDcm_t* p = _cmDcmHandleToPtr(h);
  534. const cmDcmMidi_t* c;
  535. unsigned idx;
  536. if((idx = cmDevCfgLabelToIndex(h, kMidiDcmTId, cfgLabel )) == cmInvalidIdx )
  537. {
  538. cmErrMsg(&p->err,kLabelNotFoundDcRC,"The MIDI cfg. '%s' was not found.",cmStringNullGuard(cfgLabel));
  539. return NULL;
  540. }
  541. if((c = cmDevCfgMidiCfg(h,idx)) == NULL )
  542. {
  543. cmErrMsg(&p->err,kInvalidCfgIdxDcRC,"The MIDI cfg. index %i is invalid.",idx);
  544. return NULL;
  545. }
  546. return c;
  547. }
  548. cmDcRC_t cmDevCfgNameAudioPort(
  549. cmDevCfgH_t h,
  550. const cmChar_t* dcLabelStr,
  551. const cmChar_t* inDevNameStr,
  552. const cmChar_t* outDevNameStr,
  553. bool syncInputFl,
  554. unsigned msgQueueByteCnt,
  555. unsigned devFramesPerCycle,
  556. unsigned dspFramesPerCycle,
  557. unsigned audioBufCnt,
  558. double srate,
  559. const cmChar_t* ipAddr,
  560. cmUdpPort_t ipPort,
  561. bool activeFl )
  562. {
  563. cmDcm_t* p = _cmDcmHandleToPtr(h);
  564. cmDcmCfg_t* cp;
  565. unsigned inDevIdx = cmInvalidIdx;
  566. unsigned outDevIdx = cmInvalidIdx;
  567. // validate the label
  568. if((dcLabelStr = _cmDcmTrimLabel(p,dcLabelStr,"Audio cfg")) == NULL)
  569. return cmErrLastRC(&p->err);
  570. // validate the input device
  571. if( inDevNameStr != NULL )
  572. if(( inDevIdx = cmApDeviceLabelToIndex(inDevNameStr)) == cmInvalidIdx )
  573. return cmErrMsg(&p->err, kInvalidArgDcRC,"The input audio device name '%s' is not valid.",cmStringNullGuard(inDevNameStr));
  574. // validate the output device
  575. if( outDevNameStr != NULL )
  576. if(( outDevIdx = cmApDeviceLabelToIndex(outDevNameStr)) == cmInvalidIdx )
  577. return cmErrMsg(&p->err, kInvalidArgDcRC,"The output audio device name '%s' is not valid.",cmStringNullGuard(outDevNameStr));
  578. // validate the msg byte cnt
  579. if( msgQueueByteCnt == 0 )
  580. return cmErrMsg(&p->err, kInvalidArgDcRC,"The 'message queue size' must be greater than zero.");
  581. // validate the dev. frames per cycle
  582. if( devFramesPerCycle == 0 )
  583. return cmErrMsg(&p->err, kInvalidArgDcRC,"The 'device frames per cycle' must be greater than zero.");
  584. // validate the dsp frames per cycle
  585. if( dspFramesPerCycle == 0 || ((devFramesPerCycle/dspFramesPerCycle) * dspFramesPerCycle != devFramesPerCycle) )
  586. return cmErrMsg(&p->err, kInvalidArgDcRC,"The 'DSP frames per cycle' must be greater than zero and an integer factor of 'Device frames per cycle.'.");
  587. // validate the sample rate
  588. if( srate == 0 )
  589. return cmErrMsg(&p->err, kInvalidArgDcRC,"The audio sample rate must be greater than zero.");
  590. // if dcLabelStr is already in use for this location and type then update
  591. // the assoc'd recd otherwise create a new one.
  592. if((cp = _cmDcmFindOrCreateCfg(p,kAudioDcmTId, dcLabelStr)) == NULL )
  593. return cmErrLastRC(&p->err);
  594. unsigned inChCnt = cmApDeviceChannelCount( inDevIdx, true );
  595. unsigned outChCnt = cmApDeviceChannelCount( outDevIdx, false );
  596. cp->u.a.label = cp->dcLabelStr;
  597. cp->u.a.inDevLabelStr = cmMemAllocStr(inDevNameStr==NULL?"":inDevNameStr);
  598. cp->u.a.outDevLabelStr = cmMemAllocStr(outDevNameStr==NULL?"":outDevNameStr);
  599. cp->u.a.activeFl = activeFl;
  600. cp->u.a.rtSysArgs.rpt = p->err.rpt;
  601. cp->u.a.rtSysArgs.inDevIdx = inDevIdx;
  602. cp->u.a.rtSysArgs.outDevIdx = outDevIdx;
  603. cp->u.a.rtSysArgs.syncInputFl = syncInputFl;
  604. cp->u.a.rtSysArgs.msgQueueByteCnt = msgQueueByteCnt;
  605. cp->u.a.rtSysArgs.devFramesPerCycle = devFramesPerCycle;
  606. cp->u.a.rtSysArgs.dspFramesPerCycle = dspFramesPerCycle;
  607. cp->u.a.rtSysArgs.audioBufCnt = audioBufCnt;
  608. cp->u.a.rtSysArgs.srate = srate;
  609. cp->u.a.ipAddr = ipAddr;
  610. cp->u.a.ipPort = ipPort;
  611. cp->descStr = cmTsPrintfP(cp->descStr,"%sIn: Chs:%i %s\nOut: Chs:%i %s",activeFl?"":"INACTIVE ",inChCnt,cp->u.a.inDevLabelStr,outChCnt,cp->u.a.outDevLabelStr);
  612. return kOkDcRC;
  613. }
  614. bool cmDevCfgAudioIsDeviceActive( cmDevCfgH_t h, const cmChar_t* devNameStr, bool inputFl )
  615. {
  616. cmDcm_t* p = _cmDcmHandleToPtr(h);
  617. assert( p->clp != NULL );
  618. cmDcmCfg_t* cp = p->clp->cfg;
  619. unsigned i;
  620. for(i=0; cp!=NULL; cp=cp->next)
  621. if( cp->typeId == kAudioDcmTId )
  622. {
  623. bool fl;
  624. if( inputFl )
  625. fl = strcmp(devNameStr,cp->u.a.inDevLabelStr)==0;
  626. else
  627. fl = strcmp(devNameStr,cp->u.a.outDevLabelStr)==0;
  628. if( fl )
  629. return cp->u.a.activeFl;
  630. ++i;
  631. }
  632. return false;
  633. }
  634. unsigned cmDevCfgAudioActiveCount( cmDevCfgH_t h )
  635. {
  636. cmDcm_t* p = _cmDcmHandleToPtr(h);
  637. assert( p->clp != NULL );
  638. cmDcmCfg_t* cp = p->clp->cfg;
  639. unsigned n;
  640. for(n=0; cp!=NULL; cp=cp->next)
  641. if( cp->typeId == kAudioDcmTId && cp->u.a.activeFl )
  642. ++n;
  643. return n;
  644. }
  645. const cmChar_t* cmDevCfgAudioActiveLabel( cmDevCfgH_t h, unsigned idx )
  646. {
  647. cmDcm_t* p = _cmDcmHandleToPtr(h);
  648. assert( p->clp != NULL );
  649. cmDcmCfg_t* cp = p->clp->cfg;
  650. unsigned i;
  651. for(i=0; cp!=NULL; cp=cp->next)
  652. if( cp->typeId == kAudioDcmTId && cp->u.a.activeFl )
  653. {
  654. if( i == idx )
  655. return cp->dcLabelStr;
  656. ++i;
  657. }
  658. assert(0);
  659. return NULL;
  660. }
  661. const cmDcmAudio_t* cmDevCfgAudioActiveCfg( cmDevCfgH_t h, unsigned idx )
  662. {
  663. cmDcm_t* p = _cmDcmHandleToPtr(h);
  664. assert( p->clp != NULL );
  665. cmDcmCfg_t* cp = p->clp->cfg;
  666. unsigned i;
  667. for(i=0; cp!=NULL; cp=cp->next)
  668. if( cp->typeId == kAudioDcmTId && cp->u.a.activeFl )
  669. {
  670. if( i == idx )
  671. return &cp->u.a;
  672. ++i;
  673. }
  674. assert(0);
  675. return NULL;
  676. }
  677. unsigned cmDevCfgAudioActiveIndex( cmDevCfgH_t h, const cmChar_t* cfgLabel )
  678. {
  679. cmDcm_t* p = _cmDcmHandleToPtr(h);
  680. if( cfgLabel == NULL )
  681. return cmInvalidIdx;
  682. assert( p->clp != NULL );
  683. cmDcmCfg_t* cp = p->clp->cfg;
  684. unsigned i;
  685. for(i=0; cp!=NULL; cp=cp->next)
  686. if( cp->typeId == kAudioDcmTId && cp->u.a.activeFl)
  687. {
  688. if( cp->dcLabelStr!=NULL && strcmp(cp->dcLabelStr,cfgLabel) == 0 )
  689. return i;
  690. ++i;
  691. }
  692. return cmInvalidIdx;
  693. }
  694. const cmDcmAudio_t* cmDevCfgAudioCfg( cmDevCfgH_t h, unsigned cfgIdx )
  695. {
  696. cmDcm_t* p = _cmDcmHandleToPtr(h);
  697. cmDcmCfg_t* cp;
  698. if((cp = _cmDevCfgIndexToPtr(p, kAudioDcmTId, cfgIdx, true )) == NULL )
  699. return NULL;
  700. return &cp->u.a;
  701. }
  702. const cmDcmAudio_t* cmDevCfgAudioDevMap( cmDevCfgH_t h, unsigned usrAppId, unsigned usrMapId )
  703. {
  704. cmDcm_t* p = _cmDcmHandleToPtr(h);
  705. cmDcmMap_t* mp;
  706. if((mp =_cmDcmFindMap(p,kAudioDcmTId, usrAppId, usrMapId, true )) == NULL )
  707. return NULL;
  708. return &mp->cfg->u.a;
  709. }
  710. cmDcRC_t cmDevCfgNameNetPort(
  711. cmDevCfgH_t h,
  712. const cmChar_t* dcLabelStr,
  713. const cmChar_t* sockAddr,
  714. unsigned portNumber,
  715. bool activeFl)
  716. {
  717. cmDcm_t* p = _cmDcmHandleToPtr(h);
  718. cmDcmCfg_t* cp;
  719. if( portNumber > 0xffff )
  720. return cmErrMsg(&p->err,kInvalidArgDcRC,"The network port number %i is invalid. The valid IP port number range is:0-0xffff.");
  721. // validate the label
  722. if((dcLabelStr = _cmDcmTrimLabel(p,dcLabelStr,"Net cfg")) == NULL)
  723. return cmErrLastRC(&p->err);
  724. // if dcLabelStr is already in use for this location and type then update
  725. // the assoc'd recd otherwise create a new one.
  726. if((cp = _cmDcmFindOrCreateCfg(p,kNetDcmTId, dcLabelStr)) == NULL )
  727. return cmErrLastRC(&p->err);
  728. cp->u.n.label = cp->dcLabelStr;
  729. cp->u.n.sockAddr = cmMemAllocStr(sockAddr);
  730. cp->u.n.portNumber = portNumber;
  731. cp->u.n.activeFl = activeFl;
  732. cp->descStr = cmTsPrintfP(cp->descStr,"%s %s:%i",activeFl?"":"INACTIVE",sockAddr,portNumber);
  733. return kOkDcRC;
  734. }
  735. unsigned cmDevCfgNetActiveCount( cmDevCfgH_t h )
  736. {
  737. cmDcm_t* p = _cmDcmHandleToPtr(h);
  738. assert( p->clp != NULL );
  739. cmDcmCfg_t* cp = p->clp->cfg;
  740. unsigned n;
  741. for(n=0; cp!=NULL; cp=cp->next)
  742. if( cp->typeId == kNetDcmTId && cp->u.n.activeFl )
  743. ++n;
  744. return n;
  745. }
  746. const cmDcmNet_t* cmDevCfgNetActiveCfg( cmDevCfgH_t h, unsigned idx )
  747. {
  748. cmDcm_t* p = _cmDcmHandleToPtr(h);
  749. assert( p->clp != NULL );
  750. cmDcmCfg_t* cp = p->clp->cfg;
  751. unsigned i;
  752. for(i=0; cp!=NULL; cp=cp->next)
  753. if( cp->typeId == kNetDcmTId && cp->u.n.activeFl )
  754. {
  755. if( i == idx )
  756. return &cp->u.n;
  757. ++i;
  758. }
  759. assert(0);
  760. return NULL;
  761. }
  762. const cmDcmNet_t* cmDevCfgNetCfg( cmDevCfgH_t h, unsigned cfgIdx )
  763. {
  764. cmDcm_t* p = _cmDcmHandleToPtr(h);
  765. cmDcmCfg_t* cp;
  766. if((cp = _cmDevCfgIndexToPtr(p, kNetDcmTId, cfgIdx, true )) == NULL )
  767. return NULL;
  768. return &cp->u.n;
  769. }
  770. const cmDcmNet_t* cmDevCfgNetDevMap( cmDevCfgH_t h, unsigned usrAppId, unsigned usrMapId )
  771. {
  772. cmDcm_t* p = _cmDcmHandleToPtr(h);
  773. cmDcmMap_t* mp;
  774. if((mp =_cmDcmFindMap(p,kNetDcmTId, usrAppId, usrMapId, true )) == NULL )
  775. return NULL;
  776. return &mp->cfg->u.n;
  777. }
  778. unsigned cmDevCfgLocCount( cmDevCfgH_t h )
  779. {
  780. unsigned n = 0;
  781. cmDcm_t* p = _cmDcmHandleToPtr(h);
  782. const cmDcmLoc_t* lp = p->loc;
  783. for(; lp!=NULL; lp=lp->next)
  784. ++n;
  785. return n;
  786. }
  787. const cmChar_t* cmDevCfgLocLabel( cmDevCfgH_t h, unsigned locIdx )
  788. {
  789. cmDcm_t* p = _cmDcmHandleToPtr(h);
  790. const cmDcmLoc_t* lp = p->loc;
  791. unsigned i;
  792. for(i=0; lp!=NULL; lp=lp->next,++i)
  793. if( i == locIdx )
  794. return lp->labelStr;
  795. assert(0);
  796. return NULL;
  797. }
  798. cmDcmLoc_t* _cmDcmLocLabelToPtr( cmDcm_t* p, const cmChar_t* locLabelStr, bool errFl)
  799. {
  800. if((locLabelStr = _cmDcmTrimLabel(p,locLabelStr,"location")) == NULL )
  801. return NULL;
  802. cmDcmLoc_t* lp = p->loc;
  803. for(; lp!=NULL; lp=lp->next)
  804. if( strcmp(lp->labelStr,locLabelStr) == 0 )
  805. return lp;
  806. if( errFl )
  807. cmErrMsg(&p->err,kLabelNotFoundDcRC,"The location label '%s' was not found.",locLabelStr);
  808. return NULL;
  809. }
  810. cmDcRC_t cmDevCfgLocStore( cmDevCfgH_t h, const cmChar_t* locLabelStr )
  811. {
  812. cmDcRC_t rc = kOkDcRC;
  813. cmDcm_t* p = _cmDcmHandleToPtr(h);
  814. unsigned i,j;
  815. // if this location label is already in use then it has already been stored.
  816. if( _cmDcmLocLabelToPtr(p,locLabelStr,false) != NULL )
  817. return kOkDcRC;
  818. // store the current loc ptr
  819. cmDcmLoc_t* olp = p->clp;
  820. cmDcmLoc_t* nlp;
  821. // create a new location recd and make it current
  822. if((rc = _cmDcmNewLoc(p,locLabelStr,&nlp)) != kOkDcRC )
  823. return kOkDcRC;
  824. // duplicate the cfg's
  825. cmDcmCfg_t* ocp = olp->cfg;
  826. for(; ocp!=NULL; ocp=ocp->next)
  827. {
  828. cmDcmCfg_t* ncp;
  829. // this will always create (never find) a new cfg recd
  830. if((ncp = _cmDcmFindOrCreateCfg(p,ocp->typeId, ocp->dcLabelStr)) == NULL )
  831. {
  832. rc = cmErrLastRC(&p->err);
  833. goto errLabel;
  834. }
  835. // duplicate the desc. string
  836. ncp->descStr = cmMemAllocStr(ocp->descStr);
  837. switch( ncp->typeId )
  838. {
  839. case kMidiDcmTId: _cmDcmDuplMidi(&ncp->u.m,&ocp->u.m); break;
  840. case kAudioDcmTId: _cmDcmDuplAudio(&ncp->u.a,&ocp->u.a); break;
  841. case kNetDcmTId: _cmDcmDuplNet( &ncp->u.n,&ocp->u.n); break;
  842. default:
  843. assert(0);
  844. break;
  845. }
  846. }
  847. // duplicate the app array
  848. nlp->appCnt = olp->appCnt;
  849. nlp->app = cmMemAllocZ(cmDcmApp_t,nlp->appCnt);
  850. for(i=0; i<nlp->appCnt; ++i)
  851. {
  852. cmDcmApp_t* nap = nlp->app + i;
  853. cmDcmApp_t* oap = olp->app + i;
  854. //nap->usrAppId = oap->usrAppId;
  855. nap->activeFl = oap->activeFl;
  856. nap->mapCnt = oap->mapCnt;
  857. nap->map = cmMemAllocZ(cmDcmMap_t,nap->mapCnt);
  858. for(j=0; j<nap->mapCnt; ++j)
  859. {
  860. cmDcmMap_t* nmp = nap->map + j;
  861. cmDcmMap_t* omp = oap->map + j;
  862. nmp->tid = omp->tid;
  863. nmp->cfgId = omp->cfgId;
  864. if( omp->tid != kInvalidDcmTId && omp->cfg->dcLabelStr != NULL )
  865. nmp->cfg = _cmDcmCfgLabelToPtr(p,nmp->tid,omp->cfg->dcLabelStr,true);
  866. }
  867. }
  868. errLabel:
  869. if( rc != kOkDcRC )
  870. _cmDcmFreeLoc(p,nlp);
  871. return rc;
  872. }
  873. cmDcRC_t cmDevCfgLocRecall( cmDevCfgH_t h, const cmChar_t* locLabelStr )
  874. {
  875. cmDcm_t* p = _cmDcmHandleToPtr(h);
  876. cmDcmLoc_t* lp;
  877. if((lp = _cmDcmLocLabelToPtr(p,locLabelStr,true)) == NULL)
  878. return cmErrLastRC(&p->err);
  879. p->clp = lp;
  880. return kOkDcRC;
  881. }
  882. cmDcRC_t cmDevCfgLocDelete( cmDevCfgH_t h, const cmChar_t* locLabelStr )
  883. {
  884. cmDcm_t* p = _cmDcmHandleToPtr(h);
  885. cmDcmLoc_t* lp;
  886. if((lp = _cmDcmLocLabelToPtr(p,locLabelStr,true)) == NULL )
  887. return cmErrLastRC(&p->err);
  888. _cmDcmFreeLoc(p,lp);
  889. return kOkDcRC;
  890. }
  891. unsigned cmDevCfgLocCurIndex( cmDevCfgH_t h )
  892. {
  893. unsigned i;
  894. cmDcm_t* p = _cmDcmHandleToPtr(h);
  895. cmDcmLoc_t* lp = p->loc;
  896. for(i=0; lp!=NULL; lp=lp->next,++i)
  897. if( lp == p->clp )
  898. return i;
  899. assert(0);
  900. return cmInvalidIdx;
  901. }
  902. cmDcRC_t _cmDcmJsonNotFound( cmDcm_t* p, const cmChar_t* tagStr )
  903. { return cmErrMsg(&p->err,kJsonFailDcRC,"JSON element '%s' not found.",tagStr); }
  904. cmDcRC_t _cmDcmJsonSyntaxErr( cmDcm_t* p, const cmChar_t* tagStr )
  905. { return cmErrMsg(&p->err,kJsonFailDcRC,"JSON syntax error '%s' not found.",tagStr); }
  906. cmDcRC_t _cmDevCfgRead( cmDcm_t* p, cmJsonH_t jsH, const cmJsonNode_t* rootObjPtr )
  907. {
  908. cmDcRC_t rc = kOkDcRC;
  909. const cmChar_t* errLabelPtr = NULL;
  910. cmJsonNode_t* cfgNp, *locArrNp;
  911. unsigned i,j;
  912. cmDevCfgH_t h;
  913. h.h = p;
  914. // clear the all locations
  915. _cmDcmFreeAllLocs(p);
  916. if((cfgNp = cmJsonFindValue(jsH, "cfg", rootObjPtr, kObjectTId )) == NULL )
  917. return _cmDcmJsonNotFound(p,"cfg");
  918. // get loc array
  919. if((locArrNp = cmJsonFindValue(jsH,"loc",cfgNp, kArrayTId )) == NULL )
  920. return _cmDcmJsonNotFound(p,"loc");
  921. // for each loc object
  922. for(i=0; i<cmJsonChildCount(locArrNp); ++i)
  923. {
  924. cmJsonNode_t* locObjNp, *cfgArrNp;
  925. const cmChar_t* locLabelStr = NULL;
  926. // get the loc object
  927. if((locObjNp = cmJsonArrayElement(locArrNp,i)) == NULL || cmJsonIsObject(locObjNp)==false )
  928. return _cmDcmJsonSyntaxErr(p,"loc object");
  929. // read the loc object fields
  930. if( cmJsonMemberValues(locObjNp, &errLabelPtr,
  931. "label", kStringTId, &locLabelStr,
  932. "cfg", kArrayTId, &cfgArrNp,
  933. NULL ) != kOkJsRC )
  934. { return _cmDcmJsonNotFound(p,errLabelPtr); }
  935. // create a new location recd
  936. cmDcmLoc_t* locPtr = NULL;
  937. if((rc = _cmDcmNewLoc(p,locLabelStr,&locPtr)) != kOkDcRC )
  938. return cmErrMsg(&p->err,kJsonFailDcRC,"Location '%s' create failed.",cmStringNullGuard(locLabelStr));
  939. /*
  940. // read each app object
  941. for(j=0; j<cmJsonChildCount(appArrNp); ++j)
  942. {
  943. cmJsonNode_t* appObjNp;
  944. // get the app object
  945. if((appObjNp = cmJsonArrayElement(appArrNp,j)) == NULL || cmJsonIsObject(appObjNp)==false )
  946. return _cmDcmJsonSyntaxErr(p,"loc object");
  947. // locate the map array
  948. cmJsonNode_t* mapArrNp;
  949. if((mapArrNp = cmJsonFindValue(jsH,"map",appObjNp,kArrayTId)) == NULL )
  950. return _cmDcmJsonNotFound(p,"map");
  951. // for each map array
  952. for(k=0; k<cmJsonChildCount(mapArrNp); ++k)
  953. {
  954. unsigned tid,cfgId;
  955. cmJsonNode_t* mapObjNp;
  956. if((mapObjNp = cmJsonArrayElement(mapArrNp,j)) == NULL || cmJsonIsObject(mapObjNp)==false)
  957. return _cmDcmJsonSyntaxErr(p,"cfg object");
  958. if( cmJsonMemberValues( mapObjNp, &errLabelPtr,
  959. "tid", kIntTId, &tid,
  960. "cfgId", kIntTId, &cfgId,
  961. NULL ) != kOkDcRC )
  962. { return _cmDcmJsonSyntaxErr(p,errLabelPtr); }
  963. }
  964. }
  965. */
  966. // read each cfg object
  967. for(j=0; j<cmJsonChildCount(cfgArrNp); ++j)
  968. {
  969. cmJsonNode_t* cfgObjNp;
  970. const cmChar_t* dcLabelStr;
  971. const cmChar_t* descStr;
  972. unsigned cfgId, typeId;
  973. if((cfgObjNp = cmJsonArrayElement(cfgArrNp,j)) == NULL || cmJsonIsObject(cfgObjNp)==false)
  974. return _cmDcmJsonSyntaxErr(p,"cfg object");
  975. if( cmJsonMemberValues( cfgObjNp, &errLabelPtr,
  976. "label", kStringTId, &dcLabelStr,
  977. "cfgId", kIntTId, &cfgId,
  978. "typeId", kIntTId, &typeId,
  979. "desc", kStringTId, &descStr,
  980. NULL ) != kOkJsRC )
  981. { _cmDcmJsonSyntaxErr(p,errLabelPtr); }
  982. cmDcmMidi_t m;
  983. cmDcmAudio_t a;
  984. cmDcmNet_t n;
  985. switch( typeId )
  986. {
  987. case kMidiDcmTId:
  988. if( cmJsonMemberValues( cfgObjNp, &errLabelPtr,
  989. "devLabelStr", kStringTId, &m.devLabelStr,
  990. "portLabelStr",kStringTId, &m.portLabelStr,
  991. "inputFl", kBoolTId, &m.inputFl,
  992. NULL) != kOkJsRC )
  993. {
  994. rc = _cmDcmJsonSyntaxErr(p,errLabelPtr);
  995. goto errLabel;
  996. }
  997. if((rc = cmDevCfgNameMidiPort(h,dcLabelStr,m.devLabelStr,m.portLabelStr,m.inputFl)) != kOkDcRC )
  998. goto errLabel;
  999. break;
  1000. case kAudioDcmTId:
  1001. if( cmJsonMemberValues( cfgObjNp, &errLabelPtr,
  1002. "inDevLabelStr", kStringTId, &a.inDevLabelStr,
  1003. "outDevLabelStr", kStringTId, &a.outDevLabelStr,
  1004. "syncInputFl", kBoolTId, &a.rtSysArgs.syncInputFl,
  1005. "msgQueueByteCnt", kIntTId, &a.rtSysArgs.msgQueueByteCnt,
  1006. "devFramesPerCycle", kIntTId, &a.rtSysArgs.devFramesPerCycle,
  1007. "dspFramesPerCycle", kIntTId, &a.rtSysArgs.dspFramesPerCycle,
  1008. "audioBufCnt", kIntTId, &a.rtSysArgs.audioBufCnt,
  1009. "srate", kRealTId, &a.rtSysArgs.srate,
  1010. "ipAddr", kStringTId, &a.ipAddr,
  1011. "ipPort", kIntTId, &a.ipPort,
  1012. "active", kBoolTId, &a.activeFl,
  1013. NULL ) != kOkJsRC )
  1014. {
  1015. rc = _cmDcmJsonSyntaxErr(p,errLabelPtr);
  1016. goto errLabel;
  1017. }
  1018. if((rc = cmDevCfgNameAudioPort(h,dcLabelStr,a.inDevLabelStr,a.outDevLabelStr,
  1019. a.rtSysArgs.syncInputFl,
  1020. a.rtSysArgs.msgQueueByteCnt,
  1021. a.rtSysArgs.devFramesPerCycle,
  1022. a.rtSysArgs.dspFramesPerCycle,
  1023. a.rtSysArgs.audioBufCnt,
  1024. a.rtSysArgs.srate,
  1025. a.ipAddr,
  1026. a.ipPort,
  1027. a.activeFl)) != kOkDcRC )
  1028. {
  1029. goto errLabel;
  1030. }
  1031. break;
  1032. case kNetDcmTId:
  1033. if( cmJsonMemberValues( cfgObjNp, &errLabelPtr,
  1034. "sockAddr", kStringTId, &n.sockAddr,
  1035. "portNumber", kIntTId, &n.portNumber,
  1036. "activeFl", kBoolTId, &n.activeFl,
  1037. NULL ) != kOkJsRC )
  1038. {
  1039. rc = _cmDcmJsonSyntaxErr(p,errLabelPtr);
  1040. goto errLabel;
  1041. }
  1042. if((rc = cmDevCfgNameNetPort(h,dcLabelStr,n.sockAddr,n.portNumber,n.activeFl)) != kOkDcRC )
  1043. goto errLabel;
  1044. break;
  1045. default:
  1046. assert(0);
  1047. break;
  1048. }
  1049. }
  1050. }
  1051. errLabel:
  1052. return kOkDcRC;
  1053. }
  1054. cmDcRC_t _cmDevCfgWrite( cmDcm_t* p, cmJsonH_t jsH, cmJsonNode_t* rootObjPtr )
  1055. {
  1056. cmDcRC_t rc = kOkDcRC;
  1057. const cmDcmLoc_t* lp = p->loc;
  1058. cmJsonNode_t* cfgNp = cmJsonInsertPairObject(jsH, rootObjPtr, "cfg" );
  1059. // create the loc array
  1060. cmJsonNode_t* locArrNp = cmJsonInsertPairArray( jsH, cfgNp, "loc" );
  1061. for(; lp!=NULL; lp=lp->next)
  1062. {
  1063. // create the 'loc' object
  1064. cmJsonNode_t* locObjNp = cmJsonCreateObject(jsH,locArrNp);
  1065. // set the loc label
  1066. cmJsonInsertPairString(jsH, locObjNp, "label", lp->labelStr );
  1067. /*
  1068. // create the 'loc.app[]' array
  1069. cmJsonNode_t* appArrNp = cmJsonInsertPairArray(jsH,locObjNp,"app");
  1070. // for each app recd
  1071. for(i=0; i<lp->appCnt; ++i)
  1072. if( lp->app[i].activeFl )
  1073. {
  1074. // create the app recd
  1075. cmJsonNode_t* appNp = cmJsonCreateObject(jsH,appArrNp );
  1076. // create the map array
  1077. cmJsonNode_t* mapArrNp = cmJsonInsertPairArray(jsH, appNp, "map" );
  1078. // for each map recd
  1079. for(j=0; j<lp->app[i].mapCnt; ++j)
  1080. {
  1081. cmJsonNode_t* mapNp = cmJsonCreateObject(jsH,mapArrNp);
  1082. cmJsonInsertPairs(jsH, mapNp,
  1083. "tid", kIntTId, lp->app[i].map[j].tid,
  1084. "cfgId", kIntTId, lp->app[i].map[j].cfgId,
  1085. NULL );
  1086. }
  1087. }
  1088. */
  1089. // create the 'loc.cfg[]' array
  1090. cmJsonNode_t* cfgArrNp = cmJsonInsertPairArray(jsH,locObjNp,"cfg");
  1091. // for each cfg recd
  1092. cmDcmCfg_t* cp = lp->cfg;
  1093. for(; cp!=NULL; cp=cp->next)
  1094. {
  1095. // create the cfg recd
  1096. cmJsonNode_t* cfgObjNp = cmJsonCreateObject(jsH,cfgArrNp);
  1097. // fill the cfg recd
  1098. cmJsonInsertPairs(jsH, cfgObjNp,
  1099. "label", kStringTId, cp->dcLabelStr,
  1100. "cfgId", kIntTId, cp->cfgId,
  1101. "typeId", kIntTId, cp->typeId,
  1102. "desc", kStringTId, cp->descStr,
  1103. NULL );
  1104. switch( cp->typeId )
  1105. {
  1106. case kMidiDcmTId:
  1107. cmJsonInsertPairs(jsH, cfgObjNp,
  1108. "devLabelStr", kStringTId, cp->u.m.devLabelStr,
  1109. "portLabelStr",kStringTId, cp->u.m.portLabelStr,
  1110. "inputFl", kBoolTId, cp->u.m.inputFl,
  1111. NULL );
  1112. break;
  1113. case kAudioDcmTId:
  1114. cmJsonInsertPairs(jsH, cfgObjNp,
  1115. "inDevLabelStr", kStringTId, cp->u.a.inDevLabelStr,
  1116. "outDevLabelStr", kStringTId, cp->u.a.outDevLabelStr,
  1117. "syncInputFl", kBoolTId, cp->u.a.rtSysArgs.syncInputFl,
  1118. "msgQueueByteCnt", kIntTId, cp->u.a.rtSysArgs.msgQueueByteCnt,
  1119. "devFramesPerCycle", kIntTId, cp->u.a.rtSysArgs.devFramesPerCycle,
  1120. "dspFramesPerCycle", kIntTId, cp->u.a.rtSysArgs.dspFramesPerCycle,
  1121. "audioBufCnt", kIntTId, cp->u.a.rtSysArgs.audioBufCnt,
  1122. "srate", kRealTId, cp->u.a.rtSysArgs.srate,
  1123. "ipAddr", kStringTId, cp->u.a.ipAddr,
  1124. "ipPort", kIntTId, cp->u.a.ipPort,
  1125. "active", kBoolTId, cp->u.a.activeFl,
  1126. NULL );
  1127. break;
  1128. case kNetDcmTId:
  1129. cmJsonInsertPairs(jsH, cfgObjNp,
  1130. "sockAddr", kStringTId, cp->u.n.sockAddr,
  1131. "portNumber",kIntTId, cp->u.n.portNumber,
  1132. "activeFl", kBoolTId, cp->u.n.activeFl,
  1133. NULL );
  1134. break;
  1135. default:
  1136. assert(0);
  1137. break;
  1138. }
  1139. }
  1140. }
  1141. return rc;
  1142. }
  1143. cmDcRC_t cmDevCfgWrite( cmDevCfgH_t h, const cmChar_t* fn )
  1144. {
  1145. cmDcRC_t rc = kOkDcRC;
  1146. cmDcm_t* p = _cmDcmHandleToPtr(h);
  1147. cmJsonH_t jsH = cmJsonNullHandle;
  1148. if( fn == NULL )
  1149. fn = p->fn;
  1150. // validate the filename
  1151. if( fn == NULL || strlen(fn)==0 )
  1152. return cmErrMsg(&p->err,kInvalidFnDcRC,"No output file name was provided.");
  1153. // create a json object
  1154. if( cmJsonInitialize( &jsH, p->ctx ) != kOkJsRC )
  1155. {
  1156. rc = cmErrMsg(&p->err,kJsonFailDcRC,"An empty JSON tree could not be created.");
  1157. goto errLabel;
  1158. }
  1159. // insert a wrapper object as the root
  1160. if( cmJsonCreateObject( jsH, NULL ) == NULL )
  1161. {
  1162. rc = cmErrMsg(&p->err,kJsonFailDcRC,"The JSON root object could not be created.");
  1163. goto errLabel;
  1164. }
  1165. // fill the JSON tree
  1166. if((rc = _cmDevCfgWrite(p,jsH,cmJsonRoot(jsH))) != kOkDcRC )
  1167. goto errLabel;
  1168. // write the output file
  1169. if( cmJsonWrite(jsH, cmJsonRoot(jsH), fn ) != kOkJsRC )
  1170. {
  1171. rc = cmErrMsg(&p->err,kJsonFailDcRC,"The JSON file write failed on '%s'.",cmStringNullGuard(fn));
  1172. goto errLabel;
  1173. }
  1174. errLabel:
  1175. if( cmJsonFinalize(&jsH) != kOkJsRC )
  1176. cmErrMsg(&p->err,kJsonFailDcRC,"JSON tree finalization failed.");
  1177. return rc;
  1178. }