[PATCH 15/30] asc: generate silence if FIFO empty but engine still running

Mark Cave-Ayland posted 30 patches 1 year, 1 month ago
Maintainers: Paolo Bonzini <pbonzini@redhat.com>, Gerd Hoffmann <kraxel@redhat.com>, Laurent Vivier <laurent@vivier.eu>, Kevin Wolf <kwolf@redhat.com>, Hanna Reitz <hreitz@redhat.com>
[PATCH 15/30] asc: generate silence if FIFO empty but engine still running
Posted by Mark Cave-Ayland 1 year, 1 month ago
MacOS (un)helpfully leaves the FIFO engine running even when all the samples have
been written to the hardware, and expects the FIFO status flags and IRQ to be
updated continuously.

Since not all audio backends guarantee an all-zero output when no data is
provided, explicitly generate an all-zero output when this condition occurs to
avoid the audio backends re-using their internal buffers and looping audio once
the FIFOs are empty.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
---
 hw/audio/asc.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/hw/audio/asc.c b/hw/audio/asc.c
index 04194b1e43..c5173a8d35 100644
--- a/hw/audio/asc.c
+++ b/hw/audio/asc.c
@@ -158,8 +158,10 @@ static int generate_fifo(ASCState *s, int maxsamples)
     limit = MIN(MAX(s->fifos[0].cnt, s->fifos[1].cnt), maxsamples);
 
     /*
-     * If starting a new run with no FIFO data present, update the IRQ and
-     * continue
+     * MacOS (un)helpfully leaves the FIFO engine running even when it has
+     * finished writing out samples. Since not all audio backends guarantee an
+     * all-zero output when no data is provided, zero out the sample buffer
+     * and then update the FIFO flags and IRQ as normal and continue
      */
     if (limit == 0 && s->fifos[0].int_status == 0 &&
             s->fifos[1].int_status == 0) {
@@ -168,8 +170,9 @@ static int generate_fifo(ASCState *s, int maxsamples)
         s->fifos[1].int_status |= ASC_FIFO_STATUS_HALF_FULL |
                                   ASC_FIFO_STATUS_FULL_EMPTY;
 
+        memset(buf, 0x80, maxsamples << s->shift);
         asc_raise_irq(s);
-        return 0;
+        return maxsamples;
     }
 
     while (count < limit) {
-- 
2.30.2
Re: [PATCH 15/30] asc: generate silence if FIFO empty but engine still running
Posted by Laurent Vivier 1 year, 1 month ago
Le 24/05/2023 à 23:10, Mark Cave-Ayland a écrit :
> MacOS (un)helpfully leaves the FIFO engine running even when all the samples have
> been written to the hardware, and expects the FIFO status flags and IRQ to be
> updated continuously.
> 
> Since not all audio backends guarantee an all-zero output when no data is
> provided, explicitly generate an all-zero output when this condition occurs to
> avoid the audio backends re-using their internal buffers and looping audio once
> the FIFOs are empty.
> 
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>   hw/audio/asc.c | 9 ++++++---
>   1 file changed, 6 insertions(+), 3 deletions(-)
> 
> diff --git a/hw/audio/asc.c b/hw/audio/asc.c
> index 04194b1e43..c5173a8d35 100644
> --- a/hw/audio/asc.c
> +++ b/hw/audio/asc.c
> @@ -158,8 +158,10 @@ static int generate_fifo(ASCState *s, int maxsamples)
>       limit = MIN(MAX(s->fifos[0].cnt, s->fifos[1].cnt), maxsamples);
>   
>       /*
> -     * If starting a new run with no FIFO data present, update the IRQ and
> -     * continue
> +     * MacOS (un)helpfully leaves the FIFO engine running even when it has
> +     * finished writing out samples. Since not all audio backends guarantee an
> +     * all-zero output when no data is provided, zero out the sample buffer
> +     * and then update the FIFO flags and IRQ as normal and continue
>        */
>       if (limit == 0 && s->fifos[0].int_status == 0 &&
>               s->fifos[1].int_status == 0) {
> @@ -168,8 +170,9 @@ static int generate_fifo(ASCState *s, int maxsamples)
>           s->fifos[1].int_status |= ASC_FIFO_STATUS_HALF_FULL |
>                                     ASC_FIFO_STATUS_FULL_EMPTY;
>   
> +        memset(buf, 0x80, maxsamples << s->shift);
>           asc_raise_irq(s);
> -        return 0;
> +        return maxsamples;
>       }
>   
>       while (count < limit) {

Reviewed-by: Laurent Vivier <laurent@vivier.eu>


Re: [PATCH 15/30] asc: generate silence if FIFO empty but engine still running
Posted by Volker Rümelin 1 year, 1 month ago
> MacOS (un)helpfully leaves the FIFO engine running even when all the samples have
> been written to the hardware, and expects the FIFO status flags and IRQ to be
> updated continuously.
>
> Since not all audio backends guarantee an all-zero output when no data is
> provided, explicitly generate an all-zero output when this condition occurs to
> avoid the audio backends re-using their internal buffers and looping audio once
> the FIFOs are empty.
>
> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
> ---
>   hw/audio/asc.c | 9 ++++++---
>   1 file changed, 6 insertions(+), 3 deletions(-)

Reviewed-by: Volker Rümelin <vr_qemu@t-online.de>

> diff --git a/hw/audio/asc.c b/hw/audio/asc.c
> index 04194b1e43..c5173a8d35 100644
> --- a/hw/audio/asc.c
> +++ b/hw/audio/asc.c
> @@ -158,8 +158,10 @@ static int generate_fifo(ASCState *s, int maxsamples)
>       limit = MIN(MAX(s->fifos[0].cnt, s->fifos[1].cnt), maxsamples);
>   
>       /*
> -     * If starting a new run with no FIFO data present, update the IRQ and
> -     * continue
> +     * MacOS (un)helpfully leaves the FIFO engine running even when it has
> +     * finished writing out samples. Since not all audio backends guarantee an
> +     * all-zero output when no data is provided, zero out the sample buffer
> +     * and then update the FIFO flags and IRQ as normal and continue
>        */
>       if (limit == 0 && s->fifos[0].int_status == 0 &&
>               s->fifos[1].int_status == 0) {
> @@ -168,8 +170,9 @@ static int generate_fifo(ASCState *s, int maxsamples)
>           s->fifos[1].int_status |= ASC_FIFO_STATUS_HALF_FULL |
>                                     ASC_FIFO_STATUS_FULL_EMPTY;
>   
> +        memset(buf, 0x80, maxsamples << s->shift);
>           asc_raise_irq(s);
> -        return 0;
> +        return maxsamples;
>       }
>   
>       while (count < limit) {