Files
Android-247-Radio/README.md
cottongin a09c50c302 docs: refresh README with screenshots, full feature list, and build guide
Add AI disclaimer, 4 emulator screenshots, expanded feature sections
(Android Auto, SomaFM, per-station quality, tabs, Media3 notification,
now-playing logging, blurred art background), build.sh documentation,
inline architecture diagram, and tech stack table.

Made-with: Cursor
2026-03-18 14:06:00 -04:00

6.1 KiB
Raw Permalink Blame History

24/7 Radio

Android app for 24/7 internet radio streaming with minimum latency, aggressive reconnection, and full Icecast/Shoutcast metadata support.

Important

This project was built with the assistance of Cursor (Claude Opus/Sonnet 4.6).


Screenshots

Station List Now Playing Mini-Player Station Art Fallback
Station list showing SomaFM tab Now Playing with album art Station list with mini-player bar Now Playing with station art fallback

Features

Playback

  • Custom raw audio pipeline — OkHttp → IcyParser → Mp3FrameSync → MediaCodec → AudioTrack for minimum latency (~26ms per MP3 frame)
  • Stay Connected mode — aggressive reconnection with exponential backoff; never gives up until you say stop
  • Configurable buffer — 0500ms slider; 0ms keeps you as live as possible, higher values smooth out spotty connections
  • Icecast/Shoutcast metadata — ICY protocol track title and artist extraction
  • Album art — MusicBrainz/Cover Art Archive lookup with a fallback chain (ICY stream URL → station default art → station logo → placeholder)

Station Management

  • SomaFM built-in — full SomaFM catalog pre-loaded, sorted by listener count
  • Per-station stream quality — choose 128/256 kbps and SSL/non-SSL per station, or set a global preference order
  • PLS/M3U import/export — with #EXTIMG support for station artwork URLs
  • Tabs (playlists) — pin/unpin, rename, and drag-to-reorder tabs and stations within them
  • Starring/favoriting — starred stations sort to the top of their tab

Now Playing Screen

  • Blurred album art background — art fills the screen behind the player controls
  • Session timer — total elapsed time since you hit play, not reset on reconnect
  • Connection timer — elapsed time for the current TCP connection, resets on each reconnect
  • Latency indicator — estimated stream-to-speaker latency in ms
  • Track history — every track change is logged to the database with station and timestamp
  • Now Playing file logging — optionally write track history to CSV, JSON Lines, or plain text

System Integration

  • Media3 notification — system media notification with album art, transport controls (play/stop + seek-to-live), lockscreen and Bluetooth headset support
  • Android Auto — app registers as a media source; browse your playlists and stations from the car display

Build Tooling

  • build.sh — interactive menu: release APK (signed), debug APK, keystore management, and clean

Requirements

  • Android 9.0+ (API 28)
  • Internet connection

Build

The recommended path is the interactive build script:

./build.sh

Menu options:

  1. Build Release APK — signed, ready to sideload
  2. Build Debug APK — quick, for testing
  3. Manage Keystore — create or inspect the signing key
  4. Clean — remove build artifacts

On first run, choose option 3 to create a keystore before building a release APK. Output lands in dist/.

Alternatively, build directly with Gradle:

./gradlew assembleDebug      # debug
./gradlew assembleRelease    # release (requires keystore configured in build.gradle.kts)

Importing Stations

  1. Open the app
  2. Tap the settings gear → Import
  3. Select a .m3u or .pls file
  4. Stations are added to your library

Exported files include #EXTIMG tags for stations that have a default artwork URL set.


SomaFM

The SomaFM catalog is pre-loaded on first launch — no import needed. Stations are sorted by current listener count (refreshable with the sync button). You can set a global stream quality preference (256 kbps SSL recommended) or override it per station via long-press → Quality.


Architecture

Four layers:

┌─────────────────────────────────────────┐
│              UI Layer                   │
│  Compose screens, ViewModel, StateFlow  │
├─────────────────────────────────────────┤
│           Service Layer                 │
│  RadioPlaybackService (MediaLibrary     │
│  Service), RadioPlayerAdapter (Media3   │
│  Player facade), wake + wifi locks      │
├─────────────────────────────────────────┤
│           Audio Engine                  │
│  StreamConnection → IcyParser →         │
│  Mp3FrameSync → MediaCodec → AudioTrack │
├─────────────────────────────────────────┤
│            Data Layer                   │
│  Room DB, PLS/M3U import/export,        │
│  DataStore preferences                  │
└─────────────────────────────────────────┘

The audio engine is a standalone component with no Android framework dependencies. The service owns reconnection policy, Android Auto browse tree, and the Media3 session. The UI observes state via StateFlow and never touches the engine directly.

For full detail see the design document and Media3/Android Auto design.


Tech Stack

Layer Library
Language Kotlin
UI Jetpack Compose, Material Design 3
Media session / Auto AndroidX Media3 (media3-session, media3-common)
HTTP streaming OkHttp
Audio decoding MediaCodec (hardware-accelerated)
Audio output AudioTrack
Database Room
Preferences DataStore
Image loading Coil
Album art lookup MusicBrainz / Cover Art Archive (no API key required)

License

MIT