123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224 |
- #include "cmPrefix.h"
- #include "cmGlobal.h"
- #include "cmFloatTypes.h"
- #include "cmRpt.h"
- #include "cmErr.h"
- #include "cmCtx.h"
- #include "cmMem.h"
- #include "cmMallocDebug.h"
- #include "cmLinkedHeap.h"
- #include "cmSymTbl.h"
- #include "cmJson.h"
- #include "cmFileSys.h"
- #include "cmPrefs.h"
- #include "cmAudioPort.h"
- #include "cmAudioAggDev.h"
- #include "cmAudioNrtDev.h"
- #include "cmApBuf.h"
- #include "cmMidi.h"
- #include "cmMidiPort.h"
- #include "dsp/cmDspValue.h"
- #include "cmMsgProtocol.h"
- #include "cmThread.h"
- #include "cmUdpPort.h"
- #include "cmUdpNet.h"
- #include "cmAudioSys.h"
- #include "cmProcObj.h"
- #include "dsp/cmDspCtx.h"
- #include "dsp/cmDspClass.h"
- #include "dsp/cmDspSys.h"
- #include "cmAudDsp.h"
-
-
- cmAdH_t cmAdNullHandle = cmSTATIC_NULL_HANDLE;
-
- typedef struct
- {
- cmDspSysH_t dsH;
- unsigned curPgmIdx;
- bool isLoadedFl;
- unsigned isSyncFl;
- } cmAdDsSubSys_t;
-
- typedef struct
- {
- const cmChar_t* label;
- cmAudioSysCfg_t cfg;
- } cmAdAsCfg_t;
-
- typedef struct
- {
- const cmChar_t* label;
- unsigned physDevCnt;
- unsigned* physDevIdxArray;
- } cmAdAggDev_t;
-
- typedef struct
- {
- const cmChar_t* label;
- double srate;
- unsigned iChCnt;
- unsigned oChCnt;
- unsigned cbPeriodMs;
- } cmAdNrtDev_t;
-
- typedef struct
- {
- cmErr_t err;
- cmCtx_t ctx;
- cmMsgSendFuncPtr_t cbFunc;
- void* cbDataPtr;
- cmJsonH_t sysJsH;
- const cmChar_t* sysJsFn;
- cmUdpNetH_t netH;
- cmDspSysH_t dsH;
- cmAudioSysH_t asH;
-
- unsigned midiPortBufByteCnt;
- unsigned meterMs;
- unsigned msgsPerClientPoll;
-
- cmAdAggDev_t* aggDevArray;
- unsigned aggDevCnt;
-
- cmAdNrtDev_t* nrtDevArray;
- unsigned nrtDevCnt;
-
- cmAdAsCfg_t* asCfgArray;
- unsigned asCfgCnt;
-
- unsigned curAsCfgIdx;
-
- unsigned dsSsCnt;
- cmAdDsSubSys_t* dsSsArray;
-
- bool syncFl; // all cmAdDsSubSys's are synced
- } cmAd_t;
-
- cmAd_t* _cmAdHandleToPtr( cmAdH_t h )
- {
- cmAd_t* p = (cmAd_t*)h.h;
- assert( p != NULL );
- return p;
- }
-
- // cmAudioSys DSP processing callback - this is the entry point
- // from the cmAudioSystem to the cmDspSystem. Note that it is called from the
- // the audio processing thread in cmAudioSys.c: _cmAsDeliverMsgsWithLock()
- cmRC_t _cmAudDspCallback( void *cbPtr, unsigned msgByteCnt, const void* msgDataPtr )
- {
- cmAudioSysCtx_t* ctx = (cmAudioSysCtx_t*)cbPtr;
- cmAdDsSubSys_t* p = (cmAdDsSubSys_t*)ctx->ss->cbDataPtr;
-
- if( p != NULL && p->isLoadedFl )
- return cmDspSysRcvMsg(p->dsH,ctx, msgDataPtr, msgByteCnt, ctx->srcNetNodeId );
-
- return cmOkRC;
- }
-
- // This function is called by cmAudioSysReceiveMsg() to transfer messages from the
- // cmAudioSys or cmDspSys to the client.
- cmRC_t _cmAudioSysToClientCallback(void* userCbPtr, unsigned msgByteCnt, const void* msgDataPtr )
- {
- cmAd_t* p = (cmAd_t*)userCbPtr;
- return p->cbFunc(p->cbDataPtr, msgByteCnt, msgDataPtr );
- }
-
- // This function is called by cmUdpNetReceive(), which is called in
- // cmAudioSys.c:_cmAsThreadCallback() just prior to executing the DSP process.
- void _cmAdUdpNetCallback( void* cbArg, cmUdpNetH_t h, const char* data, unsigned dataByteCnt, unsigned srcNetNodeId )
- {
- cmAd_t* p = (cmAd_t*)cbArg;
-
- // send the incoming message to the audio system for later delivery to the DSP system
- cmAudioSysDeliverMsg(p->asH, data, dataByteCnt, srcNetNodeId );
- }
-
-
- cmAdRC_t _cmAdParseMemberErr( cmAd_t* p, cmJsRC_t jsRC, const cmChar_t* errLabel, const cmChar_t* objectLabel )
- {
- if( jsRC == kNodeNotFoundJsRC && errLabel != NULL )
- return cmErrMsg(&p->err,kJsonFailAdRC,"The required field '%s'was not found in the audio DSP resource tree in the object '%s' in the file '%s'.",errLabel,cmStringNullGuard(objectLabel), cmStringNullGuard(p->sysJsFn));
-
- return cmErrMsg(&p->err,kJsonFailAdRC,"JSON parsing failed on the Audio DSP resource file '%s' in the resource object '%s'.",cmStringNullGuard(p->sysJsFn),cmStringNullGuard(objectLabel));
-
- }
-
-
- cmAdRC_t _cmAdParseSysJsonTree( cmAd_t* p )
- {
- cmAdRC_t rc = kOkAdRC;
- cmJsonNode_t* asCfgArrNodePtr = NULL;
- cmJsonNode_t* aggDevArrNodePtr = NULL;
- cmJsonNode_t* nrtDevArrNodePtr = NULL;
- cmJsonNode_t* audDspNodePtr = NULL;
- const cmChar_t* errLabelPtr = NULL;
- unsigned i;
- cmJsRC_t jsRC = kOkJsRC;
-
- // locate the aud_dsp container object
- if( cmJsonNodeMember( cmJsonRoot(p->sysJsH), "aud_dsp", &audDspNodePtr ) != kOkJsRC )
- {
- rc = cmErrMsg(&p->err,kJsonFailAdRC,"The audio DSP system resource file '%s' does not contain an 'aud_dsp' object.",cmStringNullGuard(p->sysJsFn));
- goto errLabel;
- }
-
- // locate the read the aud_dsp sub-elements
- if(( jsRC = cmJsonMemberValues( audDspNodePtr, &errLabelPtr,
- "midiPortBufByteCnt", kIntTId, &p->midiPortBufByteCnt,
- "meterMs", kIntTId, &p->meterMs,
- "msgsPerClientPoll", kIntTId, &p->msgsPerClientPoll,
- "audioSysCfgArray", kArrayTId, &asCfgArrNodePtr,
- "aggDevArray", kArrayTId | kOptArgJsFl, &aggDevArrNodePtr,
- "nrtDevArray", kArrayTId | kOptArgJsFl, &nrtDevArrNodePtr,
- NULL )) != kOkJsRC )
- {
- rc = _cmAdParseMemberErr(p, jsRC, errLabelPtr, "aud_dsp" );
- goto errLabel;
- }
-
- // parse the aggregate device specifications into p->aggDevArray[].
- if( aggDevArrNodePtr != NULL && (p->aggDevCnt = cmJsonChildCount(aggDevArrNodePtr)) > 0)
- {
- // alloc the aggregate spec. array
- p->aggDevArray = cmMemResizeZ( cmAdAggDev_t, p->aggDevArray, p->aggDevCnt );
-
- // for each agg. device spec. recd
- for(i=0; i<p->aggDevCnt; ++i)
- {
- const cmJsonNode_t* np = cmJsonArrayElementC(aggDevArrNodePtr,i);
- const cmJsonNode_t* devIdxArrNodePtr = NULL;
- unsigned j;
-
- // read aggDevArray record values
- if(( jsRC = cmJsonMemberValues( np, &errLabelPtr,
- "label", kStringTId, &p->aggDevArray[i].label,
- "physDevIdxArray", kArrayTId, &devIdxArrNodePtr,
- NULL )) != kOkJsRC )
- {
- rc = _cmAdParseMemberErr(p, jsRC, errLabelPtr, cmStringNullGuard(p->aggDevArray[i].label) );
- goto errLabel;
- }
-
- unsigned physDevCnt = cmJsonChildCount(devIdxArrNodePtr);
-
- // alloc the dev idx array for to hold the phys. dev indexes for this agg device
- p->aggDevArray[i].physDevIdxArray = cmMemResizeZ( unsigned, p->aggDevArray[i].physDevIdxArray, physDevCnt);
- p->aggDevArray[i].physDevCnt = physDevCnt;
-
- // store the phys. dev. idx's
- for(j=0; j<physDevCnt; ++j)
- if( cmJsonUIntValue( cmJsonArrayElementC(devIdxArrNodePtr,j), p->aggDevArray[i].physDevIdxArray + j ) != kOkJsRC )
- {
- rc = cmErrMsg(&p->err,kJsonFailAdRC,"Unable to retrieve a physical device index for the aggregate device '%s'.", cmStringNullGuard(p->aggDevArray[i].label));
- goto errLabel;
- }
- }
-
- }
-
- // parse the non-real-time device specifications into p->nrtDevArray[].
- if( nrtDevArrNodePtr != NULL && (p->nrtDevCnt = cmJsonChildCount(nrtDevArrNodePtr)) > 0)
- {
- // alloc the non-real-time spec. array
- p->nrtDevArray = cmMemResizeZ( cmAdNrtDev_t, p->nrtDevArray, p->nrtDevCnt );
-
- // for each nrt. device spec. recd
- for(i=0; i<p->nrtDevCnt; ++i)
- {
- const cmJsonNode_t* np = cmJsonArrayElementC(nrtDevArrNodePtr,i);
-
- // read nrtDevArray record values
- if(( jsRC = cmJsonMemberValues( np, &errLabelPtr,
- "label", kStringTId, &p->nrtDevArray[i].label,
- "srate", kRealTId, &p->nrtDevArray[i].srate,
- "iChCnt", kIntTId, &p->nrtDevArray[i].iChCnt,
- "oChCnt", kIntTId, &p->nrtDevArray[i].oChCnt,
- "cbPeriodMs", kIntTId, &p->nrtDevArray[i].cbPeriodMs,
- NULL )) != kOkJsRC )
- {
- rc = _cmAdParseMemberErr(p, jsRC, errLabelPtr, cmStringNullGuard(p->nrtDevArray[i].label) );
- goto errLabel;
- }
-
- }
-
- }
-
- if((p->asCfgCnt = cmJsonChildCount(asCfgArrNodePtr)) == 0 )
- goto errLabel;
-
- p->asCfgArray = cmMemResizeZ( cmAdAsCfg_t, p->asCfgArray, p->asCfgCnt);
-
- // for each cmAsAudioSysCfg record in audioSysCfgArray[]
- for(i=0; i<p->asCfgCnt; ++i)
- {
- unsigned j;
- const cmJsonNode_t* asCfgNodePtr = cmJsonArrayElementC(asCfgArrNodePtr,i);
- const cmJsonNode_t* ssArrayNodePtr = NULL;
- const char* cfgLabel = NULL;
-
- // read cmAsAudioSysCfg record values
- if(( jsRC = cmJsonMemberValues( asCfgNodePtr, &errLabelPtr,
- "label", kStringTId, &cfgLabel,
- "ssArray", kArrayTId, &ssArrayNodePtr,
- NULL )) != kOkJsRC )
- {
- rc = _cmAdParseMemberErr(p, jsRC, errLabelPtr, cmStringNullGuard(p->asCfgArray[i].label) );
- goto errLabel;
- }
-
- p->asCfgArray[i].label = cfgLabel;
- p->asCfgArray[i].cfg.ssCnt = cmJsonChildCount( ssArrayNodePtr );
- p->asCfgArray[i].cfg.ssArray = cmMemResizeZ( cmAudioSysSubSys_t, p->asCfgArray[i].cfg.ssArray, p->asCfgArray[i].cfg.ssCnt );
- p->asCfgArray[i].cfg.clientCbFunc = _cmAudioSysToClientCallback;
- p->asCfgArray[i].cfg.clientCbData = p;
-
-
- // for each audio system sub-subsystem
- for(j=0; j<p->asCfgArray[i].cfg.ssCnt; ++j)
- {
- cmAudioSysArgs_t* asap = &p->asCfgArray[i].cfg.ssArray[j].args;
- const cmJsonNode_t* argsNodePtr = cmJsonArrayElementC(ssArrayNodePtr,j);
-
- if((jsRC = cmJsonMemberValues( argsNodePtr, &errLabelPtr,
- "inDevIdx", kIntTId, &asap->inDevIdx,
- "outDevIdx", kIntTId, &asap->outDevIdx,
- "syncToInputFl", kTrueTId, &asap->syncInputFl,
- "msgQueueByteCnt", kIntTId, &asap->msgQueueByteCnt,
- "devFramesPerCycle", kIntTId, &asap->devFramesPerCycle,
- "dspFramesPerCycle", kIntTId, &asap->dspFramesPerCycle,
- "audioBufCnt", kIntTId, &asap->audioBufCnt,
- "srate", kRealTId, &asap->srate,
- NULL )) != kOkJsRC )
- {
- rc = _cmAdParseMemberErr(p, jsRC, errLabelPtr, cmStringNullGuard(p->asCfgArray[i].label));
- goto errLabel;
- }
-
- }
-
-
- }
- errLabel:
-
- return rc;
- }
-
- cmAdRC_t _cmAdSetup( cmAd_t* p )
- {
- unsigned i;
- cmAdRC_t rc = kOkAdRC;
-
- for(i=0; i<p->asCfgCnt; ++i)
- {
- unsigned j;
-
- p->asCfgArray[i].cfg.meterMs = p->meterMs;
-
- // BUG BUG BUG - each sub-system should have it's own network
- // manager, and socket port.
-
- p->asCfgArray[i].cfg.netH = p->netH;
-
- for(j=0; j<p->asCfgArray[i].cfg.ssCnt; ++j)
- {
- p->asCfgArray[i].cfg.ssArray[j].cbDataPtr = NULL;
- p->asCfgArray[i].cfg.ssArray[j].cbFunc = _cmAudDspCallback;
- p->asCfgArray[i].cfg.ssArray[j].args.rpt = p->err.rpt;
- }
- }
-
- return rc;
- }
-
- cmAdRC_t _cmAdCreateAggDevices( cmAd_t* p )
- {
- cmAdRC_t rc = kOkAdRC;
- unsigned i;
-
- if( cmApAggAllocate(p->err.rpt) != kOkAgRC )
- return cmErrMsg(&p->err,kAggDevSysFailAdRC,"The aggregate device system allocation failed.");
-
- for(i=0; i<p->aggDevCnt; ++i)
- {
- cmAdAggDev_t* adp = p->aggDevArray + i;
- if( cmApAggCreateDevice(adp->label,adp->physDevCnt,adp->physDevIdxArray,kInAggFl | kOutAggFl) != kOkAgRC )
- rc = cmErrMsg(&p->err,kAggDevCreateFailAdRC,"The aggregate device '%s' creation failed.",cmStringNullGuard(adp->label));
- }
-
- return rc;
- }
-
- cmAdRC_t _cmAdCreateNrtDevices( cmAd_t* p )
- {
- cmAdRC_t rc = kOkAdRC;
- unsigned i;
-
- if( cmApNrtAllocate(p->err.rpt) != kOkApRC )
- return cmErrMsg(&p->err,kNrtDevSysFailAdRC,"The non-real-time device system allocation failed.");
-
- for(i=0; i<p->nrtDevCnt; ++i)
- {
- cmAdNrtDev_t* adp = p->nrtDevArray + i;
- if( cmApNrtCreateDevice(adp->label,adp->srate,adp->iChCnt,adp->oChCnt,adp->cbPeriodMs) != kOkApRC )
- rc = cmErrMsg(&p->err,kNrtDevSysFailAdRC,"The non-real-time device '%s' creation failed.",cmStringNullGuard(adp->label));
- }
-
- return rc;
- }
-
- cmAdRC_t _cmAdSendAudioSysCfgLabels( cmAd_t* p)
- {
- cmAdRC_t rc = kOkAdRC;
- unsigned i;
-
- for(i=0; i<p->asCfgCnt; ++i)
- {
- cmDspValue_t v;
- cmDsvSetStrcz(&v, p->asCfgArray[i].label);
-
- if( cmMsgSend( &p->err,cmInvalidIdx,kUiSelAsId,kAudioSysCfgDuiId,0,i,p->asCfgCnt,&v,p->cbFunc,p->cbDataPtr) != kOkMsgRC )
- {
- rc = cmErrMsg(&p->err,kSendMsgFailAdRC,"Error sending audio system cfg. label message to host.");
- break;
- }
-
- }
- return rc;
- }
-
- cmAdRC_t _cmAdSendDeviceLabels( cmAd_t* p )
- {
- cmAdRC_t rc = kOkAdRC;
- unsigned i,j;
-
- unsigned n = cmApDeviceCount();
-
- for(i=0; i<2; ++i)
- {
- bool inputFl = i==0;
-
- for(j=0; j<n; ++j)
- if( cmApDeviceChannelCount(j,inputFl) )
- {
- cmDspValue_t v;
- cmDsvSetStrcz(&v, cmApDeviceLabel(j));
-
- if( cmMsgSend( &p->err,cmInvalidIdx,kUiSelAsId,kDeviceDuiId,inputFl,j,n,&v,p->cbFunc,p->cbDataPtr) != kOkMsgRC )
- {
- rc = cmErrMsg(&p->err,kSendMsgFailAdRC,"Error sending device label message to host.");
- break;
- }
-
- }
-
- }
- return rc;
- }
-
- cmAdRC_t _cmAdSendProgramLabels( cmAd_t* p )
- {
- cmAdRC_t rc = kOkAdRC;
- unsigned pgmCnt = cmDspSysPgmCount(p->dsH);
- unsigned i;
-
- for(i=0; i<pgmCnt; ++i)
- {
- cmDspValue_t v;
- cmDsvSetStrcz(&v, cmDspPgmLabel(p->dsH,i));
-
- if( cmMsgSend( &p->err,cmInvalidIdx,kUiSelAsId,kProgramDuiId,0,i,pgmCnt,&v,p->cbFunc,p->cbDataPtr) != kOkMsgRC )
- {
- rc = cmErrMsg(&p->err,kSendMsgFailAdRC,"Error sending program label message to host.");
- break;
- }
-
- }
-
- return rc;
- }
-
- cmAdRC_t _cmAudDspFree( cmAd_t* p )
- {
- cmAdRC_t rc = kOkAdRC;
-
- if( cmAudioSysFree(&p->asH) != kOkAsRC )
- {
- rc = cmErrMsg(&p->err,kAudioSysFailAdRC,"The audio system release failed.");
- goto errLabel;
- }
-
- if( cmDspSysFinalize(&p->dsH) != kOkDspRC )
- {
- rc = cmErrMsg(&p->err,kDspSysFailAdRC,"DSP system finalization failed.");
- goto errLabel;
- }
-
- if( cmUdpNetFree(&p->netH) != kOkUnRC )
- {
- rc = cmErrMsg(&p->err,kNetSysFailAdRC,"UDP Network finalization failed.");
- goto errLabel;
- }
-
- if( cmMpIsInitialized() )
- if( cmMpFinalize() != kOkMpRC )
- {
- rc = cmErrMsg(&p->err,kMidiSysFailAdRC,"MIDI system finalization failed.");
- goto errLabel;
- }
-
- if( cmApFinalize() != kOkApRC )
- {
- rc = cmErrMsg(&p->err,kAudioPortFailAdRC,"Audio port finalization failed.");
- goto errLabel;
- }
-
- if( cmApBufFinalize() != kOkApRC )
- {
- rc = cmErrMsg(&p->err,kAudioPortFailAdRC,"Audio port buffer finalization failed.");
- goto errLabel;
- }
-
- if( cmApNrtFree() != kOkAgRC )
- {
- rc = cmErrMsg(&p->err,kNrtDevSysFailAdRC,"The non-real-time device system realease failed.");
- goto errLabel;
- }
-
- if( cmApAggFree() != kOkAgRC )
- {
- rc = cmErrMsg(&p->err,kAggDevSysFailAdRC,"The aggregate device system release failed.");
- goto errLabel;
- }
-
- cmMemPtrFree(&p->nrtDevArray);
-
- unsigned i;
- for(i=0; i<p->aggDevCnt; ++i)
- cmMemPtrFree(&p->aggDevArray[i].physDevIdxArray);
-
- cmMemPtrFree(&p->aggDevArray);
-
- for(i=0; i<p->asCfgCnt; ++i)
- cmMemPtrFree(&p->asCfgArray[i].cfg.ssArray);
-
- cmMemPtrFree(&p->asCfgArray);
-
- cmMemPtrFree(&p->dsSsArray);
-
- if( cmJsonFinalize(&p->sysJsH) != kOkJsRC )
- {
- rc = cmErrMsg(&p->err,kJsonFailAdRC,"System JSON tree finalization failed.");
- goto errLabel;
- }
-
- if( p->sysJsFn != NULL )
- cmFsFreeFn(p->sysJsFn);
-
- cmMemFree(p);
-
- errLabel:
-
- return rc;
- }
-
- cmAdRC_t cmAudDspAlloc( cmCtx_t* ctx, cmAdH_t* hp, cmMsgSendFuncPtr_t cbFunc, void* cbDataPtr )
- {
-
- cmAdRC_t rc = kOkAdRC;
- cmAdRC_t rc0 = kOkAdRC;
-
- if((rc = cmAudDspFree(hp)) != kOkAdRC )
- return rc;
-
- cmAd_t* p = cmMemAllocZ(cmAd_t,1);
-
- cmErrSetup(&p->err,&ctx->rpt,"Audio DSP Engine");
-
- // form the audio dsp resource file name
- if((p->sysJsFn = cmFsMakeFn( cmFsPrefsDir(),cmAudDspSys_FILENAME,NULL,NULL)) == NULL )
- {
- rc = cmErrMsg(&p->err,kFileSysFailAdRC,"Unable to form the audio dsp system resource file name.");
- goto errLabel;
- }
-
- // open the audio dsp resource file
- if(cmJsonInitializeFromFile(&p->sysJsH,p->sysJsFn,ctx) != kOkJsRC )
- {
- rc = cmErrMsg(&p->err,kJsonFailAdRC,"Unable to open the audio dsp resource file: '%s'.",cmStringNullGuard(p->sysJsFn));
- goto errLabel;
- }
-
- // parse the JSON tree
- if((rc = _cmAdParseSysJsonTree(p)) != kOkAdRC )
- goto errLabel;
-
- // create the aggregate device
- if( _cmAdCreateAggDevices(p) != kOkAdRC )
- goto errLabel;
-
- // create the non-real-time devices
- if( _cmAdCreateNrtDevices(p) != kOkAdRC )
- goto errLabel;
-
- // initialize the audio device system
- if( cmApInitialize(&ctx->rpt) != kOkApRC )
- {
- rc = cmErrMsg(&p->err,kAudioPortFailAdRC,"Audio port intialization failed.");
- goto errLabel;
- }
-
- // initialize the audio buffer
- if( cmApBufInitialize( cmApDeviceCount(), p->meterMs ) != kOkApRC )
- {
- rc = cmErrMsg(&p->err,kAudioPortFailAdRC,"Audio port buffer initialization failed.");
- goto errLabel;
- }
-
- // initialize the MIDI system
- if( cmMpInitialize(NULL,NULL,p->midiPortBufByteCnt,"app",&ctx->rpt) != kOkMpRC )
- {
- rc = cmErrMsg(&p->err,kMidiSysFailAdRC,"The MIDI system initialization failed.");
- goto errLabel;
- }
-
- // initialize the UDP network - but do not go into 'listening' mode.
- if( cmUdpNetAllocJson(ctx,&p->netH,p->sysJsH,_cmAdUdpNetCallback,p,kNetOptionalUnFl) != kOkUnRC )
- {
- cmErrMsg(&p->err,kNetSysFailAdRC,"The UDP network initialization failed.");
- goto errLabel;
- }
-
- if((rc = _cmAdSetup(p)) != kOkAdRC )
- goto errLabel;
-
- // initialize the DSP system
- if( cmDspSysInitialize(ctx,&p->dsH,p->netH) )
- {
- rc = cmErrMsg(&p->err,kDspSysFailAdRC,"The DSP system initialization failed.");
- goto errLabel;
- }
-
- // allocate the audio system
- if( cmAudioSysAllocate(&p->asH, &ctx->rpt, NULL ) != kOkAsRC )
- {
- rc = cmErrMsg(&p->err,kAudioSysFailAdRC,"The audio system allocation failed.");
- goto errLabel;
- }
-
- p->cbFunc = cbFunc;
- p->cbDataPtr = cbDataPtr;
- p->curAsCfgIdx = cmInvalidIdx;
- p->ctx = *ctx;
-
- // notify the client of the available audio system configurations
- if((rc = _cmAdSendAudioSysCfgLabels(p)) != kOkAdRC )
- goto errLabel;
-
- // notify the client of the available devices
- if((rc = _cmAdSendDeviceLabels(p)) != kOkAdRC)
- goto errLabel;
-
- // notify the client of the available programs
- if((rc = _cmAdSendProgramLabels(p)) != kOkAdRC )
- goto errLabel;
-
-
- hp->h = p;
-
- errLabel:
-
-
- if( rc != kOkAdRC )
- rc0 = _cmAudDspFree(p);
-
- return rc == kOkAdRC ? rc0 : rc;
- }
-
- cmAdRC_t cmAudDspFree( cmAdH_t* hp )
- {
- cmAdRC_t rc = kOkAdRC;
-
- if( hp == NULL || cmAudDspIsValid(*hp)==false )
- return kOkAdRC;
-
- cmAd_t* p = _cmAdHandleToPtr(*hp);
-
- if((rc = _cmAudDspFree(p)) != kOkAdRC )
- return rc;
-
- hp->h = NULL;
-
- return rc;
- }
-
- bool cmAudDspIsValid( cmAdH_t h )
- { return h.h != NULL; }
-
-
- cmAdRC_t _cmAudDspUnloadPgm( cmAd_t* p, unsigned asSubSysIdx )
- {
- cmAdRC_t rc = kOkAdRC;
- const cmAdAsCfg_t* cfgPtr = NULL;
-
- // Must disable audio thread callbacks to _cmAudDspCallback()
- // while changing DSP system data structures.
- if( cmAudioSysIsEnabled(p->asH) )
- if(cmAudioSysEnable(p->asH,false) != kOkAsRC )
- {
- rc = cmErrMsg(&p->err,kAudioSysFailAdRC,"The audio system could not be disabled.");
- goto errLabel;
- }
-
- // validate the sub-system index
- if( asSubSysIdx >= p->dsSsCnt )
- {
- rc = cmErrMsg(&p->err,kInvalidSubSysIdxAdRC,"The invalid sub-system index %i was encountered while unloading a program.",asSubSysIdx);
- goto errLabel;
- }
-
- // if a valid cfg recd exists
- if( p->curAsCfgIdx != cmInvalidIdx )
- {
- // pointer to audio system configuration
- cfgPtr = p->asCfgArray + p->curAsCfgIdx;
-
- // count of audio system sub-systems should be the same as the current cfg
- assert( p->dsSsCnt == cfgPtr->cfg.ssCnt );
-
- // mark the DSP program as unloaded and pre-sync
- p->dsSsArray[ asSubSysIdx ].isLoadedFl = false;
- p->dsSsArray[ asSubSysIdx ].isSyncFl = false;
- p->syncFl = false;
- }
-
- // unload the current program
- if( cmDspSysUnload(p->dsSsArray[asSubSysIdx].dsH) != kOkDspRC )
- {
- rc = cmErrMsg(&p->err,kDspSysFailAdRC,"Program unload failed.");
- goto errLabel;
- }
-
-
- errLabel:
- return rc;
- }
-
-
- cmAdRC_t _cmAudDspUnloadAudioSys( cmAd_t* p )
- {
- unsigned i;
- cmAdRC_t rc = kOkAdRC;
-
- p->syncFl = false;
-
- for(i=1; i<p->dsSsCnt; ++i)
- {
- if((rc = _cmAudDspUnloadPgm(p,i)) != kOkAdRC )
- goto errLabel;
-
- if( cmDspSysFinalize(&p->dsSsArray[i].dsH) != kOkDspRC )
- {
- rc = cmErrMsg(&p->err,kDspSysFailAdRC,"DSP system finalization failed.");
- goto errLabel;
- }
- }
-
- p->curAsCfgIdx = cmInvalidIdx;
-
- errLabel:
- return rc;
- }
-
- cmAdRC_t _cmAdSendIntMsgToHost( cmAd_t* p, unsigned asSubIdx, unsigned selId, unsigned flags, unsigned intValue )
- {
- cmAdRC_t rc = kOkAdRC;
- cmDspValue_t v;
- cmDsvSetUInt(&v,intValue);
-
- if( cmMsgSend( &p->err,asSubIdx,kUiSelAsId,selId,flags,cmInvalidId,cmInvalidId,&v,p->cbFunc,p->cbDataPtr) != kOkMsgRC )
- rc = cmErrMsg(&p->err,kSendMsgFailAdRC,"Error sending message to host.");
-
- return rc;
- }
-
- // verify that a valid audio cfg has been selected
- cmAdRC_t _cmAdIsAudioSysLoaded( cmAd_t* p )
- {
- cmAdRC_t rc = kOkAdRC;
-
- if( cmAudioSysHandleIsValid(p->asH) == false )
- {
- rc = cmErrMsg(&p->err,kAudioSysFailAdRC,"The audio system is not allocated.");
- goto errLabel;
- }
-
- if( p->curAsCfgIdx == cmInvalidIdx )
- return kInvalidCfgIdxAdRC;
-
- // verify that an audio system is loaded
- if( cmAudioSysIsInitialized(p->asH) && p->curAsCfgIdx == cmInvalidIdx )
- {
- rc = cmErrMsg(&p->err,kInvalidCfgIdxAdRC,"The audio system has not been configured.");
- goto errLabel;
- }
-
- // count of audio system sub-systems should be the same as the current cfg
- assert( p->dsSsCnt == p->asCfgArray[p->curAsCfgIdx].cfg.ssCnt );
-
- errLabel:
- return rc;
- }
-
- // verify that a valid audio cfg and DSP program has been selected
- cmAdRC_t _cmAdIsPgmLoaded( cmAd_t* p, bool verboseFl )
- {
- cmAdRC_t rc;
-
- // a program cannot be loaded if the audio system has not been configured
- if((rc = _cmAdIsAudioSysLoaded(p)) != kOkAdRC )
- return rc;
-
- unsigned i;
-
- // for each sub-system
- for(i=0; i<p->dsSsCnt; ++i)
- {
- // verify that the DSP system has been created
- if( cmDspSysIsValid(p->dsSsArray[i].dsH) == false )
- return cmErrMsg(&p->err,kDspSysFailAdRC,"The DSP sub-system at index %i is not initialized.",i);
-
- // verify that the DSP program was loaded
- if( p->dsSsArray[ i ].isLoadedFl == false )
- {
- if( verboseFl )
- cmErrMsg(&p->err,kNoPgmLoadedAdRC,"There is no program loaded.");
-
- return kNoPgmLoadedAdRC;
- }
- }
-
- return rc;
- }
-
- bool _cmAudDspIsPgmSynced( cmAd_t* p )
- {
- unsigned syncCnt = 0;
- unsigned i;
-
- if( p->syncFl )
- return true;
-
- // if the pgm is not loaded then it cannot be sync'd
- if(_cmAdIsPgmLoaded(p,false) != kOkAdRC )
- return false;
-
- // check each sub-system
- for(i=0; i<p->dsSsCnt; ++i)
- {
- unsigned syncState = cmDspSysSyncState(p->dsSsArray[i].dsH);
-
- // if the subsys is already synced
- if( p->dsSsArray[i].isSyncFl )
- ++syncCnt;
- else
- {
- switch( syncState )
- {
- // the sub-sys is pre or pending sync mode
- case kSyncPreDspId:
- case kSyncPendingDspId:
- break;
-
- // sync mode completed - w/ success or fail
- case kSyncSuccessDspId:
- case kSyncFailDspId:
- {
- // notify the client of the the sync state
- bool syncFl = syncState == kSyncSuccessDspId;
- _cmAdSendIntMsgToHost(p,cmInvalidIdx,kSyncDuiId,syncFl,cmInvalidIdx);
- p->dsSsArray[i].isSyncFl = syncFl;
- }
- break;
-
- }
- }
- }
-
- p->syncFl = syncCnt == p->dsSsCnt;
-
- return p->syncFl;
- }
-
-
- cmAdRC_t _cmAudDspLoadPgm( cmAd_t* p, unsigned asSubSysIdx, unsigned pgmIdx )
- {
- cmAdRC_t rc = kOkAdRC;
- unsigned i;
-
- p->syncFl = false;
-
- // the audio system must be configured before a program is loaded
- if((rc = _cmAdIsAudioSysLoaded(p)) != kOkAdRC )
- return cmErrMsg(&p->err,rc,"Program load failed.");
-
- // validate the sub-system index arg.
- if( asSubSysIdx!=cmInvalidIdx && asSubSysIdx >= p->dsSsCnt )
- {
- rc = cmErrMsg(&p->err,kInvalidSubSysIdxAdRC,"The sub-system index %i is invalid.",asSubSysIdx);
- goto errLabel;
- }
-
- // for each sub-system
- for(i=0; i<p->dsSsCnt; ++i)
- if( asSubSysIdx==cmInvalidIdx || i==asSubSysIdx )
- {
- // unload any currently loaded program on this sub-system
- // (unloading a program automatically disables the audio system)
- if((rc = _cmAudDspUnloadPgm(p, i )) != kOkAdRC )
- goto errLabel;
-
- // load the program
- if( cmDspSysLoad(p->dsSsArray[ i ].dsH, cmAudioSysContext(p->asH,i), pgmIdx ) != kOkDspRC )
- {
- rc = cmErrMsg(&p->err,kDspSysFailAdRC,"The program load failed on audio sub-system %i.",i);
- goto errLabel;
- }
-
- // update the state of the DSP sub-system
- p->dsSsArray[i].curPgmIdx = pgmIdx;
- p->dsSsArray[i].isLoadedFl = true;
- p->dsSsArray[i].isSyncFl = false;
- p->syncFl = false;
-
- // notify the host of the new program
- _cmAdSendIntMsgToHost(p,i,kSetPgmDuiId,0,pgmIdx);
- }
-
- errLabel:
- return rc;
- }
-
- cmAdRC_t _cmAdReinitAudioSys( cmAd_t* p )
- {
- cmAdRC_t rc = kOkAdRC;
-
- p->syncFl = false;
-
- // pointer to the new audio system configuration
- cmAdAsCfg_t* cfgPtr = p->asCfgArray + p->curAsCfgIdx;
-
- // initialize the audio system
- if( cmAudioSysInitialize(p->asH, &cfgPtr->cfg ) != kOkAsRC )
- {
- rc = cmErrMsg(&p->err,kAudioSysFailAdRC,"The audio system initialization failed.");
- goto errLabel;
- }
-
- // reload any currently loaded programs
- unsigned i;
- for(i=0; i<p->dsSsCnt; ++i)
- {
- unsigned pgmIdx;
- if((pgmIdx = p->dsSsArray[i].curPgmIdx) != cmInvalidIdx )
- if((rc = _cmAudDspLoadPgm(p,i,pgmIdx)) != kOkAdRC )
- break;
- }
-
- errLabel:
- return rc;
- }
-
- cmAdRC_t _cmAudDspLoadAudioSys( cmAd_t* p, unsigned asCfgIdx )
- {
- cmAdRC_t rc = kOkAdRC;
- cmAdAsCfg_t* cfgPtr;
- unsigned i;
-
- // validate asCfgIdx
- if( asCfgIdx >= p->asCfgCnt )
- {
- cmErrMsg(&p->err,kInvalidCfgIdxAdRC,"The audio system index %i is invalid.",asCfgIdx);
- goto errLabel;
- }
-
- // clear the current audio system setup - this will automatically disable the audio system
- if((rc = _cmAudDspUnloadAudioSys(p)) != kOkAdRC )
- goto errLabel;
-
- // pointer to the new audio system configuration
- cfgPtr = p->asCfgArray + asCfgIdx;
-
- // get the count of audio system sub-systems
- p->dsSsCnt = cfgPtr->cfg.ssCnt;
-
- // store the index of the current audio system configuration
- p->curAsCfgIdx = asCfgIdx;
-
- if( p->dsSsCnt > 0 )
- {
- p->dsSsArray = cmMemResizeZ(cmAdDsSubSys_t, p->dsSsArray, p->dsSsCnt );
-
- for(i=0; i<p->dsSsCnt; ++i)
- {
- cmDspSysH_t dsH;
-
- // the first sub-system will always use the existing DSP system handle ...
- if( i==0 )
- dsH = p->dsH;
- else
- {
- // ... and allocate additional DSP systems when more than one sub-sys is
- // defined in the audio system configuration
- if( cmDspSysInitialize(&p->ctx,&dsH,p->netH) != kOkDspRC )
- {
- rc = cmErrMsg(&p->err,kDspSysFailAdRC,"Unable to initialize an additional DSP system.");
- goto errLabel;
- }
- }
-
- p->dsSsArray[i].dsH = dsH;
- p->dsSsArray[i].curPgmIdx = cmInvalidIdx;
- p->dsSsArray[i].isLoadedFl= false;
-
- // this cbDataPtr is picked up in _cmAudDspCallback().
- // It is used to connect the audio system to a DSP system handle.
- cfgPtr->cfg.ssArray[i].cbDataPtr = p->dsSsArray + i;
-
- }
- }
-
- // notify the client of the change of audio configuration
- _cmAdSendIntMsgToHost(p,cmInvalidIdx,kSetAudioCfgDuiId,0,asCfgIdx);
-
- // notify the client of the count of audio sub-systems
- _cmAdSendIntMsgToHost(p,cmInvalidIdx,kSubSysCntDuiId,0,p->dsSsCnt);
-
- // for each sub-system
- for(i=0; i<p->dsSsCnt; ++i)
- {
- // notify the client of the currently selected devices
- _cmAdSendIntMsgToHost(p,i,kSetAudioDevDuiId,true, cfgPtr->cfg.ssArray[i].args.inDevIdx);
- _cmAdSendIntMsgToHost(p,i,kSetAudioDevDuiId,false,cfgPtr->cfg.ssArray[i].args.outDevIdx);
-
- // notify the client of the sample rate
- _cmAdSendIntMsgToHost(p,i,kSetSampleRateDuiId,0,(unsigned)cfgPtr->cfg.ssArray[i].args.srate);
-
- _cmAdSendIntMsgToHost(p,i,kSetPgmDuiId,0,cmInvalidIdx);
- }
-
- // the audio system configuration changed so we need to initialize the audio system
- if((rc = _cmAdReinitAudioSys(p)) != kOkAdRC )
- goto errLabel;
-
- errLabel:
- if( rc != kOkAdRC )
- _cmAudDspUnloadAudioSys(p);
-
- return rc;
- }
-
-
-
- cmAdRC_t _cmAudDspEnableAudio( cmAd_t* p, bool enableFl )
- {
- cmAdRC_t rc = kOkAdRC;
-
- if( enableFl )
- {
- // verify an audio system cfg and DSP program has been selected
- if(( rc = _cmAdIsPgmLoaded(p,true)) != kOkAdRC )
- return cmErrMsg(&p->err,rc,"Audio enable failed.");
-
- // if the audio system is already enabled/disabled then do nothing
- if( cmAudioSysIsEnabled(p->asH) == enableFl )
- return kOkAdRC;
-
- // for each sub-system
- unsigned i;
- for(i=0; i<p->dsSsCnt; ++i)
- {
- if( cmDspSysReset(p->dsSsArray[i].dsH) != kOkDspRC )
- {
- rc = cmErrMsg(&p->err,kDspSysFailAdRC,"The DSP system reset failed.");
- goto errLabel;
- }
- }
-
- }
-
- // start/stop the audio sub-system
- if( cmAudioSysEnable(p->asH,enableFl) != kOkAsRC )
- {
- rc = cmErrMsg(&p->err,kAudioSysFailAdRC,"The audio system %s failed.", enableFl ? "enable" : "disable");
- goto errLabel;
- }
-
- // notify the host of the new enable state
- _cmAdSendIntMsgToHost(p,cmInvalidIdx,kEnableDuiId,enableFl,cmInvalidIdx);
-
- errLabel:
- return rc;
-
- }
-
- cmAdRC_t _cmAudDspSetDevice(cmAd_t* p,unsigned asSubIdx, bool inputFl, unsigned devIdx)
- {
- cmAdRC_t rc;
-
- // a device cannot be set if the audio system is not already configured
- if((rc = _cmAdIsAudioSysLoaded(p)) != kOkAdRC )
- return cmErrMsg(&p->err,rc,"Set audio device failed.");
-
- cmAdAsCfg_t* cfgPtr = p->asCfgArray + p->curAsCfgIdx;
-
- // validate the sub-system index
- if( asSubIdx >= p->dsSsCnt )
- {
- rc = cmErrMsg(&p->err,kInvalidSubSysIdxAdRC,"The sub-system index %i is invalid.",asSubIdx);
- goto errLabel;
- }
-
- // assign the new device index to the indicated audio system configuration recd
- if( inputFl )
- {
- if( cfgPtr->cfg.ssArray[ asSubIdx ].args.inDevIdx != devIdx )
- cfgPtr->cfg.ssArray[ asSubIdx ].args.inDevIdx = devIdx;
-
- }
- else
- {
- if( cfgPtr->cfg.ssArray[ asSubIdx ].args.outDevIdx != devIdx )
- cfgPtr->cfg.ssArray[ asSubIdx ].args.outDevIdx = devIdx;
- }
-
- // notify the host that the new device has been set
- _cmAdSendIntMsgToHost(p,asSubIdx,kSetAudioDevDuiId,inputFl, devIdx);
-
- // reinitialize the audio system
- rc = _cmAdReinitAudioSys(p);
-
- errLabel:
-
- return rc;
- }
-
- cmAdRC_t _cmAudDspSetSampleRate(cmAd_t* p, unsigned asSubIdx, double srate )
- {
- cmAdRC_t rc;
-
- if((rc = _cmAdIsAudioSysLoaded(p)) != kOkAdRC )
- return cmErrMsg(&p->err,rc,"Set audio device failed.");
-
- cmAdAsCfg_t* cfgPtr = p->asCfgArray + p->curAsCfgIdx;
-
- // validate the sub-system index
- if( asSubIdx != cmInvalidIdx && asSubIdx >= p->dsSsCnt )
- {
- rc = cmErrMsg(&p->err,kInvalidSubSysIdxAdRC,"The sub-system index %i is invalid.",asSubIdx);
- goto errLabel;
- }
-
- unsigned i;
- for(i=0; i<p->dsSsCnt; ++i)
- {
- // assign the new device index to the indicated audio system configuration recd
- if( asSubIdx==cmInvalidIdx || asSubIdx == i )
- {
- if( cfgPtr->cfg.ssArray[ i ].args.srate != srate )
- cfgPtr->cfg.ssArray[ i ].args.srate = srate;
- }
- }
-
- // notify the client of the new sample rate
- _cmAdSendIntMsgToHost(p,asSubIdx,kSetSampleRateDuiId,0,(unsigned)srate);
-
- // reinitialize the audio system
- rc = _cmAdReinitAudioSys(p);
-
- errLabel:
-
- return rc;
- }
-
-
- cmAdRC_t _cmAudDspClientMsgPoll( cmAd_t* p )
- {
- unsigned i = 0;
-
- // if the program is not synced then don't bother polling the audio system
- if( _cmAudDspIsPgmSynced(p) == false )
- return kOkAdRC;
-
- for(i=0; i<p->msgsPerClientPoll; ++i)
- {
- if( cmAudioSysIsMsgWaiting(p->asH) == 0 )
- break;
-
- if(cmAudioSysReceiveMsg(p->asH,NULL,0) != kOkAsRC )
- return cmErrMsg(&p->err,kAudioSysFailAdRC,"The delivery of an audio system msg for the client failed.");
-
- }
-
- return kOkAdRC;
- }
-
- cmAdRC_t cmAudDspReceiveClientMsg( cmAdH_t h, unsigned msgByteCnt, const void* msg )
- {
- cmAdRC_t rc = kOkAdRC;
- cmAd_t* p = _cmAdHandleToPtr(h);
- cmDspUiHdr_t* m = (cmDspUiHdr_t*)msg;
- /*
- if( m->uiId != kUiSelAsId )
- {
- rc = cmErrMsg(&p->err,kUnknownMsgTypeAdRC,"The message type %i is unknown.");
- goto errLabel;
- }
- */
-
- switch( m->selId )
- {
- case kDevReportDuiId:
- cmApReport(p->err.rpt);
- break;
-
- case kSetAudioCfgDuiId:
- rc = _cmAudDspLoadAudioSys(p,cmDsvUInt(&m->value));
- break;
-
- case kSetPgmDuiId:
- rc = _cmAudDspLoadPgm(p,m->asSubIdx,cmDsvUInt(&m->value));
- break;
-
- case kSetAudioDevDuiId:
- rc = _cmAudDspSetDevice(p,m->asSubIdx,m->flags,cmDsvUInt(&m->value));
- break;
-
- case kSetSampleRateDuiId:
- rc = _cmAudDspSetSampleRate(p,m->asSubIdx,cmDsvDouble(&m->value));
- break;
-
- case kEnableDuiId:
- rc = _cmAudDspEnableAudio(p,m->flags);
- break;
-
- case kSetNotifyEnableDuiId:
- cmAudioSysStatusNotifyEnable(p->asH, cmInvalidIdx, m->flags );
- break;
-
- case kClientMsgPollDuiId:
- rc = _cmAudDspClientMsgPoll(p);
- break;
-
- default:
- if( cmAudioSysDeliverMsg(p->asH,msg,msgByteCnt,cmInvalidId) != kOkAsRC )
- rc = cmErrMsg(&p->err,kSendMsgFailAdRC,"Message delivery to the audio system failed.");
- break;
- }
-
-
-
- // errLabel:
- return rc;
- }
|