libcm is a C development framework with an emphasis on audio signal processing applications.
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

cmDevCfg.c 35KB

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