Refactor audio player to manage subscriptions more effectively and ensure proper cleanup
This commit is contained in:
@@ -12,43 +12,74 @@ class AudioPlayer {
|
||||
final StreamController<String> _errorController =
|
||||
StreamController<String>.broadcast();
|
||||
|
||||
// Store subscriptions for cleanup
|
||||
StreamSubscription? _durationSubscription;
|
||||
StreamSubscription? _positionSubscription;
|
||||
StreamSubscription? _playSubscription;
|
||||
StreamSubscription? _pauseSubscription;
|
||||
StreamSubscription? _endedSubscription;
|
||||
StreamSubscription? _errorSubscription;
|
||||
|
||||
Stream<Duration> get positionStream => _positionController.stream;
|
||||
Stream<Duration> get durationStream => _durationController.stream;
|
||||
Stream<bool> get playingStream => _playingController.stream;
|
||||
Stream<String> get errorStream => _errorController.stream;
|
||||
|
||||
void _disposeSubscriptions() {
|
||||
_durationSubscription?.cancel();
|
||||
_positionSubscription?.cancel();
|
||||
_playSubscription?.cancel();
|
||||
_pauseSubscription?.cancel();
|
||||
_endedSubscription?.cancel();
|
||||
_errorSubscription?.cancel();
|
||||
|
||||
_durationSubscription = null;
|
||||
_positionSubscription = null;
|
||||
_playSubscription = null;
|
||||
_pauseSubscription = null;
|
||||
_endedSubscription = null;
|
||||
_errorSubscription = null;
|
||||
}
|
||||
|
||||
Future<void> setUrl(String url) async {
|
||||
// Clean up any existing subscriptions
|
||||
_disposeSubscriptions();
|
||||
|
||||
try {
|
||||
_audioElement = web.HTMLAudioElement();
|
||||
_audioElement!.src = url;
|
||||
_audioElement!.crossOrigin = 'anonymous'; // Handle CORS
|
||||
|
||||
// Set up event listeners
|
||||
_audioElement!.onLoadedMetadata.listen((_) {
|
||||
_durationController.add(
|
||||
Duration(milliseconds: (_audioElement!.duration * 1000).toInt()),
|
||||
);
|
||||
// Set up event listeners and store subscriptions
|
||||
_durationSubscription = _audioElement!.onLoadedMetadata.listen((_) {
|
||||
if (_audioElement != null) {
|
||||
_durationController.add(
|
||||
Duration(milliseconds: (_audioElement!.duration * 1000).toInt()),
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
_audioElement!.onTimeUpdate.listen((_) {
|
||||
_positionController.add(
|
||||
Duration(milliseconds: (_audioElement!.currentTime * 1000).toInt()),
|
||||
);
|
||||
_positionSubscription = _audioElement!.onTimeUpdate.listen((_) {
|
||||
if (_audioElement != null) {
|
||||
_positionController.add(
|
||||
Duration(milliseconds: (_audioElement!.currentTime * 1000).toInt()),
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
_audioElement!.onPlay.listen((_) {
|
||||
_playSubscription = _audioElement!.onPlay.listen((_) {
|
||||
_playingController.add(true);
|
||||
});
|
||||
|
||||
_audioElement!.onPause.listen((_) {
|
||||
_pauseSubscription = _audioElement!.onPause.listen((_) {
|
||||
_playingController.add(false);
|
||||
});
|
||||
|
||||
_audioElement!.onEnded.listen((_) {
|
||||
_endedSubscription = _audioElement!.onEnded.listen((_) {
|
||||
_playingController.add(false);
|
||||
});
|
||||
|
||||
_audioElement!.onError.listen((_) {
|
||||
_errorSubscription = _audioElement!.onError.listen((_) {
|
||||
_errorController.add('Failed to load audio');
|
||||
});
|
||||
|
||||
@@ -82,6 +113,7 @@ class AudioPlayer {
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
_disposeSubscriptions();
|
||||
_audioElement?.pause();
|
||||
_audioElement = null;
|
||||
_positionController.close();
|
||||
|
||||
Reference in New Issue
Block a user