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

1.1       root        1: /*
                      2:  * QEMU Audio subsystem
1.1.1.2 ! root        3:  *
        !             4:  * Copyright (c) 2003-2005 Vassili Karpov (malc)
        !             5:  *
1.1       root        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 "vl.h"
                     25: 
1.1.1.2 ! root       26: #define AUDIO_CAP "audio"
        !            27: #include "audio_int.h"
1.1       root       28: 
1.1.1.2 ! root       29: /* #define DEBUG_PLIVE */
        !            30: /* #define DEBUG_LIVE */
        !            31: /* #define DEBUG_OUT */
1.1       root       32: 
1.1.1.2 ! root       33: #define SW_NAME(sw) (sw)->name ? (sw)->name : "unknown"
        !            34: 
        !            35: static struct audio_driver *drvtab[] = {
        !            36: #ifdef CONFIG_OSS
        !            37:     &oss_audio_driver,
        !            38: #endif
        !            39: #ifdef CONFIG_ALSA
        !            40:     &alsa_audio_driver,
        !            41: #endif
        !            42: #ifdef CONFIG_COREAUDIO
        !            43:     &coreaudio_audio_driver,
        !            44: #endif
        !            45: #ifdef CONFIG_DSOUND
        !            46:     &dsound_audio_driver,
        !            47: #endif
        !            48: #ifdef CONFIG_FMOD
        !            49:     &fmod_audio_driver,
1.1       root       50: #endif
1.1.1.2 ! root       51: #ifdef CONFIG_SDL
        !            52:     &sdl_audio_driver,
        !            53: #endif
        !            54:     &no_audio_driver,
        !            55:     &wav_audio_driver
        !            56: };
        !            57: 
        !            58: struct fixed_settings {
        !            59:     int enabled;
        !            60:     int nb_voices;
        !            61:     int greedy;
        !            62:     audsettings_t settings;
        !            63: };
        !            64: 
        !            65: static struct {
        !            66:     struct fixed_settings fixed_out;
        !            67:     struct fixed_settings fixed_in;
        !            68:     union {
        !            69:         int hz;
        !            70:         int64_t ticks;
        !            71:     } period;
        !            72:     int plive;
        !            73:     int log_to_monitor;
        !            74: } conf = {
        !            75:     {                           /* DAC fixed settings */
        !            76:         1,                      /* enabled */
        !            77:         1,                      /* nb_voices */
        !            78:         1,                      /* greedy */
        !            79:         {
        !            80:             44100,              /* freq */
        !            81:             2,                  /* nchannels */
        !            82:             AUD_FMT_S16         /* fmt */
        !            83:         }
        !            84:     },
        !            85: 
        !            86:     {                           /* ADC fixed settings */
        !            87:         1,                      /* enabled */
        !            88:         1,                      /* nb_voices */
        !            89:         1,                      /* greedy */
        !            90:         {
        !            91:             44100,              /* freq */
        !            92:             2,                  /* nchannels */
        !            93:             AUD_FMT_S16         /* fmt */
        !            94:         }
        !            95:     },
        !            96: 
        !            97:     { 0 },                      /* period */
        !            98:     0,                          /* plive */
        !            99:     0                           /* log_to_monitor */
        !           100: };
1.1       root      101: 
1.1.1.2 ! root      102: static AudioState glob_audio_state;
        !           103: 
        !           104: volume_t nominal_volume = {
        !           105:     0,
        !           106: #ifdef FLOAT_MIXENG
        !           107:     1.0,
        !           108:     1.0
        !           109: #else
        !           110:     UINT_MAX,
        !           111:     UINT_MAX
        !           112: #endif
1.1       root      113: };
                    114: 
                    115: /* http://www.df.lth.se/~john_e/gems/gem002d.html */
                    116: /* http://www.multi-platforms.com/Tips/PopCount.htm */
                    117: uint32_t popcount (uint32_t u)
                    118: {
                    119:     u = ((u&0x55555555) + ((u>>1)&0x55555555));
                    120:     u = ((u&0x33333333) + ((u>>2)&0x33333333));
                    121:     u = ((u&0x0f0f0f0f) + ((u>>4)&0x0f0f0f0f));
                    122:     u = ((u&0x00ff00ff) + ((u>>8)&0x00ff00ff));
                    123:     u = ( u&0x0000ffff) + (u>>16);
                    124:     return u;
                    125: }
                    126: 
                    127: inline uint32_t lsbindex (uint32_t u)
                    128: {
                    129:     return popcount ((u&-u)-1);
                    130: }
                    131: 
1.1.1.2 ! root      132: #ifdef AUDIO_IS_FLAWLESS_AND_NO_CHECKS_ARE_REQURIED
        !           133: #error No its not
        !           134: #else
        !           135: int audio_bug (const char *funcname, int cond)
        !           136: {
        !           137:     if (cond) {
        !           138:         static int shown;
        !           139: 
        !           140:         AUD_log (NULL, "Error a bug that was just triggered in %s\n", funcname);
        !           141:         if (!shown) {
        !           142:             shown = 1;
        !           143:             AUD_log (NULL, "Save all your work and restart without audio\n");
        !           144:             AUD_log (NULL, "Please send bug report to [email protected]\n");
        !           145:             AUD_log (NULL, "I am sorry\n");
        !           146:         }
        !           147:         AUD_log (NULL, "Context:\n");
        !           148: 
        !           149: #if defined AUDIO_BREAKPOINT_ON_BUG
        !           150: #  if defined HOST_I386
        !           151: #    if defined __GNUC__
        !           152:         __asm__ ("int3");
        !           153: #    elif defined _MSC_VER
        !           154:         _asm _emit 0xcc;
        !           155: #    else
        !           156:         abort ();
        !           157: #    endif
        !           158: #  else
        !           159:         abort ();
        !           160: #  endif
        !           161: #endif
        !           162:     }
        !           163: 
        !           164:     return cond;
        !           165: }
        !           166: #endif
        !           167: 
        !           168: void *audio_calloc (const char *funcname, int nmemb, size_t size)
        !           169: {
        !           170:     int cond;
        !           171:     size_t len;
        !           172: 
        !           173:     len = nmemb * size;
        !           174:     cond = !nmemb || !size;
        !           175:     cond |= nmemb < 0;
        !           176:     cond |= len < size;
        !           177: 
        !           178:     if (audio_bug ("audio_calloc", cond)) {
        !           179:         AUD_log (NULL, "%s passed invalid arguments to audio_calloc\n",
        !           180:                  funcname);
        !           181:         AUD_log (NULL, "nmemb=%d size=%zu (len=%zu)\n", nmemb, size, len);
        !           182:         return NULL;
        !           183:     }
        !           184: 
        !           185:     return qemu_mallocz (len);
        !           186: }
        !           187: 
        !           188: static char *audio_alloc_prefix (const char *s)
1.1       root      189: {
1.1.1.2 ! root      190:     const char qemu_prefix[] = "QEMU_";
        !           191:     size_t len;
        !           192:     char *r;
        !           193: 
        !           194:     if (!s) {
        !           195:         return NULL;
        !           196:     }
        !           197: 
        !           198:     len = strlen (s);
        !           199:     r = qemu_malloc (len + sizeof (qemu_prefix));
        !           200: 
        !           201:     if (r) {
        !           202:         size_t i;
        !           203:         char *u = r + sizeof (qemu_prefix) - 1;
        !           204: 
        !           205:         strcpy (r, qemu_prefix);
        !           206:         strcat (r, s);
        !           207: 
        !           208:         for (i = 0; i < len; ++i) {
        !           209:             u[i] = toupper (u[i]);
        !           210:         }
        !           211:     }
        !           212:     return r;
        !           213: }
        !           214: 
        !           215: const char *audio_audfmt_to_string (audfmt_e fmt)
        !           216: {
        !           217:     switch (fmt) {
        !           218:     case AUD_FMT_U8:
        !           219:         return "U8";
        !           220: 
        !           221:     case AUD_FMT_U16:
        !           222:         return "U16";
        !           223: 
        !           224:     case AUD_FMT_S8:
        !           225:         return "S8";
        !           226: 
        !           227:     case AUD_FMT_S16:
        !           228:         return "S16";
        !           229:     }
        !           230: 
        !           231:     dolog ("Bogus audfmt %d returning S16\n", fmt);
        !           232:     return "S16";
        !           233: }
        !           234: 
        !           235: audfmt_e audio_string_to_audfmt (const char *s, audfmt_e defval, int *defaultp)
        !           236: {
        !           237:     if (!strcasecmp (s, "u8")) {
        !           238:         *defaultp = 0;
        !           239:         return AUD_FMT_U8;
        !           240:     }
        !           241:     else if (!strcasecmp (s, "u16")) {
        !           242:         *defaultp = 0;
        !           243:         return AUD_FMT_U16;
        !           244:     }
        !           245:     else if (!strcasecmp (s, "s8")) {
        !           246:         *defaultp = 0;
        !           247:         return AUD_FMT_S8;
        !           248:     }
        !           249:     else if (!strcasecmp (s, "s16")) {
        !           250:         *defaultp = 0;
        !           251:         return AUD_FMT_S16;
        !           252:     }
        !           253:     else {
        !           254:         dolog ("Bogus audio format `%s' using %s\n",
        !           255:                s, audio_audfmt_to_string (defval));
        !           256:         *defaultp = 1;
        !           257:         return defval;
        !           258:     }
        !           259: }
        !           260: 
        !           261: static audfmt_e audio_get_conf_fmt (const char *envname,
        !           262:                                     audfmt_e defval,
        !           263:                                     int *defaultp)
        !           264: {
        !           265:     const char *var = getenv (envname);
        !           266:     if (!var) {
        !           267:         *defaultp = 1;
        !           268:         return defval;
        !           269:     }
        !           270:     return audio_string_to_audfmt (var, defval, defaultp);
        !           271: }
        !           272: 
        !           273: static int audio_get_conf_int (const char *key, int defval, int *defaultp)
        !           274: {
        !           275:     int val;
1.1       root      276:     char *strval;
                    277: 
                    278:     strval = getenv (key);
                    279:     if (strval) {
1.1.1.2 ! root      280:         *defaultp = 0;
1.1       root      281:         val = atoi (strval);
1.1.1.2 ! root      282:         return val;
        !           283:     }
        !           284:     else {
        !           285:         *defaultp = 1;
        !           286:         return defval;
1.1       root      287:     }
                    288: }
                    289: 
1.1.1.2 ! root      290: static const char *audio_get_conf_str (const char *key,
        !           291:                                        const char *defval,
        !           292:                                        int *defaultp)
1.1       root      293: {
                    294:     const char *val = getenv (key);
1.1.1.2 ! root      295:     if (!val) {
        !           296:         *defaultp = 1;
1.1       root      297:         return defval;
1.1.1.2 ! root      298:     }
        !           299:     else {
        !           300:         *defaultp = 0;
1.1       root      301:         return val;
1.1.1.2 ! root      302:     }
        !           303: }
        !           304: 
        !           305: void AUD_vlog (const char *cap, const char *fmt, va_list ap)
        !           306: {
        !           307:     if (conf.log_to_monitor) {
        !           308:         if (cap) {
        !           309:             term_printf ("%s: ", cap);
        !           310:         }
        !           311: 
        !           312:         term_vprintf (fmt, ap);
        !           313:     }
        !           314:     else {
        !           315:         if (cap) {
        !           316:             fprintf (stderr, "%s: ", cap);
        !           317:         }
        !           318: 
        !           319:         vfprintf (stderr, fmt, ap);
        !           320:     }
1.1       root      321: }
                    322: 
                    323: void AUD_log (const char *cap, const char *fmt, ...)
                    324: {
                    325:     va_list ap;
1.1.1.2 ! root      326: 
1.1       root      327:     va_start (ap, fmt);
1.1.1.2 ! root      328:     AUD_vlog (cap, fmt, ap);
1.1       root      329:     va_end (ap);
                    330: }
                    331: 
1.1.1.2 ! root      332: static void audio_print_options (const char *prefix,
        !           333:                                  struct audio_option *opt)
1.1       root      334: {
1.1.1.2 ! root      335:     char *uprefix;
        !           336: 
        !           337:     if (!prefix) {
        !           338:         dolog ("No prefix specified\n");
        !           339:         return;
        !           340:     }
        !           341: 
        !           342:     if (!opt) {
        !           343:         dolog ("No options\n");
        !           344:         return;
        !           345:     }
        !           346: 
        !           347:     uprefix = audio_alloc_prefix (prefix);
        !           348: 
        !           349:     for (; opt->name; opt++) {
        !           350:         const char *state = "default";
        !           351:         printf ("  %s_%s: ", uprefix, opt->name);
        !           352: 
        !           353:         if (opt->overridenp && *opt->overridenp) {
        !           354:             state = "current";
        !           355:         }
        !           356: 
        !           357:         switch (opt->tag) {
        !           358:         case AUD_OPT_BOOL:
        !           359:             {
        !           360:                 int *intp = opt->valp;
        !           361:                 printf ("boolean, %s = %d\n", state, *intp ? 1 : 0);
        !           362:             }
        !           363:             break;
        !           364: 
        !           365:         case AUD_OPT_INT:
        !           366:             {
        !           367:                 int *intp = opt->valp;
        !           368:                 printf ("integer, %s = %d\n", state, *intp);
        !           369:             }
        !           370:             break;
        !           371: 
        !           372:         case AUD_OPT_FMT:
        !           373:             {
        !           374:                 audfmt_e *fmtp = opt->valp;
        !           375:                 printf (
        !           376:                     "format, %s = %s, (one of: U8 S8 U16 S16)\n",
        !           377:                     state,
        !           378:                     audio_audfmt_to_string (*fmtp)
        !           379:                     );
        !           380:             }
        !           381:             break;
        !           382: 
        !           383:         case AUD_OPT_STR:
        !           384:             {
        !           385:                 const char **strp = opt->valp;
        !           386:                 printf ("string, %s = %s\n",
        !           387:                         state,
        !           388:                         *strp ? *strp : "(not set)");
        !           389:             }
        !           390:             break;
        !           391: 
        !           392:         default:
        !           393:             printf ("???\n");
        !           394:             dolog ("Bad value tag for option %s_%s %d\n",
        !           395:                    uprefix, opt->name, opt->tag);
        !           396:             break;
        !           397:         }
        !           398:         printf ("    %s\n", opt->descr);
        !           399:     }
        !           400: 
        !           401:     qemu_free (uprefix);
1.1       root      402: }
                    403: 
1.1.1.2 ! root      404: static void audio_process_options (const char *prefix,
        !           405:                                    struct audio_option *opt)
1.1       root      406: {
1.1.1.2 ! root      407:     char *optname;
        !           408:     const char qemu_prefix[] = "QEMU_";
        !           409:     size_t preflen;
        !           410: 
        !           411:     if (audio_bug (AUDIO_FUNC, !prefix)) {
        !           412:         dolog ("prefix = NULL\n");
        !           413:         return;
        !           414:     }
        !           415: 
        !           416:     if (audio_bug (AUDIO_FUNC, !opt)) {
        !           417:         dolog ("opt = NULL\n");
        !           418:         return;
        !           419:     }
        !           420: 
        !           421:     preflen = strlen (prefix);
        !           422: 
        !           423:     for (; opt->name; opt++) {
        !           424:         size_t len, i;
        !           425:         int def;
        !           426: 
        !           427:         if (!opt->valp) {
        !           428:             dolog ("Option value pointer for `%s' is not set\n",
        !           429:                    opt->name);
        !           430:             continue;
        !           431:         }
        !           432: 
        !           433:         len = strlen (opt->name);
        !           434:         /* len of opt->name + len of prefix + size of qemu_prefix
        !           435:          * (includes trailing zero) + zero + underscore (on behalf of
        !           436:          * sizeof) */
        !           437:         optname = qemu_malloc (len + preflen + sizeof (qemu_prefix) + 1);
        !           438:         if (!optname) {
        !           439:             dolog ("Could not allocate memory for option name `%s'\n",
        !           440:                    opt->name);
        !           441:             continue;
        !           442:         }
        !           443: 
        !           444:         strcpy (optname, qemu_prefix);
        !           445: 
        !           446:         /* copy while upper-casing, including trailing zero */
        !           447:         for (i = 0; i <= preflen; ++i) {
        !           448:             optname[i + sizeof (qemu_prefix) - 1] = toupper (prefix[i]);
        !           449:         }
        !           450:         strcat (optname, "_");
        !           451:         strcat (optname, opt->name);
        !           452: 
        !           453:         def = 1;
        !           454:         switch (opt->tag) {
        !           455:         case AUD_OPT_BOOL:
        !           456:         case AUD_OPT_INT:
        !           457:             {
        !           458:                 int *intp = opt->valp;
        !           459:                 *intp = audio_get_conf_int (optname, *intp, &def);
        !           460:             }
        !           461:             break;
        !           462: 
        !           463:         case AUD_OPT_FMT:
        !           464:             {
        !           465:                 audfmt_e *fmtp = opt->valp;
        !           466:                 *fmtp = audio_get_conf_fmt (optname, *fmtp, &def);
        !           467:             }
        !           468:             break;
        !           469: 
        !           470:         case AUD_OPT_STR:
        !           471:             {
        !           472:                 const char **strp = opt->valp;
        !           473:                 *strp = audio_get_conf_str (optname, *strp, &def);
        !           474:             }
        !           475:             break;
1.1       root      476: 
1.1.1.2 ! root      477:         default:
        !           478:             dolog ("Bad value tag for option `%s' - %d\n",
        !           479:                    optname, opt->tag);
        !           480:             break;
        !           481:         }
        !           482: 
        !           483:         if (!opt->overridenp) {
        !           484:             opt->overridenp = &opt->overriden;
        !           485:         }
        !           486:         *opt->overridenp = !def;
        !           487:         qemu_free (optname);
        !           488:     }
        !           489: }
        !           490: 
        !           491: static void audio_print_settings (audsettings_t *as)
        !           492: {
        !           493:     dolog ("frequency=%d nchannels=%d fmt=", as->freq, as->nchannels);
        !           494: 
        !           495:     switch (as->fmt) {
        !           496:     case AUD_FMT_S8:
        !           497:         AUD_log (NULL, "S8");
        !           498:         break;
        !           499:     case AUD_FMT_U8:
        !           500:         AUD_log (NULL, "U8");
        !           501:         break;
        !           502:     case AUD_FMT_S16:
        !           503:         AUD_log (NULL, "S16");
        !           504:         break;
        !           505:     case AUD_FMT_U16:
        !           506:         AUD_log (NULL, "U16");
        !           507:         break;
        !           508:     default:
        !           509:         AUD_log (NULL, "invalid(%d)", as->fmt);
        !           510:         break;
        !           511:     }
        !           512:     AUD_log (NULL, "\n");
        !           513: }
        !           514: 
        !           515: static int audio_validate_settigs (audsettings_t *as)
        !           516: {
        !           517:     int invalid;
        !           518: 
        !           519:     invalid = as->nchannels != 1 && as->nchannels != 2;
        !           520: 
        !           521:     switch (as->fmt) {
        !           522:     case AUD_FMT_S8:
        !           523:     case AUD_FMT_U8:
        !           524:     case AUD_FMT_S16:
        !           525:     case AUD_FMT_U16:
        !           526:         break;
        !           527:     default:
        !           528:         invalid = 1;
        !           529:         break;
        !           530:     }
        !           531: 
        !           532:     invalid |= as->freq <= 0;
        !           533: 
        !           534:     if (invalid) {
1.1       root      535:         return -1;
                    536:     }
                    537:     return 0;
                    538: }
                    539: 
1.1.1.2 ! root      540: static int audio_pcm_info_eq (struct audio_pcm_info *info, audsettings_t *as)
1.1       root      541: {
1.1.1.2 ! root      542:     int bits = 8, sign = 0;
        !           543: 
        !           544:     switch (as->fmt) {
        !           545:     case AUD_FMT_S8:
        !           546:         sign = 1;
        !           547:     case AUD_FMT_U8:
        !           548:         break;
        !           549: 
        !           550:     case AUD_FMT_S16:
        !           551:         sign = 1;
        !           552:     case AUD_FMT_U16:
        !           553:         bits = 16;
        !           554:         break;
        !           555:     }
        !           556:     return info->freq == as->freq
        !           557:         && info->nchannels == as->nchannels
        !           558:         && info->sign == sign
        !           559:         && info->bits == bits;
1.1       root      560: }
                    561: 
1.1.1.2 ! root      562: void audio_pcm_init_info (
        !           563:     struct audio_pcm_info *info,
        !           564:     audsettings_t *as,
        !           565:     int swap_endian
        !           566:     )
1.1       root      567: {
                    568:     int bits = 8, sign = 0;
                    569: 
1.1.1.2 ! root      570:     switch (as->fmt) {
1.1       root      571:     case AUD_FMT_S8:
                    572:         sign = 1;
                    573:     case AUD_FMT_U8:
                    574:         break;
                    575: 
                    576:     case AUD_FMT_S16:
                    577:         sign = 1;
                    578:     case AUD_FMT_U16:
                    579:         bits = 16;
                    580:         break;
                    581:     }
                    582: 
1.1.1.2 ! root      583:     info->freq = as->freq;
        !           584:     info->bits = bits;
        !           585:     info->sign = sign;
        !           586:     info->nchannels = as->nchannels;
        !           587:     info->shift = (as->nchannels == 2) + (bits == 16);
        !           588:     info->align = (1 << info->shift) - 1;
        !           589:     info->bytes_per_second = info->freq << info->shift;
        !           590:     info->swap_endian = swap_endian;
1.1       root      591: }
                    592: 
1.1.1.2 ! root      593: void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len)
1.1       root      594: {
1.1.1.2 ! root      595:     if (!len) {
        !           596:         return;
        !           597:     }
        !           598: 
        !           599:     if (info->sign) {
        !           600:         memset (buf, len << info->shift, 0x00);
        !           601:     }
        !           602:     else {
        !           603:         if (info->bits == 8) {
        !           604:             memset (buf, len << info->shift, 0x80);
        !           605:         }
        !           606:         else {
        !           607:             int i;
        !           608:             uint16_t *p = buf;
        !           609:             int shift = info->nchannels - 1;
        !           610:             short s = INT16_MAX;
        !           611: 
        !           612:             if (info->swap_endian) {
        !           613:                 s = bswap16 (s);
        !           614:             }
        !           615: 
        !           616:             for (i = 0; i < len << shift; i++) {
        !           617:                 p[i] = s;
        !           618:             }
        !           619:         }
        !           620:     }
1.1       root      621: }
                    622: 
1.1.1.2 ! root      623: /*
        !           624:  * Hard voice (capture)
        !           625:  */
        !           626: static int audio_pcm_hw_find_min_in (HWVoiceIn *hw)
1.1       root      627: {
1.1.1.2 ! root      628:     SWVoiceIn *sw;
        !           629:     int m = hw->total_samples_captured;
        !           630: 
        !           631:     for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
        !           632:         if (sw->active) {
        !           633:             m = audio_MIN (m, sw->total_hw_samples_acquired);
        !           634:         }
1.1       root      635:     }
1.1.1.2 ! root      636:     return m;
1.1       root      637: }
                    638: 
1.1.1.2 ! root      639: int audio_pcm_hw_get_live_in (HWVoiceIn *hw)
1.1       root      640: {
1.1.1.2 ! root      641:     int live = hw->total_samples_captured - audio_pcm_hw_find_min_in (hw);
        !           642:     if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) {
        !           643:         dolog ("live=%d hw->samples=%d\n", live, hw->samples);
        !           644:         return 0;
        !           645:     }
        !           646:     return live;
1.1       root      647: }
                    648: 
1.1.1.2 ! root      649: /*
        !           650:  * Soft voice (capture)
        !           651:  */
        !           652: static int audio_pcm_sw_get_rpos_in (SWVoiceIn *sw)
1.1       root      653: {
1.1.1.2 ! root      654:     HWVoiceIn *hw = sw->hw;
        !           655:     int live = hw->total_samples_captured - sw->total_hw_samples_acquired;
        !           656:     int rpos;
1.1       root      657: 
1.1.1.2 ! root      658:     if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) {
        !           659:         dolog ("live=%d hw->samples=%d\n", live, hw->samples);
        !           660:         return 0;
1.1       root      661:     }
                    662: 
1.1.1.2 ! root      663:     rpos = hw->wpos - live;
        !           664:     if (rpos >= 0) {
        !           665:         return rpos;
        !           666:     }
        !           667:     else {
        !           668:         return hw->samples + rpos;
        !           669:     }
1.1       root      670: }
                    671: 
1.1.1.2 ! root      672: int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int size)
1.1       root      673: {
1.1.1.2 ! root      674:     HWVoiceIn *hw = sw->hw;
        !           675:     int samples, live, ret = 0, swlim, isamp, osamp, rpos, total = 0;
        !           676:     st_sample_t *src, *dst = sw->buf;
1.1       root      677: 
1.1.1.2 ! root      678:     rpos = audio_pcm_sw_get_rpos_in (sw) % hw->samples;
        !           679: 
        !           680:     live = hw->total_samples_captured - sw->total_hw_samples_acquired;
        !           681:     if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) {
        !           682:         dolog ("live_in=%d hw->samples=%d\n", live, hw->samples);
        !           683:         return 0;
        !           684:     }
        !           685: 
        !           686:     samples = size >> sw->info.shift;
        !           687:     if (!live) {
        !           688:         return 0;
        !           689:     }
        !           690: 
        !           691:     swlim = (live * sw->ratio) >> 32;
        !           692:     swlim = audio_MIN (swlim, samples);
        !           693: 
        !           694:     while (swlim) {
        !           695:         src = hw->conv_buf + rpos;
        !           696:         isamp = hw->wpos - rpos;
        !           697:         /* XXX: <= ? */
        !           698:         if (isamp <= 0) {
        !           699:             isamp = hw->samples - rpos;
1.1       root      700:         }
1.1.1.2 ! root      701: 
        !           702:         if (!isamp) {
        !           703:             break;
        !           704:         }
        !           705:         osamp = swlim;
        !           706: 
        !           707:         if (audio_bug (AUDIO_FUNC, osamp < 0)) {
        !           708:             dolog ("osamp=%d\n", osamp);
        !           709:             return 0;
        !           710:         }
        !           711: 
        !           712:         st_rate_flow (sw->rate, src, dst, &isamp, &osamp);
        !           713:         swlim -= osamp;
        !           714:         rpos = (rpos + isamp) % hw->samples;
        !           715:         dst += osamp;
        !           716:         ret += osamp;
        !           717:         total += isamp;
1.1       root      718:     }
                    719: 
1.1.1.2 ! root      720:     sw->clip (buf, sw->buf, ret);
        !           721:     sw->total_hw_samples_acquired += total;
        !           722:     return ret << sw->info.shift;
1.1       root      723: }
                    724: 
1.1.1.2 ! root      725: /*
        !           726:  * Hard voice (playback)
        !           727:  */
        !           728: static int audio_pcm_hw_find_min_out (HWVoiceOut *hw, int *nb_livep)
1.1       root      729: {
1.1.1.2 ! root      730:     SWVoiceOut *sw;
        !           731:     int m = INT_MAX;
        !           732:     int nb_live = 0;
1.1       root      733: 
1.1.1.2 ! root      734:     for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
        !           735:         if (sw->active || !sw->empty) {
        !           736:             m = audio_MIN (m, sw->total_hw_samples_mixed);
        !           737:             nb_live += 1;
1.1       root      738:         }
                    739:     }
1.1.1.2 ! root      740: 
        !           741:     *nb_livep = nb_live;
        !           742:     return m;
1.1       root      743: }
                    744: 
1.1.1.2 ! root      745: int audio_pcm_hw_get_live_out2 (HWVoiceOut *hw, int *nb_live)
1.1       root      746: {
1.1.1.2 ! root      747:     int smin;
1.1       root      748: 
1.1.1.2 ! root      749:     smin = audio_pcm_hw_find_min_out (hw, nb_live);
1.1       root      750: 
1.1.1.2 ! root      751:     if (!*nb_live) {
        !           752:         return 0;
        !           753:     }
        !           754:     else {
        !           755:         int live = smin;
1.1       root      756: 
1.1.1.2 ! root      757:         if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) {
        !           758:             dolog ("live=%d hw->samples=%d\n", live, hw->samples);
        !           759:             return 0;
1.1       root      760:         }
1.1.1.2 ! root      761:         return live;
1.1       root      762:     }
                    763: }
                    764: 
1.1.1.2 ! root      765: int audio_pcm_hw_get_live_out (HWVoiceOut *hw)
        !           766: {
        !           767:     int nb_live;
        !           768:     int live;
        !           769: 
        !           770:     live = audio_pcm_hw_get_live_out2 (hw, &nb_live);
        !           771:     if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) {
        !           772:         dolog ("live=%d hw->samples=%d\n", live, hw->samples);
        !           773:         return 0;
        !           774:     }
        !           775:     return live;
        !           776: }
        !           777: 
        !           778: /*
        !           779:  * Soft voice (playback)
        !           780:  */
        !           781: int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int size)
1.1       root      782: {
                    783:     int hwsamples, samples, isamp, osamp, wpos, live, dead, left, swlim, blck;
1.1.1.2 ! root      784:     int ret = 0, pos = 0, total = 0;
        !           785: 
        !           786:     if (!sw) {
1.1       root      787:         return size;
1.1.1.2 ! root      788:     }
1.1       root      789: 
                    790:     hwsamples = sw->hw->samples;
                    791: 
1.1.1.2 ! root      792:     live = sw->total_hw_samples_mixed;
        !           793:     if (audio_bug (AUDIO_FUNC, live < 0 || live > hwsamples)){
        !           794:         dolog ("live=%d hw->samples=%d\n", live, hwsamples);
        !           795:         return 0;
1.1       root      796:     }
1.1.1.2 ! root      797: 
        !           798:     if (live == hwsamples) {
        !           799:         return 0;
        !           800:     }
        !           801: 
        !           802:     wpos = (sw->hw->rpos + live) % hwsamples;
        !           803:     samples = size >> sw->info.shift;
        !           804: 
1.1       root      805:     dead = hwsamples - live;
1.1.1.2 ! root      806:     swlim = ((int64_t) dead << 32) / sw->ratio;
1.1       root      807:     swlim = audio_MIN (swlim, samples);
1.1.1.2 ! root      808:     if (swlim) {
        !           809:         sw->conv (sw->buf, buf, swlim, &sw->vol);
        !           810:     }
1.1       root      811: 
                    812:     while (swlim) {
                    813:         dead = hwsamples - live;
                    814:         left = hwsamples - wpos;
                    815:         blck = audio_MIN (dead, left);
                    816:         if (!blck) {
                    817:             break;
                    818:         }
                    819:         isamp = swlim;
                    820:         osamp = blck;
1.1.1.2 ! root      821:         st_rate_flow_mix (
        !           822:             sw->rate,
        !           823:             sw->buf + pos,
        !           824:             sw->hw->mix_buf + wpos,
        !           825:             &isamp,
        !           826:             &osamp
        !           827:             );
1.1       root      828:         ret += isamp;
                    829:         swlim -= isamp;
                    830:         pos += isamp;
                    831:         live += osamp;
1.1.1.2 ! root      832:         wpos = (wpos + osamp) % hwsamples;
        !           833:         total += osamp;
1.1       root      834:     }
                    835: 
1.1.1.2 ! root      836:     sw->total_hw_samples_mixed += total;
        !           837:     sw->empty = sw->total_hw_samples_mixed == 0;
1.1       root      838: 
1.1.1.2 ! root      839: #ifdef DEBUG_OUT
        !           840:     dolog (
        !           841:         "%s: write size %d ret %d total sw %d\n",
        !           842:         SW_NAME (sw),
        !           843:         size >> sw->info.shift,
        !           844:         ret,
        !           845:         sw->total_hw_samples_mixed
        !           846:         );
        !           847: #endif
1.1       root      848: 
1.1.1.2 ! root      849:     return ret << sw->info.shift;
1.1       root      850: }
                    851: 
1.1.1.2 ! root      852: #ifdef DEBUG_AUDIO
        !           853: static void audio_pcm_print_info (const char *cap, struct audio_pcm_info *info)
1.1       root      854: {
1.1.1.2 ! root      855:     dolog ("%s: bits %d, sign %d, freq %d, nchan %d\n",
        !           856:            cap, info->bits, info->sign, info->freq, info->nchannels);
1.1       root      857: }
1.1.1.2 ! root      858: #endif
1.1       root      859: 
1.1.1.2 ! root      860: #define DAC
        !           861: #include "audio_template.h"
        !           862: #undef DAC
        !           863: #include "audio_template.h"
1.1       root      864: 
1.1.1.2 ! root      865: int AUD_write (SWVoiceOut *sw, void *buf, int size)
1.1       root      866: {
1.1.1.2 ! root      867:     int bytes;
        !           868: 
        !           869:     if (!sw) {
        !           870:         /* XXX: Consider options */
        !           871:         return size;
1.1       root      872:     }
                    873: 
1.1.1.2 ! root      874:     if (!sw->hw->enabled) {
        !           875:         dolog ("Writing to disabled voice %s\n", SW_NAME (sw));
        !           876:         return 0;
1.1       root      877:     }
1.1.1.2 ! root      878: 
        !           879:     bytes = sw->hw->pcm_ops->write (sw, buf, size);
        !           880:     return bytes;
1.1       root      881: }
                    882: 
1.1.1.2 ! root      883: int AUD_read (SWVoiceIn *sw, void *buf, int size)
1.1       root      884: {
1.1.1.2 ! root      885:     int bytes;
        !           886: 
        !           887:     if (!sw) {
        !           888:         /* XXX: Consider options */
        !           889:         return size;
1.1       root      890:     }
                    891: 
1.1.1.2 ! root      892:     if (!sw->hw->enabled) {
        !           893:         dolog ("Reading from disabled voice %s\n", SW_NAME (sw));
        !           894:         return 0;
1.1       root      895:     }
1.1.1.2 ! root      896: 
        !           897:     bytes = sw->hw->pcm_ops->read (sw, buf, size);
        !           898:     return bytes;
1.1       root      899: }
                    900: 
1.1.1.2 ! root      901: int AUD_get_buffer_size_out (SWVoiceOut *sw)
1.1       root      902: {
1.1.1.2 ! root      903:     return sw->hw->samples << sw->hw->info.shift;
1.1       root      904: }
                    905: 
1.1.1.2 ! root      906: void AUD_set_active_out (SWVoiceOut *sw, int on)
1.1       root      907: {
1.1.1.2 ! root      908:     HWVoiceOut *hw;
1.1       root      909: 
1.1.1.2 ! root      910:     if (!sw) {
        !           911:         return;
1.1       root      912:     }
                    913: 
1.1.1.2 ! root      914:     hw = sw->hw;
        !           915:     if (sw->active != on) {
        !           916:         SWVoiceOut *temp_sw;
1.1       root      917: 
1.1.1.2 ! root      918:         if (on) {
        !           919:             int total;
1.1       root      920: 
1.1.1.2 ! root      921:             hw->pending_disable = 0;
        !           922:             if (!hw->enabled) {
        !           923:                 hw->enabled = 1;
        !           924:                 hw->pcm_ops->ctl_out (hw, VOICE_ENABLE);
        !           925:             }
1.1       root      926: 
1.1.1.2 ! root      927:             if (sw->empty) {
        !           928:                 total = 0;
        !           929:             }
1.1       root      930:         }
1.1.1.2 ! root      931:         else {
        !           932:             if (hw->enabled) {
        !           933:                 int nb_active = 0;
        !           934: 
        !           935:                 for (temp_sw = hw->sw_head.lh_first; temp_sw;
        !           936:                      temp_sw = temp_sw->entries.le_next) {
        !           937:                     nb_active += temp_sw->active != 0;
        !           938:                 }
1.1       root      939: 
1.1.1.2 ! root      940:                 hw->pending_disable = nb_active == 1;
        !           941:             }
        !           942:         }
        !           943:         sw->active = on;
        !           944:     }
1.1       root      945: }
                    946: 
1.1.1.2 ! root      947: void AUD_set_active_in (SWVoiceIn *sw, int on)
1.1       root      948: {
1.1.1.2 ! root      949:     HWVoiceIn *hw;
1.1       root      950: 
1.1.1.2 ! root      951:     if (!sw) {
        !           952:         return;
        !           953:     }
1.1       root      954: 
1.1.1.2 ! root      955:     hw = sw->hw;
        !           956:     if (sw->active != on) {
        !           957:         SWVoiceIn *temp_sw;
1.1       root      958: 
1.1.1.2 ! root      959:         if (on) {
        !           960:             if (!hw->enabled) {
        !           961:                 hw->enabled = 1;
        !           962:                 hw->pcm_ops->ctl_in (hw, VOICE_ENABLE);
        !           963:             }
        !           964:             sw->total_hw_samples_acquired = hw->total_samples_captured;
1.1       root      965:         }
1.1.1.2 ! root      966:         else {
        !           967:             if (hw->enabled) {
        !           968:                 int nb_active = 0;
        !           969: 
        !           970:                 for (temp_sw = hw->sw_head.lh_first; temp_sw;
        !           971:                      temp_sw = temp_sw->entries.le_next) {
        !           972:                     nb_active += temp_sw->active != 0;
        !           973:                 }
1.1       root      974: 
1.1.1.2 ! root      975:                 if (nb_active == 1) {
        !           976:                     hw->enabled = 0;
        !           977:                     hw->pcm_ops->ctl_in (hw, VOICE_DISABLE);
        !           978:                 }
1.1       root      979:             }
                    980:         }
1.1.1.2 ! root      981:         sw->active = on;
1.1       root      982:     }
1.1.1.2 ! root      983: }
        !           984: 
        !           985: static int audio_get_avail (SWVoiceIn *sw)
        !           986: {
        !           987:     int live;
        !           988: 
        !           989:     if (!sw) {
        !           990:         return 0;
1.1       root      991:     }
1.1.1.2 ! root      992: 
        !           993:     live = sw->hw->total_samples_captured - sw->total_hw_samples_acquired;
        !           994:     if (audio_bug (AUDIO_FUNC, live < 0 || live > sw->hw->samples)) {
        !           995:         dolog ("live=%d sw->hw->samples=%d\n", live, sw->hw->samples);
        !           996:         return 0;
        !           997:     }
        !           998: 
        !           999:     ldebug (
        !          1000:         "%s: get_avail live %d ret %lld\n",
        !          1001:         SW_NAME (sw),
        !          1002:         live, (((int64_t) live << 32) / sw->ratio) << sw->info.shift
        !          1003:         );
        !          1004: 
        !          1005:     return (((int64_t) live << 32) / sw->ratio) << sw->info.shift;
1.1       root     1006: }
                   1007: 
1.1.1.2 ! root     1008: static int audio_get_free (SWVoiceOut *sw)
1.1       root     1009: {
1.1.1.2 ! root     1010:     int live, dead;
1.1       root     1011: 
1.1.1.2 ! root     1012:     if (!sw) {
        !          1013:         return 0;
        !          1014:     }
1.1       root     1015: 
1.1.1.2 ! root     1016:     live = sw->total_hw_samples_mixed;
1.1       root     1017: 
1.1.1.2 ! root     1018:     if (audio_bug (AUDIO_FUNC, live < 0 || live > sw->hw->samples)) {
        !          1019:         dolog ("live=%d sw->hw->samples=%d\n", live, sw->hw->samples);
        !          1020:         return 0;
        !          1021:     }
1.1       root     1022: 
1.1.1.2 ! root     1023:     dead = sw->hw->samples - live;
1.1       root     1024: 
1.1.1.2 ! root     1025: #ifdef DEBUG_OUT
        !          1026:     dolog ("%s: get_free live %d dead %d ret %lld\n",
        !          1027:            SW_NAME (sw),
        !          1028:            live, dead, (((int64_t) dead << 32) / sw->ratio) << sw->info.shift);
        !          1029: #endif
1.1       root     1030: 
1.1.1.2 ! root     1031:     return (((int64_t) dead << 32) / sw->ratio) << sw->info.shift;
1.1       root     1032: }
                   1033: 
1.1.1.2 ! root     1034: static void audio_run_out (AudioState *s)
1.1       root     1035: {
1.1.1.2 ! root     1036:     HWVoiceOut *hw = NULL;
        !          1037:     SWVoiceOut *sw;
1.1       root     1038: 
1.1.1.2 ! root     1039:     while ((hw = audio_pcm_hw_find_any_enabled_out (s, hw))) {
        !          1040:         int played;
        !          1041:         int live, free, nb_live, cleanup_required;
1.1       root     1042: 
1.1.1.2 ! root     1043:         live = audio_pcm_hw_get_live_out2 (hw, &nb_live);
        !          1044:         if (!nb_live) {
        !          1045:             live = 0;
        !          1046:         }
1.1       root     1047: 
1.1.1.2 ! root     1048:         if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) {
        !          1049:             dolog ("live=%d hw->samples=%d\n", live, hw->samples);
        !          1050:             continue;
        !          1051:         }
        !          1052: 
        !          1053:         if (hw->pending_disable && !nb_live) {
        !          1054: #ifdef DEBUG_OUT
        !          1055:             dolog ("Disabling voice\n");
        !          1056: #endif
        !          1057:             hw->enabled = 0;
        !          1058:             hw->pending_disable = 0;
        !          1059:             hw->pcm_ops->ctl_out (hw, VOICE_DISABLE);
        !          1060:             continue;
        !          1061:         }
1.1       root     1062: 
1.1.1.2 ! root     1063:         if (!live) {
        !          1064:             for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
        !          1065:                 if (sw->active) {
        !          1066:                     free = audio_get_free (sw);
        !          1067:                     if (free > 0) {
        !          1068:                         sw->callback.fn (sw->callback.opaque, free);
        !          1069:                     }
        !          1070:                 }
1.1       root     1071:             }
1.1.1.2 ! root     1072:             continue;
1.1       root     1073:         }
1.1.1.2 ! root     1074: 
        !          1075:         played = hw->pcm_ops->run_out (hw);
        !          1076:         if (audio_bug (AUDIO_FUNC, hw->rpos >= hw->samples)) {
        !          1077:             dolog ("hw->rpos=%d hw->samples=%d played=%d\n",
        !          1078:                    hw->rpos, hw->samples, played);
        !          1079:             hw->rpos = 0;
1.1       root     1080:         }
                   1081: 
1.1.1.2 ! root     1082: #ifdef DEBUG_OUT
        !          1083:         dolog ("played=%d\n", played);
        !          1084: #endif
1.1       root     1085: 
1.1.1.2 ! root     1086:         if (played) {
        !          1087:             hw->ts_helper += played;
        !          1088:         }
1.1       root     1089: 
1.1.1.2 ! root     1090:         cleanup_required = 0;
        !          1091:         for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
        !          1092:             if (!sw->active && sw->empty) {
        !          1093:                 continue;
        !          1094:             }
1.1       root     1095: 
1.1.1.2 ! root     1096:             if (audio_bug (AUDIO_FUNC, played > sw->total_hw_samples_mixed)) {
        !          1097:                 dolog ("played=%d sw->total_hw_samples_mixed=%d\n",
        !          1098:                        played, sw->total_hw_samples_mixed);
        !          1099:                 played = sw->total_hw_samples_mixed;
        !          1100:             }
1.1       root     1101: 
1.1.1.2 ! root     1102:             sw->total_hw_samples_mixed -= played;
1.1       root     1103: 
1.1.1.2 ! root     1104:             if (!sw->total_hw_samples_mixed) {
        !          1105:                 sw->empty = 1;
        !          1106:                 cleanup_required |= !sw->active && !sw->callback.fn;
        !          1107:             }
1.1       root     1108: 
1.1.1.2 ! root     1109:             if (sw->active) {
        !          1110:                 free = audio_get_free (sw);
        !          1111:                 if (free > 0) {
        !          1112:                     sw->callback.fn (sw->callback.opaque, free);
        !          1113:                 }
1.1       root     1114:             }
                   1115:         }
                   1116: 
1.1.1.2 ! root     1117:         if (cleanup_required) {
        !          1118:         restart:
        !          1119:             for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
        !          1120:                 if (!sw->active && !sw->callback.fn) {
        !          1121: #ifdef DEBUG_PLIVE
        !          1122:                     dolog ("Finishing with old voice\n");
        !          1123: #endif
        !          1124:                     audio_close_out (s, sw);
        !          1125:                     goto restart; /* play it safe */
1.1       root     1126:                 }
                   1127:             }
                   1128:         }
                   1129:     }
                   1130: }
                   1131: 
1.1.1.2 ! root     1132: static void audio_run_in (AudioState *s)
1.1       root     1133: {
1.1.1.2 ! root     1134:     HWVoiceIn *hw = NULL;
1.1       root     1135: 
1.1.1.2 ! root     1136:     while ((hw = audio_pcm_hw_find_any_enabled_in (s, hw))) {
        !          1137:         SWVoiceIn *sw;
        !          1138:         int captured, min;
1.1       root     1139: 
1.1.1.2 ! root     1140:         captured = hw->pcm_ops->run_in (hw);
1.1       root     1141: 
1.1.1.2 ! root     1142:         min = audio_pcm_hw_find_min_in (hw);
        !          1143:         hw->total_samples_captured += captured - min;
        !          1144:         hw->ts_helper += captured;
1.1       root     1145: 
1.1.1.2 ! root     1146:         for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
        !          1147:             sw->total_hw_samples_acquired -= min;
1.1       root     1148: 
1.1.1.2 ! root     1149:             if (sw->active) {
        !          1150:                 int avail;
1.1       root     1151: 
1.1.1.2 ! root     1152:                 avail = audio_get_avail (sw);
        !          1153:                 if (avail > 0) {
        !          1154:                     sw->callback.fn (sw->callback.opaque, avail);
        !          1155:                 }
        !          1156:             }
        !          1157:         }
        !          1158:     }
1.1       root     1159: }
                   1160: 
1.1.1.2 ! root     1161: static void audio_timer (void *opaque)
1.1       root     1162: {
1.1.1.2 ! root     1163:     AudioState *s = opaque;
        !          1164: 
        !          1165:     audio_run_out (s);
        !          1166:     audio_run_in (s);
        !          1167: 
        !          1168:     qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + conf.period.ticks);
1.1       root     1169: }
                   1170: 
1.1.1.2 ! root     1171: static struct audio_option audio_options[] = {
        !          1172:     /* DAC */
        !          1173:     {"DAC_FIXED_SETTINGS", AUD_OPT_BOOL, &conf.fixed_out.enabled,
        !          1174:      "Use fixed settings for host DAC", NULL, 0},
1.1       root     1175: 
1.1.1.2 ! root     1176:     {"DAC_FIXED_FREQ", AUD_OPT_INT, &conf.fixed_out.settings.freq,
        !          1177:      "Frequency for fixed host DAC", NULL, 0},
1.1       root     1178: 
1.1.1.2 ! root     1179:     {"DAC_FIXED_FMT", AUD_OPT_FMT, &conf.fixed_out.settings.fmt,
        !          1180:      "Format for fixed host DAC", NULL, 0},
1.1       root     1181: 
1.1.1.2 ! root     1182:     {"DAC_FIXED_CHANNELS", AUD_OPT_INT, &conf.fixed_out.settings.nchannels,
        !          1183:      "Number of channels for fixed DAC (1 - mono, 2 - stereo)", NULL, 0},
1.1       root     1184: 
1.1.1.2 ! root     1185:     {"DAC_VOICES", AUD_OPT_INT, &conf.fixed_out.nb_voices,
        !          1186:      "Number of voices for DAC", NULL, 0},
        !          1187: 
        !          1188:     /* ADC */
        !          1189:     {"ADC_FIXED_SETTINGS", AUD_OPT_BOOL, &conf.fixed_in.enabled,
        !          1190:      "Use fixed settings for host ADC", NULL, 0},
        !          1191: 
        !          1192:     {"ADC_FIXED_FREQ", AUD_OPT_INT, &conf.fixed_in.settings.freq,
        !          1193:      "Frequency for fixed host ADC", NULL, 0},
        !          1194: 
        !          1195:     {"ADC_FIXED_FMT", AUD_OPT_FMT, &conf.fixed_in.settings.fmt,
        !          1196:      "Format for fixed host ADC", NULL, 0},
        !          1197: 
        !          1198:     {"ADC_FIXED_CHANNELS", AUD_OPT_INT, &conf.fixed_in.settings.nchannels,
        !          1199:      "Number of channels for fixed ADC (1 - mono, 2 - stereo)", NULL, 0},
        !          1200: 
        !          1201:     {"ADC_VOICES", AUD_OPT_INT, &conf.fixed_in.nb_voices,
        !          1202:      "Number of voices for ADC", NULL, 0},
        !          1203: 
        !          1204:     /* Misc */
        !          1205:     {"TIMER_PERIOD", AUD_OPT_INT, &conf.period.hz,
        !          1206:      "Timer period in HZ (0 - use lowest possible)", NULL, 0},
        !          1207: 
        !          1208:     {"PLIVE", AUD_OPT_BOOL, &conf.plive,
        !          1209:      "(undocumented)", NULL, 0},
        !          1210: 
        !          1211:     {"LOG_TO_MONITOR", AUD_OPT_BOOL, &conf.log_to_monitor,
        !          1212:      "print logging messages to montior instead of stderr", NULL, 0},
        !          1213: 
        !          1214:     {NULL, 0, NULL, NULL, NULL, 0}
        !          1215: };
        !          1216: 
        !          1217: static void audio_pp_nb_voices (const char *typ, int nb)
        !          1218: {
        !          1219:     switch (nb) {
        !          1220:     case 0:
        !          1221:         printf ("Does not support %s\n", typ);
        !          1222:         break;
        !          1223:     case 1:
        !          1224:         printf ("One %s voice\n", typ);
        !          1225:         break;
        !          1226:     case INT_MAX:
        !          1227:         printf ("Theoretically supports many %s voices\n", typ);
        !          1228:         break;
        !          1229:     default:
        !          1230:         printf ("Theoretically supports upto %d %s voices\n", nb, typ);
        !          1231:         break;
1.1       root     1232:     }
1.1.1.2 ! root     1233: 
1.1       root     1234: }
                   1235: 
1.1.1.2 ! root     1236: void AUD_help (void)
1.1       root     1237: {
1.1.1.2 ! root     1238:     size_t i;
1.1       root     1239: 
1.1.1.2 ! root     1240:     audio_process_options ("AUDIO", audio_options);
        !          1241:     for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
        !          1242:         struct audio_driver *d = drvtab[i];
        !          1243:         if (d->options) {
        !          1244:             audio_process_options (d->name, d->options);
1.1       root     1245:         }
                   1246:     }
                   1247: 
1.1.1.2 ! root     1248:     printf ("Audio options:\n");
        !          1249:     audio_print_options ("AUDIO", audio_options);
        !          1250:     printf ("\n");
        !          1251: 
        !          1252:     printf ("Available drivers:\n");
        !          1253: 
        !          1254:     for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
        !          1255:         struct audio_driver *d = drvtab[i];
        !          1256: 
        !          1257:         printf ("Name: %s\n", d->name);
        !          1258:         printf ("Description: %s\n", d->descr);
        !          1259: 
        !          1260:         audio_pp_nb_voices ("playback", d->max_voices_out);
        !          1261:         audio_pp_nb_voices ("capture", d->max_voices_in);
        !          1262: 
        !          1263:         if (d->options) {
        !          1264:             printf ("Options:\n");
        !          1265:             audio_print_options (d->name, d->options);
1.1       root     1266:         }
                   1267:         else {
1.1.1.2 ! root     1268:             printf ("No options\n");
1.1       root     1269:         }
1.1.1.2 ! root     1270:         printf ("\n");
1.1       root     1271:     }
                   1272: 
1.1.1.2 ! root     1273:     printf (
        !          1274:         "Options are settable through environment variables.\n"
        !          1275:         "Example:\n"
        !          1276: #ifdef _WIN32
        !          1277:         "  set QEMU_AUDIO_DRV=wav\n"
        !          1278:         "  set QEMU_WAV_PATH=c:\\tune.wav\n"
        !          1279: #else
        !          1280:         "  export QEMU_AUDIO_DRV=wav\n"
        !          1281:         "  export QEMU_WAV_PATH=$HOME/tune.wav\n"
        !          1282:         "(for csh replace export with setenv in the above)\n"
1.1       root     1283: #endif
1.1.1.2 ! root     1284:         "  qemu ...\n\n"
        !          1285:         );
        !          1286: }
1.1       root     1287: 
1.1.1.2 ! root     1288: static int audio_driver_init (AudioState *s, struct audio_driver *drv)
1.1       root     1289: {
1.1.1.2 ! root     1290:     if (drv->options) {
        !          1291:         audio_process_options (drv->name, drv->options);
1.1       root     1292:     }
1.1.1.2 ! root     1293:     s->drv_opaque = drv->init ();
        !          1294: 
        !          1295:     if (s->drv_opaque) {
        !          1296:         audio_init_nb_voices_out (s, drv);
        !          1297:         audio_init_nb_voices_in (s, drv);
        !          1298:         s->drv = drv;
1.1       root     1299:         return 0;
                   1300:     }
1.1.1.2 ! root     1301:     else {
        !          1302:         dolog ("Could not init `%s' audio driver\n", drv->name);
        !          1303:         return -1;
        !          1304:     }
1.1       root     1305: }
                   1306: 
1.1.1.2 ! root     1307: static void audio_vm_change_state_handler (void *opaque, int running)
1.1       root     1308: {
1.1.1.2 ! root     1309:     AudioState *s = opaque;
        !          1310:     HWVoiceOut *hwo = NULL;
        !          1311:     HWVoiceIn *hwi = NULL;
        !          1312:     int op = running ? VOICE_ENABLE : VOICE_DISABLE;
1.1       root     1313: 
1.1.1.2 ! root     1314:     while ((hwo = audio_pcm_hw_find_any_enabled_out (s, hwo))) {
        !          1315:         hwo->pcm_ops->ctl_out (hwo, op);
        !          1316:     }
1.1       root     1317: 
1.1.1.2 ! root     1318:     while ((hwi = audio_pcm_hw_find_any_enabled_in (s, hwi))) {
        !          1319:         hwi->pcm_ops->ctl_in (hwi, op);
1.1       root     1320:     }
                   1321: }
                   1322: 
                   1323: static void audio_atexit (void)
                   1324: {
1.1.1.2 ! root     1325:     AudioState *s = &glob_audio_state;
        !          1326:     HWVoiceOut *hwo = NULL;
        !          1327:     HWVoiceIn *hwi = NULL;
1.1       root     1328: 
1.1.1.2 ! root     1329:     while ((hwo = audio_pcm_hw_find_any_enabled_out (s, hwo))) {
        !          1330:         hwo->pcm_ops->ctl_out (hwo, VOICE_DISABLE);
        !          1331:         hwo->pcm_ops->fini_out (hwo);
        !          1332:     }
        !          1333: 
        !          1334:     while ((hwi = audio_pcm_hw_find_any_enabled_in (s, hwi))) {
        !          1335:         hwi->pcm_ops->ctl_in (hwi, VOICE_DISABLE);
        !          1336:         hwi->pcm_ops->fini_in (hwi);
        !          1337:     }
1.1       root     1338: 
1.1.1.2 ! root     1339:     if (s->drv) {
        !          1340:         s->drv->fini (s->drv_opaque);
1.1       root     1341:     }
                   1342: }
                   1343: 
                   1344: static void audio_save (QEMUFile *f, void *opaque)
                   1345: {
1.1.1.2 ! root     1346:     (void) f;
        !          1347:     (void) opaque;
1.1       root     1348: }
                   1349: 
                   1350: static int audio_load (QEMUFile *f, void *opaque, int version_id)
                   1351: {
1.1.1.2 ! root     1352:     (void) f;
        !          1353:     (void) opaque;
        !          1354: 
        !          1355:     if (version_id != 1) {
1.1       root     1356:         return -EINVAL;
1.1.1.2 ! root     1357:     }
1.1       root     1358: 
                   1359:     return 0;
                   1360: }
                   1361: 
1.1.1.2 ! root     1362: void AUD_register_card (AudioState *s, const char *name, QEMUSoundCard *card)
        !          1363: {
        !          1364:     card->audio = s;
        !          1365:     card->name = qemu_strdup (name);
        !          1366:     memset (&card->entries, 0, sizeof (card->entries));
        !          1367:     LIST_INSERT_HEAD (&s->card_head, card, entries);
        !          1368: }
        !          1369: 
        !          1370: void AUD_remove_card (QEMUSoundCard *card)
1.1       root     1371: {
1.1.1.2 ! root     1372:     LIST_REMOVE (card, entries);
        !          1373:     card->audio = NULL;
        !          1374:     qemu_free (card->name);
        !          1375: }
        !          1376: 
        !          1377: AudioState *AUD_init (void)
        !          1378: {
        !          1379:     size_t i;
1.1       root     1380:     int done = 0;
                   1381:     const char *drvname;
1.1.1.2 ! root     1382:     AudioState *s = &glob_audio_state;
        !          1383: 
        !          1384:     LIST_INIT (&s->hw_head_out);
        !          1385:     LIST_INIT (&s->hw_head_in);
        !          1386:     atexit (audio_atexit);
        !          1387: 
        !          1388:     s->ts = qemu_new_timer (vm_clock, audio_timer, s);
        !          1389:     if (!s->ts) {
        !          1390:         dolog ("Could not create audio timer\n");
        !          1391:         return NULL;
        !          1392:     }
        !          1393: 
        !          1394:     audio_process_options ("AUDIO", audio_options);
        !          1395: 
        !          1396:     s->nb_hw_voices_out = conf.fixed_out.nb_voices;
        !          1397:     s->nb_hw_voices_in = conf.fixed_in.nb_voices;
        !          1398: 
        !          1399:     if (s->nb_hw_voices_out <= 0) {
        !          1400:         dolog ("Bogus number of playback voices %d, setting to 1\n",
        !          1401:                s->nb_hw_voices_out);
        !          1402:         s->nb_hw_voices_out = 1;
        !          1403:     }
1.1       root     1404: 
1.1.1.2 ! root     1405:     if (s->nb_hw_voices_in <= 0) {
        !          1406:         dolog ("Bogus number of capture voices %d, setting to 0\n",
        !          1407:                s->nb_hw_voices_in);
        !          1408:         s->nb_hw_voices_in = 0;
        !          1409:     }
        !          1410: 
        !          1411:     {
        !          1412:         int def;
        !          1413:         drvname = audio_get_conf_str ("QEMU_AUDIO_DRV", NULL, &def);
1.1       root     1414:     }
                   1415: 
                   1416:     if (drvname) {
                   1417:         int found = 0;
1.1.1.2 ! root     1418: 
1.1       root     1419:         for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
                   1420:             if (!strcmp (drvname, drvtab[i]->name)) {
1.1.1.2 ! root     1421:                 done = !audio_driver_init (s, drvtab[i]);
1.1       root     1422:                 found = 1;
                   1423:                 break;
                   1424:             }
                   1425:         }
1.1.1.2 ! root     1426: 
1.1       root     1427:         if (!found) {
                   1428:             dolog ("Unknown audio driver `%s'\n", drvname);
1.1.1.2 ! root     1429:             dolog ("Run with -audio-help to list available drivers\n");
1.1       root     1430:         }
                   1431:     }
                   1432: 
                   1433:     if (!done) {
                   1434:         for (i = 0; !done && i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
1.1.1.2 ! root     1435:             if (drvtab[i]->can_be_default) {
        !          1436:                 done = !audio_driver_init (s, drvtab[i]);
        !          1437:             }
1.1       root     1438:         }
                   1439:     }
                   1440: 
                   1441:     if (!done) {
1.1.1.2 ! root     1442:         done = !audio_driver_init (s, &no_audio_driver);
        !          1443:         if (!done) {
        !          1444:             dolog ("Could not initialize audio subsystem\n");
        !          1445:         }
        !          1446:         else {
        !          1447:             dolog ("warning: Using timer based audio emulation\n");
        !          1448:         }
        !          1449:     }
        !          1450: 
        !          1451:     if (done) {
        !          1452:         VMChangeStateEntry *e;
        !          1453: 
        !          1454:         if (conf.period.hz <= 0) {
        !          1455:             if (conf.period.hz < 0) {
        !          1456:                 dolog ("warning: Timer period is negative - %d "
        !          1457:                        "treating as zero\n",
        !          1458:                        conf.period.hz);
        !          1459:             }
        !          1460:             conf.period.ticks = 1;
        !          1461:         }
        !          1462:         else {
        !          1463:             conf.period.ticks = ticks_per_sec / conf.period.hz;
        !          1464:         }
        !          1465: 
        !          1466:         e = qemu_add_vm_change_state_handler (audio_vm_change_state_handler, s);
        !          1467:         if (!e) {
        !          1468:             dolog ("warning: Could not register change state handler\n"
        !          1469:                    "(Audio can continue looping even after stopping the VM)\n");
        !          1470:         }
1.1       root     1471:     }
1.1.1.2 ! root     1472:     else {
        !          1473:         qemu_del_timer (s->ts);
        !          1474:         return NULL;
        !          1475:     }
        !          1476: 
        !          1477:     LIST_INIT (&s->card_head);
        !          1478:     register_savevm ("audio", 0, 1, audio_save, audio_load, s);
        !          1479:     qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + conf.period.ticks);
        !          1480:     return s;
1.1       root     1481: }

unix.superglobalmegacorp.com

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