zhibo/Zhibo/zhibo-h/语音视频通话模块说明.md

574 lines
12 KiB
Markdown
Raw Normal View History

# 语音/视频通话模块说明
## 📋 模块概述
本模块实现了基于 WebRTC 的一对一语音/视频通话功能,支持通话邀请、接听、拒绝、取消、结束等完整流程,并提供通话记录管理功能。
**实现时间**: 已完成
**技术方案**: WebRTC + WebSocket 信令交换
**完成度**: 100%
---
## 🏗️ 架构设计
### 核心组件
1. **CallRecord** - 通话记录实体类
- 路径: `crmeb-common/src/main/java/com/zbkj/common/model/call/CallRecord.java`
- 功能: 存储通话记录信息(通话双方、类型、状态、时长等)
2. **CallService** - 通话业务逻辑服务
- 路径: `crmeb-service/src/main/java/com/zbkj/service/service/impl/CallServiceImpl.java`
- 功能: 处理通话创建、接听、拒绝、取消、结束等业务逻辑
3. **CallController** - 通话接口控制器
- 路径: `crmeb-front/src/main/java/com/zbkj/front/controller/CallController.java`
- 功能: 提供 RESTful API 接口
4. **CallSignalingHandler** - WebRTC 信令处理器
- 路径: `crmeb-front/src/main/java/com/zbkj/front/websocket/CallSignalingHandler.java`
- 功能: 处理 WebSocket 信令交换offer、answer、ice-candidate
---
## 📊 数据库设计
### 表名: `eb_call_record`
| 字段名 | 类型 | 说明 |
|--------|------|------|
| id | BIGINT | 主键ID |
| call_id | VARCHAR(64) | 通话唯一标识(用于信令) |
| caller_id | INT | 主叫用户ID |
| callee_id | INT | 被叫用户ID |
| call_type | VARCHAR(20) | 通话类型: voice-语音, video-视频 |
| status | VARCHAR(20) | 通话状态 |
| call_time | DATETIME | 通话发起时间 |
| connect_time | DATETIME | 通话接通时间 |
| end_time | DATETIME | 通话结束时间 |
| duration | INT | 通话时长(秒) |
| end_reason | VARCHAR(50) | 结束原因 |
| caller_deleted | TINYINT(1) | 主叫是否删除记录 |
| callee_deleted | TINYINT(1) | 被叫是否删除记录 |
| create_time | DATETIME | 创建时间 |
| update_time | DATETIME | 更新时间 |
### 通话状态说明
- `calling` - 呼叫中(主叫发起,等待被叫响应)
- `ringing` - 响铃中(被叫收到邀请)
- `connected` - 通话中(双方已接通)
- `ended` - 已结束(正常结束)
- `missed` - 未接(超时未接听)
- `rejected` - 已拒绝(被叫拒绝)
- `cancelled` - 已取消(主叫取消)
- `busy` - 忙线(对方正在通话中)
---
## 🔌 API 接口
### 1. 发起通话
```http
POST /api/front/call/initiate
Content-Type: application/json
{
"calleeId": 123,
"callType": "video" // voice 或 video
}
```
**响应**:
```json
{
"code": 200,
"msg": "操作成功",
"data": {
"callId": "call_abc123...",
"callType": "video",
"calleeId": 123,
"calleeName": "用户昵称",
"calleeAvatar": "头像URL",
"status": "calling",
"signalingUrl": "/ws/call/call_abc123..."
}
}
```
### 2. 接听通话
```http
POST /api/front/call/accept/{callId}
```
### 3. 拒绝通话
```http
POST /api/front/call/reject/{callId}
```
### 4. 取消通话
```http
POST /api/front/call/cancel/{callId}
```
### 5. 结束通话
```http
POST /api/front/call/end/{callId}?endReason=normal
```
### 6. 获取通话记录
```http
GET /api/front/call/history?page=1&limit=20
```
### 7. 删除通话记录
```http
DELETE /api/front/call/record/{recordId}
```
### 8. 获取未接来电数量
```http
GET /api/front/call/missed/count
```
### 9. 检查通话状态
```http
GET /api/front/call/status
```
### 10. 获取通话详情
```http
GET /api/front/call/detail/{callId}
```
---
## 🔄 WebSocket 信令协议
### 连接地址
```
ws://your-domain/ws/call
```
### 客户端发送消息类型
#### 1. 注册用户
```json
{
"type": "register",
"userId": 123
}
```
#### 2. 发起通话请求
```json
{
"type": "call_request",
"calleeId": 456,
"callType": "video"
}
```
#### 3. 接听通话
```json
{
"type": "call_accept",
"callId": "call_abc123..."
}
```
#### 4. 拒绝通话
```json
{
"type": "call_reject",
"callId": "call_abc123..."
}
```
#### 5. 取消通话
```json
{
"type": "call_cancel",
"callId": "call_abc123..."
}
```
#### 6. 结束通话
```json
{
"type": "call_end",
"callId": "call_abc123...",
"reason": "normal"
}
```
#### 7. WebRTC Offer
```json
{
"type": "offer",
"callId": "call_abc123...",
"sdp": {
"type": "offer",
"sdp": "v=0\r\no=..."
}
}
```
#### 8. WebRTC Answer
```json
{
"type": "answer",
"callId": "call_abc123...",
"sdp": {
"type": "answer",
"sdp": "v=0\r\no=..."
}
}
```
#### 9. ICE Candidate
```json
{
"type": "ice-candidate",
"callId": "call_abc123...",
"candidate": {
"candidate": "candidate:...",
"sdpMLineIndex": 0,
"sdpMid": "0"
}
}
```
### 服务端推送消息类型
#### 1. 注册成功
```json
{
"type": "registered",
"userId": 123
}
```
#### 2. 来电通知
```json
{
"type": "incoming_call",
"callId": "call_abc123...",
"callerId": 123,
"callerName": "用户昵称",
"callerAvatar": "头像URL",
"callType": "video"
}
```
#### 3. 通话已创建
```json
{
"type": "call_created",
"callId": "call_abc123..."
}
```
#### 4. 对方已接听
```json
{
"type": "call_accepted",
"callId": "call_abc123..."
}
```
#### 5. 对方已拒绝
```json
{
"type": "call_rejected",
"callId": "call_abc123..."
}
```
#### 6. 对方已取消
```json
{
"type": "call_cancelled",
"callId": "call_abc123..."
}
```
#### 7. 通话已结束
```json
{
"type": "call_ended",
"callId": "call_abc123...",
"reason": "normal"
}
```
#### 8. 通话超时
```json
{
"type": "call_timeout",
"callId": "call_abc123..."
}
```
#### 9. 错误消息
```json
{
"type": "error",
"message": "错误描述"
}
```
---
## 🎯 通话流程
### 语音/视频通话完整流程
```
主叫方 服务器 被叫方
| | |
|--1. 发起通话----------->| |
| POST /call/initiate | |
| | |
|<--返回callId-----------| |
| | |
|--2. 连接WebSocket----->| |
| register | |
| | |
| |--3. 推送来电通知------->|
| | incoming_call |
| | |
| |<--4. 接听通话----------|
| | call_accept |
| | |
|<--5. 通知已接听--------|--5. 通知已接听-------->|
| call_accepted | call_accepted |
| | |
|--6. 发送Offer--------->|--6. 转发Offer--------->|
| | |
|<--7. 接收Answer--------|<--7. 发送Answer--------|
| | |
|--8. 交换ICE候选------->|--8. 转发ICE候选------->|
|<-----------------------|<-----------------------|
| | |
|========== WebRTC P2P 通话建立 =================|
| | |
|--9. 结束通话---------->| |
| call_end | |
| |--9. 通知结束---------->|
| | call_ended |
```
---
## ⚙️ 核心功能特性
### 1. 通话管理
- ✅ 发起语音/视频通话
- ✅ 接听/拒绝/取消通话
- ✅ 通话中状态检测
- ✅ 通话时长统计
- ✅ 通话记录保存
### 2. 状态管理
- ✅ 用户在线状态检测
- ✅ 通话状态实时同步
- ✅ 忙线检测(防止重复呼叫)
- ✅ 超时自动挂断60秒
### 3. 信令交换
- ✅ WebSocket 长连接
- ✅ SDP Offer/Answer 交换
- ✅ ICE Candidate 交换
- ✅ 信令自动转发
### 4. 通话记录
- ✅ 通话历史查询
- ✅ 未接来电统计
- ✅ 双向软删除
- ✅ 通话详情查看
### 5. 异常处理
- ✅ 网络断开自动结束
- ✅ 超时自动挂断
- ✅ 错误消息推送
- ✅ 状态一致性保证
---
## 🔒 安全特性
1. **权限验证**: 所有接口需要登录认证
2. **操作权限**: 只能操作自己参与的通话
3. **状态校验**: 严格的状态机转换验证
4. **防重复呼叫**: 检测用户是否正在通话中
5. **超时保护**: 60秒超时自动结束未接通的通话
---
## 📱 客户端集成指南
### 1. 发起通话
```javascript
// 1. 调用 API 发起通话
const response = await fetch('/api/front/call/initiate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
calleeId: 456,
callType: 'video'
})
});
const { callId, signalingUrl } = await response.json();
// 2. 连接 WebSocket
const ws = new WebSocket('ws://your-domain/ws/call');
// 3. 注册用户
ws.send(JSON.stringify({
type: 'register',
userId: currentUserId
}));
// 4. 创建 WebRTC 连接
const pc = new RTCPeerConnection(config);
// 5. 添加本地媒体流
const stream = await navigator.mediaDevices.getUserMedia({
video: callType === 'video',
audio: true
});
stream.getTracks().forEach(track => pc.addTrack(track, stream));
// 6. 创建并发送 Offer
const offer = await pc.createOffer();
await pc.setLocalDescription(offer);
ws.send(JSON.stringify({
type: 'offer',
callId: callId,
sdp: offer
}));
// 7. 监听 ICE Candidate
pc.onicecandidate = (event) => {
if (event.candidate) {
ws.send(JSON.stringify({
type: 'ice-candidate',
callId: callId,
candidate: event.candidate
}));
}
};
// 8. 接收远程流
pc.ontrack = (event) => {
remoteVideo.srcObject = event.streams[0];
};
```
### 2. 接听通话
```javascript
// 1. 收到来电通知
ws.onmessage = async (event) => {
const msg = JSON.parse(event.data);
if (msg.type === 'incoming_call') {
// 显示来电界面
showIncomingCallUI(msg);
}
};
// 2. 用户点击接听
async function acceptCall(callId) {
// 调用接听 API
await fetch(`/api/front/call/accept/${callId}`, {
method: 'POST'
});
// 创建 WebRTC 连接
const pc = new RTCPeerConnection(config);
// 添加本地媒体流
const stream = await navigator.mediaDevices.getUserMedia({
video: true,
audio: true
});
stream.getTracks().forEach(track => pc.addTrack(track, stream));
// 监听 Offer
ws.onmessage = async (event) => {
const msg = JSON.parse(event.data);
if (msg.type === 'offer') {
await pc.setRemoteDescription(msg.sdp);
const answer = await pc.createAnswer();
await pc.setLocalDescription(answer);
// 发送 Answer
ws.send(JSON.stringify({
type: 'answer',
callId: callId,
sdp: answer
}));
}
if (msg.type === 'ice-candidate') {
await pc.addIceCandidate(msg.candidate);
}
};
}
```
---
## 🧪 测试建议
### 功能测试
1. 正常通话流程测试
2. 拒绝/取消通话测试
3. 超时未接测试
4. 忙线检测测试
5. 通话记录查询测试
### 异常测试
1. 网络断开重连测试
2. 对方离线测试
3. 并发呼叫测试
4. WebSocket 断开测试
### 性能测试
1. 并发通话数量测试
2. 信令延迟测试
3. 内存泄漏测试
---
## 📝 注意事项
1. **WebRTC 兼容性**: 确保客户端浏览器支持 WebRTC
2. **HTTPS 要求**: WebRTC 需要在 HTTPS 环境下运行(本地开发除外)
3. **STUN/TURN 服务器**: 生产环境需要配置 STUN/TURN 服务器用于 NAT 穿透
4. **媒体权限**: 需要用户授权摄像头和麦克风权限
5. **超时时间**: 默认 60 秒超时,可根据需求调整
6. **通话记录清理**: 建议定期清理过期的通话记录
---
## 🚀 后续优化建议
1. **群组通话**: 支持多人视频会议
2. **屏幕共享**: 支持屏幕共享功能
3. **通话质量**: 添加网络质量检测和自适应码率
4. **通话录制**: 支持通话录制功能
5. **美颜滤镜**: 集成美颜和滤镜功能
6. **通话统计**: 添加通话质量统计和分析
---
**文档版本**: v1.0
**最后更新**: 2024年12月26日
**维护状态**: ✅ 已完成