libcm is a C development framework with an emphasis on audio signal processing applications.
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

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. }