From: "Volker Rümelin" <vr_qemu@t-online.de>
To: Gerd Hoffmann <kraxel@redhat.com>
Cc: qemu-devel@nongnu.org,
"Christian Schoenebeck" <qemu_oss@crudebyte.com>,
"Philippe Mathieu-Daudé" <philmd@linaro.org>,
"Marc-André Lureau" <marcandre.lureau@gmail.com>,
"Mark Cave-Ayland" <mark.cave-ayland@ilande.co.uk>
Subject: Re: [PATCH 00/17] audio: improve callback interface for audio frontends
Date: Sun, 15 Jan 2023 14:45:34 +0100 [thread overview]
Message-ID: <a671751a-cbb7-22c2-8840-0476176d2533@t-online.de> (raw)
In-Reply-To: <61bd351f-0683-7f58-b746-66c9578a7cdc@t-online.de>
Am 15.01.23 um 14:08 schrieb Volker Rümelin:
Ccing a few more people who might be interested in this patch series.
@Mark:
After this patch series, the code in your out of tree ASC audio device
(and a few in tree audio devices) could be simplified. write_audio() and
the loops calling write_audio() could be removed.
With best regards,
Volker
> Based-on: <3b1404eb-a7c5-f64c-3e47-1397c54c45bb@t-online.de>
> ([PATCH 00/11] audio: more improvements)
>
> The callback interface for emulated audio devices is strange. The
> callback function has an 'avail' parameter that passes the number of
> bytes that can be written or read. Unfortunately, this value sometimes
> is only an imprecise estimate and the callback functions must check
> the actual bytes written or read. For playback devices, this means
> that they either need a ring buffer or have to write the unwritten
> bytes again the next time. For recording devices, things are a bit
> easier. They only need to continue with the actual number of bytes read.
>
> After this patch series, the 'avail' argument for the -audiodev
> out.mixing-engine=on and in.mixing-engine=on cases is exact. Audio
> frontends only need a linear frame buffer and there's a guarantee they
> can write or read 'avail' bytes.
>
> The -audiodev out.mixing-engine=off case is also mostly accurate. Only
> the D-Bus audio backend is still missing a required function. The
> -audiodev in.mixing-engine=off case always passes a much too large
> 'avail' value. I haven't worked on this yet, because there was no
> reason for it so far.
>
> The following logs show the improvements. Not only the audio frontends
> can write or read all needed or available bytes. The same is true for
> the audio backends. For playback, the first six lines in the logs are
> expected. Here you can see how quickly the guest fills the empty
> downstream buffers after playback starts.
>
> QEMU was started with -device ich9-intel-hda,addr=0x1b -device
> hda-duplex,audiodev=audio0 -audiodev
> pa,out.frequency=96000,in.frequency=96000,id=audio0
>
> playback guest 44100Hz => host 96000Hz
>
> unpatched version:
> hda_audio_output_cb: to write 8188, written 1704
> audio_run_out: free 4458, played 926
> hda_audio_output_cb: to write 6488, written 2384
> audio_run_out: free 3532, played 1297
> hda_audio_output_cb: to write 4104, written 2648
> audio_run_out: free 2235, played 1441
> audio_run_out: free 794, played 793
> audio_run_out: free 897, played 896
> audio_run_out: free 831, played 829
> ...
> hda_audio_output_cb: could not write 4 bytes
> hda_audio_output_cb: to write 1764, written 1760
> audio_run_out: free 960, played 958
> ...
>
> patched version:
> hda_audio_output_cb: to write 8192, written 1620
> audio_run_out: free 4458, played 880
> hda_audio_output_cb: to write 6576, written 2508
> audio_run_out: free 3578, played 1365
> hda_audio_output_cb: to write 4068, written 2500
> audio_run_out: free 2213, played 1360
>
> record host 96000Hz => guest 44100Hz
>
> unpatched version:
> audio_run_in: avail 4458, acquired 4454
> audio_run_in: avail 1574, acquired 1572
> audio_run_in: avail 766, acquired 764
> audio_run_in: avail 1052, acquired 1051
> audio_run_in: avail 761, acquired 760
> audio_run_in: avail 1123, acquired 1121
> ...
> hda_audio_input_cb: could not read 4 bytes
> hda_audio_input_cb: to read 1988, read 1984
> audio_run_in: avail 1082, acquired 1080
> ...
>
> patched version:
> (no output)
>
> QEMU was started with -device ich9-intel-hda,addr=0x1b -device
> hda-duplex,audiodev=audio0 -audiodev
> pa,out.frequency=32000,in.frequency=32000,id=audio0
>
> playback guest 44100Hz => host 32000Hz
>
> unpatched version:
> hda_audio_output_cb: to write 8188, written 1620
> audio_run_out: free 1486, played 294
> hda_audio_output_cb: to write 6568, written 2512
> audio_run_out: free 1192, played 455
> hda_audio_output_cb: to write 4060, written 2504
> audio_run_out: free 737, played 455
> audio_run_out: free 282, played 281
> audio_run_out: free 357, played 356
> audio_run_out: free 314, played 313
> ...
> hda_audio_output_cb: could not write 4 bytes
> hda_audio_output_cb: to write 1416, written 1412
> audio_run_out: free 257, played 256
> ...
>
> patched version:
> hda_audio_output_cb: to write 8192, written 1656
> audio_run_out: free 1486, played 300
> hda_audio_output_cb: to write 6536, written 2516
> audio_run_out: free 1186, played 457
> hda_audio_output_cb: to write 4020, written 2540
> audio_run_out: free 729, played 460
>
> record host 32000Hz => guest 44100Hz
>
> unpatched version:
> audio_run_in: avail 1486, acquired 1485
> audio_run_in: avail 272, acquired 271
> audio_run_in: avail 366, acquired 365
> hda_audio_input_cb: could not read 4 bytes
> hda_audio_input_cb: to read 1420, read 1416
> audio_run_in: avail 258, acquired 257
> audio_run_in: avail 375, acquired 374
> hda_audio_input_cb: could not read 4 bytes
> hda_audio_input_cb: to read 2056, read 2052
> audio_run_in: avail 260, acquired 259
> ...
>
> patched version:
> (no output)
>
> This is the debug code for the logs above.
>
> ---snip--
> --- a/audio/audio.c 2022-12-13 19:14:31.793153558 +0100
> +++ b/audio/audio.c 2022-12-11 16:24:48.842649711 +0100
> @@ -1228,6 +1228,10 @@ static void audio_run_out (AudioState *s
> #ifdef DEBUG_OUT
> dolog("played=%zu\n", played);
> #endif
> + if (hw_free - played) {
> + fprintf(stderr, "%s: free %zu, played %zu\n",
> + __func__, hw_free, played);
> + }
>
> if (played) {
> hw->ts_helper += played;
> @@ -1318,6 +1322,7 @@ static void audio_run_in (AudioState *s)
> if (sw->active) {
> size_t sw_avail = audio_get_avail(sw);
> size_t avail;
> + size_t prev_acquired = sw->total_hw_samples_acquired;
>
> avail = st_rate_frames_out(sw->rate, sw_avail);
> if (avail > 0) {
> @@ -1325,6 +1330,11 @@ static void audio_run_in (AudioState *s)
> sw->callback.fn(sw->callback.opaque,
> avail * sw->info.bytes_per_frame);
> }
> +
> + if (sw_avail + prev_acquired -
> sw->total_hw_samples_acquired) {
> + fprintf(stderr, "%s: avail %zu, acquired %zu\n",
> __func__,
> + sw_avail, sw->total_hw_samples_acquired -
> prev_acquired);
> + }
> }
> }
> }
> --- a/hw/audio/hda-codec.c 2023-01-04 14:07:31.954304889 +0100
> +++ b/hw/audio/hda-codec.c 2023-01-04 13:57:47.687320406 +0100
> @@ -265,20 +265,28 @@ static void hda_audio_input_cb(void *opa
> int64_t rpos = st->rpos;
>
> int64_t to_transfer = MIN(B_SIZE - (wpos - rpos), avail);
> + unsigned int total_read = 0;
>
> while (to_transfer) {
> uint32_t start = (uint32_t) (wpos & B_MASK);
> uint32_t chunk = (uint32_t) MIN(B_SIZE - start, to_transfer);
> uint32_t read = AUD_read(st->voice.in, st->buf + start, chunk);
> wpos += read;
> + total_read += read;
> to_transfer -= read;
> st->wpos += read;
> if (chunk != read) {
> + fprintf(stderr, "%s: could not read %u bytes\n", __func__,
> + chunk - read);
> break;
> }
> }
>
> hda_timer_sync_adjust(st, -((wpos - rpos) - (B_SIZE >> 1)));
> + if (avail != total_read) {
> + fprintf(stderr, "%s: to read %d, read %u\n", __func__,
> + avail, total_read);
> + }
> }
>
> static void hda_audio_output_timer(void *opaque)
> @@ -329,6 +337,7 @@ static void hda_audio_output_cb(void *op
> int64_t rpos = st->rpos;
>
> int64_t to_transfer = MIN(wpos - rpos, avail);
> + unsigned int total_written = 0;
>
> if (wpos - rpos == B_SIZE) {
> /* drop buffer, reset timer adjust */
> @@ -343,15 +352,22 @@ static void hda_audio_output_cb(void *op
> uint32_t start = (uint32_t) (rpos & B_MASK);
> uint32_t chunk = (uint32_t) MIN(B_SIZE - start, to_transfer);
> uint32_t written = AUD_write(st->voice.out, st->buf + start,
> chunk);
> + total_written += written;
> rpos += written;
> to_transfer -= written;
> st->rpos += written;
> if (chunk != written) {
> + fprintf(stderr, "%s: could not write %u bytes\n", __func__,
> + chunk - written);
> break;
> }
> }
>
> hda_timer_sync_adjust(st, (wpos - rpos) - (B_SIZE >> 1));
> + if (avail != total_written) {
> + fprintf(stderr, "%s: to write %d, written %u\n", __func__,
> + avail, total_written);
> + }
> }
>
> static void hda_audio_compat_input_cb(void *opaque, int avail)
> ---snip--
>
> Volker Rümelin (17):
> audio: change type of mix_buf and conv_buf
> audio: change type and name of the resample buffer
> audio: make the resampling code greedy
> audio: replace the resampling loop in audio_pcm_sw_write()
> audio: remove sw == NULL check
> audio: rename variables in audio_pcm_sw_write()
> audio: don't misuse audio_pcm_sw_write()
> audio: remove unused noop_conv() function
> audio/mixeng: calculate number of input frames
> audio: wire up st_rate_frames_in()
> audio: replace the resampling loop in audio_pcm_sw_read()
> audio: rename variables in audio_pcm_sw_read()
> audio/mixeng: calculate number of output frames
> audio: wire up st_rate_frames_out()
> audio: handle leftover audio frame from upsampling
> audio/audio_template: substitute sw->hw with hw
> audio: remove sw->ratio
>
> audio/audio.c | 366 +++++++++++++++++++++--------------------
> audio/audio_int.h | 12 +-
> audio/audio_template.h | 41 +++--
> audio/mixeng.c | 73 ++++++++
> audio/mixeng.h | 2 +
> audio/rate_template.h | 21 ++-
> 6 files changed, 304 insertions(+), 211 deletions(-)
>
next prev parent reply other threads:[~2023-01-15 13:46 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-01-15 13:08 [PATCH 00/17] audio: improve callback interface for audio frontends Volker Rümelin
2023-01-15 13:12 ` [PATCH 01/17] audio: change type of mix_buf and conv_buf Volker Rümelin
2023-01-15 13:12 ` [PATCH 02/17] audio: change type and name of the resample buffer Volker Rümelin
2023-01-15 13:12 ` [PATCH 03/17] audio: make the resampling code greedy Volker Rümelin
2023-01-15 13:12 ` [PATCH 04/17] audio: replace the resampling loop in audio_pcm_sw_write() Volker Rümelin
2023-01-15 13:12 ` [PATCH 05/17] audio: remove sw == NULL check Volker Rümelin
2023-01-15 13:12 ` [PATCH 06/17] audio: rename variables in audio_pcm_sw_write() Volker Rümelin
2023-01-15 13:12 ` [PATCH 07/17] audio: don't misuse audio_pcm_sw_write() Volker Rümelin
2023-01-15 13:12 ` [PATCH 08/17] audio: remove unused noop_conv() function Volker Rümelin
2023-01-15 13:12 ` [PATCH 09/17] audio/mixeng: calculate number of input frames Volker Rümelin
2023-01-15 13:12 ` [PATCH 10/17] audio: wire up st_rate_frames_in() Volker Rümelin
2023-01-15 13:12 ` [PATCH 11/17] audio: replace the resampling loop in audio_pcm_sw_read() Volker Rümelin
2023-01-15 13:12 ` [PATCH 12/17] audio: rename variables " Volker Rümelin
2023-01-15 13:12 ` [PATCH 13/17] audio/mixeng: calculate number of output frames Volker Rümelin
2023-01-15 13:12 ` [PATCH 14/17] audio: wire up st_rate_frames_out() Volker Rümelin
2023-01-15 13:12 ` [PATCH 15/17] audio: handle leftover audio frame from upsampling Volker Rümelin
2023-01-15 13:12 ` [PATCH 16/17] audio/audio_template: substitute sw->hw with hw Volker Rümelin
2023-01-15 13:12 ` [PATCH 17/17] audio: remove sw->ratio Volker Rümelin
2023-01-15 13:45 ` Volker Rümelin [this message]
2023-01-22 18:13 ` [PATCH 00/17] audio: improve callback interface for audio frontends Mark Cave-Ayland
2023-01-28 9:03 ` Volker Rümelin
2023-01-28 22:01 ` Mark Cave-Ayland
2023-01-31 14:53 ` Marc-André Lureau
2023-01-31 20:25 ` Volker Rümelin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=a671751a-cbb7-22c2-8840-0476176d2533@t-online.de \
--to=vr_qemu@t-online.de \
--cc=kraxel@redhat.com \
--cc=marcandre.lureau@gmail.com \
--cc=mark.cave-ayland@ilande.co.uk \
--cc=philmd@linaro.org \
--cc=qemu-devel@nongnu.org \
--cc=qemu_oss@crudebyte.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).