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

12 KiB
Raw Permalink Blame 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. 发起通话

POST /api/front/call/initiate
Content-Type: application/json

{
  "calleeId": 123,
  "callType": "video"  // voice 或 video
}

响应:

{
  "code": 200,
  "msg": "操作成功",
  "data": {
    "callId": "call_abc123...",
    "callType": "video",
    "calleeId": 123,
    "calleeName": "用户昵称",
    "calleeAvatar": "头像URL",
    "status": "calling",
    "signalingUrl": "/ws/call/call_abc123..."
  }
}

2. 接听通话

POST /api/front/call/accept/{callId}

3. 拒绝通话

POST /api/front/call/reject/{callId}

4. 取消通话

POST /api/front/call/cancel/{callId}

5. 结束通话

POST /api/front/call/end/{callId}?endReason=normal

6. 获取通话记录

GET /api/front/call/history?page=1&limit=20

7. 删除通话记录

DELETE /api/front/call/record/{recordId}

8. 获取未接来电数量

GET /api/front/call/missed/count

9. 检查通话状态

GET /api/front/call/status

10. 获取通话详情

GET /api/front/call/detail/{callId}

🔄 WebSocket 信令协议

连接地址

ws://your-domain/ws/call

客户端发送消息类型

1. 注册用户

{
  "type": "register",
  "userId": 123
}

2. 发起通话请求

{
  "type": "call_request",
  "calleeId": 456,
  "callType": "video"
}

3. 接听通话

{
  "type": "call_accept",
  "callId": "call_abc123..."
}

4. 拒绝通话

{
  "type": "call_reject",
  "callId": "call_abc123..."
}

5. 取消通话

{
  "type": "call_cancel",
  "callId": "call_abc123..."
}

6. 结束通话

{
  "type": "call_end",
  "callId": "call_abc123...",
  "reason": "normal"
}

7. WebRTC Offer

{
  "type": "offer",
  "callId": "call_abc123...",
  "sdp": {
    "type": "offer",
    "sdp": "v=0\r\no=..."
  }
}

8. WebRTC Answer

{
  "type": "answer",
  "callId": "call_abc123...",
  "sdp": {
    "type": "answer",
    "sdp": "v=0\r\no=..."
  }
}

9. ICE Candidate

{
  "type": "ice-candidate",
  "callId": "call_abc123...",
  "candidate": {
    "candidate": "candidate:...",
    "sdpMLineIndex": 0,
    "sdpMid": "0"
  }
}

服务端推送消息类型

1. 注册成功

{
  "type": "registered",
  "userId": 123
}

2. 来电通知

{
  "type": "incoming_call",
  "callId": "call_abc123...",
  "callerId": 123,
  "callerName": "用户昵称",
  "callerAvatar": "头像URL",
  "callType": "video"
}

3. 通话已创建

{
  "type": "call_created",
  "callId": "call_abc123..."
}

4. 对方已接听

{
  "type": "call_accepted",
  "callId": "call_abc123..."
}

5. 对方已拒绝

{
  "type": "call_rejected",
  "callId": "call_abc123..."
}

6. 对方已取消

{
  "type": "call_cancelled",
  "callId": "call_abc123..."
}

7. 通话已结束

{
  "type": "call_ended",
  "callId": "call_abc123...",
  "reason": "normal"
}

8. 通话超时

{
  "type": "call_timeout",
  "callId": "call_abc123..."
}

9. 错误消息

{
  "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. 发起通话

// 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. 接听通话

// 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日
维护状态: 已完成