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