SendSpinDroid v2.0.0-alpha3
Bug fix and stability release focusing on audio synchronization accuracy, Android Auto reliability, and UI state consistency.
Bug Fixes
UI State Desynchronization on Activity Reconnection
When the app was reopened while PlaybackService was already running (either from a previous phone session or from Android Auto), the UI showed "not connected" with an empty Now Playing screen instead of reflecting the current playback state. This happened because onExtrasChanged only fires on future changes, not for state already set on the session, and the fallback syncUIWithPlayerState() updated the Activity-level field but not the Compose ViewModel. The fix reads session extras eagerly on MediaController connection and ensures the ViewModel is always kept in sync.
Audio Sync Error Measurement Overhaul
The sync error calculation was fundamentally broken: the old formula compared a write-side cursor (~300ms ahead) to the DAC playback position, producing a persistent ~4600ms error and causing unnecessary reanchor loops. Replaced with a cursor-based approach that compares the baseline-derived playback position (advancing at DAC clock rate) against a fresh Kalman conversion (advancing at server clock rate). At calibration these are identical, so divergence measures only real clock drift. Verified stable at +/-6ms in testing.
Additionally, start gating was tightened to reject the WAITING->PLAYING transition when the queue head is more than 50ms ahead of the DAC position, preventing 200ms+ initial misalignment.
Android Auto Artwork Grey Box
Track changes caused a grey box to appear in Android Auto's artwork area. The previous code eagerly cleared the current artwork bitmap before new binary artwork data arrived from the server, causing MediaSession to push a no-artwork state that Android Auto cached. The fix keeps existing artwork as a bridge during track changes until the new artwork arrives.
Stale Album Art Between Tracks
The previous track's album art could briefly appear on the new track's Now Playing screen. Fixed by clearing artwork immediately on metadata updates and pre-scaling bitmaps to 480px max to avoid silent framework downscaling.
Sync Error Calculation (Baseline Refresh)
Fixed baseline refresh reading a stale value after overwrite, and corrected the initial baseline to use a Kalman conversion instead of the first chunk server timestamp (which did not correspond to the DAC position).
New Features
Android Auto: Saved Servers on Connect Screen
The Connect screen previously only showed mDNS-discovered servers. It now shows saved servers at the top (sorted by most recently connected), with discovered servers below. Saved servers use ConnectionSelector to auto-select the best connection method (local, remote, or proxy) based on the current network.
Android Auto: Audio Focus Management
Without requesting audio focus, Android Auto's infotainment system had no way to know the app wanted to produce audio, so it never handed over the audio output channel from other sources (FM radio, other apps). The app now requests AUDIOFOCUS_GAIN with proper media attributes when playback starts and abandons focus on stop/pause/disconnect.
Android TV: D-pad Navigation for Server List
Server list cards were not focusable via D-pad navigation on TV, making it impossible to select servers without a touch input. Added focus ring and scale animation on TV while maintaining standard behavior on other form factors.
Android TV: Now Playing Navigation Entry
Added a "Now Playing" item to the TV navigation sidebar, following the standard TV music app pattern of providing a persistent destination to return to the playback screen.
High Power Mode: Keep Screen On
High Power Mode now sets FLAG_KEEP_SCREEN_ON for the entire connection lifetime, not just during active playback. This prevents the screen from dimming on always-on or kiosk devices.
Housekeeping
- Removed MP3 and AAC from the codec picker (unsupported by server)
- Removed effectiveLead-based pacing from the playback loop (replaced by pendingToDac pacing which suits Android's push audio model)
- Removed dead variables and stale comments from the audio pipeline
- Added MIT license file and Fastlane metadata structure for F-Droid/IzzyOnDroid compatibility
- Added third-party acknowledgments to README