# 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)