zhibo/模块文档/18-通话功能模块.md
2025-12-30 11:11:11 +08:00

527 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 通话功能模块
## 模块概述
通话功能模块负责处理用户之间的语音和视频通话功能,包括发起通话、接听/拒绝通话、通话记录等。
## 相关文件
- `CallActivity.java` - 通话界面
- `IncomingCallActivity.java` - 来电界面
- `CallHistoryActivity.java` - 通话记录界面
- `CallManager.java` - 通话管理器
- `CallSignalingClient.java` - 信令客户端
- `CallApiService.java` - 通话API接口
- `InitiateCallRequest.java` - 发起通话请求模型
- `InitiateCallResponse.java` - 发起通话响应模型
- `CallRecordResponse.java` - 通话记录响应模型
- `CallHistoryResponse.java` - 通话历史响应模型
---
## 接口列表
### 1. 发起通话
**接口地址**: `POST /api/front/call/initiate`
**请求参数** (InitiateCallRequest):
```json
{
"calleeId": "integer", // 被叫用户ID必填
"callType": "string" // 通话类型: voice/video必填
}
```
**返回数据** (InitiateCallResponse):
```json
{
"code": 200,
"msg": "success",
"data": {
"callId": "string", // 通话ID
"callType": "string", // 通话类型
"calleeId": "integer", // 被叫用户ID
"calleeName": "string", // 被叫用户昵称
"calleeAvatar": "string", // 被叫用户头像
"status": "string", // 通话状态: calling
"signalingUrl": "string" // 信令服务器URL
}
}
```
---
### 2. 接听通话
**接口地址**: `POST /api/front/call/accept/{callId}`
**路径参数**:
```
callId: string // 通话ID
```
**请求参数**: 无
**返回数据**:
```json
{
"code": 200,
"msg": "接听成功",
"data": true
}
```
---
### 3. 拒绝通话
**接口地址**: `POST /api/front/call/reject/{callId}`
**路径参数**:
```
callId: string // 通话ID
```
**请求参数**: 无
**返回数据**:
```json
{
"code": 200,
"msg": "已拒绝",
"data": true
}
```
---
### 4. 取消通话
**接口地址**: `POST /api/front/call/cancel/{callId}`
**路径参数**:
```
callId: string // 通话ID
```
**请求参数**: 无
**返回数据**:
```json
{
"code": 200,
"msg": "已取消",
"data": true
}
```
---
### 5. 结束通话
**接口地址**: `POST /api/front/call/end/{callId}`
**路径参数**:
```
callId: string // 通话ID
```
**请求参数**:
```
endReason: string // 结束原因(可选)
```
**返回数据**:
```json
{
"code": 200,
"msg": "通话已结束",
"data": true
}
```
---
### 6. 获取通话记录
**接口地址**: `GET /api/front/call/history`
**请求参数**:
```
page: integer // 页码默认1
limit: integer // 每页数量默认20
```
**返回数据** (CallHistoryResponse):
```json
{
"code": 200,
"msg": "success",
"data": {
"records": [
{
"id": "long", // 记录ID
"callId": "string", // 通话ID
"callType": "string", // 通话类型: voice/video
"callDirection": "string", // 通话方向: outgoing/incoming
"otherUserId": "integer", // 对方用户ID
"otherUserName": "string", // 对方用户昵称
"otherUserAvatar": "string",// 对方用户头像
"status": "string", // 状态: completed/missed/rejected/cancelled
"duration": "integer", // 通话时长(秒)
"startTime": "long", // 开始时间戳
"endTime": "long" // 结束时间戳
}
],
"total": "integer",
"page": "integer",
"limit": "integer"
}
}
```
---
### 7. 删除通话记录
**接口地址**: `DELETE /api/front/call/record/{recordId}`
**路径参数**:
```
recordId: long // 记录ID
```
**请求参数**: 无
**返回数据**:
```json
{
"code": 200,
"msg": "删除成功",
"data": true
}
```
---
### 8. 获取未接来电数量
**接口地址**: `GET /api/front/call/missed/count`
**请求参数**: 无
**返回数据**:
```json
{
"code": 200,
"msg": "success",
"data": 5 // 未接来电数量
}
```
---
### 9. 获取通话状态
**接口地址**: `GET /api/front/call/status`
**请求参数**: 无
**返回数据**:
```json
{
"code": 200,
"msg": "success",
"data": {
"inCall": "boolean", // 是否正在通话中
"callId": "string", // 当前通话ID
"callType": "string", // 通话类型
"otherUserId": "integer", // 对方用户ID
"startTime": "long" // 通话开始时间
}
}
```
---
### 10. 获取通话详情
**接口地址**: `GET /api/front/call/detail/{callId}`
**路径参数**:
```
callId: string // 通话ID
```
**请求参数**: 无
**返回数据** (CallRecordResponse):
```json
{
"code": 200,
"msg": "success",
"data": {
"id": "long",
"callId": "string",
"callType": "string",
"callDirection": "string",
"callerId": "integer",
"callerName": "string",
"callerAvatar": "string",
"calleeId": "integer",
"calleeName": "string",
"calleeAvatar": "string",
"status": "string",
"duration": "integer",
"startTime": "long",
"endTime": "long",
"endReason": "string"
}
}
```
---
## 功能说明
### 通话类型
| 类型 | 值 | 说明 |
|------|-----|------|
| 语音通话 | voice | 仅语音通话 |
| 视频通话 | video | 视频+语音通话 |
### 通话状态
| 状态 | 值 | 说明 |
|------|-----|------|
| 呼叫中 | calling | 正在呼叫对方 |
| 振铃中 | ringing | 对方正在振铃 |
| 通话中 | connected | 通话已接通 |
| 已完成 | completed | 通话正常结束 |
| 未接听 | missed | 对方未接听 |
| 已拒绝 | rejected | 对方拒绝接听 |
| 已取消 | cancelled | 主叫方取消 |
| 已结束 | ended | 通话结束 |
### 通话方向
| 方向 | 值 | 说明 |
|------|-----|------|
| 呼出 | outgoing | 我发起的通话 |
| 呼入 | incoming | 对方发起的通话 |
---
## 通话流程
### 发起通话流程
```
1. 用户A点击通话按钮
2. 调用发起通话接口
3. 获取callId和信令服务器地址
4. 连接信令服务器
5. 等待对方响应
6. 对方接听 → 建立P2P连接 → 开始通话
对方拒绝/超时 → 结束流程
```
### 接听通话流程
```
1. 用户B收到来电通知WebSocket推送
2. 显示来电界面
3. 用户点击接听按钮
4. 调用接听通话接口
5. 连接信令服务器
6. 建立P2P连接
7. 开始通话
```
### 结束通话流程
```
1. 用户点击挂断按钮
2. 调用结束通话接口
3. 断开P2P连接
4. 断开信令连接
5. 保存通话记录
6. 返回上一页面
```
---
## WebSocket推送
通话相关的实时通知通过WebSocket推送
### 来电通知
```json
{
"type": "incoming_call",
"callId": "call123",
"callType": "video",
"callerId": 123,
"callerName": "张三",
"callerAvatar": "https://..."
}
```
### 通话状态变化
```json
{
"type": "call_status",
"callId": "call123",
"status": "connected",
"timestamp": 1703001234567
}
```
### 对方挂断
```json
{
"type": "call_ended",
"callId": "call123",
"endReason": "normal",
"duration": 120
}
```
---
## 使用示例
### 1. 发起语音通话
```java
private void initiateVoiceCall(int calleeId) {
CallApiService callApiService = // 获取CallApiService实例
InitiateCallRequest request = new InitiateCallRequest(calleeId, "voice");
Call<CallApiResponse<InitiateCallResponse>> call =
callApiService.initiateCall(request);
call.enqueue(new Callback<CallApiResponse<InitiateCallResponse>>() {
@Override
public void onResponse(Call<CallApiResponse<InitiateCallResponse>> call,
Response<CallApiResponse<InitiateCallResponse>> response) {
if (response.isSuccessful() && response.body() != null) {
CallApiResponse<InitiateCallResponse> apiResponse = response.body();
if (apiResponse.getCode() == 200) {
InitiateCallResponse data = apiResponse.getData();
String callId = data.getCallId();
String signalingUrl = data.getSignalingUrl();
// 跳转到通话界面
Intent intent = new Intent(this, CallActivity.class);
intent.putExtra("callId", callId);
intent.putExtra("callType", "voice");
intent.putExtra("signalingUrl", signalingUrl);
startActivity(intent);
}
}
}
@Override
public void onFailure(Call<CallApiResponse<InitiateCallResponse>> call, Throwable t) {
Toast.makeText(this, "发起通话失败", Toast.LENGTH_SHORT).show();
}
});
}
```
### 2. 接听通话
```java
private void acceptCall(String callId) {
CallApiService callApiService = // 获取CallApiService实例
Call<CallApiResponse<Boolean>> call = callApiService.acceptCall(callId);
call.enqueue(new Callback<CallApiResponse<Boolean>>() {
@Override
public void onResponse(Call<CallApiResponse<Boolean>> call,
Response<CallApiResponse<Boolean>> response) {
if (response.isSuccessful() && response.body() != null) {
CallApiResponse<Boolean> apiResponse = response.body();
if (apiResponse.getCode() == 200) {
// 跳转到通话界面
Intent intent = new Intent(this, CallActivity.class);
intent.putExtra("callId", callId);
startActivity(intent);
finish();
}
}
}
@Override
public void onFailure(Call<CallApiResponse<Boolean>> call, Throwable t) {
Toast.makeText(this, "接听失败", Toast.LENGTH_SHORT).show();
}
});
}
```
### 3. 获取通话记录
```java
private void loadCallHistory(int page) {
CallApiService callApiService = // 获取CallApiService实例
Call<CallApiResponse<CallHistoryResponse>> call =
callApiService.getCallHistory(page, 20);
call.enqueue(new Callback<CallApiResponse<CallHistoryResponse>>() {
@Override
public void onResponse(Call<CallApiResponse<CallHistoryResponse>> call,
Response<CallApiResponse<CallHistoryResponse>> response) {
if (response.isSuccessful() && response.body() != null) {
CallApiResponse<CallHistoryResponse> apiResponse = response.body();
if (apiResponse.getCode() == 200) {
CallHistoryResponse data = apiResponse.getData();
List<CallRecordResponse> records = data.getRecords();
// 更新UI显示通话记录
updateCallHistoryList(records);
}
}
}
@Override
public void onFailure(Call<CallApiResponse<CallHistoryResponse>> call, Throwable t) {
Toast.makeText(this, "加载失败", Toast.LENGTH_SHORT).show();
}
});
}
```
---
## 技术实现
### WebRTC集成
通话功能基于WebRTC技术实现
- 使用信令服务器交换SDP和ICE候选
- 建立P2P连接进行音视频传输
- 支持NAT穿透
### 权限要求
- 语音通话:`RECORD_AUDIO`
- 视频通话:`RECORD_AUDIO` + `CAMERA`
- 网络访问:`INTERNET`
---
## 注意事项
1. 所有接口都需要登录认证
2. 通话前需要检查对方是否在线
3. 需要申请音频和摄像头权限
4. 通话过程中保持屏幕常亮
5. 通话时禁用锁屏
6. 建议使用耳机以获得更好的通话质量
7. 通话记录保存30天
8. 未接来电会显示红点提示
9. 通话过程中网络断开需要自动重连
10. 需要集成WebRTC库实现音视频通话