python-sdks icon indicating copy to clipboard operation
python-sdks copied to clipboard

Audio Source Clear Queue only clears the first second of audio

Open CalinR opened this issue 10 months ago • 1 comments

I'm using a Text to Speech service that only returns full sentences worth of audio. Because of this, the audio is sometimes 5+ seconds long. If I start a capture_frame(frame) on the audio and then do a clear_queue() when there is still more than a second to be played, it only clears 1 second worth of audio and keeps playing the rest.

Here is example code you can run with a long audio clip.

async def entrypoint(ctx: JobContext):
    room = ctx.room
    await ctx.connect(auto_subscribe=agents.AutoSubscribe.AUDIO_ONLY)
    audio_source = rtc.AudioSource(24000, 1, 5000)
    track = rtc.LocalAudioTrack.create_audio_track(f"test-mic", audio_source)
    options = rtc.TrackPublishOptions()
    options.source = rtc.TrackSource.SOURCE_MICROPHONE
    await room.local_participant.publish_track(track, options)

    async def capture_task(audio_frame: rtc.AudioFrame):
        try:
            await audio_source.capture_frame(audio_frame)
            await audio_source.wait_for_playout()
        except asyncio.CancelledError:
            print("Capture task cancelled")

    with open("audio_clip.wav", "rb") as f:
        # Get audio byte data and assign it to a variable
        audio_data = f.read()
        samples_per_channel = int(len(audio_data) / 2)
        audio_frame = rtc.AudioFrame(
            data=audio_data,
            sample_rate=24000,
            num_channels=1,
            samples_per_channel=samples_per_channel,
        )
        await asyncio.sleep(5.0) # Wait for things to load on client first
        capture_task_job = asyncio.create_task(capture_task(audio_frame))
        # simulate an interruption 1 second into playing the audio
        await asyncio.sleep(1.0)
        audio_source.clear_queue()
        await aio.gracefully_cancel(capture_task_job)

CalinR avatar Mar 13 '25 15:03 CalinR

@theomonnom Can you take a look?

        capture_task_job = asyncio.create_task(capture_task(audio_frame))
        # simulate an interruption 1 second into playing the audio
        await asyncio.sleep(1.0)

        # await aio.gracefully_cancel(capture_task_job)
        capture_task_job.cancel()
        await capture_task_job

        print("Clearing queue")
        audio_source.clear_queue()
        print("Cleared queue")

I can reproduce it with await capture_task_job before clear queue, the rest of the audio is still played out after clear_queue.

longcw avatar Mar 22 '25 16:03 longcw