zhibo/Zhibo/zhibo-h/直播间下播清空在线人数功能说明.md
2025-12-29 15:12:12 +08:00

393 lines
8.3 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.

# 直播间下播清空在线人数功能说明
> **实现时间**: 2024-12-29
> **功能**: 主播下播时自动清空在线人数并通知观众
> **状态**: ✅ 已完成
---
## 📋 功能概述
当主播关闭直播时,系统会自动执行以下操作:
1.**通知所有观众** - 通过WebSocket发送"主播已下播"消息
2.**清空内存数据** - 清空房间的所有WebSocket连接
3.**重置数据库** - 将数据库中的`online_count`字段设置为0
4.**防止数据残留** - 确保下次开播时在线人数从0开始
---
## 🔧 实现细节
### 1. 数据库字段更新
在`LiveRoomServiceImpl.setLiveStatus()`方法中,当直播关闭时:
```java
// 如果直播关闭将数据库中的在线人数设置为0
if (!isLive) {
uw.set(LiveRoom::getOnlineCount, 0);
}
```
**SQL执行效果**
```sql
UPDATE eb_live_room
SET is_live = 0,
started_at = NULL,
online_count = 0 -- 重置在线人数
WHERE stream_key = ?
```
### 2. WebSocket通知观众
在`LiveRoomOnlineServiceImpl.clearRoomAndNotify()`方法中:
```java
// 创建直播结束通知消息
Map<String, Object> liveEndedMsg = new HashMap<>();
liveEndedMsg.put("type", "live_ended");
liveEndedMsg.put("roomId", roomId);
liveEndedMsg.put("message", "主播已下播");
liveEndedMsg.put("onlineCount", 0);
liveEndedMsg.put("timestamp", System.currentTimeMillis());
```
**前端收到的消息格式**
```json
{
"type": "live_ended",
"roomId": "123",
"message": "主播已下播",
"onlineCount": 0,
"timestamp": 1703836800000
}
```
### 3. 清空内存数据
系统会清空以下内存数据:
- `roomConnections` - 房间的所有WebSocket连接
- `roomUserCounts` - 房间的在线人数计数器
- `sessionRoomMap` - Session到房间的反向映射
---
## 🔄 执行流程
```
主播点击下播
SRS回调 /srs/on_unpublish
LiveRoomService.setLiveStatus(streamKey, false)
1. 更新数据库is_live=0, online_count=0
2. 获取房间ID
3. 调用 LiveRoomOnlineService.clearRoomAndNotify(roomId, "主播已下播")
4. 发送WebSocket消息给所有观众
5. 关闭所有WebSocket连接
6. 清空内存中的房间数据
完成
```
---
## 📡 前端接收处理
### WebSocket消息监听
前端需要监听`live_ended`类型的消息:
```javascript
websocket.onmessage = function(event) {
const data = JSON.parse(event.data);
if (data.type === 'live_ended') {
// 显示提示
showToast(data.message); // "主播已下播"
// 更新UI
updateOnlineCount(0);
// 关闭直播播放器
stopPlayer();
// 可选:跳转到其他页面
// navigateToLiveList();
}
};
```
### Android端处理示例
```kotlin
when (message.type) {
"live_ended" -> {
// 显示Toast提示
Toast.makeText(context, message.message, Toast.LENGTH_LONG).show()
// 更新在线人数为0
binding.tvOnlineCount.text = "0"
// 停止播放
player.stop()
// 可选:返回直播列表
finish()
}
}
```
---
## 🧪 测试步骤
### 1. 准备测试环境
```bash
# 启动后端服务
cd Zhibo/zhibo-h
mvn spring-boot:run
# 启动SRS服务器
cd live-streaming
./objs/srs -c conf/srs.conf
```
### 2. 测试流程
1. **创建直播间**
```
POST /api/front/live/room/create
{
"title": "测试直播",
"streamerName": "测试主播",
"categoryId": 1
}
```
2. **开始推流**
- 使用OBS推流到`rtmp://localhost:1935/live/{streamKey}`
- 观察数据库:`is_live=1`
3. **观众加入**
- 打开多个浏览器/客户端
- 连接WebSocket`ws://localhost:8080/ws/live/{roomId}?clientId=user_1`
- 观察在线人数增加
4. **停止推流**
- 在OBS中停止推流
- 观察以下变化:
**预期结果**
**数据库变化**
```sql
-- 查询直播间状态
SELECT id, is_live, online_count FROM eb_live_room WHERE id = ?;
-- 结果is_live=0, online_count=0
```
**前端收到消息**
```json
{
"type": "live_ended",
"roomId": "123",
"message": "主播已下播",
"onlineCount": 0,
"timestamp": 1703836800000
}
```
**WebSocket连接关闭**
- 所有观众的WebSocket连接被服务器主动关闭
- 前端显示"主播已下播"提示
**内存数据清空**
```java
// 查询在线人数应该返回0
GET /api/live/online/count/{roomId}
// 返回:{"code":200,"data":0}
```
### 3. 验证下次开播
1. **再次推流**
- 使用相同的streamKey推流
- 观察在线人数从0开始
2. **观众重新加入**
- 观众重新连接WebSocket
- 在线人数从1开始递增
---
## 📊 数据库表结构
### eb_live_room 表
| 字段 | 类型 | 说明 | 下播时的值 |
|------|------|------|-----------|
| id | INT | 主键 | 不变 |
| is_live | TINYINT | 是否直播中 | **0** |
| online_count | INT | 在线人数 | **0** ← 重置 |
| started_at | DATETIME | 开始时间 | **NULL** |
| stream_key | VARCHAR | 推流密钥 | 不变 |
---
## 🔍 日志输出
### 正常流程日志
```
[INFO] 直播间关闭,清空房间 123 的在线人数并通知观众
[INFO] 清空房间 123 的所有在线用户,当前人数: 5
[INFO] 已通知客户端 session-001 直播结束: 主播已下播
[INFO] 已通知客户端 session-002 直播结束: 主播已下播
[INFO] 已通知客户端 session-003 直播结束: 主播已下播
[INFO] 已通知客户端 session-004 直播结束: 主播已下播
[INFO] 已通知客户端 session-005 直播结束: 主播已下播
[INFO] 房间 123 已清空,所有用户已断开连接
```
### 异常情况日志
```
[WARN] Invalid roomId, cannot clear room
[ERROR] 发送直播结束通知失败: session-001
[ERROR] 关闭session失败: session-002
[ERROR] 清空房间失败: roomId=123
```
---
## ⚠️ 注意事项
### 1. 消息发送延迟
为确保消息发送完成代码中添加了500ms延迟
```java
// 等待消息发送完成
try {
Thread.sleep(500);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
```
### 2. 并发安全
使用`ConcurrentHashMap`和`synchronized`确保线程安全:
```java
synchronized (session) {
session.sendMessage(new TextMessage(endMessage));
}
```
### 3. 异常处理
所有操作都包含异常处理,确保部分失败不影响整体流程:
```java
try {
// 发送消息
} catch (Exception e) {
log.error("发送直播结束通知失败", e);
// 继续处理其他客户端
}
```
---
## 🚀 扩展功能建议
### 1. 自定义下播消息
可以在创建直播间时设置自定义下播消息:
```java
// LiveRoom实体类添加字段
@Column(name = "end_message")
private String endMessage; // "感谢观看,下次再见!"
// 下播时使用自定义消息
String message = room.getEndMessage() != null
? room.getEndMessage()
: "主播已下播";
```
### 2. 下播统计
记录每次直播的统计数据:
```java
// 创建直播统计表
CREATE TABLE eb_live_statistics (
id INT PRIMARY KEY AUTO_INCREMENT,
room_id INT,
start_time DATETIME,
end_time DATETIME,
max_online_count INT, -- 最高在线人数
total_viewers INT, -- 总观看人数
duration INT -- 直播时长
);
```
### 3. 推送通知
给关注主播的用户发送推送通知:
```java
// 下播时通知关注者
notificationService.sendToFollowers(
streamerId,
"您关注的主播已下播",
"感谢观看,下次再见!"
);
```
---
## 📝 相关文件
### 修改的文件
1. `LiveRoomService.java` - 添加`getRoomIdByStreamKey()`方法
2. `LiveRoomServiceImpl.java` - 实现下播时重置在线人数
3. `LiveRoomOnlineService.java` - 添加`clearRoomAndNotify()`方法
4. `LiveRoomOnlineServiceImpl.java` - 实现清空房间并通知功能
### 涉及的表
- `eb_live_room` - 直播间表(更新`online_count`字段)
---
## ✅ 功能检查清单
- [x] 数据库在线人数重置为0
- [x] WebSocket通知所有观众
- [x] 清空内存中的连接数据
- [x] 关闭所有WebSocket连接
- [x] 日志记录完整
- [x] 异常处理完善
- [x] 并发安全保证
- [x] 下次开播人数从0开始
---
**实现完成时间**: 2024-12-29
**开发者**: Kiro AI Assistant
**状态**: ✅ 生产就绪