Skip to content

Audio(streaming=True): a second streaming run never plays #13807

Description

@hysts

Describe the bug

With the default waveform_options, a gr.Audio(streaming=True) output plays the first stream fine but every run after that is silent. The component re-renders and the server side is fine (each run gets its own run id, MediaStream and playlist URL), but the player never attaches a new source.

waveform_options=gr.WaveformOptions(show_recording_waveform=False) works around it.

Reproduction

from io import BytesIO

import gradio as gr
import numpy as np
from pydub import AudioSegment


def stream():
    for i in range(6):
        t = np.arange(i * 8000, (i + 1) * 8000)
        pcm = (0.2 * np.sin(2 * np.pi * 440 * t / 16000) * 32767).astype("<i2")
        seg = AudioSegment(pcm.tobytes(), frame_rate=16000, sample_width=2, channels=1)
        buf = BytesIO()
        seg.export(buf, format="wav")
        yield buf.getvalue()


with gr.Blocks() as demo:
    out = gr.Audio(streaming=True, autoplay=True)
    gr.Button("Stream").click(stream, None, out)

if __name__ == "__main__":
    demo.launch()

Click Stream, let it finish, then click it again. The first run plays, the second does not. Add waveform_options=gr.WaveformOptions(show_recording_waveform=False) to the gr.Audio and both runs play.

Confirmed in Chromium: with the workaround the second run gets a new MediaSource, without it the first one is reused.

Cause

In js/audio/player/AudioPlayer.svelte, stream_active is only reset inside load_audio():

https://github.com/gradio-app/gradio/blob/ec369a583/js/audio/player/AudioPlayer.svelte#L233-L234

and load_stream() returns immediately while it is set:

https://github.com/gradio-app/gradio/blob/ec369a583/js/audio/player/AudioPlayer.svelte#L253-L256

The effect that calls load_audio() is gated on (waveform_ready || !waveform_options.show_recording_waveform):

https://github.com/gradio-app/gradio/blob/ec369a583/js/audio/player/AudioPlayer.svelte#L296-L306

For a stream the waveform branch is deliberately not rendered, since use_waveform is show_recording_waveform && !value?.is_stream, so container never exists, create_waveform() never runs, and waveform_ready never becomes true. With the default show_recording_waveform: true both sides of the guard are false, load_audio() never runs, stream_active stays true from the first run, and every later load_stream() early-returns.

The !waveform_options.show_recording_waveform escape hatch came from #13728 and only covers the disabled-waveform player, which is why that setting works around this. Gating on the existing use_waveform derived instead of on waveform_options.show_recording_waveform looks like it would cover the streaming case too, though I have not checked what else that guard affects.

Severity

I can work around it

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingsvelteFrontend-related issue (JS)🎵 AudioRelated to Audio component

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions