esdaudio.c revision 5d0e37bc290d1743cb5acf76eb6608f1303f27dd
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
67static void*    esd_lib;
68
69
70typedef 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
81typedef 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
92static 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
102static 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 */
114static 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
198static 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
220static int qesd_write (SWVoiceOut *sw, void *buf, int len)
221{
222    return audio_pcm_sw_write (sw, buf, len);
223}
224
225static 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
292static 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
315static int qesd_ctl_out (HWVoiceOut *hw, int cmd, ...)
316{
317    (void) hw;
318    (void) cmd;
319    return 0;
320}
321
322/* capture */
323static 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
407static 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
431static int qesd_read (SWVoiceIn *sw, void *buf, int len)
432{
433    return audio_pcm_sw_read (sw, buf, len);
434}
435
436static 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
500static 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
523static int qesd_ctl_in (HWVoiceIn *hw, int cmd, ...)
524{
525    (void) hw;
526    (void) cmd;
527    return 0;
528}
529
530/* common */
531static 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
569Fail:
570    D("%s: failed to open library", __FUNCTION__);
571    dlclose(esd_lib);
572    esd_lib = NULL;
573
574Exit:
575    return  result;
576}
577
578static 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
588struct 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
616static 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
630struct 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