- Star icons now use distinct tint colors (primary vs faded) for clear state - Station switching no longer races — old playback job is cancelled before new - Skip-ahead drops ~1s of buffered audio per tap via atomic counter - Custom SocketFactory with SO_RCVBUF=16KB and TCP_NODELAY for minimal TCP buffering - Catch-up drain: discards pre-buffered frames until network reads block (live edge) - AudioTrack PERFORMANCE_MODE_LOW_LATENCY for smallest hardware buffer Made-with: Cursor
76 lines
3.1 KiB
Markdown
76 lines
3.1 KiB
Markdown
# Full Implementation — Android 24/7 Radio
|
|
|
|
**Date:** 2026-03-09
|
|
|
|
## Task Description
|
|
|
|
Brainstormed, designed, planned, and implemented a complete Android 24/7 internet radio streaming app from scratch using subagent-driven development.
|
|
|
|
## What Was Built
|
|
|
|
### Audio Engine (custom raw pipeline)
|
|
- **StreamConnection** — OkHttp HTTP client with ICY metadata header support
|
|
- **IcyParser** — Separates audio bytes from ICY metadata, parses StreamTitle into artist/title
|
|
- **Mp3FrameSync** — Finds MP3 frame boundaries with two-frame validation and re-sync
|
|
- **AudioEngine** — Wires pipeline: StreamConnection → IcyParser → RingBuffer → Mp3FrameSync → MediaCodec → AudioTrack
|
|
|
|
### Android Service Layer
|
|
- **RadioPlaybackService** — Foreground service with wake lock, wifi lock, MediaSession
|
|
- **Stay Connected** — Exponential backoff reconnection (1s→30s cap), ConnectivityManager callback for instant retry
|
|
- **NotificationHelper** — Media-style notification with stop action
|
|
- **RadioController** — Shared state between service and UI via StateFlow
|
|
|
|
### Data Layer
|
|
- **Room Database** — Station, Playlist, MetadataSnapshot, ListeningSession, ConnectionSpan entities with full DAOs
|
|
- **DataStore Preferences** — stayConnected, bufferMs, lastStationId
|
|
- **PLS/M3U Import/Export** — Full parsers with #EXTIMG support, round-trip tested
|
|
|
|
### UI (Jetpack Compose + Material 3)
|
|
- **Station List** — Playlists as expandable groups, starring, tap-to-play, long-press menu, import
|
|
- **Now Playing** — Album art, dual timers (session + connection), latency indicator, stay connected toggle, buffer slider
|
|
- **Settings** — Playback prefs, playlist export, recently played, track history with search
|
|
- **MiniPlayer** — Bottom bar on station list when playing
|
|
|
|
### Metadata
|
|
- **AlbumArtResolver** — MusicBrainz/Cover Art Archive → ICY StreamUrl → #EXTIMG → placeholder
|
|
- **ArtCache** — In-memory LRU cache (500 entries)
|
|
- **Coil 3** — Image loading in Compose
|
|
|
|
## Commit History (20 commits)
|
|
|
|
1. Design document and implementation plan
|
|
2. Project scaffolding (Gradle, manifest, dependencies)
|
|
3. Room entities, DAOs, database, DataStore
|
|
4. M3U/PLS import/export with tests
|
|
5. ICY metadata parser with tests
|
|
6. MP3 frame synchronizer with tests
|
|
7. HTTP stream connection with tests
|
|
8. Audio engine integration
|
|
9. Foreground service with Stay Connected
|
|
10. Material 3 theme and navigation
|
|
11. Station List screen
|
|
12. Now Playing screen with dual timers
|
|
13. Settings screen with history
|
|
14. Album art resolution with MusicBrainz
|
|
15. Final integration and README
|
|
|
|
## Test Coverage
|
|
|
|
- IcyParser: 10 tests
|
|
- Mp3FrameSync: 9 tests
|
|
- StreamConnection: 6 tests
|
|
- M3uParser: 6 tests
|
|
- PlsParser: 5 tests
|
|
- PlaylistExporter: 4 tests
|
|
- RingBuffer: 4 tests
|
|
- AlbumArtResolver: 9 tests (MockWebServer)
|
|
|
|
## Follow-Up Items
|
|
|
|
- Test on actual Android 9 device with real Icecast/Shoutcast streams
|
|
- Add drag-to-reorder for stations and playlists
|
|
- Implement latency estimation from AudioTrack write/play head positions
|
|
- Add Bluetooth headset AUDIO_BECOMING_NOISY handling
|
|
- Add audio focus management
|
|
- Future: recording, clips, analytics (schema already supports it)
|