From 898922efd1576327b29452cb4259adb74ced5fbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leon=20B=C3=B6sche?= Date: Sat, 17 Jan 2026 03:40:56 +0100 Subject: [PATCH] Refactor audio player to manage subscriptions more effectively and ensure proper cleanup --- .../lib/widgets/web_audio_player.dart | 58 ++++++++++++++----- 1 file changed, 45 insertions(+), 13 deletions(-) diff --git a/b0esche_cloud/lib/widgets/web_audio_player.dart b/b0esche_cloud/lib/widgets/web_audio_player.dart index c24d11e..58f0eab 100644 --- a/b0esche_cloud/lib/widgets/web_audio_player.dart +++ b/b0esche_cloud/lib/widgets/web_audio_player.dart @@ -12,43 +12,74 @@ class AudioPlayer { final StreamController _errorController = StreamController.broadcast(); + // Store subscriptions for cleanup + StreamSubscription? _durationSubscription; + StreamSubscription? _positionSubscription; + StreamSubscription? _playSubscription; + StreamSubscription? _pauseSubscription; + StreamSubscription? _endedSubscription; + StreamSubscription? _errorSubscription; + Stream get positionStream => _positionController.stream; Stream get durationStream => _durationController.stream; Stream get playingStream => _playingController.stream; Stream 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 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();