Annotation of qemu/audio/audio.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * QEMU Audio subsystem
        !             3:  * 
        !             4:  * Copyright (c) 2003-2004 Vassili Karpov (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 <assert.h>
        !            25: #include "vl.h"
        !            26: 
        !            27: #define USE_WAV_AUDIO
        !            28: 
        !            29: #include "audio/audio_int.h"
        !            30: 
        !            31: #define dolog(...) AUD_log ("audio", __VA_ARGS__)
        !            32: #ifdef DEBUG
        !            33: #define ldebug(...) dolog (__VA_ARGS__)
        !            34: #else
        !            35: #define ldebug(...)
        !            36: #endif
        !            37: 
        !            38: #define QC_AUDIO_DRV    "QEMU_AUDIO_DRV"
        !            39: #define QC_VOICES       "QEMU_VOICES"
        !            40: #define QC_FIXED_FORMAT "QEMU_FIXED_FORMAT"
        !            41: #define QC_FIXED_FREQ   "QEMU_FIXED_FREQ"
        !            42: 
        !            43: static HWVoice *hw_voices;
        !            44: 
        !            45: AudioState audio_state = {
        !            46:     1,                          /* use fixed settings */
        !            47:     44100,                      /* fixed frequency */
        !            48:     2,                          /* fixed channels */
        !            49:     AUD_FMT_S16,                /* fixed format */
        !            50:     1,                          /* number of hw voices */
        !            51:     -1                          /* voice size */
        !            52: };
        !            53: 
        !            54: /* http://www.df.lth.se/~john_e/gems/gem002d.html */
        !            55: /* http://www.multi-platforms.com/Tips/PopCount.htm */
        !            56: uint32_t popcount (uint32_t u)
        !            57: {
        !            58:     u = ((u&0x55555555) + ((u>>1)&0x55555555));
        !            59:     u = ((u&0x33333333) + ((u>>2)&0x33333333));
        !            60:     u = ((u&0x0f0f0f0f) + ((u>>4)&0x0f0f0f0f));
        !            61:     u = ((u&0x00ff00ff) + ((u>>8)&0x00ff00ff));
        !            62:     u = ( u&0x0000ffff) + (u>>16);
        !            63:     return u;
        !            64: }
        !            65: 
        !            66: inline uint32_t lsbindex (uint32_t u)
        !            67: {
        !            68:     return popcount ((u&-u)-1);
        !            69: }
        !            70: 
        !            71: int audio_get_conf_int (const char *key, int defval)
        !            72: {
        !            73:     int val = defval;
        !            74:     char *strval;
        !            75: 
        !            76:     strval = getenv (key);
        !            77:     if (strval) {
        !            78:         val = atoi (strval);
        !            79:     }
        !            80: 
        !            81:     return val;
        !            82: }
        !            83: 
        !            84: const char *audio_get_conf_str (const char *key, const char *defval)
        !            85: {
        !            86:     const char *val = getenv (key);
        !            87:     if (!val)
        !            88:         return defval;
        !            89:     else
        !            90:         return val;
        !            91: }
        !            92: 
        !            93: void AUD_log (const char *cap, const char *fmt, ...)
        !            94: {
        !            95:     va_list ap;
        !            96:     fprintf (stderr, "%s: ", cap);
        !            97:     va_start (ap, fmt);
        !            98:     vfprintf (stderr, fmt, ap);
        !            99:     va_end (ap);
        !           100: }
        !           101: 
        !           102: /*
        !           103:  * Soft Voice
        !           104:  */
        !           105: void pcm_sw_free_resources (SWVoice *sw)
        !           106: {
        !           107:     if (sw->buf) qemu_free (sw->buf);
        !           108:     if (sw->rate) st_rate_stop (sw->rate);
        !           109:     sw->buf = NULL;
        !           110:     sw->rate = NULL;
        !           111: }
        !           112: 
        !           113: int pcm_sw_alloc_resources (SWVoice *sw)
        !           114: {
        !           115:     sw->buf = qemu_mallocz (sw->hw->samples * sizeof (st_sample_t));
        !           116:     if (!sw->buf)
        !           117:         return -1;
        !           118: 
        !           119:     sw->rate = st_rate_start (sw->freq, sw->hw->freq);
        !           120:     if (!sw->rate) {
        !           121:         qemu_free (sw->buf);
        !           122:         sw->buf = NULL;
        !           123:         return -1;
        !           124:     }
        !           125:     return 0;
        !           126: }
        !           127: 
        !           128: void pcm_sw_fini (SWVoice *sw)
        !           129: {
        !           130:     pcm_sw_free_resources (sw);
        !           131: }
        !           132: 
        !           133: int pcm_sw_init (SWVoice *sw, HWVoice *hw, int freq,
        !           134:                  int nchannels, audfmt_e fmt)
        !           135: {
        !           136:     int bits = 8, sign = 0;
        !           137: 
        !           138:     switch (fmt) {
        !           139:     case AUD_FMT_S8:
        !           140:         sign = 1;
        !           141:     case AUD_FMT_U8:
        !           142:         break;
        !           143: 
        !           144:     case AUD_FMT_S16:
        !           145:         sign = 1;
        !           146:     case AUD_FMT_U16:
        !           147:         bits = 16;
        !           148:         break;
        !           149:     }
        !           150: 
        !           151:     sw->hw = hw;
        !           152:     sw->freq = freq;
        !           153:     sw->fmt = fmt;
        !           154:     sw->nchannels = nchannels;
        !           155:     sw->shift = (nchannels == 2) + (bits == 16);
        !           156:     sw->align = (1 << sw->shift) - 1;
        !           157:     sw->left = 0;
        !           158:     sw->pos = 0;
        !           159:     sw->wpos = 0;
        !           160:     sw->live = 0;
        !           161:     sw->ratio = (sw->hw->freq * ((int64_t) INT_MAX)) / sw->freq;
        !           162:     sw->bytes_per_second = sw->freq << sw->shift;
        !           163:     sw->conv = mixeng_conv[nchannels == 2][sign][bits == 16];
        !           164: 
        !           165:     pcm_sw_free_resources (sw);
        !           166:     return pcm_sw_alloc_resources (sw);
        !           167: }
        !           168: 
        !           169: /* Hard voice */
        !           170: void pcm_hw_free_resources (HWVoice *hw)
        !           171: {
        !           172:     if (hw->mix_buf)
        !           173:         qemu_free (hw->mix_buf);
        !           174:     hw->mix_buf = NULL;
        !           175: }
        !           176: 
        !           177: int pcm_hw_alloc_resources (HWVoice *hw)
        !           178: {
        !           179:     hw->mix_buf = qemu_mallocz (hw->samples * sizeof (st_sample_t));
        !           180:     if (!hw->mix_buf)
        !           181:         return -1;
        !           182:     return 0;
        !           183: }
        !           184: 
        !           185: void pcm_hw_fini (HWVoice *hw)
        !           186: {
        !           187:     if (hw->active) {
        !           188:         ldebug ("pcm_hw_fini: %d %d %d\n", hw->freq, hw->nchannels, hw->fmt);
        !           189:         pcm_hw_free_resources (hw);
        !           190:         hw->pcm_ops->fini (hw);
        !           191:         memset (hw, 0, audio_state.drv->voice_size);
        !           192:     }
        !           193: }
        !           194: 
        !           195: void pcm_hw_gc (HWVoice *hw)
        !           196: {
        !           197:     if (hw->nb_voices)
        !           198:         return;
        !           199: 
        !           200:     pcm_hw_fini (hw);
        !           201: }
        !           202: 
        !           203: int pcm_hw_get_live (HWVoice *hw)
        !           204: {
        !           205:     int i, alive = 0, live = hw->samples;
        !           206: 
        !           207:     for (i = 0; i < hw->nb_voices; i++) {
        !           208:         if (hw->pvoice[i]->live) {
        !           209:             live = audio_MIN (hw->pvoice[i]->live, live);
        !           210:             alive += 1;
        !           211:         }
        !           212:     }
        !           213: 
        !           214:     if (alive)
        !           215:         return live;
        !           216:     else
        !           217:         return -1;
        !           218: }
        !           219: 
        !           220: int pcm_hw_get_live2 (HWVoice *hw, int *nb_active)
        !           221: {
        !           222:     int i, alive = 0, live = hw->samples;
        !           223: 
        !           224:     *nb_active = 0;
        !           225:     for (i = 0; i < hw->nb_voices; i++) {
        !           226:         if (hw->pvoice[i]->live) {
        !           227:             if (hw->pvoice[i]->live < live) {
        !           228:                 *nb_active = hw->pvoice[i]->active != 0;
        !           229:                 live = hw->pvoice[i]->live;
        !           230:             }
        !           231:             alive += 1;
        !           232:         }
        !           233:     }
        !           234: 
        !           235:     if (alive)
        !           236:         return live;
        !           237:     else
        !           238:         return -1;
        !           239: }
        !           240: 
        !           241: void pcm_hw_dec_live (HWVoice *hw, int decr)
        !           242: {
        !           243:     int i;
        !           244: 
        !           245:     for (i = 0; i < hw->nb_voices; i++) {
        !           246:         if (hw->pvoice[i]->live) {
        !           247:             hw->pvoice[i]->live -= decr;
        !           248:         }
        !           249:     }
        !           250: }
        !           251: 
        !           252: void pcm_hw_clear (HWVoice *hw, void *buf, int len)
        !           253: {
        !           254:     if (!len)
        !           255:         return;
        !           256: 
        !           257:     switch (hw->fmt) {
        !           258:     case AUD_FMT_S16:
        !           259:     case AUD_FMT_S8:
        !           260:         memset (buf, len << hw->shift, 0x00);
        !           261:         break;
        !           262: 
        !           263:     case AUD_FMT_U8:
        !           264:         memset (buf, len << hw->shift, 0x80);
        !           265:         break;
        !           266: 
        !           267:     case AUD_FMT_U16:
        !           268:         {
        !           269:             unsigned int i;
        !           270:             uint16_t *p = buf;
        !           271:             int shift = hw->nchannels - 1;
        !           272: 
        !           273:             for (i = 0; i < len << shift; i++) {
        !           274:                 p[i] = INT16_MAX;
        !           275:             }
        !           276:         }
        !           277:         break;
        !           278:     }
        !           279: }
        !           280: 
        !           281: int pcm_hw_write (SWVoice *sw, void *buf, int size)
        !           282: {
        !           283:     int hwsamples, samples, isamp, osamp, wpos, live, dead, left, swlim, blck;
        !           284:     int ret = 0, pos = 0;
        !           285:     if (!sw)
        !           286:         return size;
        !           287: 
        !           288:     hwsamples = sw->hw->samples;
        !           289:     samples = size >> sw->shift;
        !           290: 
        !           291:     if (!sw->live) {
        !           292:         sw->wpos = sw->hw->rpos;
        !           293:     }
        !           294:     wpos = sw->wpos;
        !           295:     live = sw->live;
        !           296:     dead = hwsamples - live;
        !           297:     swlim = (dead * ((int64_t) INT_MAX)) / sw->ratio;
        !           298:     swlim = audio_MIN (swlim, samples);
        !           299: 
        !           300:     ldebug ("size=%d live=%d dead=%d swlim=%d wpos=%d\n",
        !           301:            size, live, dead, swlim, wpos);
        !           302:     if (swlim)
        !           303:         sw->conv (sw->buf, buf, swlim);
        !           304: 
        !           305:     while (swlim) {
        !           306:         dead = hwsamples - live;
        !           307:         left = hwsamples - wpos;
        !           308:         blck = audio_MIN (dead, left);
        !           309:         if (!blck) {
        !           310:             /* dolog ("swlim=%d\n", swlim); */
        !           311:             break;
        !           312:         }
        !           313:         isamp = swlim;
        !           314:         osamp = blck;
        !           315:         st_rate_flow (sw->rate, sw->buf + pos, sw->hw->mix_buf + wpos, &isamp, &osamp);
        !           316:         ret += isamp;
        !           317:         swlim -= isamp;
        !           318:         pos += isamp;
        !           319:         live += osamp;
        !           320:         wpos = (wpos + osamp) % hwsamples;
        !           321:     }
        !           322: 
        !           323:     sw->wpos = wpos;
        !           324:     sw->live = live;
        !           325:     return ret << sw->shift;
        !           326: }
        !           327: 
        !           328: int pcm_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)
        !           329: {
        !           330:     int sign = 0, bits = 8;
        !           331: 
        !           332:     pcm_hw_fini (hw);
        !           333:     ldebug ("pcm_hw_init: %d %d %d\n", freq, nchannels, fmt);
        !           334:     if (hw->pcm_ops->init (hw, freq, nchannels, fmt)) {
        !           335:         memset (hw, 0, audio_state.drv->voice_size);
        !           336:         return -1;
        !           337:     }
        !           338: 
        !           339:     switch (hw->fmt) {
        !           340:     case AUD_FMT_S8:
        !           341:         sign = 1;
        !           342:     case AUD_FMT_U8:
        !           343:         break;
        !           344: 
        !           345:     case AUD_FMT_S16:
        !           346:         sign = 1;
        !           347:     case AUD_FMT_U16:
        !           348:         bits = 16;
        !           349:         break;
        !           350:     }
        !           351: 
        !           352:     hw->nb_voices = 0;
        !           353:     hw->active = 1;
        !           354:     hw->shift = (hw->nchannels == 2) + (bits == 16);
        !           355:     hw->bytes_per_second = hw->freq << hw->shift;
        !           356:     hw->align = (1 << hw->shift) - 1;
        !           357:     hw->samples = hw->bufsize >> hw->shift;
        !           358:     hw->clip = mixeng_clip[hw->nchannels == 2][sign][bits == 16];
        !           359:     if (pcm_hw_alloc_resources (hw)) {
        !           360:         pcm_hw_fini (hw);
        !           361:         return -1;
        !           362:     }
        !           363:     return 0;
        !           364: }
        !           365: 
        !           366: static int dist (void *hw)
        !           367: {
        !           368:     if (hw) {
        !           369:         return (((uint8_t *) hw - (uint8_t *) hw_voices)
        !           370:                 / audio_state.drv->voice_size) + 1;
        !           371:     }
        !           372:     else {
        !           373:         return 0;
        !           374:     }
        !           375: }
        !           376: 
        !           377: #define ADVANCE(hw) \
        !           378:     ((hw) ? advance (hw, audio_state.drv->voice_size) : hw_voices)
        !           379: 
        !           380: HWVoice *pcm_hw_find_any (HWVoice *hw)
        !           381: {
        !           382:     int i = dist (hw);
        !           383:     for (; i < audio_state.nb_hw_voices; i++) {
        !           384:         hw = ADVANCE (hw);
        !           385:         return hw;
        !           386:     }
        !           387:     return NULL;
        !           388: }
        !           389: 
        !           390: HWVoice *pcm_hw_find_any_active (HWVoice *hw)
        !           391: {
        !           392:     int i = dist (hw);
        !           393:     for (; i < audio_state.nb_hw_voices; i++) {
        !           394:         hw = ADVANCE (hw);
        !           395:         if (hw->active)
        !           396:             return hw;
        !           397:     }
        !           398:     return NULL;
        !           399: }
        !           400: 
        !           401: HWVoice *pcm_hw_find_any_active_enabled (HWVoice *hw)
        !           402: {
        !           403:     int i = dist (hw);
        !           404:     for (; i < audio_state.nb_hw_voices; i++) {
        !           405:         hw = ADVANCE (hw);
        !           406:         if (hw->active && hw->enabled)
        !           407:             return hw;
        !           408:     }
        !           409:     return NULL;
        !           410: }
        !           411: 
        !           412: HWVoice *pcm_hw_find_any_passive (HWVoice *hw)
        !           413: {
        !           414:     int i = dist (hw);
        !           415:     for (; i < audio_state.nb_hw_voices; i++) {
        !           416:         hw = ADVANCE (hw);
        !           417:         if (!hw->active)
        !           418:             return hw;
        !           419:     }
        !           420:     return NULL;
        !           421: }
        !           422: 
        !           423: HWVoice *pcm_hw_find_specific (HWVoice *hw, int freq,
        !           424:                                int nchannels, audfmt_e fmt)
        !           425: {
        !           426:     while ((hw = pcm_hw_find_any_active (hw))) {
        !           427:         if (hw->freq == freq &&
        !           428:             hw->nchannels == nchannels &&
        !           429:             hw->fmt == fmt)
        !           430:             return hw;
        !           431:     }
        !           432:     return NULL;
        !           433: }
        !           434: 
        !           435: HWVoice *pcm_hw_add (int freq, int nchannels, audfmt_e fmt)
        !           436: {
        !           437:     HWVoice *hw;
        !           438: 
        !           439:     if (audio_state.fixed_format) {
        !           440:         freq = audio_state.fixed_freq;
        !           441:         nchannels = audio_state.fixed_channels;
        !           442:         fmt = audio_state.fixed_fmt;
        !           443:     }
        !           444: 
        !           445:     hw = pcm_hw_find_specific (NULL, freq, nchannels, fmt);
        !           446: 
        !           447:     if (hw)
        !           448:         return hw;
        !           449: 
        !           450:     hw = pcm_hw_find_any_passive (NULL);
        !           451:     if (hw) {
        !           452:         hw->pcm_ops = audio_state.drv->pcm_ops;
        !           453:         if (!hw->pcm_ops)
        !           454:             return NULL;
        !           455: 
        !           456:         if (pcm_hw_init (hw, freq, nchannels, fmt)) {
        !           457:             pcm_hw_gc (hw);
        !           458:             return NULL;
        !           459:         }
        !           460:         else
        !           461:             return hw;
        !           462:     }
        !           463: 
        !           464:     return pcm_hw_find_any (NULL);
        !           465: }
        !           466: 
        !           467: int pcm_hw_add_sw (HWVoice *hw, SWVoice *sw)
        !           468: {
        !           469:     SWVoice **pvoice = qemu_mallocz ((hw->nb_voices + 1) * sizeof (sw));
        !           470:     if (!pvoice)
        !           471:         return -1;
        !           472: 
        !           473:     memcpy (pvoice, hw->pvoice, hw->nb_voices * sizeof (sw));
        !           474:     qemu_free (hw->pvoice);
        !           475:     hw->pvoice = pvoice;
        !           476:     hw->pvoice[hw->nb_voices++] = sw;
        !           477:     return 0;
        !           478: }
        !           479: 
        !           480: int pcm_hw_del_sw (HWVoice *hw, SWVoice *sw)
        !           481: {
        !           482:     int i, j;
        !           483:     if (hw->nb_voices > 1) {
        !           484:         SWVoice **pvoice = qemu_mallocz ((hw->nb_voices - 1) * sizeof (sw));
        !           485: 
        !           486:         if (!pvoice) {
        !           487:             dolog ("Can not maintain consistent state (not enough memory)\n");
        !           488:             return -1;
        !           489:         }
        !           490: 
        !           491:         for (i = 0, j = 0; i < hw->nb_voices; i++) {
        !           492:             if (j >= hw->nb_voices - 1) {
        !           493:                 dolog ("Can not maintain consistent state "
        !           494:                        "(invariant violated)\n");
        !           495:                 return -1;
        !           496:             }
        !           497:             if (hw->pvoice[i] != sw)
        !           498:                 pvoice[j++] = hw->pvoice[i];
        !           499:         }
        !           500:         qemu_free (hw->pvoice);
        !           501:         hw->pvoice = pvoice;
        !           502:         hw->nb_voices -= 1;
        !           503:     }
        !           504:     else {
        !           505:         qemu_free (hw->pvoice);
        !           506:         hw->pvoice = NULL;
        !           507:         hw->nb_voices = 0;
        !           508:     }
        !           509:     return 0;
        !           510: }
        !           511: 
        !           512: SWVoice *pcm_create_voice_pair (int freq, int nchannels, audfmt_e fmt)
        !           513: {
        !           514:     SWVoice *sw;
        !           515:     HWVoice *hw;
        !           516: 
        !           517:     sw = qemu_mallocz (sizeof (*sw));
        !           518:     if (!sw)
        !           519:         goto err1;
        !           520: 
        !           521:     hw = pcm_hw_add (freq, nchannels, fmt);
        !           522:     if (!hw)
        !           523:         goto err2;
        !           524: 
        !           525:     if (pcm_hw_add_sw (hw, sw))
        !           526:         goto err3;
        !           527: 
        !           528:     if (pcm_sw_init (sw, hw, freq, nchannels, fmt))
        !           529:         goto err4;
        !           530: 
        !           531:     return sw;
        !           532: 
        !           533: err4:
        !           534:     pcm_hw_del_sw (hw, sw);
        !           535: err3:
        !           536:     pcm_hw_gc (hw);
        !           537: err2:
        !           538:     qemu_free (sw);
        !           539: err1:
        !           540:     return NULL;
        !           541: }
        !           542: 
        !           543: SWVoice *AUD_open (SWVoice *sw, const char *name,
        !           544:                    int freq, int nchannels, audfmt_e fmt)
        !           545: {
        !           546:     if (!audio_state.drv) {
        !           547:         return NULL;
        !           548:     }
        !           549: 
        !           550:     if (sw && freq == sw->freq && sw->nchannels == nchannels && sw->fmt == fmt) {
        !           551:         return sw;
        !           552:     }
        !           553: 
        !           554:     if (sw) {
        !           555:         ldebug ("Different format %s %d %d %d\n",
        !           556:                 name,
        !           557:                 sw->freq == freq,
        !           558:                 sw->nchannels == nchannels,
        !           559:                 sw->fmt == fmt);
        !           560:     }
        !           561: 
        !           562:     if (nchannels != 1 && nchannels != 2) {
        !           563:         dolog ("Bogus channel count %d for voice %s\n", nchannels, name);
        !           564:         return NULL;
        !           565:     }
        !           566: 
        !           567:     if (!audio_state.fixed_format && sw) {
        !           568:         pcm_sw_fini (sw);
        !           569:         pcm_hw_del_sw (sw->hw, sw);
        !           570:         pcm_hw_gc (sw->hw);
        !           571:         if (sw->name) {
        !           572:             qemu_free (sw->name);
        !           573:             sw->name = NULL;
        !           574:         }
        !           575:         qemu_free (sw);
        !           576:         sw = NULL;
        !           577:     }
        !           578: 
        !           579:     if (sw) {
        !           580:         HWVoice *hw = sw->hw;
        !           581:         if (!hw) {
        !           582:             dolog ("Internal logic error voice %s has no hardware store\n",
        !           583:                    name);
        !           584:             return sw;
        !           585:         }
        !           586: 
        !           587:         if (pcm_sw_init (sw, hw, freq, nchannels, fmt)) {
        !           588:             pcm_sw_fini (sw);
        !           589:             pcm_hw_del_sw (hw, sw);
        !           590:             pcm_hw_gc (hw);
        !           591:             if (sw->name) {
        !           592:                 qemu_free (sw->name);
        !           593:                 sw->name = NULL;
        !           594:             }
        !           595:             qemu_free (sw);
        !           596:             return NULL;
        !           597:         }
        !           598:     }
        !           599:     else {
        !           600:         sw = pcm_create_voice_pair (freq, nchannels, fmt);
        !           601:         if (!sw) {
        !           602:             dolog ("Failed to create voice %s\n", name);
        !           603:             return NULL;
        !           604:         }
        !           605:     }
        !           606: 
        !           607:     if (sw->name) {
        !           608:         qemu_free (sw->name);
        !           609:         sw->name = NULL;
        !           610:     }
        !           611:     sw->name = qemu_strdup (name);
        !           612:     return sw;
        !           613: }
        !           614: 
        !           615: void AUD_close (SWVoice *sw)
        !           616: {
        !           617:     if (!sw)
        !           618:         return;
        !           619: 
        !           620:     pcm_sw_fini (sw);
        !           621:     pcm_hw_del_sw (sw->hw, sw);
        !           622:     pcm_hw_gc (sw->hw);
        !           623:     if (sw->name) {
        !           624:         qemu_free (sw->name);
        !           625:         sw->name = NULL;
        !           626:     }
        !           627:     qemu_free (sw);
        !           628: }
        !           629: 
        !           630: int AUD_write (SWVoice *sw, void *buf, int size)
        !           631: {
        !           632:     int bytes;
        !           633: 
        !           634:     if (!sw->hw->enabled)
        !           635:         dolog ("Writing to disabled voice %s\n", sw->name);
        !           636:     bytes = sw->hw->pcm_ops->write (sw, buf, size);
        !           637:     return bytes;
        !           638: }
        !           639: 
        !           640: void AUD_run (void)
        !           641: {
        !           642:     HWVoice *hw = NULL;
        !           643: 
        !           644:     while ((hw = pcm_hw_find_any_active_enabled (hw))) {
        !           645:         int i;
        !           646:         if (hw->pending_disable && pcm_hw_get_live (hw) <= 0) {
        !           647:             hw->enabled = 0;
        !           648:             hw->pcm_ops->ctl (hw, VOICE_DISABLE);
        !           649:             for (i = 0; i < hw->nb_voices; i++) {
        !           650:                 hw->pvoice[i]->live = 0;
        !           651:                 /* hw->pvoice[i]->old_ticks = 0; */
        !           652:             }
        !           653:             continue;
        !           654:         }
        !           655: 
        !           656:         hw->pcm_ops->run (hw);
        !           657:         assert (hw->rpos < hw->samples);
        !           658:         for (i = 0; i < hw->nb_voices; i++) {
        !           659:             SWVoice *sw = hw->pvoice[i];
        !           660:             if (!sw->active && !sw->live && sw->old_ticks) {
        !           661:                 int64_t delta = qemu_get_clock (vm_clock) - sw->old_ticks;
        !           662:                 if (delta > audio_state.ticks_threshold) {
        !           663:                     ldebug ("resetting old_ticks for %s\n", sw->name);
        !           664:                     sw->old_ticks = 0;
        !           665:                 }
        !           666:             }
        !           667:         }
        !           668:     }
        !           669: }
        !           670: 
        !           671: int AUD_get_free (SWVoice *sw)
        !           672: {
        !           673:     int free;
        !           674: 
        !           675:     if (!sw)
        !           676:         return 4096;
        !           677: 
        !           678:     free = ((sw->hw->samples - sw->live) << sw->hw->shift) * sw->ratio
        !           679:         / INT_MAX;
        !           680: 
        !           681:     free &= ~sw->hw->align;
        !           682:     if (!free) return 0;
        !           683: 
        !           684:     return free;
        !           685: }
        !           686: 
        !           687: int AUD_get_buffer_size (SWVoice *sw)
        !           688: {
        !           689:     return sw->hw->bufsize;
        !           690: }
        !           691: 
        !           692: void AUD_adjust (SWVoice *sw, int bytes)
        !           693: {
        !           694:     if (!sw)
        !           695:         return;
        !           696:     sw->old_ticks += (ticks_per_sec * (int64_t) bytes) / sw->bytes_per_second;
        !           697: }
        !           698: 
        !           699: void AUD_reset (SWVoice *sw)
        !           700: {
        !           701:     sw->active = 0;
        !           702:     sw->old_ticks = 0;
        !           703: }
        !           704: 
        !           705: int AUD_calc_elapsed (SWVoice *sw)
        !           706: {
        !           707:     int64_t now, delta, bytes;
        !           708:     int dead, swlim;
        !           709: 
        !           710:     if (!sw)
        !           711:         return 0;
        !           712: 
        !           713:     now = qemu_get_clock (vm_clock);
        !           714:     delta = now - sw->old_ticks;
        !           715:     bytes = (delta * sw->bytes_per_second) / ticks_per_sec;
        !           716:     if (delta < 0) {
        !           717:         dolog ("whoops delta(<0)=%lld\n", delta);
        !           718:         return 0;
        !           719:     }
        !           720: 
        !           721:     dead = sw->hw->samples - sw->live;
        !           722:     swlim = ((dead * (int64_t) INT_MAX) / sw->ratio);
        !           723: 
        !           724:     if (bytes > swlim) {
        !           725:         return swlim;
        !           726:     }
        !           727:     else {
        !           728:         return bytes;
        !           729:     }
        !           730: }
        !           731: 
        !           732: void AUD_enable (SWVoice *sw, int on)
        !           733: {
        !           734:     int i;
        !           735:     HWVoice *hw;
        !           736: 
        !           737:     if (!sw)
        !           738:         return;
        !           739: 
        !           740:     hw = sw->hw;
        !           741:     if (on) {
        !           742:         if (!sw->live)
        !           743:             sw->wpos = sw->hw->rpos;
        !           744:         if (!sw->old_ticks) {
        !           745:             sw->old_ticks = qemu_get_clock (vm_clock);
        !           746:         }
        !           747:     }
        !           748: 
        !           749:     if (sw->active != on) {
        !           750:         if (on) {
        !           751:             hw->pending_disable = 0;
        !           752:             if (!hw->enabled) {
        !           753:                 hw->enabled = 1;
        !           754:                 for (i = 0; i < hw->nb_voices; i++) {
        !           755:                     ldebug ("resetting voice\n");
        !           756:                     sw = hw->pvoice[i];
        !           757:                     sw->old_ticks = qemu_get_clock (vm_clock);
        !           758:                 }
        !           759:                 hw->pcm_ops->ctl (hw, VOICE_ENABLE);
        !           760:             }
        !           761:         }
        !           762:         else {
        !           763:             if (hw->enabled && !hw->pending_disable) {
        !           764:                 int nb_active = 0;
        !           765:                 for (i = 0; i < hw->nb_voices; i++) {
        !           766:                     nb_active += hw->pvoice[i]->active != 0;
        !           767:                 }
        !           768: 
        !           769:                 if (nb_active == 1) {
        !           770:                     hw->pending_disable = 1;
        !           771:                 }
        !           772:             }
        !           773:         }
        !           774:         sw->active = on;
        !           775:     }
        !           776: }
        !           777: 
        !           778: static struct audio_output_driver *drvtab[] = {
        !           779: #ifdef CONFIG_OSS
        !           780:     &oss_output_driver,
        !           781: #endif
        !           782: #ifdef CONFIG_FMOD
        !           783:     &fmod_output_driver,
        !           784: #endif
        !           785: #ifdef CONFIG_SDL
        !           786:     &sdl_output_driver,
        !           787: #endif
        !           788:     &no_output_driver,
        !           789: #ifdef USE_WAV_AUDIO
        !           790:     &wav_output_driver,
        !           791: #endif
        !           792: };
        !           793: 
        !           794: static int voice_init (struct audio_output_driver *drv)
        !           795: {
        !           796:     audio_state.opaque = drv->init ();
        !           797:     if (audio_state.opaque) {
        !           798:         if (audio_state.nb_hw_voices > drv->max_voices) {
        !           799:             dolog ("`%s' does not support %d multiple hardware channels\n"
        !           800:                    "Resetting to %d\n",
        !           801:                    drv->name, audio_state.nb_hw_voices, drv->max_voices);
        !           802:             audio_state.nb_hw_voices = drv->max_voices;
        !           803:         }
        !           804:         hw_voices = qemu_mallocz (audio_state.nb_hw_voices * drv->voice_size);
        !           805:         if (hw_voices) {
        !           806:             audio_state.drv = drv;
        !           807:             return 1;
        !           808:         }
        !           809:         else {
        !           810:             dolog ("Not enough memory for %d `%s' voices (each %d bytes)\n",
        !           811:                    audio_state.nb_hw_voices, drv->name, drv->voice_size);
        !           812:             drv->fini (audio_state.opaque);
        !           813:             return 0;
        !           814:         }
        !           815:     }
        !           816:     else {
        !           817:         dolog ("Could not init `%s' audio\n", drv->name);
        !           818:         return 0;
        !           819:     }
        !           820: }
        !           821: 
        !           822: static void audio_vm_stop_handler (void *opaque, int reason)
        !           823: {
        !           824:     HWVoice *hw = NULL;
        !           825: 
        !           826:     while ((hw = pcm_hw_find_any (hw))) {
        !           827:         if (!hw->pcm_ops)
        !           828:             continue;
        !           829: 
        !           830:         hw->pcm_ops->ctl (hw, reason ? VOICE_ENABLE : VOICE_DISABLE);
        !           831:     }
        !           832: }
        !           833: 
        !           834: static void audio_atexit (void)
        !           835: {
        !           836:     HWVoice *hw = NULL;
        !           837: 
        !           838:     while ((hw = pcm_hw_find_any (hw))) {
        !           839:         if (!hw->pcm_ops)
        !           840:             continue;
        !           841: 
        !           842:         hw->pcm_ops->ctl (hw, VOICE_DISABLE);
        !           843:         hw->pcm_ops->fini (hw);
        !           844:     }
        !           845:     audio_state.drv->fini (audio_state.opaque);
        !           846: }
        !           847: 
        !           848: static void audio_save (QEMUFile *f, void *opaque)
        !           849: {
        !           850: }
        !           851: 
        !           852: static int audio_load (QEMUFile *f, void *opaque, int version_id)
        !           853: {
        !           854:     if (version_id != 1)
        !           855:         return -EINVAL;
        !           856: 
        !           857:     return 0;
        !           858: }
        !           859: 
        !           860: void AUD_init (void)
        !           861: {
        !           862:     int i;
        !           863:     int done = 0;
        !           864:     const char *drvname;
        !           865: 
        !           866:     audio_state.fixed_format =
        !           867:         !!audio_get_conf_int (QC_FIXED_FORMAT, audio_state.fixed_format);
        !           868:     audio_state.fixed_freq =
        !           869:         audio_get_conf_int (QC_FIXED_FREQ, audio_state.fixed_freq);
        !           870:     audio_state.nb_hw_voices =
        !           871:         audio_get_conf_int (QC_VOICES, audio_state.nb_hw_voices);
        !           872: 
        !           873:     if (audio_state.nb_hw_voices <= 0) {
        !           874:         dolog ("Bogus number of voices %d, resetting to 1\n",
        !           875:                audio_state.nb_hw_voices);
        !           876:     }
        !           877: 
        !           878:     drvname = audio_get_conf_str (QC_AUDIO_DRV, NULL);
        !           879:     if (drvname) {
        !           880:         int found = 0;
        !           881:         for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
        !           882:             if (!strcmp (drvname, drvtab[i]->name)) {
        !           883:                 done = voice_init (drvtab[i]);
        !           884:                 found = 1;
        !           885:                 break;
        !           886:             }
        !           887:         }
        !           888:         if (!found) {
        !           889:             dolog ("Unknown audio driver `%s'\n", drvname);
        !           890:         }
        !           891:     }
        !           892: 
        !           893:     qemu_add_vm_stop_handler (audio_vm_stop_handler, NULL);
        !           894:     atexit (audio_atexit);
        !           895: 
        !           896:     if (!done) {
        !           897:         for (i = 0; !done && i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
        !           898:             if (drvtab[i]->can_be_default)
        !           899:                 done = voice_init (drvtab[i]);
        !           900:         }
        !           901:     }
        !           902: 
        !           903:     audio_state.ticks_threshold = ticks_per_sec / 50;
        !           904:     audio_state.freq_threshold = 100;
        !           905: 
        !           906:     register_savevm ("audio", 0, 1, audio_save, audio_load, NULL);
        !           907:     if (!done) {
        !           908:         dolog ("Can not initialize audio subsystem\n");
        !           909:         voice_init (&no_output_driver);
        !           910:     }
        !           911: }

unix.superglobalmegacorp.com

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