adds buffering intermediate state
Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
+14
-3
@@ -58,6 +58,17 @@ class _MainPageState extends State<MainPage> {
|
||||
StreamingAudioBusinessObject get _audio => widget.audio;
|
||||
late final WebViewController _webViewController;
|
||||
|
||||
String _playbackStatusLabel() {
|
||||
switch (_audio.playbackStatus) {
|
||||
case StreamingPlaybackStatus.stopped:
|
||||
return 'Stopped';
|
||||
case StreamingPlaybackStatus.buffering:
|
||||
return 'Buffering...';
|
||||
case StreamingPlaybackStatus.playing:
|
||||
return 'Playing';
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
@@ -193,17 +204,17 @@ class _MainPageState extends State<MainPage> {
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
ElevatedButton(
|
||||
onPressed: _audio.isPlaying ? null : _play,
|
||||
onPressed: _audio.isStopped ? _play : null,
|
||||
child: const Text('▶️'),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
ElevatedButton(
|
||||
onPressed: _audio.isPlaying ? _stop : null,
|
||||
onPressed: _audio.isStopped ? null : _stop,
|
||||
child: const Text('⏹️'),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Text(
|
||||
_audio.isPlaying ? 'Playing' : 'Stopped',
|
||||
_playbackStatusLabel(),
|
||||
style: TextStyle(color: themeColors.statusText),
|
||||
),
|
||||
],
|
||||
|
||||
@@ -5,18 +5,14 @@ import 'package:flutter/foundation.dart';
|
||||
import 'package:just_audio_background/just_audio_background.dart';
|
||||
import 'package:just_audio/just_audio.dart';
|
||||
|
||||
enum StreamingPlaybackStatus { stopped, buffering, playing }
|
||||
|
||||
class StreamingAudioBusinessObject extends ChangeNotifier {
|
||||
StreamingAudioBusinessObject({
|
||||
this.streamUrl = 'https://kryz.out.airtime.pro/kryz_a',
|
||||
}) {
|
||||
_playerStateSubscription = _player.playerStateStream.listen((state) {
|
||||
final isCurrentlyPlaying =
|
||||
state.playing && state.processingState != ProcessingState.completed;
|
||||
|
||||
if (_isPlaying != isCurrentlyPlaying) {
|
||||
_isPlaying = isCurrentlyPlaying;
|
||||
notifyListeners();
|
||||
}
|
||||
_setPlaybackStatus(_mapPlayerStateToStatus(state));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -24,10 +20,43 @@ class StreamingAudioBusinessObject extends ChangeNotifier {
|
||||
final AudioPlayer _player = AudioPlayer();
|
||||
late final StreamSubscription<PlayerState> _playerStateSubscription;
|
||||
bool _isSourceLoaded = false;
|
||||
bool _isPlaying = false;
|
||||
StreamingPlaybackStatus _playbackStatus = StreamingPlaybackStatus.stopped;
|
||||
bool _isAudioSessionConfigured = false;
|
||||
bool _playRequested = false;
|
||||
|
||||
bool get isPlaying => _isPlaying;
|
||||
StreamingPlaybackStatus get playbackStatus => _playbackStatus;
|
||||
bool get isPlaying => _playbackStatus == StreamingPlaybackStatus.playing;
|
||||
bool get isBuffering => _playbackStatus == StreamingPlaybackStatus.buffering;
|
||||
bool get isStopped => _playbackStatus == StreamingPlaybackStatus.stopped;
|
||||
|
||||
StreamingPlaybackStatus _mapPlayerStateToStatus(PlayerState state) {
|
||||
if (state.processingState == ProcessingState.completed) {
|
||||
return StreamingPlaybackStatus.stopped;
|
||||
}
|
||||
|
||||
if (state.playing) {
|
||||
if (state.processingState == ProcessingState.ready) {
|
||||
return StreamingPlaybackStatus.playing;
|
||||
}
|
||||
|
||||
return StreamingPlaybackStatus.buffering;
|
||||
}
|
||||
|
||||
if (_playRequested && state.processingState != ProcessingState.completed) {
|
||||
return StreamingPlaybackStatus.buffering;
|
||||
}
|
||||
|
||||
return StreamingPlaybackStatus.stopped;
|
||||
}
|
||||
|
||||
void _setPlaybackStatus(StreamingPlaybackStatus status) {
|
||||
if (_playbackStatus == status) {
|
||||
return;
|
||||
}
|
||||
|
||||
_playbackStatus = status;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> _configureAudioSessionIfNeeded() async {
|
||||
if (_isAudioSessionConfigured) {
|
||||
@@ -40,29 +69,39 @@ class StreamingAudioBusinessObject extends ChangeNotifier {
|
||||
}
|
||||
|
||||
Future<void> play() async {
|
||||
_playRequested = true;
|
||||
await _configureAudioSessionIfNeeded();
|
||||
_setPlaybackStatus(StreamingPlaybackStatus.buffering);
|
||||
|
||||
if (!_isSourceLoaded) {
|
||||
await _player.setAudioSource(
|
||||
AudioSource.uri(
|
||||
Uri.parse(streamUrl),
|
||||
tag: const MediaItem(
|
||||
id: 'kryz-live-stream',
|
||||
title: 'KRYZ Live Stream',
|
||||
artist: 'KRYZ Radio',
|
||||
album: 'Live',
|
||||
try {
|
||||
if (!_isSourceLoaded) {
|
||||
await _player.setAudioSource(
|
||||
AudioSource.uri(
|
||||
Uri.parse(streamUrl),
|
||||
tag: const MediaItem(
|
||||
id: 'kryz-live-stream',
|
||||
title: 'KRYZ Live Stream',
|
||||
artist: 'KRYZ Radio',
|
||||
album: 'Live',
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
_isSourceLoaded = true;
|
||||
}
|
||||
);
|
||||
_isSourceLoaded = true;
|
||||
}
|
||||
|
||||
final session = await AudioSession.instance;
|
||||
await session.setActive(true);
|
||||
await _player.play();
|
||||
final session = await AudioSession.instance;
|
||||
await session.setActive(true);
|
||||
await _player.play();
|
||||
} catch (_) {
|
||||
_playRequested = false;
|
||||
_setPlaybackStatus(StreamingPlaybackStatus.stopped);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> stop() async {
|
||||
_playRequested = false;
|
||||
_setPlaybackStatus(StreamingPlaybackStatus.stopped);
|
||||
await _player.stop();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user