Annotation of qemu/audio/paaudio.c, revision 1.1.1.6

1.1       root        1: /* public domain */
                      2: #include "qemu-common.h"
                      3: #include "audio.h"
                      4: 
1.1.1.6 ! root        5: #include <pulse/pulseaudio.h>
1.1       root        6: 
                      7: #define AUDIO_CAP "pulseaudio"
                      8: #include "audio_int.h"
                      9: #include "audio_pt_int.h"
                     10: 
                     11: typedef struct {
                     12:     HWVoiceOut hw;
                     13:     int done;
                     14:     int live;
                     15:     int decr;
                     16:     int rpos;
1.1.1.6 ! root       17:     pa_stream *stream;
1.1       root       18:     void *pcm_buf;
                     19:     struct audio_pt pt;
                     20: } PAVoiceOut;
                     21: 
                     22: typedef struct {
                     23:     HWVoiceIn hw;
                     24:     int done;
                     25:     int dead;
                     26:     int incr;
                     27:     int wpos;
1.1.1.6 ! root       28:     pa_stream *stream;
1.1       root       29:     void *pcm_buf;
                     30:     struct audio_pt pt;
1.1.1.6 ! root       31:     const void *read_data;
        !            32:     size_t read_index, read_length;
1.1       root       33: } PAVoiceIn;
                     34: 
1.1.1.6 ! root       35: typedef struct {
1.1       root       36:     int samples;
                     37:     char *server;
                     38:     char *sink;
                     39:     char *source;
1.1.1.6 ! root       40:     pa_threaded_mainloop *mainloop;
        !            41:     pa_context *context;
        !            42: } paaudio;
        !            43: 
        !            44: static paaudio glob_paaudio = {
1.1.1.4   root       45:     .samples = 4096,
1.1       root       46: };
                     47: 
                     48: static void GCC_FMT_ATTR (2, 3) qpa_logerr (int err, const char *fmt, ...)
                     49: {
                     50:     va_list ap;
                     51: 
                     52:     va_start (ap, fmt);
                     53:     AUD_vlog (AUDIO_CAP, fmt, ap);
                     54:     va_end (ap);
                     55: 
                     56:     AUD_log (AUDIO_CAP, "Reason: %s\n", pa_strerror (err));
                     57: }
                     58: 
1.1.1.6 ! root       59: #ifndef PA_CONTEXT_IS_GOOD
        !            60: static inline int PA_CONTEXT_IS_GOOD(pa_context_state_t x)
        !            61: {
        !            62:     return
        !            63:         x == PA_CONTEXT_CONNECTING ||
        !            64:         x == PA_CONTEXT_AUTHORIZING ||
        !            65:         x == PA_CONTEXT_SETTING_NAME ||
        !            66:         x == PA_CONTEXT_READY;
        !            67: }
        !            68: #endif
        !            69: 
        !            70: #ifndef PA_STREAM_IS_GOOD
        !            71: static inline int PA_STREAM_IS_GOOD(pa_stream_state_t x)
        !            72: {
        !            73:     return
        !            74:         x == PA_STREAM_CREATING ||
        !            75:         x == PA_STREAM_READY;
        !            76: }
        !            77: #endif
        !            78: 
        !            79: #define CHECK_SUCCESS_GOTO(c, rerror, expression, label)        \
        !            80:     do {                                                        \
        !            81:         if (!(expression)) {                                    \
        !            82:             if (rerror) {                                       \
        !            83:                 *(rerror) = pa_context_errno ((c)->context);    \
        !            84:             }                                                   \
        !            85:             goto label;                                         \
        !            86:         }                                                       \
        !            87:     } while (0);
        !            88: 
        !            89: #define CHECK_DEAD_GOTO(c, stream, rerror, label)                       \
        !            90:     do {                                                                \
        !            91:         if (!(c)->context || !PA_CONTEXT_IS_GOOD (pa_context_get_state((c)->context)) || \
        !            92:             !(stream) || !PA_STREAM_IS_GOOD (pa_stream_get_state ((stream)))) { \
        !            93:             if (((c)->context && pa_context_get_state ((c)->context) == PA_CONTEXT_FAILED) || \
        !            94:                 ((stream) && pa_stream_get_state ((stream)) == PA_STREAM_FAILED)) { \
        !            95:                 if (rerror) {                                           \
        !            96:                     *(rerror) = pa_context_errno ((c)->context);        \
        !            97:                 }                                                       \
        !            98:             } else {                                                    \
        !            99:                 if (rerror) {                                           \
        !           100:                     *(rerror) = PA_ERR_BADSTATE;                        \
        !           101:                 }                                                       \
        !           102:             }                                                           \
        !           103:             goto label;                                                 \
        !           104:         }                                                               \
        !           105:     } while (0);
        !           106: 
        !           107: static int qpa_simple_read (PAVoiceIn *p, void *data, size_t length, int *rerror)
        !           108: {
        !           109:     paaudio *g = &glob_paaudio;
        !           110: 
        !           111:     pa_threaded_mainloop_lock (g->mainloop);
        !           112: 
        !           113:     CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
        !           114: 
        !           115:     while (length > 0) {
        !           116:         size_t l;
        !           117: 
        !           118:         while (!p->read_data) {
        !           119:             int r;
        !           120: 
        !           121:             r = pa_stream_peek (p->stream, &p->read_data, &p->read_length);
        !           122:             CHECK_SUCCESS_GOTO (g, rerror, r == 0, unlock_and_fail);
        !           123: 
        !           124:             if (!p->read_data) {
        !           125:                 pa_threaded_mainloop_wait (g->mainloop);
        !           126:                 CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
        !           127:             } else {
        !           128:                 p->read_index = 0;
        !           129:             }
        !           130:         }
        !           131: 
        !           132:         l = p->read_length < length ? p->read_length : length;
        !           133:         memcpy (data, (const uint8_t *) p->read_data+p->read_index, l);
        !           134: 
        !           135:         data = (uint8_t *) data + l;
        !           136:         length -= l;
        !           137: 
        !           138:         p->read_index += l;
        !           139:         p->read_length -= l;
        !           140: 
        !           141:         if (!p->read_length) {
        !           142:             int r;
        !           143: 
        !           144:             r = pa_stream_drop (p->stream);
        !           145:             p->read_data = NULL;
        !           146:             p->read_length = 0;
        !           147:             p->read_index = 0;
        !           148: 
        !           149:             CHECK_SUCCESS_GOTO (g, rerror, r == 0, unlock_and_fail);
        !           150:         }
        !           151:     }
        !           152: 
        !           153:     pa_threaded_mainloop_unlock (g->mainloop);
        !           154:     return 0;
        !           155: 
        !           156: unlock_and_fail:
        !           157:     pa_threaded_mainloop_unlock (g->mainloop);
        !           158:     return -1;
        !           159: }
        !           160: 
        !           161: static int qpa_simple_write (PAVoiceOut *p, const void *data, size_t length, int *rerror)
        !           162: {
        !           163:     paaudio *g = &glob_paaudio;
        !           164: 
        !           165:     pa_threaded_mainloop_lock (g->mainloop);
        !           166: 
        !           167:     CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
        !           168: 
        !           169:     while (length > 0) {
        !           170:         size_t l;
        !           171:         int r;
        !           172: 
        !           173:         while (!(l = pa_stream_writable_size (p->stream))) {
        !           174:             pa_threaded_mainloop_wait (g->mainloop);
        !           175:             CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
        !           176:         }
        !           177: 
        !           178:         CHECK_SUCCESS_GOTO (g, rerror, l != (size_t) -1, unlock_and_fail);
        !           179: 
        !           180:         if (l > length) {
        !           181:             l = length;
        !           182:         }
        !           183: 
        !           184:         r = pa_stream_write (p->stream, data, l, NULL, 0LL, PA_SEEK_RELATIVE);
        !           185:         CHECK_SUCCESS_GOTO (g, rerror, r >= 0, unlock_and_fail);
        !           186: 
        !           187:         data = (const uint8_t *) data + l;
        !           188:         length -= l;
        !           189:     }
        !           190: 
        !           191:     pa_threaded_mainloop_unlock (g->mainloop);
        !           192:     return 0;
        !           193: 
        !           194: unlock_and_fail:
        !           195:     pa_threaded_mainloop_unlock (g->mainloop);
        !           196:     return -1;
        !           197: }
        !           198: 
1.1       root      199: static void *qpa_thread_out (void *arg)
                    200: {
                    201:     PAVoiceOut *pa = arg;
                    202:     HWVoiceOut *hw = &pa->hw;
                    203: 
                    204:     if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
                    205:         return NULL;
                    206:     }
                    207: 
                    208:     for (;;) {
                    209:         int decr, to_mix, rpos;
                    210: 
                    211:         for (;;) {
                    212:             if (pa->done) {
                    213:                 goto exit;
                    214:             }
                    215: 
1.1.1.4   root      216:             if (pa->live > 0) {
1.1       root      217:                 break;
                    218:             }
                    219: 
                    220:             if (audio_pt_wait (&pa->pt, AUDIO_FUNC)) {
                    221:                 goto exit;
                    222:             }
                    223:         }
                    224: 
1.1.1.6 ! root      225:         decr = to_mix = audio_MIN (pa->live, glob_paaudio.samples >> 2);
1.1.1.4   root      226:         rpos = pa->rpos;
1.1       root      227: 
                    228:         if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) {
                    229:             return NULL;
                    230:         }
                    231: 
                    232:         while (to_mix) {
                    233:             int error;
                    234:             int chunk = audio_MIN (to_mix, hw->samples - rpos);
                    235:             struct st_sample *src = hw->mix_buf + rpos;
                    236: 
                    237:             hw->clip (pa->pcm_buf, src, chunk);
                    238: 
1.1.1.6 ! root      239:             if (qpa_simple_write (pa, pa->pcm_buf,
        !           240:                                   chunk << hw->info.shift, &error) < 0) {
1.1       root      241:                 qpa_logerr (error, "pa_simple_write failed\n");
                    242:                 return NULL;
                    243:             }
                    244: 
                    245:             rpos = (rpos + chunk) % hw->samples;
                    246:             to_mix -= chunk;
                    247:         }
                    248: 
                    249:         if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
                    250:             return NULL;
                    251:         }
                    252: 
                    253:         pa->rpos = rpos;
                    254:         pa->live -= decr;
                    255:         pa->decr += decr;
                    256:     }
                    257: 
                    258:  exit:
                    259:     audio_pt_unlock (&pa->pt, AUDIO_FUNC);
                    260:     return NULL;
                    261: }
                    262: 
1.1.1.3   root      263: static int qpa_run_out (HWVoiceOut *hw, int live)
1.1       root      264: {
1.1.1.3   root      265:     int decr;
1.1       root      266:     PAVoiceOut *pa = (PAVoiceOut *) hw;
                    267: 
                    268:     if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
                    269:         return 0;
                    270:     }
                    271: 
                    272:     decr = audio_MIN (live, pa->decr);
                    273:     pa->decr -= decr;
                    274:     pa->live = live - decr;
                    275:     hw->rpos = pa->rpos;
                    276:     if (pa->live > 0) {
                    277:         audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
                    278:     }
                    279:     else {
                    280:         audio_pt_unlock (&pa->pt, AUDIO_FUNC);
                    281:     }
                    282:     return decr;
                    283: }
                    284: 
                    285: static int qpa_write (SWVoiceOut *sw, void *buf, int len)
                    286: {
                    287:     return audio_pcm_sw_write (sw, buf, len);
                    288: }
                    289: 
                    290: /* capture */
                    291: static void *qpa_thread_in (void *arg)
                    292: {
                    293:     PAVoiceIn *pa = arg;
                    294:     HWVoiceIn *hw = &pa->hw;
                    295: 
                    296:     if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
                    297:         return NULL;
                    298:     }
                    299: 
                    300:     for (;;) {
                    301:         int incr, to_grab, wpos;
                    302: 
                    303:         for (;;) {
                    304:             if (pa->done) {
                    305:                 goto exit;
                    306:             }
                    307: 
1.1.1.4   root      308:             if (pa->dead > 0) {
1.1       root      309:                 break;
                    310:             }
                    311: 
                    312:             if (audio_pt_wait (&pa->pt, AUDIO_FUNC)) {
                    313:                 goto exit;
                    314:             }
                    315:         }
                    316: 
1.1.1.6 ! root      317:         incr = to_grab = audio_MIN (pa->dead, glob_paaudio.samples >> 2);
1.1.1.4   root      318:         wpos = pa->wpos;
1.1       root      319: 
                    320:         if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) {
                    321:             return NULL;
                    322:         }
                    323: 
                    324:         while (to_grab) {
                    325:             int error;
                    326:             int chunk = audio_MIN (to_grab, hw->samples - wpos);
                    327:             void *buf = advance (pa->pcm_buf, wpos);
                    328: 
1.1.1.6 ! root      329:             if (qpa_simple_read (pa, buf,
        !           330:                                  chunk << hw->info.shift, &error) < 0) {
1.1       root      331:                 qpa_logerr (error, "pa_simple_read failed\n");
                    332:                 return NULL;
                    333:             }
                    334: 
1.1.1.4   root      335:             hw->conv (hw->conv_buf + wpos, buf, chunk);
1.1       root      336:             wpos = (wpos + chunk) % hw->samples;
                    337:             to_grab -= chunk;
                    338:         }
                    339: 
                    340:         if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
                    341:             return NULL;
                    342:         }
                    343: 
                    344:         pa->wpos = wpos;
                    345:         pa->dead -= incr;
                    346:         pa->incr += incr;
                    347:     }
                    348: 
                    349:  exit:
                    350:     audio_pt_unlock (&pa->pt, AUDIO_FUNC);
                    351:     return NULL;
                    352: }
                    353: 
                    354: static int qpa_run_in (HWVoiceIn *hw)
                    355: {
                    356:     int live, incr, dead;
                    357:     PAVoiceIn *pa = (PAVoiceIn *) hw;
                    358: 
                    359:     if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
                    360:         return 0;
                    361:     }
                    362: 
                    363:     live = audio_pcm_hw_get_live_in (hw);
                    364:     dead = hw->samples - live;
                    365:     incr = audio_MIN (dead, pa->incr);
                    366:     pa->incr -= incr;
                    367:     pa->dead = dead - incr;
                    368:     hw->wpos = pa->wpos;
                    369:     if (pa->dead > 0) {
                    370:         audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
                    371:     }
                    372:     else {
                    373:         audio_pt_unlock (&pa->pt, AUDIO_FUNC);
                    374:     }
                    375:     return incr;
                    376: }
                    377: 
                    378: static int qpa_read (SWVoiceIn *sw, void *buf, int len)
                    379: {
                    380:     return audio_pcm_sw_read (sw, buf, len);
                    381: }
                    382: 
                    383: static pa_sample_format_t audfmt_to_pa (audfmt_e afmt, int endianness)
                    384: {
                    385:     int format;
                    386: 
                    387:     switch (afmt) {
                    388:     case AUD_FMT_S8:
                    389:     case AUD_FMT_U8:
                    390:         format = PA_SAMPLE_U8;
                    391:         break;
                    392:     case AUD_FMT_S16:
                    393:     case AUD_FMT_U16:
                    394:         format = endianness ? PA_SAMPLE_S16BE : PA_SAMPLE_S16LE;
                    395:         break;
                    396:     case AUD_FMT_S32:
                    397:     case AUD_FMT_U32:
                    398:         format = endianness ? PA_SAMPLE_S32BE : PA_SAMPLE_S32LE;
                    399:         break;
                    400:     default:
                    401:         dolog ("Internal logic error: Bad audio format %d\n", afmt);
                    402:         format = PA_SAMPLE_U8;
                    403:         break;
                    404:     }
                    405:     return format;
                    406: }
                    407: 
                    408: static audfmt_e pa_to_audfmt (pa_sample_format_t fmt, int *endianness)
                    409: {
                    410:     switch (fmt) {
                    411:     case PA_SAMPLE_U8:
                    412:         return AUD_FMT_U8;
                    413:     case PA_SAMPLE_S16BE:
                    414:         *endianness = 1;
                    415:         return AUD_FMT_S16;
                    416:     case PA_SAMPLE_S16LE:
                    417:         *endianness = 0;
                    418:         return AUD_FMT_S16;
                    419:     case PA_SAMPLE_S32BE:
                    420:         *endianness = 1;
                    421:         return AUD_FMT_S32;
                    422:     case PA_SAMPLE_S32LE:
                    423:         *endianness = 0;
                    424:         return AUD_FMT_S32;
                    425:     default:
                    426:         dolog ("Internal logic error: Bad pa_sample_format %d\n", fmt);
                    427:         return AUD_FMT_U8;
                    428:     }
                    429: }
                    430: 
1.1.1.6 ! root      431: static void context_state_cb (pa_context *c, void *userdata)
        !           432: {
        !           433:     paaudio *g = &glob_paaudio;
        !           434: 
        !           435:     switch (pa_context_get_state(c)) {
        !           436:     case PA_CONTEXT_READY:
        !           437:     case PA_CONTEXT_TERMINATED:
        !           438:     case PA_CONTEXT_FAILED:
        !           439:         pa_threaded_mainloop_signal (g->mainloop, 0);
        !           440:         break;
        !           441: 
        !           442:     case PA_CONTEXT_UNCONNECTED:
        !           443:     case PA_CONTEXT_CONNECTING:
        !           444:     case PA_CONTEXT_AUTHORIZING:
        !           445:     case PA_CONTEXT_SETTING_NAME:
        !           446:         break;
        !           447:     }
        !           448: }
        !           449: 
        !           450: static void stream_state_cb (pa_stream *s, void * userdata)
        !           451: {
        !           452:     paaudio *g = &glob_paaudio;
        !           453: 
        !           454:     switch (pa_stream_get_state (s)) {
        !           455: 
        !           456:     case PA_STREAM_READY:
        !           457:     case PA_STREAM_FAILED:
        !           458:     case PA_STREAM_TERMINATED:
        !           459:         pa_threaded_mainloop_signal (g->mainloop, 0);
        !           460:         break;
        !           461: 
        !           462:     case PA_STREAM_UNCONNECTED:
        !           463:     case PA_STREAM_CREATING:
        !           464:         break;
        !           465:     }
        !           466: }
        !           467: 
        !           468: static void stream_request_cb (pa_stream *s, size_t length, void *userdata)
        !           469: {
        !           470:     paaudio *g = &glob_paaudio;
        !           471: 
        !           472:     pa_threaded_mainloop_signal (g->mainloop, 0);
        !           473: }
        !           474: 
        !           475: static pa_stream *qpa_simple_new (
        !           476:         const char *server,
        !           477:         const char *name,
        !           478:         pa_stream_direction_t dir,
        !           479:         const char *dev,
        !           480:         const char *stream_name,
        !           481:         const pa_sample_spec *ss,
        !           482:         const pa_channel_map *map,
        !           483:         const pa_buffer_attr *attr,
        !           484:         int *rerror)
        !           485: {
        !           486:     paaudio *g = &glob_paaudio;
        !           487:     int r;
        !           488:     pa_stream *stream;
        !           489: 
        !           490:     pa_threaded_mainloop_lock (g->mainloop);
        !           491: 
        !           492:     stream = pa_stream_new (g->context, name, ss, map);
        !           493:     if (!stream) {
        !           494:         goto fail;
        !           495:     }
        !           496: 
        !           497:     pa_stream_set_state_callback (stream, stream_state_cb, g);
        !           498:     pa_stream_set_read_callback (stream, stream_request_cb, g);
        !           499:     pa_stream_set_write_callback (stream, stream_request_cb, g);
        !           500: 
        !           501:     if (dir == PA_STREAM_PLAYBACK) {
        !           502:         r = pa_stream_connect_playback (stream, dev, attr,
        !           503:                                         PA_STREAM_INTERPOLATE_TIMING
        !           504: #ifdef PA_STREAM_ADJUST_LATENCY
        !           505:                                         |PA_STREAM_ADJUST_LATENCY
        !           506: #endif
        !           507:                                         |PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL);
        !           508:     } else {
        !           509:         r = pa_stream_connect_record (stream, dev, attr,
        !           510:                                       PA_STREAM_INTERPOLATE_TIMING
        !           511: #ifdef PA_STREAM_ADJUST_LATENCY
        !           512:                                       |PA_STREAM_ADJUST_LATENCY
        !           513: #endif
        !           514:                                       |PA_STREAM_AUTO_TIMING_UPDATE);
        !           515:     }
        !           516: 
        !           517:     if (r < 0) {
        !           518:       goto fail;
        !           519:     }
        !           520: 
        !           521:     pa_threaded_mainloop_unlock (g->mainloop);
        !           522: 
        !           523:     return stream;
        !           524: 
        !           525: fail:
        !           526:     pa_threaded_mainloop_unlock (g->mainloop);
        !           527: 
        !           528:     if (stream) {
        !           529:         pa_stream_unref (stream);
        !           530:     }
        !           531: 
        !           532:     *rerror = pa_context_errno (g->context);
        !           533: 
        !           534:     return NULL;
        !           535: }
        !           536: 
1.1       root      537: static int qpa_init_out (HWVoiceOut *hw, struct audsettings *as)
                    538: {
                    539:     int error;
                    540:     static pa_sample_spec ss;
1.1.1.4   root      541:     static pa_buffer_attr ba;
1.1       root      542:     struct audsettings obt_as = *as;
                    543:     PAVoiceOut *pa = (PAVoiceOut *) hw;
                    544: 
                    545:     ss.format = audfmt_to_pa (as->fmt, as->endianness);
                    546:     ss.channels = as->nchannels;
                    547:     ss.rate = as->freq;
                    548: 
1.1.1.4   root      549:     /*
                    550:      * qemu audio tick runs at 250 Hz (by default), so processing
                    551:      * data chunks worth 4 ms of sound should be a good fit.
                    552:      */
                    553:     ba.tlength = pa_usec_to_bytes (4 * 1000, &ss);
                    554:     ba.minreq = pa_usec_to_bytes (2 * 1000, &ss);
                    555:     ba.maxlength = -1;
                    556:     ba.prebuf = -1;
                    557: 
1.1       root      558:     obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
                    559: 
1.1.1.6 ! root      560:     pa->stream = qpa_simple_new (
        !           561:         glob_paaudio.server,
1.1       root      562:         "qemu",
                    563:         PA_STREAM_PLAYBACK,
1.1.1.6 ! root      564:         glob_paaudio.sink,
1.1       root      565:         "pcm.playback",
                    566:         &ss,
                    567:         NULL,                   /* channel map */
1.1.1.4   root      568:         &ba,                    /* buffering attributes */
1.1       root      569:         &error
                    570:         );
1.1.1.6 ! root      571:     if (!pa->stream) {
1.1       root      572:         qpa_logerr (error, "pa_simple_new for playback failed\n");
                    573:         goto fail1;
                    574:     }
                    575: 
                    576:     audio_pcm_init_info (&hw->info, &obt_as);
1.1.1.6 ! root      577:     hw->samples = glob_paaudio.samples;
1.1       root      578:     pa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
1.1.1.4   root      579:     pa->rpos = hw->rpos;
1.1       root      580:     if (!pa->pcm_buf) {
                    581:         dolog ("Could not allocate buffer (%d bytes)\n",
                    582:                hw->samples << hw->info.shift);
                    583:         goto fail2;
                    584:     }
                    585: 
                    586:     if (audio_pt_init (&pa->pt, qpa_thread_out, hw, AUDIO_CAP, AUDIO_FUNC)) {
                    587:         goto fail3;
                    588:     }
                    589: 
                    590:     return 0;
                    591: 
                    592:  fail3:
1.1.1.5   root      593:     g_free (pa->pcm_buf);
1.1       root      594:     pa->pcm_buf = NULL;
                    595:  fail2:
1.1.1.6 ! root      596:     if (pa->stream) {
        !           597:         pa_stream_unref (pa->stream);
        !           598:         pa->stream = NULL;
        !           599:     }
1.1       root      600:  fail1:
                    601:     return -1;
                    602: }
                    603: 
                    604: static int qpa_init_in (HWVoiceIn *hw, struct audsettings *as)
                    605: {
                    606:     int error;
                    607:     static pa_sample_spec ss;
                    608:     struct audsettings obt_as = *as;
                    609:     PAVoiceIn *pa = (PAVoiceIn *) hw;
                    610: 
                    611:     ss.format = audfmt_to_pa (as->fmt, as->endianness);
                    612:     ss.channels = as->nchannels;
                    613:     ss.rate = as->freq;
                    614: 
                    615:     obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
                    616: 
1.1.1.6 ! root      617:     pa->stream = qpa_simple_new (
        !           618:         glob_paaudio.server,
1.1       root      619:         "qemu",
                    620:         PA_STREAM_RECORD,
1.1.1.6 ! root      621:         glob_paaudio.source,
1.1       root      622:         "pcm.capture",
                    623:         &ss,
                    624:         NULL,                   /* channel map */
                    625:         NULL,                   /* buffering attributes */
                    626:         &error
                    627:         );
1.1.1.6 ! root      628:     if (!pa->stream) {
1.1       root      629:         qpa_logerr (error, "pa_simple_new for capture failed\n");
                    630:         goto fail1;
                    631:     }
                    632: 
                    633:     audio_pcm_init_info (&hw->info, &obt_as);
1.1.1.6 ! root      634:     hw->samples = glob_paaudio.samples;
1.1       root      635:     pa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
1.1.1.4   root      636:     pa->wpos = hw->wpos;
1.1       root      637:     if (!pa->pcm_buf) {
                    638:         dolog ("Could not allocate buffer (%d bytes)\n",
                    639:                hw->samples << hw->info.shift);
                    640:         goto fail2;
                    641:     }
                    642: 
                    643:     if (audio_pt_init (&pa->pt, qpa_thread_in, hw, AUDIO_CAP, AUDIO_FUNC)) {
                    644:         goto fail3;
                    645:     }
                    646: 
                    647:     return 0;
                    648: 
                    649:  fail3:
1.1.1.5   root      650:     g_free (pa->pcm_buf);
1.1       root      651:     pa->pcm_buf = NULL;
                    652:  fail2:
1.1.1.6 ! root      653:     if (pa->stream) {
        !           654:         pa_stream_unref (pa->stream);
        !           655:         pa->stream = NULL;
        !           656:     }
1.1       root      657:  fail1:
                    658:     return -1;
                    659: }
                    660: 
                    661: static void qpa_fini_out (HWVoiceOut *hw)
                    662: {
                    663:     void *ret;
                    664:     PAVoiceOut *pa = (PAVoiceOut *) hw;
                    665: 
                    666:     audio_pt_lock (&pa->pt, AUDIO_FUNC);
                    667:     pa->done = 1;
                    668:     audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
                    669:     audio_pt_join (&pa->pt, &ret, AUDIO_FUNC);
                    670: 
1.1.1.6 ! root      671:     if (pa->stream) {
        !           672:         pa_stream_unref (pa->stream);
        !           673:         pa->stream = NULL;
1.1       root      674:     }
                    675: 
                    676:     audio_pt_fini (&pa->pt, AUDIO_FUNC);
1.1.1.5   root      677:     g_free (pa->pcm_buf);
1.1       root      678:     pa->pcm_buf = NULL;
                    679: }
                    680: 
                    681: static void qpa_fini_in (HWVoiceIn *hw)
                    682: {
                    683:     void *ret;
                    684:     PAVoiceIn *pa = (PAVoiceIn *) hw;
                    685: 
                    686:     audio_pt_lock (&pa->pt, AUDIO_FUNC);
                    687:     pa->done = 1;
                    688:     audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
                    689:     audio_pt_join (&pa->pt, &ret, AUDIO_FUNC);
                    690: 
1.1.1.6 ! root      691:     if (pa->stream) {
        !           692:         pa_stream_unref (pa->stream);
        !           693:         pa->stream = NULL;
1.1       root      694:     }
                    695: 
                    696:     audio_pt_fini (&pa->pt, AUDIO_FUNC);
1.1.1.5   root      697:     g_free (pa->pcm_buf);
1.1       root      698:     pa->pcm_buf = NULL;
                    699: }
                    700: 
                    701: static int qpa_ctl_out (HWVoiceOut *hw, int cmd, ...)
                    702: {
1.1.1.6 ! root      703:     PAVoiceOut *pa = (PAVoiceOut *) hw;
        !           704:     pa_operation *op;
        !           705:     pa_cvolume v;
        !           706:     paaudio *g = &glob_paaudio;
        !           707: 
        !           708: #ifdef PA_CHECK_VERSION    /* macro is present in 0.9.16+ */
        !           709:     pa_cvolume_init (&v);  /* function is present in 0.9.13+ */
        !           710: #endif
        !           711: 
        !           712:     switch (cmd) {
        !           713:     case VOICE_VOLUME:
        !           714:         {
        !           715:             SWVoiceOut *sw;
        !           716:             va_list ap;
        !           717: 
        !           718:             va_start (ap, cmd);
        !           719:             sw = va_arg (ap, SWVoiceOut *);
        !           720:             va_end (ap);
        !           721: 
        !           722:             v.channels = 2;
        !           723:             v.values[0] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.l) / UINT32_MAX;
        !           724:             v.values[1] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.r) / UINT32_MAX;
        !           725: 
        !           726:             pa_threaded_mainloop_lock (g->mainloop);
        !           727: 
        !           728:             op = pa_context_set_sink_input_volume (g->context,
        !           729:                 pa_stream_get_index (pa->stream),
        !           730:                 &v, NULL, NULL);
        !           731:             if (!op)
        !           732:                 qpa_logerr (pa_context_errno (g->context),
        !           733:                             "set_sink_input_volume() failed\n");
        !           734:             else
        !           735:                 pa_operation_unref (op);
        !           736: 
        !           737:             op = pa_context_set_sink_input_mute (g->context,
        !           738:                 pa_stream_get_index (pa->stream),
        !           739:                sw->vol.mute, NULL, NULL);
        !           740:             if (!op) {
        !           741:                 qpa_logerr (pa_context_errno (g->context),
        !           742:                             "set_sink_input_mute() failed\n");
        !           743:             } else {
        !           744:                 pa_operation_unref (op);
        !           745:             }
        !           746: 
        !           747:             pa_threaded_mainloop_unlock (g->mainloop);
        !           748:         }
        !           749:     }
1.1       root      750:     return 0;
                    751: }
                    752: 
                    753: static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...)
                    754: {
1.1.1.6 ! root      755:     PAVoiceIn *pa = (PAVoiceIn *) hw;
        !           756:     pa_operation *op;
        !           757:     pa_cvolume v;
        !           758:     paaudio *g = &glob_paaudio;
        !           759: 
        !           760: #ifdef PA_CHECK_VERSION
        !           761:     pa_cvolume_init (&v);
        !           762: #endif
        !           763: 
        !           764:     switch (cmd) {
        !           765:     case VOICE_VOLUME:
        !           766:         {
        !           767:             SWVoiceIn *sw;
        !           768:             va_list ap;
        !           769: 
        !           770:             va_start (ap, cmd);
        !           771:             sw = va_arg (ap, SWVoiceIn *);
        !           772:             va_end (ap);
        !           773: 
        !           774:             v.channels = 2;
        !           775:             v.values[0] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.l) / UINT32_MAX;
        !           776:             v.values[1] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.r) / UINT32_MAX;
        !           777: 
        !           778:             pa_threaded_mainloop_lock (g->mainloop);
        !           779: 
        !           780:             /* FIXME: use the upcoming "set_source_output_{volume,mute}" */
        !           781:             op = pa_context_set_source_volume_by_index (g->context,
        !           782:                 pa_stream_get_device_index (pa->stream),
        !           783:                 &v, NULL, NULL);
        !           784:             if (!op) {
        !           785:                 qpa_logerr (pa_context_errno (g->context),
        !           786:                             "set_source_volume() failed\n");
        !           787:             } else {
        !           788:                 pa_operation_unref(op);
        !           789:             }
        !           790: 
        !           791:             op = pa_context_set_source_mute_by_index (g->context,
        !           792:                 pa_stream_get_index (pa->stream),
        !           793:                 sw->vol.mute, NULL, NULL);
        !           794:             if (!op) {
        !           795:                 qpa_logerr (pa_context_errno (g->context),
        !           796:                             "set_source_mute() failed\n");
        !           797:             } else {
        !           798:                 pa_operation_unref (op);
        !           799:             }
        !           800: 
        !           801:             pa_threaded_mainloop_unlock (g->mainloop);
        !           802:         }
        !           803:     }
1.1       root      804:     return 0;
                    805: }
                    806: 
                    807: /* common */
                    808: static void *qpa_audio_init (void)
                    809: {
1.1.1.6 ! root      810:     paaudio *g = &glob_paaudio;
        !           811: 
        !           812:     g->mainloop = pa_threaded_mainloop_new ();
        !           813:     if (!g->mainloop) {
        !           814:         goto fail;
        !           815:     }
        !           816: 
        !           817:     g->context = pa_context_new (pa_threaded_mainloop_get_api (g->mainloop), glob_paaudio.server);
        !           818:     if (!g->context) {
        !           819:         goto fail;
        !           820:     }
        !           821: 
        !           822:     pa_context_set_state_callback (g->context, context_state_cb, g);
        !           823: 
        !           824:     if (pa_context_connect (g->context, glob_paaudio.server, 0, NULL) < 0) {
        !           825:         qpa_logerr (pa_context_errno (g->context),
        !           826:                     "pa_context_connect() failed\n");
        !           827:         goto fail;
        !           828:     }
        !           829: 
        !           830:     pa_threaded_mainloop_lock (g->mainloop);
        !           831: 
        !           832:     if (pa_threaded_mainloop_start (g->mainloop) < 0) {
        !           833:         goto unlock_and_fail;
        !           834:     }
        !           835: 
        !           836:     for (;;) {
        !           837:         pa_context_state_t state;
        !           838: 
        !           839:         state = pa_context_get_state (g->context);
        !           840: 
        !           841:         if (state == PA_CONTEXT_READY) {
        !           842:             break;
        !           843:         }
        !           844: 
        !           845:         if (!PA_CONTEXT_IS_GOOD (state)) {
        !           846:             qpa_logerr (pa_context_errno (g->context),
        !           847:                         "Wrong context state\n");
        !           848:             goto unlock_and_fail;
        !           849:         }
        !           850: 
        !           851:         /* Wait until the context is ready */
        !           852:         pa_threaded_mainloop_wait (g->mainloop);
        !           853:     }
        !           854: 
        !           855:     pa_threaded_mainloop_unlock (g->mainloop);
        !           856: 
        !           857:     return &glob_paaudio;
        !           858: 
        !           859: unlock_and_fail:
        !           860:     pa_threaded_mainloop_unlock (g->mainloop);
        !           861: fail:
        !           862:     AUD_log (AUDIO_CAP, "Failed to initialize PA context");
        !           863:     return NULL;
1.1       root      864: }
                    865: 
                    866: static void qpa_audio_fini (void *opaque)
                    867: {
1.1.1.6 ! root      868:     paaudio *g = opaque;
        !           869: 
        !           870:     if (g->mainloop) {
        !           871:         pa_threaded_mainloop_stop (g->mainloop);
        !           872:     }
        !           873: 
        !           874:     if (g->context) {
        !           875:         pa_context_disconnect (g->context);
        !           876:         pa_context_unref (g->context);
        !           877:         g->context = NULL;
        !           878:     }
        !           879: 
        !           880:     if (g->mainloop) {
        !           881:         pa_threaded_mainloop_free (g->mainloop);
        !           882:     }
        !           883: 
        !           884:     g->mainloop = NULL;
1.1       root      885: }
                    886: 
                    887: struct audio_option qpa_options[] = {
1.1.1.3   root      888:     {
                    889:         .name  = "SAMPLES",
                    890:         .tag   = AUD_OPT_INT,
1.1.1.6 ! root      891:         .valp  = &glob_paaudio.samples,
1.1.1.3   root      892:         .descr = "buffer size in samples"
                    893:     },
                    894:     {
                    895:         .name  = "SERVER",
                    896:         .tag   = AUD_OPT_STR,
1.1.1.6 ! root      897:         .valp  = &glob_paaudio.server,
1.1.1.3   root      898:         .descr = "server address"
                    899:     },
                    900:     {
                    901:         .name  = "SINK",
                    902:         .tag   = AUD_OPT_STR,
1.1.1.6 ! root      903:         .valp  = &glob_paaudio.sink,
1.1.1.3   root      904:         .descr = "sink device name"
                    905:     },
                    906:     {
                    907:         .name  = "SOURCE",
                    908:         .tag   = AUD_OPT_STR,
1.1.1.6 ! root      909:         .valp  = &glob_paaudio.source,
1.1.1.3   root      910:         .descr = "source device name"
                    911:     },
                    912:     { /* End of list */ }
1.1       root      913: };
                    914: 
                    915: static struct audio_pcm_ops qpa_pcm_ops = {
1.1.1.3   root      916:     .init_out = qpa_init_out,
                    917:     .fini_out = qpa_fini_out,
                    918:     .run_out  = qpa_run_out,
                    919:     .write    = qpa_write,
                    920:     .ctl_out  = qpa_ctl_out,
                    921: 
                    922:     .init_in  = qpa_init_in,
                    923:     .fini_in  = qpa_fini_in,
                    924:     .run_in   = qpa_run_in,
                    925:     .read     = qpa_read,
                    926:     .ctl_in   = qpa_ctl_in
1.1       root      927: };
                    928: 
                    929: struct audio_driver pa_audio_driver = {
1.1.1.3   root      930:     .name           = "pa",
                    931:     .descr          = "http://www.pulseaudio.org/",
                    932:     .options        = qpa_options,
                    933:     .init           = qpa_audio_init,
                    934:     .fini           = qpa_audio_fini,
                    935:     .pcm_ops        = &qpa_pcm_ops,
                    936:     .can_be_default = 1,
                    937:     .max_voices_out = INT_MAX,
                    938:     .max_voices_in  = INT_MAX,
                    939:     .voice_size_out = sizeof (PAVoiceOut),
1.1.1.6 ! root      940:     .voice_size_in  = sizeof (PAVoiceIn),
        !           941:     .ctl_caps       = VOICE_VOLUME_CAP
1.1       root      942: };

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.