[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH v3 26/50] audio: api for mixeng code free backends
From: |
Kővágó, Zoltán |
Subject: |
[Qemu-devel] [PATCH v3 26/50] audio: api for mixeng code free backends |
Date: |
Thu, 17 Jan 2019 00:36:59 +0100 |
Signed-off-by: Kővágó, Zoltán <address@hidden>
---
audio/audio_int.h | 41 ++++++--
audio/audio_template.h | 1 +
audio/audio.c | 211 ++++++++++++++++++++++++++++++++++++++++-
3 files changed, 245 insertions(+), 8 deletions(-)
diff --git a/audio/audio_int.h b/audio/audio_int.h
index 9dcdf541fb..056c63d45c 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -64,6 +64,8 @@ typedef struct HWVoiceOut {
uint64_t ts_helper;
struct st_sample *mix_buf;
+ void *buf_emul;
+ size_t pos_emul, pending_emul, size_emul;
size_t samples;
QLIST_HEAD (sw_out_listhead, SWVoiceOut) sw_head;
@@ -86,6 +88,8 @@ typedef struct HWVoiceIn {
uint64_t ts_helper;
struct st_sample *conv_buf;
+ void *buf_emul;
+ size_t pos_emul, pending_emul, size_emul;
size_t samples;
QLIST_HEAD (sw_in_listhead, SWVoiceIn) sw_head;
@@ -146,17 +150,42 @@ struct audio_driver {
};
struct audio_pcm_ops {
- int (*init_out)(HWVoiceOut *hw, struct audsettings *as, void *drv_opaque);
- void (*fini_out)(HWVoiceOut *hw);
+ int (*init_out)(HWVoiceOut *hw, audsettings *as, void *drv_opaque);
+ void (*fini_out)(HWVoiceOut *hw);
size_t (*run_out)(HWVoiceOut *hw, size_t live);
- int (*ctl_out) (HWVoiceOut *hw, int cmd, ...);
+ size_t (*write) (HWVoiceOut *hw, void *buf, size_t size);
+ /*
+ * get a buffer that after later can be passed to put_buffer_out; optional
+ * returns the buffer, and writes it's size to size (in bytes)
+ * this is unrelated to the above buffer_size_out function
+ */
+ void *(*get_buffer_out)(HWVoiceOut *hw, size_t *size);
+ /*
+ * put back the buffer returned by get_buffer_out; optional
+ * buf must be equal the pointer returned by get_buffer_out,
+ * size may be smaller
+ */
+ size_t (*put_buffer_out)(HWVoiceOut *hw, void *buf, size_t size);
+ int (*ctl_out) (HWVoiceOut *hw, int cmd, ...);
- int (*init_in) (HWVoiceIn *hw, struct audsettings *as, void *drv_opaque);
- void (*fini_in) (HWVoiceIn *hw);
+ int (*init_in) (HWVoiceIn *hw, audsettings *as, void *drv_opaque);
+ void (*fini_in) (HWVoiceIn *hw);
size_t (*run_in)(HWVoiceIn *hw);
- int (*ctl_in) (HWVoiceIn *hw, int cmd, ...);
+ size_t (*read) (HWVoiceIn *hw, void *buf, size_t size);
+ void *(*get_buffer_in)(HWVoiceIn *hw, size_t *size);
+ void (*put_buffer_in)(HWVoiceIn *hw, void *buf, size_t size);
+ int (*ctl_in) (HWVoiceIn *hw, int cmd, ...);
};
+void *audio_generic_get_buffer_in(HWVoiceIn *hw, size_t *size);
+void audio_generic_put_buffer_in(HWVoiceIn *hw, void *buf, size_t size);
+void *audio_generic_get_buffer_out(HWVoiceOut *hw, size_t *size);
+size_t audio_generic_put_buffer_out(HWVoiceOut *hw, void *buf, size_t size);
+size_t audio_generic_put_buffer_out_nowrite(HWVoiceOut *hw, void *buf,
+ size_t size);
+size_t audio_generic_write(HWVoiceOut *hw, void *buf, size_t size);
+size_t audio_generic_read(HWVoiceIn *hw, void *buf, size_t size);
+
struct capture_callback {
struct audio_capture_ops ops;
void *opaque;
diff --git a/audio/audio_template.h b/audio/audio_template.h
index 9a8aa1eebf..fcab583cfc 100644
--- a/audio/audio_template.h
+++ b/audio/audio_template.h
@@ -71,6 +71,7 @@ static void glue(audio_init_nb_voices_, TYPE)(AudioState *s,
static void glue (audio_pcm_hw_free_resources_, TYPE) (HW *hw)
{
+ g_free(hw->buf_emul);
g_free (HWBUF);
HWBUF = NULL;
}
diff --git a/audio/audio.c b/audio/audio.c
index 33b11e4feb..f4d538618f 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -574,6 +574,25 @@ size_t audio_pcm_hw_clip_out(HWVoiceOut *hw, void *pcm_buf,
return clipped;
}
+static void audio_pcm_hw_clip_out2(HWVoiceOut *hw, void *pcm_buf, size_t len)
+{
+ size_t clipped = 0;
+ size_t pos = hw->rpos;
+
+ while (len) {
+ st_sample *src = hw->mix_buf + pos;
+ uint8_t *dst = advance (pcm_buf, clipped << hw->info.shift);
+ size_t samples_till_end_of_buf = hw->samples - pos;
+ size_t samples_to_clip = MIN(len, samples_till_end_of_buf);
+
+ hw->clip (dst, src, samples_to_clip);
+
+ pos = (pos + samples_to_clip) % hw->samples;
+ len -= samples_to_clip;
+ clipped += samples_to_clip;
+ }
+}
+
/*
* Soft voice (capture)
*/
@@ -1051,6 +1070,31 @@ static void audio_capture_mix_and_clear(HWVoiceOut *hw,
size_t rpos,
mixeng_clear(hw->mix_buf, samples - n);
}
+static size_t audio_pcm_hw_run_out(HWVoiceOut *hw, size_t live)
+{
+ size_t clipped = 0;
+
+ while (live) {
+ size_t size, decr, proc;
+ void *buf = hw->pcm_ops->get_buffer_out(hw, &size);
+
+ decr = MIN(size >> hw->info.shift, live);
+ audio_pcm_hw_clip_out2(hw, buf, decr);
+ proc = hw->pcm_ops->put_buffer_out(hw, buf, decr << hw->info.shift) >>
+ hw->info.shift;
+
+ live -= proc;
+ clipped += proc;
+ hw->rpos = (hw->rpos + proc) % hw->samples;
+
+ if (proc == 0 || proc < decr) {
+ break;
+ }
+ }
+
+ return clipped;
+}
+
static void audio_run_out (AudioState *s)
{
HWVoiceOut *hw = NULL;
@@ -1098,7 +1142,11 @@ static void audio_run_out (AudioState *s)
}
prev_rpos = hw->rpos;
- played = hw->pcm_ops->run_out (hw, live);
+ if (hw->pcm_ops->run_out) {
+ played = hw->pcm_ops->run_out(hw, live);
+ } else {
+ played = audio_pcm_hw_run_out(hw, live);
+ }
replay_audio_out(&played);
if (audio_bug(__func__, hw->rpos >= hw->samples)) {
dolog("hw->rpos=%zu hw->samples=%zu played=%zu\n",
@@ -1157,6 +1205,35 @@ static void audio_run_out (AudioState *s)
}
}
+static size_t audio_pcm_hw_run_in(HWVoiceIn *hw, size_t samples)
+{
+ size_t conv = 0;
+
+ while (samples) {
+ size_t proc;
+ size_t size = samples << hw->info.shift;
+ void *buf = hw->pcm_ops->get_buffer_in(hw, &size);
+
+ assert((size & hw->info.align) == 0);
+ if (size == 0) {
+ hw->pcm_ops->put_buffer_in(hw, buf, size);
+ break;
+ }
+
+ proc = MIN(size >> hw->info.shift,
+ hw->samples - hw->wpos);
+
+ hw->conv(hw->conv_buf + hw->wpos, buf, proc);
+ hw->wpos = (hw->wpos + proc) % hw->samples;
+
+ samples -= proc;
+ conv += proc;
+ hw->pcm_ops->put_buffer_in(hw, buf, proc << hw->info.shift);
+ }
+
+ return conv;
+}
+
static void audio_run_in (AudioState *s)
{
HWVoiceIn *hw = NULL;
@@ -1166,7 +1243,12 @@ static void audio_run_in (AudioState *s)
size_t captured = 0, min;
if (replay_mode != REPLAY_MODE_PLAY) {
- captured = hw->pcm_ops->run_in(hw);
+ if (hw->pcm_ops->run_in) {
+ captured = hw->pcm_ops->run_in(hw);
+ } else {
+ captured = audio_pcm_hw_run_in(
+ hw, hw->samples - audio_pcm_hw_get_live_in(hw));
+ }
}
replay_audio_in(&captured, hw->conv_buf, &hw->wpos, hw->samples);
@@ -1260,12 +1342,137 @@ void audio_run(AudioState *s, const char *msg)
#endif
}
+void *audio_generic_get_buffer_in(HWVoiceIn *hw, size_t *size)
+{
+ ssize_t start;
+
+ if (unlikely(!hw->buf_emul)) {
+ size_t calc_size = hw->samples << hw->info.shift;
+ hw->buf_emul = g_malloc(calc_size);
+ hw->size_emul = calc_size;
+ hw->pos_emul = hw->pending_emul = 0;
+ }
+
+ while (hw->pending_emul < hw->size_emul) {
+ size_t read_len = MIN(hw->size_emul - hw->pos_emul,
+ hw->size_emul - hw->pending_emul);
+ size_t read = hw->pcm_ops->read(hw, hw->buf_emul + hw->pos_emul,
+ read_len);
+ hw->pending_emul += read;
+ if (read < read_len) {
+ break;
+ }
+ }
+
+ start = ((ssize_t) hw->pos_emul) - hw->pending_emul;
+ if (start < 0) {
+ start += hw->size_emul;
+ }
+ assert(start >= 0 && start < hw->size_emul);
+
+ *size = MIN(hw->pending_emul, hw->size_emul - start);
+ return hw->buf_emul + start;
+}
+
+void audio_generic_put_buffer_in(HWVoiceIn *hw, void *buf, size_t size)
+{
+ assert(size <= hw->pending_emul);
+ hw->pending_emul -= size;
+}
+
+void *audio_generic_get_buffer_out(HWVoiceOut *hw, size_t *size)
+{
+ if (unlikely(!hw->buf_emul)) {
+ size_t calc_size = hw->samples << hw->info.shift;
+
+ hw->buf_emul = g_malloc(calc_size);
+ hw->size_emul = calc_size;
+ hw->pos_emul = hw->pending_emul = 0;
+ }
+
+ *size = MIN(hw->size_emul - hw->pending_emul,
+ hw->size_emul - hw->pos_emul);
+ return hw->buf_emul + hw->pos_emul;
+}
+
+size_t audio_generic_put_buffer_out_nowrite(HWVoiceOut *hw, void *buf,
+ size_t size)
+{
+ assert(buf == hw->buf_emul + hw->pos_emul &&
+ size + hw->pending_emul <= hw->size_emul);
+
+ hw->pending_emul += size;
+ hw->pos_emul = (hw->pos_emul + size) % hw->size_emul;
+
+ return size;
+}
+
+size_t audio_generic_put_buffer_out(HWVoiceOut *hw, void *buf, size_t size)
+{
+ audio_generic_put_buffer_out_nowrite(hw, buf, size);
+
+ while (hw->pending_emul) {
+ size_t write_len, written;
+ ssize_t start = ((ssize_t) hw->pos_emul) - hw->pending_emul;
+ if (start < 0) {
+ start += hw->size_emul;
+ }
+ assert(start >= 0 && start < hw->size_emul);
+
+ write_len = MIN(hw->pending_emul, hw->size_emul - start);
+
+ written = hw->pcm_ops->write(hw, hw->buf_emul + start, write_len);
+ hw->pending_emul -= written;
+
+ if (written < write_len) {
+ break;
+ }
+ }
+
+ /*
+ * fake we have written everything. non-written data remain in
pending_emul,
+ * so we do not have to clip them multiple times
+ */
+ return size;
+}
+
+size_t audio_generic_write(HWVoiceOut *hw, void *buf, size_t size)
+{
+ size_t dst_size, copy_size;
+ void *dst = hw->pcm_ops->get_buffer_out(hw, &dst_size);
+ copy_size = MIN(size, dst_size);
+
+ memcpy(dst, buf, copy_size);
+ return hw->pcm_ops->put_buffer_out(hw, buf, copy_size);
+}
+
+size_t audio_generic_read(HWVoiceIn *hw, void *buf, size_t size)
+{
+ size_t dst_size, copy_size;
+ void *dst = hw->pcm_ops->get_buffer_in(hw, &dst_size);
+ copy_size = MIN(size, dst_size);
+
+ memcpy(dst, buf, copy_size);
+ hw->pcm_ops->put_buffer_in(hw, buf, copy_size);
+ return copy_size;
+}
+
+
static int audio_driver_init(AudioState *s, struct audio_driver *drv,
Audiodev *dev)
{
s->drv_opaque = drv->init(dev);
if (s->drv_opaque) {
+ if (!drv->pcm_ops->get_buffer_in) {
+ drv->pcm_ops->get_buffer_in = audio_generic_get_buffer_in;
+ drv->pcm_ops->put_buffer_in = audio_generic_put_buffer_in;
+ }
+ if (!drv->pcm_ops->get_buffer_out) {
+ drv->pcm_ops->get_buffer_out = audio_generic_get_buffer_out;
+ drv->pcm_ops->put_buffer_out = audio_generic_put_buffer_out;
+ }
+
audio_init_nb_voices_out(s, drv);
audio_init_nb_voices_in(s, drv);
s->drv = drv;
--
2.20.1
- [Qemu-devel] [PATCH v3 04/50] audio: -audiodev command line option basic implementation, (continued)
- [Qemu-devel] [PATCH v3 04/50] audio: -audiodev command line option basic implementation, Kővágó, Zoltán, 2019/01/16
- [Qemu-devel] [PATCH v3 32/50] paaudio: port to the new audio backend api, Kővágó, Zoltán, 2019/01/16
- [Qemu-devel] [PATCH v3 43/50] paaudio: get/put_buffer functions, Kővágó, Zoltán, 2019/01/16
- [Qemu-devel] [PATCH v3 35/50] wavaudio: port to the new audio backend api, Kővágó, Zoltán, 2019/01/16
- [Qemu-devel] [PATCH v3 46/50] audio: basic support for multichannel audio, Kővágó, Zoltán, 2019/01/16
- [Qemu-devel] [PATCH v3 44/50] audio: support more than two channels in volume setting, Kővágó, Zoltán, 2019/01/16
- [Qemu-devel] [PATCH v3 24/50] audio: remove read and write pcm_ops, Kővágó, Zoltán, 2019/01/16
- [Qemu-devel] [PATCH v3 45/50] audio: replace shift in audio_pcm_info with bytes_per_frame, Kővágó, Zoltán, 2019/01/16
- [Qemu-devel] [PATCH v3 37/50] audio: unify input and output mixeng buffer management, Kővágó, Zoltán, 2019/01/16
- [Qemu-devel] [PATCH v3 33/50] sdlaudio: port to the new audio backend api, Kővágó, Zoltán, 2019/01/16
- [Qemu-devel] [PATCH v3 26/50] audio: api for mixeng code free backends,
Kővágó, Zoltán <=
- [Qemu-devel] [PATCH v3 48/50] usb-audio: do not count on avail bytes actually available, Kővágó, Zoltán, 2019/01/16
- [Qemu-devel] [PATCH v3 41/50] audio: add mixeng option (documentation), Kővágó, Zoltán, 2019/01/16
- [Qemu-devel] [PATCH v3 27/50] alsaaudio: port to the new audio backend api, Kővágó, Zoltán, 2019/01/16
- [Qemu-devel] [PATCH v3 40/50] audio: split ctl_* functions into enable_* and volume_*, Kővágó, Zoltán, 2019/01/16
- [Qemu-devel] [PATCH v3 34/50] spiceaudio: port to the new audio backend api, Kővágó, Zoltán, 2019/01/16
- [Qemu-devel] [PATCH v3 42/50] audio: make mixeng optional, Kővágó, Zoltán, 2019/01/16
- [Qemu-devel] [PATCH v3 47/50] paaudio: channel-map option, Kővágó, Zoltán, 2019/01/16