Skip to content

Some radio stations freeze the app instead of failing to play #497

Description

@alessandro-zanni

Describe the bug

Some internet radio stations do not just fail to play — they freeze the app. Selecting one plays nothing and reports no error, and from that moment search and the playback controls stop responding (audio that was already playing keeps going). Only a restart recovers it.

Starting a station ends by working out the stream's audio format, and rodio's symphonia does that by scanning the stream for a start-of-stream marker it recognises. A live stream has no end to stop that scan. So a station in a format symphonia cannot identify leaves it reading forever — and since play_stream is awaited on the serial IoEvent pump (src/infra/radio/dispatch.rs:276 on main), everything queued behind it stops too.

The specific format that triggered it here is MPEG-2 ADTS AAC, which is common on European radio. symphonia's AdtsReader registers only the MPEG-4 ADTS marker ff f1, not MPEG-2's ff f9 (symphonia-codec-aac/src/adts.rs), so a stream starting with ff f9 never matches anything. Worth knowing that a mime hint cannot rescue this: Probe::format takes the hint as _hint and ignores it.

To Reproduce

  1. Build with radio, e.g. cargo run --features internet-radio
  2. Search the station directory for radio bruno
  3. Select any of the results — for example https://stream3.xdevel.com/audio6s975355-281/stream/icecast.audio (Content-Type: audio/aacp, first bytes ff f9)
  4. Nothing plays and no error appears
  5. Try to search again or change track — the app no longer responds

Measured directly: open_radio_stream returns in under a second (content type and ICY station name both read correctly), and LocalPlayer::prepare_stream then never returns. A thread sample shows it parked inside read, waiting on stream-download for bytes it will never be able to make sense of.

Expected behavior

A station that cannot be decoded should fail quickly with a message, and leave the app usable. src/infra/radio/stream.rs already caps the connect phase (CONNECT_TIMEOUT) and the header wait (HEADER_TIMEOUT) for exactly this reason — the format probe is the third step of the same tune-in sequence and is the one left unbounded.

Desktop (please complete the following information):

  • OS: macOS 26.6.2 (arm64) — but see below, this is not platform-specific
  • Terminal: any (not terminal-specific)
  • Version: 0.41.0 (current main)

Additional context

Not platform-specific: the unbounded await is in shared code on main, so the released Linux and Windows binaries freeze on these stations today.

Two things I found while tracking it down that are worth recording:

  • Giving up has to stop the download, not the reader. A cancellation flag the reader checks between reads is never reached, because the probe parks inside read. Cancelling the stream-download task marks the stream done and wakes every waiter, so the read returns, the probe hits end-of-stream, and the thread and its download are released together.
  • Making these stations actually play is an upstream matter: adding ff f9 to symphonia's ADTS markers is a one-line change there and would cover a good slice of European radio. Bounding the probe here only turns the freeze into a clean error.

I have a fix for the freeze and will open a PR referencing this issue.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions