In-progress artifact sets from the current SDD cycles: exploration, proposal, spec, design, tasks, and verify reports as produced so far. Also drops a leftover working copy of eq-device-disconnect-revert whose contents were already committed under changes/archive/.
41 lines
4.2 KiB
Markdown
41 lines
4.2 KiB
Markdown
# Exploration: alarm-volume-ramp-restore
|
|
|
|
## Current State — dual-track handoff architecture (by design)
|
|
|
|
Alarm audio is a deliberate handoff (documented in `app-quality-and-native-alarms/design.md` Decision 1.5, `docs/alarmas-pantalla-apagada.md`):
|
|
|
|
1. **Native track**: `PluriWaveAlarmReceiver(ACTION_FIRE)` → `PluriWaveAlarmService.kt` plays via `MediaPlayer` with `AudioAttributes.USAGE_ALARM` (L350-354) — Android ALARM stream, immune to media-volume-0 by OS design. Has a working fade-in (`startFadeIn`, `FADE_IN_START_FRACTION = 0.05f`, 250ms steps).
|
|
2. **Flutter track**: `app.dart` `_prearrancarAudioAlarma()` starts the regular radio player (`PluriWaveAudioHandler`/just_audio) at volume 0.05; `pantalla_alarma_sonando.dart` `_iniciarFadeIn()` ramps it 0.05 → `alarma.volumen`. Uses `AudioSessionConfiguration.music()` — normal media session, fully subject to device media volume.
|
|
3. **Handoff**: when the Flutter player reaches `reproduciendo`, `confirmarAudioFlutter` → `MainActivity` → `PluriWaveAlarmService.stop()`. Native audio torn down; Flutter media-stream player is the sole source for the rest of the ring.
|
|
|
|
Grep-verified: **zero occurrences of `setStreamVolume`/AudioManager volume-override anywhere in the codebase, ever** — the app has never programmatically overridden device stream volume. The "used to ignore device volume" impression comes from the native track's brief immune window, not a regressed capability.
|
|
|
|
## Root Causes
|
|
|
|
**A — architectural**: steady-state alarm audio is the Flutter media-stream player within 1-3s of firing. Media volume 0 → silent alarm (symptom 2).
|
|
|
|
**B — manifest bug (verified)**: `AndroidManifest.xml:55-58` declares `foregroundServiceType="mediaPlayback|systemExempted"` and NO `FOREGROUND_SERVICE_ALARM` permission — contradicting the approved design (`app-quality-and-native-alarms` design.md Decision 1.1, spec S1-R1 CRITICAL, which mandates `mediaPlayback|alarm` + permission to prevent `ForegroundServiceTypeException` on Android 14+ when starting from a broadcast receiver). `apply-progress.md` marks T-S1-03/04 done with "DEVIATION (see below)" but no Batch-1 deviation section exists. On Android 14+ this plausibly kills the native service start silently — removing even the brief volume-immune window.
|
|
|
|
**C — double fade-in**: native Kotlin ramp and Dart ramp run independently and can interleave at handoff → audible jump/reset (likely the real cause of "feels broken", symptom 1).
|
|
|
|
## Recommendation (sequenced, one change)
|
|
|
|
1. **Manifest fix**: restore `mediaPlayback|alarm` + `FOREGROUND_SERVICE_ALARM` per the already-approved design. Near-zero risk.
|
|
2. **Ring-scoped volume immunity (option c)**: at ring start, capture current media-stream volume; force it to an audible reference; ramp PLAYER volume 5% → `alarma.volumen`; restore original stream volume on stop/snooze/dismiss. Scoped strictly to the ring — must not touch normal radio listening.
|
|
3. **Fade-in dedup**: gate so only one ramp drives audible volume across the handoff.
|
|
|
|
Deferred (flagged as follow-up, not bundled): option (b) — native-only audio for the whole ring (Flutter screen as pure UI). Architecturally purest, but a large rewrite across `pantalla_alarma_sonando.dart`, `PluriWaveAlarmService.kt`, and the MethodChannel surface.
|
|
|
|
## Affected Areas
|
|
- `AndroidManifest.xml:56-58` — FGS type + missing permission (CRITICAL on API 34+)
|
|
- `PluriWaveAlarmService.kt` — native fade-in OK for its scope; handoff teardown
|
|
- `lib/servicios/servicio_audio.dart` — steady-state alarm source, no alarm-stream routing
|
|
- `lib/pantallas/pantalla_alarma_sonando.dart` — Dart ramp; double-ramp at handoff
|
|
- `lib/app.dart` — `_prearrancarAudioAlarma()` shrinks the immune window
|
|
- `app-quality-and-native-alarms/apply-progress.md` — missing Batch-1 deviation note (doc gap)
|
|
|
|
## Risks
|
|
- Kotlin/manifest edits cannot be compiled by agents (`flutter build` forbidden) — mandatory on-device verification by the user (this exact gap is how the manifest regression slipped through)
|
|
- Any audio-session/volume change must be provably scoped to the ring and reverted — must not regress phone-call ducking (`ServicioAudioSession`, S3-R1) or normal listening
|
|
- Native and Dart fade-ins duplicate the same algorithm/constants — flag for single-sourcing to prevent drift
|