From baea032ec751306805214190b1ac23f409e9739a Mon Sep 17 00:00:00 2001 From: Martin Schrodt Date: Fri, 15 Mar 2019 09:46:51 +0100 Subject: [PATCH 1/3] audio/paaudio: fix ignored buffer_length setting Audiodev configuration allows to set the length of the buffered data. The setting was ignored and a constant value used instead. This patch makes the code apply the setting properly, and uses the previous default if nothing is supplied. Signed-off-by: Martin Schrodt Message-id: 20190315084653.120020-2-martin@schrodt.org Signed-off-by: Gerd Hoffmann --- audio/paaudio.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/audio/paaudio.c b/audio/paaudio.c index 5d410ed73f..ab2a37bbdb 100644 --- a/audio/paaudio.c +++ b/audio/paaudio.c @@ -577,7 +577,8 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as, audio_pcm_init_info (&hw->info, &obt_as); hw->samples = pa->samples = audio_buffer_samples( - qapi_AudiodevPaPerDirectionOptions_base(ppdo), &obt_as, 46440); + qapi_AudiodevPaPerDirectionOptions_base(ppdo), + &obt_as, ppdo->buffer_length); pa->pcm_buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift); pa->rpos = hw->rpos; if (!pa->pcm_buf) { @@ -637,7 +638,8 @@ static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque) audio_pcm_init_info (&hw->info, &obt_as); hw->samples = pa->samples = audio_buffer_samples( - qapi_AudiodevPaPerDirectionOptions_base(ppdo), &obt_as, 46440); + qapi_AudiodevPaPerDirectionOptions_base(ppdo), + &obt_as, ppdo->buffer_length); pa->pcm_buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift); pa->wpos = hw->wpos; if (!pa->pcm_buf) { @@ -809,7 +811,16 @@ static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...) return 0; } -/* common */ +static int qpa_validate_per_direction_opts(Audiodev *dev, + AudiodevPaPerDirectionOptions *pdo) +{ + if (!pdo->has_buffer_length) { + pdo->has_buffer_length = true; + pdo->buffer_length = 46440; + } + return 1; +} + static void *qpa_audio_init(Audiodev *dev) { paaudio *g; @@ -836,6 +847,13 @@ static void *qpa_audio_init(Audiodev *dev) g = g_malloc(sizeof(paaudio)); server = popts->has_server ? popts->server : NULL; + if (!qpa_validate_per_direction_opts(dev, popts->in)) { + goto fail; + } + if (!qpa_validate_per_direction_opts(dev, popts->out)) { + goto fail; + } + g->dev = dev; g->mainloop = NULL; g->context = NULL; From f6142777659f2e7ad143f2850f1f036f899f475f Mon Sep 17 00:00:00 2001 From: Martin Schrodt Date: Fri, 15 Mar 2019 09:46:52 +0100 Subject: [PATCH 2/3] audio/paaudio: prolong and make latency configurable The latency of a connection to the PulseAudio server is determined by the tlength parameter. This was hardcoded to 10ms, which is a bit too tight on my machine, causing audio on host and guest to malfunction. A setting of 15ms works fine here. To allow tweaking, I also made the setting configurable via the new -audiodev config. This allows to squeeze out better timings in scenarios where the emulation allows it. I also removed setting of the minreq parameter to (seemingly arbitrary) half the latency, since it showed worse audio quality during my tests. Allowing PulseAudio to request smaller chunks helped. Signed-off-by: Martin Schrodt Message-id: 20190315084653.120020-3-martin@schrodt.org Signed-off-by: Gerd Hoffmann --- audio/paaudio.c | 12 ++++++------ qapi/audio.json | 6 +++++- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/audio/paaudio.c b/audio/paaudio.c index ab2a37bbdb..be27c73f09 100644 --- a/audio/paaudio.c +++ b/audio/paaudio.c @@ -549,12 +549,8 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as, ss.channels = as->nchannels; ss.rate = as->freq; - /* - * qemu audio tick runs at 100 Hz (by default), so processing - * data chunks worth 10 ms of sound should be a good fit. - */ - ba.tlength = pa_usec_to_bytes (10 * 1000, &ss); - ba.minreq = pa_usec_to_bytes (5 * 1000, &ss); + ba.tlength = pa_usec_to_bytes(ppdo->latency, &ss); + ba.minreq = -1; ba.maxlength = -1; ba.prebuf = -1; @@ -818,6 +814,10 @@ static int qpa_validate_per_direction_opts(Audiodev *dev, pdo->has_buffer_length = true; pdo->buffer_length = 46440; } + if (!pdo->has_latency) { + pdo->has_latency = true; + pdo->latency = 15000; + } return 1; } diff --git a/qapi/audio.json b/qapi/audio.json index 97aee37288..9fefdf5186 100644 --- a/qapi/audio.json +++ b/qapi/audio.json @@ -206,12 +206,16 @@ # # @name: name of the sink/source to use # +# @latency: latency you want PulseAudio to achieve in microseconds +# (default 15000) +# # Since: 4.0 ## { 'struct': 'AudiodevPaPerDirectionOptions', 'base': 'AudiodevPerDirectionOptions', 'data': { - '*name': 'str' } } + '*name': 'str', + '*latency': 'uint32' } } ## # @AudiodevPaOptions: From ade103011c6476353fbc2a707aa6ef1f1aa9e2fb Mon Sep 17 00:00:00 2001 From: Martin Schrodt Date: Fri, 15 Mar 2019 09:46:53 +0100 Subject: [PATCH 3/3] audio/paaudio: fix microphone input being unusable The current code does not specify the metrics of the buffers for the input device. This makes PulseAudio choose very bad defaults, which causes input to be unusable: Audio put in gets out 30 seconds later. This patch fixes that and makes the latency configurable as well. Signed-off-by: Martin Schrodt Message-id: 20190315084653.120020-4-martin@schrodt.org Signed-off-by: Gerd Hoffmann --- audio/paaudio.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/audio/paaudio.c b/audio/paaudio.c index be27c73f09..45295b4e5e 100644 --- a/audio/paaudio.c +++ b/audio/paaudio.c @@ -605,6 +605,7 @@ static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque) { int error; pa_sample_spec ss; + pa_buffer_attr ba; struct audsettings obt_as = *as; PAVoiceIn *pa = (PAVoiceIn *) hw; paaudio *g = pa->g = drv_opaque; @@ -615,6 +616,11 @@ static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque) ss.channels = as->nchannels; ss.rate = as->freq; + ba.fragsize = pa_usec_to_bytes(ppdo->latency, &ss); + ba.maxlength = -1; + ba.minreq = -1; + ba.prebuf = -1; + obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness); pa->stream = qpa_simple_new ( @@ -624,7 +630,7 @@ static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque) ppdo->has_name ? ppdo->name : NULL, &ss, NULL, /* channel map */ - NULL, /* buffering attributes */ + &ba, /* buffering attributes */ &error ); if (!pa->stream) {