qcow2: Order concurrent AIO requests on the same unallocated cluster
[armpft.git] / audio / esdaudio.c
blob90a8a7a689dff5d7019906bc884d1658af7391d1
1 /*
2 * QEMU ESD audio driver
4 * Copyright (c) 2006 Frederick Reeve (brushed up by malc)
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:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
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.
24 #include <esd.h>
25 #include "qemu-common.h"
26 #include "audio.h"
27 #include <signal.h>
29 #define AUDIO_CAP "esd"
30 #include "audio_int.h"
31 #include "audio_pt_int.h"
33 typedef struct {
34 HWVoiceOut hw;
35 int done;
36 int live;
37 int decr;
38 int rpos;
39 void *pcm_buf;
40 int fd;
41 struct audio_pt pt;
42 } ESDVoiceOut;
44 typedef struct {
45 HWVoiceIn hw;
46 int done;
47 int dead;
48 int incr;
49 int wpos;
50 void *pcm_buf;
51 int fd;
52 struct audio_pt pt;
53 } ESDVoiceIn;
55 static struct {
56 int samples;
57 int divisor;
58 char *dac_host;
59 char *adc_host;
60 } conf = {
61 .samples = 1024,
62 .divisor = 2,
65 static void GCC_FMT_ATTR (2, 3) qesd_logerr (int err, const char *fmt, ...)
67 va_list ap;
69 va_start (ap, fmt);
70 AUD_vlog (AUDIO_CAP, fmt, ap);
71 va_end (ap);
73 AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err));
76 /* playback */
77 static void *qesd_thread_out (void *arg)
79 ESDVoiceOut *esd = arg;
80 HWVoiceOut *hw = &esd->hw;
81 int threshold;
83 threshold = conf.divisor ? hw->samples / conf.divisor : 0;
85 if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
86 return NULL;
89 for (;;) {
90 int decr, to_mix, rpos;
92 for (;;) {
93 if (esd->done) {
94 goto exit;
97 if (esd->live > threshold) {
98 break;
101 if (audio_pt_wait (&esd->pt, AUDIO_FUNC)) {
102 goto exit;
106 decr = to_mix = esd->live;
107 rpos = hw->rpos;
109 if (audio_pt_unlock (&esd->pt, AUDIO_FUNC)) {
110 return NULL;
113 while (to_mix) {
114 ssize_t written;
115 int chunk = audio_MIN (to_mix, hw->samples - rpos);
116 struct st_sample *src = hw->mix_buf + rpos;
118 hw->clip (esd->pcm_buf, src, chunk);
120 again:
121 written = write (esd->fd, esd->pcm_buf, chunk << hw->info.shift);
122 if (written == -1) {
123 if (errno == EINTR || errno == EAGAIN) {
124 goto again;
126 qesd_logerr (errno, "write failed\n");
127 return NULL;
130 if (written != chunk << hw->info.shift) {
131 int wsamples = written >> hw->info.shift;
132 int wbytes = wsamples << hw->info.shift;
133 if (wbytes != written) {
134 dolog ("warning: Misaligned write %d (requested %zd), "
135 "alignment %d\n",
136 wbytes, written, hw->info.align + 1);
138 to_mix -= wsamples;
139 rpos = (rpos + wsamples) % hw->samples;
140 break;
143 rpos = (rpos + chunk) % hw->samples;
144 to_mix -= chunk;
147 if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
148 return NULL;
151 esd->rpos = rpos;
152 esd->live -= decr;
153 esd->decr += decr;
156 exit:
157 audio_pt_unlock (&esd->pt, AUDIO_FUNC);
158 return NULL;
161 static int qesd_run_out (HWVoiceOut *hw)
163 int live, decr;
164 ESDVoiceOut *esd = (ESDVoiceOut *) hw;
166 if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
167 return 0;
170 live = audio_pcm_hw_get_live_out (hw);
171 decr = audio_MIN (live, esd->decr);
172 esd->decr -= decr;
173 esd->live = live - decr;
174 hw->rpos = esd->rpos;
175 if (esd->live > 0) {
176 audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
178 else {
179 audio_pt_unlock (&esd->pt, AUDIO_FUNC);
181 return decr;
184 static int qesd_write (SWVoiceOut *sw, void *buf, int len)
186 return audio_pcm_sw_write (sw, buf, len);
189 static int qesd_init_out (HWVoiceOut *hw, struct audsettings *as)
191 ESDVoiceOut *esd = (ESDVoiceOut *) hw;
192 struct audsettings obt_as = *as;
193 int esdfmt = ESD_STREAM | ESD_PLAY;
194 int err;
195 sigset_t set, old_set;
197 sigfillset (&set);
199 esdfmt |= (as->nchannels == 2) ? ESD_STEREO : ESD_MONO;
200 switch (as->fmt) {
201 case AUD_FMT_S8:
202 case AUD_FMT_U8:
203 esdfmt |= ESD_BITS8;
204 obt_as.fmt = AUD_FMT_U8;
205 break;
207 case AUD_FMT_S32:
208 case AUD_FMT_U32:
209 dolog ("Will use 16 instead of 32 bit samples\n");
211 case AUD_FMT_S16:
212 case AUD_FMT_U16:
213 deffmt:
214 esdfmt |= ESD_BITS16;
215 obt_as.fmt = AUD_FMT_S16;
216 break;
218 default:
219 dolog ("Internal logic error: Bad audio format %d\n", as->fmt);
220 goto deffmt;
223 obt_as.endianness = AUDIO_HOST_ENDIANNESS;
225 audio_pcm_init_info (&hw->info, &obt_as);
227 hw->samples = conf.samples;
228 esd->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
229 if (!esd->pcm_buf) {
230 dolog ("Could not allocate buffer (%d bytes)\n",
231 hw->samples << hw->info.shift);
232 return -1;
235 esd->fd = -1;
236 err = pthread_sigmask (SIG_BLOCK, &set, &old_set);
237 if (err) {
238 qesd_logerr (err, "pthread_sigmask failed\n");
239 goto fail1;
242 esd->fd = esd_play_stream (esdfmt, as->freq, conf.dac_host, NULL);
243 if (esd->fd < 0) {
244 qesd_logerr (errno, "esd_play_stream failed\n");
245 goto fail2;
248 if (audio_pt_init (&esd->pt, qesd_thread_out, esd, AUDIO_CAP, AUDIO_FUNC)) {
249 goto fail3;
252 err = pthread_sigmask (SIG_SETMASK, &old_set, NULL);
253 if (err) {
254 qesd_logerr (err, "pthread_sigmask(restore) failed\n");
257 return 0;
259 fail3:
260 if (close (esd->fd)) {
261 qesd_logerr (errno, "%s: close on esd socket(%d) failed\n",
262 AUDIO_FUNC, esd->fd);
264 esd->fd = -1;
266 fail2:
267 err = pthread_sigmask (SIG_SETMASK, &old_set, NULL);
268 if (err) {
269 qesd_logerr (err, "pthread_sigmask(restore) failed\n");
272 fail1:
273 qemu_free (esd->pcm_buf);
274 esd->pcm_buf = NULL;
275 return -1;
278 static void qesd_fini_out (HWVoiceOut *hw)
280 void *ret;
281 ESDVoiceOut *esd = (ESDVoiceOut *) hw;
283 audio_pt_lock (&esd->pt, AUDIO_FUNC);
284 esd->done = 1;
285 audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
286 audio_pt_join (&esd->pt, &ret, AUDIO_FUNC);
288 if (esd->fd >= 0) {
289 if (close (esd->fd)) {
290 qesd_logerr (errno, "failed to close esd socket\n");
292 esd->fd = -1;
295 audio_pt_fini (&esd->pt, AUDIO_FUNC);
297 qemu_free (esd->pcm_buf);
298 esd->pcm_buf = NULL;
301 static int qesd_ctl_out (HWVoiceOut *hw, int cmd, ...)
303 (void) hw;
304 (void) cmd;
305 return 0;
308 /* capture */
309 static void *qesd_thread_in (void *arg)
311 ESDVoiceIn *esd = arg;
312 HWVoiceIn *hw = &esd->hw;
313 int threshold;
315 threshold = conf.divisor ? hw->samples / conf.divisor : 0;
317 if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
318 return NULL;
321 for (;;) {
322 int incr, to_grab, wpos;
324 for (;;) {
325 if (esd->done) {
326 goto exit;
329 if (esd->dead > threshold) {
330 break;
333 if (audio_pt_wait (&esd->pt, AUDIO_FUNC)) {
334 goto exit;
338 incr = to_grab = esd->dead;
339 wpos = hw->wpos;
341 if (audio_pt_unlock (&esd->pt, AUDIO_FUNC)) {
342 return NULL;
345 while (to_grab) {
346 ssize_t nread;
347 int chunk = audio_MIN (to_grab, hw->samples - wpos);
348 void *buf = advance (esd->pcm_buf, wpos);
350 again:
351 nread = read (esd->fd, buf, chunk << hw->info.shift);
352 if (nread == -1) {
353 if (errno == EINTR || errno == EAGAIN) {
354 goto again;
356 qesd_logerr (errno, "read failed\n");
357 return NULL;
360 if (nread != chunk << hw->info.shift) {
361 int rsamples = nread >> hw->info.shift;
362 int rbytes = rsamples << hw->info.shift;
363 if (rbytes != nread) {
364 dolog ("warning: Misaligned write %d (requested %zd), "
365 "alignment %d\n",
366 rbytes, nread, hw->info.align + 1);
368 to_grab -= rsamples;
369 wpos = (wpos + rsamples) % hw->samples;
370 break;
373 hw->conv (hw->conv_buf + wpos, buf, nread >> hw->info.shift,
374 &nominal_volume);
375 wpos = (wpos + chunk) % hw->samples;
376 to_grab -= chunk;
379 if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
380 return NULL;
383 esd->wpos = wpos;
384 esd->dead -= incr;
385 esd->incr += incr;
388 exit:
389 audio_pt_unlock (&esd->pt, AUDIO_FUNC);
390 return NULL;
393 static int qesd_run_in (HWVoiceIn *hw)
395 int live, incr, dead;
396 ESDVoiceIn *esd = (ESDVoiceIn *) hw;
398 if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
399 return 0;
402 live = audio_pcm_hw_get_live_in (hw);
403 dead = hw->samples - live;
404 incr = audio_MIN (dead, esd->incr);
405 esd->incr -= incr;
406 esd->dead = dead - incr;
407 hw->wpos = esd->wpos;
408 if (esd->dead > 0) {
409 audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
411 else {
412 audio_pt_unlock (&esd->pt, AUDIO_FUNC);
414 return incr;
417 static int qesd_read (SWVoiceIn *sw, void *buf, int len)
419 return audio_pcm_sw_read (sw, buf, len);
422 static int qesd_init_in (HWVoiceIn *hw, struct audsettings *as)
424 ESDVoiceIn *esd = (ESDVoiceIn *) hw;
425 struct audsettings obt_as = *as;
426 int esdfmt = ESD_STREAM | ESD_RECORD;
427 int err;
428 sigset_t set, old_set;
430 sigfillset (&set);
432 esdfmt |= (as->nchannels == 2) ? ESD_STEREO : ESD_MONO;
433 switch (as->fmt) {
434 case AUD_FMT_S8:
435 case AUD_FMT_U8:
436 esdfmt |= ESD_BITS8;
437 obt_as.fmt = AUD_FMT_U8;
438 break;
440 case AUD_FMT_S16:
441 case AUD_FMT_U16:
442 esdfmt |= ESD_BITS16;
443 obt_as.fmt = AUD_FMT_S16;
444 break;
446 case AUD_FMT_S32:
447 case AUD_FMT_U32:
448 dolog ("Will use 16 instead of 32 bit samples\n");
449 esdfmt |= ESD_BITS16;
450 obt_as.fmt = AUD_FMT_S16;
451 break;
453 obt_as.endianness = AUDIO_HOST_ENDIANNESS;
455 audio_pcm_init_info (&hw->info, &obt_as);
457 hw->samples = conf.samples;
458 esd->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
459 if (!esd->pcm_buf) {
460 dolog ("Could not allocate buffer (%d bytes)\n",
461 hw->samples << hw->info.shift);
462 return -1;
465 esd->fd = -1;
467 err = pthread_sigmask (SIG_BLOCK, &set, &old_set);
468 if (err) {
469 qesd_logerr (err, "pthread_sigmask failed\n");
470 goto fail1;
473 esd->fd = esd_record_stream (esdfmt, as->freq, conf.adc_host, NULL);
474 if (esd->fd < 0) {
475 qesd_logerr (errno, "esd_record_stream failed\n");
476 goto fail2;
479 if (audio_pt_init (&esd->pt, qesd_thread_in, esd, AUDIO_CAP, AUDIO_FUNC)) {
480 goto fail3;
483 err = pthread_sigmask (SIG_SETMASK, &old_set, NULL);
484 if (err) {
485 qesd_logerr (err, "pthread_sigmask(restore) failed\n");
488 return 0;
490 fail3:
491 if (close (esd->fd)) {
492 qesd_logerr (errno, "%s: close on esd socket(%d) failed\n",
493 AUDIO_FUNC, esd->fd);
495 esd->fd = -1;
497 fail2:
498 err = pthread_sigmask (SIG_SETMASK, &old_set, NULL);
499 if (err) {
500 qesd_logerr (err, "pthread_sigmask(restore) failed\n");
503 fail1:
504 qemu_free (esd->pcm_buf);
505 esd->pcm_buf = NULL;
506 return -1;
509 static void qesd_fini_in (HWVoiceIn *hw)
511 void *ret;
512 ESDVoiceIn *esd = (ESDVoiceIn *) hw;
514 audio_pt_lock (&esd->pt, AUDIO_FUNC);
515 esd->done = 1;
516 audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
517 audio_pt_join (&esd->pt, &ret, AUDIO_FUNC);
519 if (esd->fd >= 0) {
520 if (close (esd->fd)) {
521 qesd_logerr (errno, "failed to close esd socket\n");
523 esd->fd = -1;
526 audio_pt_fini (&esd->pt, AUDIO_FUNC);
528 qemu_free (esd->pcm_buf);
529 esd->pcm_buf = NULL;
532 static int qesd_ctl_in (HWVoiceIn *hw, int cmd, ...)
534 (void) hw;
535 (void) cmd;
536 return 0;
539 /* common */
540 static void *qesd_audio_init (void)
542 return &conf;
545 static void qesd_audio_fini (void *opaque)
547 (void) opaque;
548 ldebug ("esd_fini");
551 struct audio_option qesd_options[] = {
553 .name = "SAMPLES",
554 .tag = AUD_OPT_INT,
555 .valp = &conf.samples,
556 .descr = "buffer size in samples"
559 .name = "DIVISOR",
560 .tag = AUD_OPT_INT,
561 .valp = &conf.divisor,
562 .descr = "threshold divisor"
565 .name = "DAC_HOST",
566 .tag = AUD_OPT_STR,
567 .valp = &conf.dac_host,
568 .descr = "playback host"
571 .name = "ADC_HOST",
572 .tag = AUD_OPT_STR,
573 .valp = &conf.adc_host,
574 .descr = "capture host"
576 { /* End of list */ }
579 static struct audio_pcm_ops qesd_pcm_ops = {
580 .init_out = qesd_init_out,
581 .fini_out = qesd_fini_out,
582 .run_out = qesd_run_out,
583 .write = qesd_write,
584 .ctl_out = qesd_ctl_out,
586 .init_in = qesd_init_in,
587 .fini_in = qesd_fini_in,
588 .run_in = qesd_run_in,
589 .read = qesd_read,
590 .ctl_in = qesd_ctl_in,
593 struct audio_driver esd_audio_driver = {
594 .name = "esd",
595 .descr = "http://en.wikipedia.org/wiki/Esound",
596 .options = qesd_options,
597 .init = qesd_audio_init,
598 .fini = qesd_audio_fini,
599 .pcm_ops = &qesd_pcm_ops,
600 .can_be_default = 0,
601 .max_voices_out = INT_MAX,
602 .max_voices_in = INT_MAX,
603 .voice_size_out = sizeof (ESDVoiceOut),
604 .voice_size_in = sizeof (ESDVoiceIn)