创维C183

liujintao 4c9c828683 增加webrtc组件介绍readme文件 6 mēneši atpakaļ
.vscode c876fd91f2 init 9 mēneši atpakaļ
public fdb0b04fbc 去除ws-raw的直播插件 6 mēneši atpakaļ
src fb07478d27 update 6 mēneši atpakaļ
types c876fd91f2 init 9 mēneši atpakaļ
.env c5482a733b 需求变更 9 mēneši atpakaļ
.env.development 9b57124b64 webrtc直播方案 6 mēneši atpakaļ
.env.production 9b57124b64 webrtc直播方案 6 mēneši atpakaļ
.eslintignore c876fd91f2 init 9 mēneši atpakaļ
.eslintrc.cjs c876fd91f2 init 9 mēneši atpakaļ
.gitignore c876fd91f2 init 9 mēneši atpakaļ
.prettierignore c876fd91f2 init 9 mēneši atpakaļ
.prettierrc.json c876fd91f2 init 9 mēneši atpakaļ
README.md 4c9c828683 增加webrtc组件介绍readme文件 6 mēneši atpakaļ
auto-imports.d.ts c876fd91f2 init 9 mēneši atpakaļ
components.d.ts fdb0b04fbc 去除ws-raw的直播插件 6 mēneši atpakaļ
env.d.ts fb07478d27 update 6 mēneši atpakaļ
index.html fdb0b04fbc 去除ws-raw的直播插件 6 mēneši atpakaļ
package-lock.json fdb0b04fbc 去除ws-raw的直播插件 6 mēneši atpakaļ
package.json fdb0b04fbc 去除ws-raw的直播插件 6 mēneši atpakaļ
tsconfig.app.json c876fd91f2 init 9 mēneši atpakaļ
tsconfig.json c876fd91f2 init 9 mēneši atpakaļ
tsconfig.node.json c876fd91f2 init 9 mēneši atpakaļ
vite.config.ts c5482a733b 需求变更 9 mēneši atpakaļ

README.md

WebRTC 直播组件说明

概述

WebRTCVideo 是一个基于 WebRTC 的实时视频直播 Vue 3 组件,用于从远端摄像头设备接收音视频流并在浏览器中播放。组件通过 WebSocket 信令服务器与设备建立 P2P 连接,支持自动重连、画面冻结检测、截图、扬声器/麦克风控制等功能。

技术栈:Vue 3 Composition API + TypeScript + Element Plus。

连接流程

整个直播连接分为三个阶段:信令协商 → ICE 连接 → 媒体播放。

组件挂载
  │
  ├─ 1. 建立 WebSocket 信令连接
  │     ws://{host}:{port}/wswebclient/{meid}
  │
  ├─ 2. WebSocket 打开后发送 __connectto(告诉服务器要连哪个设备)
  │
  ├─ 3. 服务器返回 _create(设备在线状态 + ICE 服务器配置)
  │
  ├─ 4. 发送 __call(发起呼叫,携带音视频方向、认证信息)
  │
  ├─ 5. 服务器返回 _call 或 _offer(SDP 协商开始)
  │     ├─ 收到 _call → 创建 PeerConnection → createOffer → 发送 __offer
  │     └─ 收到 _offer → 创建 PeerConnection → createAnswer → 发送 __answer
  │
  ├─ 6. 收到 _answer → setRemoteDescription(SDP 协商完成)
  │
  ├─ 7. ICE Candidate 交换(__ice_candidate / _ice_candidate)
  │
  ├─ 8. ICE 连接建立(checking → connected)
  │
  ├─ 9. 远端 Track 到达 → video.srcObject 赋值 → video.play()
  │
  └─ 10. 画面显示,进入稳定播放状态

正常情况下,从 WebSocket 打开到画面显示约 100-500ms。

信令消息说明

方向 消息 说明
→ 发送 __connectto 请求连接指定设备
← 接收 _create 设备状态(online/offline)及 ICE 配置
→ 发送 __call 发起呼叫,携带音视频方向和认证信息
← 接收 _call / _offer 服务器要求创建 Offer 或直接下发 Offer
→ 发送 __offer / __answer SDP 协商
← 接收 _answer 远端 SDP 应答
↔ 双向 __ice_candidate / _ice_candidate ICE 候选地址交换
→ 发送 __ping 心跳保活(每 30 秒)
→ 发送 __disconnected 主动断开通知
← 接收 _session_failed 会话失败,需要重新连接
← 接收 _session_disconnected 远端断开通知
← 接收 _connectinfo 连接信息(调试用)

重要功能

自动重连机制

  • 心跳保活:每 2 秒检测 WebSocket 状态,断开后自动重建连接
  • WebSocket 握手超时:超过设定时间未连接成功则关闭并重试
  • Session 失败重试:收到 _session_failed 后立即用新 sessionId 重新发起连接
  • ICE 断连恢复:ICE 状态变为 disconnected/failed 时,如果 WebSocket 还活着则立即重新发起信令协商
  • 组件卸载通知:离开页面或切换路由时主动发送 __disconnected,让服务器立即清理旧 session

画面冻结检测(Watchdog)

每 3 秒通过 RTCPeerConnection.getStats() 检查视频流的 bytesReceived:

  • 如果连续 3 次(约 9 秒)没有新数据到达,判定为画面冻结
  • 先尝试 ICE Restart(createOffer({ iceRestart: true }))恢复连接
  • ICE Restart 失败则完全重连
  • 同时检测 <video> 元素是否意外暂停,自动恢复播放

本地媒体按需获取

组件默认以 recvonly 模式连接(只接收远端音视频),不请求本地摄像头/麦克风权限,避免浏览器弹出权限弹窗影响连接速度。只有用户主动点击"开启麦克风"时才调用 getUserMedia 获取音频轨道,并动态添加到 PeerConnection。

调试日志

所有关键步骤带有时间戳日志,格式为 [WebRTC][tag]+XXXms,从 WebSocket 开始连接计时。示例:

[WebRTC][ws]+0ms connecting... ws://192.168.1.20:8080/wswebclient/xxx
[WebRTC][ws]+3ms opened
[WebRTC][signal]+3ms sendConnect to ANSJ-00-...
[WebRTC][msg]+5ms _create
[WebRTC][signal]+5ms callDevice
[WebRTC][msg]+20ms _offer
[WebRTC][pc]+21ms PeerConnection created
[WebRTC][track]+23ms remote track received, kind: video
[WebRTC][ice]+70ms checking
[WebRTC][ice]+120ms connected
[WebRTC][play]+120ms attempting video.play()
[WebRTC][play]+200ms playing!

组件 API

Props

属性 类型 必填 默认值 说明
serno string ✅ — 设备序列号
wsUrl string — 自动推导 信令 WebSocket 地址,不传则根据环境变量拼接
iceServers RTCIceServer[] — Google STUN ICE 服务器配置,通常由信令服务器下发
mode string — 'live' 连接模式:live(直播)/ playback(回放)
source string — 'MainStream' 码流:MainStream(主码流)/ SubStream(子码流)
enableDataChannel boolean — true 是否启用 DataChannel
dragFlag boolean — false 是否允许鼠标拖拽和滚轮缩放
sessionType string — 'IE' 会话类型标识
user string — 'admin' 设备认证用户名
pwd string — 'admin' 设备认证密码

Events

事件 参数 说明
connected — ICE 连接建立成功
disconnected — 连接断开
error Error \| string 连接或播放错误
datachannel-message any 收到 DataChannel 消息

Expose(通过 ref 调用)

方法/属性 类型 说明
reconnect() function 手动断开并重新连接
captureSnapshot() function 截取当前画面并下载为 PNG
sendDataChannelMessage(msg) function 通过 DataChannel 发送消息
toggleSpeaker() function 切换扬声器开关
toggleMic() function 切换麦克风开关(首次会请求权限)
isPlaying Ref<boolean> 是否正在播放(只读)
speakerEnabled Ref<boolean> 扬声器是否开启(只读)
micEnabled Ref<boolean> 麦克风是否开启(只读)
connectionStatus Ref<string> 连接状态(只读):idle / connecting / connected / disconnected / failed

使用示例

基础用法

<template>
  <WebRTCVideo serno="ANSJ-00-I7N3-QINU-00000027" />
</template>

<script setup>
import WebRTCVideo from '@/components/WebRTCVideo.vue'
</script>

完整配置

<template>
  <WebRTCVideo
    ref="videoRef"
    :serno="deviceSerno"
    mode="live"
    source="MainStream"
    session-type="IE"
    user="admin"
    pwd="admin123"
    :drag-flag="true"
    :enable-data-channel="true"
    @connected="onConnected"
    @disconnected="onDisconnected"
    @error="onError"
    @datachannel-message="onMessage"
  />
</template>

<script setup>
import { ref } from 'vue'
import WebRTCVideo from '@/components/WebRTCVideo.vue'

const videoRef = ref()
const deviceSerno = ref('ANSJ-00-I7N3-QINU-00000027')

function onConnected() {
  console.log('直播已连接')
}

function onDisconnected() {
  console.log('直播已断开')
}

function onError(err) {
  console.error('直播错误:', err)
}

function onMessage(msg) {
  console.log('DataChannel 消息:', msg)
}

// 通过 ref 调用组件方法
function handleScreenshot() {
  videoRef.value?.captureSnapshot()
}

function handleReconnect() {
  videoRef.value?.reconnect()
}
</script>

通过 URL 参数指定设备

访问 http://localhost:3333/preview?serno=YOUR_DEVICE_SERNO 即可连接指定设备。

环境变量

在 .env.development 和 .env.production 中配置:

# WebRTC 信令服务器 IP(开发环境使用)
VITE_WEBRTC_SIGNAL_IP=192.168.1.20

# WebRTC 信令服务器端口
VITE_WEBRTC_SIGNAL_PORT=8080
  • 开发环境:WebSocket 连接到 VITE_WEBRTC_SIGNAL_IP:VITE_WEBRTC_SIGNAL_PORT
  • 生产环境:自动使用当前页面 host + 配置的端口,协议跟随 http/https 自动切换 ws/wss

文件结构

src/
├── components/
│   └── WebRTCVideo.vue      # WebRTC 直播组件
├── views/
│   └── preview/
│       └── index.vue         # 直播预览页面(使用 WebRTCVideo)