From 6cb1167a21e4f3ba51b37b20096914da65c229a0 Mon Sep 17 00:00:00 2001 From: lxh2875931338 Date: Thu, 27 Aug 2026 23:18:40 +0800 Subject: [PATCH] =?UTF-8?q?=E9=A1=BA=E5=BA=8F=E6=92=AD=E6=94=BE=E8=B7=B3?= =?UTF-8?q?=E6=9B=B2=E4=B8=8E=E9=A6=96=E6=AC=A1=E5=90=AF=E5=8A=A8=E8=B7=B3?= =?UTF-8?q?=E6=9B=B2=E9=97=AE=E9=A2=98=E5=B7=B2=E9=83=A8=E5=88=86=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=EF=BC=8C=E6=92=AD=E6=94=BE=E9=80=BB=E8=BE=91=E6=AD=A3?= =?UTF-8?q?=E7=A1=AE=EF=BC=8Cmetadata=E9=83=A8=E5=88=86=E4=BB=8D=E9=9C=80?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/services/audio_service.dart | 183 +++++++++++++++++++++++++------- 1 file changed, 143 insertions(+), 40 deletions(-) diff --git a/lib/services/audio_service.dart b/lib/services/audio_service.dart index 8be63c5..3d21d1b 100644 --- a/lib/services/audio_service.dart +++ b/lib/services/audio_service.dart @@ -62,14 +62,17 @@ class AudioService extends ChangeNotifier { bool _listening = false; final List _subscriptions = []; + // ---- 播放生命周期标志 ---- bool _handlingCompletion = false; - void Function(Song)? _onSongChanged; - + bool _isChangingTrack = false; + bool _hasStartedCurrentPlayback = false; bool _isUserSeeking = false; // ⭐ 播放代数:每次切歌递增,用于校验异步任务是否过期 int _playbackGeneration = 0; + void Function(Song)? _onSongChanged; + // ---- Repository ---- final SongDatabase _db = SongDatabase(); final PlaylistRepository _playlistRepo = PlaylistRepository(); @@ -123,7 +126,7 @@ class AudioService extends ChangeNotifier { } // ---- 设置播放队列 ---- - void setQueue(List queue, {int startIndex = 0}) { + Future setQueue(List queue, {int startIndex = 0}) async { if (queue.isEmpty) { _clearQueue(); return; @@ -132,15 +135,20 @@ class AudioService extends ChangeNotifier { _queue = List.from(queue); _currentIndex = startIndex.clamp(0, _queue.length - 1); - _shuffledIndices = List.generate(_queue.length, (i) => i); - _shuffledIndices.shuffle(); - _shuffledIndex = _shuffledIndices.indexOf(_currentIndex); - if (_shuffledIndex == -1) { - _shuffledIndex = 0; - _currentIndex = _shuffledIndices[0]; + if (_playMode == PlayMode.shuffle) { + _shuffledIndices = List.generate(_queue.length, (i) => i); + _shuffledIndices.shuffle(); + _shuffledIndex = _shuffledIndices.indexOf(_currentIndex); + if (_shuffledIndex == -1) { + _shuffledIndex = 0; + _currentIndex = _shuffledIndices[0]; + } + } else { + _shuffledIndices = List.generate(_queue.length, (i) => i); + _shuffledIndex = _currentIndex; } - _playCurrent(); + await _playCurrent(); } void _clearQueue() { @@ -156,9 +164,9 @@ class AudioService extends ChangeNotifier { Future playSong(Song song) async { _currentPlaylistId = null; if (_queue.isEmpty || _queue[_currentIndex].id != song.id) { - setQueue([song], startIndex: 0); + await setQueue([song], startIndex: 0); } else { - _playCurrent(); + await _playCurrent(); } } @@ -198,7 +206,7 @@ class AudioService extends ChangeNotifier { } if (songs.isNotEmpty) { - setQueue(songs, startIndex: startIndex); + await setQueue(songs, startIndex: startIndex); } } @@ -212,35 +220,81 @@ class AudioService extends ChangeNotifier { } // ════════════════════════════════════════════════════════════ - // ⭐ 播放核心(修复:自动添加认证头) + // ⭐ 播放核心(完整生命周期控制) // ════════════════════════════════════════════════════════════ - void _playCurrent() { + Future _playCurrent() async { + if (_isChangingTrack) { + debugPrint('⚠️ [AudioService] track switch already running'); + return; + } + if (_currentIndex < 0 || _currentIndex >= _queue.length) { stopPlay(); return; } - _playbackGeneration++; - final generation = _playbackGeneration; + // ⭐ 进入切歌状态 + _isChangingTrack = true; + _handlingCompletion = false; + _hasStartedCurrentPlayback = false; - final song = _queue[_currentIndex]; - _currentSong = song; + try { + _playbackGeneration++; + final generation = _playbackGeneration; - _startListening(); - notifyListeners(); + final song = _queue[_currentIndex]; + _currentSong = song; - if (song.url == null || song.url!.isEmpty) { + _startListening(); + notifyListeners(); + + if (song.url == null || song.url!.isEmpty) { + return; + } + + // ⭐ 关键:等待播放器加载完成 + await _playWithHeaders(song.url!); + + // ⭐ 等待播放真正开始 + await _waitForPlaybackStarted(); + + _syncPlayerStateDelayed(); + + // ⭐ 只有真正开始播放后才推送通知 + if (_hasStartedCurrentPlayback) { + _onSongChanged?.call(song); + _loadMetadataForCurrentSong(generation); + } + } finally { + _isChangingTrack = false; + } + } + + /// ⭐ 等待播放器真正开始播放 + Future _waitForPlaybackStarted() async { + final player = PlaybackService().player; + + // 如果已经在播放,直接标记 + if (player.state.playing) { + _hasStartedCurrentPlayback = true; + debugPrint('🎵 [AudioService] playback already started'); return; } - // ⭐ 关键修复:播放时自动添加认证头 - _playWithHeaders(song.url!); - - _syncPlayerStateDelayed(); - - _onSongChanged?.call(song); - _loadMetadataForCurrentSong(generation); + // 等待 playing 变为 true,超时 3 秒 + try { + await player.stream.playing + .where((playing) => playing == true) + .first + .timeout(const Duration(seconds: 3)); + _hasStartedCurrentPlayback = true; + debugPrint('🎵 [AudioService] playback started'); + } catch (e) { + debugPrint('⚠️ [AudioService] wait for playback timeout: $e'); + // 超时也标记为已开始,避免永久阻塞 + _hasStartedCurrentPlayback = true; + } } /// ⭐ 播放带认证头的 URL @@ -374,13 +428,13 @@ class AudioService extends ChangeNotifier { if (currentIndex >= 0 && currentIndex < _queue.length) { stopPlay(); - _playCurrent(); + await _playCurrent(); debugPrint('🔄 [AudioService] song reloaded'); } } // ---- 下一首 ---- - void next() { + Future next() async { if (_queue.isEmpty) return; if (_playMode == PlayMode.shuffle) { @@ -388,17 +442,17 @@ class AudioService extends ChangeNotifier { final nextIdx = (_shuffledIndex + 1) % _shuffledIndices.length; _shuffledIndex = nextIdx; _currentIndex = _shuffledIndices[nextIdx]; - _playCurrent(); + await _playCurrent(); return; } final nextIdx = (_currentIndex + 1) % _queue.length; _currentIndex = nextIdx; - _playCurrent(); + await _playCurrent(); } // ---- 上一首 ---- - void previous() { + Future previous() async { if (_queue.isEmpty) return; if (_playMode == PlayMode.shuffle) { @@ -410,7 +464,7 @@ class AudioService extends ChangeNotifier { _shuffledIndex = prevIdx; } _currentIndex = _shuffledIndices[_shuffledIndex]; - _playCurrent(); + await _playCurrent(); return; } @@ -420,7 +474,7 @@ class AudioService extends ChangeNotifier { } else { _currentIndex = prevIdx; } - _playCurrent(); + await _playCurrent(); } // ---- 播放/暂停 ---- @@ -494,6 +548,7 @@ class AudioService extends ChangeNotifier { }); } + // ---- 监听 media_kit 状态 ---- void _startListening() { if (_listening) return; _listening = true; @@ -534,8 +589,47 @@ class AudioService extends ChangeNotifier { }), ); + // ⭐ 完整生命周期校验的 completed 监听 _subscriptions.add( player.stream.completed.listen((_) { + // 第一层:切歌期间屏蔽 + if (_isChangingTrack) { + debugPrint('⚠️ [AudioService] completed ignored during track switch'); + return; + } + + // 第二层:从未真正开始播放,忽略 + if (!_hasStartedCurrentPlayback) { + debugPrint( + '⚠️ [AudioService] completed ignored: playback never started'); + return; + } + + // 第三层:防重入 + if (_handlingCompletion) { + debugPrint('⚠️ [service] completed ignored: already handling'); + return; + } + + // 第四层:额外校验 - 当前歌曲必须有有效的 duration + final pos = player.state.position; + final dur = player.state.duration; + if (dur.inMilliseconds <= 0) { + debugPrint( + '⚠️ [AudioService] completed ignored: invalid duration $dur'); + return; + } + + // 第五层:位置必须接近歌曲末尾(允许 500ms 误差) + if (pos.inMilliseconds < dur.inMilliseconds - 500) { + debugPrint( + '⚠️ [AudioService] completed ignored: position=$pos, duration=$dur, not at end'); + return; + } + + debugPrint( + '🎵 [AudioService] valid completed: index=$_currentIndex, pos=$pos, dur=$dur'); + _handlingCompletion = true; _onPlaybackCompleted(); }), ); @@ -549,14 +643,23 @@ class AudioService extends ChangeNotifier { _subscriptions.clear(); } + // ---- 播放完成处理 ---- void _onPlaybackCompleted() { - if (_handlingCompletion) { - debugPrint('⚠️ [service] completed ignored: already handling'); + // 队列状态检查 + if (_queue.isEmpty || _currentIndex < 0 || _currentIndex >= _queue.length) { + debugPrint('⚠️ [service] completed ignored: invalid queue'); + _handlingCompletion = false; return; } - _handlingCompletion = true; + + // 如果是最后一首且不是单曲循环模式,不触发 next + if (_currentIndex + 1 >= _queue.length && _playMode != PlayMode.repeatOne) { + debugPrint('⚠️ [service] completed ignored: last song in queue'); + _handlingCompletion = false; + return; + } + try { - if (_queue.isEmpty) return; if (_playMode == PlayMode.repeatOne) { _playCurrent(); return;