devaudio.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. #include "u.h"
  2. #include "lib.h"
  3. #include "dat.h"
  4. #include "fns.h"
  5. #include "error.h"
  6. #include "devaudio.h"
  7. enum
  8. {
  9. Qdir = 0,
  10. Qaudio,
  11. Qvolume,
  12. Aclosed = 0,
  13. Aread,
  14. Awrite,
  15. Speed = 44100,
  16. Ncmd = 50, /* max volume command words */
  17. };
  18. Dirtab
  19. audiodir[] =
  20. {
  21. ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
  22. "audio", {Qaudio}, 0, 0666,
  23. "volume", {Qvolume}, 0, 0666,
  24. };
  25. static struct
  26. {
  27. QLock lk;
  28. Rendez vous;
  29. int amode; /* Aclosed/Aread/Awrite for /audio */
  30. } audio;
  31. #define aqlock(a) qlock(&(a)->lk)
  32. #define aqunlock(a) qunlock(&(a)->lk)
  33. static struct
  34. {
  35. char* name;
  36. int flag;
  37. int ilval; /* initial values */
  38. int irval;
  39. } volumes[] =
  40. {
  41. "audio", Fout, 50, 50,
  42. "synth", Fin|Fout, 0, 0,
  43. "cd", Fin|Fout, 0, 0,
  44. "line", Fin|Fout, 0, 0,
  45. "mic", Fin|Fout|Fmono, 0, 0,
  46. "speaker", Fout|Fmono, 0, 0,
  47. "treb", Fout, 50, 50,
  48. "bass", Fout, 50, 50,
  49. "speed", Fin|Fout|Fmono, Speed, Speed,
  50. 0
  51. };
  52. static char Emode[] = "illegal open mode";
  53. static char Evolume[] = "illegal volume specifier";
  54. static void
  55. resetlevel(void)
  56. {
  57. int i;
  58. for(i=0; volumes[i].name; i++)
  59. audiodevsetvol(i, volumes[i].ilval, volumes[i].irval);
  60. }
  61. static void
  62. audioinit(void)
  63. {
  64. }
  65. static Chan*
  66. audioattach(char *param)
  67. {
  68. return devattach('A', param);
  69. }
  70. static Walkqid*
  71. audiowalk(Chan *c, Chan *nc, char **name, int nname)
  72. {
  73. return devwalk(c, nc, name, nname, audiodir, nelem(audiodir), devgen);
  74. }
  75. static int
  76. audiostat(Chan *c, uchar *db, int n)
  77. {
  78. return devstat(c, db, n, audiodir, nelem(audiodir), devgen);
  79. }
  80. static Chan*
  81. audioopen(Chan *c, int omode)
  82. {
  83. int amode;
  84. switch((ulong)c->qid.path) {
  85. default:
  86. error(Eperm);
  87. break;
  88. case Qvolume:
  89. case Qdir:
  90. break;
  91. case Qaudio:
  92. amode = Awrite;
  93. if((omode&7) == OREAD)
  94. amode = Aread;
  95. aqlock(&audio);
  96. if(waserror()){
  97. aqunlock(&audio);
  98. nexterror();
  99. }
  100. if(audio.amode != Aclosed)
  101. error(Einuse);
  102. audiodevopen();
  103. audio.amode = amode;
  104. poperror();
  105. aqunlock(&audio);
  106. break;
  107. }
  108. c = devopen(c, omode, audiodir, nelem(audiodir), devgen);
  109. c->mode = openmode(omode);
  110. c->flag |= COPEN;
  111. c->offset = 0;
  112. return c;
  113. }
  114. static void
  115. audioclose(Chan *c)
  116. {
  117. switch((ulong)c->qid.path) {
  118. default:
  119. error(Eperm);
  120. break;
  121. case Qdir:
  122. case Qvolume:
  123. break;
  124. case Qaudio:
  125. if(c->flag & COPEN) {
  126. aqlock(&audio);
  127. audiodevclose();
  128. audio.amode = Aclosed;
  129. aqunlock(&audio);
  130. }
  131. break;
  132. }
  133. }
  134. static long
  135. audioread(Chan *c, void *v, long n, vlong off)
  136. {
  137. int liv, riv, lov, rov;
  138. long m;
  139. char buf[300];
  140. int j;
  141. ulong offset = off;
  142. char *a;
  143. a = v;
  144. switch((ulong)c->qid.path) {
  145. default:
  146. error(Eperm);
  147. break;
  148. case Qdir:
  149. return devdirread(c, a, n, audiodir, nelem(audiodir), devgen);
  150. case Qaudio:
  151. if(audio.amode != Aread)
  152. error(Emode);
  153. aqlock(&audio);
  154. if(waserror()){
  155. aqunlock(&audio);
  156. nexterror();
  157. }
  158. n = audiodevread(v, n);
  159. poperror();
  160. aqunlock(&audio);
  161. break;
  162. case Qvolume:
  163. j = 0;
  164. buf[0] = 0;
  165. for(m=0; volumes[m].name; m++){
  166. audiodevgetvol(m, &lov, &rov);
  167. liv = lov;
  168. riv = rov;
  169. j += snprint(buf+j, sizeof(buf)-j, "%s", volumes[m].name);
  170. if((volumes[m].flag & Fmono) || (liv==riv && lov==rov)){
  171. if((volumes[m].flag&(Fin|Fout))==(Fin|Fout) && liv==lov)
  172. j += snprint(buf+j, sizeof(buf)-j, " %d", liv);
  173. else{
  174. if(volumes[m].flag & Fin)
  175. j += snprint(buf+j, sizeof(buf)-j,
  176. " in %d", liv);
  177. if(volumes[m].flag & Fout)
  178. j += snprint(buf+j, sizeof(buf)-j,
  179. " out %d", lov);
  180. }
  181. }else{
  182. if((volumes[m].flag&(Fin|Fout))==(Fin|Fout) &&
  183. liv==lov && riv==rov)
  184. j += snprint(buf+j, sizeof(buf)-j,
  185. " left %d right %d",
  186. liv, riv);
  187. else{
  188. if(volumes[m].flag & Fin)
  189. j += snprint(buf+j, sizeof(buf)-j,
  190. " in left %d right %d",
  191. liv, riv);
  192. if(volumes[m].flag & Fout)
  193. j += snprint(buf+j, sizeof(buf)-j,
  194. " out left %d right %d",
  195. lov, rov);
  196. }
  197. }
  198. j += snprint(buf+j, sizeof(buf)-j, "\n");
  199. }
  200. return readstr(offset, a, n, buf);
  201. }
  202. return n;
  203. }
  204. static long
  205. audiowrite(Chan *c, void *vp, long n, vlong off)
  206. {
  207. long m;
  208. int i, v, left, right, in, out;
  209. Cmdbuf *cb;
  210. char *a;
  211. USED(off);
  212. a = vp;
  213. switch((ulong)c->qid.path) {
  214. default:
  215. error(Eperm);
  216. break;
  217. case Qvolume:
  218. v = Vaudio;
  219. left = 1;
  220. right = 1;
  221. in = 1;
  222. out = 1;
  223. cb = parsecmd(vp, n);
  224. if(waserror()){
  225. free(cb);
  226. nexterror();
  227. }
  228. for(i = 0; i < cb->nf; i++){
  229. /*
  230. * a number is volume
  231. */
  232. if(cb->f[i][0] >= '0' && cb->f[i][0] <= '9') {
  233. m = strtoul(cb->f[i], 0, 10);
  234. if(!out)
  235. goto cont0;
  236. if(left && right)
  237. audiodevsetvol(v, m, m);
  238. else if(left)
  239. audiodevsetvol(v, m, -1);
  240. else if(right)
  241. audiodevsetvol(v, -1, m);
  242. goto cont0;
  243. }
  244. for(m=0; volumes[m].name; m++) {
  245. if(strcmp(cb->f[i], volumes[m].name) == 0) {
  246. v = m;
  247. in = 1;
  248. out = 1;
  249. left = 1;
  250. right = 1;
  251. goto cont0;
  252. }
  253. }
  254. if(strcmp(cb->f[i], "reset") == 0) {
  255. resetlevel();
  256. goto cont0;
  257. }
  258. if(strcmp(cb->f[i], "in") == 0) {
  259. in = 1;
  260. out = 0;
  261. goto cont0;
  262. }
  263. if(strcmp(cb->f[i], "out") == 0) {
  264. in = 0;
  265. out = 1;
  266. goto cont0;
  267. }
  268. if(strcmp(cb->f[i], "left") == 0) {
  269. left = 1;
  270. right = 0;
  271. goto cont0;
  272. }
  273. if(strcmp(cb->f[i], "right") == 0) {
  274. left = 0;
  275. right = 1;
  276. goto cont0;
  277. }
  278. error(Evolume);
  279. break;
  280. cont0:;
  281. }
  282. free(cb);
  283. poperror();
  284. break;
  285. case Qaudio:
  286. if(audio.amode != Awrite)
  287. error(Emode);
  288. aqlock(&audio);
  289. if(waserror()){
  290. aqunlock(&audio);
  291. nexterror();
  292. }
  293. n = audiodevwrite(vp, n);
  294. poperror();
  295. aqunlock(&audio);
  296. break;
  297. }
  298. return n;
  299. }
  300. void
  301. audioswab(uchar *a, uint n)
  302. {
  303. ulong *p, *ep, b;
  304. p = (ulong*)a;
  305. ep = p + (n>>2);
  306. while(p < ep) {
  307. b = *p;
  308. b = (b>>24) | (b<<24) |
  309. ((b&0xff0000) >> 8) |
  310. ((b&0x00ff00) << 8);
  311. *p++ = b;
  312. }
  313. }
  314. Dev audiodevtab = {
  315. 'A',
  316. "audio",
  317. devreset,
  318. audioinit,
  319. devshutdown,
  320. audioattach,
  321. audiowalk,
  322. audiostat,
  323. audioopen,
  324. devcreate,
  325. audioclose,
  326. audioread,
  327. devbread,
  328. audiowrite,
  329. devbwrite,
  330. devremove,
  331. devwstat,
  332. };