An android music player with bit-perfect USB output and native (no electron!) Tidal integration
Find a file
2026-01-13 20:30:30 +00:00
app Add button to clear all cached file/dir metadata in Settings 2026-01-13 20:30:30 +00:00
build-ffmpeg Replace Amplituda with custom seekable FFmpeg waveform extractor 2026-01-09 20:31:52 +00:00
dependencies Update androidx-media: fix slow Ogg seeking with seek map 2026-01-13 20:24:03 +00:00
gradle/wrapper Add gradle wrapper 2026-01-02 14:33:49 +00:00
scripts app_restart.sh: Allow downgrade (for bisecting) 2026-01-13 17:35:03 +00:00
.gitignore Add release build signing and configuration 2026-01-10 03:31:47 +00:00
.gitmodules Modernize Tidal API client, remove submodule 2026-01-11 07:06:58 +00:00
build.gradle.kts Add release build signing and configuration 2026-01-10 03:31:47 +00:00
CLAUDE.md Add Ogg seek map for fast seeking 2026-01-13 19:54:15 +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 Add README.md 2026-01-12 22:19:54 +00:00
settings.gradle.kts Add Tidal track playback support 2026-01-11 08:29:12 +00:00
shell.nix Misc UI polish 2026-01-04 17:19:56 +00:00
TIDAL_API_REFERENCE.md Add Tidal API reference (generated from python-tidal source) 2026-01-11 08:31:08 +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
  • 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

Planned features

  • Smarter buffering implementation (for now we're only using ExoPlayer's built in player cache)

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.

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.