fix(alarm): anchor the fade at alarm time and defer the override to first audio
On-device logcat from the latest test showed two defects the previous design created. The fade-in was gated on the station reaching `reproduciendo`, and the stream took 18.7 seconds to buffer: the ring sat frozen at 5% the whole time and the configured fade seconds only started counting afterwards. And the stream override was raised during pre-start, so the ExoPlayer AudioTrack spin-up — which runs at gain 1.0 for an instant before the player gain lands — blasted at the configured ring level, heard as "starts directly at the alarm volume". The ramp is now anchored at alarm time: it starts when the screen starts, buffering just joins it at the elapsed level, and the fade duration means seconds-from-alarm. _iniciarFadeIn is single-start so the handoff confirmation and fallback paths can no longer restart an in-progress ramp from 5%. The stream override moved from the app-side pre-start into the screen and is raised only when audio is actually about to flow (first `reproduciendo`, the already-playing branch, or right before the fallback WAV plays), so track spin-up happens under the user's original low volume and the blast is physically impossible. Exit teardown restores the device stream before resetting the player gain, removing the brief exit blip seen in the capture.
This commit is contained in:
@@ -169,47 +169,35 @@ void main() {
|
||||
},
|
||||
);
|
||||
|
||||
group('fade-in dedup en el handoff (Slice 3)', () {
|
||||
testWidgets('el fade-in de Dart se retiene hasta que el nativo confirma el '
|
||||
'handoff, y arranca justo despues (camino radio)', (tester) async {
|
||||
group('rampa anclada y override diferido al primer audio', () {
|
||||
testWidgets('la rampa arranca al montar sin esperar al stream, y el '
|
||||
'override del volumen del dispositivo espera a "reproduciendo"',
|
||||
(tester) async {
|
||||
final entorno = await _montarPantalla(
|
||||
tester,
|
||||
audioYaReproduciendo: false,
|
||||
);
|
||||
entorno.android.puertaConfirmarAudioFlutter = Completer<void>();
|
||||
|
||||
// Antes de que la radio confirme "reproduciendo", solo debe existir
|
||||
// el volumen de arranque previo (0.05): el ramp real hacia
|
||||
// alarma.volumen todavia NO debe haber arrancado.
|
||||
// La rampa esta anclada al inicio de la alarma: con fade 0 salta ya al
|
||||
// objetivo (1.0) aunque el stream siga bufferizando. Lo que NO debe
|
||||
// haber ocurrido todavia es el override del stream del dispositivo
|
||||
// (el spin-up del reproductor debe pasar bajo el volumen original) ni
|
||||
// el stop nativo del handoff.
|
||||
expect(entorno.audio.volumenesAplicados, [0.05, 1.0]);
|
||||
expect(
|
||||
entorno.android.volumenForzado,
|
||||
isEmpty,
|
||||
reason: 'el override debe esperar a que el audio realmente fluya',
|
||||
);
|
||||
expect(entorno.android.detenidas, isEmpty);
|
||||
expect(entorno.audio.volumenesAplicados, [0.05]);
|
||||
|
||||
// La radio confirma que esta reproduciendo -> dispara
|
||||
// _confirmarAudioFlutterListo(), que queda bloqueado en la puerta
|
||||
// (todavia no hay confirmacion nativa real).
|
||||
// La radio llega a "reproduciendo": recien ahi se sube el stream al
|
||||
// nivel configurado y se confirma el handoff (stop nativo).
|
||||
entorno.audio.emitirEstado(EstadoReproduccion.reproduciendo);
|
||||
await tester.pumpAndSettle();
|
||||
expect(
|
||||
entorno.android.detenidas,
|
||||
isEmpty,
|
||||
reason: 'confirmarAudioFlutter sigue bloqueado en la puerta de prueba',
|
||||
);
|
||||
expect(
|
||||
entorno.audio.volumenesAplicados,
|
||||
[0.05],
|
||||
reason: 'el fade-in de Dart no debe arrancar antes del handoff',
|
||||
);
|
||||
|
||||
// Se libera la puerta: recien ahi "confirma" el nativo, y solo
|
||||
// entonces debe arrancar el fade-in de Dart (una unica rampa
|
||||
// audible a la vez).
|
||||
entorno.android.puertaConfirmarAudioFlutter!.complete();
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(entorno.android.volumenForzado, [0.85]);
|
||||
expect(entorno.android.detenidas, contains('ring1'));
|
||||
// Player ramps to its OWN full range (1.0); the configured level is
|
||||
// enforced by the media-stream cap, not by the player target.
|
||||
expect(entorno.audio.volumenesAplicados, [0.05, 1.0]);
|
||||
});
|
||||
|
||||
testWidgets('si confirmar el audio con el nativo falla, el fade-in de Dart '
|
||||
|
||||
Reference in New Issue
Block a user