[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[RFC PATCH 19/27] virtio-snd: Add callback for SWVoiceOut
From: |
Shreyansh Chouhan |
Subject: |
[RFC PATCH 19/27] virtio-snd: Add callback for SWVoiceOut |
Date: |
Thu, 29 Apr 2021 17:34:37 +0530 |
Added the callback for writing audio using AUD_write. The callback uses
two helper functions for reading the buffers from the streams and
handling the buffers that were written. initialized the
SWVoiceOut using this callback.
Signed-off-by: Shreyansh Chouhan <chouhan.shreyansh2702@gmail.com>
---
hw/audio/virtio-snd.c | 171 ++++++++++++++++++++++++++++++++++++++++--
1 file changed, 165 insertions(+), 6 deletions(-)
diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index d0ab19a04a..e5042caf9c 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -468,6 +468,165 @@ static int
virtio_snd_pcm_get_nelems(virtio_snd_pcm_stream *st)
+ !!(st->buffer_bytes % st->period_bytes);
}
+/*
+ * Get the size in bytes of the buffer that still has to be written.
+ *
+ * @st: virtio sound pcm stream
+ */
+static int virtio_snd_pcm_get_pending_bytes(virtio_snd_pcm_stream *st)
+{
+ int pending = st->r_pos - st->w_pos;
+ return pending < 0 ? pending + st->buffer_bytes : pending;
+}
+
+/*
+ * Get data from a stream of the virtio sound device.
+ *
+ * @st: VirtIOSound card stream
+ * @offset: Start reading from this offseta in the stream (in bytes)
+ * @buffer: Write to this buffer
+ * @size: The number of bytes to read
+ */
+static void virtio_snd_pcm_get_buf(virtio_snd_pcm_stream *st, uint32_t offset,
+ void *buffer, uint32_t size)
+{
+ int nelems = virtio_snd_pcm_get_nelems(st);
+ int i = 0;
+ while (offset > st->period_bytes) {
+ offset -= st->period_bytes;
+ i++;
+ i %= nelems;
+ }
+
+
+ /*
+ * If the size spans beyond the current virtqueue element, read everything
+ * from the current virtqueue element and move to the next element. Repeat
+ * until we have read the required size.
+ */
+ while (size) {
+ int remaining = iov_size(st->elems[i]->out_sg, st->elems[i]->out_num)
+ - sizeof(virtio_snd_pcm_xfer) - offset;
+ int to_read = MIN(remaining, size), wpos = 0;
+ size_t sz;
+ sz = iov_to_buf(st->elems[i]->out_sg, st->elems[i]->out_num,
+ sizeof(virtio_snd_pcm_xfer) + offset, buffer + wpos,
+ to_read);
+
+ assert(sz == to_read);
+
+ offset = 0;
+ size -= to_read;
+ wpos += to_read;
+ i++;
+ i %= nelems;
+ }
+}
+
+/*
+ * Handle a buffer after it has been written by AUD_write.
+ * It writes the status for the I/O messages that have been completed and
+ * marks the tx virtqueue elmenets as used. It notifies the device
+ * about I/O completion.
+ *
+ * @st: VirtIOSound card stream
+ * @size: Size that was written by AUD_write
+ * If size = 0, write for the last element failed
+ */
+static void virtio_snd_pcm_handle_buf_written(virtio_snd_pcm_stream *st,
+ uint32_t size)
+{
+ int offset = st->w_pos, i = 0;
+ int nelems = virtio_snd_pcm_get_nelems(st);
+
+ while (offset >= st->period_bytes) {
+ offset -= st->period_bytes;
+ i++;
+ i %= nelems;
+ }
+
+ virtio_snd_pcm_status status;
+ size_t sz;
+ if (!size) {
+ status.status = VIRTIO_SND_S_IO_ERR;
+ status.latency_bytes = 0;
+
+ sz = iov_from_buf(st->elems[i]->in_sg, st->elems[i]->in_num, 0,
+ &status, sizeof(status));
+ assert(sz == sizeof(virtio_snd_pcm_status));
+
+ int push_size = iov_size(st->elems[i]->out_sg, st->elems[i]->out_num)
+ + sizeof(virtio_snd_pcm_status);
+
+ virtqueue_push(st->s->tx_vq, st->elems[i], push_size);
+ return;
+ }
+
+ status.status = VIRTIO_SND_S_OK;
+ status.latency_bytes = 0;
+
+ /*
+ * If the written size spans beyond current element, update the status for
+ * the current element, mark it as used and push it back on the tx
+ * virtqueue. Notify the device about the I/O completion. Repeat until
+ * the required bytes are handled.
+ */
+ while (size) {
+ int curr_elem_size = iov_size(st->elems[i]->out_sg,
st->elems[i]->out_num)
+ - sizeof(virtio_snd_pcm_xfer) - offset;
+ if (size >= curr_elem_size) {
+ sz = iov_from_buf(st->elems[i]->in_sg, st->elems[i]->in_num, 0,
+ &status, sizeof(status));
+ assert(sz == sizeof(virtio_snd_pcm_status));
+
+ int push_size = sizeof(virtio_snd_pcm_xfer) + curr_elem_size
+ + offset + sizeof(virtio_snd_pcm_status);
+
+ virtqueue_push(st->s->tx_vq, st->elems[i], push_size);
+ virtio_notify(VIRTIO_DEVICE(st->s), st->s->tx_vq);
+ g_free(st->elems[i]);
+ st->elems[i] = NULL;
+ size -= curr_elem_size;
+ virtio_snd_log("remains: %d\n", size);
+ st->w_pos += curr_elem_size;
+ st->w_pos %= st->buffer_bytes + 1;
+ i++;
+ i %= nelems;
+ offset = 0;
+ } else {
+ st->w_pos += size;
+ st->w_pos %= st->buffer_bytes + 1;
+ break;
+ }
+ }
+}
+
+/*
+ * Callback for AUD_open_out.
+ * Reads a buffer from the VirtIOSound card stream and writes it
+ * using AUD_write.
+ *
+ * @opaque: VirtIOSound card stream
+ * @free: Size in bytes that can be written via AUD_write
+ */
+static void virtio_snd_output_cb(void *opaque, int free)
+{
+ int to_play, pending;
+ virtio_snd_pcm_stream *st = opaque;
+
+ pending = virtio_snd_pcm_get_pending_bytes(st);
+ to_play = MIN(free, pending);
+
+ while (to_play) {
+ uint8_t *mixbuf = g_malloc0(to_play);
+ virtio_snd_pcm_get_buf(st, st->w_pos, mixbuf, to_play);
+ int wbytes = AUD_write(st->voice.out, mixbuf, to_play);
+ to_play -= wbytes;
+ virtio_snd_pcm_handle_buf_written(st, wbytes);
+ g_free(mixbuf);
+ }
+}
+
/*
* Prepares a VirtIOSound card stream.
* Returns a virtio sound status (VIRTIO_SND_S_*).
@@ -523,12 +682,12 @@ static uint32_t virtio_snd_pcm_prepare_impl(VirtIOSound
*s, uint32_t stream)
virtio_snd_get_qemu_audsettings(&as, s->pcm_params[stream]);
if (st->direction == VIRTIO_SND_D_OUTPUT) {
- /* st->voice.out = AUD_open_out(&s->card,
- * st->voice.out,
- * "virtio_snd_card",
- * st,
- * virtio_snd_output_cb, &as);
- */
+ st->voice.out = AUD_open_out(&s->card,
+ st->voice.out,
+ "virtio_snd_card",
+ st,
+ virtio_snd_output_cb, &as);
+
} else {
/* st->voice.in = AUD_open_in(&s->card,
* st->voice.in,
--
2.25.1
- [RFC PATCH 13/27] virtio-snd: Add VIRTIO_SND_R_JACK_INFO handler, (continued)
- [RFC PATCH 13/27] virtio-snd: Add VIRTIO_SND_R_JACK_INFO handler, Shreyansh Chouhan, 2021/04/29
- [RFC PATCH 15/27] virtio-snd: Add VIRTIO_SND_R_PCM_INFO handler, Shreyansh Chouhan, 2021/04/29
- [RFC PATCH 14/27] virtio-snd: Add stub for VIRTIO_SND_R_JACK_REMAP handler, Shreyansh Chouhan, 2021/04/29
- [RFC PATCH 18/27] virtio-snd: Add default configs to realize fn, Shreyansh Chouhan, 2021/04/29
- [RFC PATCH 16/27] virtio-snd: Add VIRITO_SND_R_PCM_SET_PARAMS handle, Shreyansh Chouhan, 2021/04/29
- [RFC PATCH 21/27] virtio-snd: Add VIRTIO_SND_R_PCM_STOP handler, Shreyansh Chouhan, 2021/04/29
- [RFC PATCH 20/27] virtio-snd: Add VIRITO_SND_R_PCM_START handler, Shreyansh Chouhan, 2021/04/29
- [RFC PATCH 17/27] virtio-snd: Add VIRTIO_SND_R_PCM_PREPARE handler, Shreyansh Chouhan, 2021/04/29
- [RFC PATCH 19/27] virtio-snd: Add callback for SWVoiceOut,
Shreyansh Chouhan <=
- [RFC PATCH 23/27] virtio-snd: Replaced goto with if else, Shreyansh Chouhan, 2021/04/29
- [RFC PATCH 22/27] virtio-snd: Add VIRTIO_SND_R_PCM_RELEASE handler, Shreyansh Chouhan, 2021/04/29
- [RFC PATCH 25/27] virtio-snd: Add tx vq and handler, Shreyansh Chouhan, 2021/04/29
- [RFC PATCH 24/27] virtio-snd: Add code to device unrealize function, Shreyansh Chouhan, 2021/04/29
- [RFC PATCH 27/27] virtio-snd: Add rx vq and stub handler, Shreyansh Chouhan, 2021/04/29
- [RFC PATCH 26/27] virtio-snd: Add event vq and a handler stub, Shreyansh Chouhan, 2021/04/29
- Re: [RFC PATCH 00/27] Virtio sound card implementation, no-reply, 2021/04/29
- Re: [RFC PATCH 00/27] Virtio sound card implementation, Gerd Hoffmann, 2021/04/30