fix(player): restore setUrl source loading
Build & Deploy Pluriwave / Análisis de código (push) Successful in 11s
Build & Deploy Pluriwave / Build APK + AAB release (push) Successful in 1m16s

This commit is contained in:
2026-05-21 00:57:41 +02:00
parent fe531a1784
commit 1791207bd4
2 changed files with 9 additions and 26 deletions
+8 -4
View File
@@ -6,17 +6,21 @@ Referencia interna para futuras correcciones del reproductor de PluriWave. Este
- `AudioPlayer.play()` **no debe esperarse como si fuera “arrancar y terminar”** en un stream de radio en vivo. Según la documentación de `just_audio`, el `Future` de `play()` completa cuando la reproducción termina, se pausa o se detiene. En una radio en vivo puede quedar vivo hasta que otra acción lo interrumpa. - `AudioPlayer.play()` **no debe esperarse como si fuera “arrancar y terminar”** en un stream de radio en vivo. Según la documentación de `just_audio`, el `Future` de `play()` completa cuando la reproducción termina, se pausa o se detiene. En una radio en vivo puede quedar vivo hasta que otra acción lo interrumpa.
- Para streams en vivo, la UI debe depender de `playerStateStream`: `loading`/`buffering` para spinner, `ready + playing` para estado en directo. - Para streams en vivo, la UI debe depender de `playerStateStream`: `loading`/`buffering` para spinner, `ready + playing` para estado en directo.
- El ejemplo de radio de `just_audio` configura `AudioSession` y escucha errores de playback. Conviene tratar el cambio de emisora como una operación transaccional: parar fuente anterior, asignar fuente nueva y arrancar sin bloquear el flujo principal. - El ejemplo de radio de `just_audio` configura sesión de audio y escucha errores de playback. Conviene tratar el cambio de emisora como una operación transaccional: parar fuente anterior, asignar fuente nueva y arrancar sin bloquear el flujo principal.
- En `audio_service`, si se cambia de fuente desde `playMediaItem`, hay que evitar que errores tardíos de la fuente anterior limpien la emisora nueva. Es una carrera típica cuando se hace `stop()` y enseguida se carga otro stream. - En `audio_service`, si se cambia de fuente desde `playMediaItem`, hay que evitar que errores tardíos de la fuente anterior limpien la emisora nueva. Es una carrera típica cuando se hace `stop()` y enseguida se carga otro stream.
## Decisión aplicada en PluriWave ## Decisión aplicada en PluriWave
- Serializar cambios de emisora con una cola interna. - Mantener `setUrl(...)` porque era la ruta que conectaba correctamente la primera emisora en esta app.
- Serializar cambios de emisora con una cola interna para que no se solapen `stop/setUrl/play`.
- Usar una revisión incremental para que solo la última solicitud pueda actualizar estado/errores. - Usar una revisión incremental para que solo la última solicitud pueda actualizar estado/errores.
- Usar `setAudioSource(..., preload: false)` y luego `play()` sin `await`, para que la carga de stream vivo no bloquee la operación. - Ejecutar `play()` sin `await`, porque en radios en vivo su `Future` no representa “ya arrancó”, sino “terminó/pausó/detuvo”.
- Ignorar errores emitidos durante la ventana de cambio de fuente, porque pueden pertenecer al stream anterior.
- Proteger `EstadoRadio.reproducir` con revisión para que una reproducción vieja que termine tarde no aplique presets/clicks encima de la emisora nueva. - Proteger `EstadoRadio.reproducir` con revisión para que una reproducción vieja que termine tarde no aplique presets/clicks encima de la emisora nueva.
## Intento descartado
- Se probó `setAudioSource(..., preload: false)` siguiendo una interpretación más transaccional del API, pero en PluriWave rompió incluso la primera conexión. Queda descartado salvo que se acompañe de logs nativos que justifiquen retomarlo.
## Fuentes consultadas ## Fuentes consultadas
- just_audio `AudioPlayer.play()` API: https://pub.dev/documentation/just_audio/latest/just_audio/AudioPlayer/play.html - just_audio `AudioPlayer.play()` API: https://pub.dev/documentation/just_audio/latest/just_audio/AudioPlayer/play.html
+1 -22
View File
@@ -1,7 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'dart:developer' as developer; import 'dart:developer' as developer;
import 'package:audio_session/audio_session.dart';
import 'package:audio_service/audio_service.dart'; import 'package:audio_service/audio_service.dart';
import 'package:just_audio/just_audio.dart'; import 'package:just_audio/just_audio.dart';
@@ -97,7 +96,6 @@ class PluriWaveAudioHandler extends BaseAudioHandler with SeekHandler {
final AndroidEqualizer _eq = AndroidEqualizer(); final AndroidEqualizer _eq = AndroidEqualizer();
late final AudioPlayer _player = AudioPlayer( late final AudioPlayer _player = AudioPlayer(
userAgent: 'PluriWave/0.1.0 (es.freetimelab.pluriwave)',
audioPipeline: AudioPipeline(androidAudioEffects: [_eq]), audioPipeline: AudioPipeline(androidAudioEffects: [_eq]),
); );
@@ -117,23 +115,9 @@ class PluriWaveAudioHandler extends BaseAudioHandler with SeekHandler {
bool _cambiandoFuente = false; bool _cambiandoFuente = false;
PluriWaveAudioHandler() { PluriWaveAudioHandler() {
unawaited(_configurarSesionAudio());
_setupStreams(); _setupStreams();
} }
Future<void> _configurarSesionAudio() async {
try {
final session = await AudioSession.instance;
await session.configure(const AudioSessionConfiguration.music());
} catch (e) {
developer.log(
'[PluriWave] No se pudo configurar AudioSession: $e',
name: 'ServicioAudio',
level: 800,
);
}
}
void _setupStreams() { void _setupStreams() {
_player.playerStateStream.listen((state) { _player.playerStateStream.listen((state) {
final playing = state.playing; final playing = state.playing;
@@ -268,12 +252,7 @@ class PluriWaveAudioHandler extends BaseAudioHandler with SeekHandler {
await _player.stop().timeout(_timeoutCambioFuente); await _player.stop().timeout(_timeoutCambioFuente);
if (revision != _revisionFuente) return; if (revision != _revisionFuente) return;
await _player await _player.setUrl(mediaItem.id).timeout(_timeoutCambioFuente);
.setAudioSource(
AudioSource.uri(Uri.parse(mediaItem.id), tag: mediaItem),
preload: false,
)
.timeout(_timeoutCambioFuente);
if (revision != _revisionFuente) return; if (revision != _revisionFuente) return;
await _activarEcualizador(); await _activarEcualizador();