aboutsummaryrefslogtreecommitdiffstats
path: root/audio/audio.c
diff options
context:
space:
mode:
Diffstat (limited to 'audio/audio.c')
-rw-r--r--audio/audio.c598
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,