An android music player with bit-perfect USB output and native (no electron!) Tidal integration
Find a file
2026-01-06 22:57:03 +00:00
app Fix path matching bug that caused erroneous cache deletes 2026-01-06 22:57:03 +00:00
build-ffmpeg Move bit-perfect functionality into ExoPlayer fork 2026-01-05 23:18:40 +00:00
dependencies Update androidx-media fork to fix 24/32-bit files being rendered to 16-bit 2026-01-06 18:46:59 +00:00
gradle/wrapper Add gradle wrapper 2026-01-02 14:33:49 +00:00
scripts Use local build of androidx-media and ffmpeg 2026-01-05 17:06:35 +00:00
.gitignore Update .gitignore 2026-01-02 14:31:54 +00:00
.gitmodules Fix playback after adding to empty queue, add (unused) androidx-media and ffmpeg submodules 2026-01-05 16:03:18 +00:00
build.gradle.kts Bump tool and dependency versions 2026-01-01 23:39:23 +00:00
CLAUDE.md Clear older browse-triggered queue scans when navigating to new dir 2026-01-06 22:06:21 +00:00
gradle.properties Use local build of androidx-media and ffmpeg 2026-01-05 17:06:35 +00:00
gradlew Add gradle wrapper 2026-01-02 14:33:49 +00:00
gradlew.bat Add gradle wrapper 2026-01-02 14:33:49 +00:00
README.md Update README.md 2026-01-06 22:01:34 +00:00
settings.gradle.kts Fix gradle config to actually use our mediax fork 2026-01-06 15:07:09 +00:00
shell.nix Misc UI polish 2026-01-04 17:19:56 +00:00

PlaceboPlayer

A minimalist Android music player focused on audio quality for USB DACs.

Key Features

  • Bit-perfect audio output - Direct USB DAC support with no resampling or mixing
  • Gapless playback - Seamless transitions between tracks
  • Aggressive buffering - Pre-loads songs into memory for instant playback
  • Folder-based navigation - No library, just browse your files
  • Privacy-first - No tracking, no analytics, no network communication
  • AOSP compatible - Works on pure Android without Google services

Technical Highlights

  • Min SDK: API 34 (Android 14.0+) for advanced AudioTrack API
  • Architecture: MVVM with Jetpack Compose
  • Playback: Media3 fork with BitPerfectAudioOutputProvider for USB DACs
  • Media Session: Lock screen controls and notification integration
  • Data Architecture: Dual database design (persistent settings + regenerable cache)
    • Persistent Database (userdata): Settings, playlists, playback history
    • Cache Database (cache storage): Metadata, cover art (cleared by Android when storage low)

Known issues

Planned features

  • Search in file browser
  • A "stats for nerds" screen with detailed debug info. A detailed display of buffer usage, etc.
  • Display an amplitude waveform instead of the seek bar, allow sliding it back and forth to seek ("waveform seekbar")

Quick Start

# Build app
./gradlew assembleDebug

# Start emulator with GUI, install the built apk and run it
./scripts/emulator.sh --gui

Available Scripts

  • emulator.sh - Install APK and run app in emulator, starting the emulator if not already running.
    • --gui - Enable graphical interface
    • --install-apk <path> - Install specified APK instead of the default
  • app_restart.sh - Kill, reinstall and restart the app on emulator
  • app_logcat.sh - Stream logs from the app (use with timeout)
  • app_play_intent.sh - Trigger playback via intent (for automated testing)

Automated Testing & Debugging

The app supports intent-based playback triggering for automated testing:

# Trigger playback with test files
./scripts/app_play_intent.sh

# View logs (use timeout to limit output)
timeout 10 ./scripts/app_logcat.sh

# Reinstall and restart app
./scripts/app_restart.sh

The app_play_intent.sh script demonstrates how to:

  • Send a PLAY_AUDIO intent with a content:// URI
  • Provide an optional queue of tracks
  • Trigger playback programmatically without UI interaction

See CLAUDE.md for technical details.

Documentation

  • CLAUDE.md - Technical documentation for developers and AI agents

License

GPLv2+