[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PULL 06/12] audio: fix bug 1858488
From: |
Gerd Hoffmann |
Subject: |
[PULL 06/12] audio: fix bug 1858488 |
Date: |
Fri, 7 Feb 2020 08:45:51 +0100 |
From: Volker RĂ¼melin <address@hidden>
The combined generic buffer management code and buffer run out
code in function audio_generic_put_buffer_out has a problematic
behaviour. A few hundred milliseconds after playback starts the
mixing buffer and the generic buffer are nearly full and the
following pattern can be seen.
On first call of audio_pcm_hw_run_out the buffer run code in
audio_generic_put_buffer_out writes some data to the audio
hardware but the generic buffer will fill faster and is full
when audio_pcm_hw_run_out returns. This is because emulated
audio devices can produce playback data at a higher rate than
the audio backend hardware consumes this data.
On next call of audio_pcm_hw_run_out the buffer run code in
audio_generic_put_buffer_out writes some data to the audio
hardware but no audio data is transferred to the generic buffer
because the buffer is already full.
Then the pattern repeats. For the emulated audio device this
looks like the audio timer period has doubled.
This patch splits the combined generic buffer management code
and buffer run out code and calls the buffer run out code after
buffer management code to break this pattern.
The bug report is for the wav audio backend. But the problem is
not limited to this backend. All audio backends which use the
audio_generic_put_buffer_out function show this problem.
Buglink: https://bugs.launchpad.net/qemu/+bug/1858488
Signed-off-by: Volker RĂ¼melin <address@hidden>
Message-Id: <address@hidden>
Signed-off-by: Gerd Hoffmann <address@hidden>
---
audio/audio_int.h | 4 +--
audio/alsaaudio.c | 1 +
audio/audio.c | 64 ++++++++++++++++++++++-------------------------
audio/coreaudio.c | 7 ++++--
audio/noaudio.c | 1 +
audio/ossaudio.c | 10 ++++++++
audio/sdlaudio.c | 7 ++++--
audio/wavaudio.c | 1 +
8 files changed, 55 insertions(+), 40 deletions(-)
diff --git a/audio/audio_int.h b/audio/audio_int.h
index 5ba20783463a..3c8e48b55b1c 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -152,6 +152,7 @@ struct audio_pcm_ops {
int (*init_out)(HWVoiceOut *hw, audsettings *as, void *drv_opaque);
void (*fini_out)(HWVoiceOut *hw);
size_t (*write) (HWVoiceOut *hw, void *buf, size_t size);
+ void (*run_buffer_out)(HWVoiceOut *hw);
/*
* get a buffer that after later can be passed to put_buffer_out; optional
* returns the buffer, and writes it's size to size (in bytes)
@@ -178,10 +179,9 @@ struct audio_pcm_ops {
void *audio_generic_get_buffer_in(HWVoiceIn *hw, size_t *size);
void audio_generic_put_buffer_in(HWVoiceIn *hw, void *buf, size_t size);
+void audio_generic_run_buffer_out(HWVoiceOut *hw);
void *audio_generic_get_buffer_out(HWVoiceOut *hw, size_t *size);
size_t audio_generic_put_buffer_out(HWVoiceOut *hw, void *buf, size_t size);
-size_t audio_generic_put_buffer_out_nowrite(HWVoiceOut *hw, void *buf,
- size_t size);
size_t audio_generic_write(HWVoiceOut *hw, void *buf, size_t size);
size_t audio_generic_read(HWVoiceIn *hw, void *buf, size_t size);
diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c
index f37ce1ce8570..4ef26818be57 100644
--- a/audio/alsaaudio.c
+++ b/audio/alsaaudio.c
@@ -906,6 +906,7 @@ static struct audio_pcm_ops alsa_pcm_ops = {
.init_out = alsa_init_out,
.fini_out = alsa_fini_out,
.write = alsa_write,
+ .run_buffer_out = audio_generic_run_buffer_out,
.enable_out = alsa_enable_out,
.init_in = alsa_init_in,
diff --git a/audio/audio.c b/audio/audio.c
index 12ed318813f4..b686429203d6 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -1097,6 +1097,10 @@ static size_t audio_pcm_hw_run_out(HWVoiceOut *hw,
size_t live)
}
}
+ if (hw->pcm_ops->run_buffer_out) {
+ hw->pcm_ops->run_buffer_out(hw);
+ }
+
return clipped;
}
@@ -1413,40 +1417,12 @@ void audio_generic_put_buffer_in(HWVoiceIn *hw, void
*buf, size_t size)
hw->pending_emul -= size;
}
-void *audio_generic_get_buffer_out(HWVoiceOut *hw, size_t *size)
+void audio_generic_run_buffer_out(HWVoiceOut *hw)
{
- if (unlikely(!hw->buf_emul)) {
- size_t calc_size = hw->mix_buf->size * hw->info.bytes_per_frame;
-
- hw->buf_emul = g_malloc(calc_size);
- hw->size_emul = calc_size;
- hw->pos_emul = hw->pending_emul = 0;
- }
-
- *size = MIN(hw->size_emul - hw->pending_emul,
- hw->size_emul - hw->pos_emul);
- return hw->buf_emul + hw->pos_emul;
-}
-
-size_t audio_generic_put_buffer_out_nowrite(HWVoiceOut *hw, void *buf,
- size_t size)
-{
- assert(buf == hw->buf_emul + hw->pos_emul &&
- size + hw->pending_emul <= hw->size_emul);
-
- hw->pending_emul += size;
- hw->pos_emul = (hw->pos_emul + size) % hw->size_emul;
-
- return size;
-}
-
-size_t audio_generic_put_buffer_out(HWVoiceOut *hw, void *buf, size_t size)
-{
- audio_generic_put_buffer_out_nowrite(hw, buf, size);
-
while (hw->pending_emul) {
size_t write_len, written;
ssize_t start = ((ssize_t) hw->pos_emul) - hw->pending_emul;
+
if (start < 0) {
start += hw->size_emul;
}
@@ -1461,11 +1437,31 @@ size_t audio_generic_put_buffer_out(HWVoiceOut *hw,
void *buf, size_t size)
break;
}
}
+}
+
+void *audio_generic_get_buffer_out(HWVoiceOut *hw, size_t *size)
+{
+ if (unlikely(!hw->buf_emul)) {
+ size_t calc_size = hw->mix_buf->size * hw->info.bytes_per_frame;
+
+ hw->buf_emul = g_malloc(calc_size);
+ hw->size_emul = calc_size;
+ hw->pos_emul = hw->pending_emul = 0;
+ }
+
+ *size = MIN(hw->size_emul - hw->pending_emul,
+ hw->size_emul - hw->pos_emul);
+ return hw->buf_emul + hw->pos_emul;
+}
+
+size_t audio_generic_put_buffer_out(HWVoiceOut *hw, void *buf, size_t size)
+{
+ assert(buf == hw->buf_emul + hw->pos_emul &&
+ size + hw->pending_emul <= hw->size_emul);
+
+ hw->pending_emul += size;
+ hw->pos_emul = (hw->pos_emul + size) % hw->size_emul;
- /*
- * fake we have written everything. non-written data remain in
pending_emul,
- * so we do not have to clip them multiple times
- */
return size;
}
diff --git a/audio/coreaudio.c b/audio/coreaudio.c
index 66f0f459cf09..c7a7196c2d53 100644
--- a/audio/coreaudio.c
+++ b/audio/coreaudio.c
@@ -411,7 +411,7 @@ static int coreaudio_unlock (coreaudioVoiceOut *core, const
char *fn_name)
}
COREAUDIO_WRAPPER_FUNC(get_buffer_out, void *, (HWVoiceOut *hw, size_t *size),
(hw, size))
-COREAUDIO_WRAPPER_FUNC(put_buffer_out_nowrite, size_t,
+COREAUDIO_WRAPPER_FUNC(put_buffer_out, size_t,
(HWVoiceOut *hw, void *buf, size_t size),
(hw, buf, size))
COREAUDIO_WRAPPER_FUNC(write, size_t, (HWVoiceOut *hw, void *buf, size_t size),
@@ -687,9 +687,12 @@ static void coreaudio_audio_fini (void *opaque)
static struct audio_pcm_ops coreaudio_pcm_ops = {
.init_out = coreaudio_init_out,
.fini_out = coreaudio_fini_out,
+ /* wrapper for audio_generic_write */
.write = coreaudio_write,
+ /* wrapper for audio_generic_get_buffer_out */
.get_buffer_out = coreaudio_get_buffer_out,
- .put_buffer_out = coreaudio_put_buffer_out_nowrite,
+ /* wrapper for audio_generic_put_buffer_out */
+ .put_buffer_out = coreaudio_put_buffer_out,
.enable_out = coreaudio_enable_out
};
diff --git a/audio/noaudio.c b/audio/noaudio.c
index ff99b253ff0b..05798ea21032 100644
--- a/audio/noaudio.c
+++ b/audio/noaudio.c
@@ -118,6 +118,7 @@ static struct audio_pcm_ops no_pcm_ops = {
.init_out = no_init_out,
.fini_out = no_fini_out,
.write = no_write,
+ .run_buffer_out = audio_generic_run_buffer_out,
.enable_out = no_enable_out,
.init_in = no_init_in,
diff --git a/audio/ossaudio.c b/audio/ossaudio.c
index 94564916fbf0..576b5b5b2021 100644
--- a/audio/ossaudio.c
+++ b/audio/ossaudio.c
@@ -382,6 +382,15 @@ static size_t oss_get_available_bytes(OSSVoiceOut *oss)
return audio_ring_dist(cntinfo.ptr, oss->hw.pos_emul, oss->hw.size_emul);
}
+static void oss_run_buffer_out(HWVoiceOut *hw)
+{
+ OSSVoiceOut *oss = (OSSVoiceOut *)hw;
+
+ if (!oss->mmapped) {
+ audio_generic_run_buffer_out(hw);
+ }
+}
+
static void *oss_get_buffer_out(HWVoiceOut *hw, size_t *size)
{
OSSVoiceOut *oss = (OSSVoiceOut *) hw;
@@ -748,6 +757,7 @@ static struct audio_pcm_ops oss_pcm_ops = {
.init_out = oss_init_out,
.fini_out = oss_fini_out,
.write = oss_write,
+ .run_buffer_out = oss_run_buffer_out,
.get_buffer_out = oss_get_buffer_out,
.put_buffer_out = oss_put_buffer_out,
.enable_out = oss_enable_out,
diff --git a/audio/sdlaudio.c b/audio/sdlaudio.c
index 5c6bcfcb3e9d..c00e7d784523 100644
--- a/audio/sdlaudio.c
+++ b/audio/sdlaudio.c
@@ -227,7 +227,7 @@ static void sdl_callback (void *opaque, Uint8 *buf, int len)
SDL_WRAPPER_FUNC(get_buffer_out, void *, (HWVoiceOut *hw, size_t *size),
(hw, size), *size = 0, sdl_unlock)
-SDL_WRAPPER_FUNC(put_buffer_out_nowrite, size_t,
+SDL_WRAPPER_FUNC(put_buffer_out, size_t,
(HWVoiceOut *hw, void *buf, size_t size), (hw, buf, size),
/*nothing*/, sdl_unlock_and_post)
SDL_WRAPPER_FUNC(write, size_t,
@@ -320,9 +320,12 @@ static void sdl_audio_fini (void *opaque)
static struct audio_pcm_ops sdl_pcm_ops = {
.init_out = sdl_init_out,
.fini_out = sdl_fini_out,
+ /* wrapper for audio_generic_write */
.write = sdl_write,
+ /* wrapper for audio_generic_get_buffer_out */
.get_buffer_out = sdl_get_buffer_out,
- .put_buffer_out = sdl_put_buffer_out_nowrite,
+ /* wrapper for audio_generic_put_buffer_out */
+ .put_buffer_out = sdl_put_buffer_out,
.enable_out = sdl_enable_out,
};
diff --git a/audio/wavaudio.c b/audio/wavaudio.c
index e46d834bd3af..20e6853f8586 100644
--- a/audio/wavaudio.c
+++ b/audio/wavaudio.c
@@ -197,6 +197,7 @@ static struct audio_pcm_ops wav_pcm_ops = {
.init_out = wav_init_out,
.fini_out = wav_fini_out,
.write = wav_write_out,
+ .run_buffer_out = audio_generic_run_buffer_out,
.enable_out = wav_enable_out,
};
--
2.18.1
- [PULL 00/12] Audio 20200207 patches, Gerd Hoffmann, 2020/02/07
- [PULL 02/12] audio: fix audio_generic_write, Gerd Hoffmann, 2020/02/07
- [PULL 04/12] paaudio: remove unused variables, Gerd Hoffmann, 2020/02/07
- [PULL 01/12] audio/oss: fix buffer pos calculation, Gerd Hoffmann, 2020/02/07
- [PULL 05/12] audio: prevent SIGSEGV in AUD_get_buffer_size_out, Gerd Hoffmann, 2020/02/07
- [PULL 03/12] audio: fix audio_generic_read, Gerd Hoffmann, 2020/02/07
- [PULL 07/12] ossaudio: prevent SIGSEGV in oss_enable_out, Gerd Hoffmann, 2020/02/07
- [PULL 08/12] ossaudio: disable poll mode can't be reached, Gerd Hoffmann, 2020/02/07
- [PULL 11/12] coreaudio: fix coreaudio playback, Gerd Hoffmann, 2020/02/07
- [PULL 09/12] audio: audio_generic_get_buffer_in should honor *size, Gerd Hoffmann, 2020/02/07
- [PULL 06/12] audio: fix bug 1858488,
Gerd Hoffmann <=
- [PULL 12/12] audio: proper support for float samples in mixeng, Gerd Hoffmann, 2020/02/07
- [PULL 10/12] audio/dsound: fix invalid parameters error, Gerd Hoffmann, 2020/02/07
- Re: [PULL 00/12] Audio 20200207 patches, Peter Maydell, 2020/02/07