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