@samitouri / QOSamiQemu / commits / 5ca6c931a7

replay: remove dependency on audio/

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 <odaki@rsg.ci.i.u-tokyo.ac.jp> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

Marc-André Lureau committed Nov 3, 2025 at 16:22 UTC 5ca6c931a7d18f3281cd7c7e5ea6cffbda63ddcc
10 files changed +92 -36
audio/audio.c
+21 -2
@@ -1301,13 +1301,32 @@ static void audio_run_in(AudioMixengBackend *s)
1301 while ((hw = audio_pcm_hw_find_any_enabled_in(s, hw))) {
1302 SWVoiceIn *sw;
1303 size_t captured = 0, min;
1304 + int pos;
1305
1306 if (replay_mode != REPLAY_MODE_PLAY) {
1307 captured = audio_pcm_hw_run_in(
1308 hw, hw->conv_buf.size - audio_pcm_hw_get_live_in(hw));
1309 }
1309 - replay_audio_in(&captured, hw->conv_buf.buffer, &hw->conv_buf.pos,
1310 - hw->conv_buf.size);
1310 +
1311 + replay_audio_in_start(&captured);
1312 + assert(captured <= hw->conv_buf.size);
1313 + if (replay_mode == REPLAY_MODE_PLAY) {
1314 + hw->conv_buf.pos = (hw->conv_buf.pos + captured) % hw->conv_buf.size;
1315 + }
1316 + for (pos = (hw->conv_buf.pos - captured + hw->conv_buf.size) % hw->conv_buf.size;
1317 + pos != hw->conv_buf.pos;
1318 + pos = (pos + 1) % hw->conv_buf.size) {
1319 + uint64_t left, right;
1320 +
1321 + if (replay_mode == REPLAY_MODE_RECORD) {
1322 + audio_sample_to_uint64(hw->conv_buf.buffer, pos, &left, &right);
1323 + }
1324 + replay_audio_in_sample_lr(&left, &right);
1325 + if (replay_mode == REPLAY_MODE_PLAY) {
1326 + audio_sample_from_uint64(hw->conv_buf.buffer, pos, left, right);
1327 + }
1328 + }
1329 + replay_audio_in_finish();
1330
1331 min = audio_pcm_hw_find_min_in (hw);
1332 hw->total_samples_captured += captured - min;
audio/audio_int.h
+5
@@ -309,6 +309,11 @@ static inline size_t audio_ring_posb(size_t pos, size_t dist, size_t len)
309 AudiodevPerDirectionOptions *audio_get_pdo_in(Audiodev *dev);
310 AudiodevPerDirectionOptions *audio_get_pdo_out(Audiodev *dev);
311
312 +void audio_sample_to_uint64(const st_sample *sample, int pos,
313 + uint64_t *left, uint64_t *right);
314 +void audio_sample_from_uint64(st_sample *sample, int pos,
315 + uint64_t left, uint64_t right);
316 +
317 #define TYPE_AUDIO_MIXENG_BACKEND "audio-mixeng-backend"
318 OBJECT_DECLARE_TYPE(AudioMixengBackend, AudioMixengBackendClass, AUDIO_MIXENG_BACKEND)
319
include/qemu/audio.h
-5
@@ -120,11 +120,6 @@ void audio_cleanup(void);
120
121 typedef struct st_sample st_sample;
122
123 -void audio_sample_to_uint64(const st_sample *sample, int pos,
124 - uint64_t *left, uint64_t *right);
125 -void audio_sample_from_uint64(st_sample *sample, int pos,
126 - uint64_t left, uint64_t right);
127 -
123 void audio_add_audiodev(Audiodev *audio);
124 void audio_add_default_audiodev(Audiodev *dev, Error **errp);
125 void audio_parse_option(const char *opt);
include/system/replay.h
+9 -2
@@ -165,8 +165,15 @@ void replay_net_packet_event(ReplayNetState *rns, unsigned flags,
165
166 /*! Saves/restores number of played samples of audio out operation. */
167 void replay_audio_out(size_t *played);
168 -/*! Saves/restores recorded samples of audio in operation. */
169 -void replay_audio_in(size_t *recorded, st_sample *samples, size_t *wpos, size_t size);
168 +/*
169 + * Start saves/restores recorded samples of audio in operation.
170 + * Must be called before replay_audio_in_sample_lr().
171 + */
172 +void replay_audio_in_start(size_t *recorded);
173 +/* Saves/restores recorded samples. */
174 +void replay_audio_in_sample_lr(uint64_t *left, uint64_t *right);
175 +/* Finish saves/restores recorded samples. */
176 +void replay_audio_in_finish(void);
177
178 /* VM state operations */
179
replay/replay-audio.c
+30 -21
@@ -13,7 +13,6 @@
13 #include "qemu/error-report.h"
14 #include "system/replay.h"
15 #include "replay-internal.h"
16 -#include "qemu/audio.h"
16
17 void replay_audio_out(size_t *played)
18 {
@@ -35,38 +34,48 @@ void replay_audio_out(size_t *played)
34 }
35 }
36
38 -void replay_audio_in(size_t *recorded, st_sample *samples, size_t *wpos, size_t size)
37 +void replay_audio_in_start(size_t *nsamples)
38 {
40 - int pos;
41 - uint64_t left, right;
39 if (replay_mode == REPLAY_MODE_RECORD) {
40 g_assert(replay_mutex_locked());
41 replay_save_instructions();
42 replay_put_event(EVENT_AUDIO_IN);
46 - replay_put_qword(*recorded);
47 - replay_put_qword(*wpos);
48 - for (pos = (*wpos - *recorded + size) % size ; pos != *wpos
49 - ; pos = (pos + 1) % size) {
50 - audio_sample_to_uint64(samples, pos, &left, &right);
51 - replay_put_qword(left);
52 - replay_put_qword(right);
53 - }
43 + replay_put_qword(*nsamples);
44 + replay_state.n_audio_samples = *nsamples;
45 } else if (replay_mode == REPLAY_MODE_PLAY) {
46 g_assert(replay_mutex_locked());
47 replay_account_executed_instructions();
48 if (replay_next_event_is(EVENT_AUDIO_IN)) {
58 - *recorded = replay_get_qword();
59 - *wpos = replay_get_qword();
60 - for (pos = (*wpos - *recorded + size) % size ; pos != *wpos
61 - ; pos = (pos + 1) % size) {
62 - left = replay_get_qword();
63 - right = replay_get_qword();
64 - audio_sample_from_uint64(samples, pos, left, right);
65 - }
66 - replay_finish_event();
49 + *nsamples = replay_get_qword();
50 + replay_state.n_audio_samples = *nsamples;
51 } else {
52 error_report("Missing audio in event in the replay log");
53 abort();
54 }
55 }
56 }
57 +
58 +void replay_audio_in_sample_lr(uint64_t *left, uint64_t *right)
59 +{
60 + if (replay_mode == REPLAY_MODE_RECORD) {
61 + replay_put_qword(*left);
62 + replay_put_qword(*right);
63 + } else if (replay_mode == REPLAY_MODE_PLAY) {
64 + *left = replay_get_qword();
65 + *right = replay_get_qword();
66 + } else {
67 + return;
68 + }
69 +
70 + assert(replay_state.n_audio_samples > 0);
71 + replay_state.n_audio_samples--;
72 +}
73 +
74 +void replay_audio_in_finish(void)
75 +{
76 + assert(replay_state.n_audio_samples == 0);
77 +
78 + if (replay_mode == REPLAY_MODE_PLAY) {
79 + replay_finish_event();
80 + }
81 +}
replay/replay-internal.h
+2
@@ -85,6 +85,7 @@ enum ReplayEvents {
85 * @file_offset: offset into replay log at replay snapshot
86 * @block_request_id: current serialised block request id
87 * @read_event_id: current async read event id
88 + * @n_audio_samples: expected audio samples
89 */
90 typedef struct ReplayState {
91 int64_t cached_clock[REPLAY_CLOCK_COUNT];
@@ -96,6 +97,7 @@ typedef struct ReplayState {
97 uint64_t file_offset;
98 uint64_t block_request_id;
99 uint64_t read_event_id;
100 + size_t n_audio_samples;
101 } ReplayState;
102 extern ReplayState replay_state;
103
replay/replay.c
+1 -1
@@ -22,7 +22,7 @@
22
23 /* Current version of the replay mechanism.
24 Increase it when file format changes. */
25 -#define REPLAY_VERSION 0xe0200c
25 +#define REPLAY_VERSION 0xe0200d
26 /* Size of replay log header */
27 #define HEADER_SIZE (sizeof(uint32_t) + sizeof(uint64_t))
28
replay/stubs-system.c
+7 -1
@@ -15,7 +15,13 @@ void replay_input_sync_event(void)
15 void replay_add_blocker(const char *feature)
16 {
17 }
18 -void replay_audio_in(size_t *recorded, st_sample *samples, size_t *wpos, size_t size)
18 +void replay_audio_in_start(size_t *nsamples)
19 +{
20 +}
21 +void replay_audio_in_sample_lr(uint64_t *left, uint64_t *right)
22 +{
23 +}
24 +void replay_audio_in_finish(void)
25 {
26 }
27 void replay_audio_out(size_t *played)
scripts/replay-dump.py
+7 -1
@@ -395,6 +395,9 @@ v12_event_table = [Decoder(0, "EVENT_INSTRUCTION", decode_instruction),
395 Decoder(39, "EVENT_END", decode_end),
396 ]
397
398 +# EVENT_AUDIO_IN has changed
399 +v13_event_table = v12_event_table
400 +
401 def parse_arguments():
402 "Grab arguments for script"
403 parser = argparse.ArgumentParser()
@@ -413,7 +416,10 @@ def decode_file(filename):
416 # see REPLAY_VERSION
417 print("HEADER: version 0x%x" % (version))
418
416 - if version == 0xe0200c:
419 + if version == 0xe0200d:
420 + event_decode_table = v13_event_table
421 + replay_state.checkpoint_start = 30
422 + elif version == 0xe0200c:
423 event_decode_table = v12_event_table
424 replay_state.checkpoint_start = 30
425 elif version == 0xe02007:
tests/audio/audio-stubs.c
+10 -3
@@ -35,12 +35,19 @@ dbus_win32_import_socket(GDBusMethodInvocation *invocation,
35 }
36 #endif
37
38 -void replay_audio_in(size_t *recorded, st_sample *samples,
39 - size_t *wpos, size_t size)
38 +void replay_audio_out(size_t *played)
39 {
40 }
41
43 -void replay_audio_out(size_t *played)
42 +void replay_audio_in_start(size_t *nsamples)
43 +{
44 +}
45 +
46 +void replay_audio_in_sample_lr(uint64_t *left, uint64_t *right)
47 +{
48 +}
49 +
50 +void replay_audio_in_finish(void)
51 {
52 }
53