An android music player with bit-perfect USB output and native (no electron!) Tidal integration
| app | ||
| build-ffmpeg | ||
| dependencies | ||
| gradle/wrapper | ||
| scripts | ||
| .gitignore | ||
| .gitmodules | ||
| build.gradle.kts | ||
| CLAUDE.md | ||
| gradle.properties | ||
| gradlew | ||
| gradlew.bat | ||
| README.md | ||
| settings.gradle.kts | ||
| shell.nix | ||
| TIDAL_API_REFERENCE.md | ||
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
- Tidal streaming - In-app streaming through Tidal
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
- Playing i24 files results in downsampling to 16-bit.
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 APKemulator.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 emulatorapp_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_AUDIOintent 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.
The Tidal client functionality is originally based on https://github.com/0xf4b1/tidal-kt with heavy modifications. That code is licensed under GPL3.
For ffmpeg and androidx-media, see the LICENSE files in the respective submodule.