cottongin 5dd7a411ed fix: refactor player state machine to eliminate race conditions
Introduce a Connecting state so the UI reflects user intent immediately,
centralize navigation in MainActivity via state transitions, and replace
the pauseRequested volatile flag with controller state as single source
of truth.

Made-with: Cursor
2026-03-10 05:15:31 -04:00
2026-03-10 00:18:05 -04:00
2026-03-10 03:11:24 -04:00

24/7 Radio

Personal-use Android app for 24/7 internet radio streaming.

Features

  • Custom Raw Audio Pipeline — OkHttp → IcyParser → Mp3FrameSync → MediaCodec → AudioTrack for absolute minimum latency (~26ms per MP3 frame)
  • Stay Connected Mode — Aggressive reconnection with exponential backoff, never gives up
  • Dual Timers — Session elapsed time and connection elapsed time
  • Latency Indicator — Estimated stream-to-speaker latency
  • Icecast/Shoutcast Metadata — Track title, artist extraction from ICY protocol
  • Album Art — MusicBrainz/Cover Art Archive lookup with fallback chain
  • Playlist Management — PLS/M3U import/export with #EXTIMG support
  • Station Organization — Playlists, starring/favoriting, manual reorder

Requirements

  • Android 9.0+ (API 28)
  • Internet connection

Build

./gradlew assembleDebug

Import Stations

  1. Open the app
  2. Tap the import icon in the top bar
  3. Select a .m3u or .pls file
  4. Stations are added to your list

Architecture

See Design Document and Implementation Plan.

Description
Android app for 24/7 internet radio streaming with minimum latency, aggressive reconnection, and full Icecast/Shoutcast metadata support.
Readme 1 MiB
Languages
Kotlin 97.3%
Shell 2.7%