Files
pluriwave/openspec/changes/android-auto-local-music-phase3/specs/android-auto-media/spec.md
T
FreeTLab dfd40ca937 feat(auto): queue playback and shuffle for local music folders [size:exception]
Adds "Reproducir carpeta" (sequential) and "Reproducir aleatorio"
(Fisher-Yates over the name-sorted order) as folder-scoped playable
actions, with auto-advance on track completion and skip next/prev.

Isolation from live radio is structural, not disciplinary: the
public playMediaItem always clears the local queue on any call, and
a new private _encolarCambioFuente is the only path that can advance
within it. _cambiarFuente, ControladorReconexion, and the reconnect
error path are untouched -- confirmed by a byte-for-byte empty diff
on all 4 pre-existing radio/reconnect regression suites, independently
re-run before and after (21/21 both times).

Handler wiring itself is static-review-only (PluriWaveAudioHandler
can't be unit-instantiated); the isolation/advance/race-guard
decision logic is extracted into cola_local.dart's pure functions,
which are fully unit-tested.
2026-07-20 01:08:15 +02:00

5.8 KiB

Delta for Android Auto Media — Local Music Phase 3 (Folder Queue + Shuffle)

ADDED Requirements

Requirement: Folder-Scoped Sequential Play Action

The local-music browse tree MUST prepend a "Reproducir carpeta" playable item on page 0 of any local folder that has at least one direct audio-file child (NodoLocal non-directory). Selecting it MUST build a queue of that folder's direct audio children in filename order and start sequential playback.

Scenario: Folder has tracks

  • GIVEN a local folder has one or more direct audio-file children
  • WHEN page 0 is browsed
  • THEN "Reproducir carpeta" is prepended, and selecting it plays those tracks in name order

Scenario: Folder has no tracks

  • GIVEN a local folder has zero direct audio-file children
  • WHEN page 0 is browsed
  • THEN no "Reproducir carpeta" item is returned

Requirement: Folder-Scoped Shuffled Play Action

The local-music browse tree MUST prepend a "Reproducir aleatorio" playable item alongside "Reproducir carpeta", under the same folder-has-tracks condition. Selecting it MUST build a queue of the same direct-audio-children set in shuffled order and start playback.

Scenario: Folder has tracks

  • GIVEN a local folder has one or more direct audio-file children
  • WHEN page 0 is browsed
  • THEN "Reproducir aleatorio" is prepended, and selecting it plays the same set shuffled

Scenario: Deterministic under seed

  • GIVEN a fixed shuffle seed is injected for testing
  • WHEN the queue is built for a given track set
  • THEN the resulting order is reproducible across runs with that seed

Requirement: Local Queue Auto-Advance and Transport Skip

While a local-music queue (from either action) is active, PluriWaveAudioHandler MUST auto-advance to the next queued track when the current track finishes, and MUST move within the queue when skipToNext/skipToPrevious is invoked.

Scenario: Track completes mid-queue

  • GIVEN the current track is not the last one in the queue
  • WHEN it finishes
  • THEN the handler advances to and plays the next track automatically

Scenario: Skip within queue

  • GIVEN a local-music queue is active
  • WHEN skipToNext/skipToPrevious is invoked, including at the first or last track
  • THEN the queue index moves accordingly and the corresponding track plays without throwing

Requirement: Local Queue Mode Isolation From Radio Playback (Regression Guard — CRITICAL)

The local-music queue mechanism (auto-advance, skip-within-queue, queue state) MUST be scoped by an explicit mode boundary and MUST NEVER activate for, interfere with, or alter radio playback, reconnection, or any other non-local-music playback path. Switching between an active local queue and radio playback, in either direction, MUST cleanly stop/replace the previously active mode. This is the highest-priority regression requirement of this change.

Scenario: Radio starts while a local queue is active

  • GIVEN a local-music queue is actively auto-advancing
  • WHEN the user selects a station (emisora:<uuid>) or a radio-group entry
  • THEN the local queue mode stops cleanly (no further auto-advance or skip behavior leaks)
  • AND radio playback starts and behaves exactly as before this feature, including reconnection

Scenario: Local queue starts while radio is active

  • GIVEN a station is currently playing
  • WHEN the user selects "Reproducir carpeta" or "Reproducir aleatorio"
  • THEN radio playback and its reconnect state exit cleanly
  • AND the local-music queue starts playing with auto-advance/skip active

Scenario: Radio reconnect logic is provably untouched

  • GIVEN no local-music queue has been started in the current session
  • WHEN a live stream stalls and reconnects, or errors
  • THEN reconnect behavior is byte-identical to pre-feature behavior, since ProcessingState.completed (the queue-advance trigger) never fires for radio streams

Scenario: Single-track local playback (pista:<id>) is unaffected

  • GIVEN the user taps a single track directly, not via a folder-play action
  • WHEN that track finishes
  • THEN no queue auto-advance occurs, matching existing Phase 1/2 single-track behavior

Requirement: Local Queue End-of-Queue Behavior

When the last track in an active local-music queue finishes, playback MUST stop cleanly rather than loop back to the first track or leave the handler in an inconsistent state, consistent with repeat modes being out of scope for this phase.

Scenario: Last track finishes

  • GIVEN the current track is the last one in the queue
  • WHEN it finishes
  • THEN playback stops with no wraparound to the first track
  • AND handler state remains consistent for a subsequent, independent play action

Requirement: New Action Media-IDs Are Collision-Free

The media-ids for "Reproducir carpeta" and "Reproducir aleatorio" MUST use prefixes distinct from every existing media-id family: emisora:, grupo:, eq_preset:, carpeta_local:, carpeta_local_pag:, carpeta_local_ord:, carpeta_local_bucket:, pista:.

Scenario: Prefix uniqueness

  • GIVEN the full set of existing prefixes plus the two new action prefixes
  • WHEN each prefix is compared against every other
  • THEN none duplicates or substring-collides with another

Scenario: Raw documentIds with :// survive round-trip

  • GIVEN a folder's SAF documentId contains : or / characters
  • WHEN an action media-id is encoded and later decoded via playFromMediaId
  • THEN the original documentId is recovered verbatim, reusing the existing strip-by-length + split-on-first-colon codec

Out of Scope (explicit boundary — not requirements of this change)

  • Recursive whole-subtree queueing; only a folder's direct audio children are queued.
  • OS-level shuffle-mode toggle (AudioService.setShuffleMode); shuffle is exposed only as a browsable action.
  • Repeat modes.
  • Cross-folder, persisted, or resumable queues; queue-reordering UI.