**Pausing looked like the track restarting, and it was not only a look.** The card carried the position it was BUILT with — zero, on the headless path, because nothing wrote it again. media3 extrapolates a position while playing, so the bar moved and seemed right, but every state rebuild snapped back to that stale zero. Worse than cosmetic: media3 then BELIEVED the player was at zero, and reconciled on resume by seeking there, so the track really did start again. The same staleness made a seek look like it had done nothing — the engine moved and the next rebuild reported zero. `getState()` asks the engine now, on every rebuild, through `positionMs()` and `sounding()`. One JNI call and always true, instead of a number remembered from the moment playback began. A seek moves the reported position immediately rather than waiting for the engine's next event, so the scrubber does not lag a beat behind and read as snapping back. **Search, which is the half of round fifty-two that needed no decisions.** `onSearch` answers the count and `onGetSearchResult` the rows; both run the same couple of LIKEs over the library, because there is no search index in this schema and a few hundred albums do not need one. Albums rank before tracks: "play Discovery" almost always means the record, and whoever wanted the song would have said more — which matters because a voice command takes the first result. Voice comes in by a different door and it is implemented too. "Play X" arrives at `onAddMediaItems` as an item with NO media id and a `searchQuery` instead; Google's own samples disagree about whether Auto uses that or `onSearch`, so both are answered. An empty query is "play some music" and gets Recent rather than an error. The prober gained a `search:` prefix for it — `probe.sh 2 false "search:discovery"` issues `playFromSearch` through the session token, which is the path a spoken sentence actually takes. It answers `auto voice 'discovery' n=1`, `auto play ss:album:2 queued=14`, and the controller reports "One More Time" playing: a sentence turned into a record, in a process with no Activity. Still library-only, and that is now the whole remaining question. Playlists are local and would play from cold exactly as albums do, blocked only on which four root slots to spend. Catalog and Soulseek rows cannot resolve without the WebView, but can whenever the app is warm — browsable always, an honest error only when cold.
43 lines
2.5 KiB
Plaintext
43 lines
2.5 KiB
Plaintext
android auto: the position the engine is actually at, and search by voice
|
|
|
|
**Pausing looked like the track restarting, and it was not only a look.** The
|
|
card carried the position it was BUILT with — zero, on the headless path,
|
|
because nothing wrote it again. media3 extrapolates a position while playing,
|
|
so the bar moved and seemed right, but every state rebuild snapped back to that
|
|
stale zero. Worse than cosmetic: media3 then BELIEVED the player was at zero,
|
|
and reconciled on resume by seeking there, so the track really did start again.
|
|
The same staleness made a seek look like it had done nothing — the engine moved
|
|
and the next rebuild reported zero.
|
|
|
|
`getState()` asks the engine now, on every rebuild, through `positionMs()` and
|
|
`sounding()`. One JNI call and always true, instead of a number remembered from
|
|
the moment playback began. A seek moves the reported position immediately
|
|
rather than waiting for the engine's next event, so the scrubber does not lag a
|
|
beat behind and read as snapping back.
|
|
|
|
**Search, which is the half of round fifty-two that needed no decisions.**
|
|
`onSearch` answers the count and `onGetSearchResult` the rows; both run the same
|
|
couple of LIKEs over the library, because there is no search index in this
|
|
schema and a few hundred albums do not need one. Albums rank before tracks:
|
|
"play Discovery" almost always means the record, and whoever wanted the song
|
|
would have said more — which matters because a voice command takes the first
|
|
result.
|
|
|
|
Voice comes in by a different door and it is implemented too. "Play X" arrives
|
|
at `onAddMediaItems` as an item with NO media id and a `searchQuery` instead;
|
|
Google's own samples disagree about whether Auto uses that or `onSearch`, so
|
|
both are answered. An empty query is "play some music" and gets Recent rather
|
|
than an error.
|
|
|
|
The prober gained a `search:` prefix for it — `probe.sh 2 false "search:discovery"`
|
|
issues `playFromSearch` through the session token, which is the path a spoken
|
|
sentence actually takes. It answers `auto voice 'discovery' n=1`,
|
|
`auto play ss:album:2 queued=14`, and the controller reports "One More Time"
|
|
playing: a sentence turned into a record, in a process with no Activity.
|
|
|
|
Still library-only, and that is now the whole remaining question. Playlists are
|
|
local and would play from cold exactly as albums do, blocked only on which four
|
|
root slots to spend. Catalog and Soulseek rows cannot resolve without the
|
|
WebView, but can whenever the app is warm — browsable always, an honest error
|
|
only when cold.
|