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.
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
androidAudioSessionIdStreaminsidePluriWaveAudioHandlerfor EQ purposes - On a changed + non-null session id, re-attach and re-push current gains via existing
_activarEcualizador()/aplicarPreset(_presetActual) - Change-guard +
_eqDisponiblegate 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
ServicioAudioSessioninterruption/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)