Installed on the SD card (installLocation auto), Minamp was killed whenever USB storage was turned on. A2DP dropouts send AUDIO_BECOMING_NOISY like an unplug: after a Bluetooth loss, resume if the speaker is back within 20 s. Focus loss, media buttons and stream failures now go to the connection log. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Minamp
A small Plexamp-style music player for Plex, built for the Samsung Galaxy Mini (GT-S5570: Android 2.2/2.3, 240×320 ldpi screen, 600 MHz ARMv6, 384 MB RAM). Runs on any Android 2.2+ phone.
Language
The interface is in Galician by default, whatever language the phone is set to. English is
available under Axustes → Idioma. All text lives in tools/strings.py (key → English, Galician),
which generates res/values/strings.xml (Galician) and res/values-en/strings.xml; the connection
log stays in English since it's meant for troubleshooting.
Install
- On the phone: Settings → Applications → Unknown sources (tick it).
- Copy
Minamp.apkto the SD card (USB cable, or download it in the browser) and open it with a file manager, or from a computer:adb install Minamp.apk. - The app can live on the SD card (Settings → Applications → Manage → Minamp → Move to SD card), which helps with the Mini's tiny internal storage.
Sign in
Open Minamp → Sign in with Plex. It shows a 4-character code; on any other device go to plex.tv/link and type it in. Minamp then lists your servers (owned and shared) and music libraries.
Connect to a server address is the manual fallback: an IP/hostname plus an optional X-Plex-Token.
Streaming from anywhere
After sign-in Minamp knows every address Plex advertises for your server and picks the best working one, re-checking whenever the phone switches network:
| Order | Connection | When it's used |
|---|---|---|
| 1 | Whatever worked last time | Tried alone first, so a normal start costs one request (if that was a remote address, the home addresses get 2 s first) |
| 2 | Home network, plain HTTP | On your Wi-Fi (fast: no encryption work for the phone) |
| 3 | Home network, HTTPS (*.plex.direct) |
On your Wi-Fi if plain HTTP is refused, or if Settings → Encrypt at home too is on |
| 4 | Remote, HTTPS | Away, if Remote Access is set up on the server |
| 5 | Plex Relay | Away, when the server isn't reachable directly (bandwidth-capped; Minamp caps itself at 192 kbps) |
Secure addresses are tried one at a time: on a 600 MHz phone a TLS handshake takes seconds, and several at once make each of them time out. Minamp uses TLS 1.2 with session resumption, so only the first connection to each server pays the full cost; later ones resume in a fraction of it.
For the best remote experience enable Settings → Remote Access on your Plex Media Server. Without it, Relay still works.
Android 2.x can't do modern TLS, so Minamp bundles its own TLS 1.2/1.3 stack (Bouncy Castle,
renamed to com.minamp.bc so it doesn't clash with the old copy inside Android) and verifies
certificates against Mozilla's root store (from certifi). A tiny loopback proxy feeds the
phone's media player, so HTTPS streams and relay work the same as local ones. If the phone's
clock has been reset to before 2024 the certificate date check is skipped rather than failing.
Playback and quality
- MP3, AAC (M4A) and Ogg Vorbis play directly. FLAC, ALAC etc. are transcoded to MP3 by the server (Android 2.2/2.3 can't decode FLAC).
- Menu → Settings: separate quality for home Wi-Fi (default Original) and for away/mobile data (default 192 kbps MP3); 320/256/192/128/96 kbps available.
- Seeking in a transcoded track restarts the transcode at the new position.
- If a stream fails, Minamp re-picks the connection and resumes; if it fails again it downloads the whole track first and plays from the SD card. "Download tracks before playing" forces that mode (useful on flaky mobile data).
- Plays are reported to Plex (Now Playing in the Plex dashboard, play counts, resume position).
Features
- Home: Library radio, Loved radio (rated 4★+ / loved), Time-travel radio (pick a decade), Random album, Recently added and Recently played shelves.
- Artists / Albums (5 sort orders) / Playlists tabs with paging and fast scroll; Search.
- Artist page with Play all and Artist radio; album and playlist pages with Play/Shuffle.
- Long-press anything: Play next, Add to queue, Go to album/artist, Love.
- Now Playing: big art on a backdrop coloured from the cover, seek bar, shuffle, repeat (queue/track), love, sleep timer (15–90 min or end of track), where it's streaming from.
- Up Next queue: jump, play next, remove, clear; the queue and position survive restarts.
- Downloads for offline listening: long-press a track, album, artist or playlist -> Download; Menu -> Downloads shows progress, space used and free, play/shuffle, retry and remove. Files go to the SD card. MP3 originals are kept as they are (unless above a lower Download quality in Settings); everything else is transcoded to MP3, 320 kbps by default. Downloaded tracks play from the SD card, offline too, and plays made offline are reported to Plex later.
- Menu -> Close Minamp stops the music and closes every screen.
- Wired headset button: 1 click play/pause, 2 next, 3 previous; Bluetooth media keys; pauses for calls and when headphones are unplugged.
Building (no Android SDK needed)
tools/setup_toolchain.sh # once: fetches aapt2, the API 8 android.jar, builds dx, renames Bouncy Castle
./build.sh # -> build/Minamp.apk
build.sh runs aapt2 (resources), javac (Java 8 bytecode checked against the API 8
android.jar), dx (dex 035) and tools/signapk.py, which writes the v1 signature in the
classic Android SignApk format and aligns the APK. (Modern jarsigner output does not install on
Android 4.2 and older: it names digests SHA-1-Digest and labels the PKCS#7 signer algorithm in a
way old JarUtils can't read, so the phone treats the APK as unsigned.) The debug key in signing/ (password minamp123) is what this APK is
signed with, so rebuilt APKs install over it.
Tests (desktop JVM, no device):
test/PlexTest.java+test/mock_plex.py: PIN sign-in, server discovery, connection picking/fallback, TLS with a wildcard plex.direct-style certificate (ECDSA leaf, RSA root), untrusted-root rejection, browsing, search, artwork, and the stream proxy (Range requests over TLS, de-chunking transcodes, aborting).test/QueueTest.java: shuffle/unshuffle, repeat modes, play next, remove, move, clear.
Limits
- No gapless playback (Android 2.2/2.3 have no API for it).
- Notification has no playback buttons (pre-Android 3 can't); tap it to open Now Playing.