On Mon, Feb 6, 2023 at 10:53 PM Volker Rümelin <vr_q...@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-ayl...@ilande.co.uk> > Signed-off-by: Volker Rümelin <vr_q...@t-online.de>
Acked-by: Marc-André Lureau <marcandre.lur...@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