|
|
1.1 root 1: /*
2: * QEMU ESD audio driver
3: *
4: * Copyright (c) 2006 Frederick Reeve (brushed up by malc)
5: *
6: * Permission is hereby granted, free of charge, to any person obtaining a copy
7: * of this software and associated documentation files (the "Software"), to deal
8: * in the Software without restriction, including without limitation the rights
9: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10: * copies of the Software, and to permit persons to whom the Software is
11: * furnished to do so, subject to the following conditions:
12: *
13: * The above copyright notice and this permission notice shall be included in
14: * all copies or substantial portions of the Software.
15: *
16: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22: * THE SOFTWARE.
23: */
24: #include <esd.h>
25: #include "qemu-common.h"
26: #include "audio.h"
27:
28: #define AUDIO_CAP "esd"
29: #include "audio_int.h"
30: #include "audio_pt_int.h"
31:
32: typedef struct {
33: HWVoiceOut hw;
34: int done;
35: int live;
36: int decr;
37: int rpos;
38: void *pcm_buf;
39: int fd;
40: struct audio_pt pt;
41: } ESDVoiceOut;
42:
43: typedef struct {
44: HWVoiceIn hw;
45: int done;
46: int dead;
47: int incr;
48: int wpos;
49: void *pcm_buf;
50: int fd;
51: struct audio_pt pt;
52: } ESDVoiceIn;
53:
54: static struct {
55: int samples;
56: int divisor;
57: char *dac_host;
58: char *adc_host;
59: } conf = {
1.1.1.2 root 60: .samples = 1024,
61: .divisor = 2,
1.1 root 62: };
63:
64: static void GCC_FMT_ATTR (2, 3) qesd_logerr (int err, const char *fmt, ...)
65: {
66: va_list ap;
67:
68: va_start (ap, fmt);
69: AUD_vlog (AUDIO_CAP, fmt, ap);
70: va_end (ap);
71:
72: AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err));
73: }
74:
75: /* playback */
76: static void *qesd_thread_out (void *arg)
77: {
78: ESDVoiceOut *esd = arg;
79: HWVoiceOut *hw = &esd->hw;
80: int threshold;
81:
82: threshold = conf.divisor ? hw->samples / conf.divisor : 0;
83:
84: if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
85: return NULL;
86: }
87:
88: for (;;) {
89: int decr, to_mix, rpos;
90:
91: for (;;) {
92: if (esd->done) {
93: goto exit;
94: }
95:
96: if (esd->live > threshold) {
97: break;
98: }
99:
100: if (audio_pt_wait (&esd->pt, AUDIO_FUNC)) {
101: goto exit;
102: }
103: }
104:
105: decr = to_mix = esd->live;
106: rpos = hw->rpos;
107:
108: if (audio_pt_unlock (&esd->pt, AUDIO_FUNC)) {
109: return NULL;
110: }
111:
112: while (to_mix) {
113: ssize_t written;
114: int chunk = audio_MIN (to_mix, hw->samples - rpos);
115: struct st_sample *src = hw->mix_buf + rpos;
116:
117: hw->clip (esd->pcm_buf, src, chunk);
118:
119: again:
120: written = write (esd->fd, esd->pcm_buf, chunk << hw->info.shift);
121: if (written == -1) {
122: if (errno == EINTR || errno == EAGAIN) {
123: goto again;
124: }
125: qesd_logerr (errno, "write failed\n");
126: return NULL;
127: }
128:
129: if (written != chunk << hw->info.shift) {
130: int wsamples = written >> hw->info.shift;
131: int wbytes = wsamples << hw->info.shift;
132: if (wbytes != written) {
1.1.1.2 root 133: dolog ("warning: Misaligned write %d (requested %zd), "
1.1 root 134: "alignment %d\n",
135: wbytes, written, hw->info.align + 1);
136: }
137: to_mix -= wsamples;
138: rpos = (rpos + wsamples) % hw->samples;
139: break;
140: }
141:
142: rpos = (rpos + chunk) % hw->samples;
143: to_mix -= chunk;
144: }
145:
146: if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
147: return NULL;
148: }
149:
150: esd->rpos = rpos;
151: esd->live -= decr;
152: esd->decr += decr;
153: }
154:
155: exit:
156: audio_pt_unlock (&esd->pt, AUDIO_FUNC);
157: return NULL;
158: }
159:
1.1.1.2 root 160: static int qesd_run_out (HWVoiceOut *hw, int live)
1.1 root 161: {
1.1.1.2 root 162: int decr;
1.1 root 163: ESDVoiceOut *esd = (ESDVoiceOut *) hw;
164:
165: if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
166: return 0;
167: }
168:
169: decr = audio_MIN (live, esd->decr);
170: esd->decr -= decr;
171: esd->live = live - decr;
172: hw->rpos = esd->rpos;
173: if (esd->live > 0) {
174: audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
175: }
176: else {
177: audio_pt_unlock (&esd->pt, AUDIO_FUNC);
178: }
179: return decr;
180: }
181:
182: static int qesd_write (SWVoiceOut *sw, void *buf, int len)
183: {
184: return audio_pcm_sw_write (sw, buf, len);
185: }
186:
187: static int qesd_init_out (HWVoiceOut *hw, struct audsettings *as)
188: {
189: ESDVoiceOut *esd = (ESDVoiceOut *) hw;
190: struct audsettings obt_as = *as;
191: int esdfmt = ESD_STREAM | ESD_PLAY;
192:
193: esdfmt |= (as->nchannels == 2) ? ESD_STEREO : ESD_MONO;
194: switch (as->fmt) {
195: case AUD_FMT_S8:
196: case AUD_FMT_U8:
197: esdfmt |= ESD_BITS8;
198: obt_as.fmt = AUD_FMT_U8;
199: break;
200:
201: case AUD_FMT_S32:
202: case AUD_FMT_U32:
203: dolog ("Will use 16 instead of 32 bit samples\n");
204:
205: case AUD_FMT_S16:
206: case AUD_FMT_U16:
207: deffmt:
208: esdfmt |= ESD_BITS16;
209: obt_as.fmt = AUD_FMT_S16;
210: break;
211:
212: default:
213: dolog ("Internal logic error: Bad audio format %d\n", as->fmt);
214: goto deffmt;
215:
216: }
217: obt_as.endianness = AUDIO_HOST_ENDIANNESS;
218:
219: audio_pcm_init_info (&hw->info, &obt_as);
220:
221: hw->samples = conf.samples;
222: esd->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
223: if (!esd->pcm_buf) {
224: dolog ("Could not allocate buffer (%d bytes)\n",
225: hw->samples << hw->info.shift);
226: return -1;
227: }
228:
229: esd->fd = esd_play_stream (esdfmt, as->freq, conf.dac_host, NULL);
230: if (esd->fd < 0) {
231: qesd_logerr (errno, "esd_play_stream failed\n");
1.1.1.3 root 232: goto fail1;
1.1 root 233: }
234:
235: if (audio_pt_init (&esd->pt, qesd_thread_out, esd, AUDIO_CAP, AUDIO_FUNC)) {
1.1.1.3 root 236: goto fail2;
1.1 root 237: }
238:
239: return 0;
240:
1.1.1.3 root 241: fail2:
1.1 root 242: if (close (esd->fd)) {
243: qesd_logerr (errno, "%s: close on esd socket(%d) failed\n",
244: AUDIO_FUNC, esd->fd);
245: }
246: esd->fd = -1;
247:
248: fail1:
1.1.1.4 ! root 249: g_free (esd->pcm_buf);
1.1 root 250: esd->pcm_buf = NULL;
251: return -1;
252: }
253:
254: static void qesd_fini_out (HWVoiceOut *hw)
255: {
256: void *ret;
257: ESDVoiceOut *esd = (ESDVoiceOut *) hw;
258:
259: audio_pt_lock (&esd->pt, AUDIO_FUNC);
260: esd->done = 1;
261: audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
262: audio_pt_join (&esd->pt, &ret, AUDIO_FUNC);
263:
264: if (esd->fd >= 0) {
265: if (close (esd->fd)) {
266: qesd_logerr (errno, "failed to close esd socket\n");
267: }
268: esd->fd = -1;
269: }
270:
271: audio_pt_fini (&esd->pt, AUDIO_FUNC);
272:
1.1.1.4 ! root 273: g_free (esd->pcm_buf);
1.1 root 274: esd->pcm_buf = NULL;
275: }
276:
277: static int qesd_ctl_out (HWVoiceOut *hw, int cmd, ...)
278: {
279: (void) hw;
280: (void) cmd;
281: return 0;
282: }
283:
284: /* capture */
285: static void *qesd_thread_in (void *arg)
286: {
287: ESDVoiceIn *esd = arg;
288: HWVoiceIn *hw = &esd->hw;
289: int threshold;
290:
291: threshold = conf.divisor ? hw->samples / conf.divisor : 0;
292:
293: if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
294: return NULL;
295: }
296:
297: for (;;) {
298: int incr, to_grab, wpos;
299:
300: for (;;) {
301: if (esd->done) {
302: goto exit;
303: }
304:
305: if (esd->dead > threshold) {
306: break;
307: }
308:
309: if (audio_pt_wait (&esd->pt, AUDIO_FUNC)) {
310: goto exit;
311: }
312: }
313:
314: incr = to_grab = esd->dead;
315: wpos = hw->wpos;
316:
317: if (audio_pt_unlock (&esd->pt, AUDIO_FUNC)) {
318: return NULL;
319: }
320:
321: while (to_grab) {
322: ssize_t nread;
323: int chunk = audio_MIN (to_grab, hw->samples - wpos);
324: void *buf = advance (esd->pcm_buf, wpos);
325:
326: again:
327: nread = read (esd->fd, buf, chunk << hw->info.shift);
328: if (nread == -1) {
329: if (errno == EINTR || errno == EAGAIN) {
330: goto again;
331: }
332: qesd_logerr (errno, "read failed\n");
333: return NULL;
334: }
335:
336: if (nread != chunk << hw->info.shift) {
337: int rsamples = nread >> hw->info.shift;
338: int rbytes = rsamples << hw->info.shift;
339: if (rbytes != nread) {
1.1.1.2 root 340: dolog ("warning: Misaligned write %d (requested %zd), "
1.1 root 341: "alignment %d\n",
342: rbytes, nread, hw->info.align + 1);
343: }
344: to_grab -= rsamples;
345: wpos = (wpos + rsamples) % hw->samples;
346: break;
347: }
348:
1.1.1.3 root 349: hw->conv (hw->conv_buf + wpos, buf, nread >> hw->info.shift);
1.1 root 350: wpos = (wpos + chunk) % hw->samples;
351: to_grab -= chunk;
352: }
353:
354: if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
355: return NULL;
356: }
357:
358: esd->wpos = wpos;
359: esd->dead -= incr;
360: esd->incr += incr;
361: }
362:
363: exit:
364: audio_pt_unlock (&esd->pt, AUDIO_FUNC);
365: return NULL;
366: }
367:
368: static int qesd_run_in (HWVoiceIn *hw)
369: {
370: int live, incr, dead;
371: ESDVoiceIn *esd = (ESDVoiceIn *) hw;
372:
373: if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
374: return 0;
375: }
376:
377: live = audio_pcm_hw_get_live_in (hw);
378: dead = hw->samples - live;
379: incr = audio_MIN (dead, esd->incr);
380: esd->incr -= incr;
381: esd->dead = dead - incr;
382: hw->wpos = esd->wpos;
383: if (esd->dead > 0) {
384: audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
385: }
386: else {
387: audio_pt_unlock (&esd->pt, AUDIO_FUNC);
388: }
389: return incr;
390: }
391:
392: static int qesd_read (SWVoiceIn *sw, void *buf, int len)
393: {
394: return audio_pcm_sw_read (sw, buf, len);
395: }
396:
397: static int qesd_init_in (HWVoiceIn *hw, struct audsettings *as)
398: {
399: ESDVoiceIn *esd = (ESDVoiceIn *) hw;
400: struct audsettings obt_as = *as;
401: int esdfmt = ESD_STREAM | ESD_RECORD;
402:
403: esdfmt |= (as->nchannels == 2) ? ESD_STEREO : ESD_MONO;
404: switch (as->fmt) {
405: case AUD_FMT_S8:
406: case AUD_FMT_U8:
407: esdfmt |= ESD_BITS8;
408: obt_as.fmt = AUD_FMT_U8;
409: break;
410:
411: case AUD_FMT_S16:
412: case AUD_FMT_U16:
413: esdfmt |= ESD_BITS16;
414: obt_as.fmt = AUD_FMT_S16;
415: break;
416:
417: case AUD_FMT_S32:
418: case AUD_FMT_U32:
419: dolog ("Will use 16 instead of 32 bit samples\n");
420: esdfmt |= ESD_BITS16;
421: obt_as.fmt = AUD_FMT_S16;
422: break;
423: }
424: obt_as.endianness = AUDIO_HOST_ENDIANNESS;
425:
426: audio_pcm_init_info (&hw->info, &obt_as);
427:
428: hw->samples = conf.samples;
429: esd->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
430: if (!esd->pcm_buf) {
431: dolog ("Could not allocate buffer (%d bytes)\n",
432: hw->samples << hw->info.shift);
433: return -1;
434: }
435:
436: esd->fd = esd_record_stream (esdfmt, as->freq, conf.adc_host, NULL);
437: if (esd->fd < 0) {
438: qesd_logerr (errno, "esd_record_stream failed\n");
1.1.1.3 root 439: goto fail1;
1.1 root 440: }
441:
442: if (audio_pt_init (&esd->pt, qesd_thread_in, esd, AUDIO_CAP, AUDIO_FUNC)) {
1.1.1.3 root 443: goto fail2;
1.1 root 444: }
445:
446: return 0;
447:
1.1.1.3 root 448: fail2:
1.1 root 449: if (close (esd->fd)) {
450: qesd_logerr (errno, "%s: close on esd socket(%d) failed\n",
451: AUDIO_FUNC, esd->fd);
452: }
453: esd->fd = -1;
454:
455: fail1:
1.1.1.4 ! root 456: g_free (esd->pcm_buf);
1.1 root 457: esd->pcm_buf = NULL;
458: return -1;
459: }
460:
461: static void qesd_fini_in (HWVoiceIn *hw)
462: {
463: void *ret;
464: ESDVoiceIn *esd = (ESDVoiceIn *) hw;
465:
466: audio_pt_lock (&esd->pt, AUDIO_FUNC);
467: esd->done = 1;
468: audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
469: audio_pt_join (&esd->pt, &ret, AUDIO_FUNC);
470:
471: if (esd->fd >= 0) {
472: if (close (esd->fd)) {
473: qesd_logerr (errno, "failed to close esd socket\n");
474: }
475: esd->fd = -1;
476: }
477:
478: audio_pt_fini (&esd->pt, AUDIO_FUNC);
479:
1.1.1.4 ! root 480: g_free (esd->pcm_buf);
1.1 root 481: esd->pcm_buf = NULL;
482: }
483:
484: static int qesd_ctl_in (HWVoiceIn *hw, int cmd, ...)
485: {
486: (void) hw;
487: (void) cmd;
488: return 0;
489: }
490:
491: /* common */
492: static void *qesd_audio_init (void)
493: {
494: return &conf;
495: }
496:
497: static void qesd_audio_fini (void *opaque)
498: {
499: (void) opaque;
500: ldebug ("esd_fini");
501: }
502:
503: struct audio_option qesd_options[] = {
1.1.1.2 root 504: {
505: .name = "SAMPLES",
506: .tag = AUD_OPT_INT,
507: .valp = &conf.samples,
508: .descr = "buffer size in samples"
509: },
510: {
511: .name = "DIVISOR",
512: .tag = AUD_OPT_INT,
513: .valp = &conf.divisor,
514: .descr = "threshold divisor"
515: },
516: {
517: .name = "DAC_HOST",
518: .tag = AUD_OPT_STR,
519: .valp = &conf.dac_host,
520: .descr = "playback host"
521: },
522: {
523: .name = "ADC_HOST",
524: .tag = AUD_OPT_STR,
525: .valp = &conf.adc_host,
526: .descr = "capture host"
527: },
528: { /* End of list */ }
1.1 root 529: };
530:
531: static struct audio_pcm_ops qesd_pcm_ops = {
1.1.1.2 root 532: .init_out = qesd_init_out,
533: .fini_out = qesd_fini_out,
534: .run_out = qesd_run_out,
535: .write = qesd_write,
536: .ctl_out = qesd_ctl_out,
537:
538: .init_in = qesd_init_in,
539: .fini_in = qesd_fini_in,
540: .run_in = qesd_run_in,
541: .read = qesd_read,
542: .ctl_in = qesd_ctl_in,
1.1 root 543: };
544:
545: struct audio_driver esd_audio_driver = {
1.1.1.2 root 546: .name = "esd",
547: .descr = "http://en.wikipedia.org/wiki/Esound",
548: .options = qesd_options,
549: .init = qesd_audio_init,
550: .fini = qesd_audio_fini,
551: .pcm_ops = &qesd_pcm_ops,
552: .can_be_default = 0,
553: .max_voices_out = INT_MAX,
554: .max_voices_in = INT_MAX,
555: .voice_size_out = sizeof (ESDVoiceOut),
556: .voice_size_in = sizeof (ESDVoiceIn)
1.1 root 557: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.