Эх сурвалжийг харах

增加webrtc组件介绍readme文件

liujintao 5 өдөр өмнө
parent
commit
4c9c828683
1 өөрчлөгдсөн 217 нэмэгдсэн , 25 устгасан
  1. 217 25
      README.md

+ 217 - 25
README.md

@@ -1,46 +1,238 @@
-# cw_web
+# WebRTC 直播组件说明
 
-This template should help get you started developing with Vue 3 in Vite.
+## 概述
 
-## Recommended IDE Setup
+`WebRTCVideo` 是一个基于 WebRTC 的实时视频直播 Vue 3 组件,用于从远端摄像头设备接收音视频流并在浏览器中播放。组件通过 WebSocket 信令服务器与设备建立 P2P 连接,支持自动重连、画面冻结检测、截图、扬声器/麦克风控制等功能。
 
-[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin).
+技术栈:Vue 3 Composition API + TypeScript + Element Plus。
 
-## Type Support for `.vue` Imports in TS
+## 连接流程
 
-TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin) to make the TypeScript language service aware of `.vue` types.
+整个直播连接分为三个阶段:**信令协商 → ICE 连接 → 媒体播放**。
 
-If the standalone TypeScript plugin doesn't feel fast enough to you, Volar has also implemented a [Take Over Mode](https://github.com/johnsoncodehk/volar/discussions/471#discussioncomment-1361669) that is more performant. You can enable it by the following steps:
+```
+组件挂载
+  │
+  ├─ 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>` 元素是否意外暂停,自动恢复播放
 
-1. Disable the built-in TypeScript Extension
-    1) Run `Extensions: Show Built-in Extensions` from VSCode's command palette
-    2) Find `TypeScript and JavaScript Language Features`, right click and select `Disable (Workspace)`
-2. Reload the VSCode window by running `Developer: Reload Window` from the command palette.
+### 本地媒体按需获取
 
-## Customize configuration
+组件默认以 `recvonly` 模式连接(只接收远端音视频),不请求本地摄像头/麦克风权限,避免浏览器弹出权限弹窗影响连接速度。只有用户主动点击"开启麦克风"时才调用 `getUserMedia` 获取音频轨道,并动态添加到 PeerConnection。
 
-See [Vite Configuration Reference](https://vitejs.dev/config/).
+### 调试日志
 
-## Project Setup
+所有关键步骤带有时间戳日志,格式为 `[WebRTC][tag]+XXXms`,从 WebSocket 开始连接计时。示例:
 
-```sh
-yarn
 ```
+[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!
+```
+
 
-### Compile and Hot-Reload for Development
+## 组件 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` |
+
+## 使用示例
+
+### 基础用法
+
+```vue
+<template>
+  <WebRTCVideo serno="ANSJ-00-I7N3-QINU-00000027" />
+</template>
+
+<script setup>
+import WebRTCVideo from '@/components/WebRTCVideo.vue'
+</script>
+```
 
-```sh
-yarn dev
+### 完整配置
+
+```vue
+<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>
 ```
 
-### Type-Check, Compile and Minify for Production
+### 通过 URL 参数指定设备
+
+访问 `http://localhost:3333/preview?serno=YOUR_DEVICE_SERNO` 即可连接指定设备。
+
+## 环境变量
 
-```sh
-yarn build
+在 `.env.development` 和 `.env.production` 中配置:
+
+```env
+# WebRTC 信令服务器 IP(开发环境使用)
+VITE_WEBRTC_SIGNAL_IP=192.168.1.20
+
+# WebRTC 信令服务器端口
+VITE_WEBRTC_SIGNAL_PORT=8080
 ```
 
-### Lint with [ESLint](https://eslint.org/)
+- 开发环境:WebSocket 连接到 `VITE_WEBRTC_SIGNAL_IP:VITE_WEBRTC_SIGNAL_PORT`
+- 生产环境:自动使用当前页面 host + 配置的端口,协议跟随 http/https 自动切换 ws/wss
 
-```sh
-yarn lint
+## 文件结构
+
+```
+src/
+├── components/
+│   └── WebRTCVideo.vue      # WebRTC 直播组件
+├── views/
+│   └── preview/
+│       └── index.vue         # 直播预览页面(使用 WebRTCVideo)
 ```