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