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

This commit is contained in:
2026-08-27 23:18:40 +08:00
parent 9fec9b98c5
commit 6cb1167a21
+143 -40
View File
@@ -62,14 +62,17 @@ class AudioService extends ChangeNotifier {
bool _listening = false;
final List<StreamSubscription> _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<Song> queue, {int startIndex = 0}) {
Future<void> setQueue(List<Song> 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<void> 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<void> _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<void> _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<void> 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<void> 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;