Skip to content

Disabling CFG_AUDIO_DEBUG causes uac2_speaker_fb to crash randomly on RP2040 #3267

@td2sk

Description

@td2sk

Operating System

Windows 11

Commit SHA

5130850

This is the latest commit as of today.
It reproduces even after reverting to v0.18.0 and applying only the minimum PRs necessary for operation on RP2040.

Board

Raspberry Pi Pico (RP2040)

Firmware

examples/device/uac2_speaker_fb

CFG_AUDIO_DEBUG is set to 1 (enabled), but to reproduce the issue, it must be set to 0 (disabled).
https://github.com/hathach/tinyusb/blob/master/examples/device/uac2_speaker_fb/src/tusb_config.h#L104

What happened ?

When CFG_AUDIO_DEBUG is set to 0, changing the Alternate settings from 0 (mute) to 1 (16-bit) may occasionally cause the device to hang.

In addition to the above conditions, it seems to occur only when using a USB hub, but I haven't been able to determine whether this is a mandatory requirement.

Related Issue

If the issue is related to using a hub, this issue might be relevant. However, there are the following differences:

  • Volume control works.
  • My PC is Windows 11 (x64), not a Mac (ARM M4).
  • The issue persists even when all other devices are disconnected from the hub.

How to reproduce ?

This issue rarely occurs when switching from alt=0 (silent) to alt=1 (16-bit) in Alternate settings. It may also occur rarely during normal use, sometimes within 10 minutes, other times taking several dozen hours.

The following Python code can be used to quickly reproduce the issue by frequently invoking the UAC Alt settings change.

This error does not occur every time the Alternate settings are changed. It occurs approximately once every 100 to 200 Alternate settings switches (roughly every 10 to 20 seconds in the script below). Occasionally, it may work fine for several thousand to tens of thousands of switches.

# /// script
# dependencies = [
#   "numpy",
#   "sounddevice",
# ]
# ///

import sys
import time

import sounddevice as sd


def main(device_name: str, sample_rate: int, channels: int):
    try:
        device_id = sd.query_devices(device_name, "output")["index"]
        device_info = sd.query_devices(device_id)
        print("--- Target Device Found ---")
        print(f"ID: {device_id}, Name: {device_info['name']}")
        print(f"Max Output Channels: {device_info['max_output_channels']}")
        print("---------------------------\n")
    except (ValueError, sd.PortAudioError) as e:
        print(
            f"Error: Target device '{device_name}' not found or is not an output device."
        )
        print("Please check the device name and ensure it's connected.")
        print("Available devices:")
        print(sd.query_devices())
        sys.exit(1)

    print(f"Starting stress test on '{device_name}'. Press Ctrl+C to stop.")

    count = 0
    while True:
        try:
            extra_settings = sd.WasapiSettings(exclusive=False)
            with sd.OutputStream(
                device=device_id,
                channels=channels,
                samplerate=sample_rate,
                extra_settings=extra_settings,
            ):
                # short time activation
                time.sleep(0.05)

            count += 1
            if count % 100 == 0:
                print(f". ({count} cycles)", flush=True)
            else:
                print(".", end="", flush=True)

        except sd.PortAudioError as e:
            # unresponsive
            print(f"\n\n--- PORTAUDIO ERROR after {count} cycles! ---")
            print("This likely means the device has become unresponsive.")
            print(f"Error details: {e}")
            break
        except KeyboardInterrupt:
            print("\n\nTest stopped by user.")
            break
        except Exception as e:
            print(f"\n\n--- UNEXPECTED ERROR after {count} cycles! ---")
            print(f"Error type: {type(e).__name__}")
            print(f"Error details: {e}")
            break

        # short sleep
        time.sleep(0.01)

    print(f"\nTotal successful cycles: {count}")


import argparse

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("--sample-rate", type=int, default=48000)
    parser.add_argument("--channels", type=int, default=2)
    parser.add_argument("-D", "--device-name", type=str, default="")
    args = parser.parse_args()

    main(args.device_name, args.sample_rate, args.channels)

Debug Log as txt file (LOG/CFG_TUSB_DEBUG=2)

After switching from Alt0 to Alt1, the log is interrupted.

USBD Xfer Complete on EP 81 with 4 bytes
  AUDIO xfer callback
  Queue EP 81 with 4 byt

All response statuses from the device since this issue occurred have been USBD_STATUS: USBD_STATUS_STALL_PID (0xc0000004).

log.txt

  • I have excluded redundant logs that appear unrelated. I can reattach all logs if necessary.

Screenshots

No response

I have checked existing issues, discussion and documentation

  • I confirm I have checked existing issues, discussion and documentation.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions