#include "sysemu/sysemu.h"
#include "qemu/cutils.h"
#include "sysemu/replay.h"
+#include "trace.h"
#define AUDIO_CAP "audio"
#include "audio_int.h"
The 1st one is the one used by default, that is the reason
that we generate the list.
*/
-static struct audio_driver *drvtab[] = {
-#ifdef CONFIG_SPICE
- &spice_audio_driver,
-#endif
+static const char *audio_prio_list[] = {
+ "spice",
CONFIG_AUDIO_DRIVERS
- &no_audio_driver,
- &wav_audio_driver
+ "none",
+ "wav",
};
+static QLIST_HEAD(, audio_driver) audio_drivers;
+
+void audio_driver_register(audio_driver *drv)
+{
+ QLIST_INSERT_HEAD(&audio_drivers, drv, next);
+}
+
+audio_driver *audio_driver_lookup(const char *name)
+{
+ struct audio_driver *d;
+
+ QLIST_FOREACH(d, &audio_drivers, next) {
+ if (strcmp(name, d->name) == 0) {
+ return d;
+ }
+ }
+
+ audio_module_load_one(name);
+ QLIST_FOREACH(d, &audio_drivers, next) {
+ if (strcmp(name, d->name) == 0) {
+ return d;
+ }
+ }
+
+ return NULL;
+}
+
+static void audio_module_load_all(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(audio_prio_list); i++) {
+ audio_driver_lookup(audio_prio_list[i]);
+ }
+}
+
struct fixed_settings {
int enabled;
int nb_voices;
char *strval;
strval = getenv (key);
- if (strval) {
+ if (strval && !qemu_strtoi(strval, NULL, 10, &val)) {
*defaultp = 0;
- val = atoi (strval);
return val;
}
else {
const char qemu_prefix[] = "QEMU_";
size_t preflen, optlen;
- if (audio_bug (AUDIO_FUNC, !prefix)) {
+ if (audio_bug(__func__, !prefix)) {
dolog ("prefix = NULL\n");
return;
}
- if (audio_bug (AUDIO_FUNC, !opt)) {
+ if (audio_bug(__func__, !opt)) {
dolog ("opt = NULL\n");
return;
}
SWVoiceOut *sw;
HWVoiceOut *hw_cap = &cap->hw;
- sc = audio_calloc (AUDIO_FUNC, 1, sizeof (*sc));
+ sc = audio_calloc(__func__, 1, sizeof(*sc));
if (!sc) {
dolog ("Could not allocate soft capture voice (%zu bytes)\n",
sizeof (*sc));
int audio_pcm_hw_get_live_in (HWVoiceIn *hw)
{
int live = hw->total_samples_captured - audio_pcm_hw_find_min_in (hw);
- if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) {
+ if (audio_bug(__func__, live < 0 || live > hw->samples)) {
dolog ("live=%d hw->samples=%d\n", live, hw->samples);
return 0;
}
int live = hw->total_samples_captured - sw->total_hw_samples_acquired;
int rpos;
- if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) {
+ if (audio_bug(__func__, live < 0 || live > hw->samples)) {
dolog ("live=%d hw->samples=%d\n", live, hw->samples);
return 0;
}
rpos = audio_pcm_sw_get_rpos_in (sw) % hw->samples;
live = hw->total_samples_captured - sw->total_hw_samples_acquired;
- if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) {
+ if (audio_bug(__func__, live < 0 || live > hw->samples)) {
dolog ("live_in=%d hw->samples=%d\n", live, hw->samples);
return 0;
}
}
osamp = swlim;
- if (audio_bug (AUDIO_FUNC, osamp < 0)) {
+ if (audio_bug(__func__, osamp < 0)) {
dolog ("osamp=%d\n", osamp);
return 0;
}
if (nb_live1) {
int live = smin;
- if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) {
+ if (audio_bug(__func__, live < 0 || live > hw->samples)) {
dolog ("live=%d hw->samples=%d\n", live, hw->samples);
return 0;
}
hwsamples = sw->hw->samples;
live = sw->total_hw_samples_mixed;
- if (audio_bug (AUDIO_FUNC, live < 0 || live > hwsamples)){
+ if (audio_bug(__func__, live < 0 || live > hwsamples)) {
dolog ("live=%d hw->samples=%d\n", live, hwsamples);
return 0;
}
/*
* Timer
*/
+
+static bool audio_timer_running;
+static uint64_t audio_timer_last;
+
static int audio_is_timer_needed (void)
{
HWVoiceIn *hwi = NULL;
if (audio_is_timer_needed ()) {
timer_mod_anticipate_ns(s->ts,
qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + conf.period.ticks);
- }
- else {
- timer_del (s->ts);
+ if (!audio_timer_running) {
+ audio_timer_running = true;
+ audio_timer_last = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ trace_audio_timer_start(conf.period.ticks / SCALE_MS);
+ }
+ } else {
+ timer_del(s->ts);
+ if (audio_timer_running) {
+ audio_timer_running = false;
+ trace_audio_timer_stop();
+ }
}
}
static void audio_timer (void *opaque)
{
+ int64_t now, diff;
+
+ now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ diff = now - audio_timer_last;
+ if (diff > conf.period.ticks * 3 / 2) {
+ trace_audio_timer_delayed(diff / SCALE_MS);
+ }
+ audio_timer_last = now;
+
audio_run ("timer");
audio_reset_timer (opaque);
}
}
live = sw->hw->total_samples_captured - sw->total_hw_samples_acquired;
- if (audio_bug (AUDIO_FUNC, live < 0 || live > sw->hw->samples)) {
+ if (audio_bug(__func__, live < 0 || live > sw->hw->samples)) {
dolog ("live=%d sw->hw->samples=%d\n", live, sw->hw->samples);
return 0;
}
live = sw->total_hw_samples_mixed;
- if (audio_bug (AUDIO_FUNC, live < 0 || live > sw->hw->samples)) {
+ if (audio_bug(__func__, live < 0 || live > sw->hw->samples)) {
dolog ("live=%d sw->hw->samples=%d\n", live, sw->hw->samples);
return 0;
}
live = 0;
}
- if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) {
+ if (audio_bug(__func__, live < 0 || live > hw->samples)) {
dolog ("live=%d hw->samples=%d\n", live, hw->samples);
continue;
}
prev_rpos = hw->rpos;
played = hw->pcm_ops->run_out (hw, live);
replay_audio_out(&played);
- if (audio_bug (AUDIO_FUNC, hw->rpos >= hw->samples)) {
+ if (audio_bug(__func__, hw->rpos >= hw->samples)) {
dolog ("hw->rpos=%d hw->samples=%d played=%d\n",
hw->rpos, hw->samples, played);
hw->rpos = 0;
continue;
}
- if (audio_bug (AUDIO_FUNC, played > sw->total_hw_samples_mixed)) {
+ if (audio_bug(__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;
continue;
}
- if (audio_bug (AUDIO_FUNC, captured > sw->total_hw_samples_mixed)) {
+ if (audio_bug(__func__, captured > sw->total_hw_samples_mixed)) {
dolog ("captured=%d sw->total_hw_samples_mixed=%d\n",
captured, sw->total_hw_samples_mixed);
captured = sw->total_hw_samples_mixed;
void AUD_help (void)
{
- size_t i;
+ struct audio_driver *d;
+
+ /* make sure we print the help text for modular drivers too */
+ audio_module_load_all();
audio_process_options ("AUDIO", audio_options);
- for (i = 0; i < ARRAY_SIZE (drvtab); i++) {
- struct audio_driver *d = drvtab[i];
+ QLIST_FOREACH(d, &audio_drivers, next) {
if (d->options) {
audio_process_options (d->name, d->options);
}
printf ("Available drivers:\n");
- for (i = 0; i < ARRAY_SIZE (drvtab); i++) {
- struct audio_driver *d = drvtab[i];
+ QLIST_FOREACH(d, &audio_drivers, next) {
printf ("Name: %s\n", d->name);
printf ("Description: %s\n", d->descr);
const char *drvname;
VMChangeStateEntry *e;
AudioState *s = &glob_audio_state;
+ struct audio_driver *driver;
if (s->drv) {
return;
}
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) {
+ driver = audio_driver_lookup(drvname);
+ if (driver) {
+ done = !audio_driver_init(s, driver);
+ } else {
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]);
+ for (i = 0; !done && i < ARRAY_SIZE(audio_prio_list); i++) {
+ driver = audio_driver_lookup(audio_prio_list[i]);
+ if (driver && driver->can_be_default) {
+ done = !audio_driver_init(s, driver);
}
}
}
if (!done) {
- done = !audio_driver_init (s, &no_audio_driver);
+ driver = audio_driver_lookup("none");
+ done = !audio_driver_init(s, driver);
assert(done);
dolog("warning: Using timer based audio emulation\n");
}
goto err0;
}
- cb = audio_calloc (AUDIO_FUNC, 1, sizeof (*cb));
+ cb = audio_calloc(__func__, 1, sizeof(*cb));
if (!cb) {
dolog ("Could not allocate capture callback information, size %zu\n",
sizeof (*cb));
HWVoiceOut *hw;
CaptureVoiceOut *cap;
- cap = audio_calloc (AUDIO_FUNC, 1, sizeof (*cap));
+ cap = audio_calloc(__func__, 1, sizeof(*cap));
if (!cap) {
dolog ("Could not allocate capture voice, size %zu\n",
sizeof (*cap));
/* XXX find a more elegant way */
hw->samples = 4096 * 4;
- hw->mix_buf = audio_calloc (AUDIO_FUNC, hw->samples,
- sizeof (struct st_sample));
+ hw->mix_buf = audio_calloc(__func__, hw->samples,
+ sizeof(struct st_sample));
if (!hw->mix_buf) {
dolog ("Could not allocate capture mix buffer (%d samples)\n",
hw->samples);
audio_pcm_init_info (&hw->info, as);
- cap->buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
+ cap->buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift);
if (!cap->buf) {
dolog ("Could not allocate capture buffer "
"(%d samples, each %d bytes)\n",