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 48KB

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