Files
pluriwave/openspec/changes/archive/2026-07-10-eq-audiofocus-reapply/proposal.md
T
FreeTLab 0ab63731d0
Build & Deploy PluriWave / Análisis de código (push) Successful in 41s
Build & Deploy PluriWave / Build APK + AAB release (push) Successful in 2m33s
fix(eq): re-apply equalizer when the native audio session rotates
ExoPlayer assigns a new audio session id after transient audio-focus
interruptions (navigation prompts, radar warnings), leaving the
AndroidEqualizer attached to the dead session so playback resumed
without equalization until the next station switch. The session-id
listener now detects genuine rotations through a dedicated guard and
re-activates the equalizer with the current preset, gated on EQ
availability to stay clear of player teardown/rebuild.
2026-07-10 18:51:45 +02:00

3.7 KiB

Proposal: EQ Re-Apply After Audio-Focus Ducking

Intent

When another app interrupts playback (Radarbot warnings, Google Maps directions), the native Android audio session id rotates on the audio-focus transition. ExoPlayer orphans the effect attached to the dead session (documented upstream, issue #5302), so just_audio's AndroidEqualizer keeps its gain state but never re-pushes it to the new session. Music resumes flat/un-equalized. Re-attachment currently only fires on explicit station switch (_cambiarFuente -> _activarEcualizador, servicio_audio.dart:449/526). The user requires the music to ALWAYS stay equalized. This is Part B; disconnect-revert (Part A) is the separate eq-device-disconnect-revert change.

Scope

In Scope

  • Subscribe to androidAudioSessionIdStream inside PluriWaveAudioHandler for EQ purposes
  • On a changed + non-null session id, re-attach and re-push current gains via existing _activarEcualizador() / aplicarPreset(_presetActual)
  • Change-guard + _eqDisponible gate so it never re-fires redundantly nor races _recrearPlayer() teardown
  • New tests covering re-apply after session-id rotation, first-activation no-op, and teardown race

Out of Scope

  • Part A device disconnect/cold-start revert (eq-device-disconnect-revert)
  • Any ServicioAudioSession interruption/duck/pause logic change
  • EstadoEcualizador / multi-device toggle logic
  • Kotlin/platform-channel changes
  • VisualizadorAudio (reference pattern only)

Capabilities

New Capabilities

  • eq-audiofocus-reapply: Equalizer re-attaches and re-applies current gains whenever the native audio session id rotates mid-playback

Modified Capabilities

  • None (no existing equalizer spec)

Approach

Extend the existing _androidAudioSessionIdSub listener (servicio_audio.dart:258-265), which today only stores/broadcasts the id. After broadcast, if the id changed and is non-null AND _eqDisponible is true, call the idempotent choke-point to re-enable and re-write band gains for _presetActual. This mirrors VisualizadorAudio._onSessionId (visualizador_audio.dart:82-88) — the proven in-repo reaction pattern. The fix lives entirely below the multi-device layer (_eqMultiDeviceEnabled is an EstadoEcualizador concern, absent from this file), so it applies regardless of that toggle.

Affected Areas

Area Impact Description
lib/servicios/servicio_audio.dart Modified Add EQ re-apply to _androidAudioSessionIdSub listener
test/servicios/ New Session-id rotation re-apply + guard/race coverage

Risks

Risk Likelihood Mitigation
Redundant re-fire on first/legit activation Med Change-guard (== _lastSessionId return), mirrors visualizer
Race with _recrearPlayer() rebuild Med Gate on _eqDisponible == true; teardown sets it false + nulls id
Regress station-switch / manual slider path Low Different call sites unchanged; full flutter test regression

Rollback Plan

Change is a self-contained addition to one listener block plus new tests. Revert the commit to restore prior (broken) behavior — no persistence, schema, or API surface change, so no data migration or downstream impact.

Dependencies

  • None. androidAudioSessionIdStream, _activarEcualizador(), aplicarPreset() all already exist.

Success Criteria

  • After another app ducks/interrupts playback, resumed music stays equalized
  • EQ re-applies on every changed non-null session id, regardless of _eqMultiDeviceEnabled
  • No redundant re-apply on first activation or during _recrearPlayer() teardown
  • Station-switch and manual slider (setBanda) paths unchanged
  • All new behavior covered by passing tests (Strict TDD)