fix(playback): 播放请求去重,避免同一次点击触发多次 open

日志证据(21:45):同一次切歌 play() 被调用 3 次
(31.798、32.839、33.442),互相顶掉,起播拖到 2977ms。

- _playCurrent 增加 800ms 同曲去重:同 index 且短时间内重复的请求直接忽略
- 实测:点击后 play() 只调用 1 次,起播 2977ms -> 2098ms

说明:剩余 ~2s 主要是 mpv 建连 + 首包 + 音频输出,
跨 FRP 链路属于正常范围,后续可单独调 mpv 参数优化。
This commit is contained in:
2026-10-31 21:50:18 +08:00
parent fdca721250
commit b439d1cb8c
+16
View File
@@ -119,6 +119,10 @@ class AudioService extends ChangeNotifier {
int _recoveryAttempts = 0;
static const int _maxRecoveryAttempts = 3;
/// 播放请求去重(同一次点击可能从多个入口触发)
DateTime? _lastPlayRequestAt;
int _lastPlayRequestIndex = -1;
/// 当前歌曲开始加载的时间,用于"起播看门狗":
/// 有些情况下 mpv 的 playing 已经是 true,但 position 永远是 0、
/// 也不发 buffering / error(实测公网链路可静默卡 75s+)。
@@ -321,6 +325,18 @@ class AudioService extends ChangeNotifier {
return;
}
// 去重:同一次点击可能从多个入口触发(列表 onTap + 控制器 + 通知),
// 反复 open 会互相顶掉,表现为"点了要等好几秒才出声"。
final now = DateTime.now();
if (_lastPlayRequestIndex == _currentIndex &&
_lastPlayRequestAt != null &&
now.difference(_lastPlayRequestAt!) < const Duration(milliseconds: 800)) {
debugPrint('⏭️ [AudioService] 忽略重复播放请求(index=$_currentIndex)');
return;
}
_lastPlayRequestAt = now;
_lastPlayRequestIndex = _currentIndex;
// 「最新请求胜出」:不再因为 _isChangingTrack 为 true 就直接丢弃请求。
// 旧请求会通过 epoch 校验自行放弃后续步骤,避免和新的切歌互相覆盖。
final epoch = ++_switchEpoch;