diff options
author | Vaporeon | 2019-01-01 15:22:27 +1300 |
---|---|---|
committer | Vaporeon | 2019-01-01 15:22:27 +1300 |
commit | d6ee75f49216ae57eea6c66b29f9c8d6a7a517b7 (patch) | |
tree | fe1542ad1e6cd092f8b03fe311313e774dbc9a4b | |
parent | 75c14ca98170ecef6278b48d19b71b46b5f8b0a7 (diff) | |
download | aur-d6ee75f49216ae57eea6c66b29f9c8d6a7a517b7.tar.gz |
update
-rw-r--r-- | .SRCINFO | 6 | ||||
-rw-r--r-- | PKGBUILD | 6 | ||||
-rw-r--r-- | pa-fixes.patch | 865 |
3 files changed, 873 insertions, 4 deletions
@@ -1,9 +1,9 @@ # Generated by mksrcinfo v8 -# Sun Dec 16 03:04:12 UTC 2018 +# Tue Jan 1 02:22:23 UTC 2019 pkgbase = qemu-patched pkgdesc = A generic and open source machine emulator and virtualizer - Patched for extra functionality pkgver = 3.1.0 - pkgrel = 1 + pkgrel = 2 url = http://wiki.qemu.org/ arch = x86_64 license = GPL2 @@ -38,6 +38,7 @@ pkgbase = qemu-patched source = qemu-ga.service source = 65-kvm.rules source = allow_elf64.patch + source = pa-fixes.patch source = cpu-pinning.patch::https://github.com/saveriomiroddi/qemu-pinning/commit/cf5294579e4b43e9bea7d681154dc1737e56e323.patch source = pcie-enhanced-link-speed-and-width.patch::https://patchwork.kernel.org/series/43129/mbox/ sha256sums = 6a0508df079a0a33c2487ca936a56c12122f105b8a96a44374704bef6c69abfc @@ -45,6 +46,7 @@ pkgbase = qemu-patched sha256sums = c39bcde4a09165e64419fd2033b3532378bba84d509d39e2d51694d44c1f8d88 sha256sums = a66f0e791b16b03b91049aac61a25950d93e962e1b2ba64a38c6ad7f609b532c sha256sums = 59751f1ed26ea61b2a37ebee4be6979e584a450b611282138a0893aa9173e2e4 + sha256sums = 848b1766b3ea6e75f0e1c69a1e964131f3884bf31e940f3bf7cf7e0737bcd0da sha256sums = a6e9c046555aca07a234ab2ec75223bfb3fb156eab37331a418b7de66d25331e sha256sums = 49f697aa8858692b6a0bc7b43fe569f83b7bcc1b5976634e08c202eccbc35e67 @@ -8,7 +8,7 @@ pkgname=(qemu-patched qemu-patched-headless qemu-patched-arch-extra qemu-patched _pkgname=qemu pkgdesc="A generic and open source machine emulator and virtualizer - Patched for extra functionality" pkgver=3.1.0 -pkgrel=1 +pkgrel=2 arch=(x86_64) license=(GPL2 LGPL2.1) url="http://wiki.qemu.org/" @@ -20,6 +20,7 @@ source=("$url/download/${_pkgname}-${pkgver}.tar.xz"{,.sig} qemu-ga.service 65-kvm.rules allow_elf64.patch + pa-fixes.patch cpu-pinning.patch::https://github.com/saveriomiroddi/qemu-pinning/commit/cf5294579e4b43e9bea7d681154dc1737e56e323.patch pcie-enhanced-link-speed-and-width.patch::https://patchwork.kernel.org/series/43129/mbox/) sha256sums=('6a0508df079a0a33c2487ca936a56c12122f105b8a96a44374704bef6c69abfc' @@ -27,6 +28,7 @@ sha256sums=('6a0508df079a0a33c2487ca936a56c12122f105b8a96a44374704bef6c69abfc' 'c39bcde4a09165e64419fd2033b3532378bba84d509d39e2d51694d44c1f8d88' 'a66f0e791b16b03b91049aac61a25950d93e962e1b2ba64a38c6ad7f609b532c' '59751f1ed26ea61b2a37ebee4be6979e584a450b611282138a0893aa9173e2e4' + '848b1766b3ea6e75f0e1c69a1e964131f3884bf31e940f3bf7cf7e0737bcd0da' 'a6e9c046555aca07a234ab2ec75223bfb3fb156eab37331a418b7de66d25331e' '49f697aa8858692b6a0bc7b43fe569f83b7bcc1b5976634e08c202eccbc35e67') validpgpkeys=('CEACC9E15534EBABB82D3FA03353C9CEF108B584') @@ -46,7 +48,7 @@ prepare() { patch -p1 < ../allow_elf64.patch # FS#60141 patch -p1 < ../cpu-pinning.patch - #patch -p1 < ../pa-fixes.patch + patch -p1 < ../pa-fixes.patch patch -p1 < ../pcie-enhanced-link-speed-and-width.patch } diff --git a/pa-fixes.patch b/pa-fixes.patch new file mode 100644 index 000000000000..815d3fe21839 --- /dev/null +++ b/pa-fixes.patch @@ -0,0 +1,865 @@ +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 >> 5); +- 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 >> 5); +- 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 + |