From 60b63625cebd5ed3fd9522b46db9bd1a14c9663b Mon Sep 17 00:00:00 2001 From: Cuda-Chen Date: Wed, 30 Oct 2024 23:11:13 +0800 Subject: [PATCH] Add FSM of snd_pcm_* --- virtio-snd.c | 95 +++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 71 insertions(+), 24 deletions(-) diff --git a/virtio-snd.c b/virtio-snd.c index 1a2c79f..3121873 100644 --- a/virtio-snd.c +++ b/virtio-snd.c @@ -1,7 +1,7 @@ -#include -#include #include #include +#include +#include #define CNFA_IMPLEMENTATION #include "CNFA_sf.h" @@ -246,7 +246,9 @@ typedef struct { } virtio_snd_prop_t; static virtio_snd_config_t vsnd_configs[VSND_DEV_CNT_MAX]; -static virtio_snd_prop_t vsnd_props[VSND_DEV_CNT_MAX]; +static virtio_snd_prop_t vsnd_props[VSND_DEV_CNT_MAX] = { + [0 ... VSND_DEV_CNT_MAX - 1].pp.hdr.hdr.code = VIRTIO_SND_R_PCM_SET_PARAMS, +}; static int vsnd_dev_cnt = 0; typedef struct { @@ -372,12 +374,20 @@ static void virtio_snd_read_chmap_info_handler( static void virtio_snd_read_pcm_set_params(struct virtq_desc *vq_desc, const virtio_snd_query_info_t *query) { + virtio_snd_pcm_set_params_t *request = query; + uint32_t id = request->hdr.stream_id; /* TODO: detect current state of stream */ + uint32_t code = vsnd_props[id].pp.hdr.hdr.code; + if (code != VIRTIO_SND_R_PCM_RELEASE && + code != VIRTIO_SND_R_PCM_SET_PARAMS && + code != VIRTIO_SND_R_PCM_PREPARE) { + fprintf(stderr, + "virtio_snd_pcm_set_params with invalid previous state %#08x\n", + code); + return; + } /* TODO: check the valiability of buffer_bytes, period_bytes, channel_min, * and channel_max */ - - virtio_snd_pcm_set_params_t *request = query; - uint32_t id = request->hdr.stream_id; vsnd_props[id].pp.hdr.hdr.code = VIRTIO_SND_R_PCM_SET_PARAMS; vsnd_props[id].pp.buffer_bytes = request->buffer_bytes; vsnd_props[id].pp.period_bytes = request->period_bytes; @@ -395,6 +405,17 @@ static void virtio_snd_read_pcm_prepare(struct virtq_desc *vq_desc, { virtio_snd_pcm_hdr_t *request = query; uint32_t stream_id = request->stream_id; + uint32_t code = vsnd_props[stream_id].pp.hdr.hdr.code; + if (code != VIRTIO_SND_R_PCM_RELEASE && + code != VIRTIO_SND_R_PCM_SET_PARAMS && + code != VIRTIO_SND_R_PCM_PREPARE) { + fprintf( + stderr, + "virtio_snd_read_pcm_prepare with invalid previous state %#08x\n", + code); + return; + } + vsnd_props[stream_id].pp.hdr.hdr.code = VIRTIO_SND_R_PCM_PREPARE; vsnd_props[stream_id].audio_host = CNFAInit(NULL, "semu-virtio-snd", virtio_snd_cb, 44100, 0, 1, 0, @@ -415,11 +436,21 @@ static void virtio_snd_read_pcm_prepare(struct virtq_desc *vq_desc, static void virtio_snd_read_pcm_start(struct virtq_desc *vq_desc, const virtio_snd_query_info_t *query) { - /* TODO: let application to set stream_id at will */ + virtio_snd_pcm_hdr_t *request = query; + uint32_t stream_id = request->stream_id; + uint32_t code = vsnd_props[stream_id].pp.hdr.hdr.code; + if (code != VIRTIO_SND_R_PCM_PREPARE && code != VIRTIO_SND_R_PCM_STOP) { + fprintf( + stderr, + "virtio_snd_read_pcm_start with previous invalide state %#08x\n", + code); + return; + } /* Control the callback to start playing */ /* TODO: add lock to avoid race condition */ pthread_mutex_lock(&virtio_snd_mutex); + vsnd_props[stream_id].pp.hdr.hdr.code = VIRTIO_SND_R_PCM_START; v.guest_playing = true; pthread_mutex_unlock(&virtio_snd_mutex); @@ -429,10 +460,20 @@ static void virtio_snd_read_pcm_start(struct virtq_desc *vq_desc, static void virtio_snd_read_pcm_stop(struct virtq_desc *vq_desc, const virtio_snd_query_info_t *query) { - /* TODO: let application to set stream_id at will */ + virtio_snd_pcm_hdr_t *request = query; + uint32_t stream_id = request->stream_id; + uint32_t code = vsnd_props[stream_id].pp.hdr.hdr.code; + if (code != VIRTIO_SND_R_PCM_START) { + fprintf(stderr, + "virtio_snd_read_pcm_stop with previous invalide state %#08x\n", + code); + return; + } + /* Control the callback to stop playing */ /* TODO: add lock to avoid race condition */ pthread_mutex_lock(&virtio_snd_mutex); + vsnd_props[stream_id].pp.hdr.hdr.code = VIRTIO_SND_R_PCM_STOP; v.guest_playing = false; pthread_mutex_lock(&virtio_snd_mutex); @@ -442,14 +483,22 @@ static void virtio_snd_read_pcm_stop(struct virtq_desc *vq_desc, static void virtio_snd_read_pcm_release(struct virtq_desc *vq_desc, const virtio_snd_query_info_t *query) { + virtio_snd_pcm_hdr_t *request = query; + uint32_t stream_id = request->stream_id; + uint32_t code = vsnd_props[stream_id].pp.hdr.hdr.code; + if (code != VIRTIO_SND_R_PCM_PREPARE && code != VIRTIO_SND_R_PCM_STOP) { + fprintf( + stderr, + "virtio_snd_read_pcm_release with previous invalide state %#08x\n", + code); + return; + } /* Control the callback to stop playing */ /* TODO: add lock to avoid race condition */ pthread_mutex_lock(&virtio_snd_mutex); v.guest_playing = false; pthread_mutex_unlock(&virtio_snd_mutex); - virtio_snd_pcm_hdr_t *request = query; - uint32_t stream_id = request->stream_id; vsnd_props[stream_id].pp.hdr.hdr.code = VIRTIO_SND_R_PCM_RELEASE; CNFAClose(vsnd_props[stream_id].audio_host); free(vsnd_props[stream_id].buf); @@ -482,23 +531,21 @@ static void virtio_snd_cb(struct CNFADriver *dev, vsnd_stream_sel_t *v_ptr = (vsnd_stream_sel_t *) dev->opaque; bool playing = v_ptr->guest_playing; - if(!playing) { - fprintf(stderr, "notplaying\n"); - return; - } + if (!playing) { + fprintf(stderr, "notplaying\n"); + return; + } - int channels = dev->channelsPlay; - for(int i = 0; i < framesp; i++ ) - { + int channels = dev->channelsPlay; + for (int i = 0; i < framesp; i++) { // Shift phase, so we run at 440 Hz (A4) - omega += ( 3.14159 * 2 * 440. ) / dev->spsPlay; + omega += (3.14159 * 2 * 440.) / dev->spsPlay; - // Make the 440 Hz tone at 10% volume and convert to short. - short value = sin( omega ) * 0.1 * 32767; + // Make the 440 Hz tone at 10% volume and convert to short. + short value = sin(omega) * 0.1 * 32767; int c; - for( c = 0; c < channels; c++ ) - { + for (c = 0; c < channels; c++) { *(out++) = value; } } @@ -827,10 +874,10 @@ static bool virtio_snd_reg_write(virtio_snd_state_t *vsnd, virtio_snd_desc_handler); break; case VSND_QUEUE_TX: - fprintf(stderr, "TX start\n"); + fprintf(stderr, "TX start\n"); /*virtio_queue_notify_handler(vsnd, value, virtio_snd_tx_desc_handler);*/ - fprintf(stderr, "TX end\n"); + fprintf(stderr, "TX end\n"); break; case VSND_QUEUE_EVT: fprintf(stderr, "EVT\n");