12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871 |
-
- #include "cmPrefix.h"
- #include "cmGlobal.h"
- #include "cmRpt.h"
- #include "cmTime.h"
- #include "cmAudioPort.h"
- #include "cmMem.h"
- #include "cmTime.h"
- #include "cmMallocDebug.h"
- #include "cmAudioPort.h"
- #include "cmAudioPortAlsa.h"
- #include "cmThread.h"
-
- #include "alsa/asoundlib.h"
- #include <unistd.h> // usleep
-
- #define NAME_CHAR_CNT (255)
- #define DESC_CHAR_CNT (255)
- #define INIT_DEV_CNT (5)
-
- //#define IMPULSE_FN "/home/kevin/temp/recd0.txt"
-
- enum { kDfltPeriodsPerBuf = 2, kPollfdsArrayCnt=2 };
-
- enum { kInFl=0x01, kOutFl=0x02 };
-
- struct cmApRoot_str;
-
-
- typedef struct devRecd_str
- {
- struct cmApRoot_str* rootPtr;
- unsigned devIdx;
- cmChar_t nameStr[ NAME_CHAR_CNT ];
- cmChar_t descStr[ DESC_CHAR_CNT ];
- unsigned flags;
-
- unsigned framesPerCycle; // samples per sub-buffer
- unsigned periodsPerBuf; // sub-buffers per buffer
- snd_async_handler_t* ahandler;
- unsigned srate; // device sample rate
-
- unsigned iChCnt; // ch count
- unsigned oChCnt;
-
- unsigned iBits; // bits per sample
- unsigned oBits;
-
- bool iSignFl; // sample type is signed
- bool oSignFl;
-
- bool iSwapFl; // swap the sample bytes
- bool oSwapFl;
-
- unsigned iSigBits; // significant bits in each sample beginning
- unsigned oSigBits; // with the most sig. bit.
-
-
- cmApSample_t* iBuf; // iBuf[ iFpc * iChCnt ]
- cmApSample_t* oBuf; // oBuf[ oFpc * oChCnt ]
-
- unsigned oBufCnt; // count of buffers written
-
- #ifdef IMPULSE_FN
- int* recdBuf;
- unsigned recdN;
- unsigned recdIdx;
- #endif
-
- unsigned iFpC; // buffer frames per cycle (in ALSA this is call period_size)
- unsigned oFpC;
-
- snd_pcm_t* iPcmH; // device handle
- snd_pcm_t* oPcmH;
-
- unsigned iCbCnt; // callback count
- unsigned oCbCnt;
-
- unsigned iErrCnt; // error count
- unsigned oErrCnt;
-
- cmApCallbackPtr_t cbPtr; // user callback
- void* userCbPtr;
-
- } cmApDevRecd_t;
-
- typedef struct cmApPoll_str
- {
- cmApDevRecd_t* devPtr;
- bool inputFl;
- unsigned fdsCnt;
- } cmApPollfdsDesc_t;
-
- typedef struct cmApRoot_str
- {
- cmRpt_t* rpt; //
- cmApDevRecd_t* devArray; // array of device records
- unsigned devCnt; // count of actual dev recds in devArray[]
- unsigned devAllocCnt; // count of dev recds allocated in devArray[]
-
- bool asyncFl; // true=use async callback false=use polling thread
-
- cmThreadH_t thH; // polling thread
- unsigned pollfdsAllocCnt; // 2*devCnt (max possible in+out handles)
- struct pollfd* pollfds; // pollfds[ pollfdsAllocCnt ]
- cmApPollfdsDesc_t *pollfdsDesc; // pollfdsDesc[ pollfdsAllocCnt ]
- unsigned pollfdsCnt; // count of active recds in pollfds[] and pollfdsDesc[]
-
- } cmApRoot_t;
-
- cmApRoot_t _cmApRoot = { NULL, NULL, 0, 0 };
-
- //===============================================================================================
- enum
- {
- kReadErrRId,
- kWriteErrRId
- };
-
-
- #undef cmALSA_RECD
- #ifdef cmALSA_RECD
-
- enum
- {
- kNotUsedRId,
- kStartRId,
- kCbRId,
- kSysErrRId,
- kAppErrRId,
- kRecoverRId
- };
-
- typedef struct
- {
- int code;
- char* label;
- } recdErrMap_t;
-
- typedef struct
- {
- unsigned devIdx;
- unsigned typeId;
- cmTimeSpec_t t;
- bool inputFl;
- unsigned arg;
- unsigned arg1;
- } recd;
-
- recd* recdArray = NULL;
- unsigned recdCnt = 0;
- unsigned recdIdx = 0;
- cmTimeSpec_t recdTime;
-
- recdErrMap_t recdSysErrMap[] =
- {
- { -EPIPE, "EPIPE" },
- { -ESTRPIPE, "ESTRPIPE" },
- { -EBADFD, "EBADFD" },
- { 0, NULL }
- };
-
- recdErrMap_t recdAppErrMap[] =
- {
- { kReadErrRId, "Read Error"},
- { kWriteErrRId, "Write Error"},
- { 0, NULL }
- };
-
- const char* _recdSysErrToLabel( int err )
- {
- unsigned i;
- for(i=0; recdSysErrMap[i].label != NULL; ++i)
- if( recdSysErrMap[i].code == err )
- return recdSysErrMap[i].label;
-
- return "<Unknown sys error>";
- }
-
- const char* _recdAppErrToLabel( int err )
- {
- unsigned i;
- for(i=0; recdAppErrMap[i].label != NULL; ++i)
- if( recdAppErrMap[i].code == err )
- return recdAppErrMap[i].label;
-
- return "<Unknown app error>";
- }
-
- void recdSetup()
- {
- recdCnt = 100;
- recdIdx = 0;
- clock_gettime(CLOCK_REALTIME,&recdTime);
- recdArray = cmMemAllocZ(recd,recdCnt);
- }
-
- void recdPush( unsigned typeId, unsigned devIdx, bool inputFl, unsigned arg, unsigned arg1 )
- {
- //if( recdIdx == recdCnt )
- // return;
-
- if( recdIdx == recdCnt )
- recdIdx = 0;
-
- recd* r = recdArray + recdIdx;
- r->typeId = typeId;
- r->devIdx = devIdx;
- r->inputFl = inputFl;
- r->arg = arg;
- r->arg1 = arg1;
- clock_gettime(CLOCK_REALTIME,&r->t);
- ++recdIdx;
- }
-
-
- void recdStart( const cmApDevRecd_t* drp, bool inputFl )
- { recdPush(kStartRId,drp->devIdx,inputFl,0,0); }
-
- void recdCb( const cmApDevRecd_t* drp, bool inputFl, unsigned frmCnt )
- { recdPush(kCbRId,drp->devIdx,inputFl, inputFl ? drp->iCbCnt : drp->oCbCnt, 0 ); }
-
- void recdSysErr( bool inputFl, int err )
- { recdPush(kSysErrRId,cmInvalidIdx,inputFl,err,0); }
-
- void recdAppErr( const cmApDevRecd_t* drp, bool inputFl, int app, int err )
- { recdPush(kAppErrRId,drp->devIdx,inputFl,app,err); }
-
- void recdRecover( const cmApDevRecd_t* drp, bool inputFl, int err, int line )
- { recdPush(kRecoverRId,drp->devIdx,inputFl,err,line); }
-
- void recdPrint()
- {
- unsigned i;
- cmTimeSpec_t t0 = recdTime;
- unsigned j = recdIdx;
- for(i=0; i<recdCnt; ++i)
- {
-
- recd* r = recdArray + j;
- ++j;
- if( j == recdCnt )
- j = 0;
-
- double ms = cmTimeElapsedMicros(&recdTime,&r->t)/1000.0;
- double dms = cmTimeElapsedMicros(&t0,&r->t)/1000.0;
-
- t0 = r->t;
-
- printf("%5i %8.3f %8.3f %i %s: ",i,ms,dms,r->devIdx,r->inputFl ? "in ":"out");
-
- switch(r->typeId)
- {
- case kStartRId:
- printf("start");
- break;
-
- case kCbRId:
- printf("callback %i",r->arg );
- break;
-
- case kSysErrRId:
- printf("sys err %s ",_recdSysErrToLabel(r->arg));
- break;
-
- case kAppErrRId:
- printf("app err %s %s",_recdAppErrToLabel(r->arg),_recdSysErrToLabel(r->arg1));
- break;
-
- case kRecoverRId:
- printf("Recover %s %i",_recdSysErrToLabel(r->arg),r->arg1);
- break;
-
- default:
- printf("Unknown recd type id.\n");
- break;
- }
-
- printf("\n");
- }
- }
-
- void recdFree()
- {
- recdPrint();
- cmMemFree(recdArray);
- }
- #else
-
- void recdSetup(){}
- void recdPush( unsigned typeId, unsigned devIdx, bool inputFl, unsigned arg, unsigned arg1 ){}
- void recdStart( const cmApDevRecd_t* drp, bool inputFl ){}
- void recdCb( const cmApDevRecd_t* drp, bool inputFl, unsigned frmCnt ){}
- void recdSysErr( bool inputFl, int err ){}
- void recdAppErr( const cmApDevRecd_t* drp, bool inputFl, int app, int err ){}
- void recdRecover( const cmApDevRecd_t* drp, bool inputFl, int err, int line ){}
- void recdPrint(){}
- void recdFree(){}
-
- #endif
-
- //===================================================================================================
-
-
- cmApRC_t _cmApOsError( cmApRoot_t* p, int err, const char* fmt, ... )
- {
- va_list vl;
- va_start(vl,fmt);
- int msgN = 255;
- char msg[ msgN+1];
-
- vsnprintf(msg,msgN,fmt,vl);
-
- if( err )
- cmRptPrintf(p->rpt,"%s ALSA Error:%s. ",msg,snd_strerror(err));
- else
- cmRptPrintf(p->rpt,"%s ",msg);
-
- cmRptPrintf(p->rpt,"\n");
-
- va_end(vl);
-
- return kSysErrApRC;
- }
-
- bool _cmApDevSetupError( cmApRoot_t* p, int err, bool inputFl, const cmApDevRecd_t* drp, const char* fmt, ... )
- {
- va_list vl;
- int msgN = 255;
- char msg[ msgN + 1];
-
- va_start(vl,fmt);
- vsnprintf(msg,msgN,fmt,vl);
- _cmApOsError(p,err,"%s for %s '%s' : '%s'.",msg,inputFl ? "INPUT" : "OUTPUT", drp->nameStr, drp->descStr);
- va_end(vl);
- return false;
- }
-
- const char* _cmApPcmStateToString( snd_pcm_state_t state )
- {
- switch( state )
- {
- case SND_PCM_STATE_OPEN: return "open";
- case SND_PCM_STATE_SETUP: return "setup";
- case SND_PCM_STATE_PREPARED: return "prepared";
- case SND_PCM_STATE_RUNNING: return "running";
- case SND_PCM_STATE_XRUN: return "xrun";
- case SND_PCM_STATE_DRAINING: return "draining";
- case SND_PCM_STATE_PAUSED: return "paused";
- case SND_PCM_STATE_SUSPENDED: return "suspended";
- case SND_PCM_STATE_DISCONNECTED: return "disconnected";
-
- }
- return "<invalid>";
- }
-
- void _cmApDevRtReport( cmRpt_t* rpt, cmApDevRecd_t* drp )
- {
- cmRptPrintf(rpt,"cb i:%i o:%i err i:%i o:%i",drp->iCbCnt,drp->oCbCnt,drp->iErrCnt,drp->oErrCnt);
-
- if( drp->iPcmH != NULL )
- cmRptPrintf(rpt," state i:%s",_cmApPcmStateToString(snd_pcm_state(drp->iPcmH)));
-
- if( drp->oPcmH != NULL )
- cmRptPrintf(rpt," o:%s",_cmApPcmStateToString(snd_pcm_state(drp->oPcmH)));
-
- cmRptPrint(rpt,"\n ");
-
- }
-
- void _cmApDevReportFormats( cmRpt_t* rpt, snd_pcm_hw_params_t* hwParams )
- {
- snd_pcm_format_mask_t* mask;
-
- snd_pcm_format_t fmt[] =
- {
- SND_PCM_FORMAT_S8,
- SND_PCM_FORMAT_U8,
- SND_PCM_FORMAT_S16_LE,
- SND_PCM_FORMAT_S16_BE,
- SND_PCM_FORMAT_U16_LE,
- SND_PCM_FORMAT_U16_BE,
- SND_PCM_FORMAT_S24_LE,
- SND_PCM_FORMAT_S24_BE,
- SND_PCM_FORMAT_U24_LE,
- SND_PCM_FORMAT_U24_BE,
- SND_PCM_FORMAT_S32_LE,
- SND_PCM_FORMAT_S32_BE,
- SND_PCM_FORMAT_U32_LE,
- SND_PCM_FORMAT_U32_BE,
- SND_PCM_FORMAT_FLOAT_LE,
- SND_PCM_FORMAT_FLOAT_BE,
- SND_PCM_FORMAT_FLOAT64_LE,
- SND_PCM_FORMAT_FLOAT64_BE,
- SND_PCM_FORMAT_IEC958_SUBFRAME_LE,
- SND_PCM_FORMAT_IEC958_SUBFRAME_BE,
- SND_PCM_FORMAT_MU_LAW,
- SND_PCM_FORMAT_A_LAW,
- SND_PCM_FORMAT_IMA_ADPCM,
- SND_PCM_FORMAT_MPEG,
- SND_PCM_FORMAT_GSM,
- SND_PCM_FORMAT_SPECIAL,
- SND_PCM_FORMAT_S24_3LE,
- SND_PCM_FORMAT_S24_3BE,
- SND_PCM_FORMAT_U24_3LE,
- SND_PCM_FORMAT_U24_3BE,
- SND_PCM_FORMAT_S20_3LE,
- SND_PCM_FORMAT_S20_3BE,
- SND_PCM_FORMAT_U20_3LE,
- SND_PCM_FORMAT_U20_3BE,
- SND_PCM_FORMAT_S18_3LE,
- SND_PCM_FORMAT_S18_3BE,
- SND_PCM_FORMAT_U18_3LE,
- SND_PCM_FORMAT_U18_3BE,
- SND_PCM_FORMAT_G723_24,
- SND_PCM_FORMAT_G723_24_1B,
- SND_PCM_FORMAT_G723_40,
- SND_PCM_FORMAT_G723_40_1B,
- SND_PCM_FORMAT_DSD_U8,
- //SND_PCM_FORMAT_DSD_U16_LE,
- //SND_PCM_FORMAT_DSD_U32_LE,
- //SND_PCM_FORMAT_DSD_U16_BE,
- //SND_PCM_FORMAT_DSD_U32_BE,
- SND_PCM_FORMAT_UNKNOWN
- };
-
- snd_pcm_format_mask_alloca(&mask);
-
- snd_pcm_hw_params_get_format_mask(hwParams,mask);
-
- cmRptPrintf(rpt,"Formats: " );
-
- int i;
- for(i=0; fmt[i]!=SND_PCM_FORMAT_UNKNOWN; ++i)
- if( snd_pcm_format_mask_test(mask, fmt[i] ))
- cmRptPrintf(rpt,"%s%s",snd_pcm_format_name(fmt[i]), snd_pcm_format_cpu_endian(fmt[i]) ? " " : " (swap) ");
-
- cmRptPrintf(rpt,"\n");
-
- }
-
- void _cmApDevReport( cmRpt_t* rpt, cmApDevRecd_t* drp )
- {
- bool inputFl = true;
- snd_pcm_t* pcmH;
- int err;
- unsigned i;
-
- cmApRoot_t* p = drp->rootPtr;
-
- cmRptPrintf(rpt,"%s %s Device:%s Desc:%s\n", drp->flags & kInFl ? "IN ":"", drp->flags & kOutFl ? "OUT ":"", drp->nameStr, drp->descStr);
-
- for(i=0; i<2; i++,inputFl=!inputFl)
- {
- if( ((inputFl==true) && (drp->flags&kInFl)) || (((inputFl==false) && (drp->flags&kOutFl))))
- {
- const char* ioLabel = inputFl ? "In " : "Out";
-
- // attempt to open the sub-device
- if((err = snd_pcm_open(&pcmH,drp->nameStr,inputFl ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,0)) < 0 )
- _cmApDevSetupError(p,err,inputFl,drp,"Attempt to open the PCM handle failed");
- else
- {
- snd_pcm_hw_params_t* hwParams;
-
- snd_pcm_hw_params_alloca(&hwParams);
- memset(hwParams,0,snd_pcm_hw_params_sizeof());
-
- // load the parameter record
- if((err = snd_pcm_hw_params_any(pcmH,hwParams)) < 0 )
- _cmApDevSetupError(p,err,inputFl,drp,"Error obtaining hw param record");
- else
- {
- unsigned minChCnt=0,maxChCnt=0,minSrate=0,maxSrate=0;
- snd_pcm_uframes_t minPeriodFrmCnt=0,maxPeriodFrmCnt=0,minBufFrmCnt=0,maxBufFrmCnt=0;
- int dir;
-
-
- // extract the min channel count
- if((err = snd_pcm_hw_params_get_channels_min(hwParams, &minChCnt )) < 0 )
- _cmApDevSetupError(p,err,inputFl,drp,"Error getting min. channel count.");
-
- // extract the max channel count
- if((err = snd_pcm_hw_params_get_channels_max(hwParams, &maxChCnt )) < 0 )
- _cmApDevSetupError(p,err,inputFl,drp,"Error getting max. channel count.");
-
- // extract the min srate
- if((err = snd_pcm_hw_params_get_rate_min(hwParams, &minSrate,&dir )) < 0 )
- _cmApDevSetupError(p,err,inputFl,drp,"Error getting min. sample rate.");
-
- // extract the max srate
- if((err = snd_pcm_hw_params_get_rate_max(hwParams, &maxSrate,&dir )) < 0 )
- _cmApDevSetupError(p,err,inputFl,drp,"Error getting max. sample rate.");
-
- // extract the min period
- if((err = snd_pcm_hw_params_get_period_size_min(hwParams, &minPeriodFrmCnt,&dir )) < 0 )
- _cmApDevSetupError(p,err,inputFl,drp,"Error getting min. period frame count.");
-
- // extract the max period
- if((err = snd_pcm_hw_params_get_period_size_max(hwParams, &maxPeriodFrmCnt,&dir )) < 0 )
- _cmApDevSetupError(p,err,inputFl,drp,"Error getting max. period frame count.");
-
- // extract the min buf
- if((err = snd_pcm_hw_params_get_buffer_size_min(hwParams, &minBufFrmCnt )) < 0 )
- _cmApDevSetupError(p,err,inputFl,drp,"Error getting min. period frame count.");
-
- // extract the max buffer
- if((err = snd_pcm_hw_params_get_buffer_size_max(hwParams, &maxBufFrmCnt )) < 0 )
- _cmApDevSetupError(p,err,inputFl,drp,"Error getting max. period frame count.");
-
- cmRptPrintf(rpt,"%s chs:%i - %i srate:%i - %i period:%i - %i buf:%i - %i half duplex only:%s joint duplex:%s\n",
- ioLabel,minChCnt,maxChCnt,minSrate,maxSrate,minPeriodFrmCnt,maxPeriodFrmCnt,minBufFrmCnt,maxBufFrmCnt,
- (snd_pcm_hw_params_is_half_duplex(hwParams) ? "yes" : "no"),
- (snd_pcm_hw_params_is_joint_duplex(hwParams) ? "yes" : "no"));
-
- _cmApDevReportFormats( rpt, hwParams );
- }
-
- if((err = snd_pcm_close(pcmH)) < 0)
- _cmApDevSetupError(p,err,inputFl,drp,"Error closing PCM handle");
- }
- }
- }
- }
-
-
- // Called by cmApInitialize() to append a cmApDevRecd to the _cmApRoot.devArray[].
- void _cmApDevAppend( cmApRoot_t* p, cmApDevRecd_t* drp )
- {
- if( p->devCnt == p->devAllocCnt )
- {
- p->devArray = cmMemResizePZ( cmApDevRecd_t, p->devArray, p->devAllocCnt + INIT_DEV_CNT );
- p->devAllocCnt += INIT_DEV_CNT;
- }
-
- drp->devIdx = p->devCnt; // set the device index
- drp->rootPtr = p; // set the pointer back to the root
-
- #ifdef IMPULSE_FN
- drp->recdN = 44100*2*2;
- drp->recdBuf = cmMemAllocZ(int,drp->recdN);
- drp->recdIdx = 0;
- #endif
-
- memcpy(p->devArray + p->devCnt, drp, sizeof(cmApDevRecd_t));
-
- ++p->devCnt;
- }
-
- cmApRC_t _cmApDevShutdown( cmApRoot_t* p, cmApDevRecd_t* drp, bool inputFl )
- {
- int err;
-
- snd_pcm_t** pcmH = inputFl ? &drp->iPcmH : &drp->oPcmH;
-
- if( *pcmH != NULL )
- {
- if((err = snd_pcm_close(*pcmH)) < 0 )
- {
- _cmApDevSetupError(p,err,inputFl,drp,"Error closing device handle.");
- return kSysErrApRC;
- }
-
- *pcmH = NULL;
- }
-
- return kOkApRC;
- }
-
- int _cmApDevOpen( snd_pcm_t** pcmHPtr, const char* devNameStr, bool inputFl )
- {
- int cnt = 0;
- int err;
-
- do
- {
- if((err = snd_pcm_open(pcmHPtr,devNameStr,inputFl ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,0)) < 0 )
- {
- cnt++;
- usleep(10000); // sleep for 10 milliseconds
- }
-
- }while(cnt<100 && err == -EBUSY );
-
- return err;
- }
-
- void _cmApXrun_recover( snd_pcm_t* pcmH, int err, cmApDevRecd_t* drp, bool inputFl, int line )
- {
- char dirCh = inputFl ? 'I' : 'O';
-
- inputFl ? drp->iErrCnt++ : drp->oErrCnt++;
-
- recdRecover(drp,inputFl,err,line);
-
- // -EPIPE signals and over/underrun (see pcm.c example xrun_recovery())
- switch( err )
- {
- case -EPIPE:
- {
-
- int silentFl = 1;
- if((err = snd_pcm_recover( pcmH, err, silentFl )) < 0 )
- _cmApDevSetupError(drp->rootPtr,err,inputFl,drp,"recover failed.");
-
- if( inputFl )
- {
- if((err= snd_pcm_prepare(pcmH)) < 0 )
- _cmApDevSetupError(drp->rootPtr,err,inputFl,drp,"re-prepare failed.");
- else
- if((err = snd_pcm_start(pcmH)) < 0 )
- _cmApDevSetupError(drp->rootPtr,err,inputFl,drp,"restart failed.");
- }
- else
- {
- /*
- _cmApWriteBuf(pcmH, NULL, drp->oChCnt, drp->oFpC );
- _cmApWriteBuf(pcmH, NULL, drp->oChCnt, drp->oFpC );
-
- if((err = snd_pcm_prepare(pcmH))<0)
- _cmApDevSetupError(drp->rootPtr,err,inputFl,drp,"Recovery failed.\n");
- else
- if((err = snd_pcm_resume(pcmH))<0)
- _cmApDevSetupError(drp->rootPtr,err,inputFl,drp,"Resume failed.\n");
- */
- }
-
-
- printf("EPIPE %c %i %i %i\n",dirCh,drp->devIdx,drp->oCbCnt,line);
-
- //if((err = snd_pcm_prepare(pcmH))<0)
- // _devSetupError(err,inputFl,*drp,"Recovery failed.\n");
- //else
- // if((err = snd_pcm_resume(pcmH))<0)
- // _devSetupError(err,inputFl,*drp,"Resume failed.\n");
- break;
- }
-
- case -ESTRPIPE:
- {
- int silentFl = 1;
- if((err = snd_pcm_recover( pcmH, err, silentFl )) < 0 )
- _cmApDevSetupError(drp->rootPtr,err,inputFl,drp,"recover failed.");
-
- printf("audio port impl ESTRPIPE:%c\n",dirCh);
- break;
- }
-
- case -EBADFD:
- {
- _cmApDevSetupError(drp->rootPtr,err,inputFl,drp,"%s failed.",inputFl ? "Read" : "Write" );
- break;
- }
-
- default:
- _cmApDevSetupError(drp->rootPtr,err,inputFl,drp,"Unknown rd/wr error.\n");
-
- } // switch
-
- }
-
- void _cmApStateRecover( snd_pcm_t* pcmH, cmApDevRecd_t* drp, bool inputFl )
- {
- int err = 0;
-
- switch( snd_pcm_state(pcmH))
- {
- case SND_PCM_STATE_XRUN:
- err = -EPIPE;
- break;
-
- case SND_PCM_STATE_SUSPENDED:
- err = -ESTRPIPE;
- break;
-
- case SND_PCM_STATE_OPEN:
- case SND_PCM_STATE_SETUP:
- case SND_PCM_STATE_PREPARED:
- case SND_PCM_STATE_RUNNING:
- case SND_PCM_STATE_DRAINING:
- case SND_PCM_STATE_PAUSED:
- case SND_PCM_STATE_DISCONNECTED:
- //case SND_PCM_STATE_LAST:
- break;
- }
-
- if( err < 0 )
- _cmApXrun_recover( pcmH, err, drp, inputFl, __LINE__ );
-
- }
-
- void _cmApS24_3BE_to_Float( const char* x, cmApSample_t* y, unsigned n )
- {
- unsigned i;
- for(i=0; i<n; ++i,x+=3)
- {
- int s = (((int)x[0])<<16) + (((int)x[1])<<8) + (((int)x[2]));
- y[i] = ((cmApSample_t)s)/0x7fffff;
- }
- }
-
- void _cmApS24_3BE_from_Float( const cmApSample_t* x, char* y, unsigned n )
- {
- unsigned i;
- for(i=0; i<n; ++i)
- {
- int s = x[i] * 0x7fffff;
- y[i*3+2] = (char)((s & 0x7f0000) >> 16);
- y[i*3+1] = (char)((s & 0x00ff00) >> 8);
- y[i*3+0] = (char)((s & 0x0000ff) >> 0);
- }
- }
-
-
- // Returns count of frames written on success or < 0 on error;
- // set smpPtr to NULL to write a buffer of silence
- int _cmApWriteBuf( cmApDevRecd_t* drp, snd_pcm_t* pcmH, const cmApSample_t* sp, unsigned chCnt, unsigned frmCnt, unsigned bits, unsigned sigBits )
- {
- int err = 0;
- unsigned bytesPerSmp = (bits==24 ? 32 : bits)/8;
- unsigned smpCnt = chCnt * frmCnt;
- unsigned byteCnt = bytesPerSmp * smpCnt;
- const cmApSample_t* ep = sp + smpCnt;
- char obuf[ byteCnt ];
-
- // if no output was given then fill the device buffer with zeros
- if( sp == NULL )
- memset(obuf,0,byteCnt);
- else
- {
- // otherwise convert the floating point samples to integers
- switch( bits )
- {
- case 8:
- {
- char* dp = (char*)obuf;
- while( sp < ep )
- *dp++ = (char)(*sp++ * 0x7f);
- }
- break;
-
- case 16:
- {
- short* dp = (short*)obuf;
- while( sp < ep )
- *dp++ = (short)(*sp++ * 0x7fff);
- }
- break;
-
- case 24:
- {
- // for use w/ MBox
- //_cmApS24_3BE_from_Float(sp, obuf, ep-sp );
-
- int* dp = (int*)obuf;
- while( sp < ep )
- *dp++ = (int)(*sp++ * 0x7fffff);
-
- }
- break;
-
- case 32:
- {
- int* dp = (int*)obuf;
-
- while( sp < ep )
- *dp++ = (int)(*sp++ * 0x7fffffff);
-
- #ifdef IMPLUSE_FN
- int* tmp = (int*)obuf;
- unsigned ii = 0;
- if( drp->oBufCnt < 3 )
- for(; ii<32; ++ii)
- tmp[ii] = 0x7fffffff;
- #endif
-
- }
- break;
- }
- }
-
-
- // send the bytes to the device
- err = snd_pcm_writei( pcmH, obuf, frmCnt );
-
- ++drp->oBufCnt;
-
- if( err < 0 )
- {
- recdAppErr(drp,false,kWriteErrRId,err);
- _cmApDevSetupError(drp->rootPtr, err, false, drp, "ALSA write error" );
- }
- else
- if( err > 0 && err != frmCnt )
- {
- _cmApDevSetupError(drp->rootPtr, 0, false, drp, "Actual count of bytes written did not match the count provided." );
- }
-
-
- return err;
- }
-
-
- // Returns frames read on success or < 0 on error.
- // Set smpPtr to NULL to read the incoming buffer and discard it
- int _cmApReadBuf( cmApDevRecd_t* drp, snd_pcm_t* pcmH, cmApSample_t* smpPtr, unsigned chCnt, unsigned frmCnt, unsigned bits, unsigned sigBits )
- {
- int err = 0;
- unsigned bytesPerSmp = (bits==24 ? 32 : bits)/8;
- unsigned smpCnt = chCnt * frmCnt;
- unsigned byteCnt = smpCnt * bytesPerSmp;
-
- char buf[ byteCnt ];
-
- // get the incoming samples into buf[] ...
- err = snd_pcm_readi(pcmH,buf,frmCnt);
-
- // if a read error occurred
- if( err < 0 )
- {
- recdAppErr(drp,true,kReadErrRId,err);
- _cmApDevSetupError(drp->rootPtr, err, false, drp, "ALSA read error" );
- }
- else
- if( err > 0 && err != frmCnt )
- {
- _cmApDevSetupError(drp->rootPtr, 0, false, drp, "Actual count of bytes read did not match the count requested." );
- }
-
- // if no buffer was given then there is nothing else to do
- if( smpPtr == NULL )
- return err;
-
- // setup the return buffer
- cmApSample_t* dp = smpPtr;
- cmApSample_t* ep = dp + cmMin(smpCnt,err*chCnt);
-
- switch(bits)
- {
- case 8:
- {
- char* sp = buf;
- while(dp < ep)
- *dp++ = ((cmApSample_t)*sp++) / 0x7f;
- }
- break;
-
- case 16:
- {
- short* sp = (short*)buf;
- while(dp < ep)
- *dp++ = ((cmApSample_t)*sp++) / 0x7fff;
- }
- break;
-
- case 24:
- {
- // For use with MBox
- //_cmApS24_3BE_to_Float(buf, dp, ep-dp );
- int* sp = (int*)buf;
- while(dp < ep)
- *dp++ = ((cmApSample_t)*sp++) / 0x7fffff;
- }
- break;
-
-
- case 32:
- {
- int* sp = (int*)buf;
- // The delta1010 (ICE1712) uses only the 24 highest bits according to
- //
- // http://www.alsa-project.org/alsa-doc/alsa-lib/pcm.html
- // <snip> The example: ICE1712 chips support 32-bit sample processing,
- // but low byte is ignored (playback) or zero (capture).
- //
- int mv = sigBits==24 ? 0x7fffff00 : 0x7fffffff;
- while(dp < ep)
- *dp++ = ((cmApSample_t)*sp++) / mv;
-
- #ifdef IMPULSE_FN
- sp = (int*)buf;
- int* esp = sp + smpCnt;
- for(; sp<esp && drp->recdIdx < drp->recdN; ++drp->recdIdx)
- drp->recdBuf[drp->recdIdx] = *sp++;
- #endif
-
- }
- break;
- default:
- { assert(0); }
- }
-
- return err;
-
- }
-
- void _cmApStaticAsyncHandler( snd_async_handler_t* ahandler )
- {
- int err;
- snd_pcm_sframes_t avail;
- cmApDevRecd_t* drp = (cmApDevRecd_t*)snd_async_handler_get_callback_private(ahandler);
- snd_pcm_t* pcmH = snd_async_handler_get_pcm(ahandler);
- bool inputFl = snd_pcm_stream(pcmH) == SND_PCM_STREAM_CAPTURE;
- cmApSample_t* b = inputFl ? drp->iBuf : drp->oBuf;
- unsigned chCnt = inputFl ? drp->iChCnt : drp->oChCnt;
- unsigned frmCnt = inputFl ? drp->iFpC : drp->oFpC;
- cmApAudioPacket_t pkt;
-
- inputFl ? drp->iCbCnt++ : drp->oCbCnt++;
-
- pkt.devIdx = drp->devIdx;
- pkt.begChIdx = 0;
- pkt.chCnt = chCnt;
- pkt.audioFramesCnt = frmCnt;
- pkt.bitsPerSample = 32;
- pkt.flags = kInterleavedApFl | kFloatApFl;
- pkt.audioBytesPtr = b;
- pkt.userCbPtr = drp->userCbPtr;
-
- recdCb(drp,inputFl,0);
-
- _cmApStateRecover( pcmH, drp, inputFl );
-
- while( (avail = snd_pcm_avail_update(pcmH)) >= (snd_pcm_sframes_t)frmCnt )
- {
-
- // Handle input
- if( inputFl )
- {
- // read samples from the device
- if((err = _cmApReadBuf(drp,pcmH,drp->iBuf,chCnt,frmCnt,drp->iBits,drp->oBits)) > 0 )
- {
- pkt.audioFramesCnt = err;
-
- drp->cbPtr(&pkt,1,NULL,0 ); // send the samples to the application
- }
- }
-
- // Handle output
- else
- {
- // callback to fill the buffer
- drp->cbPtr(NULL,0,&pkt,1);
-
- // note that the application may return fewer samples than were requested
- err = _cmApWriteBuf(drp, pcmH, pkt.audioFramesCnt < frmCnt ? NULL : drp->oBuf,chCnt,frmCnt,drp->oBits,drp->oSigBits);
-
- }
-
- // Handle read/write errors
- if( err < 0 )
- {
- inputFl ? drp->iErrCnt++ : drp->oErrCnt++;
- _cmApXrun_recover( pcmH, err, drp, inputFl, __LINE__ );
- }
- else
- {
- // _cmApStateRecover( pcmH, drp, inputFl );
- }
-
- } // while
-
- }
-
- bool _cmApThreadFunc(void* param)
- {
- cmApRoot_t* p = (cmApRoot_t*)param;
- int result;
- bool retFl = true;
-
- switch( result = poll(p->pollfds, p->pollfdsCnt, 250) )
- {
- case 0:
- // time out
- break;
-
- case -1:
- _cmApOsError(p,errno,"Poll fail.");
- break;
-
- default:
- {
- assert( result > 0 );
-
- unsigned i;
-
- // for each i/o stream
- for(i=0; i<p->pollfdsCnt; ++i)
- {
- cmApDevRecd_t* drp = p->pollfdsDesc[i].devPtr;
- bool inputFl = p->pollfdsDesc[i].inputFl;
- snd_pcm_t* pcmH = inputFl ? drp->iPcmH : drp->oPcmH;
- unsigned chCnt = inputFl ? drp->iChCnt : drp->oChCnt;
- unsigned frmCnt = inputFl ? drp->iFpC : drp->oFpC;
- cmApSample_t* b = inputFl ? drp->iBuf : drp->oBuf;
- unsigned short revents = 0;
- int err;
- cmApAudioPacket_t pkt;
- snd_pcm_uframes_t avail_frames;
-
- inputFl ? drp->iCbCnt++ : drp->oCbCnt++;
-
- pkt.devIdx = drp->devIdx;
- pkt.begChIdx = 0;
- pkt.chCnt = chCnt;
- pkt.audioFramesCnt = frmCnt;
- pkt.bitsPerSample = 32;
- pkt.flags = kInterleavedApFl | kFloatApFl;
- pkt.audioBytesPtr = b;
- pkt.userCbPtr = drp->userCbPtr;
-
- inputFl ? drp->iCbCnt++ : drp->oCbCnt++;
-
- // get the timestamp for this buffer
- if((err = snd_pcm_htimestamp(pcmH,&avail_frames,&pkt.timeStamp)) != 0 )
- {
- _cmApDevSetupError(p, err, p->pollfdsDesc[i].inputFl, drp, "Get timestamp error.");
- pkt.timeStamp.tv_sec = 0;
- pkt.timeStamp.tv_nsec = 0;
- }
-
- // Note that based on experimenting with the timestamp and the current
- // clock_gettime(CLOCK_MONOTONIC) time it appears that the time stamp
- // marks the end of the current buffer - so in fact the time stamp should
- // be backed up by the availble sample count period to get the time of the
- // first sample in the buffer
- /*
- unsigned avail_nano_secs = (unsigned)(avail_frames * (1000000000.0/drp->srate));
- if( pkt.timeStamp.tv_nsec > avail_nano_secs )
- pkt.timeStamp.tv_nsec -= avail_nano_secs;
- else
- {
- pkt.timeStamp.tv_sec -= 1;
- pkt.timeStamp.tv_nsec = 1000000000 - avail_nano_secs;
- }
- */
-
- //printf("AUDI: %ld %ld\n",pkt.timeStamp.tv_sec,pkt.timeStamp.tv_nsec);
- //cmTimeSpec_t t;
- //clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&t);
- //printf("AUDI: %ld %ld\n",t.tv_sec,t.tv_nsec);
-
-
- switch( snd_pcm_state(pcmH) )
- {
- case SND_PCM_STATE_OPEN:
- case SND_PCM_STATE_SETUP:
- case SND_PCM_STATE_PREPARED:
- case SND_PCM_STATE_DRAINING:
- case SND_PCM_STATE_PAUSED:
- case SND_PCM_STATE_DISCONNECTED:
- continue;
-
- case SND_PCM_STATE_RUNNING:
- case SND_PCM_STATE_XRUN:
- case SND_PCM_STATE_SUSPENDED:
- break;
- }
-
- if(( err = snd_pcm_poll_descriptors_revents(pcmH, p->pollfds + i, 1 , &revents)) != 0 )
- {
- _cmApDevSetupError(p, err, p->pollfdsDesc[i].inputFl, drp, "Return poll events failed.");
- retFl = false;
- goto errLabel;
- }
-
- if(revents & POLLERR)
- {
- _cmApDevSetupError(p, err, p->pollfdsDesc[i].inputFl, drp, "Poll error.");
- _cmApStateRecover( pcmH, drp, inputFl );
- //goto errLabel;
- }
-
- if( inputFl && (revents & POLLIN) )
- {
- if((err = _cmApReadBuf(drp,pcmH,drp->iBuf,chCnt,frmCnt,drp->iBits,drp->oBits)) > 0 )
- {
- pkt.audioFramesCnt = err;
- drp->cbPtr(&pkt,1,NULL,0 ); // send the samples to the application
-
- }
- }
-
- if( !inputFl && (revents & POLLOUT) )
- {
-
- /*
- unsigned srate = 96;
- cmTimeSpec_t t1;
- static cmTimeSpec_t t0 = {0,0};
- clock_gettime(CLOCK_MONOTONIC,&t1);
-
- // time since the time-stamp was generated
- unsigned smp = (srate * (t1.tv_nsec - pkt.timeStamp.tv_nsec)) / 1000000;
-
- // time since the last output buffer was sent
- unsigned dsmp = (srate * (t1.tv_nsec - t0.tv_nsec)) / 1000000;
- printf("%i %ld %i : %ld %ld -> %ld %ld\n",smp,avail_frames,dsmp,pkt.timeStamp.tv_sec,pkt.timeStamp.tv_nsec,t1.tv_sec,t1.tv_nsec);
- t0 = t1;
- */
-
- // callback to fill the buffer
- drp->cbPtr(NULL,0,&pkt,1);
-
- // note that the application may return fewer samples than were requested
- err = _cmApWriteBuf(drp, pcmH, pkt.audioFramesCnt < frmCnt ? NULL : drp->oBuf,chCnt,frmCnt,drp->oBits,drp->oSigBits);
-
- }
-
-
- }
- }
-
- }
-
- errLabel:
- return retFl;
- }
-
-
- bool _cmApDevSetup( cmApDevRecd_t *drp, unsigned srate, unsigned framesPerCycle, unsigned periodsPerBuf )
- {
- int err;
- int dir;
- unsigned i;
- bool retFl = true;
- bool inputFl = true;
- snd_pcm_uframes_t periodFrameCnt = framesPerCycle;
- snd_pcm_uframes_t bufferFrameCnt;
- unsigned bits = 0;
- int sig_bits = 0;
- bool signFl = true;
- bool swapFl = false;
- cmApRoot_t* p = drp->rootPtr;
-
- snd_pcm_format_t fmt[] =
- {
- SND_PCM_FORMAT_S32_LE,
- SND_PCM_FORMAT_S32_BE,
- SND_PCM_FORMAT_S24_LE,
- SND_PCM_FORMAT_S24_BE,
- SND_PCM_FORMAT_S24_3LE,
- SND_PCM_FORMAT_S24_3BE,
- SND_PCM_FORMAT_S16_LE,
- SND_PCM_FORMAT_S16_BE,
- };
-
-
- // setup input, then output device
- for(i=0; i<2; i++,inputFl=!inputFl)
- {
- unsigned chCnt = inputFl ? drp->iChCnt : drp->oChCnt;
- snd_pcm_uframes_t actFpC = 0;
-
- // if this is the in/out pass and the in/out flag is set
- if( ((inputFl==true) && (drp->flags & kInFl)) || ((inputFl==false) && (drp->flags & kOutFl)) )
- {
- snd_pcm_t* pcmH = NULL;
-
- if( _cmApDevShutdown(p, drp, inputFl ) != kOkApRC )
- retFl = false;
-
- // attempt to open the sub-device
- if((err = snd_pcm_open(&pcmH,drp->nameStr, inputFl ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK, 0)) < 0 )
- retFl = _cmApDevSetupError(p,err,inputFl,drp,"Unable to open the PCM handle");
- else
- {
-
- snd_pcm_hw_params_t* hwParams;
- snd_pcm_sw_params_t* swParams;
-
- // prepare the hwParam recd
- snd_pcm_hw_params_alloca(&hwParams);
- memset(hwParams,0,snd_pcm_hw_params_sizeof());
-
-
- // load the hw parameter record
- if((err = snd_pcm_hw_params_any(pcmH,hwParams)) < 0 )
- retFl = _cmApDevSetupError(p,err,inputFl,drp,"Error obtaining hw param record");
- else
- {
- if((err = snd_pcm_hw_params_set_rate_resample(pcmH,hwParams,0)) < 0 )
- retFl = _cmApDevSetupError(p,err,inputFl, drp,"Unable to disable the ALSA sample rate converter.");
-
-
- if((err = snd_pcm_hw_params_set_channels(pcmH,hwParams,chCnt)) < 0 )
- retFl = _cmApDevSetupError(p,err,inputFl, drp,"Unable to set channel count to: %i",chCnt);
-
-
- if((err = snd_pcm_hw_params_set_rate(pcmH,hwParams,srate,0)) < 0 )
- retFl = _cmApDevSetupError(p,err,inputFl, drp, "Unable to set sample rate to: %i",srate);
-
-
- if((err = snd_pcm_hw_params_set_access(pcmH,hwParams,SND_PCM_ACCESS_RW_INTERLEAVED )) < 0 )
- retFl = _cmApDevSetupError(p,err,inputFl, drp, "Unable to set access to: RW Interleaved");
-
- // select the format width
- int j;
- int fmtN = sizeof(fmt)/sizeof(fmt[0]);
- for(j=0; j<fmtN; ++j)
- if((err = snd_pcm_hw_params_set_format(pcmH,hwParams,fmt[j])) >= 0 )
- break;
-
- if( j == fmtN )
- retFl = _cmApDevSetupError(p,err,inputFl, drp, "Unable to set format to: S16");
- else
- {
- bits = snd_pcm_format_width(fmt[j]); // bits per sample
- signFl = snd_pcm_format_signed(fmt[j]);
- swapFl = !snd_pcm_format_cpu_endian(fmt[j]);
- }
-
- sig_bits = snd_pcm_hw_params_get_sbits(hwParams);
-
- snd_pcm_uframes_t ps_min,ps_max;
- if((err = snd_pcm_hw_params_get_period_size_min(hwParams,&ps_min,NULL)) < 0 )
- retFl = _cmApDevSetupError(p,err,inputFl, drp, "Unable to get the minimum period size.");
-
- if((err = snd_pcm_hw_params_get_period_size_max(hwParams,&ps_max,NULL)) < 0 )
- retFl = _cmApDevSetupError(p,err,inputFl, drp, "Unable to get the maximum period size.");
-
- if( periodFrameCnt < ps_min )
- periodFrameCnt = ps_min;
- else
- if( periodFrameCnt > ps_max )
- periodFrameCnt = ps_max;
-
- if((err = snd_pcm_hw_params_set_period_size_near(pcmH,hwParams,&periodFrameCnt,NULL)) < 0 )
- retFl = _cmApDevSetupError(p,err,inputFl, drp, "Unable to set period to %i.",periodFrameCnt);
-
- bufferFrameCnt = periodFrameCnt * periodsPerBuf + 1;
-
- if((err = snd_pcm_hw_params_set_buffer_size_near(pcmH,hwParams,&bufferFrameCnt)) < 0 )
- retFl = _cmApDevSetupError(p,err,inputFl, drp, "Unable to set buffer to %i.",bufferFrameCnt);
-
-
- // Note: snd_pcm_hw_params() automatically calls snd_pcm_prepare()
- if((err = snd_pcm_hw_params(pcmH,hwParams)) < 0 )
- retFl = _cmApDevSetupError(p,err,inputFl, drp, "Parameter application failed.");
-
-
- //_reportActualParams( hwParams, inputFl, dr, srate, periodFrameCnt, bufferFrameCnt );
- }
-
- // prepare the sw param recd
- snd_pcm_sw_params_alloca(&swParams);
- memset(swParams,0,snd_pcm_sw_params_sizeof());
-
- // load the sw param recd
- if((err = snd_pcm_sw_params_current(pcmH,swParams)) < 0 )
- retFl = _cmApDevSetupError(p,err,inputFl,drp,"Error obtaining sw param record.");
- else
- {
-
- if((err = snd_pcm_sw_params_set_start_threshold(pcmH,swParams, inputFl ? 0x7fffffff : periodFrameCnt)) < 0 )
- retFl = _cmApDevSetupError(p,err,inputFl,drp,"Error seting the start threshold.");
-
- // setting the stop-threshold to twice the buffer frame count is intended to stop spurious
- // XRUN states - it will also mean that there will have no direct way of knowing about a
- // in/out buffer over/under run.
- if((err = snd_pcm_sw_params_set_stop_threshold(pcmH,swParams,bufferFrameCnt*2)) < 0 )
- retFl = _cmApDevSetupError(p,err,inputFl,drp,"Error setting the stop threshold.");
-
- if((err = snd_pcm_sw_params_set_avail_min(pcmH,swParams,periodFrameCnt)) < 0 )
- retFl = _cmApDevSetupError(p,err,inputFl,drp,"Error setting the avail. min. setting.");
-
- if((err = snd_pcm_sw_params_set_tstamp_mode(pcmH,swParams,SND_PCM_TSTAMP_MMAP)) < 0 )
- retFl = _cmApDevSetupError(p,err,inputFl,drp,"Error setting the time samp mode.");
-
- if((err = snd_pcm_sw_params(pcmH,swParams)) < 0 )
- retFl = _cmApDevSetupError(p,err,inputFl,drp,"Error applying sw params.");
- }
-
- // setup the callback
- if( p->asyncFl )
- if((err = snd_async_add_pcm_handler(&drp->ahandler,pcmH,_cmApStaticAsyncHandler, drp )) < 0 )
- retFl = _cmApDevSetupError(p,err,inputFl,drp,"Error assigning callback handler.");
-
- // get the actual frames per cycle
- if((err = snd_pcm_hw_params_get_period_size(hwParams,&actFpC,&dir)) < 0 )
- retFl = _cmApDevSetupError(p,err,inputFl,drp,"Unable to get the actual period.");
-
- // store the device handle
- if( inputFl )
- {
- drp->iBits = bits;
- drp->iSigBits = sig_bits;
- drp->iSignFl = signFl;
- drp->iSwapFl = swapFl;
- drp->iPcmH = pcmH;
- drp->iBuf = cmMemResizeZ( cmApSample_t, drp->iBuf, actFpC * drp->iChCnt );
- drp->iFpC = actFpC;
- }
- else
- {
- drp->oBits = bits;
- drp->oSigBits = sig_bits;
- drp->oSignFl = signFl;
- drp->oSwapFl = swapFl;
- drp->oPcmH = pcmH;
- drp->oBuf = cmMemResizeZ( cmApSample_t, drp->oBuf, actFpC * drp->oChCnt );
- drp->oFpC = actFpC;
- }
-
- if( p->asyncFl == false )
- {
- assert( p->pollfdsCnt < p->pollfdsAllocCnt );
-
- unsigned incrFdsCnt = 0;
- unsigned fdsCnt = 0;
-
- // locate the pollfd associated with this device/direction
- unsigned j;
- for(j=0; j<p->pollfdsCnt; j+=p->pollfdsDesc[j].fdsCnt)
- if( p->pollfdsDesc[j].devPtr == drp && inputFl == p->pollfdsDesc[j].inputFl )
- break;
-
- // get the count of descriptors for this device/direction
- fdsCnt = snd_pcm_poll_descriptors_count(pcmH);
-
- // if the device was not found
- if( j == p->pollfdsCnt )
- {
- j = p->pollfdsCnt;
- incrFdsCnt = fdsCnt;
-
- // if the pollfds[] needs more memroy
- if( p->pollfdsCnt + fdsCnt > p->pollfdsAllocCnt )
- {
- p->pollfds = cmMemResizePZ(struct pollfd, p->pollfds, p->pollfdsCnt + fdsCnt );
- p->pollfdsDesc = cmMemResizePZ(cmApPollfdsDesc_t, p->pollfdsDesc, p->pollfdsCnt + fdsCnt );
- p->pollfdsAllocCnt += fdsCnt;
- }
- }
-
- // get the poll descriptors for this device/dir
- if( snd_pcm_poll_descriptors(pcmH,p->pollfds + j,fdsCnt) != 1 )
- retFl = _cmApDevSetupError(p,0,inputFl,drp,"Poll descriptor assignment failed.");
- else
- {
- // store the desc. record assicoated with the poll descriptor
- p->pollfdsDesc[ j ].fdsCnt = fdsCnt;
- p->pollfdsDesc[ j ].devPtr = drp;
- p->pollfdsDesc[ j ].inputFl = inputFl;
- }
-
- p->pollfdsCnt += incrFdsCnt;
- }
- printf("%s %s period:%i %i buffer:%i bits:%i sig_bits:%i\n",inputFl?"in ":"out",drp->nameStr,(unsigned)periodFrameCnt,(unsigned)actFpC,(unsigned)bufferFrameCnt,bits,sig_bits);
-
- }
- //_dumpAlsaDevice(pcmH);
-
- } // end if
-
- } // end for
-
- return retFl;
- }
-
- #ifdef NOTDEF
- #define TRY(e) while(e<0){ printf("LINE:%i ALSA ERROR:%s\n",__LINE__,snd_strerror(e)); exit(EXIT_FAILURE); }
-
- void open_device( const char* device_name, bool inputFl )
- {
- snd_pcm_t *pcm_handle = NULL;
- snd_pcm_hw_params_t *hw_params;
-
-
- snd_pcm_uframes_t bs_min,bs_max,ps_min,ps_max;
- unsigned rt_min,rt_max,ch_min,ch_max;
- const char* ioLabel = inputFl ? "in" : "out";
-
-
- // Open the device
- TRY( snd_pcm_open (&pcm_handle, device_name, inputFl ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK, 0));
-
- TRY( snd_pcm_hw_params_malloc (&hw_params) );
- TRY( snd_pcm_hw_params_any (pcm_handle, hw_params));
-
- TRY( snd_pcm_hw_params_test_format(pcm_handle, hw_params, SND_PCM_FORMAT_S16_LE));
-
- // get the sample rate range
- TRY(snd_pcm_hw_params_get_rate_min(hw_params,&rt_min,NULL));
- TRY(snd_pcm_hw_params_get_rate_max(hw_params,&rt_max,NULL));
- TRY(snd_pcm_hw_params_get_channels_min(hw_params,&ch_min));
- TRY(snd_pcm_hw_params_get_channels_max(hw_params,&ch_max));
-
- // set the basic device format - setting the format may influence the size of the possible
- // buffer and period size
- //TRY( snd_pcm_hw_params_set_access (pcm_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED));
- //TRY( snd_pcm_hw_params_set_format (pcm_handle, hw_params, SND_PCM_FORMAT_S16_LE));
- //TRY( snd_pcm_hw_params_set_rate_near(pcm_handle, hw_params, &srate, NULL));
- //TRY( snd_pcm_hw_params_set_channels(pcm_handle, hw_params, ch_cnt));
-
-
- // get the range of possible buffer and period sizes
- TRY(snd_pcm_hw_params_get_buffer_size_min(hw_params,&bs_min));
- TRY(snd_pcm_hw_params_get_buffer_size_max(hw_params,&bs_max));
- TRY(snd_pcm_hw_params_get_period_size_min(hw_params,&ps_min,NULL));
- TRY(snd_pcm_hw_params_get_period_size_max(hw_params,&ps_max,NULL));
-
- //printf("%s %s bs min:%u max:%u ps min:%u max:%u rate min:%u max:%u ch min:%u max:%u\n",device_name,ioLabel,bs_min,bs_max,ps_min,ps_max,rt_min,rt_max,ch_min,ch_max);
- printf("%s %s rate min:%u max:%u ch min:%u max:%u\n",device_name,ioLabel,rt_min,rt_max,ch_min,ch_max);
-
- snd_pcm_hw_params_free(hw_params);
- snd_pcm_close(pcm_handle);
- }
- #endif
-
- cmApRC_t cmApAlsaInitialize( cmRpt_t* rpt, unsigned baseApDevIdx )
- {
- cmApRC_t rc = kOkApRC;
- int err;
- int cardNum = -1;
-
- if((rc = cmApAlsaFinalize()) != kOkApRC )
- return rc;
-
- recdSetup();
-
- cmApRoot_t* p = &_cmApRoot;
- memset(p,0,sizeof(cmApRoot_t));
- p->rpt = rpt;
- p->asyncFl = false;
-
- // for each sound card
- while(1)
- {
- snd_ctl_t* cardH;
- char* cardNamePtr = NULL;
- char* cardLongNamePtr = NULL;
- int devNum = -1;
- int devStrN = 31;
- char devStr[devStrN+1];
-
-
- // get the next card handle
- if((err = snd_card_next(&cardNum)) < 0 )
- {
- _cmApOsError(p,err,"Error getting sound card handle");
- return kSysErrApRC;
- }
-
- // if no more card's to get
- if( cardNum < 0 )
- break;
-
- // get the card short name
- if(((err = snd_card_get_name(cardNum,&cardNamePtr)) < 0) || (cardNamePtr == NULL))
- {
- _cmApOsError(p,err,"Unable to get card name for card number %i\n",cardNum);
- goto releaseCard;
- }
-
- // get the card long name
- if((err = snd_card_get_longname(cardNum,&cardLongNamePtr)) < 0 || cardLongNamePtr == NULL )
- {
- _cmApOsError(p,err,"Unable to get long card name for card number %i\n",cardNum);
- goto releaseCard;
- }
-
- // form the device name for this card
- if(snprintf(devStr,devStrN,"hw:%i",cardNum) > devStrN )
- {
- _cmApOsError(p,0,"Device name is too long for buffer.");
- goto releaseCard;
- }
-
- // open the card device driver
- if((err = snd_ctl_open(&cardH, devStr, 0)) < 0 )
- {
- _cmApOsError(p,err,"Error opening sound card %i.",cardNum);
- goto releaseCard;
- }
-
-
- // for each device on this card
- while(1)
- {
- snd_pcm_info_t* info;
- int subDevCnt = 1;
- int i,j;
-
- // get the next device on this card
- if((err = snd_ctl_pcm_next_device(cardH,&devNum)) < 0 )
- {
- _cmApOsError(p,err,"Error gettign next device on card %i",cardNum);
- break;
- }
-
- // if no more devices to get
- if( devNum < 0 )
- break;
-
- // allocate a pcmInfo record
- snd_pcm_info_alloca(&info);
- memset(info, 0, snd_pcm_info_sizeof());
-
- // set the device to query
- snd_pcm_info_set_device(info, devNum );
-
- for(i=0; i<subDevCnt; i++)
- {
- cmApDevRecd_t dr;
- bool inputFl = false;
-
- memset(&dr,0,sizeof(dr));
-
- for(j=0; j<2; j++,inputFl=!inputFl)
- {
- snd_pcm_t* pcmH = NULL;
-
- dr.devIdx = -1;
-
- // set the subdevice and I/O direction to query
- snd_pcm_info_set_subdevice(info,i);
- snd_pcm_info_set_stream(info,inputFl ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK);
-
- // if this device does not use this sub-device
- if((err = snd_ctl_pcm_info(cardH,info)) < 0 )
- continue;
-
- // get the count of subdevices this device uses
- if(i == 0 )
- subDevCnt = snd_pcm_info_get_subdevices_count(info);
-
- // if this device has no sub-devices
- if(subDevCnt == 0 )
- continue;
-
- // form the device name and desc. string
- if(strlen(dr.nameStr) == 0)
- snprintf(dr.nameStr,NAME_CHAR_CNT,"hw:%i,%i,%i",cardNum,devNum,i);
-
-
- if(strlen(dr.descStr) == 0)
- {
- snprintf(dr.descStr,DESC_CHAR_CNT,"%s %s",cardNamePtr,snd_pcm_info_get_name(info));
- //snprintf(dr.descStr,DESC_CHAR_CNT,"Name:%s Card:[%s] [%s] Device:%s Subdevice:%s",dr.nameStr, cardNamePtr,cardLongNamePtr,snd_pcm_info_get_id(info),snd_pcm_info_get_name(info));
- }
-
- // attempt to open the sub-device
- if((err = _cmApDevOpen(&pcmH,dr.nameStr,inputFl)) < 0 )
- _cmApDevSetupError(p,err,inputFl,&dr,"Unable to open the PCM handle");
- else
- {
- snd_pcm_hw_params_t* hwParams;
-
- // allocate the parameter record
- snd_pcm_hw_params_alloca(&hwParams);
- memset( hwParams,0,snd_pcm_hw_params_sizeof());
-
-
- // load the parameter record
- if((err = snd_pcm_hw_params_any(pcmH,hwParams)) < 0 )
- _cmApDevSetupError(p,err,inputFl,&dr,"Error obtaining hw param record");
- else
- {
- unsigned* chCntPtr = inputFl ? &dr.iChCnt : &dr.oChCnt;
- unsigned rate;
-
- snd_pcm_hw_params_get_rate_max(hwParams,&rate,NULL);
-
-
- // extract the channel count
- if((err = snd_pcm_hw_params_get_channels_max(hwParams, chCntPtr )) < 0 )
- _cmApDevSetupError(p,err,inputFl,&dr,"Error getting channel count.");
- else
- // this device uses this subdevice in the current direction
- dr.flags += inputFl ? kInFl : kOutFl;
-
- //printf("%s in:%i chs:%i rate:%i\n",dr.nameStr,inputFl,*chCntPtr,rate);
-
- }
-
- // close the sub-device
- snd_pcm_close(pcmH);
-
- }
-
- } // in/out loop
-
- // insert the device in the device array
- if( dr.flags != 0 )
- _cmApDevAppend(p,&dr);
-
- } // sub-dev loop
-
- } // device loop
-
- releaseCard:
- snd_ctl_close(cardH);
-
- } // card loop
-
-
- if( rc == kOkApRC && p->asyncFl==false )
- {
- p->pollfdsCnt = 0;
- p->pollfdsAllocCnt = 2*p->devCnt;
- p->pollfds = cmMemAllocZ(struct pollfd, p->pollfdsAllocCnt );
- p->pollfdsDesc = cmMemAllocZ(cmApPollfdsDesc_t, p->pollfdsAllocCnt );
-
- if( cmThreadCreate(&p->thH,_cmApThreadFunc,p,rpt) != kOkThRC )
- {
- _cmApOsError(p,0,"Thread create failed.");
- rc = kThreadFailApRC;
- }
- }
-
- return rc;
- }
-
- cmApRC_t cmApAlsaFinalize()
- {
- cmApRoot_t* p = &_cmApRoot;
- int i;
- cmApRC_t rc = kOkApRC;
-
- if( p->asyncFl==false && cmThreadIsValid(p->thH) )
- if( cmThreadDestroy(&p->thH) != kOkThRC )
- {
- _cmApOsError(p,0,"Thread destroy failed.");
- rc = kThreadFailApRC;
- }
-
- for(i=0; i<p->devCnt; ++i)
- {
- _cmApDevShutdown(p,p->devArray+i,true);
- _cmApDevShutdown(p,p->devArray+i,false);
-
- #ifdef IMPULSE_FN
- if( p->devArray[i].recdIdx > 0 )
- {
- const char* fn = "/home/kevin/temp/recd0.txt";
- FILE* fp = fopen(fn,"wt");
- if( fp != NULL )
- {
- unsigned j;
- for(j=0; j<p->devArray[i].recdIdx; ++j)
- fprintf(fp,"%i\n",p->devArray[i].recdBuf[j]);
- fclose(fp);
- }
- }
- cmMemFree(p->devArray[i].recdBuf);
- #endif
-
- cmMemPtrFree(&p->devArray[i].iBuf);
- cmMemPtrFree(&p->devArray[i].oBuf);
-
- }
-
- cmMemPtrFree(&p->pollfds);
- cmMemPtrFree(&p->pollfdsDesc);
-
- cmMemPtrFree(&p->devArray);
- p->devAllocCnt = 0;
- p->devCnt = 0;
-
- recdFree();
- //write_rec(2);
-
-
- return rc;
- }
-
- cmApRC_t cmApAlsaDeviceCount()
- { return _cmApRoot.devCnt; }
-
- const char* cmApAlsaDeviceLabel( unsigned devIdx )
- {
- assert(devIdx < cmApAlsaDeviceCount());
- return _cmApRoot.devArray[devIdx].descStr;
- }
-
- unsigned cmApAlsaDeviceChannelCount( unsigned devIdx, bool inputFl )
- {
- assert(devIdx < cmApAlsaDeviceCount());
- return inputFl ? _cmApRoot.devArray[devIdx].iChCnt : _cmApRoot.devArray[devIdx].oChCnt;
- }
-
- double cmApAlsaDeviceSampleRate( unsigned devIdx )
- {
- assert(devIdx < cmApAlsaDeviceCount());
- return (double)_cmApRoot.devArray[devIdx].srate;
- }
-
- unsigned cmApAlsaDeviceFramesPerCycle( unsigned devIdx, bool inputFl )
- {
- assert(devIdx < cmApAlsaDeviceCount());
- return _cmApRoot.devArray[devIdx].framesPerCycle;
- }
-
- cmApRC_t cmApAlsaDeviceSetup(
- unsigned devIdx,
- double srate,
- unsigned framesPerCycle,
- cmApCallbackPtr_t callbackPtr,
- void* userCbPtr )
- {
- assert( devIdx < cmApAlsaDeviceCount());
- cmApRoot_t* p = &_cmApRoot;
- cmApDevRecd_t* drp = _cmApRoot.devArray + devIdx;
- unsigned periodsPerBuf = kDfltPeriodsPerBuf;
-
- if( p->asyncFl == false )
- if( cmThreadPause(p->thH,kWaitThFl | kPauseThFl) != kOkThRC )
- {
- _cmApOsError(p,0,"Audio thread pause failed.");
- return kThreadFailApRC;
- }
-
- if( _cmApDevSetup(drp, srate, framesPerCycle, periodsPerBuf ) )
- {
- drp->srate = srate;
- drp->framesPerCycle = framesPerCycle;
- drp->periodsPerBuf = periodsPerBuf;
- drp->cbPtr = callbackPtr;
- drp->userCbPtr = userCbPtr;
-
- return kOkApRC;
- }
-
- return kSysErrApRC;
- }
-
-
- cmApRC_t cmApAlsaDeviceStart( unsigned devIdx )
- {
- assert( devIdx < cmApAlsaDeviceCount());
- int err;
- cmApRoot_t* p = &_cmApRoot;
- cmApDevRecd_t* drp = p->devArray + devIdx;
- bool retFl = true;
- bool inputFl = true;
- unsigned i;
-
- for(i=0; i<2; ++i,inputFl=!inputFl)
- {
- snd_pcm_t* pcmH = inputFl ? drp->iPcmH : drp->oPcmH;
-
- if( pcmH != NULL )
- {
-
- snd_pcm_state_t state = snd_pcm_state(pcmH);
-
- if( state != SND_PCM_STATE_RUNNING )
- {
- unsigned chCnt = inputFl ? drp->iChCnt : drp->oChCnt;
- unsigned frmCnt = inputFl ? drp->iFpC : drp->oFpC;
- const char* ioLabel = inputFl ? "Input" : "Output";
-
- //printf("%i %s state:%s %i %i\n",drp->devIdx, ioLabel,_pcmStateToString(snd_pcm_state(pcmH)),chCnt,frmCnt);
-
- // preparing may not always be necessary because the earlier call to snd_pcm_hw_params()
- // may have left the device prepared - the redundant call however doesn't seem to hurt
- if((err= snd_pcm_prepare(pcmH)) < 0 )
- retFl = _cmApDevSetupError(p,err,inputFl,drp,"Error preparing the %i device.",ioLabel);
- else
- {
-
- recdStart(drp,inputFl);
-
- if( inputFl == false )
- {
- int j;
- for(j=0; j<1; ++j)
- if((err = _cmApWriteBuf( drp, pcmH, NULL, chCnt, frmCnt, drp->oBits, drp->oSigBits )) < 0 )
- {
- retFl = _cmApDevSetupError(p,err,inputFl,drp,"Write before start failed.");
- break;
- }
- }
- else
- {
-
- if((err = snd_pcm_start(pcmH)) < 0 )
- retFl = _cmApDevSetupError(p,err,inputFl,drp,"'%s' start failed.",ioLabel);
- }
-
- // wait 500 microseconds between starting and stopping - this prevents
- // input and output and other device callbacks from landing on top of
- // each other - when this happens callbacks are dropped.
- if( p->asyncFl )
- usleep(500);
-
- }
- //printf("%i %s state:%s %i %i\n",drp->devIdx, ioLabel,_cmApPcmStateToString(snd_pcm_state(pcmH)),chCnt,frmCnt);
-
- }
-
- }
- }
-
- if( p->asyncFl == false )
- if( cmThreadPause(p->thH,0) != kOkThRC )
- {
- _cmApOsError(p,0,"Audio thread start failed.");
- retFl = false;
- }
-
- return retFl ? kOkApRC : kSysErrApRC;
- }
-
- cmApRC_t cmApAlsaDeviceStop( unsigned devIdx )
- {
- int err;
- bool retFl = true;
- cmApRoot_t* p = &_cmApRoot;
- cmApDevRecd_t* drp = p->devArray + devIdx;
-
- if( drp->iPcmH != NULL )
- if((err = snd_pcm_drop(drp->iPcmH)) < 0 )
- retFl = _cmApDevSetupError(p,err,true,drp,"Input stop failed.");
-
- if( drp->oPcmH != NULL )
- if((err = snd_pcm_drop(drp->oPcmH)) < 0 )
- retFl = _cmApDevSetupError(p,err,false,drp,"Output stop failed.");
-
- if( p->asyncFl == false )
- if( cmThreadPause(p->thH,kPauseThFl) != kOkThRC )
- {
- _cmApOsError(p,0,"Audio thread pause failed.");
- retFl = false;
- }
-
- return retFl ? kOkApRC : kSysErrApRC;
- }
-
- bool cmApAlsaDeviceIsStarted( unsigned devIdx )
- {
- assert( devIdx < cmApAlsaDeviceCount());
-
- bool iFl = false;
- bool oFl = false;
- const cmApDevRecd_t* drp = _cmApRoot.devArray + devIdx;
-
- if( drp->iPcmH != NULL )
- iFl = snd_pcm_state(drp->iPcmH) == SND_PCM_STATE_RUNNING;
-
- if( drp->oPcmH != NULL )
- oFl = snd_pcm_state(drp->oPcmH) == SND_PCM_STATE_RUNNING;
-
- return iFl || oFl;
- }
-
- //{ { label:alsaDevRpt }
- //(
- // Here's an example of generating a report of available
- // ALSA devices.
- //)
-
- //[
- void cmApAlsaDeviceReport( cmRpt_t* rpt )
- {
- unsigned i;
- for(i=0; i<_cmApRoot.devCnt; i++)
- {
- cmRptPrintf(rpt,"%i : ",i);
- _cmApDevReport(rpt,_cmApRoot.devArray + i );
- }
- }
- //]
- //}
-
- void cmApAlsaDeviceRtReport( cmRpt_t* rpt, unsigned devIdx )
- {
- _cmApDevRtReport(rpt, _cmApRoot.devArray + devIdx );
-
- }
|