summarylogtreecommitdiffstats
path: root/pa-fixes.patch
diff options
context:
space:
mode:
Diffstat (limited to 'pa-fixes.patch')
-rw-r--r--pa-fixes.patch865
1 files changed, 0 insertions, 865 deletions
diff --git a/pa-fixes.patch b/pa-fixes.patch
deleted file mode 100644
index 65d046502c92..000000000000
--- a/pa-fixes.patch
+++ /dev/null
@@ -1,865 +0,0 @@
-From fa5f68de47d120b4f6a5f973f21567ef389b42ac Mon Sep 17 00:00:00 2001
-From: Geoffrey McRae <geoff@hostfission.com>
-Date: Tue, 8 May 2018 02:59:17 +1000
-Subject: [PATCH] PA fixes
-
----
- audio/audio.c | 5 +
- audio/audio_int.h | 2 +
- audio/paaudio.c | 635 +++++++++++++++++--------------------------
- hw/audio/hda-codec.c | 2 +
- 4 files changed, 264 insertions(+), 380 deletions(-)
-
-diff --git a/audio/audio.c b/audio/audio.c
-index 1ace47f510..253e470d12 100644
---- a/audio/audio.c
-+++ b/audio/audio.c
-@@ -2118,3 +2118,8 @@ void AUD_set_volume_in (SWVoiceIn *sw, int mute, uint8_t lvol, uint8_t rvol)
- }
- }
- }
-+
-+int64_t audio_get_timer_ticks(void)
-+{
-+ return conf.period.ticks;
-+}
-diff --git a/audio/audio_int.h b/audio/audio_int.h
-index 244b454012..19ba2d7aa4 100644
---- a/audio/audio_int.h
-+++ b/audio/audio_int.h
-@@ -210,6 +210,8 @@ extern const struct mixeng_volume nominal_volume;
- void audio_driver_register(audio_driver *drv);
- audio_driver *audio_driver_lookup(const char *name);
-
-+int64_t audio_get_timer_ticks(void);
-+
- void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as);
- void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len);
-
-diff --git a/audio/paaudio.c b/audio/paaudio.c
-index 949769774d..bd5a1781bf 100644
---- a/audio/paaudio.c
-+++ b/audio/paaudio.c
-@@ -1,16 +1,22 @@
- /* public domain */
- #include "qemu/osdep.h"
--#include "qemu-common.h"
-+#include "qemu/timer.h"
- #include "audio.h"
-
- #include <pulse/pulseaudio.h>
-
- #define AUDIO_CAP "pulseaudio"
-+#define DEBUG
- #include "audio_int.h"
--#include "audio_pt_int.h"
-
- typedef struct {
-- int samples;
-+ int buffer_size_out;
-+ int buffer_size_in;
-+ int tlength;
-+ int fragsize;
-+ int maxlength_in;
-+ int adjust_latency_out;
-+ int adjust_latency_in;
- char *server;
- char *sink;
- char *source;
-@@ -24,28 +30,18 @@ typedef struct {
-
- typedef struct {
- HWVoiceOut hw;
-- int done;
-- int live;
-- int decr;
-- int rpos;
- pa_stream *stream;
-- void *pcm_buf;
-- struct audio_pt pt;
- paaudio *g;
-+ pa_sample_spec ss;
-+ pa_buffer_attr ba;
- } PAVoiceOut;
-
- typedef struct {
- HWVoiceIn hw;
-- int done;
-- int dead;
-- int incr;
-- int wpos;
- pa_stream *stream;
-- void *pcm_buf;
-- struct audio_pt pt;
-- const void *read_data;
-- size_t read_index, read_length;
- paaudio *g;
-+ pa_sample_spec ss;
-+ pa_buffer_attr ba;
- } PAVoiceIn;
-
- static void qpa_audio_fini(void *opaque);
-@@ -109,182 +105,59 @@ static inline int PA_STREAM_IS_GOOD(pa_stream_state_t x)
- } \
- } while (0)
-
--static int qpa_simple_read (PAVoiceIn *p, void *data, size_t length, int *rerror)
--{
-- paaudio *g = p->g;
--
-- pa_threaded_mainloop_lock (g->mainloop);
--
-- CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
--
-- while (length > 0) {
-- size_t l;
--
-- while (!p->read_data) {
-- int r;
--
-- r = pa_stream_peek (p->stream, &p->read_data, &p->read_length);
-- CHECK_SUCCESS_GOTO (g, rerror, r == 0, unlock_and_fail);
--
-- if (!p->read_data) {
-- pa_threaded_mainloop_wait (g->mainloop);
-- CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
-- } else {
-- p->read_index = 0;
-- }
-- }
--
-- l = p->read_length < length ? p->read_length : length;
-- memcpy (data, (const uint8_t *) p->read_data+p->read_index, l);
--
-- data = (uint8_t *) data + l;
-- length -= l;
--
-- p->read_index += l;
-- p->read_length -= l;
--
-- if (!p->read_length) {
-- int r;
--
-- r = pa_stream_drop (p->stream);
-- p->read_data = NULL;
-- p->read_length = 0;
-- p->read_index = 0;
--
-- CHECK_SUCCESS_GOTO (g, rerror, r == 0, unlock_and_fail);
-- }
-- }
--
-- pa_threaded_mainloop_unlock (g->mainloop);
-- return 0;
--
--unlock_and_fail:
-- pa_threaded_mainloop_unlock (g->mainloop);
-- return -1;
--}
--
--static int qpa_simple_write (PAVoiceOut *p, const void *data, size_t length, int *rerror)
-+static int qpa_run_out(HWVoiceOut *hw, int live)
- {
-- paaudio *g = p->g;
--
-- pa_threaded_mainloop_lock (g->mainloop);
--
-- CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
--
-- while (length > 0) {
-- size_t l;
-- int r;
--
-- while (!(l = pa_stream_writable_size (p->stream))) {
-- pa_threaded_mainloop_wait (g->mainloop);
-- CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
-- }
--
-- CHECK_SUCCESS_GOTO (g, rerror, l != (size_t) -1, unlock_and_fail);
--
-- if (l > length) {
-- l = length;
-- }
--
-- r = pa_stream_write (p->stream, data, l, NULL, 0LL, PA_SEEK_RELATIVE);
-- CHECK_SUCCESS_GOTO (g, rerror, r >= 0, unlock_and_fail);
--
-- data = (const uint8_t *) data + l;
-- length -= l;
-- }
--
-- pa_threaded_mainloop_unlock (g->mainloop);
-- return 0;
--
--unlock_and_fail:
-- pa_threaded_mainloop_unlock (g->mainloop);
-- return -1;
--}
--
--static void *qpa_thread_out (void *arg)
--{
-- PAVoiceOut *pa = arg;
-- HWVoiceOut *hw = &pa->hw;
--
-- if (audio_pt_lock(&pa->pt, __func__)) {
-- return NULL;
-- }
-+ PAVoiceOut *pa = (PAVoiceOut *) hw;
-+ int rpos, decr, samples;
-+ size_t avail_bytes, max_bytes;
-+ struct st_sample *src;
-+ void *pa_dst;
-+ int error = 0;
-+ int *rerror = &error;
-+ int r;
-
-- for (;;) {
-- int decr, to_mix, rpos;
-+ decr = 0;
-+ rpos = hw->rpos;
-
-- for (;;) {
-- if (pa->done) {
-- goto exit;
-- }
-+ pa_threaded_mainloop_lock(pa->g->mainloop);
-+ CHECK_DEAD_GOTO(pa->g, pa->stream, rerror, fail);
-
-- if (pa->live > 0) {
-- break;
-- }
-+ avail_bytes = (size_t) live << hw->info.shift;
-
-- if (audio_pt_wait(&pa->pt, __func__)) {
-- goto exit;
-- }
-- }
-+ max_bytes = pa_stream_writable_size(pa->stream);
-+ CHECK_SUCCESS_GOTO(pa->g, rerror, max_bytes != -1, fail);
-
-- decr = to_mix = audio_MIN (pa->live, pa->g->conf.samples >> 2);
-- rpos = pa->rpos;
-+ samples = (int)(audio_MIN(avail_bytes, max_bytes)) >> hw->info.shift;
-+ while (samples) {
-+ int convert_samples = audio_MIN(samples, hw->samples - rpos);
-+ size_t b_wanted = (size_t) convert_samples << hw->info.shift;
-+ size_t b_effective = b_wanted;
-
-- if (audio_pt_unlock(&pa->pt, __func__)) {
-- return NULL;
-- }
-+ r = pa_stream_begin_write(pa->stream, &pa_dst, &b_effective);
-+ CHECK_SUCCESS_GOTO(pa->g, rerror, r == 0, fail);
-+ CHECK_SUCCESS_GOTO(pa->g, (int *)0, b_effective == b_wanted, fail);
-
-- while (to_mix) {
-- int error;
-- int chunk = audio_MIN (to_mix, hw->samples - rpos);
-- struct st_sample *src = hw->mix_buf + rpos;
-+ src = hw->mix_buf + rpos;
-+ hw->clip(pa_dst, src, convert_samples);
-
-- hw->clip (pa->pcm_buf, src, chunk);
--
-- if (qpa_simple_write (pa, pa->pcm_buf,
-- chunk << hw->info.shift, &error) < 0) {
-- qpa_logerr (error, "pa_simple_write failed\n");
-- return NULL;
-- }
-+ r = pa_stream_write(pa->stream, pa_dst, b_effective,
-+ NULL, 0LL, PA_SEEK_RELATIVE);
-+ CHECK_SUCCESS_GOTO(pa->g, rerror, r >= 0, fail);
-
-- rpos = (rpos + chunk) % hw->samples;
-- to_mix -= chunk;
-- }
--
-- if (audio_pt_lock(&pa->pt, __func__)) {
-- return NULL;
-- }
--
-- pa->rpos = rpos;
-- pa->live -= decr;
-- pa->decr += decr;
-+ rpos = (rpos + convert_samples) % hw->samples;
-+ samples -= convert_samples;
-+ decr += convert_samples;
- }
-
-- exit:
-- audio_pt_unlock(&pa->pt, __func__);
-- return NULL;
--}
--
--static int qpa_run_out (HWVoiceOut *hw, int live)
--{
-- int decr;
-- PAVoiceOut *pa = (PAVoiceOut *) hw;
--
-- if (audio_pt_lock(&pa->pt, __func__)) {
-- return 0;
-- }
-+ bail:
-+ pa_threaded_mainloop_unlock(pa->g->mainloop);
-
-- decr = audio_MIN (live, pa->decr);
-- pa->decr -= decr;
-- pa->live = live - decr;
-- hw->rpos = pa->rpos;
-- if (pa->live > 0) {
-- audio_pt_unlock_and_signal(&pa->pt, __func__);
-- }
-- else {
-- audio_pt_unlock(&pa->pt, __func__);
-- }
-+ hw->rpos = rpos;
- return decr;
-+
-+fail:
-+ qpa_logerr(error, "qpa_run_out failed\n");
-+ goto bail;
- }
-
- static int qpa_write (SWVoiceOut *sw, void *buf, int len)
-@@ -292,92 +165,68 @@ static int qpa_write (SWVoiceOut *sw, void *buf, int len)
- return audio_pcm_sw_write (sw, buf, len);
- }
-
--/* capture */
--static void *qpa_thread_in (void *arg)
-+static int qpa_run_in(HWVoiceIn *hw)
- {
-- PAVoiceIn *pa = arg;
-- HWVoiceIn *hw = &pa->hw;
-+ PAVoiceIn *pa = (PAVoiceIn *) hw;
-+ int wpos, incr;
-+ char *pa_src;
-+ int error = 0;
-+ int *rerror = &error;
-+ int r;
-+ size_t pa_avail;
-+ incr = 0;
-+ wpos = hw->wpos;
-
-- if (audio_pt_lock(&pa->pt, __func__)) {
-- return NULL;
-- }
-+ pa_threaded_mainloop_lock(pa->g->mainloop);
-+ CHECK_DEAD_GOTO(pa->g, pa->stream, rerror, fail);
-
-- for (;;) {
-- int incr, to_grab, wpos;
-+ size_t bytes_wanted = ((unsigned int)
-+ (hw->samples - audio_pcm_hw_get_live_in(hw)) << hw->info.shift);
-
-- for (;;) {
-- if (pa->done) {
-- goto exit;
-- }
-+ if (bytes_wanted == 0) {
-+ /* no room */
-+ goto bail;
-+ }
-
-- if (pa->dead > 0) {
-- break;
-- }
-+ size_t bytes_avail = pa_stream_readable_size(pa->stream);
-
-- if (audio_pt_wait(&pa->pt, __func__)) {
-- goto exit;
-- }
-- }
-+ if (bytes_wanted > bytes_avail) {
-+ bytes_wanted = bytes_avail;
-+ }
-
-- incr = to_grab = audio_MIN (pa->dead, pa->g->conf.samples >> 2);
-- wpos = pa->wpos;
-+ while (bytes_wanted) {
-+ r = pa_stream_peek(pa->stream, (const void **)&pa_src, &pa_avail);
-+ CHECK_SUCCESS_GOTO(pa->g, rerror, r == 0, fail);
-
-- if (audio_pt_unlock(&pa->pt, __func__)) {
-- return NULL;
-+ if (pa_avail == 0 || pa_avail > bytes_wanted) {
-+ break;
- }
-
-- while (to_grab) {
-- int error;
-- int chunk = audio_MIN (to_grab, hw->samples - wpos);
-- void *buf = advance (pa->pcm_buf, wpos);
-+ bytes_wanted -= pa_avail;
-
-- if (qpa_simple_read (pa, buf,
-- chunk << hw->info.shift, &error) < 0) {
-- qpa_logerr (error, "pa_simple_read failed\n");
-- return NULL;
-- }
--
-- hw->conv (hw->conv_buf + wpos, buf, chunk);
-+ while (pa_avail) {
-+ int chunk = audio_MIN(
-+ (int)(pa_avail >> hw->info.shift), hw->samples - wpos);
-+ hw->conv(hw->conv_buf + wpos, pa_src, chunk);
- wpos = (wpos + chunk) % hw->samples;
-- to_grab -= chunk;
-- }
--
-- if (audio_pt_lock(&pa->pt, __func__)) {
-- return NULL;
-+ pa_src += chunk << hw->info.shift;
-+ pa_avail -= chunk << hw->info.shift;
-+ incr += chunk;
- }
-
-- pa->wpos = wpos;
-- pa->dead -= incr;
-- pa->incr += incr;
-+ r = pa_stream_drop(pa->stream);
-+ CHECK_SUCCESS_GOTO(pa->g, rerror, r == 0, fail);
- }
-
-- exit:
-- audio_pt_unlock(&pa->pt, __func__);
-- return NULL;
--}
--
--static int qpa_run_in (HWVoiceIn *hw)
--{
-- int live, incr, dead;
-- PAVoiceIn *pa = (PAVoiceIn *) hw;
--
-- if (audio_pt_lock(&pa->pt, __func__)) {
-- return 0;
-- }
-+bail:
-+ pa_threaded_mainloop_unlock(pa->g->mainloop);
-
-- live = audio_pcm_hw_get_live_in (hw);
-- dead = hw->samples - live;
-- incr = audio_MIN (dead, pa->incr);
-- pa->incr -= incr;
-- pa->dead = dead - incr;
-- hw->wpos = pa->wpos;
-- if (pa->dead > 0) {
-- audio_pt_unlock_and_signal(&pa->pt, __func__);
-- }
-- else {
-- audio_pt_unlock(&pa->pt, __func__);
-- }
-+ hw->wpos = wpos;
- return incr;
-+
-+fail:
-+ qpa_logerr(error, "qpa_run_in failed\n");
-+ goto bail;
- }
-
- static int qpa_read (SWVoiceIn *sw, void *buf, int len)
-@@ -470,13 +319,6 @@ static void stream_state_cb (pa_stream *s, void * userdata)
- }
- }
-
--static void stream_request_cb (pa_stream *s, size_t length, void *userdata)
--{
-- paaudio *g = userdata;
--
-- pa_threaded_mainloop_signal (g->mainloop, 0);
--}
--
- static pa_stream *qpa_simple_new (
- paaudio *g,
- const char *name,
-@@ -498,23 +340,17 @@ static pa_stream *qpa_simple_new (
- }
-
- pa_stream_set_state_callback (stream, stream_state_cb, g);
-- pa_stream_set_read_callback (stream, stream_request_cb, g);
-- pa_stream_set_write_callback (stream, stream_request_cb, g);
-
- if (dir == PA_STREAM_PLAYBACK) {
-- r = pa_stream_connect_playback (stream, dev, attr,
-- PA_STREAM_INTERPOLATE_TIMING
--#ifdef PA_STREAM_ADJUST_LATENCY
-- |PA_STREAM_ADJUST_LATENCY
--#endif
-- |PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL);
-+ r = pa_stream_connect_playback(stream, dev, attr,
-+ PA_STREAM_INTERPOLATE_TIMING
-+ | (g->conf.adjust_latency_out ? PA_STREAM_ADJUST_LATENCY : 0)
-+ | PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL);
- } else {
-- r = pa_stream_connect_record (stream, dev, attr,
-- PA_STREAM_INTERPOLATE_TIMING
--#ifdef PA_STREAM_ADJUST_LATENCY
-- |PA_STREAM_ADJUST_LATENCY
--#endif
-- |PA_STREAM_AUTO_TIMING_UPDATE);
-+ r = pa_stream_connect_record(stream, dev, attr,
-+ PA_STREAM_INTERPOLATE_TIMING
-+ | (g->conf.adjust_latency_in ? PA_STREAM_ADJUST_LATENCY : 0)
-+ | PA_STREAM_AUTO_TIMING_UPDATE);
- }
-
- if (r < 0) {
-@@ -541,165 +377,167 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as,
- void *drv_opaque)
- {
- int error;
-- pa_sample_spec ss;
-- pa_buffer_attr ba;
- struct audsettings obt_as = *as;
- PAVoiceOut *pa = (PAVoiceOut *) hw;
- paaudio *g = pa->g = drv_opaque;
-
-- ss.format = audfmt_to_pa (as->fmt, as->endianness);
-- ss.channels = as->nchannels;
-- ss.rate = as->freq;
--
-- /*
-- * qemu audio tick runs at 100 Hz (by default), so processing
-- * data chunks worth 10 ms of sound should be a good fit.
-- */
-- ba.tlength = pa_usec_to_bytes (10 * 1000, &ss);
-- ba.minreq = pa_usec_to_bytes (5 * 1000, &ss);
-- ba.maxlength = -1;
-- ba.prebuf = -1;
--
-- obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
--
-- pa->stream = qpa_simple_new (
-- g,
-- "qemu",
-- PA_STREAM_PLAYBACK,
-- g->conf.sink,
-- &ss,
-- NULL, /* channel map */
-- &ba, /* buffering attributes */
-- &error
-- );
-+ int64_t timer_tick_duration =
-+ audio_MAX(audio_get_timer_ticks(), 1 * SCALE_MS);
-+ int64_t frames_per_tick_x1000 =
-+ ((timer_tick_duration * as->freq * 1000LL) / NANOSECONDS_PER_SECOND);
-+
-+ int64_t tlength = g->conf.tlength;
-+ if (tlength == 0) {
-+ tlength = (frames_per_tick_x1000) / 400;
-+ }
-+ int64_t buflen = g->conf.buffer_size_out;
-+ if (buflen == 0) {
-+ buflen = frames_per_tick_x1000 / 400;
-+ }
-+
-+ ldebug("tick duration: %.2f ms (%.3f frames)\n",
-+ ((float)timer_tick_duration) / SCALE_MS,
-+ (float)frames_per_tick_x1000 / 1000.0f);
-+
-+ ldebug("OUT internal buffer: %.2f ms (%"PRId64" frames)\n",
-+ buflen * (1000.0f / as->freq),
-+ buflen);
-+
-+ ldebug("OUT tlength: %.2f ms (%"PRId64" frames)\n",
-+ tlength * (1000.0f / as->freq),
-+ tlength);
-+
-+ ldebug("OUT adjust latency: %s\n",
-+ g->conf.adjust_latency_out ? "yes" : "no");
-+
-+ pa->ss.format = audfmt_to_pa(as->fmt, as->endianness);
-+ pa->ss.channels = as->nchannels;
-+ pa->ss.rate = as->freq;
-+
-+ pa->ba.tlength = tlength * pa_frame_size(&pa->ss);
-+ pa->ba.maxlength = -1;
-+ pa->ba.minreq = -1;
-+ pa->ba.prebuf = -1;
-+
-+ obt_as.fmt = pa_to_audfmt(pa->ss.format, &obt_as.endianness);
-+
-+ pa->stream = qpa_simple_new(
-+ g,
-+ "qemu",
-+ PA_STREAM_PLAYBACK,
-+ g->conf.sink,
-+ &pa->ss,
-+ NULL, /* channel map */
-+ &pa->ba, /* buffering attributes */
-+ &error
-+ );
- if (!pa->stream) {
- qpa_logerr (error, "pa_simple_new for playback failed\n");
- goto fail1;
- }
-
-- audio_pcm_init_info (&hw->info, &obt_as);
-- hw->samples = g->conf.samples;
-- pa->pcm_buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift);
-- pa->rpos = hw->rpos;
-- if (!pa->pcm_buf) {
-- dolog ("Could not allocate buffer (%d bytes)\n",
-- hw->samples << hw->info.shift);
-- goto fail2;
-- }
--
-- if (audio_pt_init(&pa->pt, qpa_thread_out, hw, AUDIO_CAP, __func__)) {
-- goto fail3;
-- }
-+ audio_pcm_init_info(&hw->info, &obt_as);
-+ hw->samples = buflen;
-
- return 0;
-
-- fail3:
-- g_free (pa->pcm_buf);
-- pa->pcm_buf = NULL;
-- fail2:
-- if (pa->stream) {
-- pa_stream_unref (pa->stream);
-- pa->stream = NULL;
-- }
-- fail1:
-+fail1:
- return -1;
- }
-
- static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
- {
- int error;
-- pa_sample_spec ss;
- struct audsettings obt_as = *as;
- PAVoiceIn *pa = (PAVoiceIn *) hw;
- paaudio *g = pa->g = drv_opaque;
-
-- ss.format = audfmt_to_pa (as->fmt, as->endianness);
-- ss.channels = as->nchannels;
-- ss.rate = as->freq;
--
-- obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
--
-- pa->stream = qpa_simple_new (
-- g,
-- "qemu",
-- PA_STREAM_RECORD,
-- g->conf.source,
-- &ss,
-- NULL, /* channel map */
-- NULL, /* buffering attributes */
-- &error
-- );
-+ int64_t timer_tick_duration =
-+ audio_MAX(audio_get_timer_ticks(), 1 * SCALE_MS);
-+ int64_t frames_per_tick_x1000 =
-+ ((timer_tick_duration * as->freq * 1000LL) / NANOSECONDS_PER_SECOND);
-+
-+ int64_t fragsize = g->conf.fragsize;
-+ if (fragsize == 0) {
-+ fragsize = frames_per_tick_x1000 / 1000;
-+ }
-+ int64_t buflen = g->conf.buffer_size_in;
-+ if (buflen == 0) {
-+ buflen = frames_per_tick_x1000 / 400;
-+ }
-+ int64_t maxlength = g->conf.maxlength_in;
-+ if (maxlength == 0) {
-+ maxlength = fragsize * 2;
-+ }
-+
-+ ldebug("IN internal buffer: %.2f ms (%"PRId64" frames)\n",
-+ buflen * (1000.0f / as->freq),
-+ buflen);
-+
-+ ldebug("IN fragsize: %.2f ms (%"PRId64" frames)\n",
-+ fragsize * (1000.0f / as->freq),
-+ fragsize);
-+
-+ ldebug("IN maxlength: %.2f ms (%"PRId64" frames)\n",
-+ maxlength * (1000.0f / as->freq),
-+ maxlength);
-+
-+ ldebug("IN adjust latency: %s\n",
-+ g->conf.adjust_latency_in ? "yes" : "no");
-+
-+ pa->ss.format = audfmt_to_pa(as->fmt, as->endianness);
-+ pa->ss.channels = as->nchannels;
-+ pa->ss.rate = as->freq;
-+
-+ pa->ba.fragsize = fragsize * pa_frame_size(&pa->ss);
-+ pa->ba.maxlength = maxlength * pa_frame_size(&pa->ss);
-+ pa->ba.minreq = -1;
-+ pa->ba.prebuf = -1;
-+
-+ obt_as.fmt = pa_to_audfmt(pa->ss.format, &obt_as.endianness);
-+
-+ pa->stream = qpa_simple_new(
-+ g,
-+ "qemu",
-+ PA_STREAM_RECORD,
-+ g->conf.source,
-+ &pa->ss,
-+ NULL, /* channel map */
-+ &pa->ba, /* buffering attributes */
-+ &error
-+ );
- if (!pa->stream) {
- qpa_logerr (error, "pa_simple_new for capture failed\n");
- goto fail1;
- }
-
-- audio_pcm_init_info (&hw->info, &obt_as);
-- hw->samples = g->conf.samples;
-- pa->pcm_buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift);
-- pa->wpos = hw->wpos;
-- if (!pa->pcm_buf) {
-- dolog ("Could not allocate buffer (%d bytes)\n",
-- hw->samples << hw->info.shift);
-- goto fail2;
-- }
--
-- if (audio_pt_init(&pa->pt, qpa_thread_in, hw, AUDIO_CAP, __func__)) {
-- goto fail3;
-- }
-+ audio_pcm_init_info(&hw->info, &obt_as);
-+ hw->samples = buflen;
-
- return 0;
-
-- fail3:
-- g_free (pa->pcm_buf);
-- pa->pcm_buf = NULL;
-- fail2:
-- if (pa->stream) {
-- pa_stream_unref (pa->stream);
-- pa->stream = NULL;
-- }
-- fail1:
-+ fail1:
- return -1;
- }
-
- static void qpa_fini_out (HWVoiceOut *hw)
- {
-- void *ret;
- PAVoiceOut *pa = (PAVoiceOut *) hw;
-
-- audio_pt_lock(&pa->pt, __func__);
-- pa->done = 1;
-- audio_pt_unlock_and_signal(&pa->pt, __func__);
-- audio_pt_join(&pa->pt, &ret, __func__);
--
- if (pa->stream) {
- pa_stream_unref (pa->stream);
- pa->stream = NULL;
- }
--
-- audio_pt_fini(&pa->pt, __func__);
-- g_free (pa->pcm_buf);
-- pa->pcm_buf = NULL;
- }
-
- static void qpa_fini_in (HWVoiceIn *hw)
- {
-- void *ret;
- PAVoiceIn *pa = (PAVoiceIn *) hw;
-
-- audio_pt_lock(&pa->pt, __func__);
-- pa->done = 1;
-- audio_pt_unlock_and_signal(&pa->pt, __func__);
-- audio_pt_join(&pa->pt, &ret, __func__);
--
- if (pa->stream) {
- pa_stream_unref (pa->stream);
- pa->stream = NULL;
- }
--
-- audio_pt_fini(&pa->pt, __func__);
-- g_free (pa->pcm_buf);
-- pa->pcm_buf = NULL;
- }
-
- static int qpa_ctl_out (HWVoiceOut *hw, int cmd, ...)
-@@ -809,7 +647,8 @@ static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...)
-
- /* common */
- static PAConf glob_conf = {
-- .samples = 4096,
-+ .adjust_latency_out = 0,
-+ .adjust_latency_in = 1,
- };
-
- static void *qpa_audio_init (void)
-@@ -897,10 +736,46 @@ static void qpa_audio_fini (void *opaque)
-
- struct audio_option qpa_options[] = {
- {
-- .name = "SAMPLES",
-+ .name = "BUFFER_SIZE_OUT",
-+ .tag = AUD_OPT_INT,
-+ .valp = &glob_conf.buffer_size_out,
-+ .descr = "internal buffer size in frames for playback device"
-+ },
-+ {
-+ .name = "BUFFER_SIZE_IN",
-+ .tag = AUD_OPT_INT,
-+ .valp = &glob_conf.buffer_size_in,
-+ .descr = "internal buffer size in frames for recording device"
-+ },
-+ {
-+ .name = "TLENGTH",
- .tag = AUD_OPT_INT,
-- .valp = &glob_conf.samples,
-- .descr = "buffer size in samples"
-+ .valp = &glob_conf.tlength,
-+ .descr = "playback buffer target length in frames"
-+ },
-+ {
-+ .name = "FRAGSIZE",
-+ .tag = AUD_OPT_INT,
-+ .valp = &glob_conf.fragsize,
-+ .descr = "fragment length of recording device in frames"
-+ },
-+ {
-+ .name = "MAXLENGTH_IN",
-+ .tag = AUD_OPT_INT,
-+ .valp = &glob_conf.maxlength_in,
-+ .descr = "maximum length of PA recording buffer in frames"
-+ },
-+ {
-+ .name = "ADJUST_LATENCY_OUT",
-+ .tag = AUD_OPT_BOOL,
-+ .valp = &glob_conf.adjust_latency_out,
-+ .descr = "instruct PA to adjust latency for playback device"
-+ },
-+ {
-+ .name = "ADJUST_LATENCY_IN",
-+ .tag = AUD_OPT_BOOL,
-+ .valp = &glob_conf.adjust_latency_in,
-+ .descr = "instruct PA to adjust latency for recording device"
- },
- {
- .name = "SERVER",
-diff --git a/hw/audio/hda-codec.c b/hw/audio/hda-codec.c
-index 617a1c1016..6627c5cbfd 100644
---- a/hw/audio/hda-codec.c
-+++ b/hw/audio/hda-codec.c
-@@ -18,6 +18,7 @@
- */
-
- #include "qemu/osdep.h"
-+#include "qemu/atomic.h"
- #include "hw/hw.h"
- #include "hw/pci/pci.h"
- #include "intel-hda.h"
-@@ -128,6 +129,7 @@ static void hda_codec_parse_fmt(uint32_t format, struct audsettings *as)
- #include "hda-codec-common.h"
-
- #define HDA_TIMER_TICKS (SCALE_MS)
-+#define MAX_CORR (SCALE_US * 100)
- #define B_SIZE sizeof(st->buf)
- #define B_MASK (sizeof(st->buf) - 1)
-
---
-2.18.0
-