feat(streaming): buffer resilience and automatic reconnection
- Construct the audio player with an enlarged live-stream buffer (15-50s forward cushion, 2.5s to start, 5s after rebuffer) so short network drops play through silently - Add reconnect-on-stall state machine with bounded exponential backoff (1/2/4/8/16s, ~90s total window, 5 attempts) that re-prepares to the live edge; backoff/decision logic extracted to controlador_reconexion.dart as pure testable code - Surface a new reconnecting playback state in the mini player and full player (localized in all 13 locales) instead of error dialogs during the retry window; a single friendly error appears only after exhaustion - Guard interplay: user pause/stop cancels retries, audio interruptions cancel reconnect, alarm wake-up path keeps precedence, recording fails cleanly during drops - Reset retry budget on station change; route stream timeouts through the network-error class - 10 new tests (99 total green), flutter analyze clean
This commit is contained in:
@@ -155,7 +155,10 @@ class _MiniReproductorState extends State<MiniReproductor> {
|
||||
stream: estado.estadoStream,
|
||||
builder: (context, snapshot) {
|
||||
final s = snapshot.data ?? EstadoReproduccion.detenido;
|
||||
if (s == EstadoReproduccion.cargando) {
|
||||
// S7-R3: reconectando is a transient stall — render it like
|
||||
// cargando (spinner), never as the error/retry affordance.
|
||||
if (s == EstadoReproduccion.cargando ||
|
||||
s == EstadoReproduccion.reconectando) {
|
||||
return const SizedBox(
|
||||
width: 48,
|
||||
height: 48,
|
||||
@@ -220,6 +223,7 @@ class _MiniReproductorState extends State<MiniReproductor> {
|
||||
EstadoReproduccion.cargando => l10n.playbackStatusConnecting,
|
||||
EstadoReproduccion.reproduciendo => l10n.playbackStatusLive,
|
||||
EstadoReproduccion.pausado => l10n.playbackStatusPaused,
|
||||
EstadoReproduccion.reconectando => l10n.playbackStatusReconnecting,
|
||||
EstadoReproduccion.error => l10n.playbackStatusConnectionError,
|
||||
EstadoReproduccion.detenido => l10n.playbackStatusStopped,
|
||||
};
|
||||
|
||||
@@ -68,7 +68,8 @@ class _VisualizadorAudioState extends State<VisualizadorAudio>
|
||||
void _onEstado(EstadoReproduccion estado) {
|
||||
final nuevoActivo =
|
||||
estado == EstadoReproduccion.reproduciendo ||
|
||||
estado == EstadoReproduccion.cargando;
|
||||
estado == EstadoReproduccion.cargando ||
|
||||
estado == EstadoReproduccion.reconectando;
|
||||
if (!mounted) return;
|
||||
if (nuevoActivo != _activo) {
|
||||
setState(() => _activo = nuevoActivo);
|
||||
|
||||
Reference in New Issue
Block a user