devaudio.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  1. #include "dat.h"
  2. #include "fns.h"
  3. #include "error.h"
  4. #include "audio.h"
  5. Dirtab audiotab[] =
  6. {
  7. ".", {Qdir, 0, QTDIR}, 0, 0555,
  8. "audio", {Qaudio}, 0, 0666,
  9. "audioctl", {Qaudioctl}, 0, 0666,
  10. };
  11. static void
  12. audioinit(void)
  13. {
  14. audio_file_init();
  15. }
  16. static Chan*
  17. audioattach(char *spec)
  18. {
  19. return devattach('A', spec);
  20. }
  21. static Walkqid*
  22. audiowalk(Chan *c, Chan *nc, char **name, int nname)
  23. {
  24. return devwalk(c, nc, name, nname, audiotab, nelem(audiotab), devgen);
  25. }
  26. static int
  27. audiostat(Chan *c, uchar *db, int n)
  28. {
  29. return devstat(c, db, n, audiotab, nelem(audiotab), devgen);
  30. }
  31. static Chan*
  32. audioopen(Chan *c, int omode)
  33. {
  34. c = devopen(c, omode, audiotab, nelem(audiotab), devgen);
  35. if(waserror()){
  36. c->flag &= ~COPEN;
  37. nexterror();
  38. }
  39. switch(c->qid.path) {
  40. case Qdir:
  41. case Qaudioctl:
  42. break;
  43. case Qaudio:
  44. audio_file_open(c, c->mode);
  45. break;
  46. default:
  47. error(Egreg);
  48. }
  49. poperror();
  50. return c;
  51. }
  52. static void
  53. audioclose(Chan *c)
  54. {
  55. if((c->flag & COPEN) == 0)
  56. return;
  57. switch(c->qid.path) {
  58. case Qdir:
  59. case Qaudioctl:
  60. break;
  61. case Qaudio:
  62. audio_file_close(c);
  63. break;
  64. default:
  65. error(Egreg);
  66. }
  67. }
  68. static int ctlsummary(char*, int, Audio_t*);
  69. static long
  70. audioread(Chan *c, void *va, long count, vlong offset)
  71. {
  72. char *buf;
  73. int n;
  74. if(c->qid.type & QTDIR)
  75. return devdirread(c, va, count, audiotab, nelem(audiotab), devgen);
  76. switch(c->qid.path) {
  77. case Qaudio:
  78. return audio_file_read(c, va, count, offset);
  79. case Qaudioctl:
  80. buf = smalloc(READSTR);
  81. if(waserror()){
  82. free(buf);
  83. nexterror();
  84. }
  85. n = ctlsummary(buf, READSTR, getaudiodev());
  86. count = readstr(offset, va, n, buf);
  87. poperror();
  88. free(buf);
  89. return count;
  90. }
  91. return 0;
  92. }
  93. static long
  94. audiowrite(Chan *c, void *va, long count, vlong offset)
  95. {
  96. switch(c->qid.path) {
  97. case Qaudio:
  98. return audio_file_write(c, va, count, offset);
  99. case Qaudioctl:
  100. return audio_ctl_write(c, va, count, offset);
  101. }
  102. return 0;
  103. }
  104. static int sval(char*, unsigned long*, ulong, ulong);
  105. static int str2val(svp_t*, char*, ulong*);
  106. static char* val2str(svp_t*, ulong);
  107. int
  108. audioparse(char* args, int len, Audio_t *t)
  109. {
  110. int i, n;
  111. ulong v;
  112. Cmdbuf *cb;
  113. ulong tf;
  114. Audio_t info = *t;
  115. cb = parsecmd(args, len);
  116. if(waserror()){
  117. free(cb);
  118. return 0;
  119. }
  120. tf = 0;
  121. n = cb->nf;
  122. for(i = 0; i < cb->nf-1; i++) {
  123. if(strcmp(cb->f[i], "in") == 0){
  124. tf |= AUDIO_IN_FLAG;
  125. continue;
  126. }
  127. if(strcmp(cb->f[i], "out") == 0) {
  128. tf |= AUDIO_OUT_FLAG;
  129. continue;
  130. }
  131. if(tf == 0)
  132. tf = AUDIO_IN_FLAG | AUDIO_OUT_FLAG;
  133. if(strcmp(cb->f[i], "bits") == 0) {
  134. if(!str2val(audio_bits_tbl, cb->f[i+1], &v))
  135. break;
  136. i++;
  137. if(tf & AUDIO_IN_FLAG) {
  138. info.in.flags |= AUDIO_BITS_FLAG | AUDIO_MOD_FLAG;
  139. info.in.bits = v;
  140. }
  141. if(tf & AUDIO_OUT_FLAG) {
  142. info.out.flags |= AUDIO_BITS_FLAG | AUDIO_MOD_FLAG;
  143. info.out.bits = v;
  144. }
  145. } else if(strcmp(cb->f[i], "buf") == 0) {
  146. if(!sval(cb->f[i+1], &v, Audio_Max_Val, Audio_Min_Val))
  147. break;
  148. i++;
  149. if(tf & AUDIO_IN_FLAG) {
  150. info.in.flags |= AUDIO_BUF_FLAG | AUDIO_MOD_FLAG;
  151. info.in.buf = v;
  152. }
  153. if(tf & AUDIO_OUT_FLAG) {
  154. info.out.flags |= AUDIO_BUF_FLAG | AUDIO_MOD_FLAG;
  155. info.out.buf = v;
  156. }
  157. } else if(strcmp(cb->f[i], "chans") == 0) {
  158. if(!str2val(audio_chan_tbl, cb->f[i+1], &v))
  159. break;
  160. i++;
  161. if(tf & AUDIO_IN_FLAG) {
  162. info.in.flags |= AUDIO_CHAN_FLAG | AUDIO_MOD_FLAG;
  163. info.in.chan = v;
  164. }
  165. if(tf & AUDIO_OUT_FLAG) {
  166. info.out.flags |= AUDIO_CHAN_FLAG | AUDIO_MOD_FLAG;
  167. info.out.chan = v;
  168. }
  169. } else if(strcmp(cb->f[i], "indev") == 0) {
  170. if(!str2val(audio_indev_tbl, cb->f[i+1], &v))
  171. break;
  172. i++;
  173. info.in.flags |= AUDIO_DEV_FLAG | AUDIO_MOD_FLAG;
  174. info.in.dev = v;
  175. } else if(strcmp(cb->f[i], "outdev") == 0) {
  176. if(!str2val(audio_outdev_tbl, cb->f[i+1], &v))
  177. break;
  178. i++;
  179. info.out.flags |= AUDIO_DEV_FLAG | AUDIO_MOD_FLAG;
  180. info.out.dev = v;
  181. } else if(strcmp(cb->f[i], "enc") == 0) {
  182. if(!str2val(audio_enc_tbl, cb->f[i+1], &v))
  183. break;
  184. i++;
  185. if(tf & AUDIO_IN_FLAG) {
  186. info.in.flags |= AUDIO_ENC_FLAG | AUDIO_MOD_FLAG;
  187. info.in.enc = v;
  188. }
  189. if(tf & AUDIO_OUT_FLAG) {
  190. info.out.flags |= AUDIO_ENC_FLAG | AUDIO_MOD_FLAG;
  191. info.out.enc = v;
  192. }
  193. } else if(strcmp(cb->f[i], "rate") == 0) {
  194. if(!str2val(audio_rate_tbl, cb->f[i+1], &v))
  195. break;
  196. i++;
  197. if(tf & AUDIO_IN_FLAG) {
  198. info.in.flags |= AUDIO_RATE_FLAG | AUDIO_MOD_FLAG;
  199. info.in.rate = v;
  200. }
  201. if(tf & AUDIO_OUT_FLAG) {
  202. info.out.flags |= AUDIO_RATE_FLAG | AUDIO_MOD_FLAG;
  203. info.out.rate = v;
  204. }
  205. } else if(strcmp(cb->f[i], "vol") == 0) {
  206. if(!sval(cb->f[i+1], &v, Audio_Max_Val, Audio_Min_Val))
  207. break;
  208. i++;
  209. if(tf & AUDIO_IN_FLAG) {
  210. info.in.flags |= AUDIO_VOL_FLAG | AUDIO_MOD_FLAG;
  211. info.in.left = v;
  212. info.in.right = v;
  213. }
  214. if(tf & AUDIO_OUT_FLAG) {
  215. info.out.flags |= AUDIO_VOL_FLAG | AUDIO_MOD_FLAG;
  216. info.out.left = v;
  217. info.out.right = v;
  218. }
  219. } else if(strcmp(cb->f[i], "left") == 0) {
  220. if(!sval(cb->f[i+1], &v, Audio_Max_Val, Audio_Min_Val))
  221. break;
  222. i++;
  223. if(tf & AUDIO_IN_FLAG) {
  224. info.in.flags |= AUDIO_LEFT_FLAG | AUDIO_MOD_FLAG;
  225. info.in.left = v;
  226. }
  227. if(tf & AUDIO_OUT_FLAG) {
  228. info.out.flags |= AUDIO_LEFT_FLAG | AUDIO_MOD_FLAG;
  229. info.out.left = v;
  230. }
  231. } else if(strcmp(cb->f[i], "right") == 0) {
  232. if(!sval(cb->f[i+1], &v, Audio_Max_Val, Audio_Min_Val))
  233. break;
  234. i++;
  235. if(tf & AUDIO_IN_FLAG) {
  236. info.in.flags |= AUDIO_RIGHT_FLAG | AUDIO_MOD_FLAG;
  237. info.in.right = v;
  238. }
  239. if(tf & AUDIO_OUT_FLAG) {
  240. info.out.flags |= AUDIO_RIGHT_FLAG | AUDIO_MOD_FLAG;
  241. info.out.right = v;
  242. }
  243. }else
  244. break;
  245. }
  246. poperror();
  247. free(cb);
  248. if(i < n)
  249. return 0;
  250. *t = info; /* set information back */
  251. return 1;
  252. }
  253. static char*
  254. audioparam(char* p, char* e, char* name, int val, svp_t* tbl)
  255. {
  256. char *s;
  257. svp_t *sv;
  258. if((s = val2str(tbl, val)) != nil){
  259. p = seprint(p, e, "%s %s", name, s); /* current setting */
  260. for(sv = tbl; sv->s != nil; sv++)
  261. if(sv->v != val)
  262. p = seprint(p, e, " %s", sv->s); /* other possible values */
  263. p = seprint(p, e, "\n");
  264. }else
  265. p = seprint(p, e, "%s unknown\n", name);
  266. return p;
  267. }
  268. static char*
  269. audioioparam(char* p, char* e, char* name, int ival, int oval, svp_t* tbl)
  270. {
  271. if(ival == oval)
  272. return audioparam(p, e, name, ival, tbl);
  273. p = audioparam(seprint(p, e, "in "), e, name, ival, tbl);
  274. p = audioparam(seprint(p, e, "out "), e, name, oval, tbl);
  275. return p;
  276. }
  277. static int
  278. ctlsummary(char *buf, int bsize, Audio_t *adev)
  279. {
  280. Audio_d *in, *out;
  281. char *p, *e;
  282. in = &adev->in;
  283. out = &adev->out;
  284. p = buf;
  285. e = p + bsize;
  286. p = audioparam(p, e, "indev", in->dev, audio_indev_tbl);
  287. p = audioparam(p, e, "outdev", out->dev, audio_outdev_tbl);
  288. p = audioioparam(p, e, "enc", in->enc, out->enc, audio_enc_tbl);
  289. p = audioioparam(p, e, "rate", in->rate, out->rate, audio_rate_tbl);
  290. p = audioioparam(p, e, "bits", in->bits, out->bits, audio_bits_tbl); /* this one is silly */
  291. p = audioioparam(p, e, "chans", in->chan, out->chan, audio_chan_tbl);
  292. /* TO DO: minimise in/out left/right where possible */
  293. if(in->left != in->right){
  294. p = seprint(p, e, "in left %d 0 100\n", in->left);
  295. p = seprint(p, e, "in right %d 0 100\n", in->right);
  296. }else
  297. p = seprint(p, e, "in %d 0 100\n", in->right);
  298. if(out->left != out->right){
  299. p = seprint(p, e, "out left %d 0 100\n", out->left);
  300. p = seprint(p, e, "out right %d 0 100\n", out->right);
  301. }else
  302. p = seprint(p, e, "out %d 0 100\n", out->right);
  303. p = seprint(p, e, "in buf %d %d %d\n", in->buf, Audio_Min_Val, Audio_Max_Val);
  304. p = seprint(p, e, "out buf %d %d %d\n", out->buf, Audio_Min_Val, Audio_Max_Val);
  305. return p-buf;
  306. }
  307. void
  308. audio_info_init(Audio_t *t)
  309. {
  310. t->in = Default_Audio_Format;
  311. t->in.dev = Default_Audio_Input;
  312. t->out = Default_Audio_Format;
  313. t->out.dev = Default_Audio_Output;
  314. }
  315. static int
  316. str2val(svp_t* t, char* s, ulong *v)
  317. {
  318. if(t == nil || s == nil)
  319. return 0;
  320. for(; t->s != nil; t++) {
  321. if(strncmp(t->s, s, strlen(t->s)) == 0) {
  322. *v = t->v;
  323. return 1;
  324. }
  325. }
  326. return 0;
  327. }
  328. static char*
  329. val2str(svp_t* t, ulong v)
  330. {
  331. if(t == nil)
  332. return nil;
  333. for(; t->s != nil; t++)
  334. if(t->v == v)
  335. return t->s;
  336. return nil;
  337. }
  338. static int
  339. sval(char* buf, ulong* v, ulong max, ulong min)
  340. {
  341. unsigned long val = strtoul(buf, 0, 10);
  342. if(val > max || val < min)
  343. return 0;
  344. *v = val;
  345. return 1;
  346. }
  347. Dev audiodevtab = {
  348. 'A',
  349. "audio",
  350. audioinit,
  351. audioattach,
  352. audiowalk,
  353. audiostat,
  354. audioopen,
  355. devcreate,
  356. audioclose,
  357. audioread,
  358. devbread,
  359. audiowrite,
  360. devbwrite,
  361. devremove,
  362. devwstat
  363. };