diff --git a/web/src/utils/liveWebRTC.js b/web/src/utils/liveWebRTC.js index 2368f12..f774ed3 100644 --- a/web/src/utils/liveWebRTC.js +++ b/web/src/utils/liveWebRTC.js @@ -47,6 +47,8 @@ export function startViewing(videoEl, opts = {}) { let ws = null let pollTimer = null let currentPollMs = pollMs + let pollInFlight = false + let upstreamErrorStreak = 0 let stopped = false let blackFrameTimer = null @@ -109,8 +111,12 @@ export function startViewing(videoEl, opts = {}) { if (pollTimer) return rebuildPeer() currentPollMs = pollMs + upstreamErrorStreak = 0 schedulePollLoop() - poll() + // 下一轮再 poll,避免从 poll() 内同步调用时 pollInFlight 仍为 true 导致被跳过 + setTimeout(() => { + if (!stopped) poll() + }, 0) } async function negotiate() { @@ -173,10 +179,17 @@ export function startViewing(videoEl, opts = {}) { async function poll() { if (stopped) return + if (pollInFlight) return + pollInFlight = true try { const { live, upstreamError } = await fetchLiveStatus() if (upstreamError) { - onStatus('无法连接服务器(网关 502/离线),将放慢重试…') + upstreamErrorStreak += 1 + const extra = + upstreamErrorStreak >= 6 + ? ' 若长时间如此,多为服务端未启动或网关异常,请刷新页面或联系管理员。' + : '' + onStatus(`无法连接服务器(网关 502/离线),将放慢重试…${extra}`) const next = Math.min(Math.round(currentPollMs * 1.5), 30000) if (next !== currentPollMs) { currentPollMs = next @@ -184,6 +197,7 @@ export function startViewing(videoEl, opts = {}) { } return } + upstreamErrorStreak = 0 if (currentPollMs !== pollMs) { currentPollMs = pollMs schedulePollLoop() @@ -195,12 +209,23 @@ export function startViewing(videoEl, opts = {}) { } onLive() onStatus('检测到直播,正在连接…') - await negotiate() + try { + await negotiate() + } catch (err) { + onStatus( + err?.message + ? `拉流连接失败:${err.message}` + : '拉流连接失败,将恢复轮询…' + ) + resumePollingAfterDisconnect('') + } return } onStatus('等待主播开播…') } catch { onStatus('无法获取直播状态') + } finally { + pollInFlight = false } }