fix(reproduccion): robustez HTTP cleartext, errores ExoPlayer y certificados SSL
Some checks failed
Flutter CI/CD — PluriWave / Test + Build (pull_request) Has been cancelled
Some checks failed
Flutter CI/CD — PluriWave / Test + Build (pull_request) Has been cancelled
**Fix 1 — HTTP cleartext (streams sin HTTPS):** - Añadir android/app/src/main/res/xml/network_security_config.xml con cleartextTrafficPermitted=true para permitir streams de radio HTTP - Referenciar en AndroidManifest.xml con android:networkSecurityConfig - Resuelve: 'Cleartext HTTP traffic to [host] not permitted' en ExoPlayer - Radio Paradise (Dance Wave, HTTP) y otras radios HTTP funcionan ahora **Fix 2 — Gestión de error TYPE_SOURCE y todos los PlaybackException:** - Añadir listener en playbackEventStream.onError en PluriWaveAudioHandler - _gestionarErrorReproduccion() emite AudioProcessingState.error al UI, loggea el error y resetea el player a estado idle limpio - _mensajeAmigable() traduce códigos ERROR_CODE_IO_*, ERROR_CODE_PARSING_*, ERROR_CODE_DECODING_* y mensajes de Cleartext/HandshakeException a texto legible - EstadoRadio.reproducir() captura la excepción y cancela el timer si estaba activo - EstadoRadio escucha el estadoStream y cancela timer ante cualquier error **Fix 3 — Artwork con certificado autofirmado:** - errorWidget en CachedNetworkImage captura HandshakeException silenciosamente - Muestra _iconoFallback (icono de radio) en lugar de imagen rota - El error de artwork no se propaga ni interrumpe la reproducción **Fix 4 — UI consistente en estado de error:** - PantallaReproductor._Controles muestra mensaje + botón Reintentar en error - PantallaReproductor._Artwork muestra overlay wifi_off en estado de error - MiniReproductor muestra botón refresh (reintentar) en estado de error - EstadoReproduccion.error ya estaba definido; ahora el estadoStream lo emite - Timer cancelado automáticamente cuando la reproducción falla - Test de smoke corregido (boilerplate MyApp → placeholder válido) Fixes: cleartext HTTP, cert autofirmado, ExoPlayer TYPE_SOURCE, UI inconsistente
This commit is contained in:
@@ -39,6 +39,21 @@ class EstadoRadio extends ChangeNotifier {
|
||||
EstadoRadio() {
|
||||
timer = ServicioTimer(audio);
|
||||
_init();
|
||||
_escucharErroresReproduccion();
|
||||
}
|
||||
|
||||
/// Escucha el stream de estado del audio y gestiona errores de reproducción
|
||||
/// de forma centralizada: cancela el timer y notifica al usuario.
|
||||
void _escucharErroresReproduccion() {
|
||||
audio.estadoStream.listen((estado) {
|
||||
if (estado == EstadoReproduccion.error) {
|
||||
// Cancelar el timer si estaba activo — no debe contar sin audio
|
||||
if (timer.activo) {
|
||||
timer.cancelar();
|
||||
}
|
||||
notifyListeners();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
List<Emisora> get populares => _populares;
|
||||
@@ -119,7 +134,19 @@ class EstadoRadio extends ChangeNotifier {
|
||||
await cambiarPresetEcualizador(preset, guardPorEmisora: false);
|
||||
notifyListeners();
|
||||
} catch (e) {
|
||||
_errorController.add('No se puede reproducir "${emisora.nombre}"');
|
||||
// La reproducción falló: cancelar el timer para evitar estado inconsistente
|
||||
// (el timer no debe contar si no hay audio reproduciéndose)
|
||||
if (timer.activo) {
|
||||
timer.cancelar();
|
||||
}
|
||||
// Emitir mensaje claro al usuario con el nombre de la emisora
|
||||
final mensajeError = e.toString().replaceFirst('Exception: ', '');
|
||||
_errorController.add(
|
||||
mensajeError.isNotEmpty && mensajeError != 'Exception'
|
||||
? mensajeError
|
||||
: 'No se puede reproducir "${emisora.nombre}"',
|
||||
);
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user