Files
kryz-go-flutter/lib/streaming_audio_business_object.dart
T

116 lines
3.3 KiB
Dart

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<PlayerState> _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<void> _configureAudioSessionIfNeeded() async {
if (_isAudioSessionConfigured) {
return;
}
final session = await AudioSession.instance;
await session.configure(const AudioSessionConfiguration.music());
_isAudioSessionConfigured = true;
}
Future<void> 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<void> stop() async {
_playRequested = false;
_isSourceLoaded = false;
_setPlaybackStatus(StreamingPlaybackStatus.stopped);
await _player.stop();
}
@override
void dispose() {
_playerStateSubscription.cancel();
_player.dispose();
super.dispose();
}
}