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
25 #include "qemu-common.h"
29 #define AUDIO_CAP "esd"
30 #include "audio_int.h"
31 #include "audio_pt_int.h"
65 static void GCC_FMT_ATTR (2, 3) qesd_logerr (int err, const char *fmt, ...)
70 AUD_vlog (AUDIO_CAP, fmt, ap);
73 AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err));
77 static void *qesd_thread_out (void *arg)
79 ESDVoiceOut *esd = arg;
80 HWVoiceOut *hw = &esd->hw;
83 threshold = conf.divisor ? hw->samples / conf.divisor : 0;
85 if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
90 int decr, to_mix, rpos;
97 if (esd->live > threshold) {
101 if (audio_pt_wait (&esd->pt, AUDIO_FUNC)) {
106 decr = to_mix = esd->live;
109 if (audio_pt_unlock (&esd->pt, AUDIO_FUNC)) {
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);
121 written = write (esd->fd, esd->pcm_buf, chunk << hw->info.shift);
123 if (errno == EINTR || errno == EAGAIN) {
126 qesd_logerr (errno, "write failed\n");
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), "
136 wbytes, written, hw->info.align + 1);
139 rpos = (rpos + wsamples) % hw->samples;
143 rpos = (rpos + chunk) % hw->samples;
147 if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
157 audio_pt_unlock (&esd->pt, AUDIO_FUNC);
161 static int qesd_run_out (HWVoiceOut *hw)
164 ESDVoiceOut *esd = (ESDVoiceOut *) hw;
166 if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
170 live = audio_pcm_hw_get_live_out (hw);
171 decr = audio_MIN (live, esd->decr);
173 esd->live = live - decr;
174 hw->rpos = esd->rpos;
176 audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
179 audio_pt_unlock (&esd->pt, AUDIO_FUNC);
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;
195 sigset_t set, old_set;
199 esdfmt |= (as->nchannels == 2) ? ESD_STEREO : ESD_MONO;
204 obt_as.fmt = AUD_FMT_U8;
209 dolog ("Will use 16 instead of 32 bit samples\n");
214 esdfmt |= ESD_BITS16;
215 obt_as.fmt = AUD_FMT_S16;
219 dolog ("Internal logic error: Bad audio format %d\n", as->fmt);
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);
230 dolog ("Could not allocate buffer (%d bytes)\n",
231 hw->samples << hw->info.shift);
236 err = pthread_sigmask (SIG_BLOCK, &set, &old_set);
238 qesd_logerr (err, "pthread_sigmask failed\n");
242 esd->fd = esd_play_stream (esdfmt, as->freq, conf.dac_host, NULL);
244 qesd_logerr (errno, "esd_play_stream failed\n");
248 if (audio_pt_init (&esd->pt, qesd_thread_out, esd, AUDIO_CAP, AUDIO_FUNC)) {
252 err = pthread_sigmask (SIG_SETMASK, &old_set, NULL);
254 qesd_logerr (err, "pthread_sigmask(restore) failed\n");
260 if (close (esd->fd)) {
261 qesd_logerr (errno, "%s: close on esd socket(%d) failed\n",
262 AUDIO_FUNC, esd->fd);
267 err = pthread_sigmask (SIG_SETMASK, &old_set, NULL);
269 qesd_logerr (err, "pthread_sigmask(restore) failed\n");
273 qemu_free (esd->pcm_buf);
278 static void qesd_fini_out (HWVoiceOut *hw)
281 ESDVoiceOut *esd = (ESDVoiceOut *) hw;
283 audio_pt_lock (&esd->pt, AUDIO_FUNC);
285 audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
286 audio_pt_join (&esd->pt, &ret, AUDIO_FUNC);
289 if (close (esd->fd)) {
290 qesd_logerr (errno, "failed to close esd socket\n");
295 audio_pt_fini (&esd->pt, AUDIO_FUNC);
297 qemu_free (esd->pcm_buf);
301 static int qesd_ctl_out (HWVoiceOut *hw, int cmd, ...)
309 static void *qesd_thread_in (void *arg)
311 ESDVoiceIn *esd = arg;
312 HWVoiceIn *hw = &esd->hw;
315 threshold = conf.divisor ? hw->samples / conf.divisor : 0;
317 if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
322 int incr, to_grab, wpos;
329 if (esd->dead > threshold) {
333 if (audio_pt_wait (&esd->pt, AUDIO_FUNC)) {
338 incr = to_grab = esd->dead;
341 if (audio_pt_unlock (&esd->pt, AUDIO_FUNC)) {
347 int chunk = audio_MIN (to_grab, hw->samples - wpos);
348 void *buf = advance (esd->pcm_buf, wpos);
351 nread = read (esd->fd, buf, chunk << hw->info.shift);
353 if (errno == EINTR || errno == EAGAIN) {
356 qesd_logerr (errno, "read failed\n");
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), "
366 rbytes, nread, hw->info.align + 1);
369 wpos = (wpos + rsamples) % hw->samples;
373 hw->conv (hw->conv_buf + wpos, buf, nread >> hw->info.shift,
375 wpos = (wpos + chunk) % hw->samples;
379 if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
389 audio_pt_unlock (&esd->pt, AUDIO_FUNC);
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)) {
402 live = audio_pcm_hw_get_live_in (hw);
403 dead = hw->samples - live;
404 incr = audio_MIN (dead, esd->incr);
406 esd->dead = dead - incr;
407 hw->wpos = esd->wpos;
409 audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
412 audio_pt_unlock (&esd->pt, AUDIO_FUNC);
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;
428 sigset_t set, old_set;
432 esdfmt |= (as->nchannels == 2) ? ESD_STEREO : ESD_MONO;
437 obt_as.fmt = AUD_FMT_U8;
442 esdfmt |= ESD_BITS16;
443 obt_as.fmt = AUD_FMT_S16;
448 dolog ("Will use 16 instead of 32 bit samples\n");
449 esdfmt |= ESD_BITS16;
450 obt_as.fmt = AUD_FMT_S16;
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);
460 dolog ("Could not allocate buffer (%d bytes)\n",
461 hw->samples << hw->info.shift);
467 err = pthread_sigmask (SIG_BLOCK, &set, &old_set);
469 qesd_logerr (err, "pthread_sigmask failed\n");
473 esd->fd = esd_record_stream (esdfmt, as->freq, conf.adc_host, NULL);
475 qesd_logerr (errno, "esd_record_stream failed\n");
479 if (audio_pt_init (&esd->pt, qesd_thread_in, esd, AUDIO_CAP, AUDIO_FUNC)) {
483 err = pthread_sigmask (SIG_SETMASK, &old_set, NULL);
485 qesd_logerr (err, "pthread_sigmask(restore) failed\n");
491 if (close (esd->fd)) {
492 qesd_logerr (errno, "%s: close on esd socket(%d) failed\n",
493 AUDIO_FUNC, esd->fd);
498 err = pthread_sigmask (SIG_SETMASK, &old_set, NULL);
500 qesd_logerr (err, "pthread_sigmask(restore) failed\n");
504 qemu_free (esd->pcm_buf);
509 static void qesd_fini_in (HWVoiceIn *hw)
512 ESDVoiceIn *esd = (ESDVoiceIn *) hw;
514 audio_pt_lock (&esd->pt, AUDIO_FUNC);
516 audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
517 audio_pt_join (&esd->pt, &ret, AUDIO_FUNC);
520 if (close (esd->fd)) {
521 qesd_logerr (errno, "failed to close esd socket\n");
526 audio_pt_fini (&esd->pt, AUDIO_FUNC);
528 qemu_free (esd->pcm_buf);
532 static int qesd_ctl_in (HWVoiceIn *hw, int cmd, ...)
540 static void *qesd_audio_init (void)
545 static void qesd_audio_fini (void *opaque)
551 struct audio_option qesd_options[] = {
555 .valp = &conf.samples,
556 .descr = "buffer size in samples"
561 .valp = &conf.divisor,
562 .descr = "threshold divisor"
567 .valp = &conf.dac_host,
568 .descr = "playback host"
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,
584 .ctl_out = qesd_ctl_out,
586 .init_in = qesd_init_in,
587 .fini_in = qesd_fini_in,
588 .run_in = qesd_run_in,
590 .ctl_in = qesd_ctl_in,
593 struct audio_driver esd_audio_driver = {
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,
601 .max_voices_out = INT_MAX,
602 .max_voices_in = INT_MAX,
603 .voice_size_out = sizeof (ESDVoiceOut),
604 .voice_size_in = sizeof (ESDVoiceIn)