⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 audio.c

📁 qemu虚拟机代码
💻 C
📖 第 1 页 / 共 3 页
字号:
    if (!sw) {        return 0;    }    live = sw->hw->total_samples_captured - sw->total_hw_samples_acquired;    if (audio_bug (AUDIO_FUNC, live < 0 || live > sw->hw->samples)) {        dolog ("live=%d sw->hw->samples=%d\n", live, sw->hw->samples);        return 0;    }    ldebug (        "%s: get_avail live %d ret %lld\n",        SW_NAME (sw),        live, (((int64_t) live << 32) / sw->ratio) << sw->info.shift        );    return (((int64_t) live << 32) / sw->ratio) << sw->info.shift;}static int audio_get_free (SWVoiceOut *sw){    int live, dead;    if (!sw) {        return 0;    }    live = sw->total_hw_samples_mixed;    if (audio_bug (AUDIO_FUNC, live < 0 || live > sw->hw->samples)) {        dolog ("live=%d sw->hw->samples=%d\n", live, sw->hw->samples);        return 0;    }    dead = sw->hw->samples - live;#ifdef DEBUG_OUT    dolog ("%s: get_free live %d dead %d ret %lld\n",           SW_NAME (sw),           live, dead, (((int64_t) dead << 32) / sw->ratio) << sw->info.shift);#endif    return (((int64_t) dead << 32) / sw->ratio) << sw->info.shift;}static void audio_run_out (AudioState *s){    HWVoiceOut *hw = NULL;    SWVoiceOut *sw;    while ((hw = audio_pcm_hw_find_any_enabled_out (s, hw))) {        int played;        int live, free, nb_live, cleanup_required;        live = audio_pcm_hw_get_live_out2 (hw, &nb_live);        if (!nb_live) {            live = 0;        }        if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) {            dolog ("live=%d hw->samples=%d\n", live, hw->samples);            continue;        }        if (hw->pending_disable && !nb_live) {#ifdef DEBUG_OUT            dolog ("Disabling voice\n");#endif            hw->enabled = 0;            hw->pending_disable = 0;            hw->pcm_ops->ctl_out (hw, VOICE_DISABLE);            continue;        }        if (!live) {            for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {                if (sw->active) {                    free = audio_get_free (sw);                    if (free > 0) {                        sw->callback.fn (sw->callback.opaque, free);                    }                }            }            continue;        }        played = hw->pcm_ops->run_out (hw);        if (audio_bug (AUDIO_FUNC, hw->rpos >= hw->samples)) {            dolog ("hw->rpos=%d hw->samples=%d played=%d\n",                   hw->rpos, hw->samples, played);            hw->rpos = 0;        }#ifdef DEBUG_OUT        dolog ("played=%d\n", played);#endif        if (played) {            hw->ts_helper += played;        }        cleanup_required = 0;        for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {            if (!sw->active && sw->empty) {                continue;            }            if (audio_bug (AUDIO_FUNC, played > sw->total_hw_samples_mixed)) {                dolog ("played=%d sw->total_hw_samples_mixed=%d\n",                       played, sw->total_hw_samples_mixed);                played = sw->total_hw_samples_mixed;            }            sw->total_hw_samples_mixed -= played;            if (!sw->total_hw_samples_mixed) {                sw->empty = 1;                cleanup_required |= !sw->active && !sw->callback.fn;            }            if (sw->active) {                free = audio_get_free (sw);                if (free > 0) {                    sw->callback.fn (sw->callback.opaque, free);                }            }        }        if (cleanup_required) {        restart:            for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {                if (!sw->active && !sw->callback.fn) {#ifdef DEBUG_PLIVE                    dolog ("Finishing with old voice\n");#endif                    audio_close_out (s, sw);                    goto restart; /* play it safe */                }            }        }    }}static void audio_run_in (AudioState *s){    HWVoiceIn *hw = NULL;    while ((hw = audio_pcm_hw_find_any_enabled_in (s, hw))) {        SWVoiceIn *sw;        int captured, min;        captured = hw->pcm_ops->run_in (hw);        min = audio_pcm_hw_find_min_in (hw);        hw->total_samples_captured += captured - min;        hw->ts_helper += captured;        for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {            sw->total_hw_samples_acquired -= min;            if (sw->active) {                int avail;                avail = audio_get_avail (sw);                if (avail > 0) {                    sw->callback.fn (sw->callback.opaque, avail);                }            }        }    }}static void audio_timer (void *opaque){    AudioState *s = opaque;    audio_run_out (s);    audio_run_in (s);    qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + conf.period.ticks);}static struct audio_option audio_options[] = {    /* DAC */    {"DAC_FIXED_SETTINGS", AUD_OPT_BOOL, &conf.fixed_out.enabled,     "Use fixed settings for host DAC", NULL, 0},    {"DAC_FIXED_FREQ", AUD_OPT_INT, &conf.fixed_out.settings.freq,     "Frequency for fixed host DAC", NULL, 0},    {"DAC_FIXED_FMT", AUD_OPT_FMT, &conf.fixed_out.settings.fmt,     "Format for fixed host DAC", NULL, 0},    {"DAC_FIXED_CHANNELS", AUD_OPT_INT, &conf.fixed_out.settings.nchannels,     "Number of channels for fixed DAC (1 - mono, 2 - stereo)", NULL, 0},    {"DAC_VOICES", AUD_OPT_INT, &conf.fixed_out.nb_voices,     "Number of voices for DAC", NULL, 0},    /* ADC */    {"ADC_FIXED_SETTINGS", AUD_OPT_BOOL, &conf.fixed_in.enabled,     "Use fixed settings for host ADC", NULL, 0},    {"ADC_FIXED_FREQ", AUD_OPT_INT, &conf.fixed_in.settings.freq,     "Frequency for fixed host ADC", NULL, 0},    {"ADC_FIXED_FMT", AUD_OPT_FMT, &conf.fixed_in.settings.fmt,     "Format for fixed host ADC", NULL, 0},    {"ADC_FIXED_CHANNELS", AUD_OPT_INT, &conf.fixed_in.settings.nchannels,     "Number of channels for fixed ADC (1 - mono, 2 - stereo)", NULL, 0},    {"ADC_VOICES", AUD_OPT_INT, &conf.fixed_in.nb_voices,     "Number of voices for ADC", NULL, 0},    /* Misc */    {"TIMER_PERIOD", AUD_OPT_INT, &conf.period.hz,     "Timer period in HZ (0 - use lowest possible)", NULL, 0},    {"PLIVE", AUD_OPT_BOOL, &conf.plive,     "(undocumented)", NULL, 0},    {"LOG_TO_MONITOR", AUD_OPT_BOOL, &conf.log_to_monitor,     "print logging messages to montior instead of stderr", NULL, 0},    {NULL, 0, NULL, NULL, NULL, 0}};static void audio_pp_nb_voices (const char *typ, int nb){    switch (nb) {    case 0:        printf ("Does not support %s\n", typ);        break;    case 1:        printf ("One %s voice\n", typ);        break;    case INT_MAX:        printf ("Theoretically supports many %s voices\n", typ);        break;    default:        printf ("Theoretically supports upto %d %s voices\n", nb, typ);        break;    }}void AUD_help (void){    size_t i;    audio_process_options ("AUDIO", audio_options);    for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {        struct audio_driver *d = drvtab[i];        if (d->options) {            audio_process_options (d->name, d->options);        }    }    printf ("Audio options:\n");    audio_print_options ("AUDIO", audio_options);    printf ("\n");    printf ("Available drivers:\n");    for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {        struct audio_driver *d = drvtab[i];        printf ("Name: %s\n", d->name);        printf ("Description: %s\n", d->descr);        audio_pp_nb_voices ("playback", d->max_voices_out);        audio_pp_nb_voices ("capture", d->max_voices_in);        if (d->options) {            printf ("Options:\n");            audio_print_options (d->name, d->options);        }        else {            printf ("No options\n");        }        printf ("\n");    }    printf (        "Options are settable through environment variables.\n"        "Example:\n"#ifdef _WIN32        "  set QEMU_AUDIO_DRV=wav\n"        "  set QEMU_WAV_PATH=c:\\tune.wav\n"#else        "  export QEMU_AUDIO_DRV=wav\n"        "  export QEMU_WAV_PATH=$HOME/tune.wav\n"        "(for csh replace export with setenv in the above)\n"#endif        "  qemu ...\n\n"        );}static int audio_driver_init (AudioState *s, struct audio_driver *drv){    if (drv->options) {        audio_process_options (drv->name, drv->options);    }    s->drv_opaque = drv->init ();    if (s->drv_opaque) {        audio_init_nb_voices_out (s, drv);        audio_init_nb_voices_in (s, drv);        s->drv = drv;        return 0;    }    else {        dolog ("Could not init `%s' audio driver\n", drv->name);        return -1;    }}static void audio_vm_change_state_handler (void *opaque, int running){    AudioState *s = opaque;    HWVoiceOut *hwo = NULL;    HWVoiceIn *hwi = NULL;    int op = running ? VOICE_ENABLE : VOICE_DISABLE;    while ((hwo = audio_pcm_hw_find_any_enabled_out (s, hwo))) {        hwo->pcm_ops->ctl_out (hwo, op);    }    while ((hwi = audio_pcm_hw_find_any_enabled_in (s, hwi))) {        hwi->pcm_ops->ctl_in (hwi, op);    }}static void audio_atexit (void){    AudioState *s = &glob_audio_state;    HWVoiceOut *hwo = NULL;    HWVoiceIn *hwi = NULL;    while ((hwo = audio_pcm_hw_find_any_enabled_out (s, hwo))) {        hwo->pcm_ops->ctl_out (hwo, VOICE_DISABLE);        hwo->pcm_ops->fini_out (hwo);    }    while ((hwi = audio_pcm_hw_find_any_enabled_in (s, hwi))) {        hwi->pcm_ops->ctl_in (hwi, VOICE_DISABLE);        hwi->pcm_ops->fini_in (hwi);    }    if (s->drv) {        s->drv->fini (s->drv_opaque);    }}static void audio_save (QEMUFile *f, void *opaque){    (void) f;    (void) opaque;}static int audio_load (QEMUFile *f, void *opaque, int version_id){    (void) f;    (void) opaque;    if (version_id != 1) {        return -EINVAL;    }    return 0;}void AUD_register_card (AudioState *s, const char *name, QEMUSoundCard *card){    card->audio = s;    card->name = qemu_strdup (name);    memset (&card->entries, 0, sizeof (card->entries));    LIST_INSERT_HEAD (&s->card_head, card, entries);}void AUD_remove_card (QEMUSoundCard *card){    LIST_REMOVE (card, entries);    card->audio = NULL;    qemu_free (card->name);}AudioState *AUD_init (void){    size_t i;    int done = 0;    const char *drvname;    AudioState *s = &glob_audio_state;    LIST_INIT (&s->hw_head_out);    LIST_INIT (&s->hw_head_in);    atexit (audio_atexit);    s->ts = qemu_new_timer (vm_clock, audio_timer, s);    if (!s->ts) {        dolog ("Could not create audio timer\n");        return NULL;    }    audio_process_options ("AUDIO", audio_options);    s->nb_hw_voices_out = conf.fixed_out.nb_voices;    s->nb_hw_voices_in = conf.fixed_in.nb_voices;    if (s->nb_hw_voices_out <= 0) {        dolog ("Bogus number of playback voices %d, setting to 1\n",               s->nb_hw_voices_out);        s->nb_hw_voices_out = 1;    }    if (s->nb_hw_voices_in <= 0) {        dolog ("Bogus number of capture voices %d, setting to 0\n",               s->nb_hw_voices_in);        s->nb_hw_voices_in = 0;    }    {        int def;        drvname = audio_get_conf_str ("QEMU_AUDIO_DRV", NULL, &def);    }    if (drvname) {        int found = 0;        for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {            if (!strcmp (drvname, drvtab[i]->name)) {                done = !audio_driver_init (s, drvtab[i]);                found = 1;                break;            }        }        if (!found) {            dolog ("Unknown audio driver `%s'\n", drvname);            dolog ("Run with -audio-help to list available drivers\n");        }    }    if (!done) {        for (i = 0; !done && i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {            if (drvtab[i]->can_be_default) {                done = !audio_driver_init (s, drvtab[i]);            }        }    }    if (!done) {        done = !audio_driver_init (s, &no_audio_driver);        if (!done) {            dolog ("Could not initialize audio subsystem\n");        }        else {            dolog ("warning: Using timer based audio emulation\n");        }    }    if (done) {        VMChangeStateEntry *e;        if (conf.period.hz <= 0) {            if (conf.period.hz < 0) {                dolog ("warning: Timer period is negative - %d "                       "treating as zero\n",                       conf.period.hz);            }            conf.period.ticks = 1;        }        else {            conf.period.ticks = ticks_per_sec / conf.period.hz;        }        e = qemu_add_vm_change_state_handler (audio_vm_change_state_handler, s);        if (!e) {            dolog ("warning: Could not register change state handler\n"                   "(Audio can continue looping even after stopping the VM)\n");        }    }    else {        qemu_del_timer (s->ts);        return NULL;    }    LIST_INIT (&s->card_head);    register_savevm ("audio", 0, 1, audio_save, audio_load, s);    qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + conf.period.ticks);    return s;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -