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

8.3 KiB
Raw Blame History

直播间下播清空在线人数功能说明

实现时间: 2024-12-29
功能: 主播下播时自动清空在线人数并通知观众
状态: 已完成


📋 功能概述

当主播关闭直播时,系统会自动执行以下操作:

  1. 通知所有观众 - 通过WebSocket发送"主播已下播"消息
  2. 清空内存数据 - 清空房间的所有WebSocket连接
  3. 重置数据库 - 将数据库中的online_count字段设置为0
  4. 防止数据残留 - 确保下次开播时在线人数从0开始

🔧 实现细节

1. 数据库字段更新

LiveRoomServiceImpl.setLiveStatus()方法中,当直播关闭时:

// 如果直播关闭将数据库中的在线人数设置为0
if (!isLive) {
    uw.set(LiveRoom::getOnlineCount, 0);
}

SQL执行效果

UPDATE eb_live_room 
SET is_live = 0, 
    started_at = NULL, 
    online_count = 0  -- 重置在线人数
WHERE stream_key = ?

2. WebSocket通知观众

LiveRoomOnlineServiceImpl.clearRoomAndNotify()方法中:

// 创建直播结束通知消息
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());

前端收到的消息格式

{
  "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类型的消息:

websocket.onmessage = function(event) {
    const data = JSON.parse(event.data);
    
    if (data.type === 'live_ended') {
        // 显示提示
        showToast(data.message); // "主播已下播"
        
        // 更新UI
        updateOnlineCount(0);
        
        // 关闭直播播放器
        stopPlayer();
        
        // 可选:跳转到其他页面
        // navigateToLiveList();
    }
};

Android端处理示例

when (message.type) {
    "live_ended" -> {
        // 显示Toast提示
        Toast.makeText(context, message.message, Toast.LENGTH_LONG).show()
        
        // 更新在线人数为0
        binding.tvOnlineCount.text = "0"
        
        // 停止播放
        player.stop()
        
        // 可选:返回直播列表
        finish()
    }
}

🧪 测试步骤

1. 准备测试环境

# 启动后端服务
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. 观众加入

    • 打开多个浏览器/客户端
    • 连接WebSocketws://localhost:8080/ws/live/{roomId}?clientId=user_1
    • 观察在线人数增加
  4. 停止推流

    • 在OBS中停止推流
    • 观察以下变化:

预期结果

数据库变化

-- 查询直播间状态
SELECT id, is_live, online_count FROM eb_live_room WHERE id = ?;
-- 结果is_live=0, online_count=0

前端收到消息

{
  "type": "live_ended",
  "roomId": "123",
  "message": "主播已下播",
  "onlineCount": 0,
  "timestamp": 1703836800000
}

WebSocket连接关闭

  • 所有观众的WebSocket连接被服务器主动关闭
  • 前端显示"主播已下播"提示

内存数据清空

// 查询在线人数应该返回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延迟

// 等待消息发送完成
try {
    Thread.sleep(500);
} catch (InterruptedException e) {
    Thread.currentThread().interrupt();
}

2. 并发安全

使用ConcurrentHashMapsynchronized确保线程安全:

synchronized (session) {
    session.sendMessage(new TextMessage(endMessage));
}

3. 异常处理

所有操作都包含异常处理,确保部分失败不影响整体流程:

try {
    // 发送消息
} catch (Exception e) {
    log.error("发送直播结束通知失败", e);
    // 继续处理其他客户端
}

🚀 扩展功能建议

1. 自定义下播消息

可以在创建直播间时设置自定义下播消息:

// LiveRoom实体类添加字段
@Column(name = "end_message")
private String endMessage; // "感谢观看,下次再见!"

// 下播时使用自定义消息
String message = room.getEndMessage() != null 
    ? room.getEndMessage() 
    : "主播已下播";

2. 下播统计

记录每次直播的统计数据:

// 创建直播统计表
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. 推送通知

给关注主播的用户发送推送通知:

// 下播时通知关注者
notificationService.sendToFollowers(
    streamerId, 
    "您关注的主播已下播", 
    "感谢观看,下次再见!"
);

📝 相关文件

修改的文件

  1. LiveRoomService.java - 添加getRoomIdByStreamKey()方法
  2. LiveRoomServiceImpl.java - 实现下播时重置在线人数
  3. LiveRoomOnlineService.java - 添加clearRoomAndNotify()方法
  4. LiveRoomOnlineServiceImpl.java - 实现清空房间并通知功能

涉及的表

  • eb_live_room - 直播间表(更新online_count字段)

功能检查清单

  • 数据库在线人数重置为0
  • WebSocket通知所有观众
  • 清空内存中的连接数据
  • 关闭所有WebSocket连接
  • 日志记录完整
  • 异常处理完善
  • 并发安全保证
  • 下次开播人数从0开始

实现完成时间: 2024-12-29
开发者: Kiro AI Assistant
状态: 生产就绪