diff options
Diffstat (limited to 'audio/audio.c')
-rw-r--r-- | audio/audio.c | 598 |
1 files changed, 316 insertions, 282 deletions
diff --git a/audio/audio.c b/audio/audio.c index 6f107dc..e095b1a 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -158,71 +158,59 @@ static struct { } period; int plive; int log_to_monitor; + int try_poll_in; + int try_poll_out; } conf = { - { /* DAC fixed settings */ - 1, /* enabled */ - 1, /* nb_voices */ - 1, /* greedy */ - { - 44100, /* freq */ - 2, /* nchannels */ - AUD_FMT_S16, /* fmt */ - AUDIO_HOST_ENDIANNESS + .fixed_out = { /* DAC fixed settings */ + .enabled = 1, + .nb_voices = 1, + .greedy = 1, + .settings = { + .freq = 44100, + .nchannels = 2, + .fmt = AUD_FMT_S16, + .endianness = AUDIO_HOST_ENDIANNESS, } }, - { /* ADC fixed settings */ - 1, /* enabled */ - 1, /* nb_voices */ - 1, /* greedy */ - { - 44100, /* freq */ - 2, /* nchannels */ - AUD_FMT_S16, /* fmt */ - AUDIO_HOST_ENDIANNESS + .fixed_in = { /* ADC fixed settings */ + .enabled = 1, + .nb_voices = 1, + .greedy = 1, + .settings = { + .freq = 44100, + .nchannels = 2, + .fmt = AUD_FMT_S16, + .endianness = AUDIO_HOST_ENDIANNESS, } }, - { 250 }, /* period */ - 0, /* plive */ - 0 /* log_to_monitor */ + .period = { .hertz = 250 }, + .plive = 0, + .log_to_monitor = 0, + .try_poll_in = 1, + .try_poll_out = 1, }; static AudioState glob_audio_state; struct mixeng_volume nominal_volume = { - 0, + .mute = 0, #ifdef FLOAT_MIXENG - 1.0, - 1.0 + .r = 1.0, + .l = 1.0, #else - 1ULL << 32, - 1ULL << 32 + .r = 1ULL << 32, + .l = 1ULL << 32, #endif }; -#if 0 -/* http://www.df.lth.se/~john_e/gems/gem002d.html */ -/* http://www.multi-platforms.com/Tips/PopCount.htm */ -uint32_t popcount (uint32_t u) -{ - u = ((u&0x55555555) + ((u>>1)&0x55555555)); - u = ((u&0x33333333) + ((u>>2)&0x33333333)); - u = ((u&0x0f0f0f0f) + ((u>>4)&0x0f0f0f0f)); - u = ((u&0x00ff00ff) + ((u>>8)&0x00ff00ff)); - u = ( u&0x0000ffff) + (u>>16); - return u; -} - -inline uint32_t lsbindex (uint32_t u) -{ - return popcount ((u&-u)-1); -} -#endif - #ifdef AUDIO_IS_FLAWLESS_AND_NO_CHECKS_ARE_REQURIED #error No its not #else +static void audio_print_options (const char *prefix, + struct audio_option *opt); + int audio_bug (const char *funcname, int cond) { if (cond) { @@ -230,10 +218,16 @@ int audio_bug (const char *funcname, int cond) AUD_log (NULL, "A bug was just triggered in %s\n", funcname); if (!shown) { + struct audio_driver *d; + shown = 1; AUD_log (NULL, "Save all your work and restart without audio\n"); - AUD_log (NULL, "Please send bug report to malc@pulsesoft.com\n"); + AUD_log (NULL, "Please send bug report to av1474@comtv.ru\n"); AUD_log (NULL, "I am sorry\n"); + d = glob_audio_state.drv; + if (d) { + audio_print_options (d->name, d->options); + } } AUD_log (NULL, "Context:\n"); @@ -966,6 +960,28 @@ int audio_pcm_hw_get_live_in (HWVoiceIn *hw) return live; } +int audio_pcm_hw_clip_out (HWVoiceOut *hw, void *pcm_buf, + int live, int pending) +{ + int left = hw->samples - pending; + int len = audio_MIN (left, live); + int clipped = 0; + + while (len) { + struct st_sample *src = hw->mix_buf + hw->rpos; + uint8_t *dst = advance (pcm_buf, hw->rpos << hw->info.shift); + int samples_till_end_of_buf = hw->samples - hw->rpos; + int samples_to_clip = audio_MIN (len, samples_till_end_of_buf); + + hw->clip (dst, src, samples_to_clip); + + hw->rpos = (hw->rpos + samples_to_clip) % hw->samples; + len -= samples_to_clip; + clipped += samples_to_clip; + } + return clipped; +} + /* * Soft voice (capture) */ @@ -1062,16 +1078,17 @@ static int audio_pcm_hw_find_min_out (HWVoiceOut *hw, int *nb_livep) return m; } -int audio_pcm_hw_get_live_out2 (HWVoiceOut *hw, int *nb_live) +static int audio_pcm_hw_get_live_out (HWVoiceOut *hw, int *nb_live) { int smin; + int nb_live1; - smin = audio_pcm_hw_find_min_out (hw, nb_live); - - if (!*nb_live) { - return 0; + smin = audio_pcm_hw_find_min_out (hw, &nb_live1); + if (nb_live) { + *nb_live = nb_live1; } - else { + + if (nb_live1) { int live = smin; if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) { @@ -1080,19 +1097,7 @@ int audio_pcm_hw_get_live_out2 (HWVoiceOut *hw, int *nb_live) } return live; } -} - -int audio_pcm_hw_get_live_out (HWVoiceOut *hw) -{ - int nb_live; - int live; - - live = audio_pcm_hw_get_live_out2 (hw, &nb_live); - if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) { - dolog ("live=%d hw->samples=%d\n", live, hw->samples); - return 0; - } - return live; + return 0; } /* @@ -1185,6 +1190,76 @@ static void audio_pcm_print_info (const char *cap, struct audio_pcm_info *info) #undef DAC #include "audio_template.h" +/* + * Timer + */ +static void audio_timer (void *opaque) +{ + AudioState *s = opaque; +#if 0 +#define MAX_DIFFS 100 + int64_t now = qemu_get_clock(vm_clock); + static int64_t last = 0; + static float diffs[MAX_DIFFS]; + static int num_diffs; + + if (last == 0) + last = now; + else { + diffs[num_diffs] = (float)((now-last)/1e6); /* last diff in ms */ + if (++num_diffs == MAX_DIFFS) { + double min_diff = 1e6, max_diff = -1e6; + double all_diff = 0.; + int nn; + + for (nn = 0; nn < num_diffs; nn++) { + if (diffs[nn] < min_diff) min_diff = diffs[nn]; + if (diffs[nn] > max_diff) max_diff = diffs[nn]; + all_diff += diffs[nn]; + } + all_diff *= 1.0/num_diffs; + printf("audio timer: min_diff=%6.2g max_diff=%6.2g avg_diff=%6.2g samples=%d\n", + min_diff, max_diff, all_diff, num_diffs); + num_diffs = 0; + } + } + last = now; +#endif + + audio_run ("timer"); + qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + conf.period.ticks); +} + + +static int audio_is_timer_needed (void) +{ + HWVoiceIn *hwi = NULL; + HWVoiceOut *hwo = NULL; + + while ((hwo = audio_pcm_hw_find_any_enabled_out (hwo))) { + if (!hwo->poll_mode) return 1; + } + while ((hwi = audio_pcm_hw_find_any_enabled_in (hwi))) { + if (!hwi->poll_mode) return 1; + } + return 0; +} + +static void audio_reset_timer (void) +{ + AudioState *s = &glob_audio_state; + + if (audio_is_timer_needed ()) { + qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + 1); + } + else { + qemu_del_timer (s->ts); + } +} + +/* + * Public API + */ int AUD_write (SWVoiceOut *sw, void *buf, int size) { int bytes; @@ -1199,9 +1274,7 @@ int AUD_write (SWVoiceOut *sw, void *buf, int size) return 0; } - BEGIN_NOSIGALRM - bytes = sw->hw->pcm_ops->write (sw, buf, size); - END_NOSIGALRM + bytes = sw->hw->pcm_ops->write (sw, buf, size); return bytes; } @@ -1219,9 +1292,7 @@ int AUD_read (SWVoiceIn *sw, void *buf, int size) return 0; } - BEGIN_NOSIGALRM - bytes = sw->hw->pcm_ops->read (sw, buf, size); - END_NOSIGALRM + bytes = sw->hw->pcm_ops->read (sw, buf, size); return bytes; } @@ -1249,9 +1320,8 @@ void AUD_set_active_out (SWVoiceOut *sw, int on) if (!hw->enabled) { hw->enabled = 1; if (s->vm_running) { - BEGIN_NOSIGALRM - hw->pcm_ops->ctl_out (hw, VOICE_ENABLE); - END_NOSIGALRM + hw->pcm_ops->ctl_out (hw, VOICE_ENABLE, conf.try_poll_out); + audio_reset_timer (); } } } @@ -1295,9 +1365,7 @@ void AUD_set_active_in (SWVoiceIn *sw, int on) if (!hw->enabled) { hw->enabled = 1; if (s->vm_running) { - BEGIN_NOSIGALRM - hw->pcm_ops->ctl_in (hw, VOICE_ENABLE); - END_NOSIGALRM + hw->pcm_ops->ctl_in (hw, VOICE_ENABLE, conf.try_poll_in); } } sw->total_hw_samples_acquired = hw->total_samples_captured; @@ -1313,9 +1381,7 @@ void AUD_set_active_in (SWVoiceIn *sw, int on) if (nb_active == 1) { hw->enabled = 0; - BEGIN_NOSIGALRM - hw->pcm_ops->ctl_in (hw, VOICE_DISABLE); - END_NOSIGALRM + hw->pcm_ops->ctl_in (hw, VOICE_DISABLE); } } } @@ -1418,7 +1484,7 @@ static void audio_run_out (AudioState *s) int played; int live, free, nb_live, cleanup_required, prev_rpos; - live = audio_pcm_hw_get_live_out2 (hw, &nb_live); + live = audio_pcm_hw_get_live_out (hw, &nb_live); if (!nb_live) { live = 0; } @@ -1435,9 +1501,7 @@ static void audio_run_out (AudioState *s) #endif hw->enabled = 0; hw->pending_disable = 0; - BEGIN_NOSIGALRM - hw->pcm_ops->ctl_out (hw, VOICE_DISABLE); - END_NOSIGALRM + hw->pcm_ops->ctl_out (hw, VOICE_DISABLE); for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) { sc->sw.active = 0; audio_recalc_and_notify_capture (sc->cap); @@ -1458,9 +1522,7 @@ static void audio_run_out (AudioState *s) } prev_rpos = hw->rpos; - BEGIN_NOSIGALRM - played = hw->pcm_ops->run_out (hw); - END_NOSIGALRM + played = hw->pcm_ops->run_out (hw, live); if (audio_bug (AUDIO_FUNC, hw->rpos >= hw->samples)) { dolog ("hw->rpos=%d hw->samples=%d played=%d\n", hw->rpos, hw->samples, played); @@ -1529,9 +1591,7 @@ static void audio_run_in (AudioState *s) SWVoiceIn *sw; int captured, min; - BEGIN_NOSIGALRM - captured = hw->pcm_ops->run_in (hw); - END_NOSIGALRM + captured = hw->pcm_ops->run_in (hw); min = audio_pcm_hw_find_min_in (hw); hw->total_samples_captured += captured - min; @@ -1561,7 +1621,7 @@ static void audio_run_capture (AudioState *s) HWVoiceOut *hw = &cap->hw; SWVoiceOut *sw; - captured = live = audio_pcm_hw_get_live_out (hw); + captured = live = audio_pcm_hw_get_live_out (hw, NULL); rpos = hw->rpos; while (live) { int left = hw->samples - rpos; @@ -1599,89 +1659,126 @@ static void audio_run_capture (AudioState *s) } } -static void audio_timer (void *opaque) +void audio_run (const char *msg) { - AudioState *s = opaque; -#if 0 -#define MAX_DIFFS 1000 - int64_t now = qemu_get_clock(vm_clock); - static int64_t last = 0; - static float diffs[MAX_DIFFS]; - static int num_diffs; + AudioState *s = &glob_audio_state; - if (last == 0) - last = now; - else { - diffs[num_diffs] = (float)((now-last)/1e6); /* last diff in ms */ - if (++num_diffs == MAX_DIFFS) { - double min_diff = 1e6, max_diff = -1e6; - double all_diff = 0.; - int nn; - - for (nn = 0; nn < num_diffs; nn++) { - if (diffs[nn] < min_diff) min_diff = diffs[nn]; - if (diffs[nn] > max_diff) max_diff = diffs[nn]; - all_diff += diffs[nn]; - } - all_diff *= 1.0/num_diffs; - printf("audio timer: min_diff=%6.2g max_diff=%6.2g avg_diff=%6.2g samples=%d\n", - min_diff, max_diff, all_diff, num_diffs); - num_diffs = 0; - } - } - last = now; -#endif audio_run_out (s); audio_run_in (s); audio_run_capture (s); +#ifdef DEBUG_POLL + { + static double prevtime; + double currtime; + struct timeval tv; - qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + conf.period.ticks); + if (gettimeofday (&tv, NULL)) { + perror ("audio_run: gettimeofday"); + return; + } + + currtime = tv.tv_sec + tv.tv_usec * 1e-6; + dolog ("Elapsed since last %s: %f\n", msg, currtime - prevtime); + prevtime = currtime; + } +#endif } 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}, - + { + .name = "DAC_FIXED_SETTINGS", + .tag = AUD_OPT_BOOL, + .valp = &conf.fixed_out.enabled, + .descr = "Use fixed settings for host DAC" + }, + { + .name = "DAC_FIXED_FREQ", + .tag = AUD_OPT_INT, + .valp = &conf.fixed_out.settings.freq, + .descr = "Frequency for fixed host DAC" + }, + { + .name = "DAC_FIXED_FMT", + .tag = AUD_OPT_FMT, + .valp = &conf.fixed_out.settings.fmt, + .descr = "Format for fixed host DAC" + }, + { + .name = "DAC_FIXED_CHANNELS", + .tag = AUD_OPT_INT, + .valp = &conf.fixed_out.settings.nchannels, + .descr = "Number of channels for fixed DAC (1 - mono, 2 - stereo)" + }, + { + .name = "DAC_VOICES", + .tag = AUD_OPT_INT, + .valp = &conf.fixed_out.nb_voices, + .descr = "Number of voices for DAC" + }, + { + .name = "DAC_TRY_POLL", + .tag = AUD_OPT_BOOL, + .valp = &conf.try_poll_out, + .descr = "Attempt using poll mode for DAC" + }, /* 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}, - + { + .name = "ADC_FIXED_SETTINGS", + .tag = AUD_OPT_BOOL, + .valp = &conf.fixed_in.enabled, + .descr = "Use fixed settings for host ADC" + }, + { + .name = "ADC_FIXED_FREQ", + .tag = AUD_OPT_INT, + .valp = &conf.fixed_in.settings.freq, + .descr = "Frequency for fixed host ADC" + }, + { + .name = "ADC_FIXED_FMT", + .tag = AUD_OPT_FMT, + .valp = &conf.fixed_in.settings.fmt, + .descr = "Format for fixed host ADC" + }, + { + .name = "ADC_FIXED_CHANNELS", + .tag = AUD_OPT_INT, + .valp = &conf.fixed_in.settings.nchannels, + .descr = "Number of channels for fixed ADC (1 - mono, 2 - stereo)" + }, + { + .name = "ADC_VOICES", + .tag = AUD_OPT_INT, + .valp = &conf.fixed_in.nb_voices, + .descr = "Number of voices for ADC" + }, + { + .name = "ADC_TRY_POLL", + .tag = AUD_OPT_BOOL, + .valp = &conf.try_poll_in, + .descr = "Attempt using poll mode for ADC" + }, /* Misc */ - {"TIMER_PERIOD", AUD_OPT_INT, &conf.period.hertz, - "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 monitor instead of stderr", NULL, 0}, - - {NULL, 0, NULL, NULL, NULL, 0} + { + .name = "TIMER_PERIOD", + .tag = AUD_OPT_INT, + .valp = &conf.period.hertz, + .descr = "Timer period in HZ (0 - use lowest possible)" + }, + { + .name = "PLIVE", + .tag = AUD_OPT_BOOL, + .valp = &conf.plive, + .descr = "(undocumented)" + }, + { + .name = "LOG_TO_MONITOR", + .tag = AUD_OPT_BOOL, + .valp = &conf.log_to_monitor, + .descr = "Print logging messages to monitor instead of stderr" + }, + { /* End of list */ } }; static void audio_pp_nb_voices (const char *typ, int nb) @@ -1755,43 +1852,17 @@ void AUD_help (void) ); } -static int audio_driver_init (AudioState *s, struct audio_driver *drv, int out) +static int audio_driver_init (AudioState *s, struct audio_driver *drv) { - void* opaque; - if (drv->options) { audio_process_options (drv->name, drv->options); } + s->drv_opaque = drv->init (); - /* is the driver already initialized ? */ - if (out) { - if (drv == s->drv_in) { - s->drv_out = drv; - s->drv_out_opaque = s->drv_in_opaque; - return 0; - } - } else { - if (drv == s->drv_out) { - s->drv_in = drv; - s->drv_in_opaque = s->drv_out_opaque; - return 0; - } - } - - BEGIN_NOSIGALRM - opaque = drv->init(); - END_NOSIGALRM - - if (opaque != NULL) { + if (s->drv_opaque) { audio_init_nb_voices_out (drv); audio_init_nb_voices_in (drv); - if (out) { - s->drv_out = drv; - s->drv_out_opaque = opaque; - } else { - s->drv_in = drv; - s->drv_in_opaque = opaque; - } + s->drv = drv; return 0; } else { @@ -1809,19 +1880,17 @@ static void audio_vm_change_state_handler (void *opaque, int running, int op = running ? VOICE_ENABLE : VOICE_DISABLE; s->vm_running = running; - BEGIN_NOSIGALRM - while ((hwo = audio_pcm_hw_find_any_enabled_out (hwo))) { - hwo->pcm_ops->ctl_out (hwo, op); - } + while ((hwo = audio_pcm_hw_find_any_enabled_out (hwo))) { + hwo->pcm_ops->ctl_out (hwo, op, conf.try_poll_out); + } - while ((hwi = audio_pcm_hw_find_any_enabled_in (hwi))) { - hwi->pcm_ops->ctl_in (hwi, op); - } - END_NOSIGALRM + while ((hwi = audio_pcm_hw_find_any_enabled_in (hwi))) { + hwi->pcm_ops->ctl_in (hwi, op, conf.try_poll_in); + } + audio_reset_timer (); } -// to make sure audio_atexit() is only called once -static int initialized = 0; +static int initialized; static void audio_atexit (void) { @@ -1832,7 +1901,6 @@ static void audio_atexit (void) if (!initialized) return; initialized = 0; - BEGIN_NOSIGALRM while ((hwo = audio_pcm_hw_find_any_enabled_out (hwo))) { SWVoiceCap *sc; @@ -1854,13 +1922,9 @@ static void audio_atexit (void) hwi->pcm_ops->fini_in (hwi); } - if (s->drv_in) { - s->drv_in->fini (s->drv_in_opaque); + if (s->drv) { + s->drv->fini (s->drv_opaque); } - if (s->drv_out) { - s->drv_out->fini (s->drv_out_opaque); - } - END_NOSIGALRM } static void audio_save (QEMUFile *f, void *opaque) @@ -1881,73 +1945,17 @@ static int audio_load (QEMUFile *f, void *opaque, int version_id) return 0; } -static int -find_audio_driver( AudioState* s, int out ) -{ - int i, done = 0, def; - const char* envname; - const char* drvname; - struct audio_driver* drv = NULL; - const char* drvtype = out ? "output" : "input"; - - envname = out ? "QEMU_AUDIO_OUT_DRV" : "QEMU_AUDIO_IN_DRV"; - drvname = audio_get_conf_str(envname, NULL, &def); - if (drvname == NULL) { - drvname = audio_get_conf_str("QEMU_AUDIO_DRV", NULL, &def); - } - - if (drvname != NULL) { /* look for a specific driver */ - for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) { - if (!strcmp (drvname, drvtab[i]->name)) { - drv = drvtab[i]; - break; - } - } - } - - if (drv != NULL) { - done = !audio_driver_init (s, drv, out); - if (!done) { - dolog ("Could not initialize '%s' %s audio backend, trying default one.\n", - drvname, drvtype); - dolog ("Run with -qemu -audio-help to list available backends\n"); - drv = NULL; - } - } - - if (!drv) { - for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) { - if (drvtab[i]->can_be_default) { - drv = drvtab[i]; - done = !audio_driver_init (s, drv, out); - if (done) - break; - } - } - } - - if (!done) { - drv = &no_audio_driver; - done = !audio_driver_init (s, drv, out); - if (!done) { - /* this should never happen */ - dolog ("Could not initialize audio subsystem\n"); - return -1; - } - dolog ("warning: Could not find suitable audio %s backend\n", drvtype); - } - - if (VERBOSE_CHECK(init)) - dprint("using '%s' audio %s backend", drv->name, drvtype ); - return 0; -} static void audio_init (void) { + size_t i; + int done = 0; + const char *drvname; + VMChangeStateEntry *e; AudioState *s = &glob_audio_state; - if (s->drv_out && s->drv_in) { + if (s->drv) { return; } @@ -1979,13 +1987,45 @@ static void audio_init (void) s->nb_hw_voices_in = 0; } - if ( find_audio_driver (s, 0) != 0 || - find_audio_driver (s, 1) != 0 ) { - qemu_del_timer (s->ts); - return; + { + int def; + drvname = audio_get_conf_str ("QEMU_AUDIO_DRV", NULL, &def); } - VMChangeStateEntry *e; + if (drvname) { + int found = 0; + + for (i = 0; i < ARRAY_SIZE (drvtab); 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 < ARRAY_SIZE (drvtab); 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) { + hw_error("Could not initialize audio subsystem\n"); + } + else { + dolog ("warning: Using timer based audio emulation\n"); + } + } if (conf.period.hertz <= 0) { if (conf.period.hertz < 0) { @@ -2004,12 +2044,11 @@ static void audio_init (void) dolog ("warning: Could not register change state handler\n" "(Audio can continue looping even after stopping the VM)\n"); } - initialized = 1; QLIST_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); + audio_reset_timer(); } void AUD_register_card (const char *name, QEMUSoundCard *card) @@ -2026,11 +2065,6 @@ void AUD_remove_card (QEMUSoundCard *card) qemu_free (card->name); } -// this was added to work around a deadlock in SDL when quitting -void AUD_cleanup() -{ - audio_atexit(); -} CaptureVoiceOut *AUD_add_capture ( struct audsettings *as, |