创维C183

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

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)