• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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