Skip to content

配方 · 直播间弹幕

参考实现:examples/team-video-vue/composables/useDanmakuStream.ts

需求:WebSocket 收到弹幕 → 显示在视频上;用户能发弹幕;能开关、能清屏。


分工(ADR-028)

你负责:  WebSocket 连接 · 拉历史 · 发送到服务端 · 敏感词过滤 · 限流
SDK 负责: 渲染(xgplayer Danmu 引擎)· 轨道排布 · 碰撞避让

SDK 不拉弹幕,也不发弹幕。它只有一个入口:你把一条 DanmakuItem 推进来, 它把这条渲染出去。

理由和其他所有数据一样 —— SDK 不发业务 HTTP。你的弹幕服务鉴权怎么做、 协议是 WebSocket 还是 SSE、要不要合并帧,SDK 都不该有意见。


开启

ts
const danmakuConfig: DanmakuConfig = {
  enabled: true,
  mode: 'streaming',
  display: { area: 'full', opacity: 0.85 },
}
vue
<TeamVideoPlayer ref="teamPlayerRef" :danmaku="danmakuConfig" />

推送

ts
useDanmakuStream({
  intervalMs: 800,
  onDanmaku: (item) => teamPlayerRef.value?.pushDanmaku(item),
}).start()

参考实现里 useDanmakuStream 是个假数据源(定时器随机吐), 真实业务把它换成 WebSocket 订阅:

ts
ws.onmessage = (ev) => {
  const msg = JSON.parse(ev.data)
  teamPlayerRef.value?.pushDanmaku({
    id: msg.id,
    text: msg.text,
    color: msg.color,
  })
}

pushDanmaku逐条推,不是批量。历史弹幕补进来的时候注意别一次灌几千条。


发送

SDK 不管发送。你自己发到服务端,同时本地推一条,让用户立刻看到自己的弹幕:

ts
let danmakuSeq = 0
async function handleDanmakuSend(text: string) {
  danmakuSeq += 1
  await playerFrameRef.value?.pushDanmaku({
    id: `team-${danmakuSeq}`,
    text,
    color: '#ffcc00',   // 自己发的高亮(业务策略)
  })
}

本地回显要小心重复

如果你本地推了一条,服务端广播回来又推一条,同一句会显示两次。

常见做法:发送时带一个本地 id,收到广播时按 id 去重;或者干脆不本地回显, 等服务端回声(代价是有延迟感)。

SDK 不做去重 —— 它不知道哪两条是"同一条"。


开关与清屏

ts
ref.setDanmakuEnabled(false)   // 关闭渲染
ref.clearDanmaku()             // 清空当前屏上的

setDanmakuEnabled(false) 之后再 pushDanmaku,推进去的不会显示 —— 但你的 WebSocket 该断还得自己断,SDK 关的只是渲染。


失败了会怎样

推送失败拿 E_DANMAKU_SEND_FAILED,retryable: true

这个错误码存在的原因是 xgplayer 的弹幕引擎在某些状态下(比如还没初始化完) 会抛异常,而 pushDanmaku 如果不接住,异常会冒到你的 WebSocket 回调里 把整个消息处理打断。

js
onError(({ code }) => {
  if (code === 'E_DANMAKU_SEND_FAILED') {
    // 单条失败通常可以直接丢弃 —— 弹幕是"流",丢一条不影响
  }
})

直播和点播的弹幕不一样

直播点播
数据来源WebSocket 实时流按时间轴预加载
推送时机收到就推跟着 timeupdate
seek 之后不存在 seek要清屏 + 重新按新位置推

点播场景 seek 之后没清屏,会看到上一个位置的弹幕残留在屏幕上:

js
onSeeked(({ time }) => {
  ref.clearDanmaku()
  pushDanmakuAround(time)    // 按新位置重新投
})

参考实现是直播场景,没有这段 —— 做点播弹幕要自己补。


相关