1 /*
2 * QEMU ESD audio driver
3 *
4 * Copyright (c) 2008 The Android Open Source Project
5 * Copyright (c) 2006 Frederick Reeve (brushed up by malc)
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 */
25
26 #include <esd.h>
27 #include "audio.h"
28 #include <signal.h>
29
30 #define AUDIO_CAP "esd"
31 #include "audio_int.h"
32 #include "audio_pt_int.h"
33 #include <dlfcn.h>
34
35 #include "qemu_debug.h"
36
37 #define DEBUG 1
38
39 #if DEBUG
40 # include <stdio.h>
41 # define D(...) VERBOSE_PRINT(audio,__VA_ARGS__)
42 # define D_ACTIVE VERBOSE_CHECK(audio)
43 # define O(...) VERBOSE_PRINT(audioout,__VA_ARGS__)
44 # define I(...) VERBOSE_PRINT(audioin,__VA_ARGS__)
45 #else
46 # define D(...) ((void)0)
47 # define D_ACTIVE 0
48 # define O(...) ((void)0)
49 # define I(...) ((void)0)
50 #endif
51
52 #define STRINGIFY_(x) #x
53 #define STRINGIFY(x) STRINGIFY_(x)
54
55 typedef struct {
56 HWVoiceOut hw;
57 int done;
58 int live;
59 int decr;
60 int rpos;
61 void *pcm_buf;
62 int fd;
63 struct audio_pt pt;
64 } ESDVoiceOut;
65
66 typedef struct {
67 HWVoiceIn hw;
68 int done;
69 int dead;
70 int incr;
71 int wpos;
72 void *pcm_buf;
73 int fd;
74 struct audio_pt pt;
75 } ESDVoiceIn;
76
77 static struct {
78 int samples;
79 int divisor;
80 char *dac_host;
81 char *adc_host;
82 } conf = {
83 1024,
84 2,
85 NULL,
86 NULL
87 };
88
89 /* link dynamically to the libesd.so */
90
91 #define DYNLINK_FUNCTIONS \
92 DYNLINK_FUNC(int,esd_play_stream,(esd_format_t,int,const char*,const char*)) \
93 DYNLINK_FUNC(int,esd_record_stream,(esd_format_t,int,const char*,const char*)) \
94 DYNLINK_FUNC(int,esd_open_sound,( const char *host )) \
95 DYNLINK_FUNC(int,esd_close,(int)) \
96
97 #define DYNLINK_FUNCTIONS_INIT \
98 esd_dynlink_init
99
100 #include "dynlink.h"
101
102 static void* esd_lib;
103
qesd_logerr(int err,const char * fmt,...)104 static void GCC_FMT_ATTR (2, 3) qesd_logerr (int err, const char *fmt, ...)
105 {
106 va_list ap;
107
108 va_start (ap, fmt);
109 AUD_vlog (AUDIO_CAP, fmt, ap);
110 va_end (ap);
111
112 AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err));
113 }
114
115 /* playback */
qesd_thread_out(void * arg)116 static void *qesd_thread_out (void *arg)
117 {
118 ESDVoiceOut* esd = arg;
119 HWVoiceOut* hw = &esd->hw;
120 int threshold;
121 sigset_t set;
122
123 threshold = conf.divisor ? hw->samples / conf.divisor : 0;
124
125 if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
126 return NULL;
127 }
128
129 /* ignore SIGALRM in this thread */
130 sigemptyset(&set);
131 sigaddset(&set, SIGALRM);
132
133 pthread_sigmask( SIG_BLOCK, &set, NULL);
134
135 O("EsounD output thread starting, threshold is %d samples", threshold);
136 for (;;) {
137 int decr, to_mix, rpos;
138
139 for (;;) {
140 if (esd->done) {
141 goto exit;
142 }
143
144 if (esd->live > threshold) {
145 break;
146 }
147
148 if (audio_pt_wait (&esd->pt, AUDIO_FUNC)) {
149 O("EsounD output thread aborting on wait error");
150 goto exit;
151 }
152 }
153
154 decr = to_mix = esd->live;
155 rpos = hw->rpos;
156
157 if (audio_pt_unlock (&esd->pt, AUDIO_FUNC)) {
158 O("EsounD output thread aborting on unlock error");
159 return NULL;
160 }
161
162 while (to_mix) {
163 ssize_t written;
164 int chunk = audio_MIN (to_mix, hw->samples - rpos);
165 st_sample_t *src = hw->mix_buf + rpos;
166
167 hw->clip (esd->pcm_buf, src, chunk);
168
169 again:
170 written = write (esd->fd, esd->pcm_buf, chunk << hw->info.shift);
171 if (written == -1) {
172 if (errno == EINTR || errno == EAGAIN) {
173 goto again;
174 }
175 qesd_logerr (errno, "write failed\n");
176 O("EsounD output thread aborting on write error: %s", strerror(errno));
177 return NULL;
178 }
179
180 if (written != chunk << hw->info.shift) {
181 int wsamples = written >> hw->info.shift;
182 int wbytes = wsamples << hw->info.shift;
183 if (wbytes != written) {
184 dolog ("warning: Misaligned write %d (requested %d), "
185 "alignment %d\n",
186 wbytes, written, hw->info.align + 1);
187 }
188 to_mix -= wsamples;
189 rpos = (rpos + wsamples) % hw->samples;
190 break;
191 }
192
193 rpos = (rpos + chunk) % hw->samples;
194 to_mix -= chunk;
195 }
196
197 if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
198 O("EsounD output thread aborting on lock error\n");
199 return NULL;
200 }
201
202 esd->rpos = rpos;
203 esd->live -= decr;
204 esd->decr += decr;
205 }
206 O("EsounD output thread exiting");
207
208 exit:
209 audio_pt_unlock (&esd->pt, AUDIO_FUNC);
210 return NULL;
211 }
212
qesd_run_out(HWVoiceOut * hw)213 static int qesd_run_out (HWVoiceOut *hw)
214 {
215 int live, decr;
216 ESDVoiceOut *esd = (ESDVoiceOut *) hw;
217
218 if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
219 O("%s: exiting on lock error", __FUNCTION__);
220 return 0;
221 }
222
223 live = audio_pcm_hw_get_live_out (hw);
224 decr = audio_MIN (live, esd->decr);
225 esd->decr -= decr;
226 esd->live = live - decr;
227 hw->rpos = esd->rpos;
228 if (esd->live > 0) {
229 O("%s: signaling %d samples\n", __FUNCTION__, esd->live);
230 audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
231 }
232 else {
233 O(".");
234 audio_pt_unlock (&esd->pt, AUDIO_FUNC);
235 }
236 return decr;
237 }
238
qesd_write(SWVoiceOut * sw,void * buf,int len)239 static int qesd_write (SWVoiceOut *sw, void *buf, int len)
240 {
241 return audio_pcm_sw_write (sw, buf, len);
242 }
243
qesd_init_out(HWVoiceOut * hw,audsettings_t * as)244 static int qesd_init_out (HWVoiceOut *hw, audsettings_t *as)
245 {
246 ESDVoiceOut *esd = (ESDVoiceOut *) hw;
247 audsettings_t obt_as = *as;
248 int esdfmt = ESD_STREAM | ESD_PLAY;
249 int result = -1;
250
251 /* shut down verbose debug spew */
252 if (!D_ACTIVE)
253 stdio_disable();
254
255 O("initializing EsoundD audio output");
256 esdfmt |= (as->nchannels == 2) ? ESD_STEREO : ESD_MONO;
257 switch (as->fmt) {
258 case AUD_FMT_S8:
259 case AUD_FMT_U8:
260 esdfmt |= ESD_BITS8;
261 obt_as.fmt = AUD_FMT_U8;
262 break;
263 #if 0
264 case AUD_FMT_S32:
265 case AUD_FMT_U32:
266 dolog ("Will use 16 instead of 32 bit samples\n");
267 #endif
268 case AUD_FMT_S16:
269 case AUD_FMT_U16:
270 deffmt:
271 esdfmt |= ESD_BITS16;
272 obt_as.fmt = AUD_FMT_S16;
273 break;
274
275 default:
276 dolog ("Internal logic error: Bad audio format %d\n", as->fmt);
277 goto deffmt;
278
279 }
280 obt_as.endianness = AUDIO_HOST_ENDIANNESS;
281
282 audio_pcm_init_info (&hw->info, &obt_as);
283
284 hw->samples = conf.samples;
285 esd->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
286 if (!esd->pcm_buf) {
287 dolog ("Could not allocate buffer (%d bytes)\n",
288 hw->samples << hw->info.shift);
289 goto exit;
290 }
291
292 esd->fd = FF(esd_play_stream) (esdfmt, as->freq, conf.dac_host, NULL);
293 if (esd->fd < 0) {
294 if (conf.dac_host == NULL) {
295 esd->fd = FF(esd_play_stream) (esdfmt, as->freq, "localhost", NULL);
296 }
297 if (esd->fd < 0) {
298 qesd_logerr (errno, "esd_play_stream failed\n");
299 goto fail2;
300 }
301 }
302
303 if (audio_pt_init (&esd->pt, qesd_thread_out, esd, AUDIO_CAP, AUDIO_FUNC)) {
304 goto fail3;
305 }
306
307 result = 0; /* success */
308 goto exit;
309
310 fail3:
311 if (close (esd->fd)) {
312 qesd_logerr (errno, "%s: close on esd socket(%d) failed\n",
313 AUDIO_FUNC, esd->fd);
314 }
315 esd->fd = -1;
316
317 fail2:
318 qemu_free (esd->pcm_buf);
319 esd->pcm_buf = NULL;
320
321 exit:
322 if (!D_ACTIVE)
323 stdio_enable();
324
325 return result;
326 }
327
qesd_fini_out(HWVoiceOut * hw)328 static void qesd_fini_out (HWVoiceOut *hw)
329 {
330 void *ret;
331 ESDVoiceOut *esd = (ESDVoiceOut *) hw;
332
333 audio_pt_lock (&esd->pt, AUDIO_FUNC);
334 esd->done = 1;
335 audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
336 audio_pt_join (&esd->pt, &ret, AUDIO_FUNC);
337
338 if (esd->fd >= 0) {
339 if (close (esd->fd)) {
340 qesd_logerr (errno, "failed to close esd socket\n");
341 }
342 esd->fd = -1;
343 }
344
345 audio_pt_fini (&esd->pt, AUDIO_FUNC);
346
347 qemu_free (esd->pcm_buf);
348 esd->pcm_buf = NULL;
349 }
350
qesd_ctl_out(HWVoiceOut * hw,int cmd,...)351 static int qesd_ctl_out (HWVoiceOut *hw, int cmd, ...)
352 {
353 (void) hw;
354 (void) cmd;
355 return 0;
356 }
357
358 /* capture */
qesd_thread_in(void * arg)359 static void *qesd_thread_in (void *arg)
360 {
361 ESDVoiceIn *esd = arg;
362 HWVoiceIn *hw = &esd->hw;
363 int threshold;
364
365 threshold = conf.divisor ? hw->samples / conf.divisor : 0;
366
367 if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
368 return NULL;
369 }
370
371 for (;;) {
372 int incr, to_grab, wpos;
373
374 for (;;) {
375 if (esd->done) {
376 goto exit;
377 }
378
379 if (esd->dead > threshold) {
380 break;
381 }
382
383 if (audio_pt_wait (&esd->pt, AUDIO_FUNC)) {
384 goto exit;
385 }
386 }
387
388 incr = to_grab = esd->dead;
389 wpos = hw->wpos;
390
391 if (audio_pt_unlock (&esd->pt, AUDIO_FUNC)) {
392 return NULL;
393 }
394
395 while (to_grab) {
396 ssize_t nread;
397 int chunk = audio_MIN (to_grab, hw->samples - wpos);
398 void *buf = advance (esd->pcm_buf, wpos);
399
400 again:
401 nread = read (esd->fd, buf, chunk << hw->info.shift);
402 if (nread == -1) {
403 if (errno == EINTR || errno == EAGAIN) {
404 goto again;
405 }
406 qesd_logerr (errno, "read failed\n");
407 return NULL;
408 }
409
410 if (nread != chunk << hw->info.shift) {
411 int rsamples = nread >> hw->info.shift;
412 int rbytes = rsamples << hw->info.shift;
413 if (rbytes != nread) {
414 dolog ("warning: Misaligned write %d (requested %d), "
415 "alignment %d\n",
416 rbytes, nread, hw->info.align + 1);
417 }
418 to_grab -= rsamples;
419 wpos = (wpos + rsamples) % hw->samples;
420 break;
421 }
422
423 hw->conv (hw->conv_buf + wpos, buf, nread >> hw->info.shift,
424 &nominal_volume);
425 wpos = (wpos + chunk) % hw->samples;
426 to_grab -= chunk;
427 }
428
429 if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
430 return NULL;
431 }
432
433 esd->wpos = wpos;
434 esd->dead -= incr;
435 esd->incr += incr;
436 }
437
438 exit:
439 audio_pt_unlock (&esd->pt, AUDIO_FUNC);
440 return NULL;
441 }
442
qesd_run_in(HWVoiceIn * hw)443 static int qesd_run_in (HWVoiceIn *hw)
444 {
445 int live, incr, dead;
446 ESDVoiceIn *esd = (ESDVoiceIn *) hw;
447
448 if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
449 return 0;
450 }
451
452 live = audio_pcm_hw_get_live_in (hw);
453 dead = hw->samples - live;
454 incr = audio_MIN (dead, esd->incr);
455 esd->incr -= incr;
456 esd->dead = dead - incr;
457 hw->wpos = esd->wpos;
458 if (esd->dead > 0) {
459 audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
460 }
461 else {
462 audio_pt_unlock (&esd->pt, AUDIO_FUNC);
463 }
464 return incr;
465 }
466
qesd_read(SWVoiceIn * sw,void * buf,int len)467 static int qesd_read (SWVoiceIn *sw, void *buf, int len)
468 {
469 return audio_pcm_sw_read (sw, buf, len);
470 }
471
qesd_init_in(HWVoiceIn * hw,audsettings_t * as)472 static int qesd_init_in (HWVoiceIn *hw, audsettings_t *as)
473 {
474 ESDVoiceIn *esd = (ESDVoiceIn *) hw;
475 audsettings_t obt_as = *as;
476 int esdfmt = ESD_STREAM | ESD_RECORD;
477 int result = -1;
478
479 /* shut down verbose debug spew */
480 if (!D_ACTIVE)
481 stdio_disable();
482
483 esdfmt |= (as->nchannels == 2) ? ESD_STEREO : ESD_MONO;
484 switch (as->fmt) {
485 case AUD_FMT_S8:
486 case AUD_FMT_U8:
487 esdfmt |= ESD_BITS8;
488 obt_as.fmt = AUD_FMT_U8;
489 break;
490
491 case AUD_FMT_S16:
492 case AUD_FMT_U16:
493 esdfmt |= ESD_BITS16;
494 obt_as.fmt = AUD_FMT_S16;
495 break;
496 case AUD_FMT_S32:
497 case AUD_FMT_U32:
498 dolog ("Will use 16 instead of 32 bit samples\n");
499 esdfmt |= ESD_BITS16;
500 obt_as.fmt = AUD_FMT_S16;
501 break;
502 }
503 obt_as.endianness = AUDIO_HOST_ENDIANNESS;
504
505 audio_pcm_init_info (&hw->info, &obt_as);
506
507 hw->samples = conf.samples;
508 esd->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
509 if (!esd->pcm_buf) {
510 dolog ("Could not allocate buffer (%d bytes)\n",
511 hw->samples << hw->info.shift);
512 goto exit;
513 }
514
515 esd->fd = FF(esd_record_stream) (esdfmt, as->freq, conf.adc_host, NULL);
516 if (esd->fd < 0) {
517 if (conf.adc_host == NULL) {
518 esd->fd = FF(esd_record_stream) (esdfmt, as->freq, "localhost", NULL);
519 }
520 if (esd->fd < 0) {
521 qesd_logerr (errno, "esd_record_stream failed\n");
522 goto fail2;
523 }
524 }
525
526 if (audio_pt_init (&esd->pt, qesd_thread_in, esd, AUDIO_CAP, AUDIO_FUNC)) {
527 goto fail3;
528 }
529
530 result = 0; /* success */
531 goto exit;
532
533 fail3:
534 if (close (esd->fd)) {
535 qesd_logerr (errno, "%s: close on esd socket(%d) failed\n",
536 AUDIO_FUNC, esd->fd);
537 }
538 esd->fd = -1;
539
540 fail2:
541 qemu_free (esd->pcm_buf);
542 esd->pcm_buf = NULL;
543
544 exit:
545 if (!D_ACTIVE)
546 stdio_enable();
547
548 return result;
549 }
550
qesd_fini_in(HWVoiceIn * hw)551 static void qesd_fini_in (HWVoiceIn *hw)
552 {
553 void *ret;
554 ESDVoiceIn *esd = (ESDVoiceIn *) hw;
555
556 audio_pt_lock (&esd->pt, AUDIO_FUNC);
557 esd->done = 1;
558 audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
559 audio_pt_join (&esd->pt, &ret, AUDIO_FUNC);
560
561 if (esd->fd >= 0) {
562 if (close (esd->fd)) {
563 qesd_logerr (errno, "failed to close esd socket\n");
564 }
565 esd->fd = -1;
566 }
567
568 audio_pt_fini (&esd->pt, AUDIO_FUNC);
569
570 qemu_free (esd->pcm_buf);
571 esd->pcm_buf = NULL;
572 }
573
qesd_ctl_in(HWVoiceIn * hw,int cmd,...)574 static int qesd_ctl_in (HWVoiceIn *hw, int cmd, ...)
575 {
576 (void) hw;
577 (void) cmd;
578 return 0;
579 }
580
581 /* common */
qesd_audio_init(void)582 static void *qesd_audio_init (void)
583 {
584 void* result = NULL;
585
586 D("%s: entering", __FUNCTION__);
587
588 if (esd_lib == NULL) {
589 int fd;
590
591 esd_lib = dlopen( "libesd.so", RTLD_NOW );
592 if (esd_lib == NULL)
593 esd_lib = dlopen( "libesd.so.0", RTLD_NOW );
594
595 if (esd_lib == NULL) {
596 D("could not find libesd on this system");
597 goto Exit;
598 }
599
600 if (esd_dynlink_init(esd_lib) < 0)
601 goto Fail;
602
603 fd = FF(esd_open_sound)(conf.dac_host);
604 if (fd < 0) {
605 D("%s: could not open direct sound server connection, trying localhost",
606 __FUNCTION__);
607 fd = FF(esd_open_sound)("localhost");
608 if (fd < 0) {
609 D("%s: could not open localhost sound server connection", __FUNCTION__);
610 goto Fail;
611 }
612 }
613
614 D("%s: EsounD server connection succeeded", __FUNCTION__);
615 /* FF(esd_close)(fd); */
616 }
617 result = &conf;
618 goto Exit;
619
620 Fail:
621 D("%s: failed to open library", __FUNCTION__);
622 dlclose(esd_lib);
623 esd_lib = NULL;
624
625 Exit:
626 return result;
627 }
628
qesd_audio_fini(void * opaque)629 static void qesd_audio_fini (void *opaque)
630 {
631 (void) opaque;
632 if (esd_lib != NULL) {
633 dlclose(esd_lib);
634 esd_lib = NULL;
635 }
636 ldebug ("esd_fini");
637 }
638
639 struct audio_option qesd_options[] = {
640 {"SAMPLES", AUD_OPT_INT, &conf.samples,
641 "buffer size in samples", NULL, 0},
642
643 {"DIVISOR", AUD_OPT_INT, &conf.divisor,
644 "threshold divisor", NULL, 0},
645
646 {"DAC_HOST", AUD_OPT_STR, &conf.dac_host,
647 "playback host", NULL, 0},
648
649 {"ADC_HOST", AUD_OPT_STR, &conf.adc_host,
650 "capture host", NULL, 0},
651
652 {NULL, 0, NULL, NULL, NULL, 0}
653 };
654
655 struct audio_pcm_ops qesd_pcm_ops = {
656 qesd_init_out,
657 qesd_fini_out,
658 qesd_run_out,
659 qesd_write,
660 qesd_ctl_out,
661
662 qesd_init_in,
663 qesd_fini_in,
664 qesd_run_in,
665 qesd_read,
666 qesd_ctl_in,
667 };
668
669 struct audio_driver esd_audio_driver = {
670 INIT_FIELD (name = ) "esd",
671 INIT_FIELD (descr = )
672 "EsounD audio (en.wikipedia.org/wiki/Esound)",
673 INIT_FIELD (options = ) qesd_options,
674 INIT_FIELD (init = ) qesd_audio_init,
675 INIT_FIELD (fini = ) qesd_audio_fini,
676 INIT_FIELD (pcm_ops = ) &qesd_pcm_ops,
677 INIT_FIELD (can_be_default = ) 1,
678 INIT_FIELD (max_voices_out = ) INT_MAX,
679 INIT_FIELD (max_voices_in = ) 1,
680 INIT_FIELD (voice_size_out = ) sizeof (ESDVoiceOut),
681 INIT_FIELD (voice_size_in = ) sizeof (ESDVoiceIn)
682 };
683