Created
December 16, 2020 07:34
-
-
Save luqmana/489f9d06bfeb3f863fe1e59011c1a76c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From 5af077d7b25869437d48ba3371f8874c9eeb4667 Mon Sep 17 00:00:00 2001 | |
From: Martin Schrodt <[email protected]> | |
Date: Sat, 7 Oct 2017 01:19:01 +0200 | |
Subject: [PATCH 01/30] Remove several layers of latency producing shells | |
--- | |
audio/paaudio.c | 529 +++++++------------------------------------------------- | |
1 file changed, 60 insertions(+), 469 deletions(-) | |
diff --git a/audio/paaudio.c b/audio/paaudio.c | |
index 65beb6f010..08ce7b1d48 100644 | |
--- a/audio/paaudio.c | |
+++ b/audio/paaudio.c | |
@@ -1,13 +1,35 @@ | |
-/* public domain */ | |
+/* | |
+ * QEMU ALSA audio driver | |
+ * | |
+ * Copyright (c) 2017 Martin Schrodt (spheenik) | |
+ * | |
+ * Permission is hereby granted, free of charge, to any person obtaining a copy | |
+ * of this software and associated documentation files (the "Software"), to deal | |
+ * in the Software without restriction, including without limitation the rights | |
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
+ * copies of the Software, and to permit persons to whom the Software is | |
+ * furnished to do so, subject to the following conditions: | |
+ * | |
+ * The above copyright notice and this permission notice shall be included in | |
+ * all copies or substantial portions of the Software. | |
+ * | |
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
+ * THE SOFTWARE. | |
+ */ | |
#include "qemu/osdep.h" | |
-#include "qemu-common.h" | |
#include "audio.h" | |
#include <pulse/pulseaudio.h> | |
#define AUDIO_CAP "pulseaudio" | |
#include "audio_int.h" | |
-#include "audio_pt_int.h" | |
+ | |
+#define dolog(...) AUD_log ("PA", __VA_ARGS__) | |
typedef struct { | |
int samples; | |
@@ -24,30 +46,10 @@ 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; | |
} 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; | |
-} PAVoiceIn; | |
- | |
static void qpa_audio_fini(void *opaque); | |
static void GCC_FMT_ATTR (2, 3) qpa_logerr (int err, const char *fmt, ...) | |
@@ -81,209 +83,55 @@ static inline int PA_STREAM_IS_GOOD(pa_stream_state_t x) | |
} | |
#endif | |
-#define CHECK_SUCCESS_GOTO(c, rerror, expression, label) \ | |
- do { \ | |
- if (!(expression)) { \ | |
- if (rerror) { \ | |
- *(rerror) = pa_context_errno ((c)->context); \ | |
- } \ | |
- goto label; \ | |
- } \ | |
- } while (0); | |
- | |
-#define CHECK_DEAD_GOTO(c, stream, rerror, label) \ | |
- do { \ | |
- if (!(c)->context || !PA_CONTEXT_IS_GOOD (pa_context_get_state((c)->context)) || \ | |
- !(stream) || !PA_STREAM_IS_GOOD (pa_stream_get_state ((stream)))) { \ | |
- if (((c)->context && pa_context_get_state ((c)->context) == PA_CONTEXT_FAILED) || \ | |
- ((stream) && pa_stream_get_state ((stream)) == PA_STREAM_FAILED)) { \ | |
- if (rerror) { \ | |
- *(rerror) = pa_context_errno ((c)->context); \ | |
- } \ | |
- } else { \ | |
- if (rerror) { \ | |
- *(rerror) = PA_ERR_BADSTATE; \ | |
- } \ | |
- } \ | |
- goto label; \ | |
- } \ | |
- } while (0); | |
- | |
-static int qpa_simple_read (PAVoiceIn *p, 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; | |
- | |
- 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); | |
- } | |
- } | |
+ PAVoiceOut *pa = (PAVoiceOut *) hw; | |
+ int rpos, decr, samples; | |
+ size_t avail_bytes, max_bytes; | |
+ struct st_sample *src; | |
+ void *pa_dst; | |
- pa_threaded_mainloop_unlock (g->mainloop); | |
- return 0; | |
+ pa_threaded_mainloop_lock (pa->g->mainloop); | |
-unlock_and_fail: | |
- pa_threaded_mainloop_unlock (g->mainloop); | |
- return -1; | |
-} | |
+ avail_bytes = (size_t) live << hw->info.shift; | |
+ max_bytes = pa_stream_writable_size(pa->stream); | |
-static int qpa_simple_write (PAVoiceOut *p, const void *data, size_t length, int *rerror) | |
-{ | |
- paaudio *g = p->g; | |
+ samples = (int)(audio_MIN (avail_bytes, max_bytes)) >> hw->info.shift; | |
- pa_threaded_mainloop_lock (g->mainloop); | |
+ decr = samples; | |
+ rpos = hw->rpos; | |
- CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail); | |
+ dolog("TRANSFER avail: %d bytes, max %d bytes -> %d samples from %d\n", (int)avail_bytes, (int)max_bytes, samples, rpos); | |
- while (length > 0) { | |
- size_t l; | |
- int r; | |
+ while (samples) { | |
+ int left_till_end_samples = hw->samples - rpos; | |
- while (!(l = pa_stream_writable_size (p->stream))) { | |
- pa_threaded_mainloop_wait (g->mainloop); | |
- CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail); | |
- } | |
+ int convert_samples = audio_MIN (samples, left_till_end_samples); | |
+ size_t convert_bytes_wanted = (size_t) convert_samples << hw->info.shift; | |
+ size_t convert_bytes = convert_bytes_wanted; | |
- CHECK_SUCCESS_GOTO (g, rerror, l != (size_t) -1, unlock_and_fail); | |
+ pa_stream_begin_write(pa->stream, &pa_dst, &convert_bytes); | |
- if (l > length) { | |
- l = length; | |
+ if (convert_bytes != convert_bytes_wanted) { | |
+ dolog(" OOOPS wanted %d, got %d\n", (int)convert_bytes_wanted, (int)convert_bytes); | |
} | |
- r = pa_stream_write (p->stream, data, l, NULL, 0LL, PA_SEEK_RELATIVE); | |
- CHECK_SUCCESS_GOTO (g, rerror, r >= 0, unlock_and_fail); | |
+ src = hw->mix_buf + rpos; | |
+ hw->clip (pa_dst, src, convert_samples); | |
- data = (const uint8_t *) data + l; | |
- length -= l; | |
- } | |
- | |
- pa_threaded_mainloop_unlock (g->mainloop); | |
- return 0; | |
+ int r = pa_stream_write (pa->stream, pa_dst, convert_bytes, NULL, 0LL, PA_SEEK_RELATIVE); | |
+ dolog(" CHUNK %d samples from %d, result %d\n", convert_samples, rpos, r); | |
-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, AUDIO_FUNC)) { | |
- return NULL; | |
+ rpos = (rpos + convert_samples) % hw->samples; | |
+ samples -= convert_samples; | |
} | |
- for (;;) { | |
- int decr, to_mix, rpos; | |
+ pa_threaded_mainloop_unlock (pa->g->mainloop); | |
- for (;;) { | |
- if (pa->done) { | |
- goto exit; | |
- } | |
+ dolog("\n"); | |
- if (pa->live > 0) { | |
- break; | |
- } | |
- | |
- if (audio_pt_wait (&pa->pt, AUDIO_FUNC)) { | |
- goto exit; | |
- } | |
- } | |
- | |
- decr = to_mix = audio_MIN (pa->live, pa->g->conf.samples >> 2); | |
- rpos = pa->rpos; | |
- | |
- if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) { | |
- return NULL; | |
- } | |
+ hw->rpos = rpos; | |
- while (to_mix) { | |
- int error; | |
- int chunk = audio_MIN (to_mix, hw->samples - rpos); | |
- struct st_sample *src = hw->mix_buf + rpos; | |
- | |
- 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; | |
- } | |
- | |
- rpos = (rpos + chunk) % hw->samples; | |
- to_mix -= chunk; | |
- } | |
- | |
- if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) { | |
- return NULL; | |
- } | |
- | |
- pa->rpos = rpos; | |
- pa->live -= decr; | |
- pa->decr += decr; | |
- } | |
- | |
- exit: | |
- audio_pt_unlock (&pa->pt, AUDIO_FUNC); | |
- return NULL; | |
-} | |
- | |
-static int qpa_run_out (HWVoiceOut *hw, int live) | |
-{ | |
- int decr; | |
- PAVoiceOut *pa = (PAVoiceOut *) hw; | |
- | |
- if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) { | |
- return 0; | |
- } | |
- | |
- 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, AUDIO_FUNC); | |
- } | |
- else { | |
- audio_pt_unlock (&pa->pt, AUDIO_FUNC); | |
- } | |
return decr; | |
} | |
@@ -292,102 +140,9 @@ 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) | |
-{ | |
- PAVoiceIn *pa = arg; | |
- HWVoiceIn *hw = &pa->hw; | |
- | |
- if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) { | |
- return NULL; | |
- } | |
- | |
- for (;;) { | |
- int incr, to_grab, wpos; | |
- | |
- for (;;) { | |
- if (pa->done) { | |
- goto exit; | |
- } | |
- | |
- if (pa->dead > 0) { | |
- break; | |
- } | |
- | |
- if (audio_pt_wait (&pa->pt, AUDIO_FUNC)) { | |
- goto exit; | |
- } | |
- } | |
- | |
- incr = to_grab = audio_MIN (pa->dead, pa->g->conf.samples >> 2); | |
- wpos = pa->wpos; | |
- | |
- if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) { | |
- return NULL; | |
- } | |
- | |
- while (to_grab) { | |
- int error; | |
- int chunk = audio_MIN (to_grab, hw->samples - wpos); | |
- void *buf = advance (pa->pcm_buf, wpos); | |
- | |
- 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); | |
- wpos = (wpos + chunk) % hw->samples; | |
- to_grab -= chunk; | |
- } | |
- | |
- if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) { | |
- return NULL; | |
- } | |
- | |
- pa->wpos = wpos; | |
- pa->dead -= incr; | |
- pa->incr += incr; | |
- } | |
- | |
- exit: | |
- audio_pt_unlock (&pa->pt, AUDIO_FUNC); | |
- return NULL; | |
-} | |
- | |
-static int qpa_run_in (HWVoiceIn *hw) | |
-{ | |
- int live, incr, dead; | |
- PAVoiceIn *pa = (PAVoiceIn *) hw; | |
- | |
- if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) { | |
- return 0; | |
- } | |
- | |
- 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, AUDIO_FUNC); | |
- } | |
- else { | |
- audio_pt_unlock (&pa->pt, AUDIO_FUNC); | |
- } | |
- return incr; | |
-} | |
- | |
-static int qpa_read (SWVoiceIn *sw, void *buf, int len) | |
-{ | |
- return audio_pcm_sw_read (sw, buf, len); | |
-} | |
- | |
static pa_sample_format_t audfmt_to_pa (audfmt_e afmt, int endianness) | |
{ | |
- int format; | |
+ pa_sample_format_t format; | |
switch (afmt) { | |
case AUD_FMT_S8: | |
@@ -555,8 +310,8 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as, | |
* 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.tlength = pa_usec_to_bytes (40 * 1000, &ss); | |
+ ba.minreq = -1; | |
ba.maxlength = -1; | |
ba.prebuf = -1; | |
@@ -579,127 +334,22 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as, | |
audio_pcm_init_info (&hw->info, &obt_as); | |
hw->samples = g->conf.samples; | |
- pa->pcm_buf = audio_calloc (AUDIO_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, AUDIO_FUNC)) { | |
- goto fail3; | |
- } | |
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: | |
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 | |
- ); | |
- 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 (AUDIO_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, AUDIO_FUNC)) { | |
- goto fail3; | |
- } | |
- | |
- 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: | |
- return -1; | |
-} | |
static void qpa_fini_out (HWVoiceOut *hw) | |
{ | |
- void *ret; | |
PAVoiceOut *pa = (PAVoiceOut *) hw; | |
- audio_pt_lock (&pa->pt, AUDIO_FUNC); | |
- pa->done = 1; | |
- audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC); | |
- audio_pt_join (&pa->pt, &ret, AUDIO_FUNC); | |
- | |
if (pa->stream) { | |
pa_stream_unref (pa->stream); | |
pa->stream = NULL; | |
} | |
- | |
- audio_pt_fini (&pa->pt, AUDIO_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, AUDIO_FUNC); | |
- pa->done = 1; | |
- audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC); | |
- audio_pt_join (&pa->pt, &ret, AUDIO_FUNC); | |
- | |
- if (pa->stream) { | |
- pa_stream_unref (pa->stream); | |
- pa->stream = NULL; | |
- } | |
- | |
- audio_pt_fini (&pa->pt, AUDIO_FUNC); | |
- g_free (pa->pcm_buf); | |
- pa->pcm_buf = NULL; | |
} | |
static int qpa_ctl_out (HWVoiceOut *hw, int cmd, ...) | |
@@ -754,59 +404,6 @@ static int qpa_ctl_out (HWVoiceOut *hw, int cmd, ...) | |
return 0; | |
} | |
-static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...) | |
-{ | |
- PAVoiceIn *pa = (PAVoiceIn *) hw; | |
- pa_operation *op; | |
- pa_cvolume v; | |
- paaudio *g = pa->g; | |
- | |
-#ifdef PA_CHECK_VERSION | |
- pa_cvolume_init (&v); | |
-#endif | |
- | |
- switch (cmd) { | |
- case VOICE_VOLUME: | |
- { | |
- SWVoiceIn *sw; | |
- va_list ap; | |
- | |
- va_start (ap, cmd); | |
- sw = va_arg (ap, SWVoiceIn *); | |
- va_end (ap); | |
- | |
- v.channels = 2; | |
- v.values[0] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.l) / UINT32_MAX; | |
- v.values[1] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.r) / UINT32_MAX; | |
- | |
- pa_threaded_mainloop_lock (g->mainloop); | |
- | |
- op = pa_context_set_source_output_volume (g->context, | |
- pa_stream_get_index (pa->stream), | |
- &v, NULL, NULL); | |
- if (!op) { | |
- qpa_logerr (pa_context_errno (g->context), | |
- "set_source_output_volume() failed\n"); | |
- } else { | |
- pa_operation_unref(op); | |
- } | |
- | |
- op = pa_context_set_source_output_mute (g->context, | |
- pa_stream_get_index (pa->stream), | |
- sw->vol.mute, NULL, NULL); | |
- if (!op) { | |
- qpa_logerr (pa_context_errno (g->context), | |
- "set_source_output_mute() failed\n"); | |
- } else { | |
- pa_operation_unref (op); | |
- } | |
- | |
- pa_threaded_mainloop_unlock (g->mainloop); | |
- } | |
- } | |
- return 0; | |
-} | |
- | |
/* common */ | |
static PAConf glob_conf = { | |
.samples = 4096, | |
@@ -929,12 +526,6 @@ static struct audio_pcm_ops qpa_pcm_ops = { | |
.run_out = qpa_run_out, | |
.write = qpa_write, | |
.ctl_out = qpa_ctl_out, | |
- | |
- .init_in = qpa_init_in, | |
- .fini_in = qpa_fini_in, | |
- .run_in = qpa_run_in, | |
- .read = qpa_read, | |
- .ctl_in = qpa_ctl_in | |
}; | |
struct audio_driver pa_audio_driver = { | |
@@ -946,8 +537,8 @@ struct audio_driver pa_audio_driver = { | |
.pcm_ops = &qpa_pcm_ops, | |
.can_be_default = 1, | |
.max_voices_out = INT_MAX, | |
- .max_voices_in = INT_MAX, | |
+ .max_voices_in = 0, | |
.voice_size_out = sizeof (PAVoiceOut), | |
- .voice_size_in = sizeof (PAVoiceIn), | |
+ .voice_size_in = 0, | |
.ctl_caps = VOICE_VOLUME_CAP | |
}; | |
-- | |
2.14.1 | |
From 60e18b9e1234ba0c8431a3a874a506625aa3014c Mon Sep 17 00:00:00 2001 | |
From: Martin Schrodt <[email protected]> | |
Date: Sat, 7 Oct 2017 02:14:35 +0200 | |
Subject: [PATCH 02/30] auto adjust buffer sizes | |
--- | |
audio/audio.c | 12 ++++++++++++ | |
audio/audio_int.h | 4 ++++ | |
audio/paaudio.c | 7 +++++-- | |
3 files changed, 21 insertions(+), 2 deletions(-) | |
diff --git a/audio/audio.c b/audio/audio.c | |
index beafed209b..6584ff3231 100644 | |
--- a/audio/audio.c | |
+++ b/audio/audio.c | |
@@ -2066,3 +2066,15 @@ void AUD_set_volume_in (SWVoiceIn *sw, int mute, uint8_t lvol, uint8_t rvol) | |
} | |
} | |
} | |
+ | |
+int audio_get_timer_ticks() { | |
+ return (int) conf.period.ticks; | |
+} | |
+ | |
+int audio_get_timer_frequency() { | |
+ return (int) (NANOSECONDS_PER_SECOND / conf.period.ticks); | |
+} | |
+ | |
+int audio_get_dac_frequency() { | |
+ return conf.fixed_out.settings.freq; | |
+} | |
diff --git a/audio/audio_int.h b/audio/audio_int.h | |
index 5bcb1c60e1..86fb2067e8 100644 | |
--- a/audio/audio_int.h | |
+++ b/audio/audio_int.h | |
@@ -214,6 +214,10 @@ extern struct audio_driver pa_audio_driver; | |
extern struct audio_driver spice_audio_driver; | |
extern const struct mixeng_volume nominal_volume; | |
+int audio_get_timer_ticks(void); | |
+int audio_get_timer_frequency(void); | |
+int audio_get_dac_frequency(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 08ce7b1d48..71f845ee9b 100644 | |
--- a/audio/paaudio.c | |
+++ b/audio/paaudio.c | |
@@ -310,7 +310,7 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as, | |
* 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 (40 * 1000, &ss); | |
+ ba.tlength = pa_usec_to_bytes (2 * audio_get_timer_ticks() / 1000, &ss); | |
ba.minreq = -1; | |
ba.maxlength = -1; | |
ba.prebuf = -1; | |
@@ -333,7 +333,10 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as, | |
} | |
audio_pcm_init_info (&hw->info, &obt_as); | |
- hw->samples = g->conf.samples; | |
+ //hw->samples = g->conf.samples; | |
+ | |
+ // TODO | |
+ hw->samples = (4 * audio_get_dac_frequency()) / audio_get_timer_frequency(); | |
return 0; | |
-- | |
2.14.1 | |
From 8e2014e20973f92c096a1820dadee49dcbc31cc7 Mon Sep 17 00:00:00 2001 | |
From: Martin Schrodt <[email protected]> | |
Date: Sat, 7 Oct 2017 17:39:32 +0200 | |
Subject: [PATCH 03/30] expose settings, set reasonable defaults | |
--- | |
audio/audio.c | 12 +----- | |
audio/audio_int.h | 4 +- | |
audio/paaudio.c | 111 +++++++++++++++++++++++++++++++++++++++--------------- | |
3 files changed, 83 insertions(+), 44 deletions(-) | |
diff --git a/audio/audio.c b/audio/audio.c | |
index 6584ff3231..fba1604c34 100644 | |
--- a/audio/audio.c | |
+++ b/audio/audio.c | |
@@ -2067,14 +2067,6 @@ void AUD_set_volume_in (SWVoiceIn *sw, int mute, uint8_t lvol, uint8_t rvol) | |
} | |
} | |
-int audio_get_timer_ticks() { | |
- return (int) conf.period.ticks; | |
-} | |
- | |
-int audio_get_timer_frequency() { | |
- return (int) (NANOSECONDS_PER_SECOND / conf.period.ticks); | |
-} | |
- | |
-int audio_get_dac_frequency() { | |
- return conf.fixed_out.settings.freq; | |
+int64_t audio_get_timer_ticks(void) { | |
+ return conf.period.ticks; | |
} | |
diff --git a/audio/audio_int.h b/audio/audio_int.h | |
index 86fb2067e8..2f7fc4f8ac 100644 | |
--- a/audio/audio_int.h | |
+++ b/audio/audio_int.h | |
@@ -214,9 +214,7 @@ extern struct audio_driver pa_audio_driver; | |
extern struct audio_driver spice_audio_driver; | |
extern const struct mixeng_volume nominal_volume; | |
-int audio_get_timer_ticks(void); | |
-int audio_get_timer_frequency(void); | |
-int audio_get_dac_frequency(void); | |
+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 71f845ee9b..59bda28768 100644 | |
--- a/audio/paaudio.c | |
+++ b/audio/paaudio.c | |
@@ -23,16 +23,20 @@ | |
*/ | |
#include "qemu/osdep.h" | |
#include "audio.h" | |
+#include "hw/audio/intel-hda-defs.h" | |
#include <pulse/pulseaudio.h> | |
+#include <include/qemu/timer.h> | |
#define AUDIO_CAP "pulseaudio" | |
#include "audio_int.h" | |
-#define dolog(...) AUD_log ("PA", __VA_ARGS__) | |
- | |
typedef struct { | |
- int samples; | |
+ int buffer_size; | |
+ int tlength; | |
+#ifdef PA_STREAM_ADJUST_LATENCY | |
+ int adjust_latency_out; | |
+#endif | |
char *server; | |
char *sink; | |
char *source; | |
@@ -101,7 +105,11 @@ static int qpa_run_out (HWVoiceOut *hw, int live) | |
decr = samples; | |
rpos = hw->rpos; | |
- dolog("TRANSFER avail: %d bytes, max %d bytes -> %d samples from %d\n", (int)avail_bytes, (int)max_bytes, samples, rpos); | |
+ if (avail_bytes < max_bytes) { | |
+ dolog("avail: %d, wanted: %d \n", (int)avail_bytes, (int)max_bytes); | |
+ } | |
+ | |
+ //dolog("TRANSFER avail: %d bytes, max %d bytes -> %d samples from %d\n", (int)avail_bytes, (int)max_bytes, samples, rpos); | |
while (samples) { | |
int left_till_end_samples = hw->samples - rpos; | |
@@ -119,8 +127,7 @@ static int qpa_run_out (HWVoiceOut *hw, int live) | |
src = hw->mix_buf + rpos; | |
hw->clip (pa_dst, src, convert_samples); | |
- int r = pa_stream_write (pa->stream, pa_dst, convert_bytes, NULL, 0LL, PA_SEEK_RELATIVE); | |
- dolog(" CHUNK %d samples from %d, result %d\n", convert_samples, rpos, r); | |
+ pa_stream_write (pa->stream, pa_dst, convert_bytes, NULL, 0LL, PA_SEEK_RELATIVE); | |
rpos = (rpos + convert_samples) % hw->samples; | |
samples -= convert_samples; | |
@@ -128,7 +135,7 @@ static int qpa_run_out (HWVoiceOut *hw, int live) | |
pa_threaded_mainloop_unlock (pa->g->mainloop); | |
- dolog("\n"); | |
+ //dolog("\n"); | |
hw->rpos = rpos; | |
@@ -225,13 +232,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, | |
@@ -253,14 +253,12 @@ 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 | |
+ | (g->conf.adjust_latency_out ? PA_STREAM_ADJUST_LATENCY : 0) | |
#endif | |
|PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL); | |
} else { | |
@@ -292,6 +290,20 @@ fail: | |
return NULL; | |
} | |
+ | |
+static int64_t hob (int64_t num) | |
+{ | |
+ if (!num) | |
+ return 0; | |
+ | |
+ int ret = 1; | |
+ | |
+ while (num >>= 1) | |
+ ret <<= 1; | |
+ | |
+ return ret; | |
+} | |
+ | |
static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as, | |
void *drv_opaque) | |
{ | |
@@ -302,17 +314,40 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as, | |
PAVoiceOut *pa = (PAVoiceOut *) hw; | |
paaudio *g = pa->g = drv_opaque; | |
+ 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 + 999) / 1000; | |
+ } | |
+ int64_t buflen = g->conf.buffer_size; | |
+ if (buflen == 0) { | |
+ buflen = hob(frames_per_tick_x1000 / 125); | |
+ buflen = audio_MAX(HDA_BUFFER_SIZE, buflen); // must be at least HDA_BUFFER_SIZE bytes for HDA to work at all! | |
+ } | |
+ | |
+ float ms_per_frame = 1000.0f / as->freq; | |
+ | |
+ dolog("tick duration: %.2f ms (%.3f frames)\n", | |
+ ((float) timer_tick_duration) / SCALE_MS, | |
+ (float)frames_per_tick_x1000 / 1000.0f); | |
+ | |
+ dolog("internal buffer: %.2f ms (%"PRId64" frames)\n", | |
+ buflen * ms_per_frame, | |
+ buflen); | |
+ | |
+ dolog("tlength: %.2f ms (%"PRId64" frames)\n", | |
+ tlength * ms_per_frame, | |
+ tlength); | |
+ | |
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 (2 * audio_get_timer_ticks() / 1000, &ss); | |
- ba.minreq = -1; | |
+ ba.tlength = tlength * pa_frame_size (&ss); | |
ba.maxlength = -1; | |
+ ba.minreq = -1; | |
ba.prebuf = -1; | |
obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness); | |
@@ -333,10 +368,7 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as, | |
} | |
audio_pcm_init_info (&hw->info, &obt_as); | |
- //hw->samples = g->conf.samples; | |
- | |
- // TODO | |
- hw->samples = (4 * audio_get_dac_frequency()) / audio_get_timer_frequency(); | |
+ hw->samples = buflen; | |
return 0; | |
@@ -409,9 +441,12 @@ static int qpa_ctl_out (HWVoiceOut *hw, int cmd, ...) | |
/* common */ | |
static PAConf glob_conf = { | |
- .samples = 4096, | |
+#ifdef PA_STREAM_ADJUST_LATENCY | |
+ .adjust_latency_out = 0, | |
+#endif | |
}; | |
+ | |
static void *qpa_audio_init (void) | |
{ | |
paaudio *g = g_malloc(sizeof(paaudio)); | |
@@ -497,11 +532,25 @@ static void qpa_audio_fini (void *opaque) | |
struct audio_option qpa_options[] = { | |
{ | |
- .name = "SAMPLES", | |
+ .name = "INT_BUF_SIZE", | |
+ .tag = AUD_OPT_INT, | |
+ .valp = &glob_conf.buffer_size, | |
+ .descr = "internal buffer size in frames" | |
+ }, | |
+ { | |
+ .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" | |
}, | |
+#ifdef PA_STREAM_ADJUST_LATENCY | |
+ { | |
+ .name = "ADJUST_LATENCY_OUT", | |
+ .tag = AUD_OPT_BOOL, | |
+ .valp = &glob_conf.adjust_latency_out, | |
+ .descr = "let PA adjust latency for playback device" | |
+ }, | |
+#endif | |
{ | |
.name = "SERVER", | |
.tag = AUD_OPT_STR, | |
-- | |
2.14.1 | |
From d7df7f8c7c35f9aa4f00152733e9c56fc5f8347c Mon Sep 17 00:00:00 2001 | |
From: Martin Schrodt <[email protected]> | |
Date: Sun, 8 Oct 2017 03:33:16 +0200 | |
Subject: [PATCH 04/30] reduce logging | |
--- | |
audio/paaudio.c | 10 ++++++---- | |
1 file changed, 6 insertions(+), 4 deletions(-) | |
diff --git a/audio/paaudio.c b/audio/paaudio.c | |
index 59bda28768..a1a7e94d4b 100644 | |
--- a/audio/paaudio.c | |
+++ b/audio/paaudio.c | |
@@ -105,9 +105,9 @@ static int qpa_run_out (HWVoiceOut *hw, int live) | |
decr = samples; | |
rpos = hw->rpos; | |
- if (avail_bytes < max_bytes) { | |
- dolog("avail: %d, wanted: %d \n", (int)avail_bytes, (int)max_bytes); | |
- } | |
+// if (avail_bytes < max_bytes) { | |
+// dolog("avail: %d, wanted: %d \n", (int)avail_bytes, (int)max_bytes); | |
+// } | |
//dolog("TRANSFER avail: %d bytes, max %d bytes -> %d samples from %d\n", (int)avail_bytes, (int)max_bytes, samples, rpos); | |
@@ -319,7 +319,7 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as, | |
int64_t tlength = g->conf.tlength; | |
if (tlength == 0) { | |
- tlength = (frames_per_tick_x1000 + 999) / 1000; | |
+ tlength = (frames_per_tick_x1000) / 500; | |
} | |
int64_t buflen = g->conf.buffer_size; | |
if (buflen == 0) { | |
@@ -341,6 +341,8 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as, | |
tlength * ms_per_frame, | |
tlength); | |
+ dolog("adjust latency: %s\n", g->conf.adjust_latency_out ? "yes" : "no"); | |
+ | |
ss.format = audfmt_to_pa (as->fmt, as->endianness); | |
ss.channels = as->nchannels; | |
ss.rate = as->freq; | |
-- | |
2.14.1 | |
From 7a36efa0a889ad01d538f59e5f38fca001c7ac4d Mon Sep 17 00:00:00 2001 | |
From: Martin Schrodt <[email protected]> | |
Date: Sun, 8 Oct 2017 03:35:25 +0200 | |
Subject: [PATCH 05/30] improve audio timer | |
--- | |
audio/audio.c | 34 +++++++++++++++++++++++++++++++++- | |
1 file changed, 33 insertions(+), 1 deletion(-) | |
diff --git a/audio/audio.c b/audio/audio.c | |
index fba1604c34..fae6233caf 100644 | |
--- a/audio/audio.c | |
+++ b/audio/audio.c | |
@@ -1121,10 +1121,42 @@ static void audio_reset_timer (AudioState *s) | |
} | |
} | |
+ | |
+static int64_t ref_ns = -1; | |
+static int64_t last_ns = -1; | |
+ | |
static void audio_timer (void *opaque) | |
{ | |
+ int64_t start_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); | |
+ if (ref_ns == -1) { | |
+ ref_ns = start_ns - conf.period.ticks; | |
+ last_ns = ref_ns; | |
+ } | |
audio_run ("timer"); | |
- audio_reset_timer (opaque); | |
+ int64_t end_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); | |
+ | |
+ | |
+ if ((end_ns - start_ns) > conf.period.ticks) { | |
+ dolog("audio timer after %"PRId64" us (deviation %"PRId64" us), took %"PRId64" us\n", | |
+ (start_ns - last_ns) / SCALE_US, | |
+ (start_ns - (ref_ns + conf.period.ticks)) / SCALE_US, | |
+ (end_ns - start_ns) / SCALE_US | |
+ ); | |
+ } | |
+ | |
+ last_ns = start_ns; | |
+ | |
+ AudioState *s = opaque; | |
+ | |
+ if (audio_is_timer_needed ()) { | |
+ ref_ns += conf.period.ticks; | |
+ timer_mod_anticipate_ns(s->ts, audio_MAX(ref_ns + conf.period.ticks, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 1)); | |
+ } | |
+ else { | |
+ ref_ns = -1; | |
+ timer_del (s->ts); | |
+ } | |
+ | |
} | |
/* | |
-- | |
2.14.1 | |
From 0dc3b7e85733088c342df609b76905e72971b4cf Mon Sep 17 00:00:00 2001 | |
From: Martin Schrodt <[email protected]> | |
Date: Mon, 9 Oct 2017 00:11:15 +0200 | |
Subject: [PATCH 06/30] query HDA with a separate timer | |
--- | |
hw/audio/hda-codec.c | 157 ++++++++++++++++++++++++++++++++++------------ | |
hw/audio/intel-hda-defs.h | 1 + | |
hw/audio/intel-hda.c | 14 ++--- | |
3 files changed, 126 insertions(+), 46 deletions(-) | |
diff --git a/hw/audio/hda-codec.c b/hw/audio/hda-codec.c | |
index 5402cd196c..009d9bc2eb 100644 | |
--- a/hw/audio/hda-codec.c | |
+++ b/hw/audio/hda-codec.c | |
@@ -154,8 +154,11 @@ struct HDAAudioStream { | |
SWVoiceIn *in; | |
SWVoiceOut *out; | |
} voice; | |
- uint8_t buf[HDA_BUFFER_SIZE]; | |
- uint32_t bpos; | |
+ uint8_t buf[8192]; | |
+ int64_t rpos; | |
+ int64_t wpos; | |
+ QEMUTimer *buft; | |
+ int64_t buft_start; | |
}; | |
#define TYPE_HDA_AUDIO "hda-audio" | |
@@ -178,54 +181,117 @@ struct HDAAudioState { | |
static void hda_audio_input_cb(void *opaque, int avail) | |
{ | |
+// HDAAudioStream *st = opaque; | |
+// int recv = 0; | |
+// int len; | |
+// bool rc; | |
+// | |
+// while (avail - recv >= sizeof(st->buf)) { | |
+// if (st->bpos != sizeof(st->buf)) { | |
+// len = AUD_read(st->voice.in, st->buf + st->bpos, | |
+// sizeof(st->buf) - st->bpos); | |
+// st->bpos += len; | |
+// recv += len; | |
+// if (st->bpos != sizeof(st->buf)) { | |
+// break; | |
+// } | |
+// } | |
+// rc = hda_codec_xfer(&st->state->hda, st->stream, false, | |
+// st->buf, sizeof(st->buf)); | |
+// if (!rc) { | |
+// break; | |
+// } | |
+// st->bpos = 0; | |
+// } | |
+} | |
+ | |
+ | |
+#define dolog(fmt, ...) AUD_log("XX", fmt, ## __VA_ARGS__) | |
+ | |
+static void hda_audio_output_timer(void *opaque) { | |
+ | |
+#define B_SIZE sizeof(st->buf) | |
+#define B_MASK (sizeof(st->buf) - 1) | |
+ | |
HDAAudioStream *st = opaque; | |
- int recv = 0; | |
- int len; | |
- bool rc; | |
- | |
- while (avail - recv >= sizeof(st->buf)) { | |
- if (st->bpos != sizeof(st->buf)) { | |
- len = AUD_read(st->voice.in, st->buf + st->bpos, | |
- sizeof(st->buf) - st->bpos); | |
- st->bpos += len; | |
- recv += len; | |
- if (st->bpos != sizeof(st->buf)) { | |
- break; | |
- } | |
- } | |
- rc = hda_codec_xfer(&st->state->hda, st->stream, false, | |
- st->buf, sizeof(st->buf)); | |
+ | |
+ int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); | |
+ | |
+ int64_t wanted_wpos = (st->as.freq * 4 * (now - st->buft_start)) / NANOSECONDS_PER_SECOND; | |
+ wanted_wpos &= -4; // IMPORTANT! clip to frames | |
+ | |
+ int64_t wpos = st->wpos; | |
+ int64_t rpos = st->rpos; | |
+ | |
+ if (wanted_wpos <= wpos) { | |
+ // we already have the data | |
+ goto out_timer; | |
+ } | |
+ | |
+ if (wpos - rpos >= B_SIZE) { | |
+ goto out_timer; | |
+ } | |
+ | |
+ //dolog("%"PRId64"\n", wpos - rpos); | |
+ | |
+ //dolog("rpos: %"PRId64", wpos: %"PRId64", wanted: %"PRId64"\n", rpos, wpos, wanted_wpos); | |
+ int64_t to_transfer = audio_MIN(B_SIZE - (wpos - rpos), wanted_wpos - wpos); | |
+ while (to_transfer) { | |
+ uint32_t start = (wpos & B_MASK); | |
+ uint32_t chunk = audio_MIN(B_SIZE - start, to_transfer); | |
+ int rc = hda_codec_xfer(&st->state->hda, st->stream, true, st->buf + start, chunk); | |
if (!rc) { | |
break; | |
} | |
- st->bpos = 0; | |
+ wpos += chunk; | |
+ to_transfer -= chunk; | |
+ } | |
+ st->wpos = wpos; | |
+ | |
+#undef B_MASK | |
+#undef B_SIZE | |
+ | |
+ out_timer: | |
+ | |
+ if (st->running) { | |
+ timer_mod_anticipate_ns(st->buft, now + HDA_TIMER_TICKS); | |
} | |
} | |
static void hda_audio_output_cb(void *opaque, int avail) | |
{ | |
+#define B_SIZE sizeof(st->buf) | |
+#define B_MASK (sizeof(st->buf) - 1) | |
+ | |
HDAAudioStream *st = opaque; | |
- int sent = 0; | |
- int len; | |
- bool rc; | |
- | |
- while (avail - sent >= sizeof(st->buf)) { | |
- if (st->bpos == sizeof(st->buf)) { | |
- rc = hda_codec_xfer(&st->state->hda, st->stream, true, | |
- st->buf, sizeof(st->buf)); | |
- if (!rc) { | |
- break; | |
- } | |
- st->bpos = 0; | |
- } | |
- len = AUD_write(st->voice.out, st->buf + st->bpos, | |
- sizeof(st->buf) - st->bpos); | |
- st->bpos += len; | |
- sent += len; | |
- if (st->bpos != sizeof(st->buf)) { | |
+ | |
+ int64_t wpos = st->wpos; | |
+ int64_t rpos = st->rpos; | |
+ | |
+ int64_t to_transfer = audio_MIN(wpos - rpos, avail); | |
+ | |
+ int64_t overflow = wpos - rpos - to_transfer - (B_SIZE >> 3); | |
+ if (overflow > 0) { | |
+ int64_t corr = NANOSECONDS_PER_SECOND * overflow / (4 * st->as.freq); | |
+ //dolog("CORR %"PRId64"\n", corr); | |
+ st->buft_start += corr; | |
+ } | |
+ | |
+ while (to_transfer) { | |
+ uint32_t start = (uint32_t) (rpos & B_MASK); | |
+ uint32_t chunk = (uint32_t) audio_MIN(B_SIZE - start, to_transfer); | |
+ uint32_t written = AUD_write(st->voice.out, st->buf + start, chunk); | |
+ rpos += written; | |
+ to_transfer -= written; | |
+ if (chunk != written) { | |
break; | |
} | |
} | |
+ | |
+ st->rpos = rpos; | |
+ | |
+#undef B_MASK | |
+#undef B_SIZE | |
} | |
static void hda_audio_set_running(HDAAudioStream *st, bool running) | |
@@ -237,6 +303,17 @@ static void hda_audio_set_running(HDAAudioStream *st, bool running) | |
return; | |
} | |
st->running = running; | |
+ | |
+ if (running) { | |
+ int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); | |
+ st->rpos = 0; | |
+ st->wpos = 0; | |
+ st->buft_start = now; | |
+ timer_mod_anticipate_ns(st->buft, now + HDA_TIMER_TICKS); | |
+ } else { | |
+ timer_del (st->buft); | |
+ } | |
+ | |
dprint(st->state, 1, "%s: %s (stream %d)\n", st->node->name, | |
st->running ? "on" : "off", st->stream); | |
if (st->output) { | |
@@ -286,6 +363,7 @@ static void hda_audio_setup(HDAAudioStream *st) | |
st->voice.out = AUD_open_out(&st->state->card, st->voice.out, | |
st->node->name, st, | |
hda_audio_output_cb, &st->as); | |
+ st->buft = timer_new_ns(QEMU_CLOCK_VIRTUAL, hda_audio_output_timer, st); | |
} else { | |
st->voice.in = AUD_open_in(&st->state->card, st->voice.in, | |
st->node->name, st, | |
@@ -505,7 +583,6 @@ static int hda_audio_init(HDACodecDevice *hda, const struct desc_codec *desc) | |
/* unmute output by default */ | |
st->gain_left = QEMU_HDA_AMP_STEPS; | |
st->gain_right = QEMU_HDA_AMP_STEPS; | |
- st->bpos = sizeof(st->buf); | |
st->output = true; | |
} else { | |
st->output = false; | |
@@ -533,6 +610,7 @@ static void hda_audio_exit(HDACodecDevice *hda) | |
continue; | |
} | |
if (st->output) { | |
+ timer_del (st->buft); | |
AUD_close_out(&a->card, st->voice.out); | |
} else { | |
AUD_close_in(&a->card, st->voice.in); | |
@@ -592,8 +670,9 @@ static const VMStateDescription vmstate_hda_audio_stream = { | |
VMSTATE_UINT32(gain_right, HDAAudioStream), | |
VMSTATE_BOOL(mute_left, HDAAudioStream), | |
VMSTATE_BOOL(mute_right, HDAAudioStream), | |
- VMSTATE_UINT32(bpos, HDAAudioStream), | |
VMSTATE_BUFFER(buf, HDAAudioStream), | |
+ VMSTATE_INT64(rpos, HDAAudioStream), | |
+ VMSTATE_INT64(wpos, HDAAudioStream), | |
VMSTATE_END_OF_LIST() | |
} | |
}; | |
diff --git a/hw/audio/intel-hda-defs.h b/hw/audio/intel-hda-defs.h | |
index 2e37e5b874..900a2695ec 100644 | |
--- a/hw/audio/intel-hda-defs.h | |
+++ b/hw/audio/intel-hda-defs.h | |
@@ -3,6 +3,7 @@ | |
/* qemu */ | |
#define HDA_BUFFER_SIZE 256 | |
+#define HDA_TIMER_TICKS (SCALE_MS) | |
/* --------------------------------------------------------------------- */ | |
/* from linux/sound/pci/hda/hda_intel.c */ | |
diff --git a/hw/audio/intel-hda.c b/hw/audio/intel-hda.c | |
index 18a50a8f83..9d3da3185b 100644 | |
--- a/hw/audio/intel-hda.c | |
+++ b/hw/audio/intel-hda.c | |
@@ -407,13 +407,13 @@ static bool intel_hda_xfer(HDACodecDevice *dev, uint32_t stnr, bool output, | |
if (st->bpl == NULL) { | |
return false; | |
} | |
- if (st->ctl & (1 << 26)) { | |
- /* | |
- * Wait with the next DMA xfer until the guest | |
- * has acked the buffer completion interrupt | |
- */ | |
- return false; | |
- } | |
+// if (st->ctl & (1 << 26)) { | |
+// /* | |
+// * Wait with the next DMA xfer until the guest | |
+// * has acked the buffer completion interrupt | |
+// */ | |
+// return false; | |
+// } | |
left = len; | |
s = st->bentries; | |
-- | |
2.14.1 | |
From 0e6c0f15659c56e87ca7bf21e9a2ef7053a82a0d Mon Sep 17 00:00:00 2001 | |
From: Martin Schrodt <[email protected]> | |
Date: Mon, 9 Oct 2017 00:33:41 +0200 | |
Subject: [PATCH 07/30] adjust defaults | |
--- | |
audio/paaudio.c | 18 ++---------------- | |
1 file changed, 2 insertions(+), 16 deletions(-) | |
diff --git a/audio/paaudio.c b/audio/paaudio.c | |
index a1a7e94d4b..894fcb0f71 100644 | |
--- a/audio/paaudio.c | |
+++ b/audio/paaudio.c | |
@@ -291,19 +291,6 @@ fail: | |
} | |
-static int64_t hob (int64_t num) | |
-{ | |
- if (!num) | |
- return 0; | |
- | |
- int ret = 1; | |
- | |
- while (num >>= 1) | |
- ret <<= 1; | |
- | |
- return ret; | |
-} | |
- | |
static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as, | |
void *drv_opaque) | |
{ | |
@@ -319,12 +306,11 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as, | |
int64_t tlength = g->conf.tlength; | |
if (tlength == 0) { | |
- tlength = (frames_per_tick_x1000) / 500; | |
+ tlength = (frames_per_tick_x1000) / 400; | |
} | |
int64_t buflen = g->conf.buffer_size; | |
if (buflen == 0) { | |
- buflen = hob(frames_per_tick_x1000 / 125); | |
- buflen = audio_MAX(HDA_BUFFER_SIZE, buflen); // must be at least HDA_BUFFER_SIZE bytes for HDA to work at all! | |
+ buflen = frames_per_tick_x1000 / 400; | |
} | |
float ms_per_frame = 1000.0f / as->freq; | |
-- | |
2.14.1 | |
From fe63cb9defe7f256bf11002316d641e21ffb0328 Mon Sep 17 00:00:00 2001 | |
From: Martin Schrodt <[email protected]> | |
Date: Tue, 10 Oct 2017 12:01:04 +0200 | |
Subject: [PATCH 08/30] Revert "improve audio timer" | |
This reverts commit aba100abab90382355731404e90d91b257366a8f. | |
--- | |
audio/audio.c | 34 +--------------------------------- | |
1 file changed, 1 insertion(+), 33 deletions(-) | |
diff --git a/audio/audio.c b/audio/audio.c | |
index fae6233caf..fba1604c34 100644 | |
--- a/audio/audio.c | |
+++ b/audio/audio.c | |
@@ -1121,42 +1121,10 @@ static void audio_reset_timer (AudioState *s) | |
} | |
} | |
- | |
-static int64_t ref_ns = -1; | |
-static int64_t last_ns = -1; | |
- | |
static void audio_timer (void *opaque) | |
{ | |
- int64_t start_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); | |
- if (ref_ns == -1) { | |
- ref_ns = start_ns - conf.period.ticks; | |
- last_ns = ref_ns; | |
- } | |
audio_run ("timer"); | |
- int64_t end_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); | |
- | |
- | |
- if ((end_ns - start_ns) > conf.period.ticks) { | |
- dolog("audio timer after %"PRId64" us (deviation %"PRId64" us), took %"PRId64" us\n", | |
- (start_ns - last_ns) / SCALE_US, | |
- (start_ns - (ref_ns + conf.period.ticks)) / SCALE_US, | |
- (end_ns - start_ns) / SCALE_US | |
- ); | |
- } | |
- | |
- last_ns = start_ns; | |
- | |
- AudioState *s = opaque; | |
- | |
- if (audio_is_timer_needed ()) { | |
- ref_ns += conf.period.ticks; | |
- timer_mod_anticipate_ns(s->ts, audio_MAX(ref_ns + conf.period.ticks, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 1)); | |
- } | |
- else { | |
- ref_ns = -1; | |
- timer_del (s->ts); | |
- } | |
- | |
+ audio_reset_timer (opaque); | |
} | |
/* | |
-- | |
2.14.1 | |
From 673dd8aaab8c6554474d7abd95f032a3e739b320 Mon Sep 17 00:00:00 2001 | |
From: Martin Schrodt <[email protected]> | |
Date: Tue, 10 Oct 2017 12:42:22 +0200 | |
Subject: [PATCH 09/30] fail safety in qpa_run_out | |
--- | |
audio/paaudio.c | 55 ++++++++++++++++++++++++++++++++++++++++++------------- | |
1 file changed, 42 insertions(+), 13 deletions(-) | |
diff --git a/audio/paaudio.c b/audio/paaudio.c | |
index 894fcb0f71..7c15b091fa 100644 | |
--- a/audio/paaudio.c | |
+++ b/audio/paaudio.c | |
@@ -87,6 +87,28 @@ static inline int PA_STREAM_IS_GOOD(pa_stream_state_t x) | |
} | |
#endif | |
+#define CHECK_SUCCESS_GOTO(c, rerror, expression, label) \ | |
+ do { \ | |
+ if (!(expression)) { \ | |
+ *(rerror) = pa_context_errno ((c)->context); \ | |
+ goto label; \ | |
+ } \ | |
+ } while (0); | |
+ | |
+#define CHECK_DEAD_GOTO(c, stream, rerror, label) \ | |
+ do { \ | |
+ if (!(c)->context || !PA_CONTEXT_IS_GOOD (pa_context_get_state((c)->context)) || \ | |
+ !(stream) || !PA_STREAM_IS_GOOD (pa_stream_get_state ((stream)))) { \ | |
+ if (((c)->context && pa_context_get_state ((c)->context) == PA_CONTEXT_FAILED) || \ | |
+ ((stream) && pa_stream_get_state ((stream)) == PA_STREAM_FAILED)) { \ | |
+ *(rerror) = pa_context_errno ((c)->context); \ | |
+ } else { \ | |
+ *(rerror) = PA_ERR_BADSTATE; \ | |
+ } \ | |
+ goto label; \ | |
+ } \ | |
+} while (0); | |
+ | |
static int qpa_run_out (HWVoiceOut *hw, int live) | |
{ | |
PAVoiceOut *pa = (PAVoiceOut *) hw; | |
@@ -94,22 +116,26 @@ static int qpa_run_out (HWVoiceOut *hw, int live) | |
size_t avail_bytes, max_bytes; | |
struct st_sample *src; | |
void *pa_dst; | |
+ int error = 0; | |
+ int r; | |
+ | |
+ decr = 0; | |
+ rpos = hw->rpos; | |
pa_threaded_mainloop_lock (pa->g->mainloop); | |
+ CHECK_DEAD_GOTO (pa->g, pa->stream, &error, fail); | |
avail_bytes = (size_t) live << hw->info.shift; | |
max_bytes = pa_stream_writable_size(pa->stream); | |
+ CHECK_SUCCESS_GOTO(pa->g, &error, max_bytes != -1, fail); | |
samples = (int)(audio_MIN (avail_bytes, max_bytes)) >> hw->info.shift; | |
- decr = samples; | |
- rpos = hw->rpos; | |
- | |
// if (avail_bytes < max_bytes) { | |
// dolog("avail: %d, wanted: %d \n", (int)avail_bytes, (int)max_bytes); | |
// } | |
- //dolog("TRANSFER avail: %d bytes, max %d bytes -> %d samples from %d\n", (int)avail_bytes, (int)max_bytes, samples, rpos); | |
+// dolog("TRANSFER avail: %d bytes, max %d bytes -> %d samples from %d\n", (int)avail_bytes, (int)max_bytes, samples, rpos); | |
while (samples) { | |
int left_till_end_samples = hw->samples - rpos; | |
@@ -118,28 +144,31 @@ static int qpa_run_out (HWVoiceOut *hw, int live) | |
size_t convert_bytes_wanted = (size_t) convert_samples << hw->info.shift; | |
size_t convert_bytes = convert_bytes_wanted; | |
- pa_stream_begin_write(pa->stream, &pa_dst, &convert_bytes); | |
- | |
- if (convert_bytes != convert_bytes_wanted) { | |
- dolog(" OOOPS wanted %d, got %d\n", (int)convert_bytes_wanted, (int)convert_bytes); | |
- } | |
+ r = pa_stream_begin_write(pa->stream, &pa_dst, &convert_bytes); | |
+ CHECK_SUCCESS_GOTO(pa->g, &error, r == 0, fail); | |
+ CHECK_SUCCESS_GOTO(pa->g, &error, convert_bytes == convert_bytes_wanted, fail); | |
src = hw->mix_buf + rpos; | |
hw->clip (pa_dst, src, convert_samples); | |
- pa_stream_write (pa->stream, pa_dst, convert_bytes, NULL, 0LL, PA_SEEK_RELATIVE); | |
+ r = pa_stream_write (pa->stream, pa_dst, convert_bytes, NULL, 0LL, PA_SEEK_RELATIVE); | |
+ CHECK_SUCCESS_GOTO(pa->g, &error, r >= 0, fail); | |
rpos = (rpos + convert_samples) % hw->samples; | |
samples -= convert_samples; | |
+ decr += convert_samples; | |
} | |
+ bail: | |
pa_threaded_mainloop_unlock (pa->g->mainloop); | |
- //dolog("\n"); | |
- | |
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) | |
-- | |
2.14.1 | |
From be6fcef0075fae6c664bf3164d7dd5a88ccfafba Mon Sep 17 00:00:00 2001 | |
From: Martin Schrodt <[email protected]> | |
Date: Tue, 10 Oct 2017 18:10:16 +0200 | |
Subject: [PATCH 10/30] add input functionality back to paaudio.c | |
--- | |
audio/paaudio.c | 296 ++++++++++++++++++++++++++++++++++++++++++++++----- | |
hw/audio/hda-codec.c | 127 ++++++++++++++++------ | |
2 files changed, 367 insertions(+), 56 deletions(-) | |
diff --git a/audio/paaudio.c b/audio/paaudio.c | |
index 7c15b091fa..089af32e4d 100644 | |
--- a/audio/paaudio.c | |
+++ b/audio/paaudio.c | |
@@ -23,7 +23,7 @@ | |
*/ | |
#include "qemu/osdep.h" | |
#include "audio.h" | |
-#include "hw/audio/intel-hda-defs.h" | |
+ | |
#include <pulse/pulseaudio.h> | |
#include <include/qemu/timer.h> | |
@@ -34,8 +34,10 @@ | |
typedef struct { | |
int buffer_size; | |
int tlength; | |
+ int fragsize; | |
#ifdef PA_STREAM_ADJUST_LATENCY | |
int adjust_latency_out; | |
+ int adjust_latency_in; | |
#endif | |
char *server; | |
char *sink; | |
@@ -52,8 +54,19 @@ typedef struct { | |
HWVoiceOut hw; | |
pa_stream *stream; | |
paaudio *g; | |
+ pa_sample_spec ss; | |
+ pa_buffer_attr ba; | |
} PAVoiceOut; | |
+typedef struct { | |
+ HWVoiceIn hw; | |
+ pa_stream *stream; | |
+ paaudio *g; | |
+ pa_sample_spec ss; | |
+ pa_buffer_attr ba; | |
+} PAVoiceIn; | |
+ | |
+ | |
static void qpa_audio_fini(void *opaque); | |
static void GCC_FMT_ATTR (2, 3) qpa_logerr (int err, const char *fmt, ...) | |
@@ -95,6 +108,7 @@ static inline int PA_STREAM_IS_GOOD(pa_stream_state_t x) | |
} \ | |
} while (0); | |
+ | |
#define CHECK_DEAD_GOTO(c, stream, rerror, label) \ | |
do { \ | |
if (!(c)->context || !PA_CONTEXT_IS_GOOD (pa_context_get_state((c)->context)) || \ | |
@@ -168,7 +182,6 @@ static int qpa_run_out (HWVoiceOut *hw, int live) | |
fail: | |
qpa_logerr (error, "qpa_run_out failed\n"); | |
goto bail; | |
- | |
} | |
static int qpa_write (SWVoiceOut *sw, void *buf, int len) | |
@@ -176,6 +189,93 @@ static int qpa_write (SWVoiceOut *sw, void *buf, int len) | |
return audio_pcm_sw_write (sw, buf, len); | |
} | |
+static int qpa_run_in (HWVoiceIn *hw) | |
+{ | |
+ PAVoiceIn *pa = (PAVoiceIn *) hw; | |
+ int wpos, incr; | |
+ char *pa_src; | |
+ int error = 0; | |
+ int r; | |
+ | |
+ incr = 0; | |
+ wpos = hw->wpos; | |
+ | |
+ pa_threaded_mainloop_lock (pa->g->mainloop); | |
+ CHECK_DEAD_GOTO (pa->g, pa->stream, &error, fail); | |
+ | |
+ size_t bytes_wanted = ((unsigned int)(hw->samples - audio_pcm_hw_get_live_in(hw)) << hw->info.shift); | |
+ if (bytes_wanted == 0) { | |
+ // no room | |
+ goto bail; | |
+ } | |
+ | |
+ size_t bytes_avail = pa_stream_readable_size(pa->stream); | |
+ | |
+ //dolog("WANT %d, HAVE %d\n", (int)bytes_wanted, (int) bytes_avail); | |
+ | |
+ size_t pa_avail; | |
+ | |
+ if (bytes_avail > bytes_wanted) { | |
+#if 0 | |
+ size_t to_drop = bytes_avail - bytes_wanted; | |
+ while (to_drop) { | |
+ r = pa_stream_peek(pa->stream, (const void **)&pa_src, &pa_avail); | |
+ CHECK_SUCCESS_GOTO(pa->g, &error, r == 0, fail); | |
+ if (to_drop < pa_avail) { | |
+ break; | |
+ } | |
+ r = pa_stream_drop(pa->stream); | |
+ CHECK_SUCCESS_GOTO(pa->g, &error, r == 0, fail); | |
+ to_drop -= pa_avail; | |
+ } | |
+ int n_dropped = (int)(bytes_avail - bytes_wanted - to_drop); | |
+ if(n_dropped) { | |
+ dolog("dropped %d bytes\n", n_dropped); | |
+ } | |
+#endif | |
+ } else if (bytes_wanted < bytes_avail) { | |
+ bytes_wanted = bytes_avail; | |
+ } | |
+ | |
+ while (bytes_wanted) { | |
+ r = pa_stream_peek(pa->stream, (const void **)&pa_src, &pa_avail); | |
+ CHECK_SUCCESS_GOTO(pa->g, &error, r == 0, fail); | |
+ if (pa_avail == 0 || pa_avail > bytes_wanted) { | |
+ break; | |
+ } | |
+ | |
+ bytes_wanted -= pa_avail; | |
+ | |
+ 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; | |
+ pa_src += chunk << hw->info.shift; | |
+ pa_avail -= chunk << hw->info.shift; | |
+ incr += chunk; | |
+ } | |
+ | |
+ r = pa_stream_drop(pa->stream); | |
+ CHECK_SUCCESS_GOTO(pa->g, &error, r == 0, fail); | |
+ } | |
+ | |
+ bail: | |
+ pa_threaded_mainloop_unlock (pa->g->mainloop); | |
+ | |
+ 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) | |
+{ | |
+ return audio_pcm_sw_read (sw, buf, len); | |
+} | |
+ | |
static pa_sample_format_t audfmt_to_pa (audfmt_e afmt, int endianness) | |
{ | |
pa_sample_format_t format; | |
@@ -294,7 +394,7 @@ static pa_stream *qpa_simple_new ( | |
r = pa_stream_connect_record (stream, dev, attr, | |
PA_STREAM_INTERPOLATE_TIMING | |
#ifdef PA_STREAM_ADJUST_LATENCY | |
- |PA_STREAM_ADJUST_LATENCY | |
+ | (g->conf.adjust_latency_in ? PA_STREAM_ADJUST_LATENCY : 0) | |
#endif | |
|PA_STREAM_AUTO_TIMING_UPDATE); | |
} | |
@@ -324,8 +424,6 @@ 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; | |
@@ -348,35 +446,35 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as, | |
((float) timer_tick_duration) / SCALE_MS, | |
(float)frames_per_tick_x1000 / 1000.0f); | |
- dolog("internal buffer: %.2f ms (%"PRId64" frames)\n", | |
+ dolog("OUT internal buffer: %.2f ms (%"PRId64" frames)\n", | |
buflen * ms_per_frame, | |
buflen); | |
- dolog("tlength: %.2f ms (%"PRId64" frames)\n", | |
+ dolog("OUT tlength: %.2f ms (%"PRId64" frames)\n", | |
tlength * ms_per_frame, | |
tlength); | |
- dolog("adjust latency: %s\n", g->conf.adjust_latency_out ? "yes" : "no"); | |
+ dolog("OUT adjust latency: %s\n", g->conf.adjust_latency_out ? "yes" : "no"); | |
- ss.format = audfmt_to_pa (as->fmt, as->endianness); | |
- ss.channels = as->nchannels; | |
- ss.rate = as->freq; | |
+ pa->ss.format = audfmt_to_pa (as->fmt, as->endianness); | |
+ pa->ss.channels = as->nchannels; | |
+ pa->ss.rate = as->freq; | |
- ba.tlength = tlength * pa_frame_size (&ss); | |
- ba.maxlength = -1; | |
- ba.minreq = -1; | |
- ba.prebuf = -1; | |
+ 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 (ss.format, &obt_as.endianness); | |
+ 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, | |
- &ss, | |
+ &pa->ss, | |
NULL, /* channel map */ | |
- &ba, /* buffering attributes */ | |
+ &pa->ba, /* buffering attributes */ | |
&error | |
); | |
if (!pa->stream) { | |
@@ -394,6 +492,74 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as, | |
} | |
+static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, | |
+ void *drv_opaque) | |
+{ | |
+ int error; | |
+ struct audsettings obt_as = *as; | |
+ PAVoiceIn *pa = (PAVoiceIn *) hw; | |
+ paaudio *g = pa->g = drv_opaque; | |
+ | |
+ 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 / 2500; | |
+ } | |
+ int64_t buflen = g->conf.buffer_size; | |
+ if (buflen == 0) { | |
+ buflen = frames_per_tick_x1000 / 400; | |
+ } | |
+ | |
+ float ms_per_frame = 1000.0f / as->freq; | |
+ | |
+ dolog("IN internal buffer: %.2f ms (%"PRId64" frames)\n", | |
+ buflen * ms_per_frame, | |
+ buflen); | |
+ | |
+ dolog("IN fragsize: %.2f ms (%"PRId64" frames)\n", | |
+ fragsize * ms_per_frame, | |
+ fragsize); | |
+ | |
+ dolog("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 = pa->ba.fragsize * 10; | |
+ 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 playback failed\n"); | |
+ goto fail1; | |
+ } | |
+ | |
+ audio_pcm_init_info (&hw->info, &obt_as); | |
+ hw->samples = buflen; | |
+ | |
+ return 0; | |
+ | |
+ fail1: | |
+ return -1; | |
+} | |
+ | |
+ | |
static void qpa_fini_out (HWVoiceOut *hw) | |
{ | |
PAVoiceOut *pa = (PAVoiceOut *) hw; | |
@@ -404,6 +570,16 @@ static void qpa_fini_out (HWVoiceOut *hw) | |
} | |
} | |
+static void qpa_fini_in (HWVoiceIn *hw) | |
+{ | |
+ PAVoiceIn *pa = (PAVoiceIn *) hw; | |
+ | |
+ if (pa->stream) { | |
+ pa_stream_unref (pa->stream); | |
+ pa->stream = NULL; | |
+ } | |
+} | |
+ | |
static int qpa_ctl_out (HWVoiceOut *hw, int cmd, ...) | |
{ | |
PAVoiceOut *pa = (PAVoiceOut *) hw; | |
@@ -456,10 +632,64 @@ static int qpa_ctl_out (HWVoiceOut *hw, int cmd, ...) | |
return 0; | |
} | |
+static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...) | |
+{ | |
+ PAVoiceIn *pa = (PAVoiceIn *) hw; | |
+ pa_operation *op; | |
+ pa_cvolume v; | |
+ paaudio *g = pa->g; | |
+ | |
+#ifdef PA_CHECK_VERSION | |
+ pa_cvolume_init (&v); | |
+#endif | |
+ | |
+ switch (cmd) { | |
+ case VOICE_VOLUME: | |
+ { | |
+ SWVoiceIn *sw; | |
+ va_list ap; | |
+ | |
+ va_start (ap, cmd); | |
+ sw = va_arg (ap, SWVoiceIn *); | |
+ va_end (ap); | |
+ | |
+ v.channels = 2; | |
+ v.values[0] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.l) / UINT32_MAX; | |
+ v.values[1] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.r) / UINT32_MAX; | |
+ | |
+ pa_threaded_mainloop_lock (g->mainloop); | |
+ | |
+ op = pa_context_set_source_output_volume (g->context, | |
+ pa_stream_get_index (pa->stream), | |
+ &v, NULL, NULL); | |
+ if (!op) { | |
+ qpa_logerr (pa_context_errno (g->context), | |
+ "set_source_output_volume() failed\n"); | |
+ } else { | |
+ pa_operation_unref(op); | |
+ } | |
+ | |
+ op = pa_context_set_source_output_mute (g->context, | |
+ pa_stream_get_index (pa->stream), | |
+ sw->vol.mute, NULL, NULL); | |
+ if (!op) { | |
+ qpa_logerr (pa_context_errno (g->context), | |
+ "set_source_output_mute() failed\n"); | |
+ } else { | |
+ pa_operation_unref (op); | |
+ } | |
+ | |
+ pa_threaded_mainloop_unlock (g->mainloop); | |
+ } | |
+ } | |
+ return 0; | |
+} | |
+ | |
/* common */ | |
static PAConf glob_conf = { | |
#ifdef PA_STREAM_ADJUST_LATENCY | |
.adjust_latency_out = 0, | |
+ .adjust_latency_in = 1, | |
#endif | |
}; | |
@@ -560,12 +790,24 @@ struct audio_option qpa_options[] = { | |
.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" | |
+ }, | |
#ifdef PA_STREAM_ADJUST_LATENCY | |
{ | |
- .name = "ADJUST_LATENCY_OUT", | |
- .tag = AUD_OPT_BOOL, | |
- .valp = &glob_conf.adjust_latency_out, | |
- .descr = "let PA adjust latency for playback device" | |
+ .name = "ADJUST_LATENCY_OUT", | |
+ .tag = AUD_OPT_BOOL, | |
+ .valp = &glob_conf.adjust_latency_out, | |
+ .descr = "let PA adjust latency for playback device" | |
+ }, | |
+ { | |
+ .name = "ADJUST_LATENCY_IN", | |
+ .tag = AUD_OPT_BOOL, | |
+ .valp = &glob_conf.adjust_latency_in, | |
+ .descr = "let PA adjust latency for recording device" | |
}, | |
#endif | |
{ | |
@@ -595,6 +837,12 @@ static struct audio_pcm_ops qpa_pcm_ops = { | |
.run_out = qpa_run_out, | |
.write = qpa_write, | |
.ctl_out = qpa_ctl_out, | |
+ | |
+ .init_in = qpa_init_in, | |
+ .fini_in = qpa_fini_in, | |
+ .run_in = qpa_run_in, | |
+ .read = qpa_read, | |
+ .ctl_in = qpa_ctl_in | |
}; | |
struct audio_driver pa_audio_driver = { | |
@@ -606,8 +854,8 @@ struct audio_driver pa_audio_driver = { | |
.pcm_ops = &qpa_pcm_ops, | |
.can_be_default = 1, | |
.max_voices_out = INT_MAX, | |
- .max_voices_in = 0, | |
+ .max_voices_in = INT_MAX, | |
.voice_size_out = sizeof (PAVoiceOut), | |
- .voice_size_in = 0, | |
+ .voice_size_in = sizeof (PAVoiceIn), | |
.ctl_caps = VOICE_VOLUME_CAP | |
}; | |
diff --git a/hw/audio/hda-codec.c b/hw/audio/hda-codec.c | |
index 009d9bc2eb..760bfe40d4 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" | |
@@ -179,30 +180,91 @@ struct HDAAudioState { | |
bool mixer; | |
}; | |
+static void hda_audio_input_timer(void *opaque) { | |
+ | |
+#define B_SIZE sizeof(st->buf) | |
+#define B_MASK (sizeof(st->buf) - 1) | |
+ | |
+ HDAAudioStream *st = opaque; | |
+ | |
+ int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); | |
+ | |
+ int64_t buft_start = atomic_fetch_add(&st->buft_start, 0); | |
+ int64_t wpos = atomic_fetch_add(&st->wpos, 0); | |
+ int64_t rpos = atomic_fetch_add(&st->rpos, 0); | |
+ | |
+ int64_t wanted_rpos = (st->as.freq * 4 * (now - buft_start)) / NANOSECONDS_PER_SECOND; | |
+ wanted_rpos &= -4; // IMPORTANT! clip to frames | |
+ | |
+ if (wanted_rpos <= rpos) { | |
+ // we already transmitted the data | |
+ goto out_timer; | |
+ } | |
+ | |
+ if (wpos - rpos >= B_SIZE) { | |
+ goto out_timer; | |
+ } | |
+ | |
+ //dolog("%"PRId64"\n", wpos - rpos); | |
+ | |
+ //dolog("rpos: %"PRId64", wpos: %"PRId64", wanted: %"PRId64"\n", rpos, wpos, wanted_wpos); | |
+ int64_t to_transfer = audio_MIN(B_SIZE - (wpos - rpos), wanted_rpos - rpos); | |
+ while (to_transfer) { | |
+ uint32_t start = (rpos & B_MASK); | |
+ uint32_t chunk = audio_MIN(B_SIZE - start, to_transfer); | |
+ int rc = hda_codec_xfer(&st->state->hda, st->stream, false, st->buf + start, chunk); | |
+ if (!rc) { | |
+ break; | |
+ } | |
+ rpos += chunk; | |
+ to_transfer -= chunk; | |
+ atomic_fetch_add(&st->rpos, chunk); | |
+ } | |
+ | |
+#undef B_MASK | |
+#undef B_SIZE | |
+ | |
+ out_timer: | |
+ | |
+ if (st->running) { | |
+ timer_mod_anticipate_ns(st->buft, now + HDA_TIMER_TICKS); | |
+ } | |
+} | |
+ | |
+ | |
static void hda_audio_input_cb(void *opaque, int avail) | |
{ | |
-// HDAAudioStream *st = opaque; | |
-// int recv = 0; | |
-// int len; | |
-// bool rc; | |
-// | |
-// while (avail - recv >= sizeof(st->buf)) { | |
-// if (st->bpos != sizeof(st->buf)) { | |
-// len = AUD_read(st->voice.in, st->buf + st->bpos, | |
-// sizeof(st->buf) - st->bpos); | |
-// st->bpos += len; | |
-// recv += len; | |
-// if (st->bpos != sizeof(st->buf)) { | |
-// break; | |
-// } | |
-// } | |
-// rc = hda_codec_xfer(&st->state->hda, st->stream, false, | |
-// st->buf, sizeof(st->buf)); | |
-// if (!rc) { | |
-// break; | |
-// } | |
-// st->bpos = 0; | |
+#define B_SIZE sizeof(st->buf) | |
+#define B_MASK (sizeof(st->buf) - 1) | |
+ | |
+ HDAAudioStream *st = opaque; | |
+ | |
+ int64_t wpos = atomic_fetch_add(&st->wpos, 0); | |
+ int64_t rpos = atomic_fetch_add(&st->rpos, 0); | |
+ | |
+ int64_t to_transfer = audio_MIN(wpos - rpos, avail); | |
+ | |
+// int64_t overflow = wpos - rpos - to_transfer - (B_SIZE >> 3); | |
+// if (overflow > 0) { | |
+// int64_t corr = NANOSECONDS_PER_SECOND * overflow / (4 * st->as.freq); | |
+// //dolog("CORR %"PRId64"\n", corr); | |
+// atomic_fetch_add(&st->buft_start, corr); | |
// } | |
+ | |
+ while (to_transfer) { | |
+ uint32_t start = (uint32_t) (wpos & B_MASK); | |
+ uint32_t chunk = (uint32_t) audio_MIN(B_SIZE - start, to_transfer); | |
+ uint32_t read = AUD_read(st->voice.in, st->buf + start, chunk); | |
+ wpos += read; | |
+ to_transfer -= read; | |
+ atomic_fetch_add(&st->wpos, read); | |
+ if (chunk != read) { | |
+ break; | |
+ } | |
+ } | |
+ | |
+#undef B_MASK | |
+#undef B_SIZE | |
} | |
@@ -217,14 +279,15 @@ static void hda_audio_output_timer(void *opaque) { | |
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); | |
- int64_t wanted_wpos = (st->as.freq * 4 * (now - st->buft_start)) / NANOSECONDS_PER_SECOND; | |
- wanted_wpos &= -4; // IMPORTANT! clip to frames | |
+ int64_t buft_start = atomic_fetch_add(&st->buft_start, 0); | |
+ int64_t wpos = atomic_fetch_add(&st->wpos, 0); | |
+ int64_t rpos = atomic_fetch_add(&st->rpos, 0); | |
- int64_t wpos = st->wpos; | |
- int64_t rpos = st->rpos; | |
+ int64_t wanted_wpos = (st->as.freq * 4 * (now - buft_start)) / NANOSECONDS_PER_SECOND; | |
+ wanted_wpos &= -4; // IMPORTANT! clip to frames | |
if (wanted_wpos <= wpos) { | |
- // we already have the data | |
+ // we already received the data | |
goto out_timer; | |
} | |
@@ -245,8 +308,8 @@ static void hda_audio_output_timer(void *opaque) { | |
} | |
wpos += chunk; | |
to_transfer -= chunk; | |
+ atomic_fetch_add(&st->wpos, chunk); | |
} | |
- st->wpos = wpos; | |
#undef B_MASK | |
#undef B_SIZE | |
@@ -265,8 +328,8 @@ static void hda_audio_output_cb(void *opaque, int avail) | |
HDAAudioStream *st = opaque; | |
- int64_t wpos = st->wpos; | |
- int64_t rpos = st->rpos; | |
+ int64_t wpos = atomic_fetch_add(&st->wpos, 0); | |
+ int64_t rpos = atomic_fetch_add(&st->rpos, 0); | |
int64_t to_transfer = audio_MIN(wpos - rpos, avail); | |
@@ -274,7 +337,7 @@ static void hda_audio_output_cb(void *opaque, int avail) | |
if (overflow > 0) { | |
int64_t corr = NANOSECONDS_PER_SECOND * overflow / (4 * st->as.freq); | |
//dolog("CORR %"PRId64"\n", corr); | |
- st->buft_start += corr; | |
+ atomic_fetch_add(&st->buft_start, corr); | |
} | |
while (to_transfer) { | |
@@ -283,13 +346,12 @@ static void hda_audio_output_cb(void *opaque, int avail) | |
uint32_t written = AUD_write(st->voice.out, st->buf + start, chunk); | |
rpos += written; | |
to_transfer -= written; | |
+ atomic_fetch_add(&st->rpos, written); | |
if (chunk != written) { | |
break; | |
} | |
} | |
- st->rpos = rpos; | |
- | |
#undef B_MASK | |
#undef B_SIZE | |
} | |
@@ -368,6 +430,7 @@ static void hda_audio_setup(HDAAudioStream *st) | |
st->voice.in = AUD_open_in(&st->state->card, st->voice.in, | |
st->node->name, st, | |
hda_audio_input_cb, &st->as); | |
+ st->buft = timer_new_ns(QEMU_CLOCK_VIRTUAL, hda_audio_input_timer, st); | |
} | |
} | |
-- | |
2.14.1 | |
From c06237f676ff4d75037678f829504006c55cdb04 Mon Sep 17 00:00:00 2001 | |
From: Martin Schrodt <[email protected]> | |
Date: Sat, 14 Oct 2017 21:27:39 +0200 | |
Subject: [PATCH 11/30] fix wrong calculation of input buffer transfer size | |
--- | |
hw/audio/hda-codec.c | 5 +++-- | |
1 file changed, 3 insertions(+), 2 deletions(-) | |
diff --git a/hw/audio/hda-codec.c b/hw/audio/hda-codec.c | |
index 760bfe40d4..60a5e40827 100644 | |
--- a/hw/audio/hda-codec.c | |
+++ b/hw/audio/hda-codec.c | |
@@ -180,6 +180,8 @@ struct HDAAudioState { | |
bool mixer; | |
}; | |
+#define dolog(fmt, ...) AUD_log("", fmt, ## __VA_ARGS__) | |
+ | |
static void hda_audio_input_timer(void *opaque) { | |
#define B_SIZE sizeof(st->buf) | |
@@ -242,7 +244,7 @@ static void hda_audio_input_cb(void *opaque, int avail) | |
int64_t wpos = atomic_fetch_add(&st->wpos, 0); | |
int64_t rpos = atomic_fetch_add(&st->rpos, 0); | |
- int64_t to_transfer = audio_MIN(wpos - rpos, avail); | |
+ int64_t to_transfer = audio_MIN(B_SIZE - (wpos - rpos), avail); | |
// int64_t overflow = wpos - rpos - to_transfer - (B_SIZE >> 3); | |
// if (overflow > 0) { | |
@@ -268,7 +270,6 @@ static void hda_audio_input_cb(void *opaque, int avail) | |
} | |
-#define dolog(fmt, ...) AUD_log("XX", fmt, ## __VA_ARGS__) | |
static void hda_audio_output_timer(void *opaque) { | |
-- | |
2.14.1 | |
From fb256bfbb1d19c28c5fdaeaddc3d17b205cee2c5 Mon Sep 17 00:00:00 2001 | |
From: Martin Schrodt <[email protected]> | |
Date: Sun, 15 Oct 2017 01:22:55 +0200 | |
Subject: [PATCH 12/30] try better correction | |
--- | |
hw/audio/hda-codec.c | 32 +++++++++++++++++++++----------- | |
1 file changed, 21 insertions(+), 11 deletions(-) | |
diff --git a/hw/audio/hda-codec.c b/hw/audio/hda-codec.c | |
index 60a5e40827..872840f602 100644 | |
--- a/hw/audio/hda-codec.c | |
+++ b/hw/audio/hda-codec.c | |
@@ -182,6 +182,8 @@ struct HDAAudioState { | |
#define dolog(fmt, ...) AUD_log("", fmt, ## __VA_ARGS__) | |
+#define MAX_CORR (SCALE_US * 100) | |
+ | |
static void hda_audio_input_timer(void *opaque) { | |
#define B_SIZE sizeof(st->buf) | |
@@ -246,12 +248,16 @@ static void hda_audio_input_cb(void *opaque, int avail) | |
int64_t to_transfer = audio_MIN(B_SIZE - (wpos - rpos), avail); | |
-// int64_t overflow = wpos - rpos - to_transfer - (B_SIZE >> 3); | |
-// if (overflow > 0) { | |
-// int64_t corr = NANOSECONDS_PER_SECOND * overflow / (4 * st->as.freq); | |
-// //dolog("CORR %"PRId64"\n", corr); | |
-// atomic_fetch_add(&st->buft_start, corr); | |
-// } | |
+ | |
+ int64_t c = (wpos - rpos) + to_transfer - (B_SIZE >> 1); | |
+ int64_t corr = NANOSECONDS_PER_SECOND * c / (4 * st->as.freq); | |
+ if (corr > MAX_CORR) { | |
+ corr = MAX_CORR; | |
+ } else if (corr < -MAX_CORR) { | |
+ corr = -MAX_CORR; | |
+ } | |
+ //dolog("CORR %"PRId64"\n", -corr); | |
+ atomic_fetch_add(&st->buft_start, -corr); | |
while (to_transfer) { | |
uint32_t start = (uint32_t) (wpos & B_MASK); | |
@@ -334,12 +340,16 @@ static void hda_audio_output_cb(void *opaque, int avail) | |
int64_t to_transfer = audio_MIN(wpos - rpos, avail); | |
- int64_t overflow = wpos - rpos - to_transfer - (B_SIZE >> 3); | |
- if (overflow > 0) { | |
- int64_t corr = NANOSECONDS_PER_SECOND * overflow / (4 * st->as.freq); | |
- //dolog("CORR %"PRId64"\n", corr); | |
- atomic_fetch_add(&st->buft_start, corr); | |
+ | |
+ int64_t c = (wpos - rpos) - to_transfer - (B_SIZE >> 1); | |
+ int64_t corr = NANOSECONDS_PER_SECOND * c / (4 * st->as.freq); | |
+ if (corr > MAX_CORR) { | |
+ corr = MAX_CORR; | |
+ } else if (corr < -MAX_CORR) { | |
+ corr = -MAX_CORR; | |
} | |
+ //dolog("CORR %"PRId64"\n", corr); | |
+ atomic_fetch_add(&st->buft_start, corr); | |
while (to_transfer) { | |
uint32_t start = (uint32_t) (rpos & B_MASK); | |
-- | |
2.14.1 | |
From 5562825af1ffd49b509032ec4e5370d259f04963 Mon Sep 17 00:00:00 2001 | |
From: Martin Schrodt <[email protected]> | |
Date: Sun, 15 Oct 2017 11:35:05 +0200 | |
Subject: [PATCH 13/30] PA_STREAM_ADJUST_LATENCY supported since PA 0.9.11 | |
(July 2008), can now safely require it | |
--- | |
audio/paaudio.c | 8 -------- | |
1 file changed, 8 deletions(-) | |
diff --git a/audio/paaudio.c b/audio/paaudio.c | |
index 089af32e4d..fd94d73fe4 100644 | |
--- a/audio/paaudio.c | |
+++ b/audio/paaudio.c | |
@@ -35,10 +35,8 @@ typedef struct { | |
int buffer_size; | |
int tlength; | |
int fragsize; | |
-#ifdef PA_STREAM_ADJUST_LATENCY | |
int adjust_latency_out; | |
int adjust_latency_in; | |
-#endif | |
char *server; | |
char *sink; | |
char *source; | |
@@ -386,16 +384,12 @@ static pa_stream *qpa_simple_new ( | |
if (dir == PA_STREAM_PLAYBACK) { | |
r = pa_stream_connect_playback (stream, dev, attr, | |
PA_STREAM_INTERPOLATE_TIMING | |
-#ifdef PA_STREAM_ADJUST_LATENCY | |
| (g->conf.adjust_latency_out ? PA_STREAM_ADJUST_LATENCY : 0) | |
-#endif | |
|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 | |
| (g->conf.adjust_latency_in ? PA_STREAM_ADJUST_LATENCY : 0) | |
-#endif | |
|PA_STREAM_AUTO_TIMING_UPDATE); | |
} | |
@@ -796,7 +790,6 @@ struct audio_option qpa_options[] = { | |
.valp = &glob_conf.fragsize, | |
.descr = "fragment length of recording device in frames" | |
}, | |
-#ifdef PA_STREAM_ADJUST_LATENCY | |
{ | |
.name = "ADJUST_LATENCY_OUT", | |
.tag = AUD_OPT_BOOL, | |
@@ -809,7 +802,6 @@ struct audio_option qpa_options[] = { | |
.valp = &glob_conf.adjust_latency_in, | |
.descr = "let PA adjust latency for recording device" | |
}, | |
-#endif | |
{ | |
.name = "SERVER", | |
.tag = AUD_OPT_STR, | |
-- | |
2.14.1 | |
From 71f329de776f55a493069b2008cbfb4a1871e2f9 Mon Sep 17 00:00:00 2001 | |
From: Martin Schrodt <[email protected]> | |
Date: Sun, 15 Oct 2017 11:36:15 +0200 | |
Subject: [PATCH 14/30] leave code in public domain | |
--- | |
audio/paaudio.c | 24 +----------------------- | |
1 file changed, 1 insertion(+), 23 deletions(-) | |
diff --git a/audio/paaudio.c b/audio/paaudio.c | |
index fd94d73fe4..55dd5d755d 100644 | |
--- a/audio/paaudio.c | |
+++ b/audio/paaudio.c | |
@@ -1,26 +1,4 @@ | |
-/* | |
- * QEMU ALSA audio driver | |
- * | |
- * Copyright (c) 2017 Martin Schrodt (spheenik) | |
- * | |
- * Permission is hereby granted, free of charge, to any person obtaining a copy | |
- * of this software and associated documentation files (the "Software"), to deal | |
- * in the Software without restriction, including without limitation the rights | |
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
- * copies of the Software, and to permit persons to whom the Software is | |
- * furnished to do so, subject to the following conditions: | |
- * | |
- * The above copyright notice and this permission notice shall be included in | |
- * all copies or substantial portions of the Software. | |
- * | |
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
- * THE SOFTWARE. | |
- */ | |
+/* public domain */ | |
#include "qemu/osdep.h" | |
#include "audio.h" | |
-- | |
2.14.1 | |
From 934d0176620c95b787466aac8ac17fc1ed063ad6 Mon Sep 17 00:00:00 2001 | |
From: Martin Schrodt <[email protected]> | |
Date: Sun, 15 Oct 2017 13:40:23 +0200 | |
Subject: [PATCH 15/30] cleanup HDA timer code | |
--- | |
hw/audio/hda-codec.c | 113 ++++++++++++++++----------------------------------- | |
hw/audio/intel-hda.c | 7 ---- | |
2 files changed, 34 insertions(+), 86 deletions(-) | |
diff --git a/hw/audio/hda-codec.c b/hw/audio/hda-codec.c | |
index 872840f602..af686eb1f3 100644 | |
--- a/hw/audio/hda-codec.c | |
+++ b/hw/audio/hda-codec.c | |
@@ -127,6 +127,10 @@ static void hda_codec_parse_fmt(uint32_t format, struct audsettings *as) | |
#define PARAM nomixemu | |
#include "hda-codec-common.h" | |
+#define MAX_CORR (SCALE_US * 100) | |
+#define B_SIZE sizeof(st->buf) | |
+#define B_MASK (sizeof(st->buf) - 1) | |
+ | |
/* -------------------------------------------------------------------------- */ | |
static const char *fmt2name[] = { | |
@@ -155,7 +159,7 @@ struct HDAAudioStream { | |
SWVoiceIn *in; | |
SWVoiceOut *out; | |
} voice; | |
- uint8_t buf[8192]; | |
+ uint8_t buf[8192]; // size must be power of two | |
int64_t rpos; | |
int64_t wpos; | |
QEMUTimer *buft; | |
@@ -180,15 +184,24 @@ struct HDAAudioState { | |
bool mixer; | |
}; | |
-#define dolog(fmt, ...) AUD_log("", fmt, ## __VA_ARGS__) | |
- | |
-#define MAX_CORR (SCALE_US * 100) | |
- | |
-static void hda_audio_input_timer(void *opaque) { | |
+static inline int64_t hda_bytes_per_second(HDAAudioStream *st) | |
+{ | |
+ return 2 * st->as.nchannels * st->as.freq; | |
+} | |
-#define B_SIZE sizeof(st->buf) | |
-#define B_MASK (sizeof(st->buf) - 1) | |
+static inline void hda_timer_sync_adjust(HDAAudioStream *st, int64_t target_pos) | |
+{ | |
+ int64_t corr = NANOSECONDS_PER_SECOND * target_pos / hda_bytes_per_second(st); | |
+ if (corr > MAX_CORR) { | |
+ corr = MAX_CORR; | |
+ } else if (corr < -MAX_CORR) { | |
+ corr = -MAX_CORR; | |
+ } | |
+ atomic_fetch_add(&st->buft_start, corr); | |
+} | |
+static void hda_audio_input_timer(void *opaque) | |
+{ | |
HDAAudioStream *st = opaque; | |
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); | |
@@ -197,7 +210,7 @@ static void hda_audio_input_timer(void *opaque) { | |
int64_t wpos = atomic_fetch_add(&st->wpos, 0); | |
int64_t rpos = atomic_fetch_add(&st->rpos, 0); | |
- int64_t wanted_rpos = (st->as.freq * 4 * (now - buft_start)) / NANOSECONDS_PER_SECOND; | |
+ int64_t wanted_rpos = hda_bytes_per_second(st) * (now - buft_start) / NANOSECONDS_PER_SECOND; | |
wanted_rpos &= -4; // IMPORTANT! clip to frames | |
if (wanted_rpos <= rpos) { | |
@@ -205,14 +218,7 @@ static void hda_audio_input_timer(void *opaque) { | |
goto out_timer; | |
} | |
- if (wpos - rpos >= B_SIZE) { | |
- goto out_timer; | |
- } | |
- | |
- //dolog("%"PRId64"\n", wpos - rpos); | |
- | |
- //dolog("rpos: %"PRId64", wpos: %"PRId64", wanted: %"PRId64"\n", rpos, wpos, wanted_wpos); | |
- int64_t to_transfer = audio_MIN(B_SIZE - (wpos - rpos), wanted_rpos - rpos); | |
+ int64_t to_transfer = audio_MIN(wpos - rpos, wanted_rpos - rpos); | |
while (to_transfer) { | |
uint32_t start = (rpos & B_MASK); | |
uint32_t chunk = audio_MIN(B_SIZE - start, to_transfer); | |
@@ -225,22 +231,15 @@ static void hda_audio_input_timer(void *opaque) { | |
atomic_fetch_add(&st->rpos, chunk); | |
} | |
-#undef B_MASK | |
-#undef B_SIZE | |
- | |
- out_timer: | |
+out_timer: | |
if (st->running) { | |
timer_mod_anticipate_ns(st->buft, now + HDA_TIMER_TICKS); | |
} | |
} | |
- | |
static void hda_audio_input_cb(void *opaque, int avail) | |
{ | |
-#define B_SIZE sizeof(st->buf) | |
-#define B_MASK (sizeof(st->buf) - 1) | |
- | |
HDAAudioStream *st = opaque; | |
int64_t wpos = atomic_fetch_add(&st->wpos, 0); | |
@@ -248,16 +247,7 @@ static void hda_audio_input_cb(void *opaque, int avail) | |
int64_t to_transfer = audio_MIN(B_SIZE - (wpos - rpos), avail); | |
- | |
- int64_t c = (wpos - rpos) + to_transfer - (B_SIZE >> 1); | |
- int64_t corr = NANOSECONDS_PER_SECOND * c / (4 * st->as.freq); | |
- if (corr > MAX_CORR) { | |
- corr = MAX_CORR; | |
- } else if (corr < -MAX_CORR) { | |
- corr = -MAX_CORR; | |
- } | |
- //dolog("CORR %"PRId64"\n", -corr); | |
- atomic_fetch_add(&st->buft_start, -corr); | |
+ hda_timer_sync_adjust(st, -((wpos - rpos) + to_transfer - (B_SIZE >> 1))); | |
while (to_transfer) { | |
uint32_t start = (uint32_t) (wpos & B_MASK); | |
@@ -270,18 +260,10 @@ static void hda_audio_input_cb(void *opaque, int avail) | |
break; | |
} | |
} | |
- | |
-#undef B_MASK | |
-#undef B_SIZE | |
} | |
- | |
- | |
-static void hda_audio_output_timer(void *opaque) { | |
- | |
-#define B_SIZE sizeof(st->buf) | |
-#define B_MASK (sizeof(st->buf) - 1) | |
- | |
+static void hda_audio_output_timer(void *opaque) | |
+{ | |
HDAAudioStream *st = opaque; | |
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); | |
@@ -290,7 +272,7 @@ static void hda_audio_output_timer(void *opaque) { | |
int64_t wpos = atomic_fetch_add(&st->wpos, 0); | |
int64_t rpos = atomic_fetch_add(&st->rpos, 0); | |
- int64_t wanted_wpos = (st->as.freq * 4 * (now - buft_start)) / NANOSECONDS_PER_SECOND; | |
+ int64_t wanted_wpos = hda_bytes_per_second(st) * (now - buft_start) / NANOSECONDS_PER_SECOND; | |
wanted_wpos &= -4; // IMPORTANT! clip to frames | |
if (wanted_wpos <= wpos) { | |
@@ -298,13 +280,6 @@ static void hda_audio_output_timer(void *opaque) { | |
goto out_timer; | |
} | |
- if (wpos - rpos >= B_SIZE) { | |
- goto out_timer; | |
- } | |
- | |
- //dolog("%"PRId64"\n", wpos - rpos); | |
- | |
- //dolog("rpos: %"PRId64", wpos: %"PRId64", wanted: %"PRId64"\n", rpos, wpos, wanted_wpos); | |
int64_t to_transfer = audio_MIN(B_SIZE - (wpos - rpos), wanted_wpos - wpos); | |
while (to_transfer) { | |
uint32_t start = (wpos & B_MASK); | |
@@ -318,10 +293,7 @@ static void hda_audio_output_timer(void *opaque) { | |
atomic_fetch_add(&st->wpos, chunk); | |
} | |
-#undef B_MASK | |
-#undef B_SIZE | |
- | |
- out_timer: | |
+out_timer: | |
if (st->running) { | |
timer_mod_anticipate_ns(st->buft, now + HDA_TIMER_TICKS); | |
@@ -330,9 +302,6 @@ static void hda_audio_output_timer(void *opaque) { | |
static void hda_audio_output_cb(void *opaque, int avail) | |
{ | |
-#define B_SIZE sizeof(st->buf) | |
-#define B_MASK (sizeof(st->buf) - 1) | |
- | |
HDAAudioStream *st = opaque; | |
int64_t wpos = atomic_fetch_add(&st->wpos, 0); | |
@@ -340,16 +309,7 @@ static void hda_audio_output_cb(void *opaque, int avail) | |
int64_t to_transfer = audio_MIN(wpos - rpos, avail); | |
- | |
- int64_t c = (wpos - rpos) - to_transfer - (B_SIZE >> 1); | |
- int64_t corr = NANOSECONDS_PER_SECOND * c / (4 * st->as.freq); | |
- if (corr > MAX_CORR) { | |
- corr = MAX_CORR; | |
- } else if (corr < -MAX_CORR) { | |
- corr = -MAX_CORR; | |
- } | |
- //dolog("CORR %"PRId64"\n", corr); | |
- atomic_fetch_add(&st->buft_start, corr); | |
+ hda_timer_sync_adjust(st, (wpos - rpos) - to_transfer - (B_SIZE >> 1)); | |
while (to_transfer) { | |
uint32_t start = (uint32_t) (rpos & B_MASK); | |
@@ -362,9 +322,6 @@ static void hda_audio_output_cb(void *opaque, int avail) | |
break; | |
} | |
} | |
- | |
-#undef B_MASK | |
-#undef B_SIZE | |
} | |
static void hda_audio_set_running(HDAAudioStream *st, bool running) | |
@@ -376,7 +333,8 @@ static void hda_audio_set_running(HDAAudioStream *st, bool running) | |
return; | |
} | |
st->running = running; | |
- | |
+ dprint(st->state, 1, "%s: %s (stream %d)\n", st->node->name, | |
+ st->running ? "on" : "off", st->stream); | |
if (running) { | |
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); | |
st->rpos = 0; | |
@@ -384,11 +342,8 @@ static void hda_audio_set_running(HDAAudioStream *st, bool running) | |
st->buft_start = now; | |
timer_mod_anticipate_ns(st->buft, now + HDA_TIMER_TICKS); | |
} else { | |
- timer_del (st->buft); | |
+ timer_del(st->buft); | |
} | |
- | |
- dprint(st->state, 1, "%s: %s (stream %d)\n", st->node->name, | |
- st->running ? "on" : "off", st->stream); | |
if (st->output) { | |
AUD_set_active_out(st->voice.out, st->running); | |
} else { | |
@@ -683,8 +638,8 @@ static void hda_audio_exit(HDACodecDevice *hda) | |
if (st->node == NULL) { | |
continue; | |
} | |
+ timer_del(st->buft); | |
if (st->output) { | |
- timer_del (st->buft); | |
AUD_close_out(&a->card, st->voice.out); | |
} else { | |
AUD_close_in(&a->card, st->voice.in); | |
diff --git a/hw/audio/intel-hda.c b/hw/audio/intel-hda.c | |
index 9d3da3185b..721eba792d 100644 | |
--- a/hw/audio/intel-hda.c | |
+++ b/hw/audio/intel-hda.c | |
@@ -407,13 +407,6 @@ static bool intel_hda_xfer(HDACodecDevice *dev, uint32_t stnr, bool output, | |
if (st->bpl == NULL) { | |
return false; | |
} | |
-// if (st->ctl & (1 << 26)) { | |
-// /* | |
-// * Wait with the next DMA xfer until the guest | |
-// * has acked the buffer completion interrupt | |
-// */ | |
-// return false; | |
-// } | |
left = len; | |
s = st->bentries; | |
-- | |
2.14.1 | |
From 0c2e3ea755f205b3060b8d93987766c8268293f6 Mon Sep 17 00:00:00 2001 | |
From: Martin Schrodt <[email protected]> | |
Date: Sun, 15 Oct 2017 13:53:50 +0200 | |
Subject: [PATCH 16/30] cleanup PA driver code | |
--- | |
audio/paaudio.c | 153 ++++++++++++++++++++++++-------------------------------- | |
1 file changed, 66 insertions(+), 87 deletions(-) | |
diff --git a/audio/paaudio.c b/audio/paaudio.c | |
index 55dd5d755d..4f6fb4965c 100644 | |
--- a/audio/paaudio.c | |
+++ b/audio/paaudio.c | |
@@ -1,16 +1,16 @@ | |
/* public domain */ | |
#include "qemu/osdep.h" | |
+#include "qemu/timer.h" | |
#include "audio.h" | |
- | |
#include <pulse/pulseaudio.h> | |
-#include <include/qemu/timer.h> | |
#define AUDIO_CAP "pulseaudio" | |
#include "audio_int.h" | |
typedef struct { | |
- int buffer_size; | |
+ int buffer_size_out; | |
+ int buffer_size_in; | |
int tlength; | |
int fragsize; | |
int adjust_latency_out; | |
@@ -42,7 +42,6 @@ typedef struct { | |
pa_buffer_attr ba; | |
} PAVoiceIn; | |
- | |
static void qpa_audio_fini(void *opaque); | |
static void GCC_FMT_ATTR (2, 3) qpa_logerr (int err, const char *fmt, ...) | |
@@ -79,25 +78,30 @@ static inline int PA_STREAM_IS_GOOD(pa_stream_state_t x) | |
#define CHECK_SUCCESS_GOTO(c, rerror, expression, label) \ | |
do { \ | |
if (!(expression)) { \ | |
- *(rerror) = pa_context_errno ((c)->context); \ | |
+ if (rerror) { \ | |
+ *(rerror) = pa_context_errno ((c)->context); \ | |
+ } \ | |
goto label; \ | |
} \ | |
} while (0); | |
- | |
#define CHECK_DEAD_GOTO(c, stream, rerror, label) \ | |
do { \ | |
if (!(c)->context || !PA_CONTEXT_IS_GOOD (pa_context_get_state((c)->context)) || \ | |
!(stream) || !PA_STREAM_IS_GOOD (pa_stream_get_state ((stream)))) { \ | |
if (((c)->context && pa_context_get_state ((c)->context) == PA_CONTEXT_FAILED) || \ | |
((stream) && pa_stream_get_state ((stream)) == PA_STREAM_FAILED)) { \ | |
- *(rerror) = pa_context_errno ((c)->context); \ | |
+ if (rerror) { \ | |
+ *(rerror) = pa_context_errno ((c)->context); \ | |
+ } \ | |
} else { \ | |
- *(rerror) = PA_ERR_BADSTATE; \ | |
+ if (rerror) { \ | |
+ *(rerror) = PA_ERR_BADSTATE; \ | |
+ } \ | |
} \ | |
goto label; \ | |
} \ | |
-} while (0); | |
+ } while (0); | |
static int qpa_run_out (HWVoiceOut *hw, int live) | |
{ | |
@@ -112,36 +116,30 @@ static int qpa_run_out (HWVoiceOut *hw, int live) | |
decr = 0; | |
rpos = hw->rpos; | |
- pa_threaded_mainloop_lock (pa->g->mainloop); | |
- CHECK_DEAD_GOTO (pa->g, pa->stream, &error, fail); | |
+ pa_threaded_mainloop_lock(pa->g->mainloop); | |
+ CHECK_DEAD_GOTO(pa->g, pa->stream, &error, fail); | |
avail_bytes = (size_t) live << hw->info.shift; | |
+ | |
max_bytes = pa_stream_writable_size(pa->stream); | |
CHECK_SUCCESS_GOTO(pa->g, &error, max_bytes != -1, fail); | |
- samples = (int)(audio_MIN (avail_bytes, max_bytes)) >> hw->info.shift; | |
- | |
-// if (avail_bytes < max_bytes) { | |
-// dolog("avail: %d, wanted: %d \n", (int)avail_bytes, (int)max_bytes); | |
-// } | |
- | |
-// dolog("TRANSFER avail: %d bytes, max %d bytes -> %d samples from %d\n", (int)avail_bytes, (int)max_bytes, samples, rpos); | |
- | |
+ samples = (int)(audio_MIN(avail_bytes, max_bytes)) >> hw->info.shift; | |
while (samples) { | |
int left_till_end_samples = hw->samples - rpos; | |
- int convert_samples = audio_MIN (samples, left_till_end_samples); | |
+ int convert_samples = audio_MIN(samples, left_till_end_samples); | |
size_t convert_bytes_wanted = (size_t) convert_samples << hw->info.shift; | |
size_t convert_bytes = convert_bytes_wanted; | |
r = pa_stream_begin_write(pa->stream, &pa_dst, &convert_bytes); | |
CHECK_SUCCESS_GOTO(pa->g, &error, r == 0, fail); | |
- CHECK_SUCCESS_GOTO(pa->g, &error, convert_bytes == convert_bytes_wanted, fail); | |
+ CHECK_SUCCESS_GOTO(pa->g, (int *)0, convert_bytes == convert_bytes_wanted, fail); | |
src = hw->mix_buf + rpos; | |
- hw->clip (pa_dst, src, convert_samples); | |
+ hw->clip(pa_dst, src, convert_samples); | |
- r = pa_stream_write (pa->stream, pa_dst, convert_bytes, NULL, 0LL, PA_SEEK_RELATIVE); | |
+ r = pa_stream_write(pa->stream, pa_dst, convert_bytes, NULL, 0LL, PA_SEEK_RELATIVE); | |
CHECK_SUCCESS_GOTO(pa->g, &error, r >= 0, fail); | |
rpos = (rpos + convert_samples) % hw->samples; | |
@@ -149,10 +147,10 @@ static int qpa_run_out (HWVoiceOut *hw, int live) | |
decr += convert_samples; | |
} | |
- bail: | |
- pa_threaded_mainloop_unlock (pa->g->mainloop); | |
+bail: | |
+ pa_threaded_mainloop_unlock(pa->g->mainloop); | |
- hw->rpos = rpos; | |
+hw->rpos = rpos; | |
return decr; | |
fail: | |
@@ -172,12 +170,12 @@ static int qpa_run_in (HWVoiceIn *hw) | |
char *pa_src; | |
int error = 0; | |
int r; | |
- | |
+ size_t pa_avail; | |
incr = 0; | |
wpos = hw->wpos; | |
- pa_threaded_mainloop_lock (pa->g->mainloop); | |
- CHECK_DEAD_GOTO (pa->g, pa->stream, &error, fail); | |
+ pa_threaded_mainloop_lock(pa->g->mainloop); | |
+ CHECK_DEAD_GOTO(pa->g, pa->stream, &error, fail); | |
size_t bytes_wanted = ((unsigned int)(hw->samples - audio_pcm_hw_get_live_in(hw)) << hw->info.shift); | |
if (bytes_wanted == 0) { | |
@@ -187,35 +185,14 @@ static int qpa_run_in (HWVoiceIn *hw) | |
size_t bytes_avail = pa_stream_readable_size(pa->stream); | |
- //dolog("WANT %d, HAVE %d\n", (int)bytes_wanted, (int) bytes_avail); | |
- | |
- size_t pa_avail; | |
- | |
- if (bytes_avail > bytes_wanted) { | |
-#if 0 | |
- size_t to_drop = bytes_avail - bytes_wanted; | |
- while (to_drop) { | |
- r = pa_stream_peek(pa->stream, (const void **)&pa_src, &pa_avail); | |
- CHECK_SUCCESS_GOTO(pa->g, &error, r == 0, fail); | |
- if (to_drop < pa_avail) { | |
- break; | |
- } | |
- r = pa_stream_drop(pa->stream); | |
- CHECK_SUCCESS_GOTO(pa->g, &error, r == 0, fail); | |
- to_drop -= pa_avail; | |
- } | |
- int n_dropped = (int)(bytes_avail - bytes_wanted - to_drop); | |
- if(n_dropped) { | |
- dolog("dropped %d bytes\n", n_dropped); | |
- } | |
-#endif | |
- } else if (bytes_wanted < bytes_avail) { | |
+ if (bytes_wanted > bytes_avail) { | |
bytes_wanted = bytes_avail; | |
} | |
while (bytes_wanted) { | |
r = pa_stream_peek(pa->stream, (const void **)&pa_src, &pa_avail); | |
CHECK_SUCCESS_GOTO(pa->g, &error, r == 0, fail); | |
+ | |
if (pa_avail == 0 || pa_avail > bytes_wanted) { | |
break; | |
} | |
@@ -223,8 +200,8 @@ static int qpa_run_in (HWVoiceIn *hw) | |
bytes_wanted -= pa_avail; | |
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); | |
+ 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; | |
pa_src += chunk << hw->info.shift; | |
pa_avail -= chunk << hw->info.shift; | |
@@ -235,16 +212,15 @@ static int qpa_run_in (HWVoiceIn *hw) | |
CHECK_SUCCESS_GOTO(pa->g, &error, r == 0, fail); | |
} | |
- bail: | |
- pa_threaded_mainloop_unlock (pa->g->mainloop); | |
+bail: | |
+ pa_threaded_mainloop_unlock(pa->g->mainloop); | |
hw->wpos = wpos; | |
return incr; | |
- fail: | |
+fail: | |
qpa_logerr (error, "qpa_run_in failed\n"); | |
goto bail; | |
- | |
} | |
static int qpa_read (SWVoiceIn *sw, void *buf, int len) | |
@@ -391,7 +367,6 @@ fail: | |
return NULL; | |
} | |
- | |
static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as, | |
void *drv_opaque) | |
{ | |
@@ -407,7 +382,7 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as, | |
if (tlength == 0) { | |
tlength = (frames_per_tick_x1000) / 400; | |
} | |
- int64_t buflen = g->conf.buffer_size; | |
+ int64_t buflen = g->conf.buffer_size_out; | |
if (buflen == 0) { | |
buflen = frames_per_tick_x1000 / 400; | |
} | |
@@ -440,15 +415,15 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as, | |
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 | |
- ); | |
+ 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; | |
@@ -459,13 +434,13 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as, | |
return 0; | |
- fail1: | |
+fail1: | |
return -1; | |
} | |
static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, | |
- void *drv_opaque) | |
+ void *drv_opaque) | |
{ | |
int error; | |
struct audsettings obt_as = *as; | |
@@ -479,7 +454,7 @@ static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, | |
if (fragsize == 0) { | |
fragsize = frames_per_tick_x1000 / 2500; | |
} | |
- int64_t buflen = g->conf.buffer_size; | |
+ int64_t buflen = g->conf.buffer_size_in; | |
if (buflen == 0) { | |
buflen = frames_per_tick_x1000 / 400; | |
} | |
@@ -501,7 +476,7 @@ static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, | |
pa->ss.rate = as->freq; | |
pa->ba.fragsize = fragsize * pa_frame_size (&pa->ss); | |
- pa->ba.maxlength = pa->ba.fragsize * 10; | |
+ pa->ba.maxlength = pa->ba.fragsize * 4; | |
pa->ba.minreq = -1; | |
pa->ba.prebuf = -1; | |
@@ -518,7 +493,7 @@ static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, | |
&error | |
); | |
if (!pa->stream) { | |
- qpa_logerr (error, "pa_simple_new for playback failed\n"); | |
+ qpa_logerr (error, "pa_simple_new for capture failed\n"); | |
goto fail1; | |
} | |
@@ -527,11 +502,10 @@ static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, | |
return 0; | |
- fail1: | |
+fail1: | |
return -1; | |
} | |
- | |
static void qpa_fini_out (HWVoiceOut *hw) | |
{ | |
PAVoiceOut *pa = (PAVoiceOut *) hw; | |
@@ -616,7 +590,7 @@ static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...) | |
#endif | |
switch (cmd) { | |
- case VOICE_VOLUME: | |
+ case VOICE_VOLUME: | |
{ | |
SWVoiceIn *sw; | |
va_list ap; | |
@@ -632,8 +606,8 @@ static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...) | |
pa_threaded_mainloop_lock (g->mainloop); | |
op = pa_context_set_source_output_volume (g->context, | |
- pa_stream_get_index (pa->stream), | |
- &v, NULL, NULL); | |
+ pa_stream_get_index (pa->stream), | |
+ &v, NULL, NULL); | |
if (!op) { | |
qpa_logerr (pa_context_errno (g->context), | |
"set_source_output_volume() failed\n"); | |
@@ -642,8 +616,8 @@ static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...) | |
} | |
op = pa_context_set_source_output_mute (g->context, | |
- pa_stream_get_index (pa->stream), | |
- sw->vol.mute, NULL, NULL); | |
+ pa_stream_get_index (pa->stream), | |
+ sw->vol.mute, NULL, NULL); | |
if (!op) { | |
qpa_logerr (pa_context_errno (g->context), | |
"set_source_output_mute() failed\n"); | |
@@ -665,7 +639,6 @@ static PAConf glob_conf = { | |
#endif | |
}; | |
- | |
static void *qpa_audio_init (void) | |
{ | |
paaudio *g = g_malloc(sizeof(paaudio)); | |
@@ -751,10 +724,16 @@ static void qpa_audio_fini (void *opaque) | |
struct audio_option qpa_options[] = { | |
{ | |
- .name = "INT_BUF_SIZE", | |
+ .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, | |
- .descr = "internal buffer size in frames" | |
+ .valp = &glob_conf.buffer_size_in, | |
+ .descr = "internal buffer size in frames for recording device" | |
}, | |
{ | |
.name = "TLENGTH", | |
@@ -772,13 +751,13 @@ struct audio_option qpa_options[] = { | |
.name = "ADJUST_LATENCY_OUT", | |
.tag = AUD_OPT_BOOL, | |
.valp = &glob_conf.adjust_latency_out, | |
- .descr = "let PA adjust latency for playback device" | |
+ .descr = "instruct PA to adjust latency for playback device" | |
}, | |
{ | |
.name = "ADJUST_LATENCY_IN", | |
.tag = AUD_OPT_BOOL, | |
.valp = &glob_conf.adjust_latency_in, | |
- .descr = "let PA adjust latency for recording device" | |
+ .descr = "instruct PA to adjust latency for recording device" | |
}, | |
{ | |
.name = "SERVER", | |
-- | |
2.14.1 | |
From 54da26898dfddfdfab1cd9dcb09ec8e877d33208 Mon Sep 17 00:00:00 2001 | |
From: Martin Schrodt <[email protected]> | |
Date: Sun, 15 Oct 2017 14:46:52 +0200 | |
Subject: [PATCH 17/30] expose maxlength parameter for recording device | |
--- | |
audio/paaudio.c | 33 +++++++++++++++++++++++++-------- | |
1 file changed, 25 insertions(+), 8 deletions(-) | |
diff --git a/audio/paaudio.c b/audio/paaudio.c | |
index 4f6fb4965c..06f04b02b7 100644 | |
--- a/audio/paaudio.c | |
+++ b/audio/paaudio.c | |
@@ -13,6 +13,7 @@ typedef struct { | |
int buffer_size_in; | |
int tlength; | |
int fragsize; | |
+ int maxlength_in; | |
int adjust_latency_out; | |
int adjust_latency_in; | |
char *server; | |
@@ -111,18 +112,19 @@ static int qpa_run_out (HWVoiceOut *hw, int live) | |
struct st_sample *src; | |
void *pa_dst; | |
int error = 0; | |
+ int *rerror = &error; | |
int r; | |
decr = 0; | |
rpos = hw->rpos; | |
pa_threaded_mainloop_lock(pa->g->mainloop); | |
- CHECK_DEAD_GOTO(pa->g, pa->stream, &error, fail); | |
+ CHECK_DEAD_GOTO(pa->g, pa->stream, rerror, fail); | |
avail_bytes = (size_t) live << hw->info.shift; | |
max_bytes = pa_stream_writable_size(pa->stream); | |
- CHECK_SUCCESS_GOTO(pa->g, &error, max_bytes != -1, fail); | |
+ CHECK_SUCCESS_GOTO(pa->g, rerror, max_bytes != -1, fail); | |
samples = (int)(audio_MIN(avail_bytes, max_bytes)) >> hw->info.shift; | |
while (samples) { | |
@@ -133,14 +135,14 @@ static int qpa_run_out (HWVoiceOut *hw, int live) | |
size_t convert_bytes = convert_bytes_wanted; | |
r = pa_stream_begin_write(pa->stream, &pa_dst, &convert_bytes); | |
- CHECK_SUCCESS_GOTO(pa->g, &error, r == 0, fail); | |
+ CHECK_SUCCESS_GOTO(pa->g, rerror, r == 0, fail); | |
CHECK_SUCCESS_GOTO(pa->g, (int *)0, convert_bytes == convert_bytes_wanted, fail); | |
src = hw->mix_buf + rpos; | |
hw->clip(pa_dst, src, convert_samples); | |
r = pa_stream_write(pa->stream, pa_dst, convert_bytes, NULL, 0LL, PA_SEEK_RELATIVE); | |
- CHECK_SUCCESS_GOTO(pa->g, &error, r >= 0, fail); | |
+ CHECK_SUCCESS_GOTO(pa->g, rerror, r >= 0, fail); | |
rpos = (rpos + convert_samples) % hw->samples; | |
samples -= convert_samples; | |
@@ -169,13 +171,14 @@ static int qpa_run_in (HWVoiceIn *hw) | |
int wpos, incr; | |
char *pa_src; | |
int error = 0; | |
+ int *rerror = &error; | |
int r; | |
size_t pa_avail; | |
incr = 0; | |
wpos = hw->wpos; | |
pa_threaded_mainloop_lock(pa->g->mainloop); | |
- CHECK_DEAD_GOTO(pa->g, pa->stream, &error, fail); | |
+ CHECK_DEAD_GOTO(pa->g, pa->stream, rerror, fail); | |
size_t bytes_wanted = ((unsigned int)(hw->samples - audio_pcm_hw_get_live_in(hw)) << hw->info.shift); | |
if (bytes_wanted == 0) { | |
@@ -191,7 +194,7 @@ static int qpa_run_in (HWVoiceIn *hw) | |
while (bytes_wanted) { | |
r = pa_stream_peek(pa->stream, (const void **)&pa_src, &pa_avail); | |
- CHECK_SUCCESS_GOTO(pa->g, &error, r == 0, fail); | |
+ CHECK_SUCCESS_GOTO(pa->g, rerror, r == 0, fail); | |
if (pa_avail == 0 || pa_avail > bytes_wanted) { | |
break; | |
@@ -209,7 +212,7 @@ static int qpa_run_in (HWVoiceIn *hw) | |
} | |
r = pa_stream_drop(pa->stream); | |
- CHECK_SUCCESS_GOTO(pa->g, &error, r == 0, fail); | |
+ CHECK_SUCCESS_GOTO(pa->g, rerror, r == 0, fail); | |
} | |
bail: | |
@@ -458,6 +461,10 @@ static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, | |
if (buflen == 0) { | |
buflen = frames_per_tick_x1000 / 400; | |
} | |
+ int64_t maxlength = g->conf.maxlength_in; | |
+ if (maxlength == 0) { | |
+ maxlength = fragsize * 4; | |
+ } | |
float ms_per_frame = 1000.0f / as->freq; | |
@@ -469,6 +476,10 @@ static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, | |
fragsize * ms_per_frame, | |
fragsize); | |
+ dolog("IN maxlength: %.2f ms (%"PRId64" frames)\n", | |
+ maxlength * ms_per_frame, | |
+ maxlength); | |
+ | |
dolog("IN adjust latency: %s\n", g->conf.adjust_latency_in ? "yes" : "no"); | |
pa->ss.format = audfmt_to_pa (as->fmt, as->endianness); | |
@@ -476,7 +487,7 @@ static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, | |
pa->ss.rate = as->freq; | |
pa->ba.fragsize = fragsize * pa_frame_size (&pa->ss); | |
- pa->ba.maxlength = pa->ba.fragsize * 4; | |
+ pa->ba.maxlength = maxlength * pa_frame_size (&pa->ss); | |
pa->ba.minreq = -1; | |
pa->ba.prebuf = -1; | |
@@ -747,6 +758,12 @@ struct audio_option qpa_options[] = { | |
.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, | |
-- | |
2.14.1 | |
From 3497c07ef85b94f5248bcd271391b67eb5570f8b Mon Sep 17 00:00:00 2001 | |
From: Martin Schrodt <[email protected]> | |
Date: Sun, 15 Oct 2017 14:51:08 +0200 | |
Subject: [PATCH 18/30] do not change unrelated code | |
--- | |
audio/paaudio.c | 2 +- | |
1 file changed, 1 insertion(+), 1 deletion(-) | |
diff --git a/audio/paaudio.c b/audio/paaudio.c | |
index 06f04b02b7..9e454cb9ce 100644 | |
--- a/audio/paaudio.c | |
+++ b/audio/paaudio.c | |
@@ -233,7 +233,7 @@ static int qpa_read (SWVoiceIn *sw, void *buf, int len) | |
static pa_sample_format_t audfmt_to_pa (audfmt_e afmt, int endianness) | |
{ | |
- pa_sample_format_t format; | |
+ int format; | |
switch (afmt) { | |
case AUD_FMT_S8: | |
-- | |
2.14.1 | |
From 73bf70f6c67c7d6b1ff87dbe1c86091721006d32 Mon Sep 17 00:00:00 2001 | |
From: Martin Schrodt <[email protected]> | |
Date: Sun, 15 Oct 2017 15:35:38 +0200 | |
Subject: [PATCH 19/30] ignore old fields in live migration | |
--- | |
hw/audio/hda-codec.c | 9 +++++---- | |
1 file changed, 5 insertions(+), 4 deletions(-) | |
diff --git a/hw/audio/hda-codec.c b/hw/audio/hda-codec.c | |
index af686eb1f3..7976c4dc93 100644 | |
--- a/hw/audio/hda-codec.c | |
+++ b/hw/audio/hda-codec.c | |
@@ -159,6 +159,8 @@ struct HDAAudioStream { | |
SWVoiceIn *in; | |
SWVoiceOut *out; | |
} voice; | |
+ uint8_t compat_buf[HDA_BUFFER_SIZE]; | |
+ uint32_t compat_bpos; | |
uint8_t buf[8192]; // size must be power of two | |
int64_t rpos; | |
int64_t wpos; | |
@@ -690,7 +692,7 @@ static void hda_audio_reset(DeviceState *dev) | |
static const VMStateDescription vmstate_hda_audio_stream = { | |
.name = "hda-audio-stream", | |
- .version_id = 1, | |
+ .version_id = 2, | |
.fields = (VMStateField[]) { | |
VMSTATE_UINT32(stream, HDAAudioStream), | |
VMSTATE_UINT32(channel, HDAAudioStream), | |
@@ -699,9 +701,8 @@ static const VMStateDescription vmstate_hda_audio_stream = { | |
VMSTATE_UINT32(gain_right, HDAAudioStream), | |
VMSTATE_BOOL(mute_left, HDAAudioStream), | |
VMSTATE_BOOL(mute_right, HDAAudioStream), | |
- VMSTATE_BUFFER(buf, HDAAudioStream), | |
- VMSTATE_INT64(rpos, HDAAudioStream), | |
- VMSTATE_INT64(wpos, HDAAudioStream), | |
+ VMSTATE_UINT32(compat_bpos, HDAAudioStream), | |
+ VMSTATE_BUFFER(compat_buf, HDAAudioStream), | |
VMSTATE_END_OF_LIST() | |
} | |
}; | |
-- | |
2.14.1 | |
From 4053b7b1ee100c556dbe7e276890b80bb41b5061 Mon Sep 17 00:00:00 2001 | |
From: Martin Schrodt <[email protected]> | |
Date: Sun, 15 Oct 2017 16:02:09 +0200 | |
Subject: [PATCH 20/30] move HDA_TIMER_TICKS to codec | |
--- | |
hw/audio/hda-codec.c | 1 + | |
hw/audio/intel-hda-defs.h | 1 - | |
2 files changed, 1 insertion(+), 1 deletion(-) | |
diff --git a/hw/audio/hda-codec.c b/hw/audio/hda-codec.c | |
index 7976c4dc93..d8faa6fd6a 100644 | |
--- a/hw/audio/hda-codec.c | |
+++ b/hw/audio/hda-codec.c | |
@@ -127,6 +127,7 @@ static void hda_codec_parse_fmt(uint32_t format, struct audsettings *as) | |
#define PARAM nomixemu | |
#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) | |
diff --git a/hw/audio/intel-hda-defs.h b/hw/audio/intel-hda-defs.h | |
index 900a2695ec..2e37e5b874 100644 | |
--- a/hw/audio/intel-hda-defs.h | |
+++ b/hw/audio/intel-hda-defs.h | |
@@ -3,7 +3,6 @@ | |
/* qemu */ | |
#define HDA_BUFFER_SIZE 256 | |
-#define HDA_TIMER_TICKS (SCALE_MS) | |
/* --------------------------------------------------------------------- */ | |
/* from linux/sound/pci/hda/hda_intel.c */ | |
-- | |
2.14.1 | |
From 48ea11bce21d574117ca5bdbf0cd70c9dea47df4 Mon Sep 17 00:00:00 2001 | |
From: Martin Schrodt <[email protected]> | |
Date: Sun, 15 Oct 2017 16:06:04 +0200 | |
Subject: [PATCH 21/30] do not up version | |
--- | |
hw/audio/hda-codec.c | 2 +- | |
1 file changed, 1 insertion(+), 1 deletion(-) | |
diff --git a/hw/audio/hda-codec.c b/hw/audio/hda-codec.c | |
index d8faa6fd6a..1c0474543d 100644 | |
--- a/hw/audio/hda-codec.c | |
+++ b/hw/audio/hda-codec.c | |
@@ -693,7 +693,7 @@ static void hda_audio_reset(DeviceState *dev) | |
static const VMStateDescription vmstate_hda_audio_stream = { | |
.name = "hda-audio-stream", | |
- .version_id = 2, | |
+ .version_id = 1, | |
.fields = (VMStateField[]) { | |
VMSTATE_UINT32(stream, HDAAudioStream), | |
VMSTATE_UINT32(channel, HDAAudioStream), | |
-- | |
2.14.1 | |
From ba8c2fb55cb7c010d38604c80b3d0102fd9aef84 Mon Sep 17 00:00:00 2001 | |
From: Martin Schrodt <[email protected]> | |
Date: Sun, 15 Oct 2017 16:38:17 +0200 | |
Subject: [PATCH 22/30] debug output only when it's enabled | |
--- | |
audio/paaudio.c | 32 ++++++++++++++------------------ | |
1 file changed, 14 insertions(+), 18 deletions(-) | |
diff --git a/audio/paaudio.c b/audio/paaudio.c | |
index 9e454cb9ce..3d24712483 100644 | |
--- a/audio/paaudio.c | |
+++ b/audio/paaudio.c | |
@@ -390,21 +390,19 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as, | |
buflen = frames_per_tick_x1000 / 400; | |
} | |
- float ms_per_frame = 1000.0f / as->freq; | |
- | |
- dolog("tick duration: %.2f ms (%.3f frames)\n", | |
- ((float) timer_tick_duration) / SCALE_MS, | |
+ ldebug("tick duration: %.2f ms (%.3f frames)\n", | |
+ ((float)timer_tick_duration) / SCALE_MS, | |
(float)frames_per_tick_x1000 / 1000.0f); | |
- dolog("OUT internal buffer: %.2f ms (%"PRId64" frames)\n", | |
- buflen * ms_per_frame, | |
+ ldebug("OUT internal buffer: %.2f ms (%"PRId64" frames)\n", | |
+ buflen * (1000.0f / as->freq), | |
buflen); | |
- dolog("OUT tlength: %.2f ms (%"PRId64" frames)\n", | |
- tlength * ms_per_frame, | |
+ ldebug("OUT tlength: %.2f ms (%"PRId64" frames)\n", | |
+ tlength * (1000.0f / as->freq), | |
tlength); | |
- dolog("OUT adjust latency: %s\n", g->conf.adjust_latency_out ? "yes" : "no"); | |
+ 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; | |
@@ -466,21 +464,19 @@ static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, | |
maxlength = fragsize * 4; | |
} | |
- float ms_per_frame = 1000.0f / as->freq; | |
- | |
- dolog("IN internal buffer: %.2f ms (%"PRId64" frames)\n", | |
- buflen * ms_per_frame, | |
+ ldebug("IN internal buffer: %.2f ms (%"PRId64" frames)\n", | |
+ buflen * (1000.0f / as->freq), | |
buflen); | |
- dolog("IN fragsize: %.2f ms (%"PRId64" frames)\n", | |
- fragsize * ms_per_frame, | |
+ ldebug("IN fragsize: %.2f ms (%"PRId64" frames)\n", | |
+ fragsize * (1000.0f / as->freq), | |
fragsize); | |
- dolog("IN maxlength: %.2f ms (%"PRId64" frames)\n", | |
- maxlength * ms_per_frame, | |
+ ldebug("IN maxlength: %.2f ms (%"PRId64" frames)\n", | |
+ maxlength * (1000.0f / as->freq), | |
maxlength); | |
- dolog("IN adjust latency: %s\n", g->conf.adjust_latency_in ? "yes" : "no"); | |
+ 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; | |
-- | |
2.14.1 | |
From 5639f1869a027ffb30fb94afdd7c215cbc06fa0c Mon Sep 17 00:00:00 2001 | |
From: Martin Schrodt <[email protected]> | |
Date: Sun, 15 Oct 2017 17:46:03 +0200 | |
Subject: [PATCH 23/30] checkpatch cleanup 1 | |
Signed-off-by: Martin Schrodt <[email protected]> | |
--- | |
audio/audio.c | 3 +- | |
audio/paaudio.c | 366 ++++++++++++++++++++++++++++---------------------------- | |
2 files changed, 185 insertions(+), 184 deletions(-) | |
diff --git a/audio/audio.c b/audio/audio.c | |
index fba1604c34..6f42a019b0 100644 | |
--- a/audio/audio.c | |
+++ b/audio/audio.c | |
@@ -2067,6 +2067,7 @@ void AUD_set_volume_in (SWVoiceIn *sw, int mute, uint8_t lvol, uint8_t rvol) | |
} | |
} | |
-int64_t audio_get_timer_ticks(void) { | |
+int64_t audio_get_timer_ticks(void) | |
+{ | |
return conf.period.ticks; | |
} | |
diff --git a/audio/paaudio.c b/audio/paaudio.c | |
index 3d24712483..b180d213cb 100644 | |
--- a/audio/paaudio.c | |
+++ b/audio/paaudio.c | |
@@ -104,7 +104,7 @@ static inline int PA_STREAM_IS_GOOD(pa_stream_state_t x) | |
} \ | |
} while (0); | |
-static int qpa_run_out (HWVoiceOut *hw, int live) | |
+static int qpa_run_out(HWVoiceOut *hw, int live) | |
{ | |
PAVoiceOut *pa = (PAVoiceOut *) hw; | |
int rpos, decr, samples; | |
@@ -149,14 +149,14 @@ static int qpa_run_out (HWVoiceOut *hw, int live) | |
decr += convert_samples; | |
} | |
-bail: | |
+ bail: | |
pa_threaded_mainloop_unlock(pa->g->mainloop); | |
-hw->rpos = rpos; | |
+ hw->rpos = rpos; | |
return decr; | |
fail: | |
- qpa_logerr (error, "qpa_run_out failed\n"); | |
+ qpa_logerr(error, "qpa_run_out failed\n"); | |
goto bail; | |
} | |
@@ -165,7 +165,7 @@ static int qpa_write (SWVoiceOut *sw, void *buf, int len) | |
return audio_pcm_sw_write (sw, buf, len); | |
} | |
-static int qpa_run_in (HWVoiceIn *hw) | |
+static int qpa_run_in(HWVoiceIn *hw) | |
{ | |
PAVoiceIn *pa = (PAVoiceIn *) hw; | |
int wpos, incr; | |
@@ -182,7 +182,7 @@ static int qpa_run_in (HWVoiceIn *hw) | |
size_t bytes_wanted = ((unsigned int)(hw->samples - audio_pcm_hw_get_live_in(hw)) << hw->info.shift); | |
if (bytes_wanted == 0) { | |
- // no room | |
+ /* no room */ | |
goto bail; | |
} | |
@@ -215,14 +215,14 @@ static int qpa_run_in (HWVoiceIn *hw) | |
CHECK_SUCCESS_GOTO(pa->g, rerror, r == 0, fail); | |
} | |
-bail: | |
+ bail: | |
pa_threaded_mainloop_unlock(pa->g->mainloop); | |
hw->wpos = wpos; | |
return incr; | |
-fail: | |
- qpa_logerr (error, "qpa_run_in failed\n"); | |
+ fail: | |
+ qpa_logerr(error, "qpa_run_in failed\n"); | |
goto bail; | |
} | |
@@ -236,22 +236,22 @@ static pa_sample_format_t audfmt_to_pa (audfmt_e afmt, int endianness) | |
int format; | |
switch (afmt) { | |
- case AUD_FMT_S8: | |
- case AUD_FMT_U8: | |
- format = PA_SAMPLE_U8; | |
- break; | |
- case AUD_FMT_S16: | |
- case AUD_FMT_U16: | |
- format = endianness ? PA_SAMPLE_S16BE : PA_SAMPLE_S16LE; | |
- break; | |
- case AUD_FMT_S32: | |
- case AUD_FMT_U32: | |
- format = endianness ? PA_SAMPLE_S32BE : PA_SAMPLE_S32LE; | |
- break; | |
- default: | |
- dolog ("Internal logic error: Bad audio format %d\n", afmt); | |
- format = PA_SAMPLE_U8; | |
- break; | |
+ case AUD_FMT_S8: | |
+ case AUD_FMT_U8: | |
+ format = PA_SAMPLE_U8; | |
+ break; | |
+ case AUD_FMT_S16: | |
+ case AUD_FMT_U16: | |
+ format = endianness ? PA_SAMPLE_S16BE : PA_SAMPLE_S16LE; | |
+ break; | |
+ case AUD_FMT_S32: | |
+ case AUD_FMT_U32: | |
+ format = endianness ? PA_SAMPLE_S32BE : PA_SAMPLE_S32LE; | |
+ break; | |
+ default: | |
+ dolog ("Internal logic error: Bad audio format %d\n", afmt); | |
+ format = PA_SAMPLE_U8; | |
+ break; | |
} | |
return format; | |
} | |
@@ -259,23 +259,23 @@ static pa_sample_format_t audfmt_to_pa (audfmt_e afmt, int endianness) | |
static audfmt_e pa_to_audfmt (pa_sample_format_t fmt, int *endianness) | |
{ | |
switch (fmt) { | |
- case PA_SAMPLE_U8: | |
- return AUD_FMT_U8; | |
- case PA_SAMPLE_S16BE: | |
- *endianness = 1; | |
- return AUD_FMT_S16; | |
- case PA_SAMPLE_S16LE: | |
- *endianness = 0; | |
- return AUD_FMT_S16; | |
- case PA_SAMPLE_S32BE: | |
- *endianness = 1; | |
- return AUD_FMT_S32; | |
- case PA_SAMPLE_S32LE: | |
- *endianness = 0; | |
- return AUD_FMT_S32; | |
- default: | |
- dolog ("Internal logic error: Bad pa_sample_format %d\n", fmt); | |
- return AUD_FMT_U8; | |
+ case PA_SAMPLE_U8: | |
+ return AUD_FMT_U8; | |
+ case PA_SAMPLE_S16BE: | |
+ *endianness = 1; | |
+ return AUD_FMT_S16; | |
+ case PA_SAMPLE_S16LE: | |
+ *endianness = 0; | |
+ return AUD_FMT_S16; | |
+ case PA_SAMPLE_S32BE: | |
+ *endianness = 1; | |
+ return AUD_FMT_S32; | |
+ case PA_SAMPLE_S32LE: | |
+ *endianness = 0; | |
+ return AUD_FMT_S32; | |
+ default: | |
+ dolog ("Internal logic error: Bad pa_sample_format %d\n", fmt); | |
+ return AUD_FMT_U8; | |
} | |
} | |
@@ -284,17 +284,17 @@ static void context_state_cb (pa_context *c, void *userdata) | |
paaudio *g = userdata; | |
switch (pa_context_get_state(c)) { | |
- case PA_CONTEXT_READY: | |
- case PA_CONTEXT_TERMINATED: | |
- case PA_CONTEXT_FAILED: | |
- pa_threaded_mainloop_signal (g->mainloop, 0); | |
- break; | |
- | |
- case PA_CONTEXT_UNCONNECTED: | |
- case PA_CONTEXT_CONNECTING: | |
- case PA_CONTEXT_AUTHORIZING: | |
- case PA_CONTEXT_SETTING_NAME: | |
- break; | |
+ case PA_CONTEXT_READY: | |
+ case PA_CONTEXT_TERMINATED: | |
+ case PA_CONTEXT_FAILED: | |
+ pa_threaded_mainloop_signal (g->mainloop, 0); | |
+ break; | |
+ | |
+ case PA_CONTEXT_UNCONNECTED: | |
+ case PA_CONTEXT_CONNECTING: | |
+ case PA_CONTEXT_AUTHORIZING: | |
+ case PA_CONTEXT_SETTING_NAME: | |
+ break; | |
} | |
} | |
@@ -304,15 +304,15 @@ static void stream_state_cb (pa_stream *s, void * userdata) | |
switch (pa_stream_get_state (s)) { | |
- case PA_STREAM_READY: | |
- case PA_STREAM_FAILED: | |
- case PA_STREAM_TERMINATED: | |
- pa_threaded_mainloop_signal (g->mainloop, 0); | |
- break; | |
+ case PA_STREAM_READY: | |
+ case PA_STREAM_FAILED: | |
+ case PA_STREAM_TERMINATED: | |
+ pa_threaded_mainloop_signal (g->mainloop, 0); | |
+ break; | |
- case PA_STREAM_UNCONNECTED: | |
- case PA_STREAM_CREATING: | |
- break; | |
+ case PA_STREAM_UNCONNECTED: | |
+ case PA_STREAM_CREATING: | |
+ break; | |
} | |
} | |
@@ -351,14 +351,14 @@ static pa_stream *qpa_simple_new ( | |
} | |
if (r < 0) { | |
- goto fail; | |
+ goto fail; | |
} | |
pa_threaded_mainloop_unlock (g->mainloop); | |
return stream; | |
-fail: | |
+ fail: | |
pa_threaded_mainloop_unlock (g->mainloop); | |
if (stream) { | |
@@ -391,20 +391,20 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as, | |
} | |
ldebug("tick duration: %.2f ms (%.3f frames)\n", | |
- ((float)timer_tick_duration) / SCALE_MS, | |
- (float)frames_per_tick_x1000 / 1000.0f); | |
+ ((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); | |
+ buflen * (1000.0f / as->freq), | |
+ buflen); | |
ldebug("OUT tlength: %.2f ms (%"PRId64" frames)\n", | |
- tlength * (1000.0f / as->freq), | |
- tlength); | |
+ 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.format = audfmt_to_pa(as->fmt, as->endianness); | |
pa->ss.channels = as->nchannels; | |
pa->ss.rate = as->freq; | |
@@ -413,9 +413,9 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as, | |
pa->ba.minreq = -1; | |
pa->ba.prebuf = -1; | |
- obt_as.fmt = pa_to_audfmt (pa->ss.format, &obt_as.endianness); | |
+ obt_as.fmt = pa_to_audfmt(pa->ss.format, &obt_as.endianness); | |
- pa->stream = qpa_simple_new ( | |
+ pa->stream = qpa_simple_new( | |
g, | |
"qemu", | |
PA_STREAM_PLAYBACK, | |
@@ -430,12 +430,12 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as, | |
goto fail1; | |
} | |
- audio_pcm_init_info (&hw->info, &obt_as); | |
+ audio_pcm_init_info(&hw->info, &obt_as); | |
hw->samples = buflen; | |
return 0; | |
-fail1: | |
+ fail1: | |
return -1; | |
} | |
@@ -465,31 +465,31 @@ static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, | |
} | |
ldebug("IN internal buffer: %.2f ms (%"PRId64" frames)\n", | |
- buflen * (1000.0f / as->freq), | |
- buflen); | |
+ buflen * (1000.0f / as->freq), | |
+ buflen); | |
ldebug("IN fragsize: %.2f ms (%"PRId64" frames)\n", | |
- fragsize * (1000.0f / as->freq), | |
- fragsize); | |
+ fragsize * (1000.0f / as->freq), | |
+ fragsize); | |
ldebug("IN maxlength: %.2f ms (%"PRId64" frames)\n", | |
- maxlength * (1000.0f / as->freq), | |
- maxlength); | |
+ 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.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.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); | |
+ obt_as.fmt = pa_to_audfmt(pa->ss.format, &obt_as.endianness); | |
- pa->stream = qpa_simple_new ( | |
+ pa->stream = qpa_simple_new( | |
g, | |
"qemu", | |
PA_STREAM_RECORD, | |
@@ -504,12 +504,12 @@ static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, | |
goto fail1; | |
} | |
- audio_pcm_init_info (&hw->info, &obt_as); | |
+ audio_pcm_init_info(&hw->info, &obt_as); | |
hw->samples = buflen; | |
return 0; | |
-fail1: | |
+ fail1: | |
return -1; | |
} | |
@@ -545,7 +545,7 @@ static int qpa_ctl_out (HWVoiceOut *hw, int cmd, ...) | |
#endif | |
switch (cmd) { | |
- case VOICE_VOLUME: | |
+ case VOICE_VOLUME: | |
{ | |
SWVoiceOut *sw; | |
va_list ap; | |
@@ -561,8 +561,8 @@ static int qpa_ctl_out (HWVoiceOut *hw, int cmd, ...) | |
pa_threaded_mainloop_lock (g->mainloop); | |
op = pa_context_set_sink_input_volume (g->context, | |
- pa_stream_get_index (pa->stream), | |
- &v, NULL, NULL); | |
+ pa_stream_get_index (pa->stream), | |
+ &v, NULL, NULL); | |
if (!op) | |
qpa_logerr (pa_context_errno (g->context), | |
"set_sink_input_volume() failed\n"); | |
@@ -570,8 +570,8 @@ static int qpa_ctl_out (HWVoiceOut *hw, int cmd, ...) | |
pa_operation_unref (op); | |
op = pa_context_set_sink_input_mute (g->context, | |
- pa_stream_get_index (pa->stream), | |
- sw->vol.mute, NULL, NULL); | |
+ pa_stream_get_index (pa->stream), | |
+ sw->vol.mute, NULL, NULL); | |
if (!op) { | |
qpa_logerr (pa_context_errno (g->context), | |
"set_sink_input_mute() failed\n"); | |
@@ -597,7 +597,7 @@ static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...) | |
#endif | |
switch (cmd) { | |
- case VOICE_VOLUME: | |
+ case VOICE_VOLUME: | |
{ | |
SWVoiceIn *sw; | |
va_list ap; | |
@@ -613,8 +613,8 @@ static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...) | |
pa_threaded_mainloop_lock (g->mainloop); | |
op = pa_context_set_source_output_volume (g->context, | |
- pa_stream_get_index (pa->stream), | |
- &v, NULL, NULL); | |
+ pa_stream_get_index (pa->stream), | |
+ &v, NULL, NULL); | |
if (!op) { | |
qpa_logerr (pa_context_errno (g->context), | |
"set_source_output_volume() failed\n"); | |
@@ -623,8 +623,8 @@ static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...) | |
} | |
op = pa_context_set_source_output_mute (g->context, | |
- pa_stream_get_index (pa->stream), | |
- sw->vol.mute, NULL, NULL); | |
+ pa_stream_get_index (pa->stream), | |
+ sw->vol.mute, NULL, NULL); | |
if (!op) { | |
qpa_logerr (pa_context_errno (g->context), | |
"set_source_output_mute() failed\n"); | |
@@ -701,9 +701,9 @@ static void *qpa_audio_init (void) | |
return g; | |
-unlock_and_fail: | |
+ unlock_and_fail: | |
pa_threaded_mainloop_unlock (g->mainloop); | |
-fail: | |
+ fail: | |
AUD_log (AUDIO_CAP, "Failed to initialize PA context"); | |
qpa_audio_fini(g); | |
return NULL; | |
@@ -730,94 +730,94 @@ static void qpa_audio_fini (void *opaque) | |
} | |
struct audio_option qpa_options[] = { | |
- { | |
- .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.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", | |
- .tag = AUD_OPT_STR, | |
- .valp = &glob_conf.server, | |
- .descr = "server address" | |
- }, | |
- { | |
- .name = "SINK", | |
- .tag = AUD_OPT_STR, | |
- .valp = &glob_conf.sink, | |
- .descr = "sink device name" | |
- }, | |
- { | |
- .name = "SOURCE", | |
- .tag = AUD_OPT_STR, | |
- .valp = &glob_conf.source, | |
- .descr = "source device name" | |
- }, | |
- { /* End of list */ } | |
+ { | |
+ .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.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", | |
+ .tag = AUD_OPT_STR, | |
+ .valp = &glob_conf.server, | |
+ .descr = "server address" | |
+ }, | |
+ { | |
+ .name = "SINK", | |
+ .tag = AUD_OPT_STR, | |
+ .valp = &glob_conf.sink, | |
+ .descr = "sink device name" | |
+ }, | |
+ { | |
+ .name = "SOURCE", | |
+ .tag = AUD_OPT_STR, | |
+ .valp = &glob_conf.source, | |
+ .descr = "source device name" | |
+ }, | |
+ { /* End of list */ } | |
}; | |
static struct audio_pcm_ops qpa_pcm_ops = { | |
- .init_out = qpa_init_out, | |
- .fini_out = qpa_fini_out, | |
- .run_out = qpa_run_out, | |
- .write = qpa_write, | |
- .ctl_out = qpa_ctl_out, | |
- | |
- .init_in = qpa_init_in, | |
- .fini_in = qpa_fini_in, | |
- .run_in = qpa_run_in, | |
- .read = qpa_read, | |
- .ctl_in = qpa_ctl_in | |
+ .init_out = qpa_init_out, | |
+ .fini_out = qpa_fini_out, | |
+ .run_out = qpa_run_out, | |
+ .write = qpa_write, | |
+ .ctl_out = qpa_ctl_out, | |
+ | |
+ .init_in = qpa_init_in, | |
+ .fini_in = qpa_fini_in, | |
+ .run_in = qpa_run_in, | |
+ .read = qpa_read, | |
+ .ctl_in = qpa_ctl_in | |
}; | |
struct audio_driver pa_audio_driver = { | |
- .name = "pa", | |
- .descr = "http://www.pulseaudio.org/", | |
- .options = qpa_options, | |
- .init = qpa_audio_init, | |
- .fini = qpa_audio_fini, | |
- .pcm_ops = &qpa_pcm_ops, | |
- .can_be_default = 1, | |
- .max_voices_out = INT_MAX, | |
- .max_voices_in = INT_MAX, | |
- .voice_size_out = sizeof (PAVoiceOut), | |
- .voice_size_in = sizeof (PAVoiceIn), | |
- .ctl_caps = VOICE_VOLUME_CAP | |
+ .name = "pa", | |
+ .descr = "http://www.pulseaudio.org/", | |
+ .options = qpa_options, | |
+ .init = qpa_audio_init, | |
+ .fini = qpa_audio_fini, | |
+ .pcm_ops = &qpa_pcm_ops, | |
+ .can_be_default = 1, | |
+ .max_voices_out = INT_MAX, | |
+ .max_voices_in = INT_MAX, | |
+ .voice_size_out = sizeof (PAVoiceOut), | |
+ .voice_size_in = sizeof (PAVoiceIn), | |
+ .ctl_caps = VOICE_VOLUME_CAP | |
}; | |
-- | |
2.14.1 | |
From 8a8883bfe94c04a1e693ca0fa506147681c42bc6 Mon Sep 17 00:00:00 2001 | |
From: Martin Schrodt <[email protected]> | |
Date: Sun, 15 Oct 2017 18:00:22 +0200 | |
Subject: [PATCH 24/30] checkpatch cleanup 2 | |
Signed-off-by: Martin Schrodt <[email protected]> | |
--- | |
audio/paaudio.c | 56 ++++++++++++++++++++++++++++++++------------------------ | |
1 file changed, 32 insertions(+), 24 deletions(-) | |
diff --git a/audio/paaudio.c b/audio/paaudio.c | |
index b180d213cb..fbc30fd08e 100644 | |
--- a/audio/paaudio.c | |
+++ b/audio/paaudio.c | |
@@ -128,20 +128,19 @@ static int qpa_run_out(HWVoiceOut *hw, int live) | |
samples = (int)(audio_MIN(avail_bytes, max_bytes)) >> hw->info.shift; | |
while (samples) { | |
- int left_till_end_samples = hw->samples - rpos; | |
+ 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; | |
- int convert_samples = audio_MIN(samples, left_till_end_samples); | |
- size_t convert_bytes_wanted = (size_t) convert_samples << hw->info.shift; | |
- size_t convert_bytes = convert_bytes_wanted; | |
- | |
- r = pa_stream_begin_write(pa->stream, &pa_dst, &convert_bytes); | |
+ 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, convert_bytes == convert_bytes_wanted, fail); | |
+ CHECK_SUCCESS_GOTO(pa->g, (int *)0, b_effective == b_wanted, fail); | |
src = hw->mix_buf + rpos; | |
hw->clip(pa_dst, src, convert_samples); | |
- r = pa_stream_write(pa->stream, pa_dst, convert_bytes, NULL, 0LL, PA_SEEK_RELATIVE); | |
+ 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 + convert_samples) % hw->samples; | |
@@ -180,7 +179,9 @@ static int qpa_run_in(HWVoiceIn *hw) | |
pa_threaded_mainloop_lock(pa->g->mainloop); | |
CHECK_DEAD_GOTO(pa->g, pa->stream, rerror, fail); | |
- size_t bytes_wanted = ((unsigned int)(hw->samples - audio_pcm_hw_get_live_in(hw)) << hw->info.shift); | |
+ size_t bytes_wanted = ((unsigned int) | |
+ (hw->samples - audio_pcm_hw_get_live_in(hw)) << hw->info.shift); | |
+ | |
if (bytes_wanted == 0) { | |
/* no room */ | |
goto bail; | |
@@ -203,7 +204,8 @@ static int qpa_run_in(HWVoiceIn *hw) | |
bytes_wanted -= pa_avail; | |
while (pa_avail) { | |
- int chunk = audio_MIN((int)(pa_avail >> hw->info.shift), hw->samples - wpos); | |
+ 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; | |
pa_src += chunk << hw->info.shift; | |
@@ -339,15 +341,15 @@ static pa_stream *qpa_simple_new ( | |
pa_stream_set_state_callback (stream, stream_state_cb, g); | |
if (dir == PA_STREAM_PLAYBACK) { | |
- 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); | |
+ 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 | |
- | (g->conf.adjust_latency_in ? PA_STREAM_ADJUST_LATENCY : 0) | |
- |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) { | |
@@ -378,8 +380,10 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as, | |
PAVoiceOut *pa = (PAVoiceOut *) hw; | |
paaudio *g = pa->g = drv_opaque; | |
- 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 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) { | |
@@ -402,7 +406,8 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as, | |
tlength * (1000.0f / as->freq), | |
tlength); | |
- ldebug("OUT adjust latency: %s\n", g->conf.adjust_latency_out ? "yes" : "no"); | |
+ 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; | |
@@ -448,8 +453,10 @@ static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, | |
PAVoiceIn *pa = (PAVoiceIn *) hw; | |
paaudio *g = pa->g = drv_opaque; | |
- 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 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) { | |
@@ -476,7 +483,8 @@ static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, | |
maxlength * (1000.0f / as->freq), | |
maxlength); | |
- ldebug("IN adjust latency: %s\n", g->conf.adjust_latency_in ? "yes" : "no"); | |
+ 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; | |
-- | |
2.14.1 | |
From db0c4353a9c98b357aca93deaac0e07b61475608 Mon Sep 17 00:00:00 2001 | |
From: Martin Schrodt <[email protected]> | |
Date: Sun, 15 Oct 2017 18:03:39 +0200 | |
Subject: [PATCH 25/30] checkpatch cleanup 3 | |
Signed-off-by: Martin Schrodt <[email protected]> | |
--- | |
hw/audio/hda-codec.c | 23 ++++++++++++++--------- | |
1 file changed, 14 insertions(+), 9 deletions(-) | |
diff --git a/hw/audio/hda-codec.c b/hw/audio/hda-codec.c | |
index 1c0474543d..38c8eb1561 100644 | |
--- a/hw/audio/hda-codec.c | |
+++ b/hw/audio/hda-codec.c | |
@@ -194,7 +194,8 @@ static inline int64_t hda_bytes_per_second(HDAAudioStream *st) | |
static inline void hda_timer_sync_adjust(HDAAudioStream *st, int64_t target_pos) | |
{ | |
- int64_t corr = NANOSECONDS_PER_SECOND * target_pos / hda_bytes_per_second(st); | |
+ int64_t corr = | |
+ NANOSECONDS_PER_SECOND * target_pos / hda_bytes_per_second(st); | |
if (corr > MAX_CORR) { | |
corr = MAX_CORR; | |
} else if (corr < -MAX_CORR) { | |
@@ -213,11 +214,12 @@ static void hda_audio_input_timer(void *opaque) | |
int64_t wpos = atomic_fetch_add(&st->wpos, 0); | |
int64_t rpos = atomic_fetch_add(&st->rpos, 0); | |
- int64_t wanted_rpos = hda_bytes_per_second(st) * (now - buft_start) / NANOSECONDS_PER_SECOND; | |
- wanted_rpos &= -4; // IMPORTANT! clip to frames | |
+ int64_t wanted_rpos = hda_bytes_per_second(st) * (now - buft_start) | |
+ / NANOSECONDS_PER_SECOND; | |
+ wanted_rpos &= -4; /* IMPORTANT! clip to frames */ | |
if (wanted_rpos <= rpos) { | |
- // we already transmitted the data | |
+ /* we already transmitted the data */ | |
goto out_timer; | |
} | |
@@ -225,7 +227,8 @@ static void hda_audio_input_timer(void *opaque) | |
while (to_transfer) { | |
uint32_t start = (rpos & B_MASK); | |
uint32_t chunk = audio_MIN(B_SIZE - start, to_transfer); | |
- int rc = hda_codec_xfer(&st->state->hda, st->stream, false, st->buf + start, chunk); | |
+ int rc = hda_codec_xfer( | |
+ &st->state->hda, st->stream, false, st->buf + start, chunk); | |
if (!rc) { | |
break; | |
} | |
@@ -275,11 +278,12 @@ static void hda_audio_output_timer(void *opaque) | |
int64_t wpos = atomic_fetch_add(&st->wpos, 0); | |
int64_t rpos = atomic_fetch_add(&st->rpos, 0); | |
- int64_t wanted_wpos = hda_bytes_per_second(st) * (now - buft_start) / NANOSECONDS_PER_SECOND; | |
- wanted_wpos &= -4; // IMPORTANT! clip to frames | |
+ int64_t wanted_wpos = hda_bytes_per_second(st) * (now - buft_start) | |
+ / NANOSECONDS_PER_SECOND; | |
+ wanted_wpos &= -4; /* IMPORTANT! clip to frames */ | |
if (wanted_wpos <= wpos) { | |
- // we already received the data | |
+ /* we already received the data */ | |
goto out_timer; | |
} | |
@@ -287,7 +291,8 @@ static void hda_audio_output_timer(void *opaque) | |
while (to_transfer) { | |
uint32_t start = (wpos & B_MASK); | |
uint32_t chunk = audio_MIN(B_SIZE - start, to_transfer); | |
- int rc = hda_codec_xfer(&st->state->hda, st->stream, true, st->buf + start, chunk); | |
+ int rc = hda_codec_xfer( | |
+ &st->state->hda, st->stream, true, st->buf + start, chunk); | |
if (!rc) { | |
break; | |
} | |
-- | |
2.14.1 | |
From ad4e7761ba00850e4b0e77fb98b9bdcf6462dadb Mon Sep 17 00:00:00 2001 | |
From: Martin Schrodt <[email protected]> | |
Date: Sun, 15 Oct 2017 18:04:13 +0200 | |
Subject: [PATCH 26/30] checkpatch cleanup 4 | |
Signed-off-by: Martin Schrodt <[email protected]> | |
--- | |
hw/audio/hda-codec.c | 2 +- | |
1 file changed, 1 insertion(+), 1 deletion(-) | |
diff --git a/hw/audio/hda-codec.c b/hw/audio/hda-codec.c | |
index 38c8eb1561..ab89158bfc 100644 | |
--- a/hw/audio/hda-codec.c | |
+++ b/hw/audio/hda-codec.c | |
@@ -162,7 +162,7 @@ struct HDAAudioStream { | |
} voice; | |
uint8_t compat_buf[HDA_BUFFER_SIZE]; | |
uint32_t compat_bpos; | |
- uint8_t buf[8192]; // size must be power of two | |
+ uint8_t buf[8192]; /* size must be power of two */ | |
int64_t rpos; | |
int64_t wpos; | |
QEMUTimer *buft; | |
-- | |
2.14.1 | |
From 5f1780c553a85e9b24450c5fcbf581514892729f Mon Sep 17 00:00:00 2001 | |
From: Martin Schrodt <[email protected]> | |
Date: Sun, 15 Oct 2017 18:45:49 +0200 | |
Subject: [PATCH 27/30] whitespace... | |
GODDAMNIT! | |
--- | |
audio/paaudio.c | 314 ++++++++++++++++++++++++++++---------------------------- | |
1 file changed, 155 insertions(+), 159 deletions(-) | |
diff --git a/audio/paaudio.c b/audio/paaudio.c | |
index fbc30fd08e..d3ab82d65d 100644 | |
--- a/audio/paaudio.c | |
+++ b/audio/paaudio.c | |
@@ -154,7 +154,7 @@ static int qpa_run_out(HWVoiceOut *hw, int live) | |
hw->rpos = rpos; | |
return decr; | |
- fail: | |
+fail: | |
qpa_logerr(error, "qpa_run_out failed\n"); | |
goto bail; | |
} | |
@@ -217,13 +217,13 @@ static int qpa_run_in(HWVoiceIn *hw) | |
CHECK_SUCCESS_GOTO(pa->g, rerror, r == 0, fail); | |
} | |
- bail: | |
+bail: | |
pa_threaded_mainloop_unlock(pa->g->mainloop); | |
hw->wpos = wpos; | |
return incr; | |
- fail: | |
+fail: | |
qpa_logerr(error, "qpa_run_in failed\n"); | |
goto bail; | |
} | |
@@ -238,22 +238,22 @@ static pa_sample_format_t audfmt_to_pa (audfmt_e afmt, int endianness) | |
int format; | |
switch (afmt) { | |
- case AUD_FMT_S8: | |
- case AUD_FMT_U8: | |
- format = PA_SAMPLE_U8; | |
- break; | |
- case AUD_FMT_S16: | |
- case AUD_FMT_U16: | |
- format = endianness ? PA_SAMPLE_S16BE : PA_SAMPLE_S16LE; | |
- break; | |
- case AUD_FMT_S32: | |
- case AUD_FMT_U32: | |
- format = endianness ? PA_SAMPLE_S32BE : PA_SAMPLE_S32LE; | |
- break; | |
- default: | |
- dolog ("Internal logic error: Bad audio format %d\n", afmt); | |
- format = PA_SAMPLE_U8; | |
- break; | |
+ case AUD_FMT_S8: | |
+ case AUD_FMT_U8: | |
+ format = PA_SAMPLE_U8; | |
+ break; | |
+ case AUD_FMT_S16: | |
+ case AUD_FMT_U16: | |
+ format = endianness ? PA_SAMPLE_S16BE : PA_SAMPLE_S16LE; | |
+ break; | |
+ case AUD_FMT_S32: | |
+ case AUD_FMT_U32: | |
+ format = endianness ? PA_SAMPLE_S32BE : PA_SAMPLE_S32LE; | |
+ break; | |
+ default: | |
+ dolog ("Internal logic error: Bad audio format %d\n", afmt); | |
+ format = PA_SAMPLE_U8; | |
+ break; | |
} | |
return format; | |
} | |
@@ -261,23 +261,23 @@ static pa_sample_format_t audfmt_to_pa (audfmt_e afmt, int endianness) | |
static audfmt_e pa_to_audfmt (pa_sample_format_t fmt, int *endianness) | |
{ | |
switch (fmt) { | |
- case PA_SAMPLE_U8: | |
- return AUD_FMT_U8; | |
- case PA_SAMPLE_S16BE: | |
- *endianness = 1; | |
- return AUD_FMT_S16; | |
- case PA_SAMPLE_S16LE: | |
- *endianness = 0; | |
- return AUD_FMT_S16; | |
- case PA_SAMPLE_S32BE: | |
- *endianness = 1; | |
- return AUD_FMT_S32; | |
- case PA_SAMPLE_S32LE: | |
- *endianness = 0; | |
- return AUD_FMT_S32; | |
- default: | |
- dolog ("Internal logic error: Bad pa_sample_format %d\n", fmt); | |
- return AUD_FMT_U8; | |
+ case PA_SAMPLE_U8: | |
+ return AUD_FMT_U8; | |
+ case PA_SAMPLE_S16BE: | |
+ *endianness = 1; | |
+ return AUD_FMT_S16; | |
+ case PA_SAMPLE_S16LE: | |
+ *endianness = 0; | |
+ return AUD_FMT_S16; | |
+ case PA_SAMPLE_S32BE: | |
+ *endianness = 1; | |
+ return AUD_FMT_S32; | |
+ case PA_SAMPLE_S32LE: | |
+ *endianness = 0; | |
+ return AUD_FMT_S32; | |
+ default: | |
+ dolog ("Internal logic error: Bad pa_sample_format %d\n", fmt); | |
+ return AUD_FMT_U8; | |
} | |
} | |
@@ -286,17 +286,17 @@ static void context_state_cb (pa_context *c, void *userdata) | |
paaudio *g = userdata; | |
switch (pa_context_get_state(c)) { | |
- case PA_CONTEXT_READY: | |
- case PA_CONTEXT_TERMINATED: | |
- case PA_CONTEXT_FAILED: | |
- pa_threaded_mainloop_signal (g->mainloop, 0); | |
- break; | |
- | |
- case PA_CONTEXT_UNCONNECTED: | |
- case PA_CONTEXT_CONNECTING: | |
- case PA_CONTEXT_AUTHORIZING: | |
- case PA_CONTEXT_SETTING_NAME: | |
- break; | |
+ case PA_CONTEXT_READY: | |
+ case PA_CONTEXT_TERMINATED: | |
+ case PA_CONTEXT_FAILED: | |
+ pa_threaded_mainloop_signal (g->mainloop, 0); | |
+ break; | |
+ | |
+ case PA_CONTEXT_UNCONNECTED: | |
+ case PA_CONTEXT_CONNECTING: | |
+ case PA_CONTEXT_AUTHORIZING: | |
+ case PA_CONTEXT_SETTING_NAME: | |
+ break; | |
} | |
} | |
@@ -306,15 +306,15 @@ static void stream_state_cb (pa_stream *s, void * userdata) | |
switch (pa_stream_get_state (s)) { | |
- case PA_STREAM_READY: | |
- case PA_STREAM_FAILED: | |
- case PA_STREAM_TERMINATED: | |
- pa_threaded_mainloop_signal (g->mainloop, 0); | |
- break; | |
+ case PA_STREAM_READY: | |
+ case PA_STREAM_FAILED: | |
+ case PA_STREAM_TERMINATED: | |
+ pa_threaded_mainloop_signal (g->mainloop, 0); | |
+ break; | |
- case PA_STREAM_UNCONNECTED: | |
- case PA_STREAM_CREATING: | |
- break; | |
+ case PA_STREAM_UNCONNECTED: | |
+ case PA_STREAM_CREATING: | |
+ break; | |
} | |
} | |
@@ -353,14 +353,14 @@ static pa_stream *qpa_simple_new ( | |
} | |
if (r < 0) { | |
- goto fail; | |
+ goto fail; | |
} | |
pa_threaded_mainloop_unlock (g->mainloop); | |
return stream; | |
- fail: | |
+fail: | |
pa_threaded_mainloop_unlock (g->mainloop); | |
if (stream) { | |
@@ -440,13 +440,11 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as, | |
return 0; | |
- fail1: | |
+fail1: | |
return -1; | |
} | |
- | |
-static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, | |
- void *drv_opaque) | |
+static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque) | |
{ | |
int error; | |
struct audsettings obt_as = *as; | |
@@ -553,7 +551,7 @@ static int qpa_ctl_out (HWVoiceOut *hw, int cmd, ...) | |
#endif | |
switch (cmd) { | |
- case VOICE_VOLUME: | |
+ case VOICE_VOLUME: | |
{ | |
SWVoiceOut *sw; | |
va_list ap; | |
@@ -569,8 +567,8 @@ static int qpa_ctl_out (HWVoiceOut *hw, int cmd, ...) | |
pa_threaded_mainloop_lock (g->mainloop); | |
op = pa_context_set_sink_input_volume (g->context, | |
- pa_stream_get_index (pa->stream), | |
- &v, NULL, NULL); | |
+ pa_stream_get_index (pa->stream), | |
+ &v, NULL, NULL); | |
if (!op) | |
qpa_logerr (pa_context_errno (g->context), | |
"set_sink_input_volume() failed\n"); | |
@@ -578,8 +576,8 @@ static int qpa_ctl_out (HWVoiceOut *hw, int cmd, ...) | |
pa_operation_unref (op); | |
op = pa_context_set_sink_input_mute (g->context, | |
- pa_stream_get_index (pa->stream), | |
- sw->vol.mute, NULL, NULL); | |
+ pa_stream_get_index (pa->stream), | |
+ sw->vol.mute, NULL, NULL); | |
if (!op) { | |
qpa_logerr (pa_context_errno (g->context), | |
"set_sink_input_mute() failed\n"); | |
@@ -605,7 +603,7 @@ static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...) | |
#endif | |
switch (cmd) { | |
- case VOICE_VOLUME: | |
+ case VOICE_VOLUME: | |
{ | |
SWVoiceIn *sw; | |
va_list ap; | |
@@ -621,8 +619,8 @@ static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...) | |
pa_threaded_mainloop_lock (g->mainloop); | |
op = pa_context_set_source_output_volume (g->context, | |
- pa_stream_get_index (pa->stream), | |
- &v, NULL, NULL); | |
+ pa_stream_get_index (pa->stream), | |
+ &v, NULL, NULL); | |
if (!op) { | |
qpa_logerr (pa_context_errno (g->context), | |
"set_source_output_volume() failed\n"); | |
@@ -631,8 +629,8 @@ static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...) | |
} | |
op = pa_context_set_source_output_mute (g->context, | |
- pa_stream_get_index (pa->stream), | |
- sw->vol.mute, NULL, NULL); | |
+ pa_stream_get_index (pa->stream), | |
+ sw->vol.mute, NULL, NULL); | |
if (!op) { | |
qpa_logerr (pa_context_errno (g->context), | |
"set_source_output_mute() failed\n"); | |
@@ -648,10 +646,8 @@ static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...) | |
/* common */ | |
static PAConf glob_conf = { | |
-#ifdef PA_STREAM_ADJUST_LATENCY | |
.adjust_latency_out = 0, | |
.adjust_latency_in = 1, | |
-#endif | |
}; | |
static void *qpa_audio_init (void) | |
@@ -709,9 +705,9 @@ static void *qpa_audio_init (void) | |
return g; | |
- unlock_and_fail: | |
+unlock_and_fail: | |
pa_threaded_mainloop_unlock (g->mainloop); | |
- fail: | |
+fail: | |
AUD_log (AUDIO_CAP, "Failed to initialize PA context"); | |
qpa_audio_fini(g); | |
return NULL; | |
@@ -738,94 +734,94 @@ static void qpa_audio_fini (void *opaque) | |
} | |
struct audio_option qpa_options[] = { | |
- { | |
- .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.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", | |
- .tag = AUD_OPT_STR, | |
- .valp = &glob_conf.server, | |
- .descr = "server address" | |
- }, | |
- { | |
- .name = "SINK", | |
- .tag = AUD_OPT_STR, | |
- .valp = &glob_conf.sink, | |
- .descr = "sink device name" | |
- }, | |
- { | |
- .name = "SOURCE", | |
- .tag = AUD_OPT_STR, | |
- .valp = &glob_conf.source, | |
- .descr = "source device name" | |
- }, | |
- { /* End of list */ } | |
+ { | |
+ .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.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", | |
+ .tag = AUD_OPT_STR, | |
+ .valp = &glob_conf.server, | |
+ .descr = "server address" | |
+ }, | |
+ { | |
+ .name = "SINK", | |
+ .tag = AUD_OPT_STR, | |
+ .valp = &glob_conf.sink, | |
+ .descr = "sink device name" | |
+ }, | |
+ { | |
+ .name = "SOURCE", | |
+ .tag = AUD_OPT_STR, | |
+ .valp = &glob_conf.source, | |
+ .descr = "source device name" | |
+ }, | |
+ { /* End of list */ } | |
}; | |
static struct audio_pcm_ops qpa_pcm_ops = { | |
- .init_out = qpa_init_out, | |
- .fini_out = qpa_fini_out, | |
- .run_out = qpa_run_out, | |
- .write = qpa_write, | |
- .ctl_out = qpa_ctl_out, | |
- | |
- .init_in = qpa_init_in, | |
- .fini_in = qpa_fini_in, | |
- .run_in = qpa_run_in, | |
- .read = qpa_read, | |
- .ctl_in = qpa_ctl_in | |
+ .init_out = qpa_init_out, | |
+ .fini_out = qpa_fini_out, | |
+ .run_out = qpa_run_out, | |
+ .write = qpa_write, | |
+ .ctl_out = qpa_ctl_out, | |
+ | |
+ .init_in = qpa_init_in, | |
+ .fini_in = qpa_fini_in, | |
+ .run_in = qpa_run_in, | |
+ .read = qpa_read, | |
+ .ctl_in = qpa_ctl_in | |
}; | |
struct audio_driver pa_audio_driver = { | |
- .name = "pa", | |
- .descr = "http://www.pulseaudio.org/", | |
- .options = qpa_options, | |
- .init = qpa_audio_init, | |
- .fini = qpa_audio_fini, | |
- .pcm_ops = &qpa_pcm_ops, | |
- .can_be_default = 1, | |
- .max_voices_out = INT_MAX, | |
- .max_voices_in = INT_MAX, | |
- .voice_size_out = sizeof (PAVoiceOut), | |
- .voice_size_in = sizeof (PAVoiceIn), | |
- .ctl_caps = VOICE_VOLUME_CAP | |
+ .name = "pa", | |
+ .descr = "http://www.pulseaudio.org/", | |
+ .options = qpa_options, | |
+ .init = qpa_audio_init, | |
+ .fini = qpa_audio_fini, | |
+ .pcm_ops = &qpa_pcm_ops, | |
+ .can_be_default = 1, | |
+ .max_voices_out = INT_MAX, | |
+ .max_voices_in = INT_MAX, | |
+ .voice_size_out = sizeof (PAVoiceOut), | |
+ .voice_size_in = sizeof (PAVoiceIn), | |
+ .ctl_caps = VOICE_VOLUME_CAP | |
}; | |
-- | |
2.14.1 | |
From 803d51104e6bab61faf1a7833682a0c7a4dbce56 Mon Sep 17 00:00:00 2001 | |
From: Martin Schrodt <[email protected]> | |
Date: Sun, 15 Oct 2017 16:44:19 +0200 | |
Subject: [PATCH 28/30] enable debug output | |
--- | |
audio/paaudio.c | 1 + | |
1 file changed, 1 insertion(+) | |
diff --git a/audio/paaudio.c b/audio/paaudio.c | |
index d3ab82d65d..9bd086de5f 100644 | |
--- a/audio/paaudio.c | |
+++ b/audio/paaudio.c | |
@@ -6,6 +6,7 @@ | |
#include <pulse/pulseaudio.h> | |
#define AUDIO_CAP "pulseaudio" | |
+#define DEBUG | |
#include "audio_int.h" | |
typedef struct { | |
-- | |
2.14.1 | |
From 2818f4c210353e56b21caf1def2341fa6473af4b Mon Sep 17 00:00:00 2001 | |
From: Martin Schrodt <[email protected]> | |
Date: Sun, 15 Oct 2017 22:15:12 +0200 | |
Subject: [PATCH 29/30] whitespace | |
Signed-off-by: Martin Schrodt <[email protected]> | |
--- | |
audio/paaudio.c | 6 +++--- | |
1 file changed, 3 insertions(+), 3 deletions(-) | |
diff --git a/audio/paaudio.c b/audio/paaudio.c | |
index 9bd086de5f..e76e1e006f 100644 | |
--- a/audio/paaudio.c | |
+++ b/audio/paaudio.c | |
@@ -345,12 +345,12 @@ static pa_stream *qpa_simple_new ( | |
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); | |
+ | PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL); | |
} else { | |
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); | |
+ | PA_STREAM_AUTO_TIMING_UPDATE); | |
} | |
if (r < 0) { | |
@@ -414,7 +414,7 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as, | |
pa->ss.channels = as->nchannels; | |
pa->ss.rate = as->freq; | |
- pa->ba.tlength = tlength * pa_frame_size (&pa->ss); | |
+ pa->ba.tlength = tlength * pa_frame_size(&pa->ss); | |
pa->ba.maxlength = -1; | |
pa->ba.minreq = -1; | |
pa->ba.prebuf = -1; | |
-- | |
2.14.1 | |
From c44573413940ef2fc9e41e05ec7f72dbda6b101b Mon Sep 17 00:00:00 2001 | |
From: Martin Schrodt <[email protected]> | |
Date: Sun, 15 Oct 2017 22:19:49 +0200 | |
Subject: [PATCH 30/30] bigger default fraglength, to reduce PA CPU usage | |
Signed-off-by: Martin Schrodt <[email protected]> | |
--- | |
audio/paaudio.c | 4 ++-- | |
1 file changed, 2 insertions(+), 2 deletions(-) | |
diff --git a/audio/paaudio.c b/audio/paaudio.c | |
index e76e1e006f..b46beeea92 100644 | |
--- a/audio/paaudio.c | |
+++ b/audio/paaudio.c | |
@@ -459,7 +459,7 @@ static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque) | |
int64_t fragsize = g->conf.fragsize; | |
if (fragsize == 0) { | |
- fragsize = frames_per_tick_x1000 / 2500; | |
+ fragsize = frames_per_tick_x1000 / 1000; | |
} | |
int64_t buflen = g->conf.buffer_size_in; | |
if (buflen == 0) { | |
@@ -467,7 +467,7 @@ static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque) | |
} | |
int64_t maxlength = g->conf.maxlength_in; | |
if (maxlength == 0) { | |
- maxlength = fragsize * 4; | |
+ maxlength = fragsize * 2; | |
} | |
ldebug("IN internal buffer: %.2f ms (%"PRId64" frames)\n", | |
-- | |
2.14.1 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment