qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

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 <geoff@hostfission.com>
Message-id: 20200613040518.38172-6-geoff@hostfission.com
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>

authored by

Geoffrey McRae and committed by
Gerd Hoffmann
81e0efb2 de826408

+21 -8
+21 -8
audio/jackaudio.c
··· 56 56 AudiodevJackPerDirectionOptions *opt; 57 57 58 58 bool out; 59 - bool finished; 59 + bool enabled; 60 60 bool connect_ports; 61 61 int packets; 62 62 ··· 271 271 } 272 272 273 273 if (c->out) { 274 - qjack_buffer_read_l(&c->fifo, buffers, nframes); 274 + if (likely(c->enabled)) { 275 + qjack_buffer_read_l(&c->fifo, buffers, nframes); 276 + } else { 277 + for(int i = 0; i < c->nchannels; ++i) { 278 + memset(buffers[i], 0, nframes * sizeof(float)); 279 + } 280 + } 275 281 } else { 276 - qjack_buffer_write_l(&c->fifo, buffers, nframes); 282 + if (likely(c->enabled)) { 283 + qjack_buffer_write_l(&c->fifo, buffers, nframes); 284 + } 277 285 } 278 286 279 287 return 0; ··· 314 322 if (c->state == QJACK_STATE_DISCONNECTED && 315 323 c->packets % 100 == 0) { 316 324 317 - /* if not finished then attempt to recover */ 318 - if (!c->finished) { 325 + /* if enabled then attempt to recover */ 326 + if (c->enabled) { 319 327 dolog("attempting to reconnect to server\n"); 320 328 qjack_client_init(c); 321 329 } ··· 387 395 char client_name[jack_client_name_size()]; 388 396 jack_options_t options = JackNullOption; 389 397 390 - c->finished = false; 391 398 c->connect_ports = true; 392 399 393 400 snprintf(client_name, sizeof(client_name), "%s-%s", ··· 483 490 } 484 491 485 492 jo->c.out = true; 493 + jo->c.enabled = false; 486 494 jo->c.nchannels = as->nchannels; 487 495 jo->c.opt = dev->u.jack.out; 496 + 488 497 int ret = qjack_client_init(&jo->c); 489 498 if (ret != 0) { 490 499 return ret; ··· 519 528 } 520 529 521 530 ji->c.out = false; 531 + ji->c.enabled = false; 522 532 ji->c.nchannels = as->nchannels; 523 533 ji->c.opt = dev->u.jack.in; 534 + 524 535 int ret = qjack_client_init(&ji->c); 525 536 if (ret != 0) { 526 537 return ret; ··· 568 579 static void qjack_fini_out(HWVoiceOut *hw) 569 580 { 570 581 QJackOut *jo = (QJackOut *)hw; 571 - jo->c.finished = true; 572 582 qjack_client_fini(&jo->c); 573 583 } 574 584 575 585 static void qjack_fini_in(HWVoiceIn *hw) 576 586 { 577 587 QJackIn *ji = (QJackIn *)hw; 578 - ji->c.finished = true; 579 588 qjack_client_fini(&ji->c); 580 589 } 581 590 582 591 static void qjack_enable_out(HWVoiceOut *hw, bool enable) 583 592 { 593 + QJackOut *jo = (QJackOut *)hw; 594 + jo->c.enabled = enable; 584 595 } 585 596 586 597 static void qjack_enable_in(HWVoiceIn *hw, bool enable) 587 598 { 599 + QJackIn *ji = (QJackIn *)hw; 600 + ji->c.enabled = enable; 588 601 } 589 602 590 603 static int qjack_thread_creator(jack_native_thread_t *thread,