An android music player with bit-perfect USB output and native (no electron!) Tidal integration
Find a file
2026-01-11 04:28:10 +00:00
app Increase SQLite cursor window size to 40MiB 2026-01-11 04:25:54 +00:00
build-ffmpeg Replace Amplituda with custom seekable FFmpeg waveform extractor 2026-01-09 20:31:52 +00:00
dependencies Bump androidx-media, remove unneeded debug logs 2026-01-11 04:28:10 +00:00
gradle/wrapper Add gradle wrapper 2026-01-02 14:33:49 +00:00
scripts app_logcat.sh: Pass extra arguments to adb logcat 2026-01-10 22:05:20 +00:00
.gitignore Add release build signing and configuration 2026-01-10 03:31:47 +00:00
.gitmodules Move waveform display into main codebase 2026-01-10 21:03:29 +00:00
build.gradle.kts Add release build signing and configuration 2026-01-10 03:31:47 +00:00
CLAUDE.md Increase SQLite cursor window size to 40MiB 2026-01-11 04:25:54 +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 documentation 2026-01-10 21:08:42 +00:00
settings.gradle.kts Move waveform display into main codebase 2026-01-10 21:03:29 +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
  • SMB network storage - Access music on network shares (NAS, Windows shares, Samba)
  • Privacy-first - No tracking, no analytics (network only used for SMB)
  • 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

  • The buffer usage reporting seems wrong

Quick Start

# Build debug APK
./gradlew assembleDebug

# Build release APK (requires keystore.properties)
./scripts/build_release.sh

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

Release Builds

Create keystore.properties in the project root:

storeFile=/path/to/your/keystore.p12
storePassword=your_password
keyAlias=your_alias
keyPassword=your_password

Available Scripts

  • build_release.sh - Build signed release APK
  • 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+

Waveform extraction and display code is originally based on Andrii Serbeniuk's Amplituda and compose-audiowaveform code, which is licensed under the Apache 2.0 license.

For ffmpeg and androidx-media, see the LICENSE files in the respective submodule.