Private
Public Access
Two causes, both fixed: - Plex keeps one file stream per device and cuts the one in progress when another starts, so the read-ahead and the player cut each other off. Whole-file fetches (read-ahead, downloads, download-first) now ask for the file as a download (?download=1), which Plex leaves out of that rule; the plain address follows for servers that refuse downloads. - Http.abort closed the socket of a response already read to the end, whose connection was back in the pool and could be carrying the read-ahead. abort now leaves finished responses alone (test/PoolAbortTest.java). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
76 lines
4.7 KiB
Markdown
76 lines
4.7 KiB
Markdown
# Plexamp Lite (Android) — spec
|
||
|
||
The short contract for working on this app. `README.md` is the user guide; this file says what the app is
|
||
for, what limits it lives within, and what must not break.
|
||
|
||
## Goal
|
||
|
||
A Plexamp-style Plex music player for the Samsung Galaxy Mini that keeps playing reliably at home, away and
|
||
over a Bluetooth speaker.
|
||
|
||
## Target and hard limits
|
||
|
||
- Samsung Galaxy Mini GT-S5570: Android 2.2/2.3 (API 8), 240×320 ldpi, 600 MHz ARMv6, 384 MB RAM; any 2.2+
|
||
phone. A second build for Android 4.1+ (API 16: Xperia J, Galaxy S II), one per Android level, never per phone.
|
||
- Native Java (this app uses XML layouts), no libraries beyond the bundled Bouncy Castle TLS; the Android 4.1 build
|
||
adds ExoPlayer 2.18.7 (+ Guava), shrunk by R8.
|
||
- Galician by default, English in Settings. All text in `tools/strings.py`, which generates
|
||
`res/values*/strings.xml`. The connection log stays in English.
|
||
- Plays MP3/AAC/Vorbis directly; FLAC, ALAC and the rest are transcoded to MP3 by the server.
|
||
|
||
## Current scope (1.14)
|
||
|
||
- Sign in with a plex.tv/link PIN (or a manual address + token). Owned and shared servers and libraries.
|
||
- Connection picking: last good one first, then LAN HTTP, LAN HTTPS (`plex.direct`), remote HTTPS, Relay
|
||
(capped at 192 kbps). Secure addresses tried one at a time; re-checked on network changes.
|
||
- Bundled TLS 1.2/1.3 with session resumption; a loopback `StreamProxy` feeds the media player.
|
||
- Quality per network (home, away, Bluetooth cap), read-ahead of the next two tracks, stall and failure
|
||
recovery (re-pick, then download first), resume after short Bluetooth drop-outs.
|
||
- Home radios and shelves, Artists/Albums/Playlists, Search, artist/album/playlist pages, Now Playing, Up
|
||
Next queue (survives restarts), sleep timer, love, downloads to SD card with offline play reporting.
|
||
- Headset and Bluetooth buttons; pauses for calls and unplugging. Plays reported to Plex (not while
|
||
`PlexampLite-noreport` is on the SD card: for tests against a real server).
|
||
- Lyrics in Now Playing (as in the Mac app): a lasting on/off; timed lyrics follow and seek; plain text scrolls.
|
||
- Home-screen widget (both builds).
|
||
- Android 4.1 build: ExoPlayer with gapless hand-over to read-ahead/downloaded files, notification and lock screen
|
||
with art and buttons, resizable widget, Holo, ⋮ without a Menu key, metered networks.
|
||
|
||
## Out of scope
|
||
|
||
- On the Android 2.x build: gapless playback and notification playback buttons (Android 2.x can't).
|
||
- Video, photos.
|
||
|
||
## Must not break
|
||
|
||
- Package `com.minamp` and `signing/minamp.keystore` (password `minamp123`): updates install over Minamp.
|
||
- Signing: `tools/signapk.py` (classic SignApk v1); never `jarsigner`.
|
||
- `src/com/minamp/net/` is the origin of `tlskit`; keep the two in step (change `../tlskit`, reinstall).
|
||
- This repo's `tools/setup_toolchain.sh`, `make_roots.py` and `signapk.py` prepare the toolchain all the
|
||
Galaxy Mini apps use: changes there affect every app.
|
||
- Installs to internal storage (SD-card installs get killed during USB sharing).
|
||
- Whole-file fetches of a part (read-ahead, downloads) use `Library.downloadUrls` (`?download=1` first): Plex
|
||
cuts a device's file stream when the same device starts another, except for downloads.
|
||
- `platform/api8` and `platform/api16` keep the same `Platform` methods; shared code calls no API the API 8 jar
|
||
lacks (the api8 compile and Dalvik check catch it). Each build's `versionCode` is the manifest's × 100 + level,
|
||
same key; both APKs are listed in `../tenda-lite/repo/apps.json`.
|
||
- The Android 4.1 build targets API 16: no `clipPath` in drawing (the GPU can't before 4.3), and network on the
|
||
main thread is allowed in `Platform.init` (the shared code closes connections there).
|
||
|
||
## Code map
|
||
|
||
`PlayerService` (playback, recovery, gapless) · `Engine` (`MediaPlayerEngine`; `ExoEngine` in platform/api16) ·
|
||
`Platform` (per level) · `PlayerWidget` + `PlayerViews` · `Lyrics` + `LyricsView` + `util/Lrc` · · `PlayQueue` · `Downloads` · `plex/` (`Plex`, `Server`, `Library`,
|
||
`Item`) · `net/` (`Http`, `CertVerifier`, `StreamProxy`, `Threads`, `DiagLog`) · activities Home, Browse,
|
||
NowPlaying, Queue, Search, Setup, Downloads.
|
||
|
||
## Build, test, release
|
||
|
||
- `tools/setup_toolchain.sh` and `tools/fetch_exoplayer.sh` once, then `./build.sh` → `build/PlexampLite.apk`
|
||
and `build/PlexampLite-api16.apk`.
|
||
- Tests on the desktop JVM: `PlexTest` with `test/mock_plex.py`, `QueueTest`, `LyricsTest`, `PreferHomeTest` with
|
||
`test/identity_server.py`, `NetTest`, `HandshakeProfile`.
|
||
- Release: raise `versionCode`/`versionName`, build, add `changes` in `../tenda-lite/repo/apps.json`, commit
|
||
and push, `../tenda-lite/repo/publish.sh`.
|
||
- Siblings for iPod, Mac and Linux (`plexamp-lite-ios`, `-mac`, `-linux`) share behaviour; fixes are often
|
||
backported between them.
|