feat(player): add radio recording and real waveform
This commit is contained in:
@@ -22,7 +22,10 @@ void registrarHandler(PluriWaveAudioHandler handler) {
|
||||
/// Wrapper de alto nivel para el UI.
|
||||
class ServicioAudio {
|
||||
PluriWaveAudioHandler get _handler {
|
||||
assert(_handlerGlobal != null, 'registrarHandler() no fue llamado en main.dart');
|
||||
assert(
|
||||
_handlerGlobal != null,
|
||||
'registrarHandler() no fue llamado en main.dart',
|
||||
);
|
||||
return _handlerGlobal!;
|
||||
}
|
||||
|
||||
@@ -50,9 +53,10 @@ class ServicioAudio {
|
||||
title: emisora.nombre,
|
||||
artist: emisora.pais ?? '',
|
||||
album: 'PluriWave',
|
||||
artUri: emisora.favicon != null && emisora.favicon!.isNotEmpty
|
||||
? Uri.tryParse(emisora.favicon!)
|
||||
: null,
|
||||
artUri:
|
||||
emisora.favicon != null && emisora.favicon!.isNotEmpty
|
||||
? Uri.tryParse(emisora.favicon!)
|
||||
: null,
|
||||
extras: {'uuid': emisora.uuid},
|
||||
);
|
||||
await _handler.playMediaItem(item);
|
||||
@@ -73,6 +77,8 @@ class ServicioAudio {
|
||||
Future<void> setVolumen(double vol) => _handler.setVolumen(vol);
|
||||
double get volumen => _handler.volumen;
|
||||
bool get estaSonando => _handler.playbackState.value.playing;
|
||||
Stream<int?> get androidAudioSessionIdStream =>
|
||||
_handler.androidAudioSessionIdStream;
|
||||
Future<void> dispose() async {}
|
||||
|
||||
// ── Ecualizador ───────────────────────────────────────────────────────────
|
||||
@@ -83,8 +89,7 @@ class ServicioAudio {
|
||||
Future<void> aplicarPreset(PresetEcualizador preset) =>
|
||||
_handler.aplicarPreset(preset);
|
||||
|
||||
Future<void> setBanda(int index, double db) =>
|
||||
_handler.setBanda(index, db);
|
||||
Future<void> setBanda(int index, double db) => _handler.setBanda(index, db);
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
@@ -99,6 +104,8 @@ class PluriWaveAudioHandler extends BaseAudioHandler with SeekHandler {
|
||||
StreamSubscription<PlayerState>? _estadoPlayerSub;
|
||||
StreamSubscription<Duration>? _bufferedSub;
|
||||
StreamSubscription<PlaybackEvent>? _eventosSub;
|
||||
StreamSubscription<int?>? _androidAudioSessionIdSub;
|
||||
final _androidAudioSessionIdController = StreamController<int?>.broadcast();
|
||||
Future<void> _colaCambioFuente = Future<void>.value();
|
||||
int _revisionFuente = 0;
|
||||
|
||||
@@ -112,6 +119,8 @@ class PluriWaveAudioHandler extends BaseAudioHandler with SeekHandler {
|
||||
|
||||
PresetEcualizador _presetActual = PresetEcualizador.flat;
|
||||
PresetEcualizador get presetActual => _presetActual;
|
||||
Stream<int?> get androidAudioSessionIdStream =>
|
||||
_androidAudioSessionIdController.stream;
|
||||
|
||||
PluriWaveAudioHandler() {
|
||||
_conectarStreamsPlayer();
|
||||
@@ -127,18 +136,20 @@ class PluriWaveAudioHandler extends BaseAudioHandler with SeekHandler {
|
||||
_estadoPlayerSub = _player.playerStateStream.listen((state) {
|
||||
final playing = state.playing;
|
||||
final proc = state.processingState;
|
||||
playbackState.add(playbackState.value.copyWith(
|
||||
controls: [
|
||||
if (playing) MediaControl.pause else MediaControl.play,
|
||||
MediaControl.stop,
|
||||
],
|
||||
systemActions: const {MediaAction.seek, MediaAction.stop},
|
||||
androidCompactActionIndices: const [0],
|
||||
processingState: _mapProcState(proc),
|
||||
playing: playing,
|
||||
bufferedPosition: _player.bufferedPosition,
|
||||
speed: _player.speed,
|
||||
));
|
||||
playbackState.add(
|
||||
playbackState.value.copyWith(
|
||||
controls: [
|
||||
if (playing) MediaControl.pause else MediaControl.play,
|
||||
MediaControl.stop,
|
||||
],
|
||||
systemActions: const {MediaAction.seek, MediaAction.stop},
|
||||
androidCompactActionIndices: const [0],
|
||||
processingState: _mapProcState(proc),
|
||||
playing: playing,
|
||||
bufferedPosition: _player.bufferedPosition,
|
||||
speed: _player.speed,
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
_bufferedSub = _player.bufferedPositionStream.listen((pos) {
|
||||
@@ -151,6 +162,14 @@ class PluriWaveAudioHandler extends BaseAudioHandler with SeekHandler {
|
||||
_gestionarErrorReproduccion(error);
|
||||
},
|
||||
);
|
||||
|
||||
_androidAudioSessionIdSub = _player.androidAudioSessionIdStream.listen((
|
||||
sessionId,
|
||||
) {
|
||||
if (!_androidAudioSessionIdController.isClosed) {
|
||||
_androidAudioSessionIdController.add(sessionId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Gestiona cualquier error de reproducción de ExoPlayer.
|
||||
@@ -172,11 +191,13 @@ class PluriWaveAudioHandler extends BaseAudioHandler with SeekHandler {
|
||||
level: 900,
|
||||
);
|
||||
|
||||
playbackState.add(playbackState.value.copyWith(
|
||||
processingState: AudioProcessingState.error,
|
||||
playing: false,
|
||||
errorMessage: mensaje,
|
||||
));
|
||||
playbackState.add(
|
||||
playbackState.value.copyWith(
|
||||
processingState: AudioProcessingState.error,
|
||||
playing: false,
|
||||
errorMessage: mensaje,
|
||||
),
|
||||
);
|
||||
emisoraActual = null;
|
||||
mediaItem.add(null);
|
||||
|
||||
@@ -236,11 +257,13 @@ class PluriWaveAudioHandler extends BaseAudioHandler with SeekHandler {
|
||||
Future<void> _cambiarFuente(MediaItem mediaItem, int revision) async {
|
||||
this.mediaItem.add(mediaItem);
|
||||
emisoraActual = _emisoraDesdeMediaItem(mediaItem);
|
||||
playbackState.add(playbackState.value.copyWith(
|
||||
processingState: AudioProcessingState.loading,
|
||||
playing: false,
|
||||
errorMessage: null,
|
||||
));
|
||||
playbackState.add(
|
||||
playbackState.value.copyWith(
|
||||
processingState: AudioProcessingState.loading,
|
||||
playing: false,
|
||||
errorMessage: null,
|
||||
),
|
||||
);
|
||||
try {
|
||||
await _recrearPlayer();
|
||||
if (revision != _revisionFuente) return;
|
||||
@@ -263,11 +286,13 @@ class PluriWaveAudioHandler extends BaseAudioHandler with SeekHandler {
|
||||
stackTrace: stackTrace,
|
||||
);
|
||||
if (revision == _revisionFuente) {
|
||||
playbackState.add(playbackState.value.copyWith(
|
||||
processingState: AudioProcessingState.error,
|
||||
playing: false,
|
||||
errorMessage: 'Error inesperado al reproducir',
|
||||
));
|
||||
playbackState.add(
|
||||
playbackState.value.copyWith(
|
||||
processingState: AudioProcessingState.error,
|
||||
playing: false,
|
||||
errorMessage: 'Error inesperado al reproducir',
|
||||
),
|
||||
);
|
||||
emisoraActual = null;
|
||||
this.mediaItem.add(null);
|
||||
}
|
||||
@@ -279,6 +304,7 @@ class PluriWaveAudioHandler extends BaseAudioHandler with SeekHandler {
|
||||
await _estadoPlayerSub?.cancel();
|
||||
await _bufferedSub?.cancel();
|
||||
await _eventosSub?.cancel();
|
||||
await _androidAudioSessionIdSub?.cancel();
|
||||
|
||||
final anterior = _player;
|
||||
try {
|
||||
@@ -330,7 +356,11 @@ class PluriWaveAudioHandler extends BaseAudioHandler with SeekHandler {
|
||||
if (!_eqDisponible) return;
|
||||
try {
|
||||
final params = await _eq.parameters;
|
||||
for (int i = 0; i < params.bands.length && i < preset.bandas.length; i++) {
|
||||
for (
|
||||
int i = 0;
|
||||
i < params.bands.length && i < preset.bandas.length;
|
||||
i++
|
||||
) {
|
||||
await params.bands[i].setGain(preset.bandas[i]);
|
||||
}
|
||||
} catch (_) {}
|
||||
@@ -381,7 +411,9 @@ class PluriWaveAudioHandler extends BaseAudioHandler with SeekHandler {
|
||||
await _estadoPlayerSub?.cancel();
|
||||
await _bufferedSub?.cancel();
|
||||
await _eventosSub?.cancel();
|
||||
await _androidAudioSessionIdSub?.cancel();
|
||||
await _player.dispose();
|
||||
await _androidAudioSessionIdController.close();
|
||||
}
|
||||
|
||||
Emisora _emisoraDesdeMediaItem(MediaItem mediaItem) {
|
||||
|
||||
Reference in New Issue
Block a user