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

cmAudioPortAlsa.c 50KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692
  1. #include "cmPrefix.h"
  2. #include "cmGlobal.h"
  3. #include "cmRpt.h"
  4. #include "cmTime.h"
  5. #include "cmAudioPort.h"
  6. #include "cmMem.h"
  7. #include "cmTime.h"
  8. #include "cmMallocDebug.h"
  9. #include "cmAudioPort.h"
  10. #include "cmAudioPortAlsa.h"
  11. #include "cmThread.h"
  12. #include "alsa/asoundlib.h"
  13. #include <unistd.h> // usleep
  14. #define NAME_CHAR_CNT (255)
  15. #define DESC_CHAR_CNT (255)
  16. #define INIT_DEV_CNT (5)
  17. enum { kDfltPeriodsPerBuf = 2, kPollfdsArrayCnt=2 };
  18. enum { kInFl=0x01, kOutFl=0x02 };
  19. struct cmApRoot_str;
  20. typedef struct devRecd_str
  21. {
  22. struct cmApRoot_str* rootPtr;
  23. unsigned devIdx;
  24. cmChar_t nameStr[ NAME_CHAR_CNT ];
  25. cmChar_t descStr[ DESC_CHAR_CNT ];
  26. unsigned flags;
  27. unsigned framesPerCycle; // samples per sub-buffer
  28. unsigned periodsPerBuf; // sub-buffers per buffer
  29. snd_async_handler_t* ahandler;
  30. unsigned srate; // device sample rate
  31. unsigned iChCnt; // ch count
  32. unsigned oChCnt;
  33. unsigned iBits; // bits per sample
  34. unsigned oBits;
  35. unsigned iSigBits; // significant bits in each sample beginning
  36. unsigned oSigBits; // with the most sig. bit.
  37. cmApSample_t* iBuf; // iBuf[ iFpc * iChCnt ]
  38. cmApSample_t* oBuf; // oBuf[ oFpc * oChCnt ]
  39. unsigned iFpC; // buffer frames per cycle (in ALSA this is call period_size)
  40. unsigned oFpC;
  41. snd_pcm_t* iPcmH; // device handle
  42. snd_pcm_t* oPcmH;
  43. unsigned iCbCnt; // callback count
  44. unsigned oCbCnt;
  45. unsigned iErrCnt; // error count
  46. unsigned oErrCnt;
  47. cmApCallbackPtr_t cbPtr; // user callback
  48. void* userCbPtr;
  49. } cmApDevRecd_t;
  50. typedef struct cmApPoll_str
  51. {
  52. cmApDevRecd_t* devPtr;
  53. bool inputFl;
  54. unsigned fdsCnt;
  55. } cmApPollfdsDesc_t;
  56. typedef struct cmApRoot_str
  57. {
  58. cmRpt_t* rpt; //
  59. cmApDevRecd_t* devArray; // array of device records
  60. unsigned devCnt; // count of actual dev recds in devArray[]
  61. unsigned devAllocCnt; // count of dev recds allocated in devArray[]
  62. bool asyncFl; // true=use async callback false=use polling thread
  63. cmThreadH_t thH; // polling thread
  64. unsigned pollfdsAllocCnt; // 2*devCnt (max possible in+out handles)
  65. struct pollfd* pollfds; // pollfds[ pollfdsAllocCnt ]
  66. cmApPollfdsDesc_t *pollfdsDesc; // pollfdsDesc[ pollfdsAllocCnt ]
  67. unsigned pollfdsCnt; // count of active recds in pollfds[] and pollfdsDesc[]
  68. } cmApRoot_t;
  69. cmApRoot_t _cmApRoot = { NULL, NULL, 0, 0 };
  70. //===============================================================================================
  71. enum
  72. {
  73. kReadErrRId,
  74. kWriteErrRId
  75. };
  76. #undef cmALSA_RECD
  77. #ifdef cmALSA_RECD
  78. enum
  79. {
  80. kNotUsedRId,
  81. kStartRId,
  82. kCbRId,
  83. kSysErrRId,
  84. kAppErrRId,
  85. kRecoverRId
  86. };
  87. typedef struct
  88. {
  89. int code;
  90. char* label;
  91. } recdErrMap_t;
  92. typedef struct
  93. {
  94. unsigned devIdx;
  95. unsigned typeId;
  96. cmTimeSpec_t t;
  97. bool inputFl;
  98. unsigned arg;
  99. unsigned arg1;
  100. } recd;
  101. recd* recdArray = NULL;
  102. unsigned recdCnt = 0;
  103. unsigned recdIdx = 0;
  104. cmTimeSpec_t recdTime;
  105. recdErrMap_t recdSysErrMap[] =
  106. {
  107. { -EPIPE, "EPIPE" },
  108. { -ESTRPIPE, "ESTRPIPE" },
  109. { -EBADFD, "EBADFD" },
  110. { 0, NULL }
  111. };
  112. recdErrMap_t recdAppErrMap[] =
  113. {
  114. { kReadErrRId, "Read Error"},
  115. { kWriteErrRId, "Write Error"},
  116. { 0, NULL }
  117. };
  118. const char* _recdSysErrToLabel( int err )
  119. {
  120. unsigned i;
  121. for(i=0; recdSysErrMap[i].label != NULL; ++i)
  122. if( recdSysErrMap[i].code == err )
  123. return recdSysErrMap[i].label;
  124. return "<Unknown sys error>";
  125. }
  126. const char* _recdAppErrToLabel( int err )
  127. {
  128. unsigned i;
  129. for(i=0; recdAppErrMap[i].label != NULL; ++i)
  130. if( recdAppErrMap[i].code == err )
  131. return recdAppErrMap[i].label;
  132. return "<Unknown app error>";
  133. }
  134. void recdSetup()
  135. {
  136. recdCnt = 100;
  137. recdIdx = 0;
  138. clock_gettime(CLOCK_REALTIME,&recdTime);
  139. recdArray = cmMemAllocZ(recd,recdCnt);
  140. }
  141. void recdPush( unsigned typeId, unsigned devIdx, bool inputFl, unsigned arg, unsigned arg1 )
  142. {
  143. //if( recdIdx == recdCnt )
  144. // return;
  145. if( recdIdx == recdCnt )
  146. recdIdx = 0;
  147. recd* r = recdArray + recdIdx;
  148. r->typeId = typeId;
  149. r->devIdx = devIdx;
  150. r->inputFl = inputFl;
  151. r->arg = arg;
  152. r->arg1 = arg1;
  153. clock_gettime(CLOCK_REALTIME,&r->t);
  154. ++recdIdx;
  155. }
  156. void recdStart( const cmApDevRecd_t* drp, bool inputFl )
  157. { recdPush(kStartRId,drp->devIdx,inputFl,0,0); }
  158. void recdCb( const cmApDevRecd_t* drp, bool inputFl, unsigned frmCnt )
  159. { recdPush(kCbRId,drp->devIdx,inputFl, inputFl ? drp->iCbCnt : drp->oCbCnt, 0 ); }
  160. void recdSysErr( bool inputFl, int err )
  161. { recdPush(kSysErrRId,cmInvalidIdx,inputFl,err,0); }
  162. void recdAppErr( const cmApDevRecd_t* drp, bool inputFl, int app, int err )
  163. { recdPush(kAppErrRId,drp->devIdx,inputFl,app,err); }
  164. void recdRecover( const cmApDevRecd_t* drp, bool inputFl, int err, int line )
  165. { recdPush(kRecoverRId,drp->devIdx,inputFl,err,line); }
  166. void recdPrint()
  167. {
  168. unsigned i;
  169. cmTimeSpec_t t0 = recdTime;
  170. unsigned j = recdIdx;
  171. for(i=0; i<recdCnt; ++i)
  172. {
  173. recd* r = recdArray + j;
  174. ++j;
  175. if( j == recdCnt )
  176. j = 0;
  177. double ms = cmTimeElapsedMicros(&recdTime,&r->t)/1000.0;
  178. double dms = cmTimeElapsedMicros(&t0,&r->t)/1000.0;
  179. t0 = r->t;
  180. printf("%5i %8.3f %8.3f %i %s: ",i,ms,dms,r->devIdx,r->inputFl ? "in ":"out");
  181. switch(r->typeId)
  182. {
  183. case kStartRId:
  184. printf("start");
  185. break;
  186. case kCbRId:
  187. printf("callback %i",r->arg );
  188. break;
  189. case kSysErrRId:
  190. printf("sys err %s ",_recdSysErrToLabel(r->arg));
  191. break;
  192. case kAppErrRId:
  193. printf("app err %s %s",_recdAppErrToLabel(r->arg),_recdSysErrToLabel(r->arg1));
  194. break;
  195. case kRecoverRId:
  196. printf("Recover %s %i",_recdSysErrToLabel(r->arg),r->arg1);
  197. break;
  198. default:
  199. printf("Unknown recd type id.\n");
  200. break;
  201. }
  202. printf("\n");
  203. }
  204. }
  205. void recdFree()
  206. {
  207. recdPrint();
  208. cmMemFree(recdArray);
  209. }
  210. #else
  211. void recdSetup(){}
  212. void recdPush( unsigned typeId, unsigned devIdx, bool inputFl, unsigned arg, unsigned arg1 ){}
  213. void recdStart( const cmApDevRecd_t* drp, bool inputFl ){}
  214. void recdCb( const cmApDevRecd_t* drp, bool inputFl, unsigned frmCnt ){}
  215. void recdSysErr( bool inputFl, int err ){}
  216. void recdAppErr( const cmApDevRecd_t* drp, bool inputFl, int app, int err ){}
  217. void recdRecover( const cmApDevRecd_t* drp, bool inputFl, int err, int line ){}
  218. void recdPrint(){}
  219. void recdFree(){}
  220. #endif
  221. //===================================================================================================
  222. cmApRC_t _cmApOsError( cmApRoot_t* p, int err, const char* fmt, ... )
  223. {
  224. va_list vl;
  225. va_start(vl,fmt);
  226. int msgN = 255;
  227. char msg[ msgN+1];
  228. vsnprintf(msg,msgN,fmt,vl);
  229. if( err )
  230. cmRptPrintf(p->rpt,"%s ALSA Error:%s. ",msg,snd_strerror(err));
  231. else
  232. cmRptPrintf(p->rpt,"%s ",msg);
  233. cmRptPrintf(p->rpt,"\n");
  234. va_end(vl);
  235. return kSysErrApRC;
  236. }
  237. bool _cmApDevSetupError( cmApRoot_t* p, int err, bool inputFl, const cmApDevRecd_t* drp, const char* fmt, ... )
  238. {
  239. va_list vl;
  240. int msgN = 255;
  241. char msg[ msgN + 1];
  242. va_start(vl,fmt);
  243. vsnprintf(msg,msgN,fmt,vl);
  244. _cmApOsError(p,err,"%s for %s '%s' : '%s'.",msg,inputFl ? "INPUT" : "OUTPUT", drp->nameStr, drp->descStr);
  245. va_end(vl);
  246. return false;
  247. }
  248. const char* _cmApPcmStateToString( snd_pcm_state_t state )
  249. {
  250. switch( state )
  251. {
  252. case SND_PCM_STATE_OPEN: return "open";
  253. case SND_PCM_STATE_SETUP: return "setup";
  254. case SND_PCM_STATE_PREPARED: return "prepared";
  255. case SND_PCM_STATE_RUNNING: return "running";
  256. case SND_PCM_STATE_XRUN: return "xrun";
  257. case SND_PCM_STATE_DRAINING: return "draining";
  258. case SND_PCM_STATE_PAUSED: return "paused";
  259. case SND_PCM_STATE_SUSPENDED: return "suspended";
  260. case SND_PCM_STATE_DISCONNECTED: return "disconnected";
  261. }
  262. return "<invalid>";
  263. }
  264. void _cmApDevRtReport( cmRpt_t* rpt, cmApDevRecd_t* drp )
  265. {
  266. cmRptPrintf(rpt,"cb i:%i o:%i err i:%i o:%i",drp->iCbCnt,drp->oCbCnt,drp->iErrCnt,drp->oErrCnt);
  267. if( drp->iPcmH != NULL )
  268. cmRptPrintf(rpt," state i:%s",_cmApPcmStateToString(snd_pcm_state(drp->iPcmH)));
  269. if( drp->oPcmH != NULL )
  270. cmRptPrintf(rpt," o:%s",_cmApPcmStateToString(snd_pcm_state(drp->oPcmH)));
  271. cmRptPrint(rpt,"\n ");
  272. }
  273. void _cmApDevReport( cmRpt_t* rpt, cmApDevRecd_t* drp )
  274. {
  275. bool inputFl = true;
  276. snd_pcm_t* pcmH;
  277. int err;
  278. unsigned i;
  279. cmApRoot_t* p = drp->rootPtr;
  280. cmRptPrintf(rpt,"%s %s Device:%s Desc:%s\n", drp->flags & kInFl ? "IN ":"", drp->flags & kOutFl ? "OUT ":"", drp->nameStr, drp->descStr);
  281. for(i=0; i<2; i++,inputFl=!inputFl)
  282. {
  283. if( ((inputFl==true) && (drp->flags&kInFl)) || (((inputFl==false) && (drp->flags&kOutFl))))
  284. {
  285. const char* ioLabel = inputFl ? "In" : "Out";
  286. // attempt to open the sub-device
  287. if((err = snd_pcm_open(&pcmH,drp->nameStr,inputFl ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,0)) < 0 )
  288. _cmApDevSetupError(p,err,inputFl,drp,"Attempt to open the PCM handle failed");
  289. else
  290. {
  291. snd_pcm_hw_params_t* hwParams;
  292. snd_pcm_hw_params_alloca(&hwParams);
  293. memset(hwParams,0,snd_pcm_hw_params_sizeof());
  294. // load the parameter record
  295. if((err = snd_pcm_hw_params_any(pcmH,hwParams)) < 0 )
  296. _cmApDevSetupError(p,err,inputFl,drp,"Error obtaining hw param record");
  297. else
  298. {
  299. unsigned minChCnt=0,maxChCnt=0,minSrate=0,maxSrate=0;
  300. snd_pcm_uframes_t minPeriodFrmCnt=0,maxPeriodFrmCnt=0,minBufFrmCnt=0,maxBufFrmCnt=0;
  301. int dir;
  302. // extract the min channel count
  303. if((err = snd_pcm_hw_params_get_channels_min(hwParams, &minChCnt )) < 0 )
  304. _cmApDevSetupError(p,err,inputFl,drp,"Error getting min. channel count.");
  305. // extract the max channel count
  306. if((err = snd_pcm_hw_params_get_channels_max(hwParams, &maxChCnt )) < 0 )
  307. _cmApDevSetupError(p,err,inputFl,drp,"Error getting max. channel count.");
  308. // extract the min srate
  309. if((err = snd_pcm_hw_params_get_rate_min(hwParams, &minSrate,&dir )) < 0 )
  310. _cmApDevSetupError(p,err,inputFl,drp,"Error getting min. sample rate.");
  311. // extract the max srate
  312. if((err = snd_pcm_hw_params_get_rate_max(hwParams, &maxSrate,&dir )) < 0 )
  313. _cmApDevSetupError(p,err,inputFl,drp,"Error getting max. sample rate.");
  314. // extract the min period
  315. if((err = snd_pcm_hw_params_get_period_size_min(hwParams, &minPeriodFrmCnt,&dir )) < 0 )
  316. _cmApDevSetupError(p,err,inputFl,drp,"Error getting min. period frame count.");
  317. // extract the max period
  318. if((err = snd_pcm_hw_params_get_period_size_max(hwParams, &maxPeriodFrmCnt,&dir )) < 0 )
  319. _cmApDevSetupError(p,err,inputFl,drp,"Error getting max. period frame count.");
  320. // extract the min buf
  321. if((err = snd_pcm_hw_params_get_buffer_size_min(hwParams, &minBufFrmCnt )) < 0 )
  322. _cmApDevSetupError(p,err,inputFl,drp,"Error getting min. period frame count.");
  323. // extract the max buffer
  324. if((err = snd_pcm_hw_params_get_buffer_size_max(hwParams, &maxBufFrmCnt )) < 0 )
  325. _cmApDevSetupError(p,err,inputFl,drp,"Error getting max. period frame count.");
  326. cmRptPrintf(rpt,"%s chs:%i - %i srate:%i - %i period:%i - %i buf:%i - %i half duplex only:%s joint duplex:%s\n",
  327. ioLabel,minChCnt,maxChCnt,minSrate,maxSrate,minPeriodFrmCnt,maxPeriodFrmCnt,minBufFrmCnt,maxBufFrmCnt,
  328. (snd_pcm_hw_params_is_half_duplex(hwParams) ? "yes" : "no"),
  329. (snd_pcm_hw_params_is_joint_duplex(hwParams) ? "yes" : "no"));
  330. }
  331. if((err = snd_pcm_close(pcmH)) < 0)
  332. _cmApDevSetupError(p,err,inputFl,drp,"Error closing PCM handle");
  333. }
  334. }
  335. }
  336. }
  337. // Called by cmApInitialize() to append a cmApDevRecd to the _cmApRoot.devArray[].
  338. void _cmApDevAppend( cmApRoot_t* p, cmApDevRecd_t* drp )
  339. {
  340. if( p->devCnt == p->devAllocCnt )
  341. {
  342. p->devArray = cmMemResizePZ( cmApDevRecd_t, p->devArray, p->devAllocCnt + INIT_DEV_CNT );
  343. p->devAllocCnt += INIT_DEV_CNT;
  344. }
  345. drp->devIdx = p->devCnt; // set the device index
  346. drp->rootPtr = p; // set the pointer back to the root
  347. memcpy(p->devArray + p->devCnt, drp, sizeof(cmApDevRecd_t));
  348. ++p->devCnt;
  349. }
  350. cmApRC_t _cmApDevShutdown( cmApRoot_t* p, cmApDevRecd_t* drp, bool inputFl )
  351. {
  352. int err;
  353. snd_pcm_t** pcmH = inputFl ? &drp->iPcmH : &drp->oPcmH;
  354. if( *pcmH != NULL )
  355. {
  356. if((err = snd_pcm_close(*pcmH)) < 0 )
  357. {
  358. _cmApDevSetupError(p,err,inputFl,drp,"Error closing device handle.");
  359. return kSysErrApRC;
  360. }
  361. *pcmH = NULL;
  362. }
  363. return kOkApRC;
  364. }
  365. int _cmApDevOpen( snd_pcm_t** pcmHPtr, const char* devNameStr, bool inputFl )
  366. {
  367. int cnt = 0;
  368. int err;
  369. do
  370. {
  371. if((err = snd_pcm_open(pcmHPtr,devNameStr,inputFl ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,0)) < 0 )
  372. {
  373. cnt++;
  374. usleep(10000); // sleep for 10 milliseconds
  375. }
  376. }while(cnt<100 && err == -EBUSY );
  377. return err;
  378. }
  379. void _cmApXrun_recover( snd_pcm_t* pcmH, int err, cmApDevRecd_t* drp, bool inputFl, int line )
  380. {
  381. char dirCh = inputFl ? 'I' : 'O';
  382. inputFl ? drp->iErrCnt++ : drp->oErrCnt++;
  383. recdRecover(drp,inputFl,err,line);
  384. // -EPIPE signals and over/underrun (see pcm.c example xrun_recovery())
  385. switch( err )
  386. {
  387. case -EPIPE:
  388. {
  389. int silentFl = 1;
  390. if((err = snd_pcm_recover( pcmH, err, silentFl )) < 0 )
  391. _cmApDevSetupError(drp->rootPtr,err,inputFl,drp,"recover failed.");
  392. if( inputFl )
  393. {
  394. if((err= snd_pcm_prepare(pcmH)) < 0 )
  395. _cmApDevSetupError(drp->rootPtr,err,inputFl,drp,"re-prepare failed.");
  396. else
  397. if((err = snd_pcm_start(pcmH)) < 0 )
  398. _cmApDevSetupError(drp->rootPtr,err,inputFl,drp,"restart failed.");
  399. }
  400. else
  401. {
  402. /*
  403. _cmApWriteBuf(pcmH, NULL, drp->oChCnt, drp->oFpC );
  404. _cmApWriteBuf(pcmH, NULL, drp->oChCnt, drp->oFpC );
  405. if((err = snd_pcm_prepare(pcmH))<0)
  406. _cmApDevSetupError(drp->rootPtr,err,inputFl,drp,"Recovery failed.\n");
  407. else
  408. if((err = snd_pcm_resume(pcmH))<0)
  409. _cmApDevSetupError(drp->rootPtr,err,inputFl,drp,"Resume failed.\n");
  410. */
  411. }
  412. printf("EPIPE %c %i %i %i\n",dirCh,drp->devIdx,drp->oCbCnt,line);
  413. //if((err = snd_pcm_prepare(pcmH))<0)
  414. // _devSetupError(err,inputFl,*drp,"Recovery failed.\n");
  415. //else
  416. // if((err = snd_pcm_resume(pcmH))<0)
  417. // _devSetupError(err,inputFl,*drp,"Resume failed.\n");
  418. break;
  419. }
  420. case -ESTRPIPE:
  421. {
  422. int silentFl = 1;
  423. if((err = snd_pcm_recover( pcmH, err, silentFl )) < 0 )
  424. _cmApDevSetupError(drp->rootPtr,err,inputFl,drp,"recover failed.");
  425. printf("audio port impl ESTRPIPE:%c\n",dirCh);
  426. break;
  427. }
  428. case -EBADFD:
  429. {
  430. _cmApDevSetupError(drp->rootPtr,err,inputFl,drp,"%s failed.",inputFl ? "Read" : "Write" );
  431. break;
  432. }
  433. default:
  434. _cmApDevSetupError(drp->rootPtr,err,inputFl,drp,"Unknown rd/wr error.\n");
  435. } // switch
  436. }
  437. void _cmApStateRecover( snd_pcm_t* pcmH, cmApDevRecd_t* drp, bool inputFl )
  438. {
  439. int err = 0;
  440. switch( snd_pcm_state(pcmH))
  441. {
  442. case SND_PCM_STATE_XRUN:
  443. err = -EPIPE;
  444. break;
  445. case SND_PCM_STATE_SUSPENDED:
  446. err = -ESTRPIPE;
  447. break;
  448. case SND_PCM_STATE_OPEN:
  449. case SND_PCM_STATE_SETUP:
  450. case SND_PCM_STATE_PREPARED:
  451. case SND_PCM_STATE_RUNNING:
  452. case SND_PCM_STATE_DRAINING:
  453. case SND_PCM_STATE_PAUSED:
  454. case SND_PCM_STATE_DISCONNECTED:
  455. //case SND_PCM_STATE_LAST:
  456. break;
  457. }
  458. if( err < 0 )
  459. _cmApXrun_recover( pcmH, err, drp, inputFl, __LINE__ );
  460. }
  461. // Returns count of frames written on success or < 0 on error;
  462. // set smpPtr to NULL to write a buffer of silence
  463. int _cmApWriteBuf( const cmApDevRecd_t* drp, snd_pcm_t* pcmH, const cmApSample_t* sp, unsigned chCnt, unsigned frmCnt, unsigned bits, unsigned sigBits )
  464. {
  465. int err = 0;
  466. unsigned bytesPerSmp = (bits==24 ? 32 : bits)/8;
  467. unsigned smpCnt = chCnt * frmCnt;
  468. unsigned byteCnt = bytesPerSmp * smpCnt;
  469. const cmApSample_t* ep = sp + smpCnt;
  470. char obuf[ byteCnt ];
  471. // if no output was given then fill the device buffer with zeros
  472. if( sp == NULL )
  473. memset(obuf,0,byteCnt);
  474. else
  475. {
  476. // otherwise convert the floating point samples to integers
  477. switch( bits )
  478. {
  479. case 8:
  480. {
  481. char* dp = (char*)obuf;
  482. while( sp < ep )
  483. *dp++ = (char)(*sp++ * 0x7f);
  484. }
  485. break;
  486. case 16:
  487. {
  488. short* dp = (short*)obuf;
  489. while( sp < ep )
  490. *dp++ = (short)(*sp++ * 0x7fff);
  491. }
  492. break;
  493. case 24:
  494. {
  495. int* dp = (int*)obuf;
  496. while( sp < ep )
  497. *dp++ = (int)(*sp++ * 0x7fffff);
  498. }
  499. break;
  500. case 32:
  501. {
  502. int* dp = (int*)obuf;
  503. while( sp < ep )
  504. *dp++ = (int)(*sp++ * 0x7fffffff);
  505. }
  506. break;
  507. }
  508. }
  509. // send the bytes to the device
  510. err = snd_pcm_writei( pcmH, obuf, frmCnt );
  511. if( err < 0 )
  512. {
  513. recdAppErr(drp,false,kWriteErrRId,err);
  514. _cmApDevSetupError(drp->rootPtr, err, false, drp, "ALSA write error" );
  515. }
  516. else
  517. if( err > 0 && err != frmCnt )
  518. {
  519. _cmApDevSetupError(drp->rootPtr, 0, false, drp, "Actual count of bytes written did not match the count provided." );
  520. }
  521. return err;
  522. }
  523. // Returns frames read on success or < 0 on error.
  524. // Set smpPtr to NULL to read the incoming buffer and discard it
  525. int _cmApReadBuf( const cmApDevRecd_t* drp, snd_pcm_t* pcmH, cmApSample_t* smpPtr, unsigned chCnt, unsigned frmCnt, unsigned bits, unsigned sigBits )
  526. {
  527. int err = 0;
  528. unsigned bytesPerSmp = (bits==24 ? 32 : bits)/8;
  529. unsigned smpCnt = chCnt * frmCnt;
  530. unsigned byteCnt = smpCnt * bytesPerSmp;
  531. char buf[ byteCnt ];
  532. // get the incoming samples into buf[] ...
  533. err = snd_pcm_readi(pcmH,buf,frmCnt);
  534. // if a read error occurred
  535. if( err < 0 )
  536. {
  537. recdAppErr(drp,true,kReadErrRId,err);
  538. _cmApDevSetupError(drp->rootPtr, err, false, drp, "ALSA read error" );
  539. }
  540. else
  541. if( err > 0 && err != frmCnt )
  542. {
  543. _cmApDevSetupError(drp->rootPtr, 0, false, drp, "Actual count of bytes read did not match the count requested." );
  544. }
  545. // if no buffer was given then there is nothing else to do
  546. if( smpPtr == NULL )
  547. return err;
  548. // setup the return buffer
  549. cmApSample_t* dp = smpPtr;
  550. cmApSample_t* ep = dp + cmMin(smpCnt,err*chCnt);
  551. switch(bits)
  552. {
  553. case 8:
  554. {
  555. char* sp = buf;
  556. while(dp < ep)
  557. *dp++ = ((cmApSample_t)*sp++) / 0x7f;
  558. }
  559. break;
  560. case 16:
  561. {
  562. short* sp = (short*)buf;
  563. while(dp < ep)
  564. *dp++ = ((cmApSample_t)*sp++) / 0x7fff;
  565. }
  566. break;
  567. case 24:
  568. {
  569. int* sp = (int*)buf;
  570. while(dp < ep)
  571. *dp++ = ((cmApSample_t)*sp++) / 0x7fffff;
  572. }
  573. break;
  574. case 32:
  575. {
  576. int* sp = (int*)buf;
  577. // The delta1010 (ICE1712) uses only the 24 highest bits according to
  578. //
  579. // http://www.alsa-project.org/alsa-doc/alsa-lib/pcm.html
  580. // <snip> The example: ICE1712 chips support 32-bit sample processing,
  581. // but low byte is ignored (playback) or zero (capture).
  582. //
  583. int mv = sigBits==24 ? 0x7fffff00 : 0x7fffffff;
  584. while(dp < ep)
  585. *dp++ = ((cmApSample_t)*sp++) / mv;
  586. }
  587. break;
  588. default:
  589. { assert(0); }
  590. }
  591. return err;
  592. }
  593. void _cmApStaticAsyncHandler( snd_async_handler_t* ahandler )
  594. {
  595. int err;
  596. snd_pcm_sframes_t avail;
  597. cmApDevRecd_t* drp = (cmApDevRecd_t*)snd_async_handler_get_callback_private(ahandler);
  598. snd_pcm_t* pcmH = snd_async_handler_get_pcm(ahandler);
  599. bool inputFl = snd_pcm_stream(pcmH) == SND_PCM_STREAM_CAPTURE;
  600. cmApSample_t* b = inputFl ? drp->iBuf : drp->oBuf;
  601. unsigned chCnt = inputFl ? drp->iChCnt : drp->oChCnt;
  602. unsigned frmCnt = inputFl ? drp->iFpC : drp->oFpC;
  603. cmApAudioPacket_t pkt;
  604. inputFl ? drp->iCbCnt++ : drp->oCbCnt++;
  605. pkt.devIdx = drp->devIdx;
  606. pkt.begChIdx = 0;
  607. pkt.chCnt = chCnt;
  608. pkt.audioFramesCnt = frmCnt;
  609. pkt.bitsPerSample = 32;
  610. pkt.flags = kInterleavedApFl | kFloatApFl;
  611. pkt.audioBytesPtr = b;
  612. pkt.userCbPtr = drp->userCbPtr;
  613. recdCb(drp,inputFl,0);
  614. _cmApStateRecover( pcmH, drp, inputFl );
  615. while( (avail = snd_pcm_avail_update(pcmH)) >= (snd_pcm_sframes_t)frmCnt )
  616. {
  617. // Handle inpuut
  618. if( inputFl )
  619. {
  620. // read samples from the device
  621. if((err = _cmApReadBuf(drp,pcmH,drp->iBuf,chCnt,frmCnt,drp->iBits,drp->oBits)) > 0 )
  622. {
  623. pkt.audioFramesCnt = err;
  624. drp->cbPtr(&pkt,1,NULL,0 ); // send the samples to the application
  625. }
  626. }
  627. // Handle output
  628. else
  629. {
  630. // callback to fill the buffer
  631. drp->cbPtr(NULL,0,&pkt,1);
  632. // note that the application may return fewer samples than were requested
  633. err = _cmApWriteBuf(drp, pcmH, pkt.audioFramesCnt < frmCnt ? NULL : drp->oBuf,chCnt,frmCnt,drp->oBits,drp->oSigBits);
  634. }
  635. // Handle read/write errors
  636. if( err < 0 )
  637. {
  638. inputFl ? drp->iErrCnt++ : drp->oErrCnt++;
  639. _cmApXrun_recover( pcmH, err, drp, inputFl, __LINE__ );
  640. }
  641. else
  642. {
  643. // _cmApStateRecover( pcmH, drp, inputFl );
  644. }
  645. } // while
  646. }
  647. bool _cmApThreadFunc(void* param)
  648. {
  649. cmApRoot_t* p = (cmApRoot_t*)param;
  650. int result;
  651. bool retFl = true;
  652. switch( result = poll(p->pollfds, p->pollfdsCnt, 250) )
  653. {
  654. case 0:
  655. // time out
  656. break;
  657. case -1:
  658. _cmApOsError(p,errno,"Poll fail.");
  659. break;
  660. default:
  661. {
  662. assert( result > 0 );
  663. unsigned i;
  664. // for each i/o stream
  665. for(i=0; i<p->pollfdsCnt; ++i)
  666. {
  667. cmApDevRecd_t* drp = p->pollfdsDesc[i].devPtr;
  668. bool inputFl = p->pollfdsDesc[i].inputFl;
  669. snd_pcm_t* pcmH = inputFl ? drp->iPcmH : drp->oPcmH;
  670. unsigned chCnt = inputFl ? drp->iChCnt : drp->oChCnt;
  671. unsigned frmCnt = inputFl ? drp->iFpC : drp->oFpC;
  672. cmApSample_t* b = inputFl ? drp->iBuf : drp->oBuf;
  673. unsigned short revents = 0;
  674. int err;
  675. cmApAudioPacket_t pkt;
  676. snd_pcm_uframes_t avail_frames;
  677. inputFl ? drp->iCbCnt++ : drp->oCbCnt++;
  678. pkt.devIdx = drp->devIdx;
  679. pkt.begChIdx = 0;
  680. pkt.chCnt = chCnt;
  681. pkt.audioFramesCnt = frmCnt;
  682. pkt.bitsPerSample = 32;
  683. pkt.flags = kInterleavedApFl | kFloatApFl;
  684. pkt.audioBytesPtr = b;
  685. pkt.userCbPtr = drp->userCbPtr;
  686. inputFl ? drp->iCbCnt++ : drp->oCbCnt++;
  687. // get the timestamp for this buffer
  688. if((err = snd_pcm_htimestamp(pcmH,&avail_frames,&pkt.timeStamp)) != 0 )
  689. {
  690. _cmApDevSetupError(p, err, p->pollfdsDesc[i].inputFl, drp, "Get timestamp error.");
  691. pkt.timeStamp.tv_sec = 0;
  692. pkt.timeStamp.tv_nsec = 0;
  693. }
  694. // Note that based on experimenting with the timestamp and the current
  695. // clock_gettime(CLOCK_MONOTONIC) time it appears that the time stamp
  696. // marks the end of the current buffer - so in fact the time stamp should
  697. // be backed up by the availble sample count period to get the time of the
  698. // first sample in the buffer
  699. /*
  700. unsigned avail_nano_secs = (unsigned)(avail_frames * (1000000000.0/drp->srate));
  701. if( pkt.timeStamp.tv_nsec > avail_nano_secs )
  702. pkt.timeStamp.tv_nsec -= avail_nano_secs;
  703. else
  704. {
  705. pkt.timeStamp.tv_sec -= 1;
  706. pkt.timeStamp.tv_nsec = 1000000000 - avail_nano_secs;
  707. }
  708. */
  709. //printf("AUDI: %ld %ld\n",pkt.timeStamp.tv_sec,pkt.timeStamp.tv_nsec);
  710. //cmTimeSpec_t t;
  711. //clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&t);
  712. //printf("AUDI: %ld %ld\n",t.tv_sec,t.tv_nsec);
  713. switch( snd_pcm_state(pcmH) )
  714. {
  715. case SND_PCM_STATE_OPEN:
  716. case SND_PCM_STATE_SETUP:
  717. case SND_PCM_STATE_PREPARED:
  718. case SND_PCM_STATE_DRAINING:
  719. case SND_PCM_STATE_PAUSED:
  720. case SND_PCM_STATE_DISCONNECTED:
  721. continue;
  722. case SND_PCM_STATE_RUNNING:
  723. case SND_PCM_STATE_XRUN:
  724. case SND_PCM_STATE_SUSPENDED:
  725. break;
  726. }
  727. if(( err = snd_pcm_poll_descriptors_revents(pcmH, p->pollfds + i, 1 , &revents)) != 0 )
  728. {
  729. _cmApDevSetupError(p, err, p->pollfdsDesc[i].inputFl, drp, "Return poll events failed.");
  730. retFl = false;
  731. goto errLabel;
  732. }
  733. if(revents & POLLERR)
  734. {
  735. _cmApDevSetupError(p, err, p->pollfdsDesc[i].inputFl, drp, "Poll error.");
  736. _cmApStateRecover( pcmH, drp, inputFl );
  737. //goto errLabel;
  738. }
  739. if( inputFl && (revents & POLLIN) )
  740. {
  741. if((err = _cmApReadBuf(drp,pcmH,drp->iBuf,chCnt,frmCnt,drp->iBits,drp->oBits)) > 0 )
  742. {
  743. pkt.audioFramesCnt = err;
  744. drp->cbPtr(&pkt,1,NULL,0 ); // send the samples to the application
  745. }
  746. }
  747. if( !inputFl && (revents & POLLOUT) )
  748. {
  749. /*
  750. unsigned srate = 96;
  751. cmTimeSpec_t t1;
  752. static cmTimeSpec_t t0 = {0,0};
  753. clock_gettime(CLOCK_MONOTONIC,&t1);
  754. // time since the time-stamp was generated
  755. unsigned smp = (srate * (t1.tv_nsec - pkt.timeStamp.tv_nsec)) / 1000000;
  756. // time since the last output buffer was sent
  757. unsigned dsmp = (srate * (t1.tv_nsec - t0.tv_nsec)) / 1000000;
  758. 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);
  759. t0 = t1;
  760. */
  761. // callback to fill the buffer
  762. drp->cbPtr(NULL,0,&pkt,1);
  763. // note that the application may return fewer samples than were requested
  764. err = _cmApWriteBuf(drp, pcmH, pkt.audioFramesCnt < frmCnt ? NULL : drp->oBuf,chCnt,frmCnt,drp->oBits,drp->oSigBits);
  765. }
  766. }
  767. }
  768. }
  769. errLabel:
  770. return retFl;
  771. }
  772. bool _cmApDevSetup( cmApDevRecd_t *drp, unsigned srate, unsigned framesPerCycle, unsigned periodsPerBuf )
  773. {
  774. int err;
  775. int dir;
  776. unsigned i;
  777. bool retFl = true;
  778. bool inputFl = true;
  779. snd_pcm_uframes_t periodFrameCnt = framesPerCycle;
  780. snd_pcm_uframes_t bufferFrameCnt;
  781. unsigned bits = 0;
  782. int sig_bits = 0;
  783. cmApRoot_t* p = drp->rootPtr;
  784. // setup input, then output device
  785. for(i=0; i<2; i++,inputFl=!inputFl)
  786. {
  787. unsigned chCnt = inputFl ? drp->iChCnt : drp->oChCnt;
  788. snd_pcm_uframes_t actFpC = 0;
  789. // if this is the in/out pass and the in/out flag is set
  790. if( ((inputFl==true) && (drp->flags & kInFl)) || ((inputFl==false) && (drp->flags & kOutFl)) )
  791. {
  792. snd_pcm_t* pcmH = NULL;
  793. if( _cmApDevShutdown(p, drp, inputFl ) != kOkApRC )
  794. retFl = false;
  795. // attempt to open the sub-device
  796. if((err = snd_pcm_open(&pcmH,drp->nameStr, inputFl ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK, 0)) < 0 )
  797. retFl = _cmApDevSetupError(p,err,inputFl,drp,"Unable to open the PCM handle");
  798. else
  799. {
  800. snd_pcm_hw_params_t* hwParams;
  801. snd_pcm_sw_params_t* swParams;
  802. // prepare the hwParam recd
  803. snd_pcm_hw_params_alloca(&hwParams);
  804. memset(hwParams,0,snd_pcm_hw_params_sizeof());
  805. // load the hw parameter record
  806. if((err = snd_pcm_hw_params_any(pcmH,hwParams)) < 0 )
  807. retFl = _cmApDevSetupError(p,err,inputFl,drp,"Error obtaining hw param record");
  808. else
  809. {
  810. if((err = snd_pcm_hw_params_set_rate_resample(pcmH,hwParams,0)) < 0 )
  811. retFl = _cmApDevSetupError(p,err,inputFl, drp,"Unable to disable the ALSA sample rate converter.");
  812. if((err = snd_pcm_hw_params_set_channels(pcmH,hwParams,chCnt)) < 0 )
  813. retFl = _cmApDevSetupError(p,err,inputFl, drp,"Unable to set channel count to: %i",chCnt);
  814. if((err = snd_pcm_hw_params_set_rate(pcmH,hwParams,srate,0)) < 0 )
  815. retFl = _cmApDevSetupError(p,err,inputFl, drp, "Unable to set sample rate to: %i",srate);
  816. if((err = snd_pcm_hw_params_set_access(pcmH,hwParams,SND_PCM_ACCESS_RW_INTERLEAVED )) < 0 )
  817. retFl = _cmApDevSetupError(p,err,inputFl, drp, "Unable to set access to: RW Interleaved");
  818. // select the widest possible sample width
  819. if((err = snd_pcm_hw_params_set_format(pcmH,hwParams,SND_PCM_FORMAT_S32)) >= 0 )
  820. bits = 32;
  821. else
  822. {
  823. if((err = snd_pcm_hw_params_set_format(pcmH,hwParams,SND_PCM_FORMAT_S24)) >= 0 )
  824. bits = 24;
  825. else
  826. {
  827. if((err = snd_pcm_hw_params_set_format(pcmH,hwParams,SND_PCM_FORMAT_S16)) >= 0 )
  828. bits = 16;
  829. else
  830. retFl = _cmApDevSetupError(p,err,inputFl, drp, "Unable to set format to: S16");
  831. }
  832. }
  833. sig_bits = snd_pcm_hw_params_get_sbits(hwParams);
  834. snd_pcm_uframes_t ps_min,ps_max;
  835. if((err = snd_pcm_hw_params_get_period_size_min(hwParams,&ps_min,NULL)) < 0 )
  836. retFl = _cmApDevSetupError(p,err,inputFl, drp, "Unable to get the minimum period size.");
  837. if((err = snd_pcm_hw_params_get_period_size_max(hwParams,&ps_max,NULL)) < 0 )
  838. retFl = _cmApDevSetupError(p,err,inputFl, drp, "Unable to get the maximum period size.");
  839. if( periodFrameCnt < ps_min )
  840. periodFrameCnt = ps_min;
  841. else
  842. if( periodFrameCnt > ps_max )
  843. periodFrameCnt = ps_max;
  844. if((err = snd_pcm_hw_params_set_period_size_near(pcmH,hwParams,&periodFrameCnt,NULL)) < 0 )
  845. retFl = _cmApDevSetupError(p,err,inputFl, drp, "Unable to set period to %i.",periodFrameCnt);
  846. bufferFrameCnt = periodFrameCnt * periodsPerBuf + 1;
  847. if((err = snd_pcm_hw_params_set_buffer_size_near(pcmH,hwParams,&bufferFrameCnt)) < 0 )
  848. retFl = _cmApDevSetupError(p,err,inputFl, drp, "Unable to set buffer to %i.",bufferFrameCnt);
  849. // Note: snd_pcm_hw_params() automatically calls snd_pcm_prepare()
  850. if((err = snd_pcm_hw_params(pcmH,hwParams)) < 0 )
  851. retFl = _cmApDevSetupError(p,err,inputFl, drp, "Parameter application failed.");
  852. //_reportActualParams( hwParams, inputFl, dr, srate, periodFrameCnt, bufferFrameCnt );
  853. }
  854. // prepare the sw param recd
  855. snd_pcm_sw_params_alloca(&swParams);
  856. memset(swParams,0,snd_pcm_sw_params_sizeof());
  857. // load the sw param recd
  858. if((err = snd_pcm_sw_params_current(pcmH,swParams)) < 0 )
  859. retFl = _cmApDevSetupError(p,err,inputFl,drp,"Error obtaining sw param record.");
  860. else
  861. {
  862. if((err = snd_pcm_sw_params_set_start_threshold(pcmH,swParams, inputFl ? 0x7fffffff : periodFrameCnt)) < 0 )
  863. retFl = _cmApDevSetupError(p,err,inputFl,drp,"Error seting the start threshold.");
  864. // setting the stop-threshold to twice the buffer frame count is intended to stop spurious
  865. // XRUN states - it will also mean that there will have no direct way of knowing about a
  866. // in/out buffer over/under run.
  867. if((err = snd_pcm_sw_params_set_stop_threshold(pcmH,swParams,bufferFrameCnt*2)) < 0 )
  868. retFl = _cmApDevSetupError(p,err,inputFl,drp,"Error setting the stop threshold.");
  869. if((err = snd_pcm_sw_params_set_avail_min(pcmH,swParams,periodFrameCnt)) < 0 )
  870. retFl = _cmApDevSetupError(p,err,inputFl,drp,"Error setting the avail. min. setting.");
  871. if((err = snd_pcm_sw_params_set_tstamp_mode(pcmH,swParams,SND_PCM_TSTAMP_MMAP)) < 0 )
  872. retFl = _cmApDevSetupError(p,err,inputFl,drp,"Error setting the time samp mode.");
  873. if((err = snd_pcm_sw_params(pcmH,swParams)) < 0 )
  874. retFl = _cmApDevSetupError(p,err,inputFl,drp,"Error applying sw params.");
  875. }
  876. // setup the callback
  877. if( p->asyncFl )
  878. if((err = snd_async_add_pcm_handler(&drp->ahandler,pcmH,_cmApStaticAsyncHandler, drp )) < 0 )
  879. retFl = _cmApDevSetupError(p,err,inputFl,drp,"Error assigning callback handler.");
  880. // get the actual frames per cycle
  881. if((err = snd_pcm_hw_params_get_period_size(hwParams,&actFpC,&dir)) < 0 )
  882. retFl = _cmApDevSetupError(p,err,inputFl,drp,"Unable to get the actual period.");
  883. // store the device handle
  884. if( inputFl )
  885. {
  886. drp->iBits = bits;
  887. drp->iSigBits = sig_bits;
  888. drp->iPcmH = pcmH;
  889. drp->iBuf = cmMemResizeZ( cmApSample_t, drp->iBuf, actFpC * drp->iChCnt );
  890. drp->iFpC = actFpC;
  891. }
  892. else
  893. {
  894. drp->oBits = bits;
  895. drp->oSigBits = sig_bits;
  896. drp->oPcmH = pcmH;
  897. drp->oBuf = cmMemResizeZ( cmApSample_t, drp->oBuf, actFpC * drp->oChCnt );
  898. drp->oFpC = actFpC;
  899. }
  900. if( p->asyncFl == false )
  901. {
  902. assert( p->pollfdsCnt < p->pollfdsAllocCnt );
  903. unsigned incrFdsCnt = 0;
  904. unsigned fdsCnt = 0;
  905. // locate the pollfd associated with this device/direction
  906. unsigned j;
  907. for(j=0; j<p->pollfdsCnt; j+=p->pollfdsDesc[j].fdsCnt)
  908. if( p->pollfdsDesc[j].devPtr == drp && inputFl == p->pollfdsDesc[j].inputFl )
  909. break;
  910. // get the count of descriptors for this device/direction
  911. fdsCnt = snd_pcm_poll_descriptors_count(pcmH);
  912. // if the device was not found
  913. if( j == p->pollfdsCnt )
  914. {
  915. j = p->pollfdsCnt;
  916. incrFdsCnt = fdsCnt;
  917. // if the pollfds[] needs more memroy
  918. if( p->pollfdsCnt + fdsCnt > p->pollfdsAllocCnt )
  919. {
  920. p->pollfds = cmMemResizePZ(struct pollfd, p->pollfds, p->pollfdsCnt + fdsCnt );
  921. p->pollfdsDesc = cmMemResizePZ(cmApPollfdsDesc_t, p->pollfdsDesc, p->pollfdsCnt + fdsCnt );
  922. p->pollfdsAllocCnt += fdsCnt;
  923. }
  924. }
  925. // get the poll descriptors for this device/dir
  926. if( snd_pcm_poll_descriptors(pcmH,p->pollfds + j,fdsCnt) != 1 )
  927. retFl = _cmApDevSetupError(p,0,inputFl,drp,"Poll descriptor assignment failed.");
  928. else
  929. {
  930. // store the desc. record assicoated with the poll descriptor
  931. p->pollfdsDesc[ j ].fdsCnt = fdsCnt;
  932. p->pollfdsDesc[ j ].devPtr = drp;
  933. p->pollfdsDesc[ j ].inputFl = inputFl;
  934. }
  935. p->pollfdsCnt += incrFdsCnt;
  936. }
  937. 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);
  938. }
  939. //_dumpAlsaDevice(pcmH);
  940. } // end if
  941. } // end for
  942. return retFl;
  943. }
  944. #ifdef NOTDEF
  945. #define TRY(e) while(e<0){ printf("LINE:%i ALSA ERROR:%s\n",__LINE__,snd_strerror(e)); exit(EXIT_FAILURE); }
  946. void open_device( const char* device_name, bool inputFl )
  947. {
  948. snd_pcm_t *pcm_handle = NULL;
  949. snd_pcm_hw_params_t *hw_params;
  950. snd_pcm_uframes_t bs_min,bs_max,ps_min,ps_max;
  951. unsigned rt_min,rt_max,ch_min,ch_max;
  952. const char* ioLabel = inputFl ? "in" : "out";
  953. // Open the device
  954. TRY( snd_pcm_open (&pcm_handle, device_name, inputFl ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK, 0));
  955. TRY( snd_pcm_hw_params_malloc (&hw_params) );
  956. TRY( snd_pcm_hw_params_any (pcm_handle, hw_params));
  957. TRY( snd_pcm_hw_params_test_format(pcm_handle, hw_params, SND_PCM_FORMAT_S16_LE));
  958. // get the sample rate range
  959. TRY(snd_pcm_hw_params_get_rate_min(hw_params,&rt_min,NULL));
  960. TRY(snd_pcm_hw_params_get_rate_max(hw_params,&rt_max,NULL));
  961. TRY(snd_pcm_hw_params_get_channels_min(hw_params,&ch_min));
  962. TRY(snd_pcm_hw_params_get_channels_max(hw_params,&ch_max));
  963. // set the basic device format - setting the format may influence the size of the possible
  964. // buffer and period size
  965. //TRY( snd_pcm_hw_params_set_access (pcm_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED));
  966. //TRY( snd_pcm_hw_params_set_format (pcm_handle, hw_params, SND_PCM_FORMAT_S16_LE));
  967. //TRY( snd_pcm_hw_params_set_rate_near(pcm_handle, hw_params, &srate, NULL));
  968. //TRY( snd_pcm_hw_params_set_channels(pcm_handle, hw_params, ch_cnt));
  969. // get the range of possible buffer and period sizes
  970. TRY(snd_pcm_hw_params_get_buffer_size_min(hw_params,&bs_min));
  971. TRY(snd_pcm_hw_params_get_buffer_size_max(hw_params,&bs_max));
  972. TRY(snd_pcm_hw_params_get_period_size_min(hw_params,&ps_min,NULL));
  973. TRY(snd_pcm_hw_params_get_period_size_max(hw_params,&ps_max,NULL));
  974. //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);
  975. 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);
  976. snd_pcm_hw_params_free(hw_params);
  977. snd_pcm_close(pcm_handle);
  978. }
  979. #endif
  980. cmApRC_t cmApAlsaInitialize( cmRpt_t* rpt, unsigned baseApDevIdx )
  981. {
  982. cmApRC_t rc = kOkApRC;
  983. int err;
  984. int cardNum = -1;
  985. if((rc = cmApAlsaFinalize()) != kOkApRC )
  986. return rc;
  987. recdSetup();
  988. cmApRoot_t* p = &_cmApRoot;
  989. memset(p,0,sizeof(cmApRoot_t));
  990. p->rpt = rpt;
  991. p->asyncFl = false;
  992. // for each sound card
  993. while(1)
  994. {
  995. snd_ctl_t* cardH;
  996. char* cardNamePtr = NULL;
  997. char* cardLongNamePtr = NULL;
  998. int devNum = -1;
  999. int devStrN = 31;
  1000. char devStr[devStrN+1];
  1001. // get the next card handle
  1002. if((err = snd_card_next(&cardNum)) < 0 )
  1003. {
  1004. _cmApOsError(p,err,"Error getting sound card handle");
  1005. return kSysErrApRC;
  1006. }
  1007. // if no more card's to get
  1008. if( cardNum < 0 )
  1009. break;
  1010. // get the card short name
  1011. if(((err = snd_card_get_name(cardNum,&cardNamePtr)) < 0) || (cardNamePtr == NULL))
  1012. {
  1013. _cmApOsError(p,err,"Unable to get card name for card number %i\n",cardNum);
  1014. goto releaseCard;
  1015. }
  1016. // get the card long name
  1017. if((err = snd_card_get_longname(cardNum,&cardLongNamePtr)) < 0 || cardLongNamePtr == NULL )
  1018. {
  1019. _cmApOsError(p,err,"Unable to get long card name for card number %i\n",cardNum);
  1020. goto releaseCard;
  1021. }
  1022. // form the device name for this card
  1023. if(snprintf(devStr,devStrN,"hw:%i",cardNum) > devStrN )
  1024. {
  1025. _cmApOsError(p,0,"Device name is too long for buffer.");
  1026. goto releaseCard;
  1027. }
  1028. // open the card device driver
  1029. if((err = snd_ctl_open(&cardH, devStr, 0)) < 0 )
  1030. {
  1031. _cmApOsError(p,err,"Error opening sound card %i.",cardNum);
  1032. goto releaseCard;
  1033. }
  1034. // for each device on this card
  1035. while(1)
  1036. {
  1037. snd_pcm_info_t* info;
  1038. int subDevCnt = 1;
  1039. int i,j;
  1040. // get the next device on this card
  1041. if((err = snd_ctl_pcm_next_device(cardH,&devNum)) < 0 )
  1042. {
  1043. _cmApOsError(p,err,"Error gettign next device on card %i",cardNum);
  1044. break;
  1045. }
  1046. // if no more devices to get
  1047. if( devNum < 0 )
  1048. break;
  1049. // allocate a pcmInfo record
  1050. snd_pcm_info_alloca(&info);
  1051. memset(info, 0, snd_pcm_info_sizeof());
  1052. // set the device to query
  1053. snd_pcm_info_set_device(info, devNum );
  1054. for(i=0; i<subDevCnt; i++)
  1055. {
  1056. cmApDevRecd_t dr;
  1057. bool inputFl = false;
  1058. memset(&dr,0,sizeof(dr));
  1059. for(j=0; j<2; j++,inputFl=!inputFl)
  1060. {
  1061. snd_pcm_t* pcmH = NULL;
  1062. dr.devIdx = -1;
  1063. // set the subdevice and I/O direction to query
  1064. snd_pcm_info_set_subdevice(info,i);
  1065. snd_pcm_info_set_stream(info,inputFl ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK);
  1066. // if this device does not use this sub-device
  1067. if((err = snd_ctl_pcm_info(cardH,info)) < 0 )
  1068. continue;
  1069. // get the count of subdevices this device uses
  1070. if(i == 0 )
  1071. subDevCnt = snd_pcm_info_get_subdevices_count(info);
  1072. // if this device has no sub-devices
  1073. if(subDevCnt == 0 )
  1074. continue;
  1075. // form the device name and desc. string
  1076. if(strlen(dr.nameStr) == 0)
  1077. snprintf(dr.nameStr,NAME_CHAR_CNT,"hw:%i,%i,%i",cardNum,devNum,i);
  1078. if(strlen(dr.descStr) == 0)
  1079. {
  1080. snprintf(dr.descStr,DESC_CHAR_CNT,"%s %s",cardNamePtr,snd_pcm_info_get_name(info));
  1081. //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));
  1082. }
  1083. // attempt to open the sub-device
  1084. if((err = _cmApDevOpen(&pcmH,dr.nameStr,inputFl)) < 0 )
  1085. _cmApDevSetupError(p,err,inputFl,&dr,"Unable to open the PCM handle");
  1086. else
  1087. {
  1088. snd_pcm_hw_params_t* hwParams;
  1089. // allocate the parameter record
  1090. snd_pcm_hw_params_alloca(&hwParams);
  1091. memset( hwParams,0,snd_pcm_hw_params_sizeof());
  1092. // load the parameter record
  1093. if((err = snd_pcm_hw_params_any(pcmH,hwParams)) < 0 )
  1094. _cmApDevSetupError(p,err,inputFl,&dr,"Error obtaining hw param record");
  1095. else
  1096. {
  1097. unsigned* chCntPtr = inputFl ? &dr.iChCnt : &dr.oChCnt;
  1098. unsigned rate;
  1099. snd_pcm_hw_params_get_rate_max(hwParams,&rate,NULL);
  1100. // extract the channel count
  1101. if((err = snd_pcm_hw_params_get_channels_max(hwParams, chCntPtr )) < 0 )
  1102. _cmApDevSetupError(p,err,inputFl,&dr,"Error getting channel count.");
  1103. else
  1104. // this device uses this subdevice in the current direction
  1105. dr.flags += inputFl ? kInFl : kOutFl;
  1106. printf("%s in:%i chs:%i rate:%i\n",dr.nameStr,inputFl,*chCntPtr,rate);
  1107. }
  1108. // close the sub-device
  1109. snd_pcm_close(pcmH);
  1110. }
  1111. } // in/out loop
  1112. // insert the device in the device array
  1113. if( dr.flags != 0 )
  1114. _cmApDevAppend(p,&dr);
  1115. } // sub-dev loop
  1116. } // device loop
  1117. releaseCard:
  1118. snd_ctl_close(cardH);
  1119. } // card loop
  1120. if( rc == kOkApRC && p->asyncFl==false )
  1121. {
  1122. p->pollfdsCnt = 0;
  1123. p->pollfdsAllocCnt = 2*p->devCnt;
  1124. p->pollfds = cmMemAllocZ(struct pollfd, p->pollfdsAllocCnt );
  1125. p->pollfdsDesc = cmMemAllocZ(cmApPollfdsDesc_t, p->pollfdsAllocCnt );
  1126. if( cmThreadCreate(&p->thH,_cmApThreadFunc,p,rpt) != kOkThRC )
  1127. {
  1128. _cmApOsError(p,0,"Thread create failed.");
  1129. rc = kThreadFailApRC;
  1130. }
  1131. }
  1132. return rc;
  1133. }
  1134. cmApRC_t cmApAlsaFinalize()
  1135. {
  1136. cmApRoot_t* p = &_cmApRoot;
  1137. int i;
  1138. cmApRC_t rc = kOkApRC;
  1139. if( p->asyncFl==false && cmThreadIsValid(p->thH) )
  1140. if( cmThreadDestroy(&p->thH) != kOkThRC )
  1141. {
  1142. _cmApOsError(p,0,"Thread destroy failed.");
  1143. rc = kThreadFailApRC;
  1144. }
  1145. for(i=0; i<p->devCnt; ++i)
  1146. {
  1147. _cmApDevShutdown(p,p->devArray+i,true);
  1148. _cmApDevShutdown(p,p->devArray+i,false);
  1149. cmMemPtrFree(&p->devArray[i].iBuf);
  1150. cmMemPtrFree(&p->devArray[i].oBuf);
  1151. }
  1152. cmMemPtrFree(&p->pollfds);
  1153. cmMemPtrFree(&p->pollfdsDesc);
  1154. cmMemPtrFree(&p->devArray);
  1155. p->devAllocCnt = 0;
  1156. p->devCnt = 0;
  1157. recdFree();
  1158. //write_rec(2);
  1159. return rc;
  1160. }
  1161. cmApRC_t cmApAlsaDeviceCount()
  1162. { return _cmApRoot.devCnt; }
  1163. const char* cmApAlsaDeviceLabel( unsigned devIdx )
  1164. {
  1165. assert(devIdx < cmApAlsaDeviceCount());
  1166. return _cmApRoot.devArray[devIdx].descStr;
  1167. }
  1168. unsigned cmApAlsaDeviceChannelCount( unsigned devIdx, bool inputFl )
  1169. {
  1170. assert(devIdx < cmApAlsaDeviceCount());
  1171. return inputFl ? _cmApRoot.devArray[devIdx].iChCnt : _cmApRoot.devArray[devIdx].oChCnt;
  1172. }
  1173. double cmApAlsaDeviceSampleRate( unsigned devIdx )
  1174. {
  1175. assert(devIdx < cmApAlsaDeviceCount());
  1176. return (double)_cmApRoot.devArray[devIdx].srate;
  1177. }
  1178. unsigned cmApAlsaDeviceFramesPerCycle( unsigned devIdx, bool inputFl )
  1179. {
  1180. assert(devIdx < cmApAlsaDeviceCount());
  1181. return _cmApRoot.devArray[devIdx].framesPerCycle;
  1182. }
  1183. cmApRC_t cmApAlsaDeviceSetup(
  1184. unsigned devIdx,
  1185. double srate,
  1186. unsigned framesPerCycle,
  1187. cmApCallbackPtr_t callbackPtr,
  1188. void* userCbPtr )
  1189. {
  1190. assert( devIdx < cmApAlsaDeviceCount());
  1191. cmApRoot_t* p = &_cmApRoot;
  1192. cmApDevRecd_t* drp = _cmApRoot.devArray + devIdx;
  1193. unsigned periodsPerBuf = kDfltPeriodsPerBuf;
  1194. if( p->asyncFl == false )
  1195. if( cmThreadPause(p->thH,kWaitThFl | kPauseThFl) != kOkThRC )
  1196. {
  1197. _cmApOsError(p,0,"Audio thread pause failed.");
  1198. return kThreadFailApRC;
  1199. }
  1200. if( _cmApDevSetup(drp, srate, framesPerCycle, periodsPerBuf ) )
  1201. {
  1202. drp->srate = srate;
  1203. drp->framesPerCycle = framesPerCycle;
  1204. drp->periodsPerBuf = periodsPerBuf;
  1205. drp->cbPtr = callbackPtr;
  1206. drp->userCbPtr = userCbPtr;
  1207. return kOkApRC;
  1208. }
  1209. return kSysErrApRC;
  1210. }
  1211. cmApRC_t cmApAlsaDeviceStart( unsigned devIdx )
  1212. {
  1213. assert( devIdx < cmApAlsaDeviceCount());
  1214. int err;
  1215. cmApRoot_t* p = &_cmApRoot;
  1216. cmApDevRecd_t* drp = p->devArray + devIdx;
  1217. bool retFl = true;
  1218. bool inputFl = true;
  1219. unsigned i;
  1220. for(i=0; i<2; ++i,inputFl=!inputFl)
  1221. {
  1222. snd_pcm_t* pcmH = inputFl ? drp->iPcmH : drp->oPcmH;
  1223. if( pcmH != NULL )
  1224. {
  1225. snd_pcm_state_t state = snd_pcm_state(pcmH);
  1226. if( state != SND_PCM_STATE_RUNNING )
  1227. {
  1228. unsigned chCnt = inputFl ? drp->iChCnt : drp->oChCnt;
  1229. unsigned frmCnt = inputFl ? drp->iFpC : drp->oFpC;
  1230. const char* ioLabel = inputFl ? "Input" : "Output";
  1231. //printf("%i %s state:%s %i %i\n",drp->devIdx, ioLabel,_pcmStateToString(snd_pcm_state(pcmH)),chCnt,frmCnt);
  1232. // preparing may not always be necessary because the earlier call to snd_pcm_hw_params()
  1233. // may have left the device prepared - the redundant call however doesn't seem to hurt
  1234. if((err= snd_pcm_prepare(pcmH)) < 0 )
  1235. retFl = _cmApDevSetupError(p,err,inputFl,drp,"Error preparing the %i device.",ioLabel);
  1236. else
  1237. {
  1238. recdStart(drp,inputFl);
  1239. if( inputFl == false )
  1240. {
  1241. int j;
  1242. for(j=0; j<1; ++j)
  1243. if((err = _cmApWriteBuf( drp, pcmH, NULL, chCnt, frmCnt, drp->oBits, drp->oSigBits )) < 0 )
  1244. {
  1245. retFl = _cmApDevSetupError(p,err,inputFl,drp,"Write before start failed.");
  1246. break;
  1247. }
  1248. }
  1249. else
  1250. {
  1251. if((err = snd_pcm_start(pcmH)) < 0 )
  1252. retFl = _cmApDevSetupError(p,err,inputFl,drp,"'%s' start failed.",ioLabel);
  1253. }
  1254. // wait 500 microseconds between starting and stopping - this prevents
  1255. // input and output and other device callbacks from landing on top of
  1256. // each other - when this happens callbacks are dropped.
  1257. if( p->asyncFl )
  1258. usleep(500);
  1259. }
  1260. //printf("%i %s state:%s %i %i\n",drp->devIdx, ioLabel,_cmApPcmStateToString(snd_pcm_state(pcmH)),chCnt,frmCnt);
  1261. }
  1262. }
  1263. }
  1264. if( p->asyncFl == false )
  1265. if( cmThreadPause(p->thH,0) != kOkThRC )
  1266. {
  1267. _cmApOsError(p,0,"Audio thread start failed.");
  1268. retFl = false;
  1269. }
  1270. return retFl ? kOkApRC : kSysErrApRC;
  1271. }
  1272. cmApRC_t cmApAlsaDeviceStop( unsigned devIdx )
  1273. {
  1274. int err;
  1275. bool retFl = true;
  1276. cmApRoot_t* p = &_cmApRoot;
  1277. cmApDevRecd_t* drp = p->devArray + devIdx;
  1278. if( drp->iPcmH != NULL )
  1279. if((err = snd_pcm_drop(drp->iPcmH)) < 0 )
  1280. retFl = _cmApDevSetupError(p,err,true,drp,"Input stop failed.");
  1281. if( drp->oPcmH != NULL )
  1282. if((err = snd_pcm_drop(drp->oPcmH)) < 0 )
  1283. retFl = _cmApDevSetupError(p,err,false,drp,"Output stop failed.");
  1284. if( p->asyncFl == false )
  1285. if( cmThreadPause(p->thH,kPauseThFl) != kOkThRC )
  1286. {
  1287. _cmApOsError(p,0,"Audio thread pause failed.");
  1288. retFl = false;
  1289. }
  1290. return retFl ? kOkApRC : kSysErrApRC;
  1291. }
  1292. bool cmApAlsaDeviceIsStarted( unsigned devIdx )
  1293. {
  1294. assert( devIdx < cmApAlsaDeviceCount());
  1295. bool iFl = false;
  1296. bool oFl = false;
  1297. const cmApDevRecd_t* drp = _cmApRoot.devArray + devIdx;
  1298. if( drp->iPcmH != NULL )
  1299. iFl = snd_pcm_state(drp->iPcmH) == SND_PCM_STATE_RUNNING;
  1300. if( drp->oPcmH != NULL )
  1301. oFl = snd_pcm_state(drp->oPcmH) == SND_PCM_STATE_RUNNING;
  1302. return iFl || oFl;
  1303. }
  1304. //{ { label:alsaDevRpt }
  1305. //(
  1306. // Here's an example of generating a report of available
  1307. // ALSA devices.
  1308. //)
  1309. //[
  1310. void cmApAlsaDeviceReport( cmRpt_t* rpt )
  1311. {
  1312. unsigned i;
  1313. for(i=0; i<_cmApRoot.devCnt; i++)
  1314. {
  1315. cmRptPrintf(rpt,"%i : ",i);
  1316. _cmApDevReport(rpt,_cmApRoot.devArray + i );
  1317. }
  1318. }
  1319. //]
  1320. //}
  1321. void cmApAlsaDeviceRtReport( cmRpt_t* rpt, unsigned devIdx )
  1322. {
  1323. _cmApDevRtReport(rpt, _cmApRoot.devArray + devIdx );
  1324. }