Home | History | Annotate | Download | only in audio
      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 "android/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 "android/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 
    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 */
    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 
    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 
    220 static int qesd_write (SWVoiceOut *sw, void *buf, int len)
    221 {
    222     return audio_pcm_sw_write (sw, buf, len);
    223 }
    224 
    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     g_free (esd->pcm_buf);
    288     esd->pcm_buf = NULL;
    289     return -1;
    290 }
    291 
    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     g_free (esd->pcm_buf);
    312     esd->pcm_buf = NULL;
    313 }
    314 
    315 static int qesd_ctl_out (HWVoiceOut *hw, int cmd, ...)
    316 {
    317     (void) hw;
    318     (void) cmd;
    319     return 0;
    320 }
    321 
    322 /* capture */
    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 
    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 
    431 static int qesd_read (SWVoiceIn *sw, void *buf, int len)
    432 {
    433     return audio_pcm_sw_read (sw, buf, len);
    434 }
    435 
    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     g_free (esd->pcm_buf);
    496     esd->pcm_buf = NULL;
    497     return -1;
    498 }
    499 
    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     g_free (esd->pcm_buf);
    520     esd->pcm_buf = NULL;
    521 }
    522 
    523 static int qesd_ctl_in (HWVoiceIn *hw, int cmd, ...)
    524 {
    525     (void) hw;
    526     (void) cmd;
    527     return 0;
    528 }
    529 
    530 /* common */
    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 
    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