Annotation of qemu/audio/esdaudio.c, revision 1.1.1.3

1.1       root        1: /*
                      2:  * QEMU ESD audio driver
                      3:  *
                      4:  * Copyright (c) 2006 Frederick Reeve (brushed up by malc)
                      5:  *
                      6:  * Permission is hereby granted, free of charge, to any person obtaining a copy
                      7:  * of this software and associated documentation files (the "Software"), to deal
                      8:  * in the Software without restriction, including without limitation the rights
                      9:  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
                     10:  * copies of the Software, and to permit persons to whom the Software is
                     11:  * furnished to do so, subject to the following conditions:
                     12:  *
                     13:  * The above copyright notice and this permission notice shall be included in
                     14:  * all copies or substantial portions of the Software.
                     15:  *
                     16:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
                     17:  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
                     18:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
                     19:  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
                     20:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
                     21:  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
                     22:  * THE SOFTWARE.
                     23:  */
                     24: #include <esd.h>
                     25: #include "qemu-common.h"
                     26: #include "audio.h"
                     27: 
                     28: #define AUDIO_CAP "esd"
                     29: #include "audio_int.h"
                     30: #include "audio_pt_int.h"
                     31: 
                     32: typedef struct {
                     33:     HWVoiceOut hw;
                     34:     int done;
                     35:     int live;
                     36:     int decr;
                     37:     int rpos;
                     38:     void *pcm_buf;
                     39:     int fd;
                     40:     struct audio_pt pt;
                     41: } ESDVoiceOut;
                     42: 
                     43: typedef struct {
                     44:     HWVoiceIn hw;
                     45:     int done;
                     46:     int dead;
                     47:     int incr;
                     48:     int wpos;
                     49:     void *pcm_buf;
                     50:     int fd;
                     51:     struct audio_pt pt;
                     52: } ESDVoiceIn;
                     53: 
                     54: static struct {
                     55:     int samples;
                     56:     int divisor;
                     57:     char *dac_host;
                     58:     char *adc_host;
                     59: } conf = {
1.1.1.2   root       60:     .samples = 1024,
                     61:     .divisor = 2,
1.1       root       62: };
                     63: 
                     64: static void GCC_FMT_ATTR (2, 3) qesd_logerr (int err, const char *fmt, ...)
                     65: {
                     66:     va_list ap;
                     67: 
                     68:     va_start (ap, fmt);
                     69:     AUD_vlog (AUDIO_CAP, fmt, ap);
                     70:     va_end (ap);
                     71: 
                     72:     AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err));
                     73: }
                     74: 
                     75: /* playback */
                     76: static void *qesd_thread_out (void *arg)
                     77: {
                     78:     ESDVoiceOut *esd = arg;
                     79:     HWVoiceOut *hw = &esd->hw;
                     80:     int threshold;
                     81: 
                     82:     threshold = conf.divisor ? hw->samples / conf.divisor : 0;
                     83: 
                     84:     if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
                     85:         return NULL;
                     86:     }
                     87: 
                     88:     for (;;) {
                     89:         int decr, to_mix, rpos;
                     90: 
                     91:         for (;;) {
                     92:             if (esd->done) {
                     93:                 goto exit;
                     94:             }
                     95: 
                     96:             if (esd->live > threshold) {
                     97:                 break;
                     98:             }
                     99: 
                    100:             if (audio_pt_wait (&esd->pt, AUDIO_FUNC)) {
                    101:                 goto exit;
                    102:             }
                    103:         }
                    104: 
                    105:         decr = to_mix = esd->live;
                    106:         rpos = hw->rpos;
                    107: 
                    108:         if (audio_pt_unlock (&esd->pt, AUDIO_FUNC)) {
                    109:             return NULL;
                    110:         }
                    111: 
                    112:         while (to_mix) {
                    113:             ssize_t written;
                    114:             int chunk = audio_MIN (to_mix, hw->samples - rpos);
                    115:             struct st_sample *src = hw->mix_buf + rpos;
                    116: 
                    117:             hw->clip (esd->pcm_buf, src, chunk);
                    118: 
                    119:         again:
                    120:             written = write (esd->fd, esd->pcm_buf, chunk << hw->info.shift);
                    121:             if (written == -1) {
                    122:                 if (errno == EINTR || errno == EAGAIN) {
                    123:                     goto again;
                    124:                 }
                    125:                 qesd_logerr (errno, "write failed\n");
                    126:                 return NULL;
                    127:             }
                    128: 
                    129:             if (written != chunk << hw->info.shift) {
                    130:                 int wsamples = written >> hw->info.shift;
                    131:                 int wbytes = wsamples << hw->info.shift;
                    132:                 if (wbytes != written) {
1.1.1.2   root      133:                     dolog ("warning: Misaligned write %d (requested %zd), "
1.1       root      134:                            "alignment %d\n",
                    135:                            wbytes, written, hw->info.align + 1);
                    136:                 }
                    137:                 to_mix -= wsamples;
                    138:                 rpos = (rpos + wsamples) % hw->samples;
                    139:                 break;
                    140:             }
                    141: 
                    142:             rpos = (rpos + chunk) % hw->samples;
                    143:             to_mix -= chunk;
                    144:         }
                    145: 
                    146:         if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
                    147:             return NULL;
                    148:         }
                    149: 
                    150:         esd->rpos = rpos;
                    151:         esd->live -= decr;
                    152:         esd->decr += decr;
                    153:     }
                    154: 
                    155:  exit:
                    156:     audio_pt_unlock (&esd->pt, AUDIO_FUNC);
                    157:     return NULL;
                    158: }
                    159: 
1.1.1.2   root      160: static int qesd_run_out (HWVoiceOut *hw, int live)
1.1       root      161: {
1.1.1.2   root      162:     int decr;
1.1       root      163:     ESDVoiceOut *esd = (ESDVoiceOut *) hw;
                    164: 
                    165:     if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
                    166:         return 0;
                    167:     }
                    168: 
                    169:     decr = audio_MIN (live, esd->decr);
                    170:     esd->decr -= decr;
                    171:     esd->live = live - decr;
                    172:     hw->rpos = esd->rpos;
                    173:     if (esd->live > 0) {
                    174:         audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
                    175:     }
                    176:     else {
                    177:         audio_pt_unlock (&esd->pt, AUDIO_FUNC);
                    178:     }
                    179:     return decr;
                    180: }
                    181: 
                    182: static int qesd_write (SWVoiceOut *sw, void *buf, int len)
                    183: {
                    184:     return audio_pcm_sw_write (sw, buf, len);
                    185: }
                    186: 
                    187: static int qesd_init_out (HWVoiceOut *hw, struct audsettings *as)
                    188: {
                    189:     ESDVoiceOut *esd = (ESDVoiceOut *) hw;
                    190:     struct audsettings obt_as = *as;
                    191:     int esdfmt = ESD_STREAM | ESD_PLAY;
                    192: 
                    193:     esdfmt |= (as->nchannels == 2) ? ESD_STEREO : ESD_MONO;
                    194:     switch (as->fmt) {
                    195:     case AUD_FMT_S8:
                    196:     case AUD_FMT_U8:
                    197:         esdfmt |= ESD_BITS8;
                    198:         obt_as.fmt = AUD_FMT_U8;
                    199:         break;
                    200: 
                    201:     case AUD_FMT_S32:
                    202:     case AUD_FMT_U32:
                    203:         dolog ("Will use 16 instead of 32 bit samples\n");
                    204: 
                    205:     case AUD_FMT_S16:
                    206:     case AUD_FMT_U16:
                    207:     deffmt:
                    208:         esdfmt |= ESD_BITS16;
                    209:         obt_as.fmt = AUD_FMT_S16;
                    210:         break;
                    211: 
                    212:     default:
                    213:         dolog ("Internal logic error: Bad audio format %d\n", as->fmt);
                    214:         goto deffmt;
                    215: 
                    216:     }
                    217:     obt_as.endianness = AUDIO_HOST_ENDIANNESS;
                    218: 
                    219:     audio_pcm_init_info (&hw->info, &obt_as);
                    220: 
                    221:     hw->samples = conf.samples;
                    222:     esd->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
                    223:     if (!esd->pcm_buf) {
                    224:         dolog ("Could not allocate buffer (%d bytes)\n",
                    225:                hw->samples << hw->info.shift);
                    226:         return -1;
                    227:     }
                    228: 
                    229:     esd->fd = esd_play_stream (esdfmt, as->freq, conf.dac_host, NULL);
                    230:     if (esd->fd < 0) {
                    231:         qesd_logerr (errno, "esd_play_stream failed\n");
1.1.1.3 ! root      232:         goto fail1;
1.1       root      233:     }
                    234: 
                    235:     if (audio_pt_init (&esd->pt, qesd_thread_out, esd, AUDIO_CAP, AUDIO_FUNC)) {
1.1.1.3 ! root      236:         goto fail2;
1.1       root      237:     }
                    238: 
                    239:     return 0;
                    240: 
1.1.1.3 ! root      241:  fail2:
1.1       root      242:     if (close (esd->fd)) {
                    243:         qesd_logerr (errno, "%s: close on esd socket(%d) failed\n",
                    244:                      AUDIO_FUNC, esd->fd);
                    245:     }
                    246:     esd->fd = -1;
                    247: 
                    248:  fail1:
                    249:     qemu_free (esd->pcm_buf);
                    250:     esd->pcm_buf = NULL;
                    251:     return -1;
                    252: }
                    253: 
                    254: static void qesd_fini_out (HWVoiceOut *hw)
                    255: {
                    256:     void *ret;
                    257:     ESDVoiceOut *esd = (ESDVoiceOut *) hw;
                    258: 
                    259:     audio_pt_lock (&esd->pt, AUDIO_FUNC);
                    260:     esd->done = 1;
                    261:     audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
                    262:     audio_pt_join (&esd->pt, &ret, AUDIO_FUNC);
                    263: 
                    264:     if (esd->fd >= 0) {
                    265:         if (close (esd->fd)) {
                    266:             qesd_logerr (errno, "failed to close esd socket\n");
                    267:         }
                    268:         esd->fd = -1;
                    269:     }
                    270: 
                    271:     audio_pt_fini (&esd->pt, AUDIO_FUNC);
                    272: 
                    273:     qemu_free (esd->pcm_buf);
                    274:     esd->pcm_buf = NULL;
                    275: }
                    276: 
                    277: static int qesd_ctl_out (HWVoiceOut *hw, int cmd, ...)
                    278: {
                    279:     (void) hw;
                    280:     (void) cmd;
                    281:     return 0;
                    282: }
                    283: 
                    284: /* capture */
                    285: static void *qesd_thread_in (void *arg)
                    286: {
                    287:     ESDVoiceIn *esd = arg;
                    288:     HWVoiceIn *hw = &esd->hw;
                    289:     int threshold;
                    290: 
                    291:     threshold = conf.divisor ? hw->samples / conf.divisor : 0;
                    292: 
                    293:     if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
                    294:         return NULL;
                    295:     }
                    296: 
                    297:     for (;;) {
                    298:         int incr, to_grab, wpos;
                    299: 
                    300:         for (;;) {
                    301:             if (esd->done) {
                    302:                 goto exit;
                    303:             }
                    304: 
                    305:             if (esd->dead > threshold) {
                    306:                 break;
                    307:             }
                    308: 
                    309:             if (audio_pt_wait (&esd->pt, AUDIO_FUNC)) {
                    310:                 goto exit;
                    311:             }
                    312:         }
                    313: 
                    314:         incr = to_grab = esd->dead;
                    315:         wpos = hw->wpos;
                    316: 
                    317:         if (audio_pt_unlock (&esd->pt, AUDIO_FUNC)) {
                    318:             return NULL;
                    319:         }
                    320: 
                    321:         while (to_grab) {
                    322:             ssize_t nread;
                    323:             int chunk = audio_MIN (to_grab, hw->samples - wpos);
                    324:             void *buf = advance (esd->pcm_buf, wpos);
                    325: 
                    326:         again:
                    327:             nread = read (esd->fd, buf, chunk << hw->info.shift);
                    328:             if (nread == -1) {
                    329:                 if (errno == EINTR || errno == EAGAIN) {
                    330:                     goto again;
                    331:                 }
                    332:                 qesd_logerr (errno, "read failed\n");
                    333:                 return NULL;
                    334:             }
                    335: 
                    336:             if (nread != chunk << hw->info.shift) {
                    337:                 int rsamples = nread >> hw->info.shift;
                    338:                 int rbytes = rsamples << hw->info.shift;
                    339:                 if (rbytes != nread) {
1.1.1.2   root      340:                     dolog ("warning: Misaligned write %d (requested %zd), "
1.1       root      341:                            "alignment %d\n",
                    342:                            rbytes, nread, hw->info.align + 1);
                    343:                 }
                    344:                 to_grab -= rsamples;
                    345:                 wpos = (wpos + rsamples) % hw->samples;
                    346:                 break;
                    347:             }
                    348: 
1.1.1.3 ! root      349:             hw->conv (hw->conv_buf + wpos, buf, nread >> hw->info.shift);
1.1       root      350:             wpos = (wpos + chunk) % hw->samples;
                    351:             to_grab -= chunk;
                    352:         }
                    353: 
                    354:         if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
                    355:             return NULL;
                    356:         }
                    357: 
                    358:         esd->wpos = wpos;
                    359:         esd->dead -= incr;
                    360:         esd->incr += incr;
                    361:     }
                    362: 
                    363:  exit:
                    364:     audio_pt_unlock (&esd->pt, AUDIO_FUNC);
                    365:     return NULL;
                    366: }
                    367: 
                    368: static int qesd_run_in (HWVoiceIn *hw)
                    369: {
                    370:     int live, incr, dead;
                    371:     ESDVoiceIn *esd = (ESDVoiceIn *) hw;
                    372: 
                    373:     if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
                    374:         return 0;
                    375:     }
                    376: 
                    377:     live = audio_pcm_hw_get_live_in (hw);
                    378:     dead = hw->samples - live;
                    379:     incr = audio_MIN (dead, esd->incr);
                    380:     esd->incr -= incr;
                    381:     esd->dead = dead - incr;
                    382:     hw->wpos = esd->wpos;
                    383:     if (esd->dead > 0) {
                    384:         audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
                    385:     }
                    386:     else {
                    387:         audio_pt_unlock (&esd->pt, AUDIO_FUNC);
                    388:     }
                    389:     return incr;
                    390: }
                    391: 
                    392: static int qesd_read (SWVoiceIn *sw, void *buf, int len)
                    393: {
                    394:     return audio_pcm_sw_read (sw, buf, len);
                    395: }
                    396: 
                    397: static int qesd_init_in (HWVoiceIn *hw, struct audsettings *as)
                    398: {
                    399:     ESDVoiceIn *esd = (ESDVoiceIn *) hw;
                    400:     struct audsettings obt_as = *as;
                    401:     int esdfmt = ESD_STREAM | ESD_RECORD;
                    402: 
                    403:     esdfmt |= (as->nchannels == 2) ? ESD_STEREO : ESD_MONO;
                    404:     switch (as->fmt) {
                    405:     case AUD_FMT_S8:
                    406:     case AUD_FMT_U8:
                    407:         esdfmt |= ESD_BITS8;
                    408:         obt_as.fmt = AUD_FMT_U8;
                    409:         break;
                    410: 
                    411:     case AUD_FMT_S16:
                    412:     case AUD_FMT_U16:
                    413:         esdfmt |= ESD_BITS16;
                    414:         obt_as.fmt = AUD_FMT_S16;
                    415:         break;
                    416: 
                    417:     case AUD_FMT_S32:
                    418:     case AUD_FMT_U32:
                    419:         dolog ("Will use 16 instead of 32 bit samples\n");
                    420:         esdfmt |= ESD_BITS16;
                    421:         obt_as.fmt = AUD_FMT_S16;
                    422:         break;
                    423:     }
                    424:     obt_as.endianness = AUDIO_HOST_ENDIANNESS;
                    425: 
                    426:     audio_pcm_init_info (&hw->info, &obt_as);
                    427: 
                    428:     hw->samples = conf.samples;
                    429:     esd->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
                    430:     if (!esd->pcm_buf) {
                    431:         dolog ("Could not allocate buffer (%d bytes)\n",
                    432:                hw->samples << hw->info.shift);
                    433:         return -1;
                    434:     }
                    435: 
                    436:     esd->fd = esd_record_stream (esdfmt, as->freq, conf.adc_host, NULL);
                    437:     if (esd->fd < 0) {
                    438:         qesd_logerr (errno, "esd_record_stream failed\n");
1.1.1.3 ! root      439:         goto fail1;
1.1       root      440:     }
                    441: 
                    442:     if (audio_pt_init (&esd->pt, qesd_thread_in, esd, AUDIO_CAP, AUDIO_FUNC)) {
1.1.1.3 ! root      443:         goto fail2;
1.1       root      444:     }
                    445: 
                    446:     return 0;
                    447: 
1.1.1.3 ! root      448:  fail2:
1.1       root      449:     if (close (esd->fd)) {
                    450:         qesd_logerr (errno, "%s: close on esd socket(%d) failed\n",
                    451:                      AUDIO_FUNC, esd->fd);
                    452:     }
                    453:     esd->fd = -1;
                    454: 
                    455:  fail1:
                    456:     qemu_free (esd->pcm_buf);
                    457:     esd->pcm_buf = NULL;
                    458:     return -1;
                    459: }
                    460: 
                    461: static void qesd_fini_in (HWVoiceIn *hw)
                    462: {
                    463:     void *ret;
                    464:     ESDVoiceIn *esd = (ESDVoiceIn *) hw;
                    465: 
                    466:     audio_pt_lock (&esd->pt, AUDIO_FUNC);
                    467:     esd->done = 1;
                    468:     audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
                    469:     audio_pt_join (&esd->pt, &ret, AUDIO_FUNC);
                    470: 
                    471:     if (esd->fd >= 0) {
                    472:         if (close (esd->fd)) {
                    473:             qesd_logerr (errno, "failed to close esd socket\n");
                    474:         }
                    475:         esd->fd = -1;
                    476:     }
                    477: 
                    478:     audio_pt_fini (&esd->pt, AUDIO_FUNC);
                    479: 
                    480:     qemu_free (esd->pcm_buf);
                    481:     esd->pcm_buf = NULL;
                    482: }
                    483: 
                    484: static int qesd_ctl_in (HWVoiceIn *hw, int cmd, ...)
                    485: {
                    486:     (void) hw;
                    487:     (void) cmd;
                    488:     return 0;
                    489: }
                    490: 
                    491: /* common */
                    492: static void *qesd_audio_init (void)
                    493: {
                    494:     return &conf;
                    495: }
                    496: 
                    497: static void qesd_audio_fini (void *opaque)
                    498: {
                    499:     (void) opaque;
                    500:     ldebug ("esd_fini");
                    501: }
                    502: 
                    503: struct audio_option qesd_options[] = {
1.1.1.2   root      504:     {
                    505:         .name  = "SAMPLES",
                    506:         .tag   = AUD_OPT_INT,
                    507:         .valp  = &conf.samples,
                    508:         .descr = "buffer size in samples"
                    509:     },
                    510:     {
                    511:         .name  = "DIVISOR",
                    512:         .tag   = AUD_OPT_INT,
                    513:         .valp  = &conf.divisor,
                    514:         .descr = "threshold divisor"
                    515:     },
                    516:     {
                    517:         .name  = "DAC_HOST",
                    518:         .tag   = AUD_OPT_STR,
                    519:         .valp  = &conf.dac_host,
                    520:         .descr = "playback host"
                    521:     },
                    522:     {
                    523:         .name  = "ADC_HOST",
                    524:         .tag   = AUD_OPT_STR,
                    525:         .valp  = &conf.adc_host,
                    526:         .descr = "capture host"
                    527:     },
                    528:     { /* End of list */ }
1.1       root      529: };
                    530: 
                    531: static struct audio_pcm_ops qesd_pcm_ops = {
1.1.1.2   root      532:     .init_out = qesd_init_out,
                    533:     .fini_out = qesd_fini_out,
                    534:     .run_out  = qesd_run_out,
                    535:     .write    = qesd_write,
                    536:     .ctl_out  = qesd_ctl_out,
                    537: 
                    538:     .init_in  = qesd_init_in,
                    539:     .fini_in  = qesd_fini_in,
                    540:     .run_in   = qesd_run_in,
                    541:     .read     = qesd_read,
                    542:     .ctl_in   = qesd_ctl_in,
1.1       root      543: };
                    544: 
                    545: struct audio_driver esd_audio_driver = {
1.1.1.2   root      546:     .name           = "esd",
                    547:     .descr          = "http://en.wikipedia.org/wiki/Esound",
                    548:     .options        = qesd_options,
                    549:     .init           = qesd_audio_init,
                    550:     .fini           = qesd_audio_fini,
                    551:     .pcm_ops        = &qesd_pcm_ops,
                    552:     .can_be_default = 0,
                    553:     .max_voices_out = INT_MAX,
                    554:     .max_voices_in  = INT_MAX,
                    555:     .voice_size_out = sizeof (ESDVoiceOut),
                    556:     .voice_size_in  = sizeof (ESDVoiceIn)
1.1       root      557: };

unix.superglobalmegacorp.com

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