* [PATCH v2 01/17] audio: change type of mix_buf and conv_buf
2023-02-06 18:47 [PATCH v2 00/17] audio: improve callback interface for audio frontends Volker Rümelin
@ 2023-02-06 18:52 ` Volker Rümelin
2023-02-22 10:49 ` Marc-André Lureau
2023-02-06 18:52 ` [PATCH v2 02/17] audio: change type and name of the resample buffer Volker Rümelin
` (15 subsequent siblings)
16 siblings, 1 reply; 34+ messages in thread
From: Volker Rümelin @ 2023-02-06 18:52 UTC (permalink / raw)
To: Gerd Hoffmann, Marc-André Lureau
Cc: qemu-devel, Christian Schoenebeck, Mark Cave-Ayland
Change the type of mix_buf in struct HWVoiceOut and conv_buf
in struct HWVoiceIn from STSampleBuffer * to STSampleBuffer.
However, a buffer pointer is still needed. For this reason in
struct STSampleBuffer samples[] is changed to *buffer.
This is a preparation for the next patch. The next patch will
add this line, which is not possible with the current struct
STSampleBuffer definition.
+ sw->resample_buf.buffer = hw->mix_buf.buffer + rpos2;
There are no functional changes.
Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
---
audio/audio.c | 106 ++++++++++++++++++++---------------------
audio/audio_int.h | 6 +--
audio/audio_template.h | 19 ++++----
3 files changed, 67 insertions(+), 64 deletions(-)
diff --git a/audio/audio.c b/audio/audio.c
index 772c3cc320..a0b54e4a2e 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -523,8 +523,8 @@ static size_t audio_pcm_hw_find_min_in (HWVoiceIn *hw)
static size_t audio_pcm_hw_get_live_in(HWVoiceIn *hw)
{
size_t live = hw->total_samples_captured - audio_pcm_hw_find_min_in (hw);
- if (audio_bug(__func__, live > hw->conv_buf->size)) {
- dolog("live=%zu hw->conv_buf->size=%zu\n", live, hw->conv_buf->size);
+ if (audio_bug(__func__, live > hw->conv_buf.size)) {
+ dolog("live=%zu hw->conv_buf.size=%zu\n", live, hw->conv_buf.size);
return 0;
}
return live;
@@ -533,13 +533,13 @@ static size_t audio_pcm_hw_get_live_in(HWVoiceIn *hw)
static size_t audio_pcm_hw_conv_in(HWVoiceIn *hw, void *pcm_buf, size_t samples)
{
size_t conv = 0;
- STSampleBuffer *conv_buf = hw->conv_buf;
+ STSampleBuffer *conv_buf = &hw->conv_buf;
while (samples) {
uint8_t *src = advance(pcm_buf, conv * hw->info.bytes_per_frame);
size_t proc = MIN(samples, conv_buf->size - conv_buf->pos);
- hw->conv(conv_buf->samples + conv_buf->pos, src, proc);
+ hw->conv(conv_buf->buffer + conv_buf->pos, src, proc);
conv_buf->pos = (conv_buf->pos + proc) % conv_buf->size;
samples -= proc;
conv += proc;
@@ -561,12 +561,12 @@ static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t size)
if (!live) {
return 0;
}
- if (audio_bug(__func__, live > hw->conv_buf->size)) {
- dolog("live_in=%zu hw->conv_buf->size=%zu\n", live, hw->conv_buf->size);
+ if (audio_bug(__func__, live > hw->conv_buf.size)) {
+ dolog("live_in=%zu hw->conv_buf.size=%zu\n", live, hw->conv_buf.size);
return 0;
}
- rpos = audio_ring_posb(hw->conv_buf->pos, live, hw->conv_buf->size);
+ rpos = audio_ring_posb(hw->conv_buf.pos, live, hw->conv_buf.size);
samples = size / sw->info.bytes_per_frame;
@@ -574,11 +574,11 @@ static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t size)
swlim = MIN (swlim, samples);
while (swlim) {
- src = hw->conv_buf->samples + rpos;
- if (hw->conv_buf->pos > rpos) {
- isamp = hw->conv_buf->pos - rpos;
+ src = hw->conv_buf.buffer + rpos;
+ if (hw->conv_buf.pos > rpos) {
+ isamp = hw->conv_buf.pos - rpos;
} else {
- isamp = hw->conv_buf->size - rpos;
+ isamp = hw->conv_buf.size - rpos;
}
if (!isamp) {
@@ -588,7 +588,7 @@ static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t size)
st_rate_flow (sw->rate, src, dst, &isamp, &osamp);
swlim -= osamp;
- rpos = (rpos + isamp) % hw->conv_buf->size;
+ rpos = (rpos + isamp) % hw->conv_buf.size;
dst += osamp;
ret += osamp;
total += isamp;
@@ -636,8 +636,8 @@ static size_t audio_pcm_hw_get_live_out (HWVoiceOut *hw, int *nb_live)
if (nb_live1) {
size_t live = smin;
- if (audio_bug(__func__, live > hw->mix_buf->size)) {
- dolog("live=%zu hw->mix_buf->size=%zu\n", live, hw->mix_buf->size);
+ if (audio_bug(__func__, live > hw->mix_buf.size)) {
+ dolog("live=%zu hw->mix_buf.size=%zu\n", live, hw->mix_buf.size);
return 0;
}
return live;
@@ -654,17 +654,17 @@ static size_t audio_pcm_hw_get_free(HWVoiceOut *hw)
static void audio_pcm_hw_clip_out(HWVoiceOut *hw, void *pcm_buf, size_t len)
{
size_t clipped = 0;
- size_t pos = hw->mix_buf->pos;
+ size_t pos = hw->mix_buf.pos;
while (len) {
- st_sample *src = hw->mix_buf->samples + pos;
+ st_sample *src = hw->mix_buf.buffer + pos;
uint8_t *dst = advance(pcm_buf, clipped * hw->info.bytes_per_frame);
- size_t samples_till_end_of_buf = hw->mix_buf->size - pos;
+ size_t samples_till_end_of_buf = hw->mix_buf.size - pos;
size_t samples_to_clip = MIN(len, samples_till_end_of_buf);
hw->clip(dst, src, samples_to_clip);
- pos = (pos + samples_to_clip) % hw->mix_buf->size;
+ pos = (pos + samples_to_clip) % hw->mix_buf.size;
len -= samples_to_clip;
clipped += samples_to_clip;
}
@@ -683,11 +683,11 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
return size;
}
- hwsamples = sw->hw->mix_buf->size;
+ hwsamples = sw->hw->mix_buf.size;
live = sw->total_hw_samples_mixed;
if (audio_bug(__func__, live > hwsamples)) {
- dolog("live=%zu hw->mix_buf->size=%zu\n", live, hwsamples);
+ dolog("live=%zu hw->mix_buf.size=%zu\n", live, hwsamples);
return 0;
}
@@ -698,7 +698,7 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
return 0;
}
- wpos = (sw->hw->mix_buf->pos + live) % hwsamples;
+ wpos = (sw->hw->mix_buf.pos + live) % hwsamples;
dead = hwsamples - live;
hw_free = audio_pcm_hw_get_free(sw->hw);
@@ -725,7 +725,7 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
st_rate_flow_mix (
sw->rate,
sw->buf + pos,
- sw->hw->mix_buf->samples + wpos,
+ sw->hw->mix_buf.buffer + wpos,
&isamp,
&osamp
);
@@ -989,9 +989,9 @@ static size_t audio_get_avail (SWVoiceIn *sw)
}
live = sw->hw->total_samples_captured - sw->total_hw_samples_acquired;
- if (audio_bug(__func__, live > sw->hw->conv_buf->size)) {
- dolog("live=%zu sw->hw->conv_buf->size=%zu\n", live,
- sw->hw->conv_buf->size);
+ if (audio_bug(__func__, live > sw->hw->conv_buf.size)) {
+ dolog("live=%zu sw->hw->conv_buf.size=%zu\n", live,
+ sw->hw->conv_buf.size);
return 0;
}
@@ -1026,13 +1026,13 @@ static size_t audio_get_free(SWVoiceOut *sw)
live = sw->total_hw_samples_mixed;
- if (audio_bug(__func__, live > sw->hw->mix_buf->size)) {
- dolog("live=%zu sw->hw->mix_buf->size=%zu\n", live,
- sw->hw->mix_buf->size);
+ if (audio_bug(__func__, live > sw->hw->mix_buf.size)) {
+ dolog("live=%zu sw->hw->mix_buf.size=%zu\n", live,
+ sw->hw->mix_buf.size);
return 0;
}
- dead = sw->hw->mix_buf->size - live;
+ dead = sw->hw->mix_buf.size - live;
#ifdef DEBUG_OUT
dolog("%s: get_free live %zu dead %zu frontend frames %zu\n",
@@ -1056,12 +1056,12 @@ static void audio_capture_mix_and_clear(HWVoiceOut *hw, size_t rpos,
n = samples;
while (n) {
- size_t till_end_of_hw = hw->mix_buf->size - rpos2;
+ size_t till_end_of_hw = hw->mix_buf.size - rpos2;
size_t to_write = MIN(till_end_of_hw, n);
size_t bytes = to_write * hw->info.bytes_per_frame;
size_t written;
- sw->buf = hw->mix_buf->samples + rpos2;
+ sw->buf = hw->mix_buf.buffer + rpos2;
written = audio_pcm_sw_write (sw, NULL, bytes);
if (written - bytes) {
dolog("Could not mix %zu bytes into a capture "
@@ -1070,14 +1070,14 @@ static void audio_capture_mix_and_clear(HWVoiceOut *hw, size_t rpos,
break;
}
n -= to_write;
- rpos2 = (rpos2 + to_write) % hw->mix_buf->size;
+ rpos2 = (rpos2 + to_write) % hw->mix_buf.size;
}
}
}
- n = MIN(samples, hw->mix_buf->size - rpos);
- mixeng_clear(hw->mix_buf->samples + rpos, n);
- mixeng_clear(hw->mix_buf->samples, samples - n);
+ n = MIN(samples, hw->mix_buf.size - rpos);
+ mixeng_clear(hw->mix_buf.buffer + rpos, n);
+ mixeng_clear(hw->mix_buf.buffer, samples - n);
}
static size_t audio_pcm_hw_run_out(HWVoiceOut *hw, size_t live)
@@ -1103,7 +1103,7 @@ static size_t audio_pcm_hw_run_out(HWVoiceOut *hw, size_t live)
live -= proc;
clipped += proc;
- hw->mix_buf->pos = (hw->mix_buf->pos + proc) % hw->mix_buf->size;
+ hw->mix_buf.pos = (hw->mix_buf.pos + proc) % hw->mix_buf.size;
if (proc == 0 || proc < decr) {
break;
@@ -1174,8 +1174,8 @@ static void audio_run_out (AudioState *s)
live = 0;
}
- if (audio_bug(__func__, live > hw->mix_buf->size)) {
- dolog("live=%zu hw->mix_buf->size=%zu\n", live, hw->mix_buf->size);
+ if (audio_bug(__func__, live > hw->mix_buf.size)) {
+ dolog("live=%zu hw->mix_buf.size=%zu\n", live, hw->mix_buf.size);
continue;
}
@@ -1203,13 +1203,13 @@ static void audio_run_out (AudioState *s)
continue;
}
- prev_rpos = hw->mix_buf->pos;
+ prev_rpos = hw->mix_buf.pos;
played = audio_pcm_hw_run_out(hw, live);
replay_audio_out(&played);
- if (audio_bug(__func__, hw->mix_buf->pos >= hw->mix_buf->size)) {
- dolog("hw->mix_buf->pos=%zu hw->mix_buf->size=%zu played=%zu\n",
- hw->mix_buf->pos, hw->mix_buf->size, played);
- hw->mix_buf->pos = 0;
+ if (audio_bug(__func__, hw->mix_buf.pos >= hw->mix_buf.size)) {
+ dolog("hw->mix_buf.pos=%zu hw->mix_buf.size=%zu played=%zu\n",
+ hw->mix_buf.pos, hw->mix_buf.size, played);
+ hw->mix_buf.pos = 0;
}
#ifdef DEBUG_OUT
@@ -1290,10 +1290,10 @@ static void audio_run_in (AudioState *s)
if (replay_mode != REPLAY_MODE_PLAY) {
captured = audio_pcm_hw_run_in(
- hw, hw->conv_buf->size - audio_pcm_hw_get_live_in(hw));
+ hw, hw->conv_buf.size - audio_pcm_hw_get_live_in(hw));
}
- replay_audio_in(&captured, hw->conv_buf->samples, &hw->conv_buf->pos,
- hw->conv_buf->size);
+ replay_audio_in(&captured, hw->conv_buf.buffer, &hw->conv_buf.pos,
+ hw->conv_buf.size);
min = audio_pcm_hw_find_min_in (hw);
hw->total_samples_captured += captured - min;
@@ -1326,14 +1326,14 @@ static void audio_run_capture (AudioState *s)
SWVoiceOut *sw;
captured = live = audio_pcm_hw_get_live_out (hw, NULL);
- rpos = hw->mix_buf->pos;
+ rpos = hw->mix_buf.pos;
while (live) {
- size_t left = hw->mix_buf->size - rpos;
+ size_t left = hw->mix_buf.size - rpos;
size_t to_capture = MIN(live, left);
struct st_sample *src;
struct capture_callback *cb;
- src = hw->mix_buf->samples + rpos;
+ src = hw->mix_buf.buffer + rpos;
hw->clip (cap->buf, src, to_capture);
mixeng_clear (src, to_capture);
@@ -1341,10 +1341,10 @@ static void audio_run_capture (AudioState *s)
cb->ops.capture (cb->opaque, cap->buf,
to_capture * hw->info.bytes_per_frame);
}
- rpos = (rpos + to_capture) % hw->mix_buf->size;
+ rpos = (rpos + to_capture) % hw->mix_buf.size;
live -= to_capture;
}
- hw->mix_buf->pos = rpos;
+ hw->mix_buf.pos = rpos;
for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
if (!sw->active && sw->empty) {
@@ -1903,7 +1903,7 @@ CaptureVoiceOut *AUD_add_capture(
audio_pcm_init_info (&hw->info, as);
- cap->buf = g_malloc0_n(hw->mix_buf->size, hw->info.bytes_per_frame);
+ cap->buf = g_malloc0_n(hw->mix_buf.size, hw->info.bytes_per_frame);
if (hw->info.is_float) {
hw->clip = mixeng_clip_float[hw->info.nchannels == 2];
@@ -1955,7 +1955,7 @@ void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque)
sw = sw1;
}
QLIST_REMOVE (cap, entries);
- g_free (cap->hw.mix_buf);
+ g_free(cap->hw.mix_buf.buffer);
g_free (cap->buf);
g_free (cap);
}
diff --git a/audio/audio_int.h b/audio/audio_int.h
index 5028f2354a..061845dcc2 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -58,7 +58,7 @@ typedef struct SWVoiceCap SWVoiceCap;
typedef struct STSampleBuffer {
size_t pos, size;
- st_sample samples[];
+ st_sample *buffer;
} STSampleBuffer;
typedef struct HWVoiceOut {
@@ -71,7 +71,7 @@ typedef struct HWVoiceOut {
f_sample *clip;
uint64_t ts_helper;
- STSampleBuffer *mix_buf;
+ STSampleBuffer mix_buf;
void *buf_emul;
size_t pos_emul, pending_emul, size_emul;
@@ -93,7 +93,7 @@ typedef struct HWVoiceIn {
size_t total_samples_captured;
uint64_t ts_helper;
- STSampleBuffer *conv_buf;
+ STSampleBuffer conv_buf;
void *buf_emul;
size_t pos_emul, pending_emul, size_emul;
diff --git a/audio/audio_template.h b/audio/audio_template.h
index 980e1f4bd0..dd87170cbd 100644
--- a/audio/audio_template.h
+++ b/audio/audio_template.h
@@ -71,8 +71,9 @@ static void glue(audio_init_nb_voices_, TYPE)(AudioState *s,
static void glue (audio_pcm_hw_free_resources_, TYPE) (HW *hw)
{
g_free(hw->buf_emul);
- g_free (HWBUF);
- HWBUF = NULL;
+ g_free(HWBUF.buffer);
+ HWBUF.buffer = NULL;
+ HWBUF.size = 0;
}
static void glue(audio_pcm_hw_alloc_resources_, TYPE)(HW *hw)
@@ -83,10 +84,12 @@ static void glue(audio_pcm_hw_alloc_resources_, TYPE)(HW *hw)
dolog("Attempted to allocate empty buffer\n");
}
- HWBUF = g_malloc0(sizeof(STSampleBuffer) + sizeof(st_sample) * samples);
- HWBUF->size = samples;
+ HWBUF.buffer = g_new0(st_sample, samples);
+ HWBUF.size = samples;
+ HWBUF.pos = 0;
} else {
- HWBUF = NULL;
+ HWBUF.buffer = NULL;
+ HWBUF.size = 0;
}
}
@@ -111,9 +114,9 @@ static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
}
#ifdef DAC
- samples = ((int64_t) sw->HWBUF->size << 32) / sw->ratio;
+ samples = ((int64_t)sw->HWBUF.size << 32) / sw->ratio;
#else
- samples = (int64_t)sw->HWBUF->size * sw->ratio >> 32;
+ samples = (int64_t)sw->HWBUF.size * sw->ratio >> 32;
#endif
if (audio_bug(__func__, samples < 0)) {
dolog("Can not allocate buffer for `%s' (%d samples)\n",
@@ -126,7 +129,7 @@ static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
size_t f_fe_min;
/* f_fe_min = ceil(1 [frames] * f_be [Hz] / size_be [frames]) */
- f_fe_min = (hw->info.freq + HWBUF->size - 1) / HWBUF->size;
+ f_fe_min = (hw->info.freq + HWBUF.size - 1) / HWBUF.size;
qemu_log_mask(LOG_UNIMP,
AUDIO_CAP ": The guest selected a " NAME " sample rate"
" of %d Hz for %s. Only sample rates >= %zu Hz are"
--
2.35.3
^ permalink raw reply related [flat|nested] 34+ messages in thread
* Re: [PATCH v2 01/17] audio: change type of mix_buf and conv_buf
2023-02-06 18:52 ` [PATCH v2 01/17] audio: change type of mix_buf and conv_buf Volker Rümelin
@ 2023-02-22 10:49 ` Marc-André Lureau
0 siblings, 0 replies; 34+ messages in thread
From: Marc-André Lureau @ 2023-02-22 10:49 UTC (permalink / raw)
To: Volker Rümelin
Cc: Gerd Hoffmann, qemu-devel, Christian Schoenebeck,
Mark Cave-Ayland
On Mon, Feb 6, 2023 at 10:52 PM Volker Rümelin <vr_qemu@t-online.de> wrote:
>
> Change the type of mix_buf in struct HWVoiceOut and conv_buf
> in struct HWVoiceIn from STSampleBuffer * to STSampleBuffer.
> However, a buffer pointer is still needed. For this reason in
> struct STSampleBuffer samples[] is changed to *buffer.
>
> This is a preparation for the next patch. The next patch will
> add this line, which is not possible with the current struct
> STSampleBuffer definition.
>
> + sw->resample_buf.buffer = hw->mix_buf.buffer + rpos2;
>
> There are no functional changes.
>
> Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
> audio/audio.c | 106 ++++++++++++++++++++---------------------
> audio/audio_int.h | 6 +--
> audio/audio_template.h | 19 ++++----
> 3 files changed, 67 insertions(+), 64 deletions(-)
>
> diff --git a/audio/audio.c b/audio/audio.c
> index 772c3cc320..a0b54e4a2e 100644
> --- a/audio/audio.c
> +++ b/audio/audio.c
> @@ -523,8 +523,8 @@ static size_t audio_pcm_hw_find_min_in (HWVoiceIn *hw)
> static size_t audio_pcm_hw_get_live_in(HWVoiceIn *hw)
> {
> size_t live = hw->total_samples_captured - audio_pcm_hw_find_min_in (hw);
> - if (audio_bug(__func__, live > hw->conv_buf->size)) {
> - dolog("live=%zu hw->conv_buf->size=%zu\n", live, hw->conv_buf->size);
> + if (audio_bug(__func__, live > hw->conv_buf.size)) {
> + dolog("live=%zu hw->conv_buf.size=%zu\n", live, hw->conv_buf.size);
> return 0;
> }
> return live;
> @@ -533,13 +533,13 @@ static size_t audio_pcm_hw_get_live_in(HWVoiceIn *hw)
> static size_t audio_pcm_hw_conv_in(HWVoiceIn *hw, void *pcm_buf, size_t samples)
> {
> size_t conv = 0;
> - STSampleBuffer *conv_buf = hw->conv_buf;
> + STSampleBuffer *conv_buf = &hw->conv_buf;
>
> while (samples) {
> uint8_t *src = advance(pcm_buf, conv * hw->info.bytes_per_frame);
> size_t proc = MIN(samples, conv_buf->size - conv_buf->pos);
>
> - hw->conv(conv_buf->samples + conv_buf->pos, src, proc);
> + hw->conv(conv_buf->buffer + conv_buf->pos, src, proc);
> conv_buf->pos = (conv_buf->pos + proc) % conv_buf->size;
> samples -= proc;
> conv += proc;
> @@ -561,12 +561,12 @@ static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t size)
> if (!live) {
> return 0;
> }
> - if (audio_bug(__func__, live > hw->conv_buf->size)) {
> - dolog("live_in=%zu hw->conv_buf->size=%zu\n", live, hw->conv_buf->size);
> + if (audio_bug(__func__, live > hw->conv_buf.size)) {
> + dolog("live_in=%zu hw->conv_buf.size=%zu\n", live, hw->conv_buf.size);
> return 0;
> }
>
> - rpos = audio_ring_posb(hw->conv_buf->pos, live, hw->conv_buf->size);
> + rpos = audio_ring_posb(hw->conv_buf.pos, live, hw->conv_buf.size);
>
> samples = size / sw->info.bytes_per_frame;
>
> @@ -574,11 +574,11 @@ static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t size)
> swlim = MIN (swlim, samples);
>
> while (swlim) {
> - src = hw->conv_buf->samples + rpos;
> - if (hw->conv_buf->pos > rpos) {
> - isamp = hw->conv_buf->pos - rpos;
> + src = hw->conv_buf.buffer + rpos;
> + if (hw->conv_buf.pos > rpos) {
> + isamp = hw->conv_buf.pos - rpos;
> } else {
> - isamp = hw->conv_buf->size - rpos;
> + isamp = hw->conv_buf.size - rpos;
> }
>
> if (!isamp) {
> @@ -588,7 +588,7 @@ static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t size)
>
> st_rate_flow (sw->rate, src, dst, &isamp, &osamp);
> swlim -= osamp;
> - rpos = (rpos + isamp) % hw->conv_buf->size;
> + rpos = (rpos + isamp) % hw->conv_buf.size;
> dst += osamp;
> ret += osamp;
> total += isamp;
> @@ -636,8 +636,8 @@ static size_t audio_pcm_hw_get_live_out (HWVoiceOut *hw, int *nb_live)
> if (nb_live1) {
> size_t live = smin;
>
> - if (audio_bug(__func__, live > hw->mix_buf->size)) {
> - dolog("live=%zu hw->mix_buf->size=%zu\n", live, hw->mix_buf->size);
> + if (audio_bug(__func__, live > hw->mix_buf.size)) {
> + dolog("live=%zu hw->mix_buf.size=%zu\n", live, hw->mix_buf.size);
> return 0;
> }
> return live;
> @@ -654,17 +654,17 @@ static size_t audio_pcm_hw_get_free(HWVoiceOut *hw)
> static void audio_pcm_hw_clip_out(HWVoiceOut *hw, void *pcm_buf, size_t len)
> {
> size_t clipped = 0;
> - size_t pos = hw->mix_buf->pos;
> + size_t pos = hw->mix_buf.pos;
>
> while (len) {
> - st_sample *src = hw->mix_buf->samples + pos;
> + st_sample *src = hw->mix_buf.buffer + pos;
> uint8_t *dst = advance(pcm_buf, clipped * hw->info.bytes_per_frame);
> - size_t samples_till_end_of_buf = hw->mix_buf->size - pos;
> + size_t samples_till_end_of_buf = hw->mix_buf.size - pos;
> size_t samples_to_clip = MIN(len, samples_till_end_of_buf);
>
> hw->clip(dst, src, samples_to_clip);
>
> - pos = (pos + samples_to_clip) % hw->mix_buf->size;
> + pos = (pos + samples_to_clip) % hw->mix_buf.size;
> len -= samples_to_clip;
> clipped += samples_to_clip;
> }
> @@ -683,11 +683,11 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
> return size;
> }
>
> - hwsamples = sw->hw->mix_buf->size;
> + hwsamples = sw->hw->mix_buf.size;
>
> live = sw->total_hw_samples_mixed;
> if (audio_bug(__func__, live > hwsamples)) {
> - dolog("live=%zu hw->mix_buf->size=%zu\n", live, hwsamples);
> + dolog("live=%zu hw->mix_buf.size=%zu\n", live, hwsamples);
> return 0;
> }
>
> @@ -698,7 +698,7 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
> return 0;
> }
>
> - wpos = (sw->hw->mix_buf->pos + live) % hwsamples;
> + wpos = (sw->hw->mix_buf.pos + live) % hwsamples;
>
> dead = hwsamples - live;
> hw_free = audio_pcm_hw_get_free(sw->hw);
> @@ -725,7 +725,7 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
> st_rate_flow_mix (
> sw->rate,
> sw->buf + pos,
> - sw->hw->mix_buf->samples + wpos,
> + sw->hw->mix_buf.buffer + wpos,
> &isamp,
> &osamp
> );
> @@ -989,9 +989,9 @@ static size_t audio_get_avail (SWVoiceIn *sw)
> }
>
> live = sw->hw->total_samples_captured - sw->total_hw_samples_acquired;
> - if (audio_bug(__func__, live > sw->hw->conv_buf->size)) {
> - dolog("live=%zu sw->hw->conv_buf->size=%zu\n", live,
> - sw->hw->conv_buf->size);
> + if (audio_bug(__func__, live > sw->hw->conv_buf.size)) {
> + dolog("live=%zu sw->hw->conv_buf.size=%zu\n", live,
> + sw->hw->conv_buf.size);
> return 0;
> }
>
> @@ -1026,13 +1026,13 @@ static size_t audio_get_free(SWVoiceOut *sw)
>
> live = sw->total_hw_samples_mixed;
>
> - if (audio_bug(__func__, live > sw->hw->mix_buf->size)) {
> - dolog("live=%zu sw->hw->mix_buf->size=%zu\n", live,
> - sw->hw->mix_buf->size);
> + if (audio_bug(__func__, live > sw->hw->mix_buf.size)) {
> + dolog("live=%zu sw->hw->mix_buf.size=%zu\n", live,
> + sw->hw->mix_buf.size);
> return 0;
> }
>
> - dead = sw->hw->mix_buf->size - live;
> + dead = sw->hw->mix_buf.size - live;
>
> #ifdef DEBUG_OUT
> dolog("%s: get_free live %zu dead %zu frontend frames %zu\n",
> @@ -1056,12 +1056,12 @@ static void audio_capture_mix_and_clear(HWVoiceOut *hw, size_t rpos,
>
> n = samples;
> while (n) {
> - size_t till_end_of_hw = hw->mix_buf->size - rpos2;
> + size_t till_end_of_hw = hw->mix_buf.size - rpos2;
> size_t to_write = MIN(till_end_of_hw, n);
> size_t bytes = to_write * hw->info.bytes_per_frame;
> size_t written;
>
> - sw->buf = hw->mix_buf->samples + rpos2;
> + sw->buf = hw->mix_buf.buffer + rpos2;
> written = audio_pcm_sw_write (sw, NULL, bytes);
> if (written - bytes) {
> dolog("Could not mix %zu bytes into a capture "
> @@ -1070,14 +1070,14 @@ static void audio_capture_mix_and_clear(HWVoiceOut *hw, size_t rpos,
> break;
> }
> n -= to_write;
> - rpos2 = (rpos2 + to_write) % hw->mix_buf->size;
> + rpos2 = (rpos2 + to_write) % hw->mix_buf.size;
> }
> }
> }
>
> - n = MIN(samples, hw->mix_buf->size - rpos);
> - mixeng_clear(hw->mix_buf->samples + rpos, n);
> - mixeng_clear(hw->mix_buf->samples, samples - n);
> + n = MIN(samples, hw->mix_buf.size - rpos);
> + mixeng_clear(hw->mix_buf.buffer + rpos, n);
> + mixeng_clear(hw->mix_buf.buffer, samples - n);
> }
>
> static size_t audio_pcm_hw_run_out(HWVoiceOut *hw, size_t live)
> @@ -1103,7 +1103,7 @@ static size_t audio_pcm_hw_run_out(HWVoiceOut *hw, size_t live)
>
> live -= proc;
> clipped += proc;
> - hw->mix_buf->pos = (hw->mix_buf->pos + proc) % hw->mix_buf->size;
> + hw->mix_buf.pos = (hw->mix_buf.pos + proc) % hw->mix_buf.size;
>
> if (proc == 0 || proc < decr) {
> break;
> @@ -1174,8 +1174,8 @@ static void audio_run_out (AudioState *s)
> live = 0;
> }
>
> - if (audio_bug(__func__, live > hw->mix_buf->size)) {
> - dolog("live=%zu hw->mix_buf->size=%zu\n", live, hw->mix_buf->size);
> + if (audio_bug(__func__, live > hw->mix_buf.size)) {
> + dolog("live=%zu hw->mix_buf.size=%zu\n", live, hw->mix_buf.size);
> continue;
> }
>
> @@ -1203,13 +1203,13 @@ static void audio_run_out (AudioState *s)
> continue;
> }
>
> - prev_rpos = hw->mix_buf->pos;
> + prev_rpos = hw->mix_buf.pos;
> played = audio_pcm_hw_run_out(hw, live);
> replay_audio_out(&played);
> - if (audio_bug(__func__, hw->mix_buf->pos >= hw->mix_buf->size)) {
> - dolog("hw->mix_buf->pos=%zu hw->mix_buf->size=%zu played=%zu\n",
> - hw->mix_buf->pos, hw->mix_buf->size, played);
> - hw->mix_buf->pos = 0;
> + if (audio_bug(__func__, hw->mix_buf.pos >= hw->mix_buf.size)) {
> + dolog("hw->mix_buf.pos=%zu hw->mix_buf.size=%zu played=%zu\n",
> + hw->mix_buf.pos, hw->mix_buf.size, played);
> + hw->mix_buf.pos = 0;
> }
>
> #ifdef DEBUG_OUT
> @@ -1290,10 +1290,10 @@ static void audio_run_in (AudioState *s)
>
> if (replay_mode != REPLAY_MODE_PLAY) {
> captured = audio_pcm_hw_run_in(
> - hw, hw->conv_buf->size - audio_pcm_hw_get_live_in(hw));
> + hw, hw->conv_buf.size - audio_pcm_hw_get_live_in(hw));
> }
> - replay_audio_in(&captured, hw->conv_buf->samples, &hw->conv_buf->pos,
> - hw->conv_buf->size);
> + replay_audio_in(&captured, hw->conv_buf.buffer, &hw->conv_buf.pos,
> + hw->conv_buf.size);
>
> min = audio_pcm_hw_find_min_in (hw);
> hw->total_samples_captured += captured - min;
> @@ -1326,14 +1326,14 @@ static void audio_run_capture (AudioState *s)
> SWVoiceOut *sw;
>
> captured = live = audio_pcm_hw_get_live_out (hw, NULL);
> - rpos = hw->mix_buf->pos;
> + rpos = hw->mix_buf.pos;
> while (live) {
> - size_t left = hw->mix_buf->size - rpos;
> + size_t left = hw->mix_buf.size - rpos;
> size_t to_capture = MIN(live, left);
> struct st_sample *src;
> struct capture_callback *cb;
>
> - src = hw->mix_buf->samples + rpos;
> + src = hw->mix_buf.buffer + rpos;
> hw->clip (cap->buf, src, to_capture);
> mixeng_clear (src, to_capture);
>
> @@ -1341,10 +1341,10 @@ static void audio_run_capture (AudioState *s)
> cb->ops.capture (cb->opaque, cap->buf,
> to_capture * hw->info.bytes_per_frame);
> }
> - rpos = (rpos + to_capture) % hw->mix_buf->size;
> + rpos = (rpos + to_capture) % hw->mix_buf.size;
> live -= to_capture;
> }
> - hw->mix_buf->pos = rpos;
> + hw->mix_buf.pos = rpos;
>
> for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
> if (!sw->active && sw->empty) {
> @@ -1903,7 +1903,7 @@ CaptureVoiceOut *AUD_add_capture(
>
> audio_pcm_init_info (&hw->info, as);
>
> - cap->buf = g_malloc0_n(hw->mix_buf->size, hw->info.bytes_per_frame);
> + cap->buf = g_malloc0_n(hw->mix_buf.size, hw->info.bytes_per_frame);
>
> if (hw->info.is_float) {
> hw->clip = mixeng_clip_float[hw->info.nchannels == 2];
> @@ -1955,7 +1955,7 @@ void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque)
> sw = sw1;
> }
> QLIST_REMOVE (cap, entries);
> - g_free (cap->hw.mix_buf);
> + g_free(cap->hw.mix_buf.buffer);
> g_free (cap->buf);
> g_free (cap);
> }
> diff --git a/audio/audio_int.h b/audio/audio_int.h
> index 5028f2354a..061845dcc2 100644
> --- a/audio/audio_int.h
> +++ b/audio/audio_int.h
> @@ -58,7 +58,7 @@ typedef struct SWVoiceCap SWVoiceCap;
>
> typedef struct STSampleBuffer {
> size_t pos, size;
> - st_sample samples[];
> + st_sample *buffer;
> } STSampleBuffer;
>
> typedef struct HWVoiceOut {
> @@ -71,7 +71,7 @@ typedef struct HWVoiceOut {
> f_sample *clip;
> uint64_t ts_helper;
>
> - STSampleBuffer *mix_buf;
> + STSampleBuffer mix_buf;
> void *buf_emul;
> size_t pos_emul, pending_emul, size_emul;
>
> @@ -93,7 +93,7 @@ typedef struct HWVoiceIn {
> size_t total_samples_captured;
> uint64_t ts_helper;
>
> - STSampleBuffer *conv_buf;
> + STSampleBuffer conv_buf;
> void *buf_emul;
> size_t pos_emul, pending_emul, size_emul;
>
> diff --git a/audio/audio_template.h b/audio/audio_template.h
> index 980e1f4bd0..dd87170cbd 100644
> --- a/audio/audio_template.h
> +++ b/audio/audio_template.h
> @@ -71,8 +71,9 @@ static void glue(audio_init_nb_voices_, TYPE)(AudioState *s,
> static void glue (audio_pcm_hw_free_resources_, TYPE) (HW *hw)
> {
> g_free(hw->buf_emul);
> - g_free (HWBUF);
> - HWBUF = NULL;
> + g_free(HWBUF.buffer);
> + HWBUF.buffer = NULL;
> + HWBUF.size = 0;
> }
>
> static void glue(audio_pcm_hw_alloc_resources_, TYPE)(HW *hw)
> @@ -83,10 +84,12 @@ static void glue(audio_pcm_hw_alloc_resources_, TYPE)(HW *hw)
> dolog("Attempted to allocate empty buffer\n");
> }
>
> - HWBUF = g_malloc0(sizeof(STSampleBuffer) + sizeof(st_sample) * samples);
> - HWBUF->size = samples;
> + HWBUF.buffer = g_new0(st_sample, samples);
> + HWBUF.size = samples;
> + HWBUF.pos = 0;
> } else {
> - HWBUF = NULL;
> + HWBUF.buffer = NULL;
> + HWBUF.size = 0;
> }
> }
>
> @@ -111,9 +114,9 @@ static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
> }
>
> #ifdef DAC
> - samples = ((int64_t) sw->HWBUF->size << 32) / sw->ratio;
> + samples = ((int64_t)sw->HWBUF.size << 32) / sw->ratio;
> #else
> - samples = (int64_t)sw->HWBUF->size * sw->ratio >> 32;
> + samples = (int64_t)sw->HWBUF.size * sw->ratio >> 32;
> #endif
> if (audio_bug(__func__, samples < 0)) {
> dolog("Can not allocate buffer for `%s' (%d samples)\n",
> @@ -126,7 +129,7 @@ static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
> size_t f_fe_min;
>
> /* f_fe_min = ceil(1 [frames] * f_be [Hz] / size_be [frames]) */
> - f_fe_min = (hw->info.freq + HWBUF->size - 1) / HWBUF->size;
> + f_fe_min = (hw->info.freq + HWBUF.size - 1) / HWBUF.size;
> qemu_log_mask(LOG_UNIMP,
> AUDIO_CAP ": The guest selected a " NAME " sample rate"
> " of %d Hz for %s. Only sample rates >= %zu Hz are"
> --
> 2.35.3
>
--
Marc-André Lureau
^ permalink raw reply [flat|nested] 34+ messages in thread
* [PATCH v2 02/17] audio: change type and name of the resample buffer
2023-02-06 18:47 [PATCH v2 00/17] audio: improve callback interface for audio frontends Volker Rümelin
2023-02-06 18:52 ` [PATCH v2 01/17] audio: change type of mix_buf and conv_buf Volker Rümelin
@ 2023-02-06 18:52 ` Volker Rümelin
2023-02-22 10:49 ` Marc-André Lureau
2023-02-06 18:52 ` [PATCH v2 03/17] audio: make the resampling code greedy Volker Rümelin
` (14 subsequent siblings)
16 siblings, 1 reply; 34+ messages in thread
From: Volker Rümelin @ 2023-02-06 18:52 UTC (permalink / raw)
To: Gerd Hoffmann, Marc-André Lureau
Cc: qemu-devel, Christian Schoenebeck, Mark Cave-Ayland
Change the type of the resample buffer from struct st_sample *
to STSampleBuffer. Also change the name from buf to resample_buf
for better readability.
The new variables resample_buf.size and resample_buf.pos will be
used after the next patches. There is no functional change.
Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
---
audio/audio.c | 15 ++++++++-------
audio/audio_int.h | 4 ++--
audio/audio_template.h | 10 ++++++----
3 files changed, 16 insertions(+), 13 deletions(-)
diff --git a/audio/audio.c b/audio/audio.c
index a0b54e4a2e..a399147486 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -555,7 +555,7 @@ static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t size)
{
HWVoiceIn *hw = sw->hw;
size_t samples, live, ret = 0, swlim, isamp, osamp, rpos, total = 0;
- struct st_sample *src, *dst = sw->buf;
+ struct st_sample *src, *dst = sw->resample_buf.buffer;
live = hw->total_samples_captured - sw->total_hw_samples_acquired;
if (!live) {
@@ -595,10 +595,10 @@ static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t size)
}
if (!hw->pcm_ops->volume_in) {
- mixeng_volume (sw->buf, ret, &sw->vol);
+ mixeng_volume(sw->resample_buf.buffer, ret, &sw->vol);
}
- sw->clip (buf, sw->buf, ret);
+ sw->clip(buf, sw->resample_buf.buffer, ret);
sw->total_hw_samples_acquired += total;
return ret * sw->info.bytes_per_frame;
}
@@ -706,10 +706,10 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
samples = ((int64_t)MIN(dead, hw_free) << 32) / sw->ratio;
samples = MIN(samples, size / sw->info.bytes_per_frame);
if (samples) {
- sw->conv(sw->buf, buf, samples);
+ sw->conv(sw->resample_buf.buffer, buf, samples);
if (!sw->hw->pcm_ops->volume_out) {
- mixeng_volume(sw->buf, samples, &sw->vol);
+ mixeng_volume(sw->resample_buf.buffer, samples, &sw->vol);
}
}
@@ -724,7 +724,7 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
osamp = blck;
st_rate_flow_mix (
sw->rate,
- sw->buf + pos,
+ sw->resample_buf.buffer + pos,
sw->hw->mix_buf.buffer + wpos,
&isamp,
&osamp
@@ -1061,7 +1061,8 @@ static void audio_capture_mix_and_clear(HWVoiceOut *hw, size_t rpos,
size_t bytes = to_write * hw->info.bytes_per_frame;
size_t written;
- sw->buf = hw->mix_buf.buffer + rpos2;
+ sw->resample_buf.buffer = hw->mix_buf.buffer + rpos2;
+ sw->resample_buf.size = to_write;
written = audio_pcm_sw_write (sw, NULL, bytes);
if (written - bytes) {
dolog("Could not mix %zu bytes into a capture "
diff --git a/audio/audio_int.h b/audio/audio_int.h
index 061845dcc2..8b163e1759 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -109,7 +109,7 @@ struct SWVoiceOut {
struct audio_pcm_info info;
t_sample *conv;
int64_t ratio;
- struct st_sample *buf;
+ STSampleBuffer resample_buf;
void *rate;
size_t total_hw_samples_mixed;
int active;
@@ -129,7 +129,7 @@ struct SWVoiceIn {
int64_t ratio;
void *rate;
size_t total_hw_samples_acquired;
- struct st_sample *buf;
+ STSampleBuffer resample_buf;
f_sample *clip;
HWVoiceIn *hw;
char *name;
diff --git a/audio/audio_template.h b/audio/audio_template.h
index dd87170cbd..a0b653f52c 100644
--- a/audio/audio_template.h
+++ b/audio/audio_template.h
@@ -95,13 +95,13 @@ static void glue(audio_pcm_hw_alloc_resources_, TYPE)(HW *hw)
static void glue (audio_pcm_sw_free_resources_, TYPE) (SW *sw)
{
- g_free (sw->buf);
+ g_free(sw->resample_buf.buffer);
+ sw->resample_buf.buffer = NULL;
+ sw->resample_buf.size = 0;
if (sw->rate) {
st_rate_stop (sw->rate);
}
-
- sw->buf = NULL;
sw->rate = NULL;
}
@@ -138,7 +138,9 @@ static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
return -1;
}
- sw->buf = g_new0(st_sample, samples);
+ sw->resample_buf.buffer = g_new0(st_sample, samples);
+ sw->resample_buf.size = samples;
+ sw->resample_buf.pos = 0;
#ifdef DAC
sw->rate = st_rate_start (sw->info.freq, sw->hw->info.freq);
--
2.35.3
^ permalink raw reply related [flat|nested] 34+ messages in thread
* Re: [PATCH v2 02/17] audio: change type and name of the resample buffer
2023-02-06 18:52 ` [PATCH v2 02/17] audio: change type and name of the resample buffer Volker Rümelin
@ 2023-02-22 10:49 ` Marc-André Lureau
0 siblings, 0 replies; 34+ messages in thread
From: Marc-André Lureau @ 2023-02-22 10:49 UTC (permalink / raw)
To: Volker Rümelin
Cc: Gerd Hoffmann, qemu-devel, Christian Schoenebeck,
Mark Cave-Ayland
On Mon, Feb 6, 2023 at 10:52 PM Volker Rümelin <vr_qemu@t-online.de> wrote:
>
> Change the type of the resample buffer from struct st_sample *
> to STSampleBuffer. Also change the name from buf to resample_buf
> for better readability.
>
> The new variables resample_buf.size and resample_buf.pos will be
> used after the next patches. There is no functional change.
>
> Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
> audio/audio.c | 15 ++++++++-------
> audio/audio_int.h | 4 ++--
> audio/audio_template.h | 10 ++++++----
> 3 files changed, 16 insertions(+), 13 deletions(-)
>
> diff --git a/audio/audio.c b/audio/audio.c
> index a0b54e4a2e..a399147486 100644
> --- a/audio/audio.c
> +++ b/audio/audio.c
> @@ -555,7 +555,7 @@ static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t size)
> {
> HWVoiceIn *hw = sw->hw;
> size_t samples, live, ret = 0, swlim, isamp, osamp, rpos, total = 0;
> - struct st_sample *src, *dst = sw->buf;
> + struct st_sample *src, *dst = sw->resample_buf.buffer;
>
> live = hw->total_samples_captured - sw->total_hw_samples_acquired;
> if (!live) {
> @@ -595,10 +595,10 @@ static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t size)
> }
>
> if (!hw->pcm_ops->volume_in) {
> - mixeng_volume (sw->buf, ret, &sw->vol);
> + mixeng_volume(sw->resample_buf.buffer, ret, &sw->vol);
> }
>
> - sw->clip (buf, sw->buf, ret);
> + sw->clip(buf, sw->resample_buf.buffer, ret);
> sw->total_hw_samples_acquired += total;
> return ret * sw->info.bytes_per_frame;
> }
> @@ -706,10 +706,10 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
> samples = ((int64_t)MIN(dead, hw_free) << 32) / sw->ratio;
> samples = MIN(samples, size / sw->info.bytes_per_frame);
> if (samples) {
> - sw->conv(sw->buf, buf, samples);
> + sw->conv(sw->resample_buf.buffer, buf, samples);
>
> if (!sw->hw->pcm_ops->volume_out) {
> - mixeng_volume(sw->buf, samples, &sw->vol);
> + mixeng_volume(sw->resample_buf.buffer, samples, &sw->vol);
> }
> }
>
> @@ -724,7 +724,7 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
> osamp = blck;
> st_rate_flow_mix (
> sw->rate,
> - sw->buf + pos,
> + sw->resample_buf.buffer + pos,
> sw->hw->mix_buf.buffer + wpos,
> &isamp,
> &osamp
> @@ -1061,7 +1061,8 @@ static void audio_capture_mix_and_clear(HWVoiceOut *hw, size_t rpos,
> size_t bytes = to_write * hw->info.bytes_per_frame;
> size_t written;
>
> - sw->buf = hw->mix_buf.buffer + rpos2;
> + sw->resample_buf.buffer = hw->mix_buf.buffer + rpos2;
> + sw->resample_buf.size = to_write;
> written = audio_pcm_sw_write (sw, NULL, bytes);
> if (written - bytes) {
> dolog("Could not mix %zu bytes into a capture "
> diff --git a/audio/audio_int.h b/audio/audio_int.h
> index 061845dcc2..8b163e1759 100644
> --- a/audio/audio_int.h
> +++ b/audio/audio_int.h
> @@ -109,7 +109,7 @@ struct SWVoiceOut {
> struct audio_pcm_info info;
> t_sample *conv;
> int64_t ratio;
> - struct st_sample *buf;
> + STSampleBuffer resample_buf;
> void *rate;
> size_t total_hw_samples_mixed;
> int active;
> @@ -129,7 +129,7 @@ struct SWVoiceIn {
> int64_t ratio;
> void *rate;
> size_t total_hw_samples_acquired;
> - struct st_sample *buf;
> + STSampleBuffer resample_buf;
> f_sample *clip;
> HWVoiceIn *hw;
> char *name;
> diff --git a/audio/audio_template.h b/audio/audio_template.h
> index dd87170cbd..a0b653f52c 100644
> --- a/audio/audio_template.h
> +++ b/audio/audio_template.h
> @@ -95,13 +95,13 @@ static void glue(audio_pcm_hw_alloc_resources_, TYPE)(HW *hw)
>
> static void glue (audio_pcm_sw_free_resources_, TYPE) (SW *sw)
> {
> - g_free (sw->buf);
> + g_free(sw->resample_buf.buffer);
> + sw->resample_buf.buffer = NULL;
> + sw->resample_buf.size = 0;
>
> if (sw->rate) {
> st_rate_stop (sw->rate);
> }
> -
> - sw->buf = NULL;
> sw->rate = NULL;
> }
>
> @@ -138,7 +138,9 @@ static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
> return -1;
> }
>
> - sw->buf = g_new0(st_sample, samples);
> + sw->resample_buf.buffer = g_new0(st_sample, samples);
> + sw->resample_buf.size = samples;
> + sw->resample_buf.pos = 0;
>
> #ifdef DAC
> sw->rate = st_rate_start (sw->info.freq, sw->hw->info.freq);
> --
> 2.35.3
>
--
Marc-André Lureau
^ permalink raw reply [flat|nested] 34+ messages in thread
* [PATCH v2 03/17] audio: make the resampling code greedy
2023-02-06 18:47 [PATCH v2 00/17] audio: improve callback interface for audio frontends Volker Rümelin
2023-02-06 18:52 ` [PATCH v2 01/17] audio: change type of mix_buf and conv_buf Volker Rümelin
2023-02-06 18:52 ` [PATCH v2 02/17] audio: change type and name of the resample buffer Volker Rümelin
@ 2023-02-06 18:52 ` Volker Rümelin
2023-02-22 10:49 ` Marc-André Lureau
2023-02-06 18:52 ` [PATCH v2 04/17] audio: replace the resampling loop in audio_pcm_sw_write() Volker Rümelin
` (13 subsequent siblings)
16 siblings, 1 reply; 34+ messages in thread
From: Volker Rümelin @ 2023-02-06 18:52 UTC (permalink / raw)
To: Gerd Hoffmann, Marc-André Lureau
Cc: qemu-devel, Christian Schoenebeck, Mark Cave-Ayland
Read the maximum possible number of audio frames instead of the
minimum necessary number of frames when the audio stream is
downsampled and the output buffer is limited. This makes the
function symmetrical to upsampling when the input buffer is
limited. The maximum possible number of frames is written here.
With this change it's easier to calculate the exact number of
audio frames the resample function will read or write. These two
functions will be introduced later.
Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
---
audio/rate_template.h | 21 +++++++++++++--------
1 file changed, 13 insertions(+), 8 deletions(-)
diff --git a/audio/rate_template.h b/audio/rate_template.h
index b432719ebb..6648f0d2e5 100644
--- a/audio/rate_template.h
+++ b/audio/rate_template.h
@@ -40,8 +40,6 @@ void NAME (void *opaque, struct st_sample *ibuf, struct st_sample *obuf,
int64_t t;
#endif
- ilast = rate->ilast;
-
istart = ibuf;
iend = ibuf + *isamp;
@@ -59,15 +57,17 @@ void NAME (void *opaque, struct st_sample *ibuf, struct st_sample *obuf,
return;
}
- while (obuf < oend) {
+ /* without input samples, there's nothing to do */
+ if (ibuf >= iend) {
+ *osamp = 0;
+ return;
+ }
- /* Safety catch to make sure we have input samples. */
- if (ibuf >= iend) {
- break;
- }
+ ilast = rate->ilast;
- /* read as many input samples so that ipos > opos */
+ while (true) {
+ /* read as many input samples so that ipos > opos */
while (rate->ipos <= (rate->opos >> 32)) {
ilast = *ibuf++;
rate->ipos++;
@@ -78,6 +78,11 @@ void NAME (void *opaque, struct st_sample *ibuf, struct st_sample *obuf,
}
}
+ /* make sure that the next output sample can be written */
+ if (obuf >= oend) {
+ break;
+ }
+
icur = *ibuf;
/* wrap ipos and opos around long before they overflow */
--
2.35.3
^ permalink raw reply related [flat|nested] 34+ messages in thread
* Re: [PATCH v2 03/17] audio: make the resampling code greedy
2023-02-06 18:52 ` [PATCH v2 03/17] audio: make the resampling code greedy Volker Rümelin
@ 2023-02-22 10:49 ` Marc-André Lureau
0 siblings, 0 replies; 34+ messages in thread
From: Marc-André Lureau @ 2023-02-22 10:49 UTC (permalink / raw)
To: Volker Rümelin
Cc: Gerd Hoffmann, qemu-devel, Christian Schoenebeck,
Mark Cave-Ayland
Hi
On Mon, Feb 6, 2023 at 10:52 PM Volker Rümelin <vr_qemu@t-online.de> wrote:
>
> Read the maximum possible number of audio frames instead of the
> minimum necessary number of frames when the audio stream is
> downsampled and the output buffer is limited. This makes the
> function symmetrical to upsampling when the input buffer is
> limited. The maximum possible number of frames is written here.
>
> With this change it's easier to calculate the exact number of
> audio frames the resample function will read or write. These two
> functions will be introduced later.
>
> Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
a bit hard to review, but looks ok
Acked-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
> audio/rate_template.h | 21 +++++++++++++--------
> 1 file changed, 13 insertions(+), 8 deletions(-)
>
> diff --git a/audio/rate_template.h b/audio/rate_template.h
> index b432719ebb..6648f0d2e5 100644
> --- a/audio/rate_template.h
> +++ b/audio/rate_template.h
> @@ -40,8 +40,6 @@ void NAME (void *opaque, struct st_sample *ibuf, struct st_sample *obuf,
> int64_t t;
> #endif
>
> - ilast = rate->ilast;
> -
> istart = ibuf;
> iend = ibuf + *isamp;
>
> @@ -59,15 +57,17 @@ void NAME (void *opaque, struct st_sample *ibuf, struct st_sample *obuf,
> return;
> }
>
> - while (obuf < oend) {
> + /* without input samples, there's nothing to do */
> + if (ibuf >= iend) {
> + *osamp = 0;
> + return;
> + }
>
> - /* Safety catch to make sure we have input samples. */
> - if (ibuf >= iend) {
> - break;
> - }
> + ilast = rate->ilast;
>
> - /* read as many input samples so that ipos > opos */
> + while (true) {
>
> + /* read as many input samples so that ipos > opos */
> while (rate->ipos <= (rate->opos >> 32)) {
> ilast = *ibuf++;
> rate->ipos++;
> @@ -78,6 +78,11 @@ void NAME (void *opaque, struct st_sample *ibuf, struct st_sample *obuf,
> }
> }
>
> + /* make sure that the next output sample can be written */
> + if (obuf >= oend) {
> + break;
> + }
> +
> icur = *ibuf;
>
> /* wrap ipos and opos around long before they overflow */
> --
> 2.35.3
>
--
Marc-André Lureau
^ permalink raw reply [flat|nested] 34+ messages in thread
* [PATCH v2 04/17] audio: replace the resampling loop in audio_pcm_sw_write()
2023-02-06 18:47 [PATCH v2 00/17] audio: improve callback interface for audio frontends Volker Rümelin
` (2 preceding siblings ...)
2023-02-06 18:52 ` [PATCH v2 03/17] audio: make the resampling code greedy Volker Rümelin
@ 2023-02-06 18:52 ` Volker Rümelin
2023-02-22 10:49 ` Marc-André Lureau
2023-02-06 18:52 ` [PATCH v2 05/17] audio: remove sw == NULL check Volker Rümelin
` (12 subsequent siblings)
16 siblings, 1 reply; 34+ messages in thread
From: Volker Rümelin @ 2023-02-06 18:52 UTC (permalink / raw)
To: Gerd Hoffmann, Marc-André Lureau
Cc: qemu-devel, Christian Schoenebeck, Mark Cave-Ayland
Replace the resampling loop in audio_pcm_sw_write() with the new
function audio_pcm_sw_resample_out(). Unlike the old resample
loop the new function will try to consume input frames even if
the output buffer is full. This is necessary when downsampling
to avoid reading less audio frames than calculated in advance.
The loop was unrolled to avoid complicated loop control conditions
in this case.
Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
---
audio/audio.c | 63 +++++++++++++++++++++++++++++----------------------
1 file changed, 36 insertions(+), 27 deletions(-)
diff --git a/audio/audio.c b/audio/audio.c
index a399147486..4412b5fad8 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -673,11 +673,44 @@ static void audio_pcm_hw_clip_out(HWVoiceOut *hw, void *pcm_buf, size_t len)
/*
* Soft voice (playback)
*/
+static void audio_pcm_sw_resample_out(SWVoiceOut *sw,
+ size_t frames_in_max, size_t frames_out_max,
+ size_t *total_in, size_t *total_out)
+{
+ HWVoiceOut *hw = sw->hw;
+ struct st_sample *src, *dst;
+ size_t live, wpos, frames_in, frames_out;
+
+ live = sw->total_hw_samples_mixed;
+ wpos = (hw->mix_buf.pos + live) % hw->mix_buf.size;
+
+ /* write to mix_buf from wpos to end of buffer */
+ src = sw->resample_buf.buffer;
+ frames_in = frames_in_max;
+ dst = hw->mix_buf.buffer + wpos;
+ frames_out = MIN(frames_out_max, hw->mix_buf.size - wpos);
+ st_rate_flow_mix(sw->rate, src, dst, &frames_in, &frames_out);
+ wpos += frames_out;
+ *total_in = frames_in;
+ *total_out = frames_out;
+
+ /* write to mix_buf from start of buffer if there are input frames left */
+ if (frames_in_max - frames_in > 0 && wpos == hw->mix_buf.size) {
+ src += frames_in;
+ frames_in = frames_in_max - frames_in;
+ dst = hw->mix_buf.buffer;
+ frames_out = frames_out_max - frames_out;
+ st_rate_flow_mix(sw->rate, src, dst, &frames_in, &frames_out);
+ *total_in += frames_in;
+ *total_out += frames_out;
+ }
+}
+
static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
{
- size_t hwsamples, samples, isamp, osamp, wpos, live, dead, left, blck;
+ size_t hwsamples, samples, live, dead;
size_t hw_free;
- size_t ret = 0, pos = 0, total = 0;
+ size_t ret, total;
if (!sw) {
return size;
@@ -698,8 +731,6 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
return 0;
}
- wpos = (sw->hw->mix_buf.pos + live) % hwsamples;
-
dead = hwsamples - live;
hw_free = audio_pcm_hw_get_free(sw->hw);
hw_free = hw_free > live ? hw_free - live : 0;
@@ -713,29 +744,7 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
}
}
- while (samples) {
- dead = hwsamples - live;
- left = hwsamples - wpos;
- blck = MIN (dead, left);
- if (!blck) {
- break;
- }
- isamp = samples;
- osamp = blck;
- st_rate_flow_mix (
- sw->rate,
- sw->resample_buf.buffer + pos,
- sw->hw->mix_buf.buffer + wpos,
- &isamp,
- &osamp
- );
- ret += isamp;
- samples -= isamp;
- pos += isamp;
- live += osamp;
- wpos = (wpos + osamp) % hwsamples;
- total += osamp;
- }
+ audio_pcm_sw_resample_out(sw, samples, MIN(dead, hw_free), &ret, &total);
sw->total_hw_samples_mixed += total;
sw->empty = sw->total_hw_samples_mixed == 0;
--
2.35.3
^ permalink raw reply related [flat|nested] 34+ messages in thread
* Re: [PATCH v2 04/17] audio: replace the resampling loop in audio_pcm_sw_write()
2023-02-06 18:52 ` [PATCH v2 04/17] audio: replace the resampling loop in audio_pcm_sw_write() Volker Rümelin
@ 2023-02-22 10:49 ` Marc-André Lureau
0 siblings, 0 replies; 34+ messages in thread
From: Marc-André Lureau @ 2023-02-22 10:49 UTC (permalink / raw)
To: Volker Rümelin
Cc: Gerd Hoffmann, qemu-devel, Christian Schoenebeck,
Mark Cave-Ayland
Hi
On Mon, Feb 6, 2023 at 10:53 PM Volker Rümelin <vr_qemu@t-online.de> wrote:
>
> Replace the resampling loop in audio_pcm_sw_write() with the new
> function audio_pcm_sw_resample_out(). Unlike the old resample
> loop the new function will try to consume input frames even if
> the output buffer is full. This is necessary when downsampling
> to avoid reading less audio frames than calculated in advance.
> The loop was unrolled to avoid complicated loop control conditions
> in this case.
>
> Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
lgtm
Acked-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
> audio/audio.c | 63 +++++++++++++++++++++++++++++----------------------
> 1 file changed, 36 insertions(+), 27 deletions(-)
>
> diff --git a/audio/audio.c b/audio/audio.c
> index a399147486..4412b5fad8 100644
> --- a/audio/audio.c
> +++ b/audio/audio.c
> @@ -673,11 +673,44 @@ static void audio_pcm_hw_clip_out(HWVoiceOut *hw, void *pcm_buf, size_t len)
> /*
> * Soft voice (playback)
> */
> +static void audio_pcm_sw_resample_out(SWVoiceOut *sw,
> + size_t frames_in_max, size_t frames_out_max,
> + size_t *total_in, size_t *total_out)
> +{
> + HWVoiceOut *hw = sw->hw;
> + struct st_sample *src, *dst;
> + size_t live, wpos, frames_in, frames_out;
> +
> + live = sw->total_hw_samples_mixed;
> + wpos = (hw->mix_buf.pos + live) % hw->mix_buf.size;
> +
> + /* write to mix_buf from wpos to end of buffer */
> + src = sw->resample_buf.buffer;
> + frames_in = frames_in_max;
> + dst = hw->mix_buf.buffer + wpos;
> + frames_out = MIN(frames_out_max, hw->mix_buf.size - wpos);
> + st_rate_flow_mix(sw->rate, src, dst, &frames_in, &frames_out);
> + wpos += frames_out;
> + *total_in = frames_in;
> + *total_out = frames_out;
> +
> + /* write to mix_buf from start of buffer if there are input frames left */
> + if (frames_in_max - frames_in > 0 && wpos == hw->mix_buf.size) {
> + src += frames_in;
> + frames_in = frames_in_max - frames_in;
> + dst = hw->mix_buf.buffer;
> + frames_out = frames_out_max - frames_out;
> + st_rate_flow_mix(sw->rate, src, dst, &frames_in, &frames_out);
> + *total_in += frames_in;
> + *total_out += frames_out;
> + }
> +}
> +
> static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
> {
> - size_t hwsamples, samples, isamp, osamp, wpos, live, dead, left, blck;
> + size_t hwsamples, samples, live, dead;
> size_t hw_free;
> - size_t ret = 0, pos = 0, total = 0;
> + size_t ret, total;
>
> if (!sw) {
> return size;
> @@ -698,8 +731,6 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
> return 0;
> }
>
> - wpos = (sw->hw->mix_buf.pos + live) % hwsamples;
> -
> dead = hwsamples - live;
> hw_free = audio_pcm_hw_get_free(sw->hw);
> hw_free = hw_free > live ? hw_free - live : 0;
> @@ -713,29 +744,7 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
> }
> }
>
> - while (samples) {
> - dead = hwsamples - live;
> - left = hwsamples - wpos;
> - blck = MIN (dead, left);
> - if (!blck) {
> - break;
> - }
> - isamp = samples;
> - osamp = blck;
> - st_rate_flow_mix (
> - sw->rate,
> - sw->resample_buf.buffer + pos,
> - sw->hw->mix_buf.buffer + wpos,
> - &isamp,
> - &osamp
> - );
> - ret += isamp;
> - samples -= isamp;
> - pos += isamp;
> - live += osamp;
> - wpos = (wpos + osamp) % hwsamples;
> - total += osamp;
> - }
> + audio_pcm_sw_resample_out(sw, samples, MIN(dead, hw_free), &ret, &total);
>
> sw->total_hw_samples_mixed += total;
> sw->empty = sw->total_hw_samples_mixed == 0;
> --
> 2.35.3
>
--
Marc-André Lureau
^ permalink raw reply [flat|nested] 34+ messages in thread
* [PATCH v2 05/17] audio: remove sw == NULL check
2023-02-06 18:47 [PATCH v2 00/17] audio: improve callback interface for audio frontends Volker Rümelin
` (3 preceding siblings ...)
2023-02-06 18:52 ` [PATCH v2 04/17] audio: replace the resampling loop in audio_pcm_sw_write() Volker Rümelin
@ 2023-02-06 18:52 ` Volker Rümelin
2023-02-22 10:49 ` Marc-André Lureau
2023-02-06 18:52 ` [PATCH v2 06/17] audio: rename variables in audio_pcm_sw_write() Volker Rümelin
` (11 subsequent siblings)
16 siblings, 1 reply; 34+ messages in thread
From: Volker Rümelin @ 2023-02-06 18:52 UTC (permalink / raw)
To: Gerd Hoffmann, Marc-André Lureau
Cc: qemu-devel, Christian Schoenebeck, Mark Cave-Ayland
All call sites of audio_pcm_sw_write() guarantee that sw is not
NULL. Remove the unnecessary NULL check.
Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
---
audio/audio.c | 4 ----
1 file changed, 4 deletions(-)
diff --git a/audio/audio.c b/audio/audio.c
index 4412b5fad8..8f1c0e77b0 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -712,10 +712,6 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
size_t hw_free;
size_t ret, total;
- if (!sw) {
- return size;
- }
-
hwsamples = sw->hw->mix_buf.size;
live = sw->total_hw_samples_mixed;
--
2.35.3
^ permalink raw reply related [flat|nested] 34+ messages in thread
* Re: [PATCH v2 05/17] audio: remove sw == NULL check
2023-02-06 18:52 ` [PATCH v2 05/17] audio: remove sw == NULL check Volker Rümelin
@ 2023-02-22 10:49 ` Marc-André Lureau
0 siblings, 0 replies; 34+ messages in thread
From: Marc-André Lureau @ 2023-02-22 10:49 UTC (permalink / raw)
To: Volker Rümelin
Cc: Gerd Hoffmann, qemu-devel, Christian Schoenebeck,
Mark Cave-Ayland
On Mon, Feb 6, 2023 at 10:52 PM Volker Rümelin <vr_qemu@t-online.de> wrote:
>
> All call sites of audio_pcm_sw_write() guarantee that sw is not
> NULL. Remove the unnecessary NULL check.
>
> Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
> audio/audio.c | 4 ----
> 1 file changed, 4 deletions(-)
>
> diff --git a/audio/audio.c b/audio/audio.c
> index 4412b5fad8..8f1c0e77b0 100644
> --- a/audio/audio.c
> +++ b/audio/audio.c
> @@ -712,10 +712,6 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
> size_t hw_free;
> size_t ret, total;
>
> - if (!sw) {
> - return size;
> - }
> -
> hwsamples = sw->hw->mix_buf.size;
>
> live = sw->total_hw_samples_mixed;
> --
> 2.35.3
>
--
Marc-André Lureau
^ permalink raw reply [flat|nested] 34+ messages in thread
* [PATCH v2 06/17] audio: rename variables in audio_pcm_sw_write()
2023-02-06 18:47 [PATCH v2 00/17] audio: improve callback interface for audio frontends Volker Rümelin
` (4 preceding siblings ...)
2023-02-06 18:52 ` [PATCH v2 05/17] audio: remove sw == NULL check Volker Rümelin
@ 2023-02-06 18:52 ` Volker Rümelin
2023-02-22 10:49 ` Marc-André Lureau
2023-02-06 18:52 ` [PATCH v2 07/17] audio: don't misuse audio_pcm_sw_write() Volker Rümelin
` (10 subsequent siblings)
16 siblings, 1 reply; 34+ messages in thread
From: Volker Rümelin @ 2023-02-06 18:52 UTC (permalink / raw)
To: Gerd Hoffmann, Marc-André Lureau
Cc: qemu-devel, Christian Schoenebeck, Mark Cave-Ayland
The audio_pcm_sw_write() function uses a lot of very unspecific
variable names. Rename them for better readability.
ret => total_in
total => total_out
size => buf_len
hwsamples => hw->mix_buf.size
samples => frames_in_max
Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
---
audio/audio.c | 45 ++++++++++++++++++++++-----------------------
1 file changed, 22 insertions(+), 23 deletions(-)
diff --git a/audio/audio.c b/audio/audio.c
index 8f1c0e77b0..cd10f1ec10 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -706,56 +706,55 @@ static void audio_pcm_sw_resample_out(SWVoiceOut *sw,
}
}
-static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
+static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t buf_len)
{
- size_t hwsamples, samples, live, dead;
- size_t hw_free;
- size_t ret, total;
-
- hwsamples = sw->hw->mix_buf.size;
+ HWVoiceOut *hw = sw->hw;
+ size_t live, dead, hw_free;
+ size_t frames_in_max, total_in, total_out;
live = sw->total_hw_samples_mixed;
- if (audio_bug(__func__, live > hwsamples)) {
- dolog("live=%zu hw->mix_buf.size=%zu\n", live, hwsamples);
+ if (audio_bug(__func__, live > hw->mix_buf.size)) {
+ dolog("live=%zu hw->mix_buf.size=%zu\n", live, hw->mix_buf.size);
return 0;
}
- if (live == hwsamples) {
+ if (live == hw->mix_buf.size) {
#ifdef DEBUG_OUT
dolog ("%s is full %zu\n", sw->name, live);
#endif
return 0;
}
- dead = hwsamples - live;
- hw_free = audio_pcm_hw_get_free(sw->hw);
+ dead = hw->mix_buf.size - live;
+ hw_free = audio_pcm_hw_get_free(hw);
hw_free = hw_free > live ? hw_free - live : 0;
- samples = ((int64_t)MIN(dead, hw_free) << 32) / sw->ratio;
- samples = MIN(samples, size / sw->info.bytes_per_frame);
- if (samples) {
- sw->conv(sw->resample_buf.buffer, buf, samples);
+ frames_in_max = ((int64_t)MIN(dead, hw_free) << 32) / sw->ratio;
+ frames_in_max = MIN(frames_in_max, buf_len / sw->info.bytes_per_frame);
+ if (frames_in_max) {
+ sw->conv(sw->resample_buf.buffer, buf, frames_in_max);
if (!sw->hw->pcm_ops->volume_out) {
- mixeng_volume(sw->resample_buf.buffer, samples, &sw->vol);
+ mixeng_volume(sw->resample_buf.buffer, frames_in_max, &sw->vol);
}
}
- audio_pcm_sw_resample_out(sw, samples, MIN(dead, hw_free), &ret, &total);
+ audio_pcm_sw_resample_out(sw, frames_in_max, MIN(dead, hw_free),
+ &total_in, &total_out);
- sw->total_hw_samples_mixed += total;
+ sw->total_hw_samples_mixed += total_out;
sw->empty = sw->total_hw_samples_mixed == 0;
#ifdef DEBUG_OUT
dolog (
- "%s: write size %zu ret %zu total sw %zu\n",
- SW_NAME (sw),
- size / sw->info.bytes_per_frame,
- ret,
+ "%s: write size %zu written %zu total mixed %zu\n",
+ SW_NAME(sw),
+ buf_len / sw->info.bytes_per_frame,
+ total_in,
sw->total_hw_samples_mixed
);
#endif
- return ret * sw->info.bytes_per_frame;
+ return total_in * sw->info.bytes_per_frame;
}
#ifdef DEBUG_AUDIO
--
2.35.3
^ permalink raw reply related [flat|nested] 34+ messages in thread
* Re: [PATCH v2 06/17] audio: rename variables in audio_pcm_sw_write()
2023-02-06 18:52 ` [PATCH v2 06/17] audio: rename variables in audio_pcm_sw_write() Volker Rümelin
@ 2023-02-22 10:49 ` Marc-André Lureau
0 siblings, 0 replies; 34+ messages in thread
From: Marc-André Lureau @ 2023-02-22 10:49 UTC (permalink / raw)
To: Volker Rümelin
Cc: Gerd Hoffmann, qemu-devel, Christian Schoenebeck,
Mark Cave-Ayland
On Mon, Feb 6, 2023 at 10:52 PM Volker Rümelin <vr_qemu@t-online.de> wrote:
>
> The audio_pcm_sw_write() function uses a lot of very unspecific
> variable names. Rename them for better readability.
>
> ret => total_in
> total => total_out
> size => buf_len
> hwsamples => hw->mix_buf.size
> samples => frames_in_max
>
> Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
> audio/audio.c | 45 ++++++++++++++++++++++-----------------------
> 1 file changed, 22 insertions(+), 23 deletions(-)
>
> diff --git a/audio/audio.c b/audio/audio.c
> index 8f1c0e77b0..cd10f1ec10 100644
> --- a/audio/audio.c
> +++ b/audio/audio.c
> @@ -706,56 +706,55 @@ static void audio_pcm_sw_resample_out(SWVoiceOut *sw,
> }
> }
>
> -static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
> +static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t buf_len)
> {
> - size_t hwsamples, samples, live, dead;
> - size_t hw_free;
> - size_t ret, total;
> -
> - hwsamples = sw->hw->mix_buf.size;
> + HWVoiceOut *hw = sw->hw;
> + size_t live, dead, hw_free;
> + size_t frames_in_max, total_in, total_out;
>
> live = sw->total_hw_samples_mixed;
> - if (audio_bug(__func__, live > hwsamples)) {
> - dolog("live=%zu hw->mix_buf.size=%zu\n", live, hwsamples);
> + if (audio_bug(__func__, live > hw->mix_buf.size)) {
> + dolog("live=%zu hw->mix_buf.size=%zu\n", live, hw->mix_buf.size);
> return 0;
> }
>
> - if (live == hwsamples) {
> + if (live == hw->mix_buf.size) {
> #ifdef DEBUG_OUT
> dolog ("%s is full %zu\n", sw->name, live);
> #endif
> return 0;
> }
>
> - dead = hwsamples - live;
> - hw_free = audio_pcm_hw_get_free(sw->hw);
> + dead = hw->mix_buf.size - live;
> + hw_free = audio_pcm_hw_get_free(hw);
> hw_free = hw_free > live ? hw_free - live : 0;
> - samples = ((int64_t)MIN(dead, hw_free) << 32) / sw->ratio;
> - samples = MIN(samples, size / sw->info.bytes_per_frame);
> - if (samples) {
> - sw->conv(sw->resample_buf.buffer, buf, samples);
> + frames_in_max = ((int64_t)MIN(dead, hw_free) << 32) / sw->ratio;
> + frames_in_max = MIN(frames_in_max, buf_len / sw->info.bytes_per_frame);
> + if (frames_in_max) {
> + sw->conv(sw->resample_buf.buffer, buf, frames_in_max);
>
> if (!sw->hw->pcm_ops->volume_out) {
> - mixeng_volume(sw->resample_buf.buffer, samples, &sw->vol);
> + mixeng_volume(sw->resample_buf.buffer, frames_in_max, &sw->vol);
> }
> }
>
> - audio_pcm_sw_resample_out(sw, samples, MIN(dead, hw_free), &ret, &total);
> + audio_pcm_sw_resample_out(sw, frames_in_max, MIN(dead, hw_free),
> + &total_in, &total_out);
>
> - sw->total_hw_samples_mixed += total;
> + sw->total_hw_samples_mixed += total_out;
> sw->empty = sw->total_hw_samples_mixed == 0;
>
> #ifdef DEBUG_OUT
> dolog (
> - "%s: write size %zu ret %zu total sw %zu\n",
> - SW_NAME (sw),
> - size / sw->info.bytes_per_frame,
> - ret,
> + "%s: write size %zu written %zu total mixed %zu\n",
> + SW_NAME(sw),
> + buf_len / sw->info.bytes_per_frame,
> + total_in,
> sw->total_hw_samples_mixed
> );
> #endif
>
> - return ret * sw->info.bytes_per_frame;
> + return total_in * sw->info.bytes_per_frame;
> }
>
> #ifdef DEBUG_AUDIO
> --
> 2.35.3
>
--
Marc-André Lureau
^ permalink raw reply [flat|nested] 34+ messages in thread
* [PATCH v2 07/17] audio: don't misuse audio_pcm_sw_write()
2023-02-06 18:47 [PATCH v2 00/17] audio: improve callback interface for audio frontends Volker Rümelin
` (5 preceding siblings ...)
2023-02-06 18:52 ` [PATCH v2 06/17] audio: rename variables in audio_pcm_sw_write() Volker Rümelin
@ 2023-02-06 18:52 ` Volker Rümelin
2023-02-22 10:49 ` Marc-André Lureau
2023-02-06 18:52 ` [PATCH v2 08/17] audio: remove unused noop_conv() function Volker Rümelin
` (9 subsequent siblings)
16 siblings, 1 reply; 34+ messages in thread
From: Volker Rümelin @ 2023-02-06 18:52 UTC (permalink / raw)
To: Gerd Hoffmann, Marc-André Lureau
Cc: qemu-devel, Christian Schoenebeck, Mark Cave-Ayland
The audio_pcm_sw_write() function is intended to convert a
PCM audio stream to the internal representation, adjust the
volume, and then mix it with the other audio streams with a
possibly changed sample rate in mix_buf. In order for the
audio_capture_mix_and_clear() function to use audio_pcm_sw_write(),
it must bypass the first two tasks of audio_pcm_sw_write().
Since patch "audio: split out the resampling loop in
audio_pcm_sw_write()" this is no longer necessary, because now
the audio_pcm_sw_resample_out() function can be used instead of
audio_pcm_sw_write().
Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
---
audio/audio.c | 29 ++++++++++++++++++-----------
1 file changed, 18 insertions(+), 11 deletions(-)
diff --git a/audio/audio.c b/audio/audio.c
index cd10f1ec10..44eb7b63b4 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -1056,26 +1056,33 @@ static void audio_capture_mix_and_clear(HWVoiceOut *hw, size_t rpos,
for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) {
SWVoiceOut *sw = &sc->sw;
- int rpos2 = rpos;
+ size_t rpos2 = rpos;
n = samples;
while (n) {
size_t till_end_of_hw = hw->mix_buf.size - rpos2;
- size_t to_write = MIN(till_end_of_hw, n);
- size_t bytes = to_write * hw->info.bytes_per_frame;
- size_t written;
+ size_t to_read = MIN(till_end_of_hw, n);
+ size_t live, frames_in, frames_out;
sw->resample_buf.buffer = hw->mix_buf.buffer + rpos2;
- sw->resample_buf.size = to_write;
- written = audio_pcm_sw_write (sw, NULL, bytes);
- if (written - bytes) {
- dolog("Could not mix %zu bytes into a capture "
+ sw->resample_buf.size = to_read;
+ live = sw->total_hw_samples_mixed;
+
+ audio_pcm_sw_resample_out(sw,
+ to_read, sw->hw->mix_buf.size - live,
+ &frames_in, &frames_out);
+
+ sw->total_hw_samples_mixed += frames_out;
+ sw->empty = sw->total_hw_samples_mixed == 0;
+
+ if (to_read - frames_in) {
+ dolog("Could not mix %zu frames into a capture "
"buffer, mixed %zu\n",
- bytes, written);
+ to_read, frames_in);
break;
}
- n -= to_write;
- rpos2 = (rpos2 + to_write) % hw->mix_buf.size;
+ n -= to_read;
+ rpos2 = (rpos2 + to_read) % hw->mix_buf.size;
}
}
}
--
2.35.3
^ permalink raw reply related [flat|nested] 34+ messages in thread
* Re: [PATCH v2 07/17] audio: don't misuse audio_pcm_sw_write()
2023-02-06 18:52 ` [PATCH v2 07/17] audio: don't misuse audio_pcm_sw_write() Volker Rümelin
@ 2023-02-22 10:49 ` Marc-André Lureau
0 siblings, 0 replies; 34+ messages in thread
From: Marc-André Lureau @ 2023-02-22 10:49 UTC (permalink / raw)
To: Volker Rümelin
Cc: Gerd Hoffmann, qemu-devel, Christian Schoenebeck,
Mark Cave-Ayland
On Mon, Feb 6, 2023 at 10:52 PM Volker Rümelin <vr_qemu@t-online.de> wrote:
>
> The audio_pcm_sw_write() function is intended to convert a
> PCM audio stream to the internal representation, adjust the
> volume, and then mix it with the other audio streams with a
> possibly changed sample rate in mix_buf. In order for the
> audio_capture_mix_and_clear() function to use audio_pcm_sw_write(),
> it must bypass the first two tasks of audio_pcm_sw_write().
>
> Since patch "audio: split out the resampling loop in
> audio_pcm_sw_write()" this is no longer necessary, because now
> the audio_pcm_sw_resample_out() function can be used instead of
> audio_pcm_sw_write().
>
> Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
Acked-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
> audio/audio.c | 29 ++++++++++++++++++-----------
> 1 file changed, 18 insertions(+), 11 deletions(-)
>
> diff --git a/audio/audio.c b/audio/audio.c
> index cd10f1ec10..44eb7b63b4 100644
> --- a/audio/audio.c
> +++ b/audio/audio.c
> @@ -1056,26 +1056,33 @@ static void audio_capture_mix_and_clear(HWVoiceOut *hw, size_t rpos,
>
> for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) {
> SWVoiceOut *sw = &sc->sw;
> - int rpos2 = rpos;
> + size_t rpos2 = rpos;
>
> n = samples;
> while (n) {
> size_t till_end_of_hw = hw->mix_buf.size - rpos2;
> - size_t to_write = MIN(till_end_of_hw, n);
> - size_t bytes = to_write * hw->info.bytes_per_frame;
> - size_t written;
> + size_t to_read = MIN(till_end_of_hw, n);
> + size_t live, frames_in, frames_out;
>
> sw->resample_buf.buffer = hw->mix_buf.buffer + rpos2;
> - sw->resample_buf.size = to_write;
> - written = audio_pcm_sw_write (sw, NULL, bytes);
> - if (written - bytes) {
> - dolog("Could not mix %zu bytes into a capture "
> + sw->resample_buf.size = to_read;
> + live = sw->total_hw_samples_mixed;
> +
> + audio_pcm_sw_resample_out(sw,
> + to_read, sw->hw->mix_buf.size - live,
> + &frames_in, &frames_out);
> +
> + sw->total_hw_samples_mixed += frames_out;
> + sw->empty = sw->total_hw_samples_mixed == 0;
> +
> + if (to_read - frames_in) {
> + dolog("Could not mix %zu frames into a capture "
> "buffer, mixed %zu\n",
> - bytes, written);
> + to_read, frames_in);
> break;
> }
> - n -= to_write;
> - rpos2 = (rpos2 + to_write) % hw->mix_buf.size;
> + n -= to_read;
> + rpos2 = (rpos2 + to_read) % hw->mix_buf.size;
> }
> }
> }
> --
> 2.35.3
>
--
Marc-André Lureau
^ permalink raw reply [flat|nested] 34+ messages in thread
* [PATCH v2 08/17] audio: remove unused noop_conv() function
2023-02-06 18:47 [PATCH v2 00/17] audio: improve callback interface for audio frontends Volker Rümelin
` (6 preceding siblings ...)
2023-02-06 18:52 ` [PATCH v2 07/17] audio: don't misuse audio_pcm_sw_write() Volker Rümelin
@ 2023-02-06 18:52 ` Volker Rümelin
2023-02-22 10:49 ` Marc-André Lureau
2023-02-06 18:52 ` [PATCH v2 09/17] audio/mixeng: calculate number of input frames Volker Rümelin
` (8 subsequent siblings)
16 siblings, 1 reply; 34+ messages in thread
From: Volker Rümelin @ 2023-02-06 18:52 UTC (permalink / raw)
To: Gerd Hoffmann, Marc-André Lureau
Cc: qemu-devel, Christian Schoenebeck, Mark Cave-Ayland
The function audio_capture_mix_and_clear() no longer uses
audio_pcm_sw_write() to resample audio frames from one internal
buffer to another. For this reason, the noop_conv() function is
now unused. Remove it.
Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
---
audio/audio.c | 8 --------
1 file changed, 8 deletions(-)
diff --git a/audio/audio.c b/audio/audio.c
index 44eb7b63b4..556696b095 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -381,13 +381,6 @@ void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len)
/*
* Capture
*/
-static void noop_conv (struct st_sample *dst, const void *src, int samples)
-{
- (void) src;
- (void) dst;
- (void) samples;
-}
-
static CaptureVoiceOut *audio_pcm_capture_find_specific(AudioState *s,
struct audsettings *as)
{
@@ -485,7 +478,6 @@ static int audio_attach_capture (HWVoiceOut *hw)
sw->info = hw->info;
sw->empty = 1;
sw->active = hw->enabled;
- sw->conv = noop_conv;
sw->ratio = ((int64_t) hw_cap->info.freq << 32) / sw->info.freq;
sw->vol = nominal_volume;
sw->rate = st_rate_start (sw->info.freq, hw_cap->info.freq);
--
2.35.3
^ permalink raw reply related [flat|nested] 34+ messages in thread
* Re: [PATCH v2 08/17] audio: remove unused noop_conv() function
2023-02-06 18:52 ` [PATCH v2 08/17] audio: remove unused noop_conv() function Volker Rümelin
@ 2023-02-22 10:49 ` Marc-André Lureau
0 siblings, 0 replies; 34+ messages in thread
From: Marc-André Lureau @ 2023-02-22 10:49 UTC (permalink / raw)
To: Volker Rümelin
Cc: Gerd Hoffmann, qemu-devel, Christian Schoenebeck,
Mark Cave-Ayland
On Mon, Feb 6, 2023 at 10:52 PM Volker Rümelin <vr_qemu@t-online.de> wrote:
>
> The function audio_capture_mix_and_clear() no longer uses
> audio_pcm_sw_write() to resample audio frames from one internal
> buffer to another. For this reason, the noop_conv() function is
> now unused. Remove it.
>
> Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
> audio/audio.c | 8 --------
> 1 file changed, 8 deletions(-)
>
> diff --git a/audio/audio.c b/audio/audio.c
> index 44eb7b63b4..556696b095 100644
> --- a/audio/audio.c
> +++ b/audio/audio.c
> @@ -381,13 +381,6 @@ void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len)
> /*
> * Capture
> */
> -static void noop_conv (struct st_sample *dst, const void *src, int samples)
> -{
> - (void) src;
> - (void) dst;
> - (void) samples;
> -}
> -
> static CaptureVoiceOut *audio_pcm_capture_find_specific(AudioState *s,
> struct audsettings *as)
> {
> @@ -485,7 +478,6 @@ static int audio_attach_capture (HWVoiceOut *hw)
> sw->info = hw->info;
> sw->empty = 1;
> sw->active = hw->enabled;
> - sw->conv = noop_conv;
> sw->ratio = ((int64_t) hw_cap->info.freq << 32) / sw->info.freq;
> sw->vol = nominal_volume;
> sw->rate = st_rate_start (sw->info.freq, hw_cap->info.freq);
> --
> 2.35.3
>
--
Marc-André Lureau
^ permalink raw reply [flat|nested] 34+ messages in thread
* [PATCH v2 09/17] audio/mixeng: calculate number of input frames
2023-02-06 18:47 [PATCH v2 00/17] audio: improve callback interface for audio frontends Volker Rümelin
` (7 preceding siblings ...)
2023-02-06 18:52 ` [PATCH v2 08/17] audio: remove unused noop_conv() function Volker Rümelin
@ 2023-02-06 18:52 ` Volker Rümelin
2023-02-22 10:50 ` Marc-André Lureau
2023-02-06 18:52 ` [PATCH v2 10/17] audio: wire up st_rate_frames_in() Volker Rümelin
` (7 subsequent siblings)
16 siblings, 1 reply; 34+ messages in thread
From: Volker Rümelin @ 2023-02-06 18:52 UTC (permalink / raw)
To: Gerd Hoffmann, Marc-André Lureau
Cc: qemu-devel, Christian Schoenebeck, Mark Cave-Ayland
Calculate the exact number of audio input frames needed to get
a given number of audio output frames. The exact number of
frames depends only on the difference of opos - ipos and the
number of output frames. When downsampling, this function
returns the maximum number of input frames needed.
This function will later replace the audio_frontend_frames_out()
function, which calculates the average number of input frames
rounded down to the nearest integer.
Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
---
audio/mixeng.c | 36 ++++++++++++++++++++++++++++++++++++
audio/mixeng.h | 1 +
2 files changed, 37 insertions(+)
diff --git a/audio/mixeng.c b/audio/mixeng.c
index fe454e0725..6bb3d54f77 100644
--- a/audio/mixeng.c
+++ b/audio/mixeng.c
@@ -440,6 +440,42 @@ void st_rate_stop (void *opaque)
g_free (opaque);
}
+/**
+ * st_rate_frames_in() - returns the number of frames needed to
+ * get frames_out frames after resampling
+ *
+ * @opaque: pointer to struct rate
+ * @frames_out: number of frames
+ */
+uint32_t st_rate_frames_in(void *opaque, uint32_t frames_out)
+{
+ struct rate *rate = opaque;
+ uint64_t opos_start, opos_end;
+ uint32_t ipos_start, ipos_end;
+
+ if (rate->opos_inc == 1ULL << 32) {
+ return frames_out;
+ }
+
+ if (frames_out) {
+ opos_start = rate->opos;
+ ipos_start = rate->ipos;
+ } else {
+ uint64_t offset;
+
+ /* add offset = ceil(opos_inc) to opos and ipos to avoid an underflow */
+ offset = (rate->opos_inc + (1ULL << 32) - 1) & ~((1ULL << 32) - 1);
+ opos_start = rate->opos + offset;
+ ipos_start = rate->ipos + (offset >> 32);
+ }
+ /* last frame written was at opos_start - rate->opos_inc */
+ opos_end = opos_start - rate->opos_inc + rate->opos_inc * frames_out;
+ ipos_end = (opos_end >> 32) + 1;
+
+ /* last frame read was at ipos_start - 1 */
+ return ipos_end + 1 > ipos_start ? ipos_end + 1 - ipos_start : 0;
+}
+
void mixeng_clear (struct st_sample *buf, int len)
{
memset (buf, 0, len * sizeof (struct st_sample));
diff --git a/audio/mixeng.h b/audio/mixeng.h
index 2dcd6df245..64c1e231cc 100644
--- a/audio/mixeng.h
+++ b/audio/mixeng.h
@@ -52,6 +52,7 @@ void st_rate_flow(void *opaque, st_sample *ibuf, st_sample *obuf,
void st_rate_flow_mix(void *opaque, st_sample *ibuf, st_sample *obuf,
size_t *isamp, size_t *osamp);
void st_rate_stop (void *opaque);
+uint32_t st_rate_frames_in(void *opaque, uint32_t frames_out);
void mixeng_clear (struct st_sample *buf, int len);
void mixeng_volume (struct st_sample *buf, int len, struct mixeng_volume *vol);
--
2.35.3
^ permalink raw reply related [flat|nested] 34+ messages in thread
* Re: [PATCH v2 09/17] audio/mixeng: calculate number of input frames
2023-02-06 18:52 ` [PATCH v2 09/17] audio/mixeng: calculate number of input frames Volker Rümelin
@ 2023-02-22 10:50 ` Marc-André Lureau
0 siblings, 0 replies; 34+ messages in thread
From: Marc-André Lureau @ 2023-02-22 10:50 UTC (permalink / raw)
To: Volker Rümelin
Cc: Gerd Hoffmann, qemu-devel, Christian Schoenebeck,
Mark Cave-Ayland
Hi
On Mon, Feb 6, 2023 at 10:52 PM Volker Rümelin <vr_qemu@t-online.de> wrote:
>
> Calculate the exact number of audio input frames needed to get
> a given number of audio output frames. The exact number of
> frames depends only on the difference of opos - ipos and the
> number of output frames. When downsampling, this function
> returns the maximum number of input frames needed.
>
> This function will later replace the audio_frontend_frames_out()
> function, which calculates the average number of input frames
> rounded down to the nearest integer.
>
> Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
We usually introduce functions with their usage, but ok
Acked-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
> audio/mixeng.c | 36 ++++++++++++++++++++++++++++++++++++
> audio/mixeng.h | 1 +
> 2 files changed, 37 insertions(+)
>
> diff --git a/audio/mixeng.c b/audio/mixeng.c
> index fe454e0725..6bb3d54f77 100644
> --- a/audio/mixeng.c
> +++ b/audio/mixeng.c
> @@ -440,6 +440,42 @@ void st_rate_stop (void *opaque)
> g_free (opaque);
> }
>
> +/**
> + * st_rate_frames_in() - returns the number of frames needed to
> + * get frames_out frames after resampling
> + *
> + * @opaque: pointer to struct rate
> + * @frames_out: number of frames
> + */
> +uint32_t st_rate_frames_in(void *opaque, uint32_t frames_out)
> +{
> + struct rate *rate = opaque;
> + uint64_t opos_start, opos_end;
> + uint32_t ipos_start, ipos_end;
> +
> + if (rate->opos_inc == 1ULL << 32) {
> + return frames_out;
> + }
> +
> + if (frames_out) {
> + opos_start = rate->opos;
> + ipos_start = rate->ipos;
> + } else {
> + uint64_t offset;
> +
> + /* add offset = ceil(opos_inc) to opos and ipos to avoid an underflow */
> + offset = (rate->opos_inc + (1ULL << 32) - 1) & ~((1ULL << 32) - 1);
> + opos_start = rate->opos + offset;
> + ipos_start = rate->ipos + (offset >> 32);
> + }
> + /* last frame written was at opos_start - rate->opos_inc */
> + opos_end = opos_start - rate->opos_inc + rate->opos_inc * frames_out;
> + ipos_end = (opos_end >> 32) + 1;
> +
> + /* last frame read was at ipos_start - 1 */
> + return ipos_end + 1 > ipos_start ? ipos_end + 1 - ipos_start : 0;
> +}
> +
> void mixeng_clear (struct st_sample *buf, int len)
> {
> memset (buf, 0, len * sizeof (struct st_sample));
> diff --git a/audio/mixeng.h b/audio/mixeng.h
> index 2dcd6df245..64c1e231cc 100644
> --- a/audio/mixeng.h
> +++ b/audio/mixeng.h
> @@ -52,6 +52,7 @@ void st_rate_flow(void *opaque, st_sample *ibuf, st_sample *obuf,
> void st_rate_flow_mix(void *opaque, st_sample *ibuf, st_sample *obuf,
> size_t *isamp, size_t *osamp);
> void st_rate_stop (void *opaque);
> +uint32_t st_rate_frames_in(void *opaque, uint32_t frames_out);
> void mixeng_clear (struct st_sample *buf, int len);
> void mixeng_volume (struct st_sample *buf, int len, struct mixeng_volume *vol);
>
> --
> 2.35.3
>
--
Marc-André Lureau
^ permalink raw reply [flat|nested] 34+ messages in thread
* [PATCH v2 10/17] audio: wire up st_rate_frames_in()
2023-02-06 18:47 [PATCH v2 00/17] audio: improve callback interface for audio frontends Volker Rümelin
` (8 preceding siblings ...)
2023-02-06 18:52 ` [PATCH v2 09/17] audio/mixeng: calculate number of input frames Volker Rümelin
@ 2023-02-06 18:52 ` Volker Rümelin
2023-02-22 10:50 ` Marc-André Lureau
2023-02-06 18:52 ` [PATCH v2 11/17] audio: replace the resampling loop in audio_pcm_sw_read() Volker Rümelin
` (6 subsequent siblings)
16 siblings, 1 reply; 34+ messages in thread
From: Volker Rümelin @ 2023-02-06 18:52 UTC (permalink / raw)
To: Gerd Hoffmann, Marc-André Lureau
Cc: qemu-devel, Christian Schoenebeck, Mark Cave-Ayland
Wire up the st_rate_frames_in() function and replace
audio_frontend_frames_out() to make audio packet length
calculation exact. When upsampling, it's still possible that
the audio frontends can't write the last audio frame. This will
be fixed later.
Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
---
audio/audio.c | 43 ++++++++++++++++++-------------------------
1 file changed, 18 insertions(+), 25 deletions(-)
diff --git a/audio/audio.c b/audio/audio.c
index 556696b095..e18b5e98c5 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -701,8 +701,8 @@ static void audio_pcm_sw_resample_out(SWVoiceOut *sw,
static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t buf_len)
{
HWVoiceOut *hw = sw->hw;
- size_t live, dead, hw_free;
- size_t frames_in_max, total_in, total_out;
+ size_t live, dead, hw_free, sw_max, fe_max;
+ size_t frames_in_max, frames_out_max, total_in, total_out;
live = sw->total_hw_samples_mixed;
if (audio_bug(__func__, live > hw->mix_buf.size)) {
@@ -720,17 +720,21 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t buf_len)
dead = hw->mix_buf.size - live;
hw_free = audio_pcm_hw_get_free(hw);
hw_free = hw_free > live ? hw_free - live : 0;
- frames_in_max = ((int64_t)MIN(dead, hw_free) << 32) / sw->ratio;
- frames_in_max = MIN(frames_in_max, buf_len / sw->info.bytes_per_frame);
- if (frames_in_max) {
- sw->conv(sw->resample_buf.buffer, buf, frames_in_max);
+ frames_out_max = MIN(dead, hw_free);
+ sw_max = st_rate_frames_in(sw->rate, frames_out_max);
+ fe_max = MIN(buf_len / sw->info.bytes_per_frame, sw->resample_buf.size);
+ frames_in_max = MIN(sw_max, fe_max);
- if (!sw->hw->pcm_ops->volume_out) {
- mixeng_volume(sw->resample_buf.buffer, frames_in_max, &sw->vol);
- }
+ if (!frames_in_max) {
+ return 0;
}
- audio_pcm_sw_resample_out(sw, frames_in_max, MIN(dead, hw_free),
+ sw->conv(sw->resample_buf.buffer, buf, frames_in_max);
+ if (!sw->hw->pcm_ops->volume_out) {
+ mixeng_volume(sw->resample_buf.buffer, frames_in_max, &sw->vol);
+ }
+
+ audio_pcm_sw_resample_out(sw, frames_in_max, frames_out_max,
&total_in, &total_out);
sw->total_hw_samples_mixed += total_out;
@@ -1000,18 +1004,6 @@ static size_t audio_get_avail (SWVoiceIn *sw)
return live;
}
-/**
- * audio_frontend_frames_out() - returns the number of frames needed to
- * get frames_out frames after resampling
- *
- * @sw: audio playback frontend
- * @frames_out: number of frames
- */
-static size_t audio_frontend_frames_out(SWVoiceOut *sw, size_t frames_out)
-{
- return ((int64_t)frames_out << 32) / sw->ratio;
-}
-
static size_t audio_get_free(SWVoiceOut *sw)
{
size_t live, dead;
@@ -1031,8 +1023,8 @@ static size_t audio_get_free(SWVoiceOut *sw)
dead = sw->hw->mix_buf.size - live;
#ifdef DEBUG_OUT
- dolog("%s: get_free live %zu dead %zu frontend frames %zu\n",
- SW_NAME(sw), live, dead, audio_frontend_frames_out(sw, dead));
+ dolog("%s: get_free live %zu dead %zu frontend frames %u\n",
+ SW_NAME(sw), live, dead, st_rate_frames_in(sw->rate, dead));
#endif
return dead;
@@ -1161,12 +1153,13 @@ static void audio_run_out (AudioState *s)
size_t free;
if (hw_free > sw->total_hw_samples_mixed) {
- free = audio_frontend_frames_out(sw,
+ free = st_rate_frames_in(sw->rate,
MIN(sw_free, hw_free - sw->total_hw_samples_mixed));
} else {
free = 0;
}
if (free > 0) {
+ free = MIN(free, sw->resample_buf.size);
sw->callback.fn(sw->callback.opaque,
free * sw->info.bytes_per_frame);
}
--
2.35.3
^ permalink raw reply related [flat|nested] 34+ messages in thread
* Re: [PATCH v2 10/17] audio: wire up st_rate_frames_in()
2023-02-06 18:52 ` [PATCH v2 10/17] audio: wire up st_rate_frames_in() Volker Rümelin
@ 2023-02-22 10:50 ` Marc-André Lureau
0 siblings, 0 replies; 34+ messages in thread
From: Marc-André Lureau @ 2023-02-22 10:50 UTC (permalink / raw)
To: Volker Rümelin
Cc: Gerd Hoffmann, qemu-devel, Christian Schoenebeck,
Mark Cave-Ayland
Hi
On Mon, Feb 6, 2023 at 10:53 PM Volker Rümelin <vr_qemu@t-online.de> wrote:
>
> Wire up the st_rate_frames_in() function and replace
> audio_frontend_frames_out() to make audio packet length
> calculation exact. When upsampling, it's still possible that
> the audio frontends can't write the last audio frame. This will
> be fixed later.
>
> Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
I think you should squash it with the previous patch and detail the
differences of computation (the code comment of the functions should
reflect the change, that would help ;)
> ---
> audio/audio.c | 43 ++++++++++++++++++-------------------------
> 1 file changed, 18 insertions(+), 25 deletions(-)
>
> diff --git a/audio/audio.c b/audio/audio.c
> index 556696b095..e18b5e98c5 100644
> --- a/audio/audio.c
> +++ b/audio/audio.c
> @@ -701,8 +701,8 @@ static void audio_pcm_sw_resample_out(SWVoiceOut *sw,
> static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t buf_len)
> {
> HWVoiceOut *hw = sw->hw;
> - size_t live, dead, hw_free;
> - size_t frames_in_max, total_in, total_out;
> + size_t live, dead, hw_free, sw_max, fe_max;
> + size_t frames_in_max, frames_out_max, total_in, total_out;
>
> live = sw->total_hw_samples_mixed;
> if (audio_bug(__func__, live > hw->mix_buf.size)) {
> @@ -720,17 +720,21 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t buf_len)
> dead = hw->mix_buf.size - live;
> hw_free = audio_pcm_hw_get_free(hw);
> hw_free = hw_free > live ? hw_free - live : 0;
> - frames_in_max = ((int64_t)MIN(dead, hw_free) << 32) / sw->ratio;
> - frames_in_max = MIN(frames_in_max, buf_len / sw->info.bytes_per_frame);
> - if (frames_in_max) {
> - sw->conv(sw->resample_buf.buffer, buf, frames_in_max);
> + frames_out_max = MIN(dead, hw_free);
> + sw_max = st_rate_frames_in(sw->rate, frames_out_max);
> + fe_max = MIN(buf_len / sw->info.bytes_per_frame, sw->resample_buf.size);
> + frames_in_max = MIN(sw_max, fe_max);
>
> - if (!sw->hw->pcm_ops->volume_out) {
> - mixeng_volume(sw->resample_buf.buffer, frames_in_max, &sw->vol);
> - }
> + if (!frames_in_max) {
> + return 0;
> }
>
> - audio_pcm_sw_resample_out(sw, frames_in_max, MIN(dead, hw_free),
> + sw->conv(sw->resample_buf.buffer, buf, frames_in_max);
> + if (!sw->hw->pcm_ops->volume_out) {
> + mixeng_volume(sw->resample_buf.buffer, frames_in_max, &sw->vol);
> + }
> +
> + audio_pcm_sw_resample_out(sw, frames_in_max, frames_out_max,
> &total_in, &total_out);
>
> sw->total_hw_samples_mixed += total_out;
> @@ -1000,18 +1004,6 @@ static size_t audio_get_avail (SWVoiceIn *sw)
> return live;
> }
>
> -/**
> - * audio_frontend_frames_out() - returns the number of frames needed to
> - * get frames_out frames after resampling
> - *
> - * @sw: audio playback frontend
> - * @frames_out: number of frames
> - */
> -static size_t audio_frontend_frames_out(SWVoiceOut *sw, size_t frames_out)
> -{
> - return ((int64_t)frames_out << 32) / sw->ratio;
> -}
> -
> static size_t audio_get_free(SWVoiceOut *sw)
> {
> size_t live, dead;
> @@ -1031,8 +1023,8 @@ static size_t audio_get_free(SWVoiceOut *sw)
> dead = sw->hw->mix_buf.size - live;
>
> #ifdef DEBUG_OUT
> - dolog("%s: get_free live %zu dead %zu frontend frames %zu\n",
> - SW_NAME(sw), live, dead, audio_frontend_frames_out(sw, dead));
> + dolog("%s: get_free live %zu dead %zu frontend frames %u\n",
> + SW_NAME(sw), live, dead, st_rate_frames_in(sw->rate, dead));
> #endif
>
> return dead;
> @@ -1161,12 +1153,13 @@ static void audio_run_out (AudioState *s)
> size_t free;
>
> if (hw_free > sw->total_hw_samples_mixed) {
> - free = audio_frontend_frames_out(sw,
> + free = st_rate_frames_in(sw->rate,
> MIN(sw_free, hw_free - sw->total_hw_samples_mixed));
> } else {
> free = 0;
> }
> if (free > 0) {
> + free = MIN(free, sw->resample_buf.size);
> sw->callback.fn(sw->callback.opaque,
> free * sw->info.bytes_per_frame);
> }
> --
> 2.35.3
>
--
Marc-André Lureau
^ permalink raw reply [flat|nested] 34+ messages in thread
* [PATCH v2 11/17] audio: replace the resampling loop in audio_pcm_sw_read()
2023-02-06 18:47 [PATCH v2 00/17] audio: improve callback interface for audio frontends Volker Rümelin
` (9 preceding siblings ...)
2023-02-06 18:52 ` [PATCH v2 10/17] audio: wire up st_rate_frames_in() Volker Rümelin
@ 2023-02-06 18:52 ` Volker Rümelin
2023-02-22 10:50 ` Marc-André Lureau
2023-02-06 18:52 ` [PATCH v2 12/17] audio: rename variables " Volker Rümelin
` (5 subsequent siblings)
16 siblings, 1 reply; 34+ messages in thread
From: Volker Rümelin @ 2023-02-06 18:52 UTC (permalink / raw)
To: Gerd Hoffmann, Marc-André Lureau
Cc: qemu-devel, Christian Schoenebeck, Mark Cave-Ayland
Replace the resampling loop in audio_pcm_sw_read() with the new
function audio_pcm_sw_resample_in(). Unlike the old resample
loop the new function will try to consume input frames even if
the output buffer is full. This is necessary when downsampling
to avoid reading less audio frames than calculated in advance.
The loop was unrolled to avoid complicated loop control conditions
in this case.
Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
---
audio/audio.c | 59 ++++++++++++++++++++++++++++++---------------------
1 file changed, 35 insertions(+), 24 deletions(-)
diff --git a/audio/audio.c b/audio/audio.c
index e18b5e98c5..9e9c03a42e 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -543,11 +543,43 @@ static size_t audio_pcm_hw_conv_in(HWVoiceIn *hw, void *pcm_buf, size_t samples)
/*
* Soft voice (capture)
*/
+static void audio_pcm_sw_resample_in(SWVoiceIn *sw,
+ size_t frames_in_max, size_t frames_out_max,
+ size_t *total_in, size_t *total_out)
+{
+ HWVoiceIn *hw = sw->hw;
+ struct st_sample *src, *dst;
+ size_t live, rpos, frames_in, frames_out;
+
+ live = hw->total_samples_captured - sw->total_hw_samples_acquired;
+ rpos = audio_ring_posb(hw->conv_buf.pos, live, hw->conv_buf.size);
+
+ /* resample conv_buf from rpos to end of buffer */
+ src = hw->conv_buf.buffer + rpos;
+ frames_in = MIN(frames_in_max, hw->conv_buf.size - rpos);
+ dst = sw->resample_buf.buffer;
+ frames_out = frames_out_max;
+ st_rate_flow(sw->rate, src, dst, &frames_in, &frames_out);
+ rpos += frames_in;
+ *total_in = frames_in;
+ *total_out = frames_out;
+
+ /* resample conv_buf from start of buffer if there are input frames left */
+ if (frames_in_max - frames_in && rpos == hw->conv_buf.size) {
+ src = hw->conv_buf.buffer;
+ frames_in = frames_in_max - frames_in;
+ dst += frames_out;
+ frames_out = frames_out_max - frames_out;
+ st_rate_flow(sw->rate, src, dst, &frames_in, &frames_out);
+ *total_in += frames_in;
+ *total_out += frames_out;
+ }
+}
+
static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t size)
{
HWVoiceIn *hw = sw->hw;
- size_t samples, live, ret = 0, swlim, isamp, osamp, rpos, total = 0;
- struct st_sample *src, *dst = sw->resample_buf.buffer;
+ size_t samples, live, ret, swlim, total;
live = hw->total_samples_captured - sw->total_hw_samples_acquired;
if (!live) {
@@ -558,33 +590,12 @@ static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t size)
return 0;
}
- rpos = audio_ring_posb(hw->conv_buf.pos, live, hw->conv_buf.size);
-
samples = size / sw->info.bytes_per_frame;
swlim = (live * sw->ratio) >> 32;
swlim = MIN (swlim, samples);
- while (swlim) {
- src = hw->conv_buf.buffer + rpos;
- if (hw->conv_buf.pos > rpos) {
- isamp = hw->conv_buf.pos - rpos;
- } else {
- isamp = hw->conv_buf.size - rpos;
- }
-
- if (!isamp) {
- break;
- }
- osamp = swlim;
-
- st_rate_flow (sw->rate, src, dst, &isamp, &osamp);
- swlim -= osamp;
- rpos = (rpos + isamp) % hw->conv_buf.size;
- dst += osamp;
- ret += osamp;
- total += isamp;
- }
+ audio_pcm_sw_resample_in(sw, live, swlim, &total, &ret);
if (!hw->pcm_ops->volume_in) {
mixeng_volume(sw->resample_buf.buffer, ret, &sw->vol);
--
2.35.3
^ permalink raw reply related [flat|nested] 34+ messages in thread
* Re: [PATCH v2 11/17] audio: replace the resampling loop in audio_pcm_sw_read()
2023-02-06 18:52 ` [PATCH v2 11/17] audio: replace the resampling loop in audio_pcm_sw_read() Volker Rümelin
@ 2023-02-22 10:50 ` Marc-André Lureau
0 siblings, 0 replies; 34+ messages in thread
From: Marc-André Lureau @ 2023-02-22 10:50 UTC (permalink / raw)
To: Volker Rümelin
Cc: Gerd Hoffmann, qemu-devel, Christian Schoenebeck,
Mark Cave-Ayland
On Mon, Feb 6, 2023 at 10:53 PM Volker Rümelin <vr_qemu@t-online.de> wrote:
>
> Replace the resampling loop in audio_pcm_sw_read() with the new
> function audio_pcm_sw_resample_in(). Unlike the old resample
> loop the new function will try to consume input frames even if
> the output buffer is full. This is necessary when downsampling
> to avoid reading less audio frames than calculated in advance.
> The loop was unrolled to avoid complicated loop control conditions
> in this case.
>
> Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
Acked-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
> audio/audio.c | 59 ++++++++++++++++++++++++++++++---------------------
> 1 file changed, 35 insertions(+), 24 deletions(-)
>
> diff --git a/audio/audio.c b/audio/audio.c
> index e18b5e98c5..9e9c03a42e 100644
> --- a/audio/audio.c
> +++ b/audio/audio.c
> @@ -543,11 +543,43 @@ static size_t audio_pcm_hw_conv_in(HWVoiceIn *hw, void *pcm_buf, size_t samples)
> /*
> * Soft voice (capture)
> */
> +static void audio_pcm_sw_resample_in(SWVoiceIn *sw,
> + size_t frames_in_max, size_t frames_out_max,
> + size_t *total_in, size_t *total_out)
> +{
> + HWVoiceIn *hw = sw->hw;
> + struct st_sample *src, *dst;
> + size_t live, rpos, frames_in, frames_out;
> +
> + live = hw->total_samples_captured - sw->total_hw_samples_acquired;
> + rpos = audio_ring_posb(hw->conv_buf.pos, live, hw->conv_buf.size);
> +
> + /* resample conv_buf from rpos to end of buffer */
> + src = hw->conv_buf.buffer + rpos;
> + frames_in = MIN(frames_in_max, hw->conv_buf.size - rpos);
> + dst = sw->resample_buf.buffer;
> + frames_out = frames_out_max;
> + st_rate_flow(sw->rate, src, dst, &frames_in, &frames_out);
> + rpos += frames_in;
> + *total_in = frames_in;
> + *total_out = frames_out;
> +
> + /* resample conv_buf from start of buffer if there are input frames left */
> + if (frames_in_max - frames_in && rpos == hw->conv_buf.size) {
> + src = hw->conv_buf.buffer;
> + frames_in = frames_in_max - frames_in;
> + dst += frames_out;
> + frames_out = frames_out_max - frames_out;
> + st_rate_flow(sw->rate, src, dst, &frames_in, &frames_out);
> + *total_in += frames_in;
> + *total_out += frames_out;
> + }
> +}
> +
> static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t size)
> {
> HWVoiceIn *hw = sw->hw;
> - size_t samples, live, ret = 0, swlim, isamp, osamp, rpos, total = 0;
> - struct st_sample *src, *dst = sw->resample_buf.buffer;
> + size_t samples, live, ret, swlim, total;
>
> live = hw->total_samples_captured - sw->total_hw_samples_acquired;
> if (!live) {
> @@ -558,33 +590,12 @@ static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t size)
> return 0;
> }
>
> - rpos = audio_ring_posb(hw->conv_buf.pos, live, hw->conv_buf.size);
> -
> samples = size / sw->info.bytes_per_frame;
>
> swlim = (live * sw->ratio) >> 32;
> swlim = MIN (swlim, samples);
>
> - while (swlim) {
> - src = hw->conv_buf.buffer + rpos;
> - if (hw->conv_buf.pos > rpos) {
> - isamp = hw->conv_buf.pos - rpos;
> - } else {
> - isamp = hw->conv_buf.size - rpos;
> - }
> -
> - if (!isamp) {
> - break;
> - }
> - osamp = swlim;
> -
> - st_rate_flow (sw->rate, src, dst, &isamp, &osamp);
> - swlim -= osamp;
> - rpos = (rpos + isamp) % hw->conv_buf.size;
> - dst += osamp;
> - ret += osamp;
> - total += isamp;
> - }
> + audio_pcm_sw_resample_in(sw, live, swlim, &total, &ret);
>
> if (!hw->pcm_ops->volume_in) {
> mixeng_volume(sw->resample_buf.buffer, ret, &sw->vol);
> --
> 2.35.3
>
--
Marc-André Lureau
^ permalink raw reply [flat|nested] 34+ messages in thread
* [PATCH v2 12/17] audio: rename variables in audio_pcm_sw_read()
2023-02-06 18:47 [PATCH v2 00/17] audio: improve callback interface for audio frontends Volker Rümelin
` (10 preceding siblings ...)
2023-02-06 18:52 ` [PATCH v2 11/17] audio: replace the resampling loop in audio_pcm_sw_read() Volker Rümelin
@ 2023-02-06 18:52 ` Volker Rümelin
2023-02-22 10:50 ` Marc-André Lureau
2023-02-06 18:52 ` [PATCH v2 13/17] audio/mixeng: calculate number of output frames Volker Rümelin
` (4 subsequent siblings)
16 siblings, 1 reply; 34+ messages in thread
From: Volker Rümelin @ 2023-02-06 18:52 UTC (permalink / raw)
To: Gerd Hoffmann, Marc-André Lureau
Cc: qemu-devel, Christian Schoenebeck, Mark Cave-Ayland
The audio_pcm_sw_read() function uses a few very unspecific
variable names. Rename them for better readability.
ret => total_out
total => total_in
size => buf_len
samples => frames_out_max
Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
---
audio/audio.c | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/audio/audio.c b/audio/audio.c
index 9e9c03a42e..22c36d6660 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -576,10 +576,10 @@ static void audio_pcm_sw_resample_in(SWVoiceIn *sw,
}
}
-static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t size)
+static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t buf_len)
{
HWVoiceIn *hw = sw->hw;
- size_t samples, live, ret, swlim, total;
+ size_t live, frames_out_max, swlim, total_in, total_out;
live = hw->total_samples_captured - sw->total_hw_samples_acquired;
if (!live) {
@@ -590,20 +590,20 @@ static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t size)
return 0;
}
- samples = size / sw->info.bytes_per_frame;
+ frames_out_max = buf_len / sw->info.bytes_per_frame;
swlim = (live * sw->ratio) >> 32;
- swlim = MIN (swlim, samples);
+ swlim = MIN(swlim, frames_out_max);
- audio_pcm_sw_resample_in(sw, live, swlim, &total, &ret);
+ audio_pcm_sw_resample_in(sw, live, swlim, &total_in, &total_out);
if (!hw->pcm_ops->volume_in) {
- mixeng_volume(sw->resample_buf.buffer, ret, &sw->vol);
+ mixeng_volume(sw->resample_buf.buffer, total_out, &sw->vol);
}
+ sw->clip(buf, sw->resample_buf.buffer, total_out);
- sw->clip(buf, sw->resample_buf.buffer, ret);
- sw->total_hw_samples_acquired += total;
- return ret * sw->info.bytes_per_frame;
+ sw->total_hw_samples_acquired += total_in;
+ return total_out * sw->info.bytes_per_frame;
}
/*
--
2.35.3
^ permalink raw reply related [flat|nested] 34+ messages in thread
* Re: [PATCH v2 12/17] audio: rename variables in audio_pcm_sw_read()
2023-02-06 18:52 ` [PATCH v2 12/17] audio: rename variables " Volker Rümelin
@ 2023-02-22 10:50 ` Marc-André Lureau
0 siblings, 0 replies; 34+ messages in thread
From: Marc-André Lureau @ 2023-02-22 10:50 UTC (permalink / raw)
To: Volker Rümelin
Cc: Gerd Hoffmann, qemu-devel, Christian Schoenebeck,
Mark Cave-Ayland
On Mon, Feb 6, 2023 at 10:53 PM Volker Rümelin <vr_qemu@t-online.de> wrote:
>
> The audio_pcm_sw_read() function uses a few very unspecific
> variable names. Rename them for better readability.
>
> ret => total_out
> total => total_in
> size => buf_len
> samples => frames_out_max
>
> Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
> audio/audio.c | 18 +++++++++---------
> 1 file changed, 9 insertions(+), 9 deletions(-)
>
> diff --git a/audio/audio.c b/audio/audio.c
> index 9e9c03a42e..22c36d6660 100644
> --- a/audio/audio.c
> +++ b/audio/audio.c
> @@ -576,10 +576,10 @@ static void audio_pcm_sw_resample_in(SWVoiceIn *sw,
> }
> }
>
> -static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t size)
> +static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t buf_len)
> {
> HWVoiceIn *hw = sw->hw;
> - size_t samples, live, ret, swlim, total;
> + size_t live, frames_out_max, swlim, total_in, total_out;
>
> live = hw->total_samples_captured - sw->total_hw_samples_acquired;
> if (!live) {
> @@ -590,20 +590,20 @@ static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t size)
> return 0;
> }
>
> - samples = size / sw->info.bytes_per_frame;
> + frames_out_max = buf_len / sw->info.bytes_per_frame;
>
> swlim = (live * sw->ratio) >> 32;
> - swlim = MIN (swlim, samples);
> + swlim = MIN(swlim, frames_out_max);
>
> - audio_pcm_sw_resample_in(sw, live, swlim, &total, &ret);
> + audio_pcm_sw_resample_in(sw, live, swlim, &total_in, &total_out);
>
> if (!hw->pcm_ops->volume_in) {
> - mixeng_volume(sw->resample_buf.buffer, ret, &sw->vol);
> + mixeng_volume(sw->resample_buf.buffer, total_out, &sw->vol);
> }
> + sw->clip(buf, sw->resample_buf.buffer, total_out);
>
> - sw->clip(buf, sw->resample_buf.buffer, ret);
> - sw->total_hw_samples_acquired += total;
> - return ret * sw->info.bytes_per_frame;
> + sw->total_hw_samples_acquired += total_in;
> + return total_out * sw->info.bytes_per_frame;
> }
>
> /*
> --
> 2.35.3
>
--
Marc-André Lureau
^ permalink raw reply [flat|nested] 34+ messages in thread
* [PATCH v2 13/17] audio/mixeng: calculate number of output frames
2023-02-06 18:47 [PATCH v2 00/17] audio: improve callback interface for audio frontends Volker Rümelin
` (11 preceding siblings ...)
2023-02-06 18:52 ` [PATCH v2 12/17] audio: rename variables " Volker Rümelin
@ 2023-02-06 18:52 ` Volker Rümelin
2023-02-06 18:52 ` [PATCH v2 14/17] audio: wire up st_rate_frames_out() Volker Rümelin
` (3 subsequent siblings)
16 siblings, 0 replies; 34+ messages in thread
From: Volker Rümelin @ 2023-02-06 18:52 UTC (permalink / raw)
To: Gerd Hoffmann, Marc-André Lureau
Cc: qemu-devel, Christian Schoenebeck, Mark Cave-Ayland
Calculate the exact number of audio output frames the resampling
code can generate from a given number of audio input frames.
When upsampling, this function returns the maximum number of
output frames.
This function will later replace the audio_frontend_frames_in()
function, which calculates the average number of output frames
rounded down to the nearest integer.
Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
---
audio/mixeng.c | 37 +++++++++++++++++++++++++++++++++++++
audio/mixeng.h | 1 +
2 files changed, 38 insertions(+)
diff --git a/audio/mixeng.c b/audio/mixeng.c
index 6bb3d54f77..92a3a1ac58 100644
--- a/audio/mixeng.c
+++ b/audio/mixeng.c
@@ -440,6 +440,43 @@ void st_rate_stop (void *opaque)
g_free (opaque);
}
+/**
+ * st_rate_frames_out() - returns the number of frames the resampling code
+ * generates from frames_in frames
+ *
+ * @opaque: pointer to struct rate
+ * @frames_in: number of frames
+ */
+uint32_t st_rate_frames_out(void *opaque, uint32_t frames_in)
+{
+ struct rate *rate = opaque;
+ uint64_t opos_end, opos_delta;
+ uint32_t ipos_end;
+ uint32_t frames_out;
+
+ if (rate->opos_inc == 1ULL << 32) {
+ return frames_in;
+ }
+
+ /* no output frame without at least one input frame */
+ if (!frames_in) {
+ return 0;
+ }
+
+ /* last frame read was at rate->ipos - 1 */
+ ipos_end = rate->ipos - 1 + frames_in;
+ opos_end = (uint64_t)ipos_end << 32;
+
+ /* last frame written was at rate->opos - rate->opos_inc */
+ if (opos_end + rate->opos_inc <= rate->opos) {
+ return 0;
+ }
+ opos_delta = opos_end - rate->opos + rate->opos_inc;
+ frames_out = opos_delta / rate->opos_inc;
+
+ return opos_delta % rate->opos_inc ? frames_out : frames_out - 1;
+}
+
/**
* st_rate_frames_in() - returns the number of frames needed to
* get frames_out frames after resampling
diff --git a/audio/mixeng.h b/audio/mixeng.h
index 64c1e231cc..f9de7cffeb 100644
--- a/audio/mixeng.h
+++ b/audio/mixeng.h
@@ -52,6 +52,7 @@ void st_rate_flow(void *opaque, st_sample *ibuf, st_sample *obuf,
void st_rate_flow_mix(void *opaque, st_sample *ibuf, st_sample *obuf,
size_t *isamp, size_t *osamp);
void st_rate_stop (void *opaque);
+uint32_t st_rate_frames_out(void *opaque, uint32_t frames_in);
uint32_t st_rate_frames_in(void *opaque, uint32_t frames_out);
void mixeng_clear (struct st_sample *buf, int len);
void mixeng_volume (struct st_sample *buf, int len, struct mixeng_volume *vol);
--
2.35.3
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH v2 14/17] audio: wire up st_rate_frames_out()
2023-02-06 18:47 [PATCH v2 00/17] audio: improve callback interface for audio frontends Volker Rümelin
` (12 preceding siblings ...)
2023-02-06 18:52 ` [PATCH v2 13/17] audio/mixeng: calculate number of output frames Volker Rümelin
@ 2023-02-06 18:52 ` Volker Rümelin
2023-02-22 10:50 ` Marc-André Lureau
2023-02-06 18:52 ` [PATCH v2 15/17] audio: handle leftover audio frame from upsampling Volker Rümelin
` (2 subsequent siblings)
16 siblings, 1 reply; 34+ messages in thread
From: Volker Rümelin @ 2023-02-06 18:52 UTC (permalink / raw)
To: Gerd Hoffmann, Marc-André Lureau
Cc: qemu-devel, Christian Schoenebeck, Mark Cave-Ayland
Wire up the st_rate_frames_out() function and replace
audio_frontend_frames_in() to make audio packet length
calculation exact.
Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
---
audio/audio.c | 29 ++++++++---------------------
1 file changed, 8 insertions(+), 21 deletions(-)
diff --git a/audio/audio.c b/audio/audio.c
index 22c36d6660..dad17e59b8 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -579,7 +579,7 @@ static void audio_pcm_sw_resample_in(SWVoiceIn *sw,
static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t buf_len)
{
HWVoiceIn *hw = sw->hw;
- size_t live, frames_out_max, swlim, total_in, total_out;
+ size_t live, frames_out_max, total_in, total_out;
live = hw->total_samples_captured - sw->total_hw_samples_acquired;
if (!live) {
@@ -590,12 +590,10 @@ static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t buf_len)
return 0;
}
- frames_out_max = buf_len / sw->info.bytes_per_frame;
+ frames_out_max = MIN(buf_len / sw->info.bytes_per_frame,
+ sw->resample_buf.size);
- swlim = (live * sw->ratio) >> 32;
- swlim = MIN(swlim, frames_out_max);
-
- audio_pcm_sw_resample_in(sw, live, swlim, &total_in, &total_out);
+ audio_pcm_sw_resample_in(sw, live, frames_out_max, &total_in, &total_out);
if (!hw->pcm_ops->volume_in) {
mixeng_volume(sw->resample_buf.buffer, total_out, &sw->vol);
@@ -979,18 +977,6 @@ void AUD_set_active_in (SWVoiceIn *sw, int on)
}
}
-/**
- * audio_frontend_frames_in() - returns the number of frames the resampling
- * code generates from frames_in frames
- *
- * @sw: audio recording frontend
- * @frames_in: number of frames
- */
-static size_t audio_frontend_frames_in(SWVoiceIn *sw, size_t frames_in)
-{
- return (int64_t)frames_in * sw->ratio >> 32;
-}
-
static size_t audio_get_avail (SWVoiceIn *sw)
{
size_t live;
@@ -1007,9 +993,9 @@ static size_t audio_get_avail (SWVoiceIn *sw)
}
ldebug (
- "%s: get_avail live %zu frontend frames %zu\n",
+ "%s: get_avail live %zu frontend frames %u\n",
SW_NAME (sw),
- live, audio_frontend_frames_in(sw, live)
+ live, st_rate_frames_out(sw->rate, live)
);
return live;
@@ -1314,8 +1300,9 @@ static void audio_run_in (AudioState *s)
size_t sw_avail = audio_get_avail(sw);
size_t avail;
- avail = audio_frontend_frames_in(sw, sw_avail);
+ avail = st_rate_frames_out(sw->rate, sw_avail);
if (avail > 0) {
+ avail = MIN(avail, sw->resample_buf.size);
sw->callback.fn(sw->callback.opaque,
avail * sw->info.bytes_per_frame);
}
--
2.35.3
^ permalink raw reply related [flat|nested] 34+ messages in thread
* Re: [PATCH v2 14/17] audio: wire up st_rate_frames_out()
2023-02-06 18:52 ` [PATCH v2 14/17] audio: wire up st_rate_frames_out() Volker Rümelin
@ 2023-02-22 10:50 ` Marc-André Lureau
0 siblings, 0 replies; 34+ messages in thread
From: Marc-André Lureau @ 2023-02-22 10:50 UTC (permalink / raw)
To: Volker Rümelin
Cc: Gerd Hoffmann, qemu-devel, Christian Schoenebeck,
Mark Cave-Ayland
Hi
On Mon, Feb 6, 2023 at 10:53 PM Volker Rümelin <vr_qemu@t-online.de> wrote:
>
> Wire up the st_rate_frames_out() function and replace
> audio_frontend_frames_in() to make audio packet length
> calculation exact.
>
> Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
Same comments as st_rate_frames_in patches.
> ---
> audio/audio.c | 29 ++++++++---------------------
> 1 file changed, 8 insertions(+), 21 deletions(-)
>
> diff --git a/audio/audio.c b/audio/audio.c
> index 22c36d6660..dad17e59b8 100644
> --- a/audio/audio.c
> +++ b/audio/audio.c
> @@ -579,7 +579,7 @@ static void audio_pcm_sw_resample_in(SWVoiceIn *sw,
> static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t buf_len)
> {
> HWVoiceIn *hw = sw->hw;
> - size_t live, frames_out_max, swlim, total_in, total_out;
> + size_t live, frames_out_max, total_in, total_out;
>
> live = hw->total_samples_captured - sw->total_hw_samples_acquired;
> if (!live) {
> @@ -590,12 +590,10 @@ static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t buf_len)
> return 0;
> }
>
> - frames_out_max = buf_len / sw->info.bytes_per_frame;
> + frames_out_max = MIN(buf_len / sw->info.bytes_per_frame,
> + sw->resample_buf.size);
>
> - swlim = (live * sw->ratio) >> 32;
> - swlim = MIN(swlim, frames_out_max);
> -
> - audio_pcm_sw_resample_in(sw, live, swlim, &total_in, &total_out);
> + audio_pcm_sw_resample_in(sw, live, frames_out_max, &total_in, &total_out);
>
> if (!hw->pcm_ops->volume_in) {
> mixeng_volume(sw->resample_buf.buffer, total_out, &sw->vol);
> @@ -979,18 +977,6 @@ void AUD_set_active_in (SWVoiceIn *sw, int on)
> }
> }
>
> -/**
> - * audio_frontend_frames_in() - returns the number of frames the resampling
> - * code generates from frames_in frames
> - *
> - * @sw: audio recording frontend
> - * @frames_in: number of frames
> - */
> -static size_t audio_frontend_frames_in(SWVoiceIn *sw, size_t frames_in)
> -{
> - return (int64_t)frames_in * sw->ratio >> 32;
> -}
> -
> static size_t audio_get_avail (SWVoiceIn *sw)
> {
> size_t live;
> @@ -1007,9 +993,9 @@ static size_t audio_get_avail (SWVoiceIn *sw)
> }
>
> ldebug (
> - "%s: get_avail live %zu frontend frames %zu\n",
> + "%s: get_avail live %zu frontend frames %u\n",
> SW_NAME (sw),
> - live, audio_frontend_frames_in(sw, live)
> + live, st_rate_frames_out(sw->rate, live)
> );
>
> return live;
> @@ -1314,8 +1300,9 @@ static void audio_run_in (AudioState *s)
> size_t sw_avail = audio_get_avail(sw);
> size_t avail;
>
> - avail = audio_frontend_frames_in(sw, sw_avail);
> + avail = st_rate_frames_out(sw->rate, sw_avail);
> if (avail > 0) {
> + avail = MIN(avail, sw->resample_buf.size);
> sw->callback.fn(sw->callback.opaque,
> avail * sw->info.bytes_per_frame);
> }
> --
> 2.35.3
>
--
Marc-André Lureau
^ permalink raw reply [flat|nested] 34+ messages in thread
* [PATCH v2 15/17] audio: handle leftover audio frame from upsampling
2023-02-06 18:47 [PATCH v2 00/17] audio: improve callback interface for audio frontends Volker Rümelin
` (13 preceding siblings ...)
2023-02-06 18:52 ` [PATCH v2 14/17] audio: wire up st_rate_frames_out() Volker Rümelin
@ 2023-02-06 18:52 ` Volker Rümelin
2023-02-22 10:50 ` Marc-André Lureau
2023-02-06 18:52 ` [PATCH v2 16/17] audio/audio_template: substitute sw->hw with hw Volker Rümelin
2023-02-06 18:52 ` [PATCH v2 17/17] audio: remove sw->ratio Volker Rümelin
16 siblings, 1 reply; 34+ messages in thread
From: Volker Rümelin @ 2023-02-06 18:52 UTC (permalink / raw)
To: Gerd Hoffmann, Marc-André Lureau
Cc: qemu-devel, Christian Schoenebeck, Mark Cave-Ayland
Upsampling may leave one remaining audio frame in the input
buffer. The emulated audio playback devices are currently
resposible to write this audio frame again in the next write
cycle. Push that task down to audio_pcm_sw_write.
This is another step towards an audio callback interface that
guarantees that when audio frontends are told they can write
n audio frames, they can actually do so.
Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
---
audio/audio.c | 34 ++++++++++++++++++++++++++++------
audio/audio_template.h | 6 ++++++
2 files changed, 34 insertions(+), 6 deletions(-)
diff --git a/audio/audio.c b/audio/audio.c
index dad17e59b8..4836ab8ca8 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -731,16 +731,21 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t buf_len)
hw_free = hw_free > live ? hw_free - live : 0;
frames_out_max = MIN(dead, hw_free);
sw_max = st_rate_frames_in(sw->rate, frames_out_max);
- fe_max = MIN(buf_len / sw->info.bytes_per_frame, sw->resample_buf.size);
+ fe_max = MIN(buf_len / sw->info.bytes_per_frame + sw->resample_buf.pos,
+ sw->resample_buf.size);
frames_in_max = MIN(sw_max, fe_max);
if (!frames_in_max) {
return 0;
}
- sw->conv(sw->resample_buf.buffer, buf, frames_in_max);
- if (!sw->hw->pcm_ops->volume_out) {
- mixeng_volume(sw->resample_buf.buffer, frames_in_max, &sw->vol);
+ if (frames_in_max > sw->resample_buf.pos) {
+ sw->conv(sw->resample_buf.buffer + sw->resample_buf.pos,
+ buf, frames_in_max - sw->resample_buf.pos);
+ if (!sw->hw->pcm_ops->volume_out) {
+ mixeng_volume(sw->resample_buf.buffer + sw->resample_buf.pos,
+ frames_in_max - sw->resample_buf.pos, &sw->vol);
+ }
}
audio_pcm_sw_resample_out(sw, frames_in_max, frames_out_max,
@@ -749,6 +754,22 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t buf_len)
sw->total_hw_samples_mixed += total_out;
sw->empty = sw->total_hw_samples_mixed == 0;
+ /*
+ * Upsampling may leave one audio frame in the resample buffer. Decrement
+ * total_in by one if there was a leftover frame from the previous resample
+ * pass in the resample buffer. Increment total_in by one if the current
+ * resample pass left one frame in the resample buffer.
+ */
+ if (frames_in_max - total_in == 1) {
+ /* copy one leftover audio frame to the beginning of the buffer */
+ *sw->resample_buf.buffer = *(sw->resample_buf.buffer + total_in);
+ total_in += 1 - sw->resample_buf.pos;
+ sw->resample_buf.pos = 1;
+ } else if (total_in >= sw->resample_buf.pos) {
+ total_in -= sw->resample_buf.pos;
+ sw->resample_buf.pos = 0;
+ }
+
#ifdef DEBUG_OUT
dolog (
"%s: write size %zu written %zu total mixed %zu\n",
@@ -1155,8 +1176,9 @@ static void audio_run_out (AudioState *s)
} else {
free = 0;
}
- if (free > 0) {
- free = MIN(free, sw->resample_buf.size);
+ if (free > sw->resample_buf.pos) {
+ free = MIN(free, sw->resample_buf.size)
+ - sw->resample_buf.pos;
sw->callback.fn(sw->callback.opaque,
free * sw->info.bytes_per_frame);
}
diff --git a/audio/audio_template.h b/audio/audio_template.h
index a0b653f52c..0d8aab6fad 100644
--- a/audio/audio_template.h
+++ b/audio/audio_template.h
@@ -138,6 +138,12 @@ static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
return -1;
}
+ /*
+ * Allocate one additional audio frame that is needed for upsampling
+ * if the resample buffer size is small. For large buffer sizes take
+ * care of overflows.
+ */
+ samples = samples < INT_MAX ? samples + 1 : INT_MAX;
sw->resample_buf.buffer = g_new0(st_sample, samples);
sw->resample_buf.size = samples;
sw->resample_buf.pos = 0;
--
2.35.3
^ permalink raw reply related [flat|nested] 34+ messages in thread
* Re: [PATCH v2 15/17] audio: handle leftover audio frame from upsampling
2023-02-06 18:52 ` [PATCH v2 15/17] audio: handle leftover audio frame from upsampling Volker Rümelin
@ 2023-02-22 10:50 ` Marc-André Lureau
0 siblings, 0 replies; 34+ messages in thread
From: Marc-André Lureau @ 2023-02-22 10:50 UTC (permalink / raw)
To: Volker Rümelin
Cc: Gerd Hoffmann, qemu-devel, Christian Schoenebeck,
Mark Cave-Ayland
On Mon, Feb 6, 2023 at 10:53 PM Volker Rümelin <vr_qemu@t-online.de> wrote:
>
> Upsampling may leave one remaining audio frame in the input
> buffer. The emulated audio playback devices are currently
> resposible to write this audio frame again in the next write
> cycle. Push that task down to audio_pcm_sw_write.
>
> This is another step towards an audio callback interface that
> guarantees that when audio frontends are told they can write
> n audio frames, they can actually do so.
>
> Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
Acked-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
> audio/audio.c | 34 ++++++++++++++++++++++++++++------
> audio/audio_template.h | 6 ++++++
> 2 files changed, 34 insertions(+), 6 deletions(-)
>
> diff --git a/audio/audio.c b/audio/audio.c
> index dad17e59b8..4836ab8ca8 100644
> --- a/audio/audio.c
> +++ b/audio/audio.c
> @@ -731,16 +731,21 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t buf_len)
> hw_free = hw_free > live ? hw_free - live : 0;
> frames_out_max = MIN(dead, hw_free);
> sw_max = st_rate_frames_in(sw->rate, frames_out_max);
> - fe_max = MIN(buf_len / sw->info.bytes_per_frame, sw->resample_buf.size);
> + fe_max = MIN(buf_len / sw->info.bytes_per_frame + sw->resample_buf.pos,
> + sw->resample_buf.size);
> frames_in_max = MIN(sw_max, fe_max);
>
> if (!frames_in_max) {
> return 0;
> }
>
> - sw->conv(sw->resample_buf.buffer, buf, frames_in_max);
> - if (!sw->hw->pcm_ops->volume_out) {
> - mixeng_volume(sw->resample_buf.buffer, frames_in_max, &sw->vol);
> + if (frames_in_max > sw->resample_buf.pos) {
> + sw->conv(sw->resample_buf.buffer + sw->resample_buf.pos,
> + buf, frames_in_max - sw->resample_buf.pos);
> + if (!sw->hw->pcm_ops->volume_out) {
> + mixeng_volume(sw->resample_buf.buffer + sw->resample_buf.pos,
> + frames_in_max - sw->resample_buf.pos, &sw->vol);
> + }
> }
>
> audio_pcm_sw_resample_out(sw, frames_in_max, frames_out_max,
> @@ -749,6 +754,22 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t buf_len)
> sw->total_hw_samples_mixed += total_out;
> sw->empty = sw->total_hw_samples_mixed == 0;
>
> + /*
> + * Upsampling may leave one audio frame in the resample buffer. Decrement
> + * total_in by one if there was a leftover frame from the previous resample
> + * pass in the resample buffer. Increment total_in by one if the current
> + * resample pass left one frame in the resample buffer.
> + */
> + if (frames_in_max - total_in == 1) {
> + /* copy one leftover audio frame to the beginning of the buffer */
> + *sw->resample_buf.buffer = *(sw->resample_buf.buffer + total_in);
> + total_in += 1 - sw->resample_buf.pos;
> + sw->resample_buf.pos = 1;
> + } else if (total_in >= sw->resample_buf.pos) {
> + total_in -= sw->resample_buf.pos;
> + sw->resample_buf.pos = 0;
> + }
> +
> #ifdef DEBUG_OUT
> dolog (
> "%s: write size %zu written %zu total mixed %zu\n",
> @@ -1155,8 +1176,9 @@ static void audio_run_out (AudioState *s)
> } else {
> free = 0;
> }
> - if (free > 0) {
> - free = MIN(free, sw->resample_buf.size);
> + if (free > sw->resample_buf.pos) {
> + free = MIN(free, sw->resample_buf.size)
> + - sw->resample_buf.pos;
> sw->callback.fn(sw->callback.opaque,
> free * sw->info.bytes_per_frame);
> }
> diff --git a/audio/audio_template.h b/audio/audio_template.h
> index a0b653f52c..0d8aab6fad 100644
> --- a/audio/audio_template.h
> +++ b/audio/audio_template.h
> @@ -138,6 +138,12 @@ static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
> return -1;
> }
>
> + /*
> + * Allocate one additional audio frame that is needed for upsampling
> + * if the resample buffer size is small. For large buffer sizes take
> + * care of overflows.
> + */
> + samples = samples < INT_MAX ? samples + 1 : INT_MAX;
> sw->resample_buf.buffer = g_new0(st_sample, samples);
> sw->resample_buf.size = samples;
> sw->resample_buf.pos = 0;
> --
> 2.35.3
>
--
Marc-André Lureau
^ permalink raw reply [flat|nested] 34+ messages in thread
* [PATCH v2 16/17] audio/audio_template: substitute sw->hw with hw
2023-02-06 18:47 [PATCH v2 00/17] audio: improve callback interface for audio frontends Volker Rümelin
` (14 preceding siblings ...)
2023-02-06 18:52 ` [PATCH v2 15/17] audio: handle leftover audio frame from upsampling Volker Rümelin
@ 2023-02-06 18:52 ` Volker Rümelin
2023-02-22 10:50 ` Marc-André Lureau
2023-02-06 18:52 ` [PATCH v2 17/17] audio: remove sw->ratio Volker Rümelin
16 siblings, 1 reply; 34+ messages in thread
From: Volker Rümelin @ 2023-02-06 18:52 UTC (permalink / raw)
To: Gerd Hoffmann, Marc-André Lureau
Cc: qemu-devel, Christian Schoenebeck, Mark Cave-Ayland
Substitute sw->hw with hw in the audio_pcm_sw_alloc_resources_*
functions.
Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
---
audio/audio_template.h | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/audio/audio_template.h b/audio/audio_template.h
index 0d8aab6fad..7e116426c7 100644
--- a/audio/audio_template.h
+++ b/audio/audio_template.h
@@ -107,6 +107,7 @@ static void glue (audio_pcm_sw_free_resources_, TYPE) (SW *sw)
static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
{
+ HW *hw = sw->hw;
int samples;
if (!glue(audio_get_pdo_, TYPE)(sw->s->dev)->mixing_engine) {
@@ -125,7 +126,6 @@ static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
}
if (samples == 0) {
- HW *hw = sw->hw;
size_t f_fe_min;
/* f_fe_min = ceil(1 [frames] * f_be [Hz] / size_be [frames]) */
@@ -149,9 +149,9 @@ static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
sw->resample_buf.pos = 0;
#ifdef DAC
- sw->rate = st_rate_start (sw->info.freq, sw->hw->info.freq);
+ sw->rate = st_rate_start(sw->info.freq, hw->info.freq);
#else
- sw->rate = st_rate_start (sw->hw->info.freq, sw->info.freq);
+ sw->rate = st_rate_start(hw->info.freq, sw->info.freq);
#endif
return 0;
--
2.35.3
^ permalink raw reply related [flat|nested] 34+ messages in thread
* Re: [PATCH v2 16/17] audio/audio_template: substitute sw->hw with hw
2023-02-06 18:52 ` [PATCH v2 16/17] audio/audio_template: substitute sw->hw with hw Volker Rümelin
@ 2023-02-22 10:50 ` Marc-André Lureau
0 siblings, 0 replies; 34+ messages in thread
From: Marc-André Lureau @ 2023-02-22 10:50 UTC (permalink / raw)
To: Volker Rümelin
Cc: Gerd Hoffmann, qemu-devel, Christian Schoenebeck,
Mark Cave-Ayland
On Mon, Feb 6, 2023 at 10:53 PM Volker Rümelin <vr_qemu@t-online.de> wrote:
>
> Substitute sw->hw with hw in the audio_pcm_sw_alloc_resources_*
> functions.
>
> Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
> audio/audio_template.h | 6 +++---
> 1 file changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/audio/audio_template.h b/audio/audio_template.h
> index 0d8aab6fad..7e116426c7 100644
> --- a/audio/audio_template.h
> +++ b/audio/audio_template.h
> @@ -107,6 +107,7 @@ static void glue (audio_pcm_sw_free_resources_, TYPE) (SW *sw)
>
> static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
> {
> + HW *hw = sw->hw;
> int samples;
>
> if (!glue(audio_get_pdo_, TYPE)(sw->s->dev)->mixing_engine) {
> @@ -125,7 +126,6 @@ static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
> }
>
> if (samples == 0) {
> - HW *hw = sw->hw;
> size_t f_fe_min;
>
> /* f_fe_min = ceil(1 [frames] * f_be [Hz] / size_be [frames]) */
> @@ -149,9 +149,9 @@ static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
> sw->resample_buf.pos = 0;
>
> #ifdef DAC
> - sw->rate = st_rate_start (sw->info.freq, sw->hw->info.freq);
> + sw->rate = st_rate_start(sw->info.freq, hw->info.freq);
> #else
> - sw->rate = st_rate_start (sw->hw->info.freq, sw->info.freq);
> + sw->rate = st_rate_start(hw->info.freq, sw->info.freq);
> #endif
>
> return 0;
> --
> 2.35.3
>
--
Marc-André Lureau
^ permalink raw reply [flat|nested] 34+ messages in thread
* [PATCH v2 17/17] audio: remove sw->ratio
2023-02-06 18:47 [PATCH v2 00/17] audio: improve callback interface for audio frontends Volker Rümelin
` (15 preceding siblings ...)
2023-02-06 18:52 ` [PATCH v2 16/17] audio/audio_template: substitute sw->hw with hw Volker Rümelin
@ 2023-02-06 18:52 ` Volker Rümelin
2023-02-22 10:50 ` Marc-André Lureau
16 siblings, 1 reply; 34+ messages in thread
From: Volker Rümelin @ 2023-02-06 18:52 UTC (permalink / raw)
To: Gerd Hoffmann, Marc-André Lureau
Cc: qemu-devel, Christian Schoenebeck, Mark Cave-Ayland
Simplify the resample buffer size calculation.
For audio playback we have
sw->ratio = ((int64_t)sw->hw->info.freq << 32) / sw->info.freq;
samples = ((int64_t)sw->HWBUF.size << 32) / sw->ratio;
This can be simplified to
samples = muldiv64(sw->HWBUF.size, sw->info.freq, sw->hw->info.freq);
For audio recording we have
sw->ratio = ((int64_t)sw->info.freq << 32) / sw->hw->info.freq;
samples = (int64_t)sw->HWBUF.size * sw->ratio >> 32;
This can be simplified to
samples = muldiv64(sw->HWBUF.size, sw->info.freq, sw->hw->info.freq);
With hw = sw->hw this becomes in both cases
samples = muldiv64(HWBUF.size, sw->info.freq, hw->info.freq);
Now that sw->ratio is no longer needed, remove sw->ratio.
Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
---
audio/audio.c | 1 -
audio/audio_int.h | 2 --
audio/audio_template.h | 30 +++++++++---------------------
3 files changed, 9 insertions(+), 24 deletions(-)
diff --git a/audio/audio.c b/audio/audio.c
index 4836ab8ca8..70b096713c 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -478,7 +478,6 @@ static int audio_attach_capture (HWVoiceOut *hw)
sw->info = hw->info;
sw->empty = 1;
sw->active = hw->enabled;
- sw->ratio = ((int64_t) hw_cap->info.freq << 32) / sw->info.freq;
sw->vol = nominal_volume;
sw->rate = st_rate_start (sw->info.freq, hw_cap->info.freq);
QLIST_INSERT_HEAD (&hw_cap->sw_head, sw, entries);
diff --git a/audio/audio_int.h b/audio/audio_int.h
index 8b163e1759..d51d63f08d 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -108,7 +108,6 @@ struct SWVoiceOut {
AudioState *s;
struct audio_pcm_info info;
t_sample *conv;
- int64_t ratio;
STSampleBuffer resample_buf;
void *rate;
size_t total_hw_samples_mixed;
@@ -126,7 +125,6 @@ struct SWVoiceIn {
AudioState *s;
int active;
struct audio_pcm_info info;
- int64_t ratio;
void *rate;
size_t total_hw_samples_acquired;
STSampleBuffer resample_buf;
diff --git a/audio/audio_template.h b/audio/audio_template.h
index 7e116426c7..e42326c20d 100644
--- a/audio/audio_template.h
+++ b/audio/audio_template.h
@@ -108,32 +108,23 @@ static void glue (audio_pcm_sw_free_resources_, TYPE) (SW *sw)
static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
{
HW *hw = sw->hw;
- int samples;
+ uint64_t samples;
if (!glue(audio_get_pdo_, TYPE)(sw->s->dev)->mixing_engine) {
return 0;
}
-#ifdef DAC
- samples = ((int64_t)sw->HWBUF.size << 32) / sw->ratio;
-#else
- samples = (int64_t)sw->HWBUF.size * sw->ratio >> 32;
-#endif
- if (audio_bug(__func__, samples < 0)) {
- dolog("Can not allocate buffer for `%s' (%d samples)\n",
- SW_NAME(sw), samples);
- return -1;
- }
-
+ samples = muldiv64(HWBUF.size, sw->info.freq, hw->info.freq);
if (samples == 0) {
- size_t f_fe_min;
+ uint64_t f_fe_min;
+ uint64_t f_be = (uint32_t)hw->info.freq;
/* f_fe_min = ceil(1 [frames] * f_be [Hz] / size_be [frames]) */
- f_fe_min = (hw->info.freq + HWBUF.size - 1) / HWBUF.size;
+ f_fe_min = (f_be + HWBUF.size - 1) / HWBUF.size;
qemu_log_mask(LOG_UNIMP,
AUDIO_CAP ": The guest selected a " NAME " sample rate"
- " of %d Hz for %s. Only sample rates >= %zu Hz are"
- " supported.\n",
+ " of %d Hz for %s. Only sample rates >= %" PRIu64 " Hz"
+ " are supported.\n",
sw->info.freq, sw->name, f_fe_min);
return -1;
}
@@ -141,9 +132,9 @@ static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
/*
* Allocate one additional audio frame that is needed for upsampling
* if the resample buffer size is small. For large buffer sizes take
- * care of overflows.
+ * care of overflows and truncation.
*/
- samples = samples < INT_MAX ? samples + 1 : INT_MAX;
+ samples = samples < SIZE_MAX ? samples + 1 : SIZE_MAX;
sw->resample_buf.buffer = g_new0(st_sample, samples);
sw->resample_buf.size = samples;
sw->resample_buf.pos = 0;
@@ -170,11 +161,8 @@ static int glue (audio_pcm_sw_init_, TYPE) (
sw->hw = hw;
sw->active = 0;
#ifdef DAC
- sw->ratio = ((int64_t) sw->hw->info.freq << 32) / sw->info.freq;
sw->total_hw_samples_mixed = 0;
sw->empty = 1;
-#else
- sw->ratio = ((int64_t) sw->info.freq << 32) / sw->hw->info.freq;
#endif
if (sw->info.is_float) {
--
2.35.3
^ permalink raw reply related [flat|nested] 34+ messages in thread
* Re: [PATCH v2 17/17] audio: remove sw->ratio
2023-02-06 18:52 ` [PATCH v2 17/17] audio: remove sw->ratio Volker Rümelin
@ 2023-02-22 10:50 ` Marc-André Lureau
0 siblings, 0 replies; 34+ messages in thread
From: Marc-André Lureau @ 2023-02-22 10:50 UTC (permalink / raw)
To: Volker Rümelin
Cc: Gerd Hoffmann, qemu-devel, Christian Schoenebeck,
Mark Cave-Ayland
On Mon, Feb 6, 2023 at 10:53 PM Volker Rümelin <vr_qemu@t-online.de> wrote:
>
> Simplify the resample buffer size calculation.
>
> For audio playback we have
> sw->ratio = ((int64_t)sw->hw->info.freq << 32) / sw->info.freq;
> samples = ((int64_t)sw->HWBUF.size << 32) / sw->ratio;
>
> This can be simplified to
> samples = muldiv64(sw->HWBUF.size, sw->info.freq, sw->hw->info.freq);
>
> For audio recording we have
> sw->ratio = ((int64_t)sw->info.freq << 32) / sw->hw->info.freq;
> samples = (int64_t)sw->HWBUF.size * sw->ratio >> 32;
>
> This can be simplified to
> samples = muldiv64(sw->HWBUF.size, sw->info.freq, sw->hw->info.freq);
>
> With hw = sw->hw this becomes in both cases
> samples = muldiv64(HWBUF.size, sw->info.freq, hw->info.freq);
>
> Now that sw->ratio is no longer needed, remove sw->ratio.
>
> Acked-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
> audio/audio.c | 1 -
> audio/audio_int.h | 2 --
> audio/audio_template.h | 30 +++++++++---------------------
> 3 files changed, 9 insertions(+), 24 deletions(-)
>
> diff --git a/audio/audio.c b/audio/audio.c
> index 4836ab8ca8..70b096713c 100644
> --- a/audio/audio.c
> +++ b/audio/audio.c
> @@ -478,7 +478,6 @@ static int audio_attach_capture (HWVoiceOut *hw)
> sw->info = hw->info;
> sw->empty = 1;
> sw->active = hw->enabled;
> - sw->ratio = ((int64_t) hw_cap->info.freq << 32) / sw->info.freq;
> sw->vol = nominal_volume;
> sw->rate = st_rate_start (sw->info.freq, hw_cap->info.freq);
> QLIST_INSERT_HEAD (&hw_cap->sw_head, sw, entries);
> diff --git a/audio/audio_int.h b/audio/audio_int.h
> index 8b163e1759..d51d63f08d 100644
> --- a/audio/audio_int.h
> +++ b/audio/audio_int.h
> @@ -108,7 +108,6 @@ struct SWVoiceOut {
> AudioState *s;
> struct audio_pcm_info info;
> t_sample *conv;
> - int64_t ratio;
> STSampleBuffer resample_buf;
> void *rate;
> size_t total_hw_samples_mixed;
> @@ -126,7 +125,6 @@ struct SWVoiceIn {
> AudioState *s;
> int active;
> struct audio_pcm_info info;
> - int64_t ratio;
> void *rate;
> size_t total_hw_samples_acquired;
> STSampleBuffer resample_buf;
> diff --git a/audio/audio_template.h b/audio/audio_template.h
> index 7e116426c7..e42326c20d 100644
> --- a/audio/audio_template.h
> +++ b/audio/audio_template.h
> @@ -108,32 +108,23 @@ static void glue (audio_pcm_sw_free_resources_, TYPE) (SW *sw)
> static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
> {
> HW *hw = sw->hw;
> - int samples;
> + uint64_t samples;
>
> if (!glue(audio_get_pdo_, TYPE)(sw->s->dev)->mixing_engine) {
> return 0;
> }
>
> -#ifdef DAC
> - samples = ((int64_t)sw->HWBUF.size << 32) / sw->ratio;
> -#else
> - samples = (int64_t)sw->HWBUF.size * sw->ratio >> 32;
> -#endif
> - if (audio_bug(__func__, samples < 0)) {
> - dolog("Can not allocate buffer for `%s' (%d samples)\n",
> - SW_NAME(sw), samples);
> - return -1;
> - }
> -
> + samples = muldiv64(HWBUF.size, sw->info.freq, hw->info.freq);
> if (samples == 0) {
> - size_t f_fe_min;
> + uint64_t f_fe_min;
> + uint64_t f_be = (uint32_t)hw->info.freq;
>
> /* f_fe_min = ceil(1 [frames] * f_be [Hz] / size_be [frames]) */
> - f_fe_min = (hw->info.freq + HWBUF.size - 1) / HWBUF.size;
> + f_fe_min = (f_be + HWBUF.size - 1) / HWBUF.size;
> qemu_log_mask(LOG_UNIMP,
> AUDIO_CAP ": The guest selected a " NAME " sample rate"
> - " of %d Hz for %s. Only sample rates >= %zu Hz are"
> - " supported.\n",
> + " of %d Hz for %s. Only sample rates >= %" PRIu64 " Hz"
> + " are supported.\n",
> sw->info.freq, sw->name, f_fe_min);
> return -1;
> }
> @@ -141,9 +132,9 @@ static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
> /*
> * Allocate one additional audio frame that is needed for upsampling
> * if the resample buffer size is small. For large buffer sizes take
> - * care of overflows.
> + * care of overflows and truncation.
> */
> - samples = samples < INT_MAX ? samples + 1 : INT_MAX;
> + samples = samples < SIZE_MAX ? samples + 1 : SIZE_MAX;
> sw->resample_buf.buffer = g_new0(st_sample, samples);
> sw->resample_buf.size = samples;
> sw->resample_buf.pos = 0;
> @@ -170,11 +161,8 @@ static int glue (audio_pcm_sw_init_, TYPE) (
> sw->hw = hw;
> sw->active = 0;
> #ifdef DAC
> - sw->ratio = ((int64_t) sw->hw->info.freq << 32) / sw->info.freq;
> sw->total_hw_samples_mixed = 0;
> sw->empty = 1;
> -#else
> - sw->ratio = ((int64_t) sw->info.freq << 32) / sw->hw->info.freq;
> #endif
>
> if (sw->info.is_float) {
> --
> 2.35.3
>
--
Marc-André Lureau
^ permalink raw reply [flat|nested] 34+ messages in thread