[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH v2 35/49] audio: api for mixeng code free backends
From: |
Kővágó, Zoltán |
Subject: |
[Qemu-devel] [PATCH v2 35/49] audio: api for mixeng code free backends |
Date: |
Fri, 21 Aug 2015 17:37:31 +0200 |
Signed-off-by: Kővágó, Zoltán <address@hidden>
---
audio/audio.c | 209 ++++++++++++++++++++++++++++++++++++++++++++++++-
audio/audio_int.h | 41 ++++++++--
audio/audio_template.h | 1 +
3 files changed, 241 insertions(+), 10 deletions(-)
diff --git a/audio/audio.c b/audio/audio.c
index 013d980..f24d0a1 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -544,6 +544,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)
*/
@@ -1005,6 +1024,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;
@@ -1052,7 +1096,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);
+ }
if (audio_bug(AUDIO_FUNC, hw->rpos >= hw->samples)) {
dolog("rpos=%zu samples=%zu played=%zu\n",
hw->rpos, hw->samples, played);
@@ -1110,6 +1158,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;
@@ -1118,7 +1195,12 @@ static void audio_run_in (AudioState *s)
SWVoiceIn *sw;
size_t captured, min;
- 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));
+ }
min = audio_pcm_hw_find_min_in (hw);
hw->total_samples_captured += captured - min;
@@ -1210,12 +1292,135 @@ 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;
diff --git a/audio/audio_int.h b/audio/audio_int.h
index a3bf79e..469fe5e 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -63,6 +63,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;
@@ -85,6 +87,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;
@@ -143,17 +147,38 @@ struct audio_driver {
};
struct audio_pcm_ops {
- int (*init_out)(HWVoiceOut *hw, struct audsettings *as, void *drv_opaque);
- void (*fini_out)(HWVoiceOut *hw);
- int (*run_out) (HWVoiceOut *hw, int live);
- int (*ctl_out) (HWVoiceOut *hw, int cmd, ...);
+ int (*init_out)(HWVoiceOut *hw, audsettings *as, void *drv_opaque);
+ void (*fini_out)(HWVoiceOut *hw);
+ int (*run_out) (HWVoiceOut *hw, int live);
+ 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 (*run_in) (HWVoiceIn *hw);
- int (*ctl_in) (HWVoiceIn *hw, int cmd, ...);
+ int (*init_in) (HWVoiceIn *hw, audsettings *as, void *drv_opaque);
+ void (*fini_in) (HWVoiceIn *hw);
+ int (*run_in) (HWVoiceIn *hw);
+ 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 5e28aea..f157695 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;
}
--
2.5.0
- [Qemu-devel] [PATCH v2 25/49] audio: add audiodev properties to frontends, (continued)
- [Qemu-devel] [PATCH v2 25/49] audio: add audiodev properties to frontends, Kővágó, Zoltán, 2015/08/21
- [Qemu-devel] [PATCH v2 24/49] audio: basic support for multi backend audio, Kővágó, Zoltán, 2015/08/21
- [Qemu-devel] [PATCH v2 29/49] paaudio: properly disconnect streams in fini_*, Kővágó, Zoltán, 2015/08/21
- [Qemu-devel] [PATCH v2 27/49] paaudio: do not create multiple connections to the same server, Kővágó, Zoltán, 2015/08/21
- [Qemu-devel] [PATCH v2 28/49] paaudio: do not move stream when sink/source name is specified, Kővágó, Zoltán, 2015/08/21
- [Qemu-devel] [PATCH v2 31/49] audio: do not run each backend in audio_run, Kővágó, Zoltán, 2015/08/21
- [Qemu-devel] [PATCH v2 32/49] paaudio: fix playback glitches, Kővágó, Zoltán, 2015/08/21
- [Qemu-devel] [PATCH v2 33/49] audio: remove read and write pcm_ops, Kővágó, Zoltán, 2015/08/21
- [Qemu-devel] [PATCH v2 26/49] audio: audiodev= parameters no longer optional when -audiodev present, Kővágó, Zoltán, 2015/08/21
- [Qemu-devel] [PATCH v2 30/49] audio: remove audio_MIN, audio_MAX, Kővágó, Zoltán, 2015/08/21
- [Qemu-devel] [PATCH v2 35/49] audio: api for mixeng code free backends,
Kővágó, Zoltán <=
- [Qemu-devel] [PATCH v2 37/49] coreaudio: port to the new audio backend api, Kővágó, Zoltán, 2015/08/21
- [Qemu-devel] [PATCH v2 39/49] noaudio: port to the new audio backend api, Kővágó, Zoltán, 2015/08/21
- [Qemu-devel] [PATCH v2 34/49] audio: use size_t where makes sense, Kővágó, Zoltán, 2015/08/21
- [Qemu-devel] [PATCH v2 38/49] dsoundaudio: port to the new audio backend api, Kővágó, Zoltán, 2015/08/21
- [Qemu-devel] [PATCH v2 40/49] ossaudio: port to the new audio backend api, Kővágó, Zoltán, 2015/08/21
- [Qemu-devel] [PATCH v2 42/49] sdlaudio: port to the new audio backend api, Kővágó, Zoltán, 2015/08/21
- [Qemu-devel] [PATCH v2 44/49] wavaudio: port to the new audio backend api, Kővágó, Zoltán, 2015/08/21
- [Qemu-devel] [PATCH v2 45/49] audio: remove remains of the old backend api, Kővágó, Zoltán, 2015/08/21
- [Qemu-devel] [PATCH v2 41/49] paaudio: port to the new audio backend api, Kővágó, Zoltán, 2015/08/21
- [Qemu-devel] [PATCH v2 36/49] alsaaudio: port to the new audio backend api, Kővágó, Zoltán, 2015/08/21