From nobody Sun Apr 12 02:50:01 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1771854835; cv=none; d=zohomail.com; s=zohoarc; b=UoBV6638Q3wnoXIz2eCv5UtPZnb/oRL0MWSufD2AC5m6bHe5Z0EMQvlIOzSvbVFP3TFgrJGLCL5x1LjPiM02tUEhFtkwau7Rv4A15jtW8rz/p5AxUkfeQYGiFKhL2LhbpAEWJkFqUPxGhpSqVbqXzkFoV+4oo2ccdnHNwVa/b7s= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1771854835; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=Jpet2QkO3YlzQfYSfDPOd1CVsnkxJoKnqMXiSPFSPJA=; b=SzE/jJatEdsQ28+RGX39n4lS4Vwkxk3ZDubrAkQkF/VFn1Ysc8DjPVVH/jABuwACp+XzIXDJ7xufp0kdrngwogP8f0481qkX2KfjA1gy5TLoBQ5JH5iwuQtK6hHzXYoFy9U3qEzPSLmSN3/jbsb7+rstf5vbdBWWYmHPJv0wsIg= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1771854835762790.9811178867129; Mon, 23 Feb 2026 05:53:55 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1vuWJO-0002QX-GZ; Mon, 23 Feb 2026 08:49:22 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1vuWJE-0001Ud-OM for qemu-devel@nongnu.org; Mon, 23 Feb 2026 08:49:14 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1vuWJC-00078l-TW for qemu-devel@nongnu.org; Mon, 23 Feb 2026 08:49:12 -0500 Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-519-UauFlspDMG23hi5Ns43MeA-1; Mon, 23 Feb 2026 08:49:05 -0500 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 3E1ED19560AE; Mon, 23 Feb 2026 13:49:04 +0000 (UTC) Received: from localhost (unknown [10.45.242.25]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 891D519560A2; Mon, 23 Feb 2026 13:49:03 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1771854548; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Jpet2QkO3YlzQfYSfDPOd1CVsnkxJoKnqMXiSPFSPJA=; b=N1leg60Za2bA0FEUbNRC7FY6rXpqeO4D8LvZM58xuAMYsgm7wBisCf/HktSrUIZjXZnZgU l6auHumqVnsvBvssmo2nlaPdcgAO07JE8gGMGADcPkajb+K1SSJGt3Ho48+BOvV9RHQH0Y EQVjhXbWrfm4vJcqsscBAxKTgXs7wD8= X-MC-Unique: UauFlspDMG23hi5Ns43MeA-1 X-Mimecast-MFC-AGG-ID: UauFlspDMG23hi5Ns43MeA_1771854544 From: marcandre.lureau@redhat.com To: qemu-devel@nongnu.org Cc: Peter Maydell , =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , Gerd Hoffmann , Paolo Bonzini , =?UTF-8?q?Alex=20Benn=C3=A9e?= , John Snow , Cleber Rosa Subject: [PULL v3 33/85] replay: remove dependency on audio/ Date: Mon, 23 Feb 2026 14:46:34 +0100 Message-ID: <20260223134731.2377432-34-marcandre.lureau@redhat.com> In-Reply-To: <20260223134731.2377432-1-marcandre.lureau@redhat.com> References: <20260223134731.2377432-1-marcandre.lureau@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=170.10.129.124; envelope-from=marcandre.lureau@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -1 X-Spam_score: -0.2 X-Spam_bar: / X-Spam_report: (-0.2 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H4=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED=1.179, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.717, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1771854836440158500 From: Marc-Andr=C3=A9 Lureau The replay infrastructure shouldn't depend on internals of audio/. (st_sample is an internal implementation detail and could be different) Let audio drive the audio samples recording/replaying. Notice also we don't need to save & restore the internal ring "wpos", all replay should care about is the number of samples and the samples. Bump the replay version. Reviewed-by: Akihiko Odaki Signed-off-by: Marc-Andr=C3=A9 Lureau --- audio/audio_int.h | 5 ++++ include/qemu/audio.h | 5 ---- include/system/replay.h | 11 +++++++-- replay/replay-internal.h | 2 ++ audio/audio.c | 23 ++++++++++++++++-- replay/replay-audio.c | 51 +++++++++++++++++++++++---------------- replay/replay.c | 2 +- replay/stubs-system.c | 8 +++++- tests/audio/audio-stubs.c | 13 +++++++--- scripts/replay-dump.py | 8 +++++- 10 files changed, 92 insertions(+), 36 deletions(-) diff --git a/audio/audio_int.h b/audio/audio_int.h index e1f9fa333ba..250fd45238d 100644 --- a/audio/audio_int.h +++ b/audio/audio_int.h @@ -309,6 +309,11 @@ static inline size_t audio_ring_posb(size_t pos, size_= t dist, size_t len) AudiodevPerDirectionOptions *audio_get_pdo_in(Audiodev *dev); AudiodevPerDirectionOptions *audio_get_pdo_out(Audiodev *dev); =20 +void audio_sample_to_uint64(const st_sample *sample, int pos, + uint64_t *left, uint64_t *right); +void audio_sample_from_uint64(st_sample *sample, int pos, + uint64_t left, uint64_t right); + #define TYPE_AUDIO_MIXENG_BACKEND "audio-mixeng-backend" OBJECT_DECLARE_TYPE(AudioMixengBackend, AudioMixengBackendClass, AUDIO_MIX= ENG_BACKEND) =20 diff --git a/include/qemu/audio.h b/include/qemu/audio.h index 1eeead2a722..03ce9adbc88 100644 --- a/include/qemu/audio.h +++ b/include/qemu/audio.h @@ -120,11 +120,6 @@ void audio_cleanup(void); =20 typedef struct st_sample st_sample; =20 -void audio_sample_to_uint64(const st_sample *sample, int pos, - uint64_t *left, uint64_t *right); -void audio_sample_from_uint64(st_sample *sample, int pos, - uint64_t left, uint64_t right); - void audio_add_audiodev(Audiodev *audio); void audio_add_default_audiodev(Audiodev *dev, Error **errp); void audio_parse_option(const char *opt); diff --git a/include/system/replay.h b/include/system/replay.h index f8715ca9feb..19fb6dbb396 100644 --- a/include/system/replay.h +++ b/include/system/replay.h @@ -165,8 +165,15 @@ void replay_net_packet_event(ReplayNetState *rns, unsi= gned flags, =20 /*! Saves/restores number of played samples of audio out operation. */ void replay_audio_out(size_t *played); -/*! Saves/restores recorded samples of audio in operation. */ -void replay_audio_in(size_t *recorded, st_sample *samples, size_t *wpos, s= ize_t size); +/* + * Start saves/restores recorded samples of audio in operation. + * Must be called before replay_audio_in_sample_lr(). + */ +void replay_audio_in_start(size_t *recorded); +/* Saves/restores recorded samples. */ +void replay_audio_in_sample_lr(uint64_t *left, uint64_t *right); +/* Finish saves/restores recorded samples. */ +void replay_audio_in_finish(void); =20 /* VM state operations */ =20 diff --git a/replay/replay-internal.h b/replay/replay-internal.h index 75249b76936..643b357da12 100644 --- a/replay/replay-internal.h +++ b/replay/replay-internal.h @@ -85,6 +85,7 @@ enum ReplayEvents { * @file_offset: offset into replay log at replay snapshot * @block_request_id: current serialised block request id * @read_event_id: current async read event id + * @n_audio_samples: expected audio samples */ typedef struct ReplayState { int64_t cached_clock[REPLAY_CLOCK_COUNT]; @@ -96,6 +97,7 @@ typedef struct ReplayState { uint64_t file_offset; uint64_t block_request_id; uint64_t read_event_id; + size_t n_audio_samples; } ReplayState; extern ReplayState replay_state; =20 diff --git a/audio/audio.c b/audio/audio.c index 1fa63ee0421..3e16b719399 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -1301,13 +1301,32 @@ static void audio_run_in(AudioMixengBackend *s) while ((hw =3D audio_pcm_hw_find_any_enabled_in(s, hw))) { SWVoiceIn *sw; size_t captured =3D 0, min; + int pos; =20 if (replay_mode !=3D REPLAY_MODE_PLAY) { captured =3D audio_pcm_hw_run_in( hw, hw->conv_buf.size - audio_pcm_hw_get_live_in(hw)); } - replay_audio_in(&captured, hw->conv_buf.buffer, &hw->conv_buf.pos, - hw->conv_buf.size); + + replay_audio_in_start(&captured); + assert(captured <=3D hw->conv_buf.size); + if (replay_mode =3D=3D REPLAY_MODE_PLAY) { + hw->conv_buf.pos =3D (hw->conv_buf.pos + captured) % hw->conv_= buf.size; + } + for (pos =3D (hw->conv_buf.pos - captured + hw->conv_buf.size) % h= w->conv_buf.size; + pos !=3D hw->conv_buf.pos; + pos =3D (pos + 1) % hw->conv_buf.size) { + uint64_t left, right; + + if (replay_mode =3D=3D REPLAY_MODE_RECORD) { + audio_sample_to_uint64(hw->conv_buf.buffer, pos, &left= , &right); + } + replay_audio_in_sample_lr(&left, &right); + if (replay_mode =3D=3D REPLAY_MODE_PLAY) { + audio_sample_from_uint64(hw->conv_buf.buffer, pos, lef= t, right); + } + } + replay_audio_in_finish(); =20 min =3D audio_pcm_hw_find_min_in (hw); hw->total_samples_captured +=3D captured - min; diff --git a/replay/replay-audio.c b/replay/replay-audio.c index 1b614f41379..7d20ae9110c 100644 --- a/replay/replay-audio.c +++ b/replay/replay-audio.c @@ -13,7 +13,6 @@ #include "qemu/error-report.h" #include "system/replay.h" #include "replay-internal.h" -#include "qemu/audio.h" =20 void replay_audio_out(size_t *played) { @@ -35,38 +34,48 @@ void replay_audio_out(size_t *played) } } =20 -void replay_audio_in(size_t *recorded, st_sample *samples, size_t *wpos, s= ize_t size) +void replay_audio_in_start(size_t *nsamples) { - int pos; - uint64_t left, right; if (replay_mode =3D=3D REPLAY_MODE_RECORD) { g_assert(replay_mutex_locked()); replay_save_instructions(); replay_put_event(EVENT_AUDIO_IN); - replay_put_qword(*recorded); - replay_put_qword(*wpos); - for (pos =3D (*wpos - *recorded + size) % size ; pos !=3D *wpos - ; pos =3D (pos + 1) % size) { - audio_sample_to_uint64(samples, pos, &left, &right); - replay_put_qword(left); - replay_put_qword(right); - } + replay_put_qword(*nsamples); + replay_state.n_audio_samples =3D *nsamples; } else if (replay_mode =3D=3D REPLAY_MODE_PLAY) { g_assert(replay_mutex_locked()); replay_account_executed_instructions(); if (replay_next_event_is(EVENT_AUDIO_IN)) { - *recorded =3D replay_get_qword(); - *wpos =3D replay_get_qword(); - for (pos =3D (*wpos - *recorded + size) % size ; pos !=3D *wpos - ; pos =3D (pos + 1) % size) { - left =3D replay_get_qword(); - right =3D replay_get_qword(); - audio_sample_from_uint64(samples, pos, left, right); - } - replay_finish_event(); + *nsamples =3D replay_get_qword(); + replay_state.n_audio_samples =3D *nsamples; } else { error_report("Missing audio in event in the replay log"); abort(); } } } + +void replay_audio_in_sample_lr(uint64_t *left, uint64_t *right) +{ + if (replay_mode =3D=3D REPLAY_MODE_RECORD) { + replay_put_qword(*left); + replay_put_qword(*right); + } else if (replay_mode =3D=3D REPLAY_MODE_PLAY) { + *left =3D replay_get_qword(); + *right =3D replay_get_qword(); + } else { + return; + } + + assert(replay_state.n_audio_samples > 0); + replay_state.n_audio_samples--; +} + +void replay_audio_in_finish(void) +{ + assert(replay_state.n_audio_samples =3D=3D 0); + + if (replay_mode =3D=3D REPLAY_MODE_PLAY) { + replay_finish_event(); + } +} diff --git a/replay/replay.c b/replay/replay.c index b2121788c1d..2e5c6fa82ea 100644 --- a/replay/replay.c +++ b/replay/replay.c @@ -22,7 +22,7 @@ =20 /* Current version of the replay mechanism. Increase it when file format changes. */ -#define REPLAY_VERSION 0xe0200c +#define REPLAY_VERSION 0xe0200d /* Size of replay log header */ #define HEADER_SIZE (sizeof(uint32_t) + sizeof(uint64_t)) =20 diff --git a/replay/stubs-system.c b/replay/stubs-system.c index 7f85764936f..b2c52bc4043 100644 --- a/replay/stubs-system.c +++ b/replay/stubs-system.c @@ -15,7 +15,13 @@ void replay_input_sync_event(void) void replay_add_blocker(const char *feature) { } -void replay_audio_in(size_t *recorded, st_sample *samples, size_t *wpos, s= ize_t size) +void replay_audio_in_start(size_t *nsamples) +{ +} +void replay_audio_in_sample_lr(uint64_t *left, uint64_t *right) +{ +} +void replay_audio_in_finish(void) { } void replay_audio_out(size_t *played) diff --git a/tests/audio/audio-stubs.c b/tests/audio/audio-stubs.c index dd7f635d460..2c19dfa7d6b 100644 --- a/tests/audio/audio-stubs.c +++ b/tests/audio/audio-stubs.c @@ -35,12 +35,19 @@ dbus_win32_import_socket(GDBusMethodInvocation *invocat= ion, } #endif =20 -void replay_audio_in(size_t *recorded, st_sample *samples, - size_t *wpos, size_t size) +void replay_audio_out(size_t *played) { } =20 -void replay_audio_out(size_t *played) +void replay_audio_in_start(size_t *nsamples) +{ +} + +void replay_audio_in_sample_lr(uint64_t *left, uint64_t *right) +{ +} + +void replay_audio_in_finish(void) { } =20 diff --git a/scripts/replay-dump.py b/scripts/replay-dump.py index 097636570dd..081aaa36c5e 100755 --- a/scripts/replay-dump.py +++ b/scripts/replay-dump.py @@ -395,6 +395,9 @@ def decode_end(eid, name, dumpfile): Decoder(39, "EVENT_END", decode_end), ] =20 +# EVENT_AUDIO_IN has changed +v13_event_table =3D v12_event_table + def parse_arguments(): "Grab arguments for script" parser =3D argparse.ArgumentParser() @@ -413,7 +416,10 @@ def decode_file(filename): # see REPLAY_VERSION print("HEADER: version 0x%x" % (version)) =20 - if version =3D=3D 0xe0200c: + if version =3D=3D 0xe0200d: + event_decode_table =3D v13_event_table + replay_state.checkpoint_start =3D 30 + elif version =3D=3D 0xe0200c: event_decode_table =3D v12_event_table replay_state.checkpoint_start =3D 30 elif version =3D=3D 0xe02007: --=20 2.53.0