aboutsummaryrefslogtreecommitdiff
path: root/hw/audio
diff options
context:
space:
mode:
authorMark Cave-Ayland <mark.cave-ayland@ilande.co.uk>2023-10-04 09:37:54 +0100
committerLaurent Vivier <laurent@vivier.eu>2023-10-06 10:33:43 +0200
commit5243e5543e27410984d84a30aa7d7b7210d14daa (patch)
treeaf4719aa5f499c9fd8327941ed28eac784a5a3a6 /hw/audio
parentac13a6b3fd7421606822bd20c7d847c0756fd32d (diff)
downloadqemu-5243e5543e27410984d84a30aa7d7b7210d14daa.zip
qemu-5243e5543e27410984d84a30aa7d7b7210d14daa.tar.gz
qemu-5243e5543e27410984d84a30aa7d7b7210d14daa.tar.bz2
asc: generate silence if FIFO empty but engine still running
MacOS (un)helpfully leaves the FIFO engine running even when all the samples have been written to the hardware, and expects the FIFO status flags and IRQ to be updated continuously. There is an additional problem in that not all audio backends guarantee an all-zero output when there is no FIFO data available, in particular the Windows dsound backend which re-uses its internal circular buffer causing the last played sound to loop indefinitely. Whilst this is effectively a bug in the Windows dsound backend, work around it for now using a simple heuristic: if the FIFO remains empty for half a cycle (~23ms) then continuously fill the generated buffer with empty silence. Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> Reviewed-by: Laurent Vivier <laurent@vivier.eu> Message-ID: <20231004083806.757242-9-mark.cave-ayland@ilande.co.uk> Signed-off-by: Laurent Vivier <laurent@vivier.eu>
Diffstat (limited to 'hw/audio')
-rw-r--r--hw/audio/asc.c19
1 files changed, 19 insertions, 0 deletions
diff --git a/hw/audio/asc.c b/hw/audio/asc.c
index 9084708..0f36b4c 100644
--- a/hw/audio/asc.c
+++ b/hw/audio/asc.c
@@ -341,6 +341,21 @@ static void asc_out_cb(void *opaque, int free_b)
}
if (!generated) {
+ /* Workaround for audio underflow bug on Windows dsound backend */
+ int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ int silent_samples = muldiv64(now - s->fifo_empty_ns,
+ NANOSECONDS_PER_SECOND, ASC_FREQ);
+
+ if (silent_samples > ASC_FIFO_CYCLE_TIME / 2) {
+ /*
+ * No new FIFO data within half a cycle time (~23ms) so fill the
+ * entire available buffer with silence. This prevents an issue
+ * with the Windows dsound backend whereby the sound appears to
+ * loop because the FIFO has run out of data, and the driver
+ * reuses the stale content in its circular audio buffer.
+ */
+ AUD_write(s->voice, s->silentbuf, samples << s->shift);
+ }
return;
}
@@ -618,6 +633,7 @@ static void asc_unrealize(DeviceState *dev)
ASCState *s = ASC(dev);
g_free(s->mixbuf);
+ g_free(s->silentbuf);
AUD_remove_card(&s->card);
}
@@ -642,6 +658,9 @@ static void asc_realize(DeviceState *dev, Error **errp)
s->samples = AUD_get_buffer_size_out(s->voice) >> s->shift;
s->mixbuf = g_malloc0(s->samples << s->shift);
+ s->silentbuf = g_malloc0(s->samples << s->shift);
+ memset(s->silentbuf, 0x80, s->samples << s->shift);
+
/* Add easc registers if required */
if (s->type == ASC_TYPE_EASC) {
memory_region_add_subregion(&s->asc, ASC_EXTREG_OFFSET,