Am Mo., 29. Juni 2026 um 10:19 Uhr schrieb Manos Pitsidianakis
<[email protected]>:
>
> On Fri, 26 Jun 2026 15:35, Alexander Mikhalitsyn <[email protected]>
> wrote:
> >From: Volker Rümelin <[email protected]>
> >
> >So far, only rudimentary checks have been made to ensure that
> >the guest only performs state transitions permitted in
> >virtio-v1.2-csd01 5.14.6.6.1 PCM Command Lifecycle. Add a state
> >variable per audio stream and check all state transitions.
>
>
> This was on purpose: 5.14.6.6.1 is not a Device Requirement / normative
> statement. (In my opinion it should have been).
>
> I do not oppose keeping the state though, I chose to do it in the Rust
> implementation (vhost-device-sound) after I wrote this one as well. It
> makes sense. But please update the commit message to say that this is
> not about spec compliance, but simply doing a sanity check following the
> PCM Command Lifecycle section.
>
>
> >
> >Because only permitted state transitions are possible, only one
> >copy of the audio stream parameters is required and these do not
> >need to be initialised with default values.
> >
> >The state variable will also make it easier to restore the audio
> >stream after migration.
> >
> >Signed-off-by: Volker Rümelin <[email protected]>
> >[AM: there were too many conflicts, I did `git checkout --ours -- <.>`
> > and then reimplemented the patch idea
> >/AM]
> >Signed-off-by: Alexander Mikhalitsyn <[email protected]>
> >---
> >v3:
> > - explicitly call virtio_snd_pcm_close() from unrealize
> > - remove a call to virtio_snd_pcm_flush() from virtio_snd_pcm_close()
> > [ ^ this was my rebase mistake ]
> >---
> > hw/audio/virtio-snd.c | 196 +++++++++++++++++++---------------
> > include/hw/audio/virtio-snd.h | 18 +---
> > 2 files changed, 109 insertions(+), 105 deletions(-)
> >
> >diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
> >index 300ba13ffeb..68d737478f5 100644
> >--- a/hw/audio/virtio-snd.c
> >+++ b/hw/audio/virtio-snd.c
> >@@ -30,11 +30,30 @@
> > #define VIRTIO_SOUND_CHMAP_DEFAULT 0
> > #define VIRTIO_SOUND_HDA_FN_NID 0
> >
> >+#define VSND_PCMSTREAM_STATE_F_PARAMS_SET 0x10000
> >+#define VSND_PCMSTREAM_STATE_F_PREPARED 0x20000
> >+#define VSND_PCMSTREAM_STATE_F_ACTIVE 0x40000
> >+
> >+#define VSND_PCMSTREAM_STATE_UNINITIALIZED 0
> >+#define VSND_PCMSTREAM_STATE_PARAMS_SET (1 \
> >+ |
> >VSND_PCMSTREAM_STATE_F_PARAMS_SET)
> >+#define VSND_PCMSTREAM_STATE_PREPARED (2 \
> >+ |
> >VSND_PCMSTREAM_STATE_F_PARAMS_SET \
> >+ |
> >VSND_PCMSTREAM_STATE_F_PREPARED)
> >+#define VSND_PCMSTREAM_STATE_STARTED (4 \
> >+ |
> >VSND_PCMSTREAM_STATE_F_PARAMS_SET \
> >+ |
> >VSND_PCMSTREAM_STATE_F_PREPARED \
> >+ | VSND_PCMSTREAM_STATE_F_ACTIVE)
> >+#define VSND_PCMSTREAM_STATE_STOPPED (6 \
> >+ |
> >VSND_PCMSTREAM_STATE_F_PARAMS_SET \
> >+ |
> >VSND_PCMSTREAM_STATE_F_PREPARED)
> >+#define VSND_PCMSTREAM_STATE_RELEASED (7 \
> >+ |
> >VSND_PCMSTREAM_STATE_F_PARAMS_SET)
>
> Are the VSND_PCMSTREAM_STATE_F_* really needed? Seems excessive.
yeah, I don't know exactly why Volker went this way originally, but I
can guess he had just
tried to follow a numbering scheme for states from 5.14.6.6.1 "PCM
Command Lifecycle"
and make it universal enough, cause as long as we put this thing as:
VMSTATE_UINT32(state, VirtIOSoundPCMStream)
it stops being just an implementation detail and becomes an API that
we’ll need to remain backward-compatible with.
>
> I'd do: (did not type check/compile)
>
> + enum virtio_snd_pcm_state {
> + VIRTIO_SND_PCM_STATE_UNINIT = 0,
> + VIRTIO_SND_PCM_STATE_PARAMS_SET,
> + VIRTIO_SND_PCM_STATE_PREPARED,
> + VIRTIO_SND_PCM_STATE_STARTED,
> + VIRTIO_SND_PCM_STATE_STOPPED,
> + VIRTIO_SND_PCM_STATE_RELEASED,
> + }
>
> Maybe even write a "method" "macro" for preparedness:
>
> +
> + static inline bool virtio_snd_pcm_state_prepared(virtio_snd_pcm_state
> s) {
> + return s > VIRTIO_SND_PCM_STATE_PARAMS_SET && s <
> VIRTIO_SND_PCM_STATE_RELEASED
> + }
>
> And "active" flag bit is only in STARTED state, so just check for
> equality.
>
> This is not a hard request, but it seems simpler to me and would prefer
> it.
yeah, let me try to rework that part to see if everything fits well.
>
> >+
> > static void virtio_snd_pcm_out_cb(void *data, int available);
> > static void virtio_snd_process_cmdq(VirtIOSound *s);
> > static void virtio_snd_pcm_flush(VirtIOSoundPCMStream *stream);
> > static void virtio_snd_pcm_in_cb(void *data, int available);
> >-static void virtio_snd_unrealize(DeviceState *dev);
> >
> > static uint32_t supported_formats = BIT(VIRTIO_SND_PCM_FMT_S8)
> > | BIT(VIRTIO_SND_PCM_FMT_U8)
> >@@ -129,7 +148,7 @@ static VirtIOSoundPCMStream
> >*virtio_snd_pcm_get_stream(VirtIOSound *s,
> > uint32_t stream_id)
> > {
> > return stream_id >= s->snd_conf.streams ? NULL :
> >- s->pcm.streams[stream_id];
> >+ &s->streams[stream_id];
> > }
> >
> > /*
> >@@ -141,8 +160,8 @@ static VirtIOSoundPCMStream
> >*virtio_snd_pcm_get_stream(VirtIOSound *s,
> > static virtio_snd_pcm_set_params *virtio_snd_pcm_get_params(VirtIOSound *s,
> > uint32_t
> > stream_id)
> > {
> >- return stream_id >= s->snd_conf.streams ? NULL
> >- : &s->pcm.pcm_params[stream_id];
> >+ return stream_id >= s->snd_conf.streams ? NULL :
> >+ &s->streams[stream_id].params;
> > }
> >
> > /*
> >@@ -245,11 +264,10 @@ static void virtio_snd_handle_pcm_info(VirtIOSound *s,
> >
> > /*
> > * Set the given stream params.
> >- * Called by both virtio_snd_handle_pcm_set_params and during device
> >- * initialization.
> > * Returns the response status code. (VIRTIO_SND_S_*).
> > *
> > * @s: VirtIOSound device
> >+ * @stream_id: stream id
> > * @params: The PCM params as defined in the virtio specification
> > */
> > static
> >@@ -257,14 +275,25 @@ uint32_t virtio_snd_set_pcm_params(VirtIOSound *s,
> > uint32_t stream_id,
> > virtio_snd_pcm_set_params *params)
> > {
> >+ VirtIOSoundPCMStream *stream;
> > virtio_snd_pcm_set_params *st_params;
> >
> >- if (stream_id >= s->snd_conf.streams || s->pcm.pcm_params == NULL) {
> >+ if (stream_id >= s->snd_conf.streams) {
> > virtio_error(VIRTIO_DEVICE(s), "Streams have not been
> > initialized.\n");
> > return cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
> > }
> >
> >- st_params = virtio_snd_pcm_get_params(s, stream_id);
> >+ stream = virtio_snd_pcm_get_stream(s, stream_id);
> >+
> >+ switch (stream->state) {
> >+ case VSND_PCMSTREAM_STATE_UNINITIALIZED:
> >+ case VSND_PCMSTREAM_STATE_PARAMS_SET:
> >+ case VSND_PCMSTREAM_STATE_PREPARED:
> >+ case VSND_PCMSTREAM_STATE_RELEASED:
> >+ break;
> >+ default:
> >+ return cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
> >+ }
> >
> > if (params->channels < 1 || params->channels > AUDIO_MAX_CHANNELS) {
> > error_report("Number of channels is not supported.");
> >@@ -281,6 +310,8 @@ uint32_t virtio_snd_set_pcm_params(VirtIOSound *s,
> > return cpu_to_le32(VIRTIO_SND_S_NOT_SUPP);
> > }
> >
> >+ st_params = virtio_snd_pcm_get_params(s, stream_id);
> >+
> > st_params->buffer_bytes = le32_to_cpu(params->buffer_bytes);
> > st_params->period_bytes = le32_to_cpu(params->period_bytes);
> > st_params->features = le32_to_cpu(params->features);
> >@@ -289,6 +320,13 @@ uint32_t virtio_snd_set_pcm_params(VirtIOSound *s,
> > st_params->format = params->format;
> > st_params->rate = params->rate;
> >
> >+ if (stream->state & VSND_PCMSTREAM_STATE_F_PREPARED) {
> >+ /* implicit VIRTIO_SND_R_PCM_RELEASE */
> >+ virtio_snd_pcm_flush(stream);
> >+ }
> >+
> >+ stream->state = VSND_PCMSTREAM_STATE_PARAMS_SET;
> >+
> > return cpu_to_le32(VIRTIO_SND_S_OK);
> > }
> >
> >@@ -398,15 +436,12 @@ static void
> >virtio_snd_get_qemu_audsettings(audsettings *as,
> > */
> > static void virtio_snd_pcm_close(VirtIOSoundPCMStream *stream)
> > {
> >- if (stream) {
> >- virtio_snd_pcm_flush(stream);
> >- if (stream->info.direction == VIRTIO_SND_D_OUTPUT) {
> >- audio_be_close_out(stream->s->audio_be, stream->voice.out);
> >- stream->voice.out = NULL;
> >- } else if (stream->info.direction == VIRTIO_SND_D_INPUT) {
> >- audio_be_close_in(stream->s->audio_be, stream->voice.in);
> >- stream->voice.in = NULL;
> >- }
> >+ if (stream->info.direction == VIRTIO_SND_D_OUTPUT) {
> >+ audio_be_close_out(stream->s->audio_be, stream->voice.out);
> >+ stream->voice.out = NULL;
> >+ } else if (stream->info.direction == VIRTIO_SND_D_INPUT) {
> >+ audio_be_close_in(stream->s->audio_be, stream->voice.in);
> >+ stream->voice.in = NULL;
> > }
> > }
> >
> >@@ -423,32 +458,23 @@ static uint32_t virtio_snd_pcm_prepare(VirtIOSound *s,
> >uint32_t stream_id)
> > virtio_snd_pcm_set_params *params;
> > VirtIOSoundPCMStream *stream;
> >
> >- if (s->pcm.streams == NULL ||
> >- s->pcm.pcm_params == NULL ||
> >- stream_id >= s->snd_conf.streams) {
> >+ stream = virtio_snd_pcm_get_stream(s, stream_id);
> >+ if (!stream) {
> > return cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
> > }
> >
> >- params = virtio_snd_pcm_get_params(s, stream_id);
> >- if (params == NULL) {
> >+ switch (stream->state) {
> >+ case VSND_PCMSTREAM_STATE_PARAMS_SET:
> >+ case VSND_PCMSTREAM_STATE_PREPARED:
> >+ case VSND_PCMSTREAM_STATE_RELEASED:
> >+ break;
> >+ default:
> > return cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
> > }
> >
> >- stream = virtio_snd_pcm_get_stream(s, stream_id);
> >- if (stream == NULL) {
> >- stream = &s->streams[stream_id];
> >- stream->active = false;
> >- stream->latency_bytes = 0;
> >-
> >- /*
> >- * stream_id >= s->snd_conf.streams was checked before so this is
> >- * in-bounds
> >- */
> >- s->pcm.streams[stream_id] = stream;
> >- }
> >+ params = virtio_snd_pcm_get_params(s, stream_id);
> >
> > virtio_snd_get_qemu_audsettings(&as, params);
> >- stream->params = *params;
> >
> > stream->positions[0] = VIRTIO_SND_CHMAP_FL;
> > stream->positions[1] = VIRTIO_SND_CHMAP_FR;
> >@@ -472,6 +498,8 @@ static uint32_t virtio_snd_pcm_prepare(VirtIOSound *s,
> >uint32_t stream_id)
> > audio_be_set_volume_in_lr(s->audio_be, stream->voice.in, 0, 255,
> > 255);
> > }
> >
> >+ stream->state = VSND_PCMSTREAM_STATE_PREPARED;
> >+
> > return cpu_to_le32(VIRTIO_SND_S_OK);
> > }
> >
> >@@ -542,12 +570,28 @@ static uint32_t virtio_snd_pcm_start_stop(VirtIOSound
> >*s,
> > }
> >
> > if (start) {
> >+ switch (stream->state) {
> >+ case VSND_PCMSTREAM_STATE_PREPARED:
> >+ case VSND_PCMSTREAM_STATE_STOPPED:
> >+ break;
> >+ default:
> >+ return cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
> >+ }
> >+
> > trace_virtio_snd_handle_pcm_start(stream_id);
> >+ stream->state = VSND_PCMSTREAM_STATE_STARTED;
> > } else {
> >+ switch (stream->state) {
> >+ case VSND_PCMSTREAM_STATE_STARTED:
> >+ break;
> >+ default:
> >+ return cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
> >+ }
> >+
> > trace_virtio_snd_handle_pcm_stop(stream_id);
> >+ stream->state = VSND_PCMSTREAM_STATE_STOPPED;
> > }
> >
> >- stream->active = start;
> > if (stream->info.direction == VIRTIO_SND_D_OUTPUT) {
> > audio_be_set_active_out(s->audio_be, stream->voice.out, start);
> > } else {
> >@@ -641,6 +685,15 @@ static void virtio_snd_handle_pcm_release(VirtIOSound
> >*s,
> > return;
> > }
> >
> >+ switch (stream->state) {
> >+ case VSND_PCMSTREAM_STATE_PREPARED:
> >+ case VSND_PCMSTREAM_STATE_STOPPED:
> >+ break;
> >+ default:
> >+ cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_BAD_MSG);
> >+ return;
> >+ }
> >+
> > if (virtio_snd_pcm_get_io_msgs_count(stream)) {
> > /*
> > * virtio-v1.2-csd01, 5.14.6.6.5.1,
> >@@ -655,6 +708,8 @@ static void virtio_snd_handle_pcm_release(VirtIOSound *s,
> > virtio_snd_pcm_flush(stream);
> > }
> >
> >+ stream->state = VSND_PCMSTREAM_STATE_RELEASED;
> >+
> > cmd->resp.code = cpu_to_le32(VIRTIO_SND_S_OK);
> > }
> >
> >@@ -876,12 +931,11 @@ static void virtio_snd_handle_tx_xfer(VirtIODevice
> >*vdev, VirtQueue *vq)
> > }
> > stream_id = le32_to_cpu(hdr.stream_id);
> >
> >- if (stream_id >= vsnd->snd_conf.streams
> >- || vsnd->pcm.streams[stream_id] == NULL) {
> >+ if (stream_id >= vsnd->snd_conf.streams) {
> > goto tx_err;
> > }
> >
> >- stream = vsnd->pcm.streams[stream_id];
> >+ stream = &vsnd->streams[stream_id];
> > if (stream->info.direction != VIRTIO_SND_D_OUTPUT) {
> > goto tx_err;
> > }
> >@@ -956,13 +1010,12 @@ static void virtio_snd_handle_rx_xfer(VirtIODevice
> >*vdev, VirtQueue *vq)
> > }
> > stream_id = le32_to_cpu(hdr.stream_id);
> >
> >- if (stream_id >= vsnd->snd_conf.streams
> >- || !vsnd->pcm.streams[stream_id]) {
> >+ if (stream_id >= vsnd->snd_conf.streams) {
> > goto rx_err;
> > }
> >
> >- stream = vsnd->pcm.streams[stream_id];
> >- if (stream == NULL || stream->info.direction != VIRTIO_SND_D_INPUT)
> >{
> >+ stream = &vsnd->streams[stream_id];
> >+ if (stream->info.direction != VIRTIO_SND_D_INPUT) {
> > goto rx_err;
> > }
> >
> >@@ -1021,8 +1074,6 @@ static void virtio_snd_realize(DeviceState *dev, Error
> >**errp)
> > ERRP_GUARD();
> > VirtIOSound *vsnd = VIRTIO_SND(dev);
> > VirtIODevice *vdev = VIRTIO_DEVICE(dev);
> >- virtio_snd_pcm_set_params default_params = { 0 };
> >- uint32_t status;
> >
> > trace_virtio_snd_realize(vsnd);
> >
> >@@ -1059,6 +1110,7 @@ static void virtio_snd_realize(DeviceState *dev, Error
> >**errp)
> > for (uint32_t i = 0; i < vsnd->snd_conf.streams; i++) {
> > VirtIOSoundPCMStream *stream = &vsnd->streams[i];
> >
> >+ stream->state = VSND_PCMSTREAM_STATE_UNINITIALIZED;
> > stream->s = vsnd;
> > QSIMPLEQ_INIT(&stream->queue);
> > stream->info.hdr.hda_fn_nid = VIRTIO_SOUND_HDA_FN_NID;
> >@@ -1072,21 +1124,9 @@ static void virtio_snd_realize(DeviceState *dev,
> >Error **errp)
> > stream->info.channels_max = 2;
> > }
> >
> >- vsnd->pcm.streams =
> >- g_new0(VirtIOSoundPCMStream *, vsnd->snd_conf.streams);
> >- vsnd->pcm.pcm_params =
> >- g_new0(virtio_snd_pcm_set_params, vsnd->snd_conf.streams);
> >-
> > virtio_init(vdev, VIRTIO_ID_SOUND, sizeof(virtio_snd_config));
> > virtio_add_feature(&vsnd->features, VIRTIO_F_VERSION_1);
> >
> >- /* set default params for all streams */
> >- default_params.features = 0;
> >- default_params.buffer_bytes = cpu_to_le32(8192);
> >- default_params.period_bytes = cpu_to_le32(2048);
> >- default_params.channels = 2;
> >- default_params.format = VIRTIO_SND_PCM_FMT_S16;
> >- default_params.rate = VIRTIO_SND_PCM_RATE_48000;
> > vsnd->queues[VIRTIO_SND_VQ_CONTROL] =
> > virtio_add_queue(vdev, 64, virtio_snd_handle_ctrl);
> > vsnd->queues[VIRTIO_SND_VQ_EVENT] =
> >@@ -1097,28 +1137,6 @@ static void virtio_snd_realize(DeviceState *dev,
> >Error **errp)
> > virtio_add_queue(vdev, 64, virtio_snd_handle_rx_xfer);
> > QTAILQ_INIT(&vsnd->cmdq);
> > QSIMPLEQ_INIT(&vsnd->invalid);
> >-
> >- for (uint32_t i = 0; i < vsnd->snd_conf.streams; i++) {
> >- status = virtio_snd_set_pcm_params(vsnd, i, &default_params);
> >- if (status != cpu_to_le32(VIRTIO_SND_S_OK)) {
> >- error_setg(errp,
> >- "Can't initialize stream params, device responded
> >with %s.",
> >- print_code(status));
> >- goto error_cleanup;
> >- }
> >- status = virtio_snd_pcm_prepare(vsnd, i);
> >- if (status != cpu_to_le32(VIRTIO_SND_S_OK)) {
> >- error_setg(errp,
> >- "Can't prepare streams, device responded with %s.",
> >- print_code(status));
> >- goto error_cleanup;
> >- }
> >- }
> >-
> >- return;
> >-
> >-error_cleanup:
> >- virtio_snd_unrealize(dev);
> > }
> >
> > static inline void update_latency(VirtIOSoundPCMStream *s, size_t used)
> >@@ -1167,7 +1185,7 @@ static void virtio_snd_pcm_out_cb(void *data, int
> >available)
> > if (!virtio_queue_ready(buffer->vq)) {
> > return;
> > }
> >- if (!stream->active) {
> >+ if (!(stream->state & VSND_PCMSTREAM_STATE_F_ACTIVE)) {
> > /* Stream has stopped, so do not perform audio_be_write. */
> > return_tx_buffer(stream, buffer);
> > continue;
> >@@ -1261,7 +1279,7 @@ static void virtio_snd_pcm_in_cb(void *data, int
> >available)
> > if (!virtio_queue_ready(buffer->vq)) {
> > return;
> > }
> >- if (!stream->active) {
> >+ if (!(stream->state & VSND_PCMSTREAM_STATE_F_ACTIVE)) {
> > /* Stream has stopped, so do not perform audio_be_read. */
> > return_rx_buffer(stream, buffer);
> > continue;
> >@@ -1334,17 +1352,16 @@ static void virtio_snd_unrealize(DeviceState *dev)
> > qemu_del_vm_change_state_handler(vsnd->vmstate);
> > trace_virtio_snd_unrealize(vsnd);
> >
> >- if (vsnd->pcm.streams) {
> >+ if (vsnd->streams) {
> >+ virtio_snd_process_cmdq(vsnd);
> > for (uint32_t i = 0; i < vsnd->snd_conf.streams; i++) {
> >- stream = vsnd->pcm.streams[i];
> >- if (stream) {
> >- virtio_snd_process_cmdq(stream->s);
> >- virtio_snd_pcm_close(stream);
> >+ stream = &vsnd->streams[i];
> >+ if (stream->state & VSND_PCMSTREAM_STATE_F_PREPARED) {
> >+ virtio_snd_pcm_flush(stream);
> > }
> >+ virtio_snd_pcm_close(stream);
> > }
> >- g_free(vsnd->pcm.streams);
> > }
> >- g_free(vsnd->pcm.pcm_params);
> > g_free(vsnd->streams);
> > vsnd->streams = NULL;
> > virtio_delete_queue(vsnd->queues[VIRTIO_SND_VQ_CONTROL]);
> >@@ -1378,6 +1395,9 @@ static void virtio_snd_reset(VirtIODevice *vdev)
> > VirtIOSoundPCMStream *stream = &vsnd->streams[i];
> > VirtIOSoundPCMBuffer *buffer;
> >
> >+ virtio_snd_pcm_close(stream);
> >+ stream->state = VSND_PCMSTREAM_STATE_UNINITIALIZED;
> >+
> > while ((buffer = QSIMPLEQ_FIRST(&stream->queue))) {
> > QSIMPLEQ_REMOVE_HEAD(&stream->queue, entry);
> > virtio_snd_pcm_buffer_free(buffer);
> >diff --git a/include/hw/audio/virtio-snd.h b/include/hw/audio/virtio-snd.h
> >index 41c63b3f23b..72ef34e0976 100644
> >--- a/include/hw/audio/virtio-snd.h
> >+++ b/include/hw/audio/virtio-snd.h
> >@@ -75,8 +75,6 @@ typedef struct VirtIOSoundPCMStream VirtIOSoundPCMStream;
> >
> > typedef struct virtio_snd_ctrl_command virtio_snd_ctrl_command;
> >
> >-typedef struct VirtIOSoundPCM VirtIOSoundPCM;
> >-
> > typedef struct VirtIOSoundPCMBuffer VirtIOSoundPCMBuffer;
> >
> > /*
> >@@ -121,31 +119,18 @@ struct VirtIOSoundPCMBuffer {
> > uint8_t data[];
> > };
> >
> >-struct VirtIOSoundPCM {
> >- /*
> >- * PCM parameters are a separate field instead of a VirtIOSoundPCMStream
> >- * field, because the operation of PCM control requests is first
> >- * VIRTIO_SND_R_PCM_SET_PARAMS and then VIRTIO_SND_R_PCM_PREPARE; this
> >- * means that some times we get parameters without having an allocated
> >- * stream yet.
> >- */
> >- virtio_snd_pcm_set_params *pcm_params;
> >- VirtIOSoundPCMStream **streams;
> >-};
> >-
> > struct VirtIOSoundPCMStream {
> > virtio_snd_pcm_info info;
> > virtio_snd_pcm_set_params params;
> >+ uint32_t state;
> > /* channel position values (VIRTIO_SND_CHMAP_XXX) */
> > uint8_t positions[VIRTIO_SND_CHMAP_MAX_SIZE];
> > VirtIOSound *s;
> >- bool flushing;
>
> Spurious change: this should be a separate patch.
Sure, I'll split this one in v4.
>
> > audsettings as;
> > union {
> > SWVoiceIn *in;
> > SWVoiceOut *out;
> > } voice;
> >- bool active;
> > uint32_t latency_bytes;
> > QSIMPLEQ_HEAD(, VirtIOSoundPCMBuffer) queue;
> > };
> >@@ -212,7 +197,6 @@ struct VirtIOSound {
> >
> > VirtQueue *queues[VIRTIO_SND_VQ_MAX];
> > uint64_t features;
> >- VirtIOSoundPCM pcm;
> > VirtIOSoundPCMStream *streams;
> > AudioBackend *audio_be;
> > VMChangeStateEntry *vmstate;
> >--
> >2.47.3
> >