zhibo/Zhibo/zhibo-h/直播间下播清空在线人数功能说明.md

393 lines
8.3 KiB
Markdown
Raw Normal View History

2025-12-29 15:12:12 +08:00
# 直播间下播清空在线人数功能说明
> **实现时间**: 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
**状态**: ✅ 生产就绪