From 36963ed116b625c6dcdf71002c804f893dc6fdc1 Mon Sep 17 00:00:00 2001 From: Geoffrey McRae Date: Sat, 13 Jun 2020 14:05:13 +1000 Subject: [PATCH 1/7] audio/jack: fix invalid minimum buffer size check JACK does not provide us with the configured buffer size until after activiation which was overriding this minimum value. JACK itself doesn't have this minimum limitation, but the QEMU virtual hardware and as such it must be enforced, failure to do so results in audio discontinuities. Signed-off-by: Geoffrey McRae Message-id: 20200613040518.38172-2-geoff@hostfission.com Signed-off-by: Gerd Hoffmann --- audio/jackaudio.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/audio/jackaudio.c b/audio/jackaudio.c index 722ddb1dfe..d0b6f748f2 100644 --- a/audio/jackaudio.c +++ b/audio/jackaudio.c @@ -434,17 +434,6 @@ static int qjack_client_init(QJackClient *c) jack_set_xrun_callback(c->client, qjack_xrun, c); jack_on_shutdown(c->client, qjack_shutdown, c); - /* - * ensure the buffersize is no smaller then 512 samples, some (all?) qemu - * virtual devices do not work correctly otherwise - */ - if (c->buffersize < 512) { - c->buffersize = 512; - } - - /* create a 2 period buffer */ - qjack_buffer_create(&c->fifo, c->nchannels, c->buffersize * 2); - /* allocate and register the ports */ c->port = g_malloc(sizeof(jack_port_t *) * c->nchannels); for (int i = 0; i < c->nchannels; ++i) { @@ -468,6 +457,17 @@ static int qjack_client_init(QJackClient *c) jack_activate(c->client); c->buffersize = jack_get_buffer_size(c->client); + /* + * ensure the buffersize is no smaller then 512 samples, some (all?) qemu + * virtual devices do not work correctly otherwise + */ + if (c->buffersize < 512) { + c->buffersize = 512; + } + + /* create a 2 period buffer */ + qjack_buffer_create(&c->fifo, c->nchannels, c->buffersize * 2); + qjack_client_connect_ports(c); c->state = QJACK_STATE_RUNNING; return 0; From 2f33ee08083ca540120ab572a7130f08c4d47be3 Mon Sep 17 00:00:00 2001 From: Geoffrey McRae Date: Sat, 13 Jun 2020 14:05:14 +1000 Subject: [PATCH 2/7] audio/jack: remove unused stopped state Signed-off-by: Geoffrey McRae Message-id: 20200613040518.38172-3-geoff@hostfission.com Signed-off-by: Gerd Hoffmann --- audio/jackaudio.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/audio/jackaudio.c b/audio/jackaudio.c index d0b6f748f2..fb8efd7af7 100644 --- a/audio/jackaudio.c +++ b/audio/jackaudio.c @@ -38,7 +38,6 @@ struct QJack; typedef enum QJackState { QJACK_STATE_DISCONNECTED, - QJACK_STATE_STOPPED, QJACK_STATE_RUNNING, QJACK_STATE_SHUTDOWN } @@ -549,9 +548,6 @@ static void qjack_client_fini(QJackClient *c) { switch (c->state) { case QJACK_STATE_RUNNING: - /* fallthrough */ - - case QJACK_STATE_STOPPED: for (int i = 0; i < c->nchannels; ++i) { jack_port_unregister(c->client, c->port[i]); } From f8f0f218d4212598eab6c824754cfc40d4961ab7 Mon Sep 17 00:00:00 2001 From: Geoffrey McRae Date: Sat, 13 Jun 2020 14:05:15 +1000 Subject: [PATCH 3/7] audio/jack: remove invalid set of input support bool Initial code for JACK did not support audio input and as such this boolean was set to let QEMU know, however JACK ended up including input support making this invalid. Further investigation shows it was invalid to set it in the first instance anyway due to a failure on my part understand properly what this was for when the audodev was initially developed. Signed-off-by: Geoffrey McRae Message-id: 20200613040518.38172-4-geoff@hostfission.com Signed-off-by: Gerd Hoffmann --- audio/jackaudio.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/audio/jackaudio.c b/audio/jackaudio.c index fb8efd7af7..58c7344497 100644 --- a/audio/jackaudio.c +++ b/audio/jackaudio.c @@ -607,9 +607,6 @@ static int qjack_thread_creator(jack_native_thread_t *thread, static void *qjack_init(Audiodev *dev) { assert(dev->driver == AUDIODEV_DRIVER_JACK); - - dev->u.jack.has_in = false; - return dev; } From de82640843769e84139b5b5a8ed60b076f0bcabe Mon Sep 17 00:00:00 2001 From: Geoffrey McRae Date: Sat, 13 Jun 2020 14:05:16 +1000 Subject: [PATCH 4/7] audio/jack: do not remove ports when finishing This fixes a hang when there is a communications issue with the JACK server. Simply closing the connection is enough to completely clean up and as such we do not need to remove the ports first. As JACK uses a socket based protocol that relies on the `select` call, if there is a communication breakdown with the server the client library waits forever for a response to the unregister request. Signed-off-by: Geoffrey McRae Message-id: 20200613040518.38172-5-geoff@hostfission.com Signed-off-by: Gerd Hoffmann --- audio/jackaudio.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/audio/jackaudio.c b/audio/jackaudio.c index 58c7344497..249cbd3265 100644 --- a/audio/jackaudio.c +++ b/audio/jackaudio.c @@ -548,9 +548,6 @@ static void qjack_client_fini(QJackClient *c) { switch (c->state) { case QJACK_STATE_RUNNING: - for (int i = 0; i < c->nchannels; ++i) { - jack_port_unregister(c->client, c->port[i]); - } jack_deactivate(c->client); /* fallthrough */ From 81e0efb2e57cfdb076887b0f99ce6f0353952617 Mon Sep 17 00:00:00 2001 From: Geoffrey McRae Date: Sat, 13 Jun 2020 14:05:17 +1000 Subject: [PATCH 5/7] audio/jack: honour the enable state of the audio device When the guest closes the audio device we must start dropping input samples from JACK and zeroing the output buffer samples. Failure to do so causes sound artifacts during operations such as guest OS reboot, and causes a hang of the input pipeline breaking it until QEMU is restated. Closing and reconnecting to JACK was tested during these enable/disable calls which works well for Linux guests, however Windows re-opens the audio hardware repeatedly even when doing simple tasks like playing a system sounds. As such it was decided it is better to feed silence to JACK while the device is disabled. Signed-off-by: Geoffrey McRae Message-id: 20200613040518.38172-6-geoff@hostfission.com Signed-off-by: Gerd Hoffmann --- audio/jackaudio.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/audio/jackaudio.c b/audio/jackaudio.c index 249cbd3265..b2b53985ae 100644 --- a/audio/jackaudio.c +++ b/audio/jackaudio.c @@ -56,7 +56,7 @@ typedef struct QJackClient { AudiodevJackPerDirectionOptions *opt; bool out; - bool finished; + bool enabled; bool connect_ports; int packets; @@ -271,9 +271,17 @@ static int qjack_process(jack_nframes_t nframes, void *arg) } if (c->out) { - qjack_buffer_read_l(&c->fifo, buffers, nframes); + if (likely(c->enabled)) { + qjack_buffer_read_l(&c->fifo, buffers, nframes); + } else { + for(int i = 0; i < c->nchannels; ++i) { + memset(buffers[i], 0, nframes * sizeof(float)); + } + } } else { - qjack_buffer_write_l(&c->fifo, buffers, nframes); + if (likely(c->enabled)) { + qjack_buffer_write_l(&c->fifo, buffers, nframes); + } } return 0; @@ -314,8 +322,8 @@ static void qjack_client_recover(QJackClient *c) if (c->state == QJACK_STATE_DISCONNECTED && c->packets % 100 == 0) { - /* if not finished then attempt to recover */ - if (!c->finished) { + /* if enabled then attempt to recover */ + if (c->enabled) { dolog("attempting to reconnect to server\n"); qjack_client_init(c); } @@ -387,7 +395,6 @@ static int qjack_client_init(QJackClient *c) char client_name[jack_client_name_size()]; jack_options_t options = JackNullOption; - c->finished = false; c->connect_ports = true; snprintf(client_name, sizeof(client_name), "%s-%s", @@ -483,8 +490,10 @@ static int qjack_init_out(HWVoiceOut *hw, struct audsettings *as, } jo->c.out = true; + jo->c.enabled = false; jo->c.nchannels = as->nchannels; jo->c.opt = dev->u.jack.out; + int ret = qjack_client_init(&jo->c); if (ret != 0) { return ret; @@ -519,8 +528,10 @@ static int qjack_init_in(HWVoiceIn *hw, struct audsettings *as, } ji->c.out = false; + ji->c.enabled = false; ji->c.nchannels = as->nchannels; ji->c.opt = dev->u.jack.in; + int ret = qjack_client_init(&ji->c); if (ret != 0) { return ret; @@ -568,23 +579,25 @@ static void qjack_client_fini(QJackClient *c) static void qjack_fini_out(HWVoiceOut *hw) { QJackOut *jo = (QJackOut *)hw; - jo->c.finished = true; qjack_client_fini(&jo->c); } static void qjack_fini_in(HWVoiceIn *hw) { QJackIn *ji = (QJackIn *)hw; - ji->c.finished = true; qjack_client_fini(&ji->c); } static void qjack_enable_out(HWVoiceOut *hw, bool enable) { + QJackOut *jo = (QJackOut *)hw; + jo->c.enabled = enable; } static void qjack_enable_in(HWVoiceIn *hw, bool enable) { + QJackIn *ji = (QJackIn *)hw; + ji->c.enabled = enable; } static int qjack_thread_creator(jack_native_thread_t *thread, From bc81e6e56eeea88bb1e3b6105c80850ffb58841c Mon Sep 17 00:00:00 2001 From: Geoffrey McRae Date: Sat, 13 Jun 2020 14:05:18 +1000 Subject: [PATCH 6/7] audio/jack: simplify the re-init code path Instead of checking for the audodev state in each code path, centralize the check into the initialize function itself to make it safe to call it at any time. Signed-off-by: Geoffrey McRae Message-id: 20200613040518.38172-7-geoff@hostfission.com Signed-off-by: Gerd Hoffmann --- audio/jackaudio.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/audio/jackaudio.c b/audio/jackaudio.c index b2b53985ae..72ed7c4929 100644 --- a/audio/jackaudio.c +++ b/audio/jackaudio.c @@ -395,6 +395,10 @@ static int qjack_client_init(QJackClient *c) char client_name[jack_client_name_size()]; jack_options_t options = JackNullOption; + if (c->state == QJACK_STATE_RUNNING) { + return 0; + } + c->connect_ports = true; snprintf(client_name, sizeof(client_name), "%s-%s", @@ -485,9 +489,7 @@ static int qjack_init_out(HWVoiceOut *hw, struct audsettings *as, QJackOut *jo = (QJackOut *)hw; Audiodev *dev = (Audiodev *)drv_opaque; - if (jo->c.state != QJACK_STATE_DISCONNECTED) { - return 0; - } + qjack_client_fini(&jo->c); jo->c.out = true; jo->c.enabled = false; @@ -523,9 +525,7 @@ static int qjack_init_in(HWVoiceIn *hw, struct audsettings *as, QJackIn *ji = (QJackIn *)hw; Audiodev *dev = (Audiodev *)drv_opaque; - if (ji->c.state != QJACK_STATE_DISCONNECTED) { - return 0; - } + qjack_client_fini(&ji->c); ji->c.out = false; ji->c.enabled = false; From 586803455b3fa44d949ecd42cd9c87e5a6287aef Mon Sep 17 00:00:00 2001 From: Allan Peramaki Date: Thu, 18 Jun 2020 12:36:23 +0200 Subject: [PATCH 7/7] hw/audio/gus: Fix registers 32-bit access MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix audio on software that accesses DRAM above 64k via register peek/poke and some cases when more than 16 voices are used. Cc: qemu-stable@nongnu.org Fixes: 135f5ae1974c ("audio: GUSsample is int16_t") Signed-off-by: Allan Peramaki Tested-by: Volker Rümelin Reviewed-by: Volker Rümelin Reviewed-by: Thomas Huth Reviewed-by: Peter Maydell Signed-off-by: Philippe Mathieu-Daudé Message-id: 20200618103623.6031-1-philmd@redhat.com Message-Id: <20200615201757.16868-1-aperamak@pp1.inet.fi> [PMD: Removed unrelated style changes] Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Gerd Hoffmann --- hw/audio/gusemu_hal.c | 2 +- hw/audio/gusemu_mixer.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/audio/gusemu_hal.c b/hw/audio/gusemu_hal.c index ae40ca341c..5b9a14ee21 100644 --- a/hw/audio/gusemu_hal.c +++ b/hw/audio/gusemu_hal.c @@ -32,7 +32,7 @@ #define GUSregb(position) (* (gusptr+(position))) #define GUSregw(position) (*(uint16_t *) (gusptr+(position))) -#define GUSregd(position) (*(uint16_t *)(gusptr+(position))) +#define GUSregd(position) (*(uint32_t *)(gusptr + (position))) /* size given in bytes */ unsigned int gus_read(GUSEmuState * state, int port, int size) diff --git a/hw/audio/gusemu_mixer.c b/hw/audio/gusemu_mixer.c index 00b9861b92..56300de77e 100644 --- a/hw/audio/gusemu_mixer.c +++ b/hw/audio/gusemu_mixer.c @@ -28,7 +28,7 @@ #define GUSregb(position) (* (gusptr+(position))) #define GUSregw(position) (*(uint16_t *) (gusptr+(position))) -#define GUSregd(position) (*(uint16_t *)(gusptr+(position))) +#define GUSregd(position) (*(uint32_t *)(gusptr + (position))) #define GUSvoice(position) (*(uint16_t *)(voiceptr+(position)))