Home | History | Annotate | Download | only in audio
      1 /* public domain */
      2 #include "qemu-common.h"
      3 #include "audio.h"
      4 
      5 #include <pulse/simple.h>
      6 #include <pulse/error.h>
      7 #include <dlfcn.h>
      8 
      9 #define AUDIO_CAP "pulseaudio"
     10 #include "audio_int.h"
     11 #include "audio_pt_int.h"
     12 
     13 #define DEBUG 1
     14 
     15 #if DEBUG
     16 #  include "qemu_debug.h"
     17 #  include <stdio.h>
     18 #  define D(...)  VERBOSE_PRINT(audio,__VA_ARGS__)
     19 #  define D_ACTIVE  VERBOSE_CHECK(audio)
     20 #  define O(...)  VERBOSE_PRINT(audioout,__VA_ARGS__)
     21 #  define I(...)  VERBOSE_PRINT(audioin,__VA_ARGS__)
     22 #else
     23 #  define D(...)  ((void)0)
     24 #  define D_ACTIVE 0
     25 #  define O(...)  ((void)0)
     26 #  define I(...)  ((void)0)
     27 #endif
     28 
     29 #define  DYNLINK_FUNCTIONS   \
     30     DYNLINK_FUNC(pa_simple*,pa_simple_new,(const char* server,const char* name, pa_stream_direction_t dir, const char* dev, const char* stream_name, const pa_sample_spec* ss, const pa_channel_map* map, const pa_buffer_attr *attr, int *error)) \
     31     DYNLINK_FUNC(void,pa_simple_free,(pa_simple* s))\
     32     DYNLINK_FUNC(int,pa_simple_write,(pa_simple* s, const void* data, size_t bytes, int* error))\
     33     DYNLINK_FUNC(int,pa_simple_read,(pa_simple* s,void* data, size_t bytes, int* error))\
     34     DYNLINK_FUNC(const char*,pa_strerror,(int error))\
     35 
     36 #define DYNLINK_FUNCTIONS_INIT \
     37     pa_dynlink_init
     38 
     39 static void* pa_lib;
     40 
     41 #include "dynlink.h"
     42 
     43 typedef struct {
     44     HWVoiceOut hw;
     45     int done;
     46     int live;
     47     int decr;
     48     int rpos;
     49     pa_simple *s;
     50     void *pcm_buf;
     51     struct audio_pt pt;
     52 } PAVoiceOut;
     53 
     54 typedef struct {
     55     HWVoiceIn hw;
     56     int done;
     57     int dead;
     58     int incr;
     59     int wpos;
     60     pa_simple *s;
     61     void *pcm_buf;
     62     struct audio_pt pt;
     63 } PAVoiceIn;
     64 
     65 static struct {
     66     int samples;
     67     int divisor;
     68     char *server;
     69     char *sink;
     70     char *source;
     71 } conf = {
     72     .samples = 1024,
     73     .divisor = 2,
     74 };
     75 
     76 static void GCC_FMT_ATTR (2, 3) qpa_logerr (int err, const char *fmt, ...)
     77 {
     78     va_list ap;
     79 
     80     va_start (ap, fmt);
     81     AUD_vlog (AUDIO_CAP, fmt, ap);
     82     va_end (ap);
     83 
     84     AUD_log (AUDIO_CAP, "Reason: %s\n", FF(pa_strerror) (err));
     85 }
     86 
     87 static void *qpa_thread_out (void *arg)
     88 {
     89     PAVoiceOut *pa = arg;
     90     HWVoiceOut *hw = &pa->hw;
     91     int threshold;
     92 
     93     threshold = conf.divisor ? hw->samples / conf.divisor : 0;
     94 
     95     if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
     96         return NULL;
     97     }
     98 
     99     for (;;) {
    100         int decr, to_mix, rpos;
    101 
    102         for (;;) {
    103             if (pa->done) {
    104                 goto exit;
    105             }
    106 
    107             if (pa->live > threshold) {
    108                 break;
    109             }
    110 
    111             if (audio_pt_wait (&pa->pt, AUDIO_FUNC)) {
    112                 goto exit;
    113             }
    114         }
    115 
    116         decr = to_mix = pa->live;
    117         rpos = hw->rpos;
    118 
    119         if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) {
    120             return NULL;
    121         }
    122 
    123         while (to_mix) {
    124             int error;
    125             int chunk = audio_MIN (to_mix, hw->samples - rpos);
    126             struct st_sample *src = hw->mix_buf + rpos;
    127 
    128             hw->clip (pa->pcm_buf, src, chunk);
    129 
    130             if (FF(pa_simple_write) (pa->s, pa->pcm_buf,
    131                                  chunk << hw->info.shift, &error) < 0) {
    132                 qpa_logerr (error, "pa_simple_write failed\n");
    133                 return NULL;
    134             }
    135 
    136             rpos = (rpos + chunk) % hw->samples;
    137             to_mix -= chunk;
    138         }
    139 
    140         if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
    141             return NULL;
    142         }
    143 
    144         pa->rpos = rpos;
    145         pa->live -= decr;
    146         pa->decr += decr;
    147     }
    148 
    149  exit:
    150     audio_pt_unlock (&pa->pt, AUDIO_FUNC);
    151     return NULL;
    152 }
    153 
    154 static int qpa_run_out (HWVoiceOut *hw, int live)
    155 {
    156     int decr;
    157     PAVoiceOut *pa = (PAVoiceOut *) hw;
    158 
    159     if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
    160         return 0;
    161     }
    162 
    163     decr = audio_MIN (live, pa->decr);
    164     pa->decr -= decr;
    165     pa->live = live - decr;
    166     hw->rpos = pa->rpos;
    167     if (pa->live > 0) {
    168         audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
    169     }
    170     else {
    171         audio_pt_unlock (&pa->pt, AUDIO_FUNC);
    172     }
    173     return decr;
    174 }
    175 
    176 static int qpa_write (SWVoiceOut *sw, void *buf, int len)
    177 {
    178     return audio_pcm_sw_write (sw, buf, len);
    179 }
    180 
    181 /* capture */
    182 static void *qpa_thread_in (void *arg)
    183 {
    184     PAVoiceIn *pa = arg;
    185     HWVoiceIn *hw = &pa->hw;
    186     int threshold;
    187 
    188     threshold = conf.divisor ? hw->samples / conf.divisor : 0;
    189 
    190     if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
    191         return NULL;
    192     }
    193 
    194     for (;;) {
    195         int incr, to_grab, wpos;
    196 
    197         for (;;) {
    198             if (pa->done) {
    199                 goto exit;
    200             }
    201 
    202             if (pa->dead > threshold) {
    203                 break;
    204             }
    205 
    206             if (audio_pt_wait (&pa->pt, AUDIO_FUNC)) {
    207                 goto exit;
    208             }
    209         }
    210 
    211         incr = to_grab = pa->dead;
    212         wpos = hw->wpos;
    213 
    214         if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) {
    215             return NULL;
    216         }
    217 
    218         while (to_grab) {
    219             int error;
    220             int chunk = audio_MIN (to_grab, hw->samples - wpos);
    221             void *buf = advance (pa->pcm_buf, wpos);
    222 
    223             if (FF(pa_simple_read) (pa->s, buf,
    224                                 chunk << hw->info.shift, &error) < 0) {
    225                 qpa_logerr (error, "pa_simple_read failed\n");
    226                 return NULL;
    227             }
    228 
    229             hw->conv (hw->conv_buf + wpos, buf, chunk, &nominal_volume);
    230             wpos = (wpos + chunk) % hw->samples;
    231             to_grab -= chunk;
    232         }
    233 
    234         if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
    235             return NULL;
    236         }
    237 
    238         pa->wpos = wpos;
    239         pa->dead -= incr;
    240         pa->incr += incr;
    241     }
    242 
    243  exit:
    244     audio_pt_unlock (&pa->pt, AUDIO_FUNC);
    245     return NULL;
    246 }
    247 
    248 static int qpa_run_in (HWVoiceIn *hw)
    249 {
    250     int live, incr, dead;
    251     PAVoiceIn *pa = (PAVoiceIn *) hw;
    252 
    253     if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
    254         return 0;
    255     }
    256 
    257     live = audio_pcm_hw_get_live_in (hw);
    258     dead = hw->samples - live;
    259     incr = audio_MIN (dead, pa->incr);
    260     pa->incr -= incr;
    261     pa->dead = dead - incr;
    262     hw->wpos = pa->wpos;
    263     if (pa->dead > 0) {
    264         audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
    265     }
    266     else {
    267         audio_pt_unlock (&pa->pt, AUDIO_FUNC);
    268     }
    269     return incr;
    270 }
    271 
    272 static int qpa_read (SWVoiceIn *sw, void *buf, int len)
    273 {
    274     return audio_pcm_sw_read (sw, buf, len);
    275 }
    276 
    277 static pa_sample_format_t audfmt_to_pa (audfmt_e afmt, int endianness)
    278 {
    279     int format;
    280 
    281     switch (afmt) {
    282     case AUD_FMT_S8:
    283     case AUD_FMT_U8:
    284         format = PA_SAMPLE_U8;
    285         break;
    286     case AUD_FMT_S16:
    287     case AUD_FMT_U16:
    288         format = endianness ? PA_SAMPLE_S16BE : PA_SAMPLE_S16LE;
    289         break;
    290     case AUD_FMT_S32:
    291     case AUD_FMT_U32:
    292         format = endianness ? PA_SAMPLE_S32BE : PA_SAMPLE_S32LE;
    293         break;
    294     default:
    295         dolog ("Internal logic error: Bad audio format %d\n", afmt);
    296         format = PA_SAMPLE_U8;
    297         break;
    298     }
    299     return format;
    300 }
    301 
    302 static audfmt_e pa_to_audfmt (pa_sample_format_t fmt, int *endianness)
    303 {
    304     switch (fmt) {
    305     case PA_SAMPLE_U8:
    306         return AUD_FMT_U8;
    307     case PA_SAMPLE_S16BE:
    308         *endianness = 1;
    309         return AUD_FMT_S16;
    310     case PA_SAMPLE_S16LE:
    311         *endianness = 0;
    312         return AUD_FMT_S16;
    313     case PA_SAMPLE_S32BE:
    314         *endianness = 1;
    315         return AUD_FMT_S32;
    316     case PA_SAMPLE_S32LE:
    317         *endianness = 0;
    318         return AUD_FMT_S32;
    319     default:
    320         dolog ("Internal logic error: Bad pa_sample_format %d\n", fmt);
    321         return AUD_FMT_U8;
    322     }
    323 }
    324 
    325 static int qpa_init_out (HWVoiceOut *hw, struct audsettings *as)
    326 {
    327     int error;
    328     static pa_sample_spec ss;
    329     struct audsettings obt_as = *as;
    330     PAVoiceOut *pa = (PAVoiceOut *) hw;
    331 
    332     ss.format = audfmt_to_pa (as->fmt, as->endianness);
    333     ss.channels = as->nchannels;
    334     ss.rate = as->freq;
    335 
    336     obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
    337 
    338     pa->s = FF(pa_simple_new) (
    339         conf.server,
    340         "qemu",
    341         PA_STREAM_PLAYBACK,
    342         conf.sink,
    343         "pcm.playback",
    344         &ss,
    345         NULL,                   /* channel map */
    346         NULL,                   /* buffering attributes */
    347         &error
    348         );
    349     if (!pa->s) {
    350         qpa_logerr (error, "pa_simple_new for playback failed\n");
    351         goto fail1;
    352     }
    353 
    354     audio_pcm_init_info (&hw->info, &obt_as);
    355     hw->samples = conf.samples;
    356     pa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
    357     if (!pa->pcm_buf) {
    358         dolog ("Could not allocate buffer (%d bytes)\n",
    359                hw->samples << hw->info.shift);
    360         goto fail2;
    361     }
    362 
    363     if (audio_pt_init (&pa->pt, qpa_thread_out, hw, AUDIO_CAP, AUDIO_FUNC)) {
    364         goto fail3;
    365     }
    366 
    367     return 0;
    368 
    369  fail3:
    370     qemu_free (pa->pcm_buf);
    371     pa->pcm_buf = NULL;
    372  fail2:
    373     FF(pa_simple_free) (pa->s);
    374     pa->s = NULL;
    375  fail1:
    376     return -1;
    377 }
    378 
    379 static int qpa_init_in (HWVoiceIn *hw, struct audsettings *as)
    380 {
    381     int error;
    382     static pa_sample_spec ss;
    383     struct audsettings obt_as = *as;
    384     PAVoiceIn *pa = (PAVoiceIn *) hw;
    385 
    386     ss.format = audfmt_to_pa (as->fmt, as->endianness);
    387     ss.channels = as->nchannels;
    388     ss.rate = as->freq;
    389 
    390     obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
    391 
    392     pa->s = FF(pa_simple_new) (
    393         conf.server,
    394         "qemu",
    395         PA_STREAM_RECORD,
    396         conf.source,
    397         "pcm.capture",
    398         &ss,
    399         NULL,                   /* channel map */
    400         NULL,                   /* buffering attributes */
    401         &error
    402         );
    403     if (!pa->s) {
    404         qpa_logerr (error, "pa_simple_new for capture failed\n");
    405         goto fail1;
    406     }
    407 
    408     audio_pcm_init_info (&hw->info, &obt_as);
    409     hw->samples = conf.samples;
    410     pa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
    411     if (!pa->pcm_buf) {
    412         dolog ("Could not allocate buffer (%d bytes)\n",
    413                hw->samples << hw->info.shift);
    414         goto fail2;
    415     }
    416 
    417     if (audio_pt_init (&pa->pt, qpa_thread_in, hw, AUDIO_CAP, AUDIO_FUNC)) {
    418         goto fail3;
    419     }
    420 
    421     return 0;
    422 
    423  fail3:
    424     qemu_free (pa->pcm_buf);
    425     pa->pcm_buf = NULL;
    426  fail2:
    427     FF(pa_simple_free) (pa->s);
    428     pa->s = NULL;
    429  fail1:
    430     return -1;
    431 }
    432 
    433 static void qpa_fini_out (HWVoiceOut *hw)
    434 {
    435     void *ret;
    436     PAVoiceOut *pa = (PAVoiceOut *) hw;
    437 
    438     audio_pt_lock (&pa->pt, AUDIO_FUNC);
    439     pa->done = 1;
    440     audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
    441     audio_pt_join (&pa->pt, &ret, AUDIO_FUNC);
    442 
    443     if (pa->s) {
    444         FF(pa_simple_free) (pa->s);
    445         pa->s = NULL;
    446     }
    447 
    448     audio_pt_fini (&pa->pt, AUDIO_FUNC);
    449     qemu_free (pa->pcm_buf);
    450     pa->pcm_buf = NULL;
    451 }
    452 
    453 static void qpa_fini_in (HWVoiceIn *hw)
    454 {
    455     void *ret;
    456     PAVoiceIn *pa = (PAVoiceIn *) hw;
    457 
    458     audio_pt_lock (&pa->pt, AUDIO_FUNC);
    459     pa->done = 1;
    460     audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
    461     audio_pt_join (&pa->pt, &ret, AUDIO_FUNC);
    462 
    463     if (pa->s) {
    464         FF(pa_simple_free) (pa->s);
    465         pa->s = NULL;
    466     }
    467 
    468     audio_pt_fini (&pa->pt, AUDIO_FUNC);
    469     qemu_free (pa->pcm_buf);
    470     pa->pcm_buf = NULL;
    471 }
    472 
    473 static int qpa_ctl_out (HWVoiceOut *hw, int cmd, ...)
    474 {
    475     (void) hw;
    476     (void) cmd;
    477     return 0;
    478 }
    479 
    480 static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...)
    481 {
    482     (void) hw;
    483     (void) cmd;
    484     return 0;
    485 }
    486 
    487 /* common */
    488 static void *qpa_audio_init (void)
    489 {
    490     void*  result = NULL;
    491 
    492     D("%s: entering", __FUNCTION__);
    493     pa_lib = dlopen( "libpulse-simple.so", RTLD_NOW );
    494     if (pa_lib == NULL)
    495         pa_lib = dlopen( "libpulse-simple.so.0", RTLD_NOW );
    496 
    497     if (pa_lib == NULL) {
    498         D("could not find libpulse on this system\n");
    499         goto Exit;
    500     }
    501 
    502     if (pa_dynlink_init(pa_lib) < 0)
    503         goto Fail;
    504 
    505     {
    506         pa_sample_spec  ss;
    507         int             error;
    508         pa_simple*      simple;
    509 
    510         ss.format   = PA_SAMPLE_U8;
    511         ss.rate     = 44100;
    512         ss.channels = 1;
    513 
    514         /* try to open it for playback */
    515         simple = FF(pa_simple_new) (
    516             conf.server,
    517             "qemu",
    518             PA_STREAM_PLAYBACK,
    519             conf.sink,
    520             "pcm.playback",
    521             &ss,
    522             NULL,                   /* channel map */
    523             NULL,                   /* buffering attributes */
    524             &error
    525             );
    526 
    527         if (simple == NULL) {
    528             D("%s: error opening open pulse audio library: %s",
    529               __FUNCTION__, FF(pa_strerror)(error));
    530             goto Fail;
    531         }
    532         FF(pa_simple_free)(simple);
    533     }
    534 
    535     result = &conf;
    536     goto Exit;
    537 
    538 Fail:
    539     D("%s: failed to open library\n", __FUNCTION__);
    540     dlclose(pa_lib);
    541 
    542 Exit:
    543     D("%s: exiting", __FUNCTION__);
    544     return result;
    545 }
    546 
    547 static void qpa_audio_fini (void *opaque)
    548 {
    549     if (pa_lib != NULL) {
    550         dlclose(pa_lib);
    551         pa_lib = NULL;
    552     }
    553     (void) opaque;
    554     (void) opaque;
    555 }
    556 
    557 struct audio_option qpa_options[] = {
    558     {
    559         .name  = "SAMPLES",
    560         .tag   = AUD_OPT_INT,
    561         .valp  = &conf.samples,
    562         .descr = "buffer size in samples"
    563     },
    564     {
    565         .name  = "DIVISOR",
    566         .tag   = AUD_OPT_INT,
    567         .valp  = &conf.divisor,
    568         .descr = "threshold divisor"
    569     },
    570     {
    571         .name  = "SERVER",
    572         .tag   = AUD_OPT_STR,
    573         .valp  = &conf.server,
    574         .descr = "server address"
    575     },
    576     {
    577         .name  = "SINK",
    578         .tag   = AUD_OPT_STR,
    579         .valp  = &conf.sink,
    580         .descr = "sink device name"
    581     },
    582     {
    583         .name  = "SOURCE",
    584         .tag   = AUD_OPT_STR,
    585         .valp  = &conf.source,
    586         .descr = "source device name"
    587     },
    588     { /* End of list */ }
    589 };
    590 
    591 static struct audio_pcm_ops qpa_pcm_ops = {
    592     .init_out = qpa_init_out,
    593     .fini_out = qpa_fini_out,
    594     .run_out  = qpa_run_out,
    595     .write    = qpa_write,
    596     .ctl_out  = qpa_ctl_out,
    597 
    598     .init_in  = qpa_init_in,
    599     .fini_in  = qpa_fini_in,
    600     .run_in   = qpa_run_in,
    601     .read     = qpa_read,
    602     .ctl_in   = qpa_ctl_in
    603 };
    604 
    605 struct audio_driver pa_audio_driver = {
    606     .name           = "pa",
    607     .descr          = "http://www.pulseaudio.org/",
    608     .options        = qpa_options,
    609     .init           = qpa_audio_init,
    610     .fini           = qpa_audio_fini,
    611     .pcm_ops        = &qpa_pcm_ops,
    612     .can_be_default = 1,
    613     .max_voices_out = INT_MAX,
    614     .max_voices_in  = INT_MAX,
    615     .voice_size_out = sizeof (PAVoiceOut),
    616     .voice_size_in  = sizeof (PAVoiceIn)
    617 };
    618