import 'dart:async'; import 'package:audio_session/audio_session.dart'; 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) { _setPlaybackStatus(_mapPlayerStateToStatus(state)); }); } final String streamUrl; final AudioPlayer _player = AudioPlayer(); late final StreamSubscription _playerStateSubscription; bool _isSourceLoaded = false; StreamingPlaybackStatus _playbackStatus = StreamingPlaybackStatus.stopped; bool _isAudioSessionConfigured = false; bool _playRequested = false; 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 _configureAudioSessionIfNeeded() async { if (_isAudioSessionConfigured) { return; } final session = await AudioSession.instance; await session.configure(const AudioSessionConfiguration.music()); _isAudioSessionConfigured = true; } Future play() async { _playRequested = true; await _configureAudioSessionIfNeeded(); _setPlaybackStatus(StreamingPlaybackStatus.buffering); 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; } final session = await AudioSession.instance; await session.setActive(true); await _player.play(); } catch (_) { _playRequested = false; _setPlaybackStatus(StreamingPlaybackStatus.stopped); rethrow; } } Future stop() async { _playRequested = false; _setPlaybackStatus(StreamingPlaybackStatus.stopped); await _player.stop(); } @override void dispose() { _playerStateSubscription.cancel(); _player.dispose(); super.dispose(); } }