You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

7.3 KiB

监控直播 HLS 真实播放补齐

日期:2026-09-02
状态:已确认(待实现计划)

背景

后端直播播放地址是 HLS:

https://vpull.jiagutech.com/dock-live/<streamSessionId>.m3u8?auth_key=...

当前前端缺口:

  1. LivePlayer.vue.m3u8 直接赋给原生 <video src>,项目无 hls.js。Safari 通常可播,Chrome/Edge/Firefox 通常不能。
  2. useMonitorLive 创建会话后只靠观看租约心跳刷新状态。默认租约约 30s,第一次刷新约 15s;即使流已就绪,页面也会长时间停在「启动中」。
  3. GET play-url 返回 expiresAt(默认约 300s),前端只在「尚无 playUrl」时拉一次;过期后播放失败,仅 toast,不换新地址。
  4. 播放器错误只向上抛,没有重建路径。
  5. 关闭按钮语义只有「退出观看」(leaveLive);后端已有 POST /v1/live/:dockId/stop,前端未接。

相关后端契约:

  • GET /v1/live/:dockId/sessions/:streamSessionId → 会话状态
  • GET /v1/live/:dockId/play-url?streamSessionId={ playUrl, expiresAt, streamName }
  • POST /v1/live/:dockId/sessions/:id/heartbeat → 续观看租约
  • DELETE .../viewers/me → 退出观看
  • POST /v1/live/:dockId/stop → 停止直播推流

目标

监控详情实时画面:

  1. Chrome/Edge 用 hls.js 播放 HLS;Safari / 原生可播 HLS 时走原生 <video>
  2. join 后每 2–3 秒查询会话,直到 streaming / failed / 超时,再尽快取 playUrl。
  3. 记录 playUrl expiresAt,到期前约 30 秒自动刷新地址并重建播放器。
  4. HLS 网络/鉴权/解码错误时限流重试:重新拉 play-url 并重建播放器。
  5. 区分:
    • 退出观看:现有中心按钮 / leaveLive
    • 停止直播:详情面板新增按钮,调 POST /stop

非目标

  • 不改 Media 页(仍可 window.open
  • 不改后端协议 / 鉴权
  • 不做 WebRTC / FLV 播放器
  • 不把停止直播做成播放器内复杂手势
  • 不在本轮处理多路同屏播放

方案

采用:LivePlayer 负责媒体;useMonitorLive 负责会话/轮询/续期/退出与停止;详情面板加停止按钮。

1. 依赖

package.json 增加 hls.js(运行时依赖)。

2. API

文件:src/api/live.jssrc/config/urls.js

新增:

export function getLiveSession(dockId, sessionId) {
  return request.get(`/v1/live/${dockId}/sessions/${sessionId}`)
}

export function stopLive(dockId) {
  return request.post(`/v1/live/${dockId}/stop`)
}

现有 getLivePlayURL(dockId, sessionId) 保持;调用方必须消费返回的 expiresAt

3. LivePlayer

文件:src/components/LivePlayer.vue

职责:

  • props 仍接收 playUrl / phase / active / cameraLabel
  • playable 判定不变:有 playUrl 且非 fake://
  • playable
    • video.canPlayType('application/vnd.apple.mpegurl') 真 → 原生 src = playUrl
    • 否则动态/静态引入 hls.jsHls.isSupported()new Hls()loadSourceattachMedia
    • 不支持则 emit error,展示失败态
  • playUrl 变化或组件卸载:destroy 旧 Hls 实例,清空 video.src / removeAttribute('src') + load()
  • 监听 video.error 与 hls ERRORfatal)→ emit error
  • 中心按钮语义不变:emit toggle(由上层解释为退出观看 / 打开)

不在 LivePlayer 内请求 API。

4. useMonitorLive

文件:src/composables/useMonitorLive.js

状态扩展:

live = {
  session, dockId, playUrl,
  playUrlExpiresAt,      // unix 秒;缺省时用拿到时刻 + 270s 兜底
  heartbeatTimer,
  phasePollTimer,
  playRefreshTimer,
  playRetryCount,
}

对外新增:stopLiveStream

4.1 打开

  1. joinLive(dockId)
  2. session / dockId
  3. 启动观看租约心跳(逻辑保留;与状态轮询分离)
  4. 若已 streamingrefreshPlayURL()
  5. 否则启动 phase 轮询:每 2.5s getLiveSession
    • 响应经 http 解包后直接是 LiveSession(含 phase/id),不是 { session } 包装
    • streaming → 停轮询,refreshPlayURL()
    • failed / stopped → toast,清本地态(不强制 stop)
    • 超过 60s 仍非终态 → toast「直播启动超时」,清本地态

4.2 playUrl 刷新

refreshPlayURL()

  1. getLivePlayURL
  2. live.playUrl
  3. live.playUrlExpiresAt = play.expiresAt || nowSec + 270
  4. 调度续期:delay = max(5000, expiresAt*1000 - Date.now() - 30000)
  5. 到期触发时再次 refreshPlayURL();失败走播放错误重试路径

仅当本地仍持有同一 session.id 时回填,避免竞态。

4.3 播放错误重建

详情面板 @live-error → composable onPlayError()

  • playRetryCount < 3:递增,重新 refreshPlayURL()(新 URL 触发 LivePlayer 重建)
  • 达到 3:toast「播放失败」,重置计数但不 leave;心跳可继续

成功拿到并切换新 playUrl 后把 playRetryCount 置 0。

4.4 退出观看

现有 closeLive(true)

  • 清所有定时器
  • session/playUrl/expires
  • leaveLive

切换设备 / 关详情 / 卸载:仍走退出观看。

4.5 停止直播

stopLiveStream()

  1. 无 active session 直接 return
  2. ui.confirm 确认(文案:停止后所有观看者失去画面)
  3. POST /v1/live/:dockId/stop
  4. 成功:清本地播放态(等同 close 本地部分);可再尝试 leave(忽略错误)
  5. 失败:toast,保留当前播放与心跳

5. 详情面板 UI

文件:src/components/MonitorDetailPanel.vue + MonitorView 接线

在「实时画面」标题行(状态文案 / 全屏旁)增加:

  • 按钮文案:停止直播
  • liveView.active 时可见/可点
  • emit stop-live → MonitorView → useMonitorLive.stopLiveStream

中心播放按钮保持 toggle:有 session 时退出观看。

6. 验收

  1. Chrome/Edge:join → streaming 后页内可见真实 HLS 画面(非仅黑框)
  2. Safari:原生路径可播,不强制挂 hls.js
  3. join 后非 streaming:约 2.5s 内开始轮询;流就绪后数秒内出现画面,不再干等 ~15s 心跳
  4. playUrl 到期前约 30s 自动换新地址,播放不中断或短暂重建后恢复
  5. 人为弄坏/过期 URL 后,最多自动重建 3 次
  6. 「停止直播」调 /stop;中心关闭只 leave,不 stop
  7. 切设备 / 关面板:销毁 hls、清定时器,无残留请求风暴
  8. fake:// 行为与现网一致
  9. npm run build 通过

风险

  • 后端 GetLiveSession 返回解包后的 LiveSession 本体(handler OKWithData(session)),不是 LiveSessionVO
  • 云端 phase 推进依赖后端 reconcile;前端轮询只能反映后端状态,不能替代设备推流
  • 多标签页同时观看:停止直播会影响所有观看者——必须确认框
  • hls.js:LivePlayer 内 动态 import,避免拖大非监控首屏 chunk

文件清单

文件 变更
package.json / lock hls.js
src/api/live.js getLiveSession / stopLive
src/config/urls.js 对应常量
src/components/LivePlayer.vue HLS 适配 + 销毁
src/composables/useMonitorLive.js 轮询 / 续期 / 重试 / stop
src/components/MonitorDetailPanel.vue 停止按钮
src/views/MonitorView/MonitorView.vue 接线 stop / live-error