顺序播放跳曲与首次启动跳曲问题已部分修复,播放逻辑正确,metadata部分仍需修复

This commit is contained in:
2026-08-27 23:18:40 +08:00
parent 9fec9b98c5
commit 6cb1167a21
+125 -22
View File
@@ -62,14 +62,17 @@ class AudioService extends ChangeNotifier {
bool _listening = false; bool _listening = false;
final List<StreamSubscription> _subscriptions = []; final List<StreamSubscription> _subscriptions = [];
// ---- 播放生命周期标志 ----
bool _handlingCompletion = false; bool _handlingCompletion = false;
void Function(Song)? _onSongChanged; bool _isChangingTrack = false;
bool _hasStartedCurrentPlayback = false;
bool _isUserSeeking = false; bool _isUserSeeking = false;
// ⭐ 播放代数:每次切歌递增,用于校验异步任务是否过期 // ⭐ 播放代数:每次切歌递增,用于校验异步任务是否过期
int _playbackGeneration = 0; int _playbackGeneration = 0;
void Function(Song)? _onSongChanged;
// ---- Repository ---- // ---- Repository ----
final SongDatabase _db = SongDatabase(); final SongDatabase _db = SongDatabase();
final PlaylistRepository _playlistRepo = PlaylistRepository(); final PlaylistRepository _playlistRepo = PlaylistRepository();
@@ -123,7 +126,7 @@ class AudioService extends ChangeNotifier {
} }
// ---- 设置播放队列 ---- // ---- 设置播放队列 ----
void setQueue(List<Song> queue, {int startIndex = 0}) { Future<void> setQueue(List<Song> queue, {int startIndex = 0}) async {
if (queue.isEmpty) { if (queue.isEmpty) {
_clearQueue(); _clearQueue();
return; return;
@@ -132,6 +135,7 @@ class AudioService extends ChangeNotifier {
_queue = List.from(queue); _queue = List.from(queue);
_currentIndex = startIndex.clamp(0, _queue.length - 1); _currentIndex = startIndex.clamp(0, _queue.length - 1);
if (_playMode == PlayMode.shuffle) {
_shuffledIndices = List.generate(_queue.length, (i) => i); _shuffledIndices = List.generate(_queue.length, (i) => i);
_shuffledIndices.shuffle(); _shuffledIndices.shuffle();
_shuffledIndex = _shuffledIndices.indexOf(_currentIndex); _shuffledIndex = _shuffledIndices.indexOf(_currentIndex);
@@ -139,8 +143,12 @@ class AudioService extends ChangeNotifier {
_shuffledIndex = 0; _shuffledIndex = 0;
_currentIndex = _shuffledIndices[0]; _currentIndex = _shuffledIndices[0];
} }
} else {
_shuffledIndices = List.generate(_queue.length, (i) => i);
_shuffledIndex = _currentIndex;
}
_playCurrent(); await _playCurrent();
} }
void _clearQueue() { void _clearQueue() {
@@ -156,9 +164,9 @@ class AudioService extends ChangeNotifier {
Future<void> playSong(Song song) async { Future<void> playSong(Song song) async {
_currentPlaylistId = null; _currentPlaylistId = null;
if (_queue.isEmpty || _queue[_currentIndex].id != song.id) { if (_queue.isEmpty || _queue[_currentIndex].id != song.id) {
setQueue([song], startIndex: 0); await setQueue([song], startIndex: 0);
} else { } else {
_playCurrent(); await _playCurrent();
} }
} }
@@ -198,7 +206,7 @@ class AudioService extends ChangeNotifier {
} }
if (songs.isNotEmpty) { if (songs.isNotEmpty) {
setQueue(songs, startIndex: startIndex); await setQueue(songs, startIndex: startIndex);
} }
} }
@@ -212,15 +220,26 @@ class AudioService extends ChangeNotifier {
} }
// ════════════════════════════════════════════════════════════ // ════════════════════════════════════════════════════════════
// ⭐ 播放核心(修复:自动添加认证头 // ⭐ 播放核心(完整生命周期控制
// ════════════════════════════════════════════════════════════ // ════════════════════════════════════════════════════════════
void _playCurrent() { Future<void> _playCurrent() async {
if (_isChangingTrack) {
debugPrint('⚠️ [AudioService] track switch already running');
return;
}
if (_currentIndex < 0 || _currentIndex >= _queue.length) { if (_currentIndex < 0 || _currentIndex >= _queue.length) {
stopPlay(); stopPlay();
return; return;
} }
// ⭐ 进入切歌状态
_isChangingTrack = true;
_handlingCompletion = false;
_hasStartedCurrentPlayback = false;
try {
_playbackGeneration++; _playbackGeneration++;
final generation = _playbackGeneration; final generation = _playbackGeneration;
@@ -234,14 +253,49 @@ class AudioService extends ChangeNotifier {
return; return;
} }
// ⭐ 关键修复:播放时自动添加认证头 // ⭐ 关键:等待播放器加载完成
_playWithHeaders(song.url!); await _playWithHeaders(song.url!);
// ⭐ 等待播放真正开始
await _waitForPlaybackStarted();
_syncPlayerStateDelayed(); _syncPlayerStateDelayed();
// ⭐ 只有真正开始播放后才推送通知
if (_hasStartedCurrentPlayback) {
_onSongChanged?.call(song); _onSongChanged?.call(song);
_loadMetadataForCurrentSong(generation); _loadMetadataForCurrentSong(generation);
} }
} finally {
_isChangingTrack = false;
}
}
/// ⭐ 等待播放器真正开始播放
Future<void> _waitForPlaybackStarted() async {
final player = PlaybackService().player;
// 如果已经在播放,直接标记
if (player.state.playing) {
_hasStartedCurrentPlayback = true;
debugPrint('🎵 [AudioService] playback already started');
return;
}
// 等待 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 /// ⭐ 播放带认证头的 URL
Future<void> _playWithHeaders(String url) async { Future<void> _playWithHeaders(String url) async {
@@ -374,13 +428,13 @@ class AudioService extends ChangeNotifier {
if (currentIndex >= 0 && currentIndex < _queue.length) { if (currentIndex >= 0 && currentIndex < _queue.length) {
stopPlay(); stopPlay();
_playCurrent(); await _playCurrent();
debugPrint('🔄 [AudioService] song reloaded'); debugPrint('🔄 [AudioService] song reloaded');
} }
} }
// ---- 下一首 ---- // ---- 下一首 ----
void next() { Future<void> next() async {
if (_queue.isEmpty) return; if (_queue.isEmpty) return;
if (_playMode == PlayMode.shuffle) { if (_playMode == PlayMode.shuffle) {
@@ -388,17 +442,17 @@ class AudioService extends ChangeNotifier {
final nextIdx = (_shuffledIndex + 1) % _shuffledIndices.length; final nextIdx = (_shuffledIndex + 1) % _shuffledIndices.length;
_shuffledIndex = nextIdx; _shuffledIndex = nextIdx;
_currentIndex = _shuffledIndices[nextIdx]; _currentIndex = _shuffledIndices[nextIdx];
_playCurrent(); await _playCurrent();
return; return;
} }
final nextIdx = (_currentIndex + 1) % _queue.length; final nextIdx = (_currentIndex + 1) % _queue.length;
_currentIndex = nextIdx; _currentIndex = nextIdx;
_playCurrent(); await _playCurrent();
} }
// ---- 上一首 ---- // ---- 上一首 ----
void previous() { Future<void> previous() async {
if (_queue.isEmpty) return; if (_queue.isEmpty) return;
if (_playMode == PlayMode.shuffle) { if (_playMode == PlayMode.shuffle) {
@@ -410,7 +464,7 @@ class AudioService extends ChangeNotifier {
_shuffledIndex = prevIdx; _shuffledIndex = prevIdx;
} }
_currentIndex = _shuffledIndices[_shuffledIndex]; _currentIndex = _shuffledIndices[_shuffledIndex];
_playCurrent(); await _playCurrent();
return; return;
} }
@@ -420,7 +474,7 @@ class AudioService extends ChangeNotifier {
} else { } else {
_currentIndex = prevIdx; _currentIndex = prevIdx;
} }
_playCurrent(); await _playCurrent();
} }
// ---- 播放/暂停 ---- // ---- 播放/暂停 ----
@@ -494,6 +548,7 @@ class AudioService extends ChangeNotifier {
}); });
} }
// ---- 监听 media_kit 状态 ----
void _startListening() { void _startListening() {
if (_listening) return; if (_listening) return;
_listening = true; _listening = true;
@@ -534,8 +589,47 @@ class AudioService extends ChangeNotifier {
}), }),
); );
// ⭐ 完整生命周期校验的 completed 监听
_subscriptions.add( _subscriptions.add(
player.stream.completed.listen((_) { 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(); _onPlaybackCompleted();
}), }),
); );
@@ -549,14 +643,23 @@ class AudioService extends ChangeNotifier {
_subscriptions.clear(); _subscriptions.clear();
} }
// ---- 播放完成处理 ----
void _onPlaybackCompleted() { 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; return;
} }
_handlingCompletion = true;
// 如果是最后一首且不是单曲循环模式,不触发 next
if (_currentIndex + 1 >= _queue.length && _playMode != PlayMode.repeatOne) {
debugPrint('⚠️ [service] completed ignored: last song in queue');
_handlingCompletion = false;
return;
}
try { try {
if (_queue.isEmpty) return;
if (_playMode == PlayMode.repeatOne) { if (_playMode == PlayMode.repeatOne) {
_playCurrent(); _playCurrent();
return; return;