Commit 07f3bab72acd11b3469ff708ac5b2a1e71430616

Authored by YunaiV
1 parent d0aac382

✨ feat(im): 将后端的 roomName 和 callId 融合,简化字段和逻辑(一致性更好、概念更简洁)

Showing 17 changed files with 150 additions and 192 deletions
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/rtc/ImRtcCallController.java
... ... @@ -26,7 +26,6 @@ import java.util.Set;
26 26 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
27 27 import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
28 28  
29   -// TODO @AI:需要讨论,到底使用 roomName 还是 callId 更好?前端传参;然后,DO 那种,是不是只存储 callId,roomName 二选 1,是不是就行了。或者统一成 room?uuid 完事;callid 还给 call.id 更好理解;
30 29 @Tag(name = "管理后台 - IM 实时通话")
31 30 @RestController
32 31 @RequestMapping("/im/rtc")
... ... @@ -47,9 +46,9 @@ public class ImRtcCallController {
47 46  
48 47 @PostMapping("/join")
49 48 @Operation(summary = "加入已有群通话;用于胶囊条「加入」按钮")
50   - @Parameter(name = "roomName", description = "LiveKit 房间名", required = true, example = "im_rtc_call_xxxx")
51   - public CommonResult<ImRtcCallRespVO> joinCall(@RequestParam("roomName") String roomName) {
52   - ImRtcCallDO call = rtcCallService.joinCall(getLoginUserId(), roomName);
  49 + @Parameter(name = "room", description = "业务通话编号", required = true, example = "f47ac10b58cc4372a567")
  50 + public CommonResult<ImRtcCallRespVO> joinCall(@RequestParam("room") String room) {
  51 + ImRtcCallDO call = rtcCallService.joinCall(getLoginUserId(), room);
53 52 return success(buildCallResp(call, getLoginUserId()));
54 53 }
55 54  
... ... @@ -62,41 +61,41 @@ public class ImRtcCallController {
62 61  
63 62 @PostMapping("/accept")
64 63 @Operation(summary = "接听通话")
65   - @Parameter(name = "roomName", description = "LiveKit 房间名", required = true, example = "call_friend_1_2")
66   - public CommonResult<ImRtcCallRespVO> accept(@RequestParam("roomName") String roomName) {
67   - ImRtcCallDO call = rtcCallService.acceptCall(getLoginUserId(), roomName);
  64 + @Parameter(name = "room", description = "业务通话编号", required = true, example = "f47ac10b58cc4372a567")
  65 + public CommonResult<ImRtcCallRespVO> accept(@RequestParam("room") String room) {
  66 + ImRtcCallDO call = rtcCallService.acceptCall(getLoginUserId(), room);
68 67 return success(buildCallResp(call, getLoginUserId()));
69 68 }
70 69  
71 70 @PostMapping("/reject")
72 71 @Operation(summary = "拒绝通话")
73   - @Parameter(name = "roomName", description = "LiveKit 房间名", required = true, example = "call_friend_1_2")
74   - public CommonResult<Boolean> reject(@RequestParam("roomName") String roomName) {
75   - rtcCallService.rejectCall(getLoginUserId(), roomName);
  72 + @Parameter(name = "room", description = "业务通话编号", required = true, example = "f47ac10b58cc4372a567")
  73 + public CommonResult<Boolean> reject(@RequestParam("room") String room) {
  74 + rtcCallService.rejectCall(getLoginUserId(), room);
76 75 return success(true);
77 76 }
78 77  
79 78 @PostMapping("/cancel")
80 79 @Operation(summary = "取消邀请;主叫接通前调用")
81   - @Parameter(name = "roomName", description = "LiveKit 房间名", required = true, example = "call_friend_1_2")
82   - public CommonResult<Boolean> cancel(@RequestParam("roomName") String roomName) {
83   - rtcCallService.cancelCall(getLoginUserId(), roomName);
  80 + @Parameter(name = "room", description = "业务通话编号", required = true, example = "f47ac10b58cc4372a567")
  81 + public CommonResult<Boolean> cancel(@RequestParam("room") String room) {
  82 + rtcCallService.cancelCall(getLoginUserId(), room);
84 83 return success(true);
85 84 }
86 85  
87 86 @PostMapping("/leave")
88 87 @Operation(summary = "离开通话;接通后调用")
89   - @Parameter(name = "roomName", description = "LiveKit 房间名", required = true, example = "call_friend_1_2")
90   - public CommonResult<Boolean> leave(@RequestParam("roomName") String roomName) {
91   - rtcCallService.leaveCall(getLoginUserId(), roomName);
  88 + @Parameter(name = "room", description = "业务通话编号", required = true, example = "f47ac10b58cc4372a567")
  89 + public CommonResult<Boolean> leave(@RequestParam("room") String room) {
  90 + rtcCallService.leaveCall(getLoginUserId(), room);
92 91 return success(true);
93 92 }
94 93  
95 94 @GetMapping("/refresh-token")
96 95 @Operation(summary = "重新签发 Token;客户端重连或 Token 过期续期")
97   - @Parameter(name = "roomName", description = "LiveKit 房间名", required = true, example = "call_friend_1_2")
98   - public CommonResult<ImRtcCallRespVO> refreshToken(@RequestParam("roomName") String roomName) {
99   - ImRtcCallDO call = rtcCallService.refreshCallToken(getLoginUserId(), roomName);
  96 + @Parameter(name = "room", description = "业务通话编号", required = true, example = "f47ac10b58cc4372a567")
  97 + public CommonResult<ImRtcCallRespVO> refreshToken(@RequestParam("room") String room) {
  98 + ImRtcCallDO call = rtcCallService.refreshCallToken(getLoginUserId(), room);
100 99 return success(buildCallResp(call, getLoginUserId()));
101 100 }
102 101  
... ... @@ -114,11 +113,11 @@ public class ImRtcCallController {
114 113 if (call == null) {
115 114 return null;
116 115 }
117   - List<ImRtcParticipantDO> participants = rtcCallService.getCallParticipants(call.getCallId());
  116 + List<ImRtcParticipantDO> participants = rtcCallService.getCallParticipants(call.getRoom());
118 117 return new ImRtcCallRespVO()
119   - .setCallId(call.getCallId()).setRoomName(call.getRoomName())
  118 + .setRoom(call.getRoom())
120 119 .setLivekitUrl(imProperties.getRtc().getLivekitUrl())
121   - .setToken(rtcCallService.signCallToken(userId, call.getRoomName()))
  120 + .setToken(rtcCallService.signCallToken(userId, call.getRoom()))
122 121 .setScene(call.getConversationType()).setMediaType(call.getMediaType())
123 122 .setStatus(call.getStatus()).setInviterId(call.getInviterUserId())
124 123 .setGroupId(call.getGroupId())
... ... @@ -130,9 +129,9 @@ public class ImRtcCallController {
130 129 if (call == null) {
131 130 return null;
132 131 }
133   - List<ImRtcParticipantDO> participants = rtcCallService.getCallParticipants(call.getCallId());
  132 + List<ImRtcParticipantDO> participants = rtcCallService.getCallParticipants(call.getRoom());
134 133 return new ImRtcGroupCallRespVO()
135   - .setCallId(call.getCallId()).setRoomName(call.getRoomName())
  134 + .setRoom(call.getRoom())
136 135 .setGroupId(call.getGroupId()).setMediaType(call.getMediaType())
137 136 .setInviterId(call.getInviterUserId())
138 137 .setJoinedUserIds(filterUserIds(participants, ImRtcParticipantStatusEnum.JOINED))
... ...
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/rtc/ImRtcLiveKitController.java
... ... @@ -57,7 +57,7 @@ public class ImRtcLiveKitController {
57 57 }
58 58  
59 59 // 2. 交给 service 处理;幂等由 service 自己保证
60   - log.info("[webhook][事件处理 event={} roomName={}]", event.getEvent(),
  60 + log.info("[webhook][事件处理 event={} room={}]", event.getEvent(),
61 61 event.getRoom() == null ? null : event.getRoom().getName());
62 62 try {
63 63 rtcCallService.handleLiveKitEvent(event);
... ...
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/rtc/vo/ImRtcCallInviteMoreReqVO.java
... ... @@ -11,11 +11,10 @@ import java.util.Set;
11 11 @Data
12 12 public class ImRtcCallInviteMoreReqVO {
13 13  
14   - @Schema(description = "LiveKit 房间名", requiredMode = Schema.RequiredMode.REQUIRED, example = "call_group_2048")
15   - @NotBlank(message = "房间名不能为空")
16   - private String roomName;
  14 + @Schema(description = "业务通话编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "f47ac10b58cc4372a567")
  15 + @NotBlank(message = "通话编号不能为空")
  16 + private String room;
17 17  
18   - // TODO @AI:targetIds?
19 18 @Schema(description = "新邀请的用户编号集合", requiredMode = Schema.RequiredMode.REQUIRED)
20 19 @NotEmpty(message = "请至少选择一位成员")
21 20 private Set<Long> inviteeIds;
... ...
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/rtc/vo/ImRtcCallRespVO.java
... ... @@ -10,10 +10,7 @@ import java.util.Set;
10 10 public class ImRtcCallRespVO {
11 11  
12 12 @Schema(description = "业务通话编号")
13   - private String callId;
14   -
15   - @Schema(description = "LiveKit 房间名")
16   - private String roomName;
  13 + private String room;
17 14  
18 15 @Schema(description = "LiveKit Server WebSocket 地址;前端 connect 用")
19 16 private String livekitUrl;
... ...
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/controller/admin/rtc/vo/ImRtcGroupCallRespVO.java
... ... @@ -10,10 +10,7 @@ import java.util.Set;
10 10 public class ImRtcGroupCallRespVO {
11 11  
12 12 @Schema(description = "业务通话编号")
13   - private String callId;
14   -
15   - @Schema(description = "LiveKit 房间名")
16   - private String roomName;
  13 + private String room;
17 14  
18 15 @Schema(description = "群编号")
19 16 private Long groupId;
... ...
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/rtc/ImRtcCallDO.java
... ... @@ -16,7 +16,7 @@ import java.time.LocalDateTime;
16 16 /**
17 17 * IM 通话记录 DO(房间级 / 主表)
18 18 * <p>
19   - * 一通通话一行;状态机 CREATED → RUNNING → ENDED;和明细表 {@link ImRtcParticipantDO} 通过 callId 关联
  19 + * 一通通话一行;状态机 CREATED → RUNNING → ENDED;和明细表 {@link ImRtcParticipantDO} 通过 {@link #room} 关联
20 20 *
21 21 * @author 芋道源码
22 22 */
... ... @@ -31,25 +31,14 @@ import java.time.LocalDateTime;
31 31 public class ImRtcCallDO extends BaseDO {
32 32  
33 33 /**
34   - * LiveKit 房间名前缀;roomName 格式固定为 {@code ROOM_NAME_PREFIX + callId}
35   - */
36   - public static final String ROOM_NAME_PREFIX = "im_rtc_call_";
37   -
38   - /**
39 34 * 编号
40 35 */
41 36 @TableId
42 37 private Long id;
43 38 /**
44   - * 业务通话编号;唯一;UUID 生成
45   - */
46   - private String callId;
47   - /**
48   - * LiveKit 房间名
49   - *
50   - * 格式 {@code im_rtc_call_{callId}}
  39 + * 业务通话编号(UUID,同时作为 LiveKit 房间名);唯一
51 40 */
52   - private String roomName;
  41 + private String room;
53 42 /**
54 43 * 会话类型
55 44 *
... ...
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/dataobject/rtc/ImRtcParticipantDO.java
... ... @@ -13,7 +13,7 @@ import java.time.LocalDateTime;
13 13 /**
14 14 * IM 通话参与者 DO(用户级 / 明细表)
15 15 * <p>
16   - * 一通通话每个参与者一行;通过 callId 关联主表 {@link ImRtcCallDO}
  16 + * 一通通话每个参与者一行;通过 {@link #room} 关联主表 {@link ImRtcCallDO}
17 17 * <p>
18 18 * 终态闭合:通话 ENDED 时所有明细 status 必属 {LEFT / REJECTED / NO_ANSWER} 之一
19 19 *
... ... @@ -37,9 +37,9 @@ public class ImRtcParticipantDO extends BaseDO {
37 37 /**
38 38 * 业务通话编号
39 39 * <p>
40   - * 关联 {@link ImRtcCallDO#getCallId()}
  40 + * 关联 {@link ImRtcCallDO#getRoom()}
41 41 */
42   - private String callId;
  42 + private String room;
43 43 /**
44 44 * 参与者用户编号
45 45 * <p>
... ...
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/rtc/ImRtcCallMapper.java
... ... @@ -18,12 +18,8 @@ import java.util.List;
18 18 @Mapper
19 19 public interface ImRtcCallMapper extends BaseMapperX<ImRtcCallDO> {
20 20  
21   - default ImRtcCallDO selectByCallId(String callId) {
22   - return selectOne(ImRtcCallDO::getCallId, callId);
23   - }
24   -
25   - default ImRtcCallDO selectByRoomName(String roomName) {
26   - return selectOne(ImRtcCallDO::getRoomName, roomName);
  21 + default ImRtcCallDO selectByRoom(String room) {
  22 + return selectOne(ImRtcCallDO::getRoom, room);
27 23 }
28 24  
29 25 default ImRtcCallDO selectLastOneByGroupIdAndStatusIn(Long groupId, Collection<Integer> statuses) {
... ...
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/dal/mysql/rtc/ImRtcParticipantMapper.java
... ... @@ -17,19 +17,19 @@ import java.util.List;
17 17 @Mapper
18 18 public interface ImRtcParticipantMapper extends BaseMapperX<ImRtcParticipantDO> {
19 19  
20   - default ImRtcParticipantDO selectByCallIdAndUserId(String callId, Long userId) {
  20 + default ImRtcParticipantDO selectByRoomAndUserId(String room, Long userId) {
21 21 return selectOne(new LambdaQueryWrapperX<ImRtcParticipantDO>()
22   - .eq(ImRtcParticipantDO::getCallId, callId)
  22 + .eq(ImRtcParticipantDO::getRoom, room)
23 23 .eq(ImRtcParticipantDO::getUserId, userId));
24 24 }
25 25  
26   - default List<ImRtcParticipantDO> selectListByCallId(String callId) {
27   - return selectList(ImRtcParticipantDO::getCallId, callId);
  26 + default List<ImRtcParticipantDO> selectListByRoom(String room) {
  27 + return selectList(ImRtcParticipantDO::getRoom, room);
28 28 }
29 29  
30   - default List<ImRtcParticipantDO> selectListByCallIdAndStatus(String callId, Integer status) {
  30 + default List<ImRtcParticipantDO> selectListByRoomAndStatus(String room, Integer status) {
31 31 return selectList(new LambdaQueryWrapperX<ImRtcParticipantDO>()
32   - .eq(ImRtcParticipantDO::getCallId, callId)
  32 + .eq(ImRtcParticipantDO::getRoom, room)
33 33 .eq(ImRtcParticipantDO::getStatus, status));
34 34 }
35 35  
... ... @@ -47,9 +47,9 @@ public interface ImRtcParticipantMapper extends BaseMapperX&lt;ImRtcParticipantDO&gt;
47 47 }
48 48  
49 49 @SuppressWarnings("UnusedReturnValue")
50   - default int updateByCallIdAndStatus(String callId, Integer oldStatus, ImRtcParticipantDO updateObj) {
  50 + default int updateByRoomAndStatus(String room, Integer oldStatus, ImRtcParticipantDO updateObj) {
51 51 return update(updateObj, Wrappers.<ImRtcParticipantDO>lambdaUpdate()
52   - .eq(ImRtcParticipantDO::getCallId, callId)
  52 + .eq(ImRtcParticipantDO::getRoom, room)
53 53 .eq(ImRtcParticipantDO::getStatus, oldStatus));
54 54 }
55 55  
... ...
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/framework/rtc/core/LiveKitClient.java
... ... @@ -62,18 +62,18 @@ public class LiveKitClient {
62 62 *
63 63 * @param identity 用户唯一标识;写入 sub claim;同 identity 重连会踢前一个连接
64 64 * @param displayName 客户端展示名;可空
65   - * @param roomName 房间名
  65 + * @param room 房间名
66 66 * @return JWT 字符串
67 67 */
68   - public String signJoinToken(String identity, String displayName, String roomName) {
  68 + public String signJoinToken(String identity, String displayName, String room) {
69 69 Assert.notBlank(identity, "identity 不可为空");
70   - Assert.notBlank(roomName, "roomName 不可为空");
  70 + Assert.notBlank(room, "room 不可为空");
71 71 ImProperties.Rtc cfg = imProperties.getRtc();
72 72  
73 73 // video claim:限定客户端能在该房间内做什么
74 74 Map<String, Object> video = new HashMap<>();
75 75 video.put("roomJoin", true); // 允许加入房间
76   - video.put("room", roomName); // 限定只能加入这个房间
  76 + video.put("room", room); // 限定只能加入这个房间
77 77 video.put("canPublish", true); // 允许发布媒体(推流)
78 78 video.put("canSubscribe", true); // 允许订阅媒体(拉流)
79 79 video.put("canPublishData", true); // 允许发送 data channel 消息
... ... @@ -96,11 +96,11 @@ public class LiveKitClient {
96 96 /**
97 97 * 调用 LiveKit Server API 删除房间:用于通话结束时,强制断开异常残留客户端
98 98 *
99   - * @param roomName 房间名
  99 + * @param room 房间名
100 100 */
101 101 @SuppressWarnings("EmptyTryBlock")
102   - public void deleteRoom(String roomName) {
103   - try (HttpResponse ignored = postTwirp(TWIRP_DELETE_ROOM, roomName)) {
  102 + public void deleteRoom(String room) {
  103 + try (HttpResponse ignored = postTwirp(TWIRP_DELETE_ROOM, room)) {
104 104 // 状态码不区分;调用方失败即兜底
105 105 }
106 106 }
... ... @@ -110,17 +110,17 @@ public class LiveKitClient {
110 110 * <p>
111 111 * 房间不存在 LiveKit 返回 404,视同 0 人
112 112 *
113   - * @param roomName 房间名
  113 + * @param room 房间名
114 114 * @return 参与者数量;HTTP 失败返回 -1
115 115 */
116   - public int listParticipants(String roomName) {
117   - try (HttpResponse response = postTwirp(TWIRP_LIST_PARTICIPANTS, roomName)) {
  116 + public int listParticipants(String room) {
  117 + try (HttpResponse response = postTwirp(TWIRP_LIST_PARTICIPANTS, room)) {
118 118 if (response.getStatus() == 404) {
119 119 return 0;
120 120 }
121 121 if (!response.isOk()) {
122   - log.warn("[listParticipants][LiveKit 返回非 2xx status={} roomName={} body={}]",
123   - response.getStatus(), roomName, response.body());
  122 + log.warn("[listParticipants][LiveKit 返回非 2xx status={} room={} body={}]",
  123 + response.getStatus(), room, response.body());
124 124 return -1;
125 125 }
126 126 JSONArray participants = JSONUtil.parseObj(response.body()).getJSONArray("participants");
... ... @@ -223,16 +223,16 @@ public class LiveKitClient {
223 223 * Twirp 协议 POST 调用;统一处理 ws→http 协议切换、签 admin token、Bearer 头、JSON body、超时
224 224 *
225 225 * @param path Twirp 端点路径,例如 {@code /twirp/livekit.RoomService/DeleteRoom}
226   - * @param roomName 房间名;写入 JSON body 的 room 字段
  226 + * @param room 房间名;写入 JSON body 的 room 字段
227 227 * @return HTTP 响应;调用方负责 close 与状态码判断
228 228 */
229   - private HttpResponse postTwirp(String path, String roomName) {
230   - Assert.notBlank(roomName, "roomName 不可为空");
  229 + private HttpResponse postTwirp(String path, String room) {
  230 + Assert.notBlank(room, "room 不可为空");
231 231 String token = signAdminToken();
232 232 return HttpRequest.post(HttpUtils.wsUrlToHttp(imProperties.getRtc().getLivekitUrl()) + path)
233 233 .header("Authorization", "Bearer " + token)
234 234 .header("Content-Type", "application/json")
235   - .body(JSONUtil.toJsonStr(Map.of("room", roomName)))
  235 + .body(JSONUtil.toJsonStr(Map.of("room", room)))
236 236 .timeout(SERVER_API_TIMEOUT_MS)
237 237 .execute();
238 238 }
... ...
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/rtc/ImRtcCallService.java
... ... @@ -28,17 +28,17 @@ public interface ImRtcCallService {
28 28 /**
29 29 * 加入已有群通话:用于群胶囊条「加入」按钮;旁观者作为 ACTIVE_JOIN 加入,邀请池内成员转 JOINED
30 30 *
31   - * @param userId 加入者用户编号
32   - * @param roomName LiveKit 房间名;从胶囊条 activeCall 拿
  31 + * @param userId 加入者用户编号
  32 + * @param room 业务通话编号;从胶囊条 activeCall 拿
33 33 * @return 通话主表
34 34 */
35   - ImRtcCallDO joinCall(Long userId, String roomName);
  35 + ImRtcCallDO joinCall(Long userId, String room);
36 36  
37 37 /**
38 38 * 通话中追加成员:仅群通话场景可用;给新邀请人推 RTC_CALL(INVITE)
39 39 *
40 40 * @param userId 操作人编号;必须是当前会话参与者
41   - * @param reqVO 房间名 + 新邀请的用户编号集合
  41 + * @param reqVO room + 新邀请的用户编号集合
42 42 */
43 43 void inviteMoreCall(Long userId, ImRtcCallInviteMoreReqVO reqVO);
44 44  
... ... @@ -47,22 +47,22 @@ public interface ImRtcCallService {
47 47 *
48 48 * @return 通话主表
49 49 */
50   - ImRtcCallDO acceptCall(Long userId, String roomName);
  50 + ImRtcCallDO acceptCall(Long userId, String room);
51 51  
52 52 /**
53 53 * 拒绝通话;仅 INVITING 状态可拒;群通话拒绝等同于不参与,房间仍存在
54 54 */
55   - void rejectCall(Long userId, String roomName);
  55 + void rejectCall(Long userId, String room);
56 56  
57 57 /**
58 58 * 取消邀请;主叫在 INVITING 状态主动取消
59 59 */
60   - void cancelCall(Long userId, String roomName);
  60 + void cancelCall(Long userId, String room);
61 61  
62 62 /**
63 63 * 离开通话;RUNNING 状态下离开;私聊任一方离开 = 通话结束;群通话最后一人离开才结束
64 64 */
65   - void leaveCall(Long userId, String roomName);
  65 + void leaveCall(Long userId, String room);
66 66  
67 67 /**
68 68 * 校验用户仍是该通话的参与者,用于客户端重连或 Token 过期续期前的合法性检查;
... ... @@ -70,7 +70,7 @@ public interface ImRtcCallService {
70 70 *
71 71 * @return 通话主表
72 72 */
73   - ImRtcCallDO refreshCallToken(Long userId, String roomName);
  73 + ImRtcCallDO refreshCallToken(Long userId, String room);
74 74  
75 75 /**
76 76 * 查询当前正在进行的通话;目前仅群聊场景(胶囊条),私聊未来扩展再补 peerUserId 参数
... ... @@ -86,19 +86,19 @@ public interface ImRtcCallService {
86 86 /**
87 87 * 查询某通话的全部参与者明细;交给 Controller 拼装 inviteeIds / joinedUserIds
88 88 *
89   - * @param callId 业务通话编号
  89 + * @param room 业务通话编号
90 90 * @return 参与者明细列表
91 91 */
92   - List<ImRtcParticipantDO> getCallParticipants(String callId);
  92 + List<ImRtcParticipantDO> getCallParticipants(String room);
93 93  
94 94 /**
95 95 * 签发指定用户进入该通话的 LiveKit Token;供 Controller 拼接到响应 VO
96 96 *
97   - * @param userId 进房用户编号;token 内 displayName 取该用户昵称
98   - * @param roomName LiveKit 房间名
  97 + * @param userId 进房用户编号;token 内 displayName 取该用户昵称
  98 + * @param room 业务通话编号
99 99 * @return JWT 字符串
100 100 */
101   - String signCallToken(Long userId, String roomName);
  101 + String signCallToken(Long userId, String room);
102 102  
103 103 /**
104 104 * 处理 LiveKit Webhook 事件;用于关 tab / 强杀 / 网络断开等异常退出场景的兜底清理
... ...
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/rtc/ImRtcCallServiceImpl.java
... ... @@ -155,28 +155,26 @@ public class ImRtcCallServiceImpl implements ImRtcCallService {
155 155 * @return 通话主表
156 156 */
157 157 private ImRtcCallDO createCall(Long inviterId, ImRtcCallInviteReqVO reqVO) {
158   - // 1. 构造参数:派生 callId / roomName,解析被邀请池(私聊单元素;群聊 invitee 子集或全员)
159   - // TODO @AI:callId、roomName 都抽成小方法。
160   - String callId = IdUtil.fastSimpleUUID();
161   - String roomName = ImRtcCallDO.ROOM_NAME_PREFIX + callId;
  158 + // 1. 构造参数:room 用 UUID;解析被邀请池
  159 + String room = IdUtil.fastSimpleUUID();
162 160 LocalDateTime now = LocalDateTime.now();
163 161 Set<Long> invitees = resolveInvitees(reqVO, inviterId);
164 162  
165 163 // 2.1 INSERT 主表;群聊发起人即时 JOINED 但通话仍处 CREATED,等首个非发起人接通才切 RUNNING
166   - ImRtcCallDO call = new ImRtcCallDO().setCallId(callId).setRoomName(roomName)
  164 + ImRtcCallDO call = new ImRtcCallDO().setRoom(room)
167 165 .setConversationType(reqVO.getScene()).setMediaType(reqVO.getMediaType())
168 166 .setInviterUserId(inviterId).setGroupId(reqVO.getGroupId())
169 167 .setStatus(ImRtcCallStatusEnum.CREATED.getStatus()).setStartTime(now);
170 168 rtcCallMapper.insert(call);
171 169 // 2.2 批量 INSERT 参与表:发起人即时 JOINED,被邀请人 INVITING 等接通
172 170 List<ImRtcParticipantDO> participants = new ArrayList<>(invitees.size() + 1);
173   - participants.add(new ImRtcParticipantDO().setCallId(callId).setUserId(inviterId)
  171 + participants.add(new ImRtcParticipantDO().setRoom(room).setUserId(inviterId)
174 172 .setRole(ImRtcParticipantRoleEnum.INVITER.getRole())
175 173 .setStatus(ImRtcParticipantStatusEnum.JOINED.getStatus())
176 174 .setInviteTime(now).setAcceptTime(now));
177 175 for (Long inviteeId : invitees) {
178 176 participants.add(new ImRtcParticipantDO()
179   - .setCallId(callId).setUserId(inviteeId)
  177 + .setRoom(room).setUserId(inviteeId)
180 178 .setRole(ImRtcParticipantRoleEnum.INVITEE.getRole())
181 179 .setStatus(ImRtcParticipantStatusEnum.INVITING.getStatus())
182 180 .setInviteTime(now));
... ... @@ -197,10 +195,10 @@ public class ImRtcCallServiceImpl implements ImRtcCallService {
197 195 }
198 196  
199 197 @Override
200   - public ImRtcCallDO joinCall(Long userId, String roomName) {
  198 + public ImRtcCallDO joinCall(Long userId, String room) {
201 199 ensureEnabled();
202 200 // 1.1 校验通话存在且活跃
203   - ImRtcCallDO call = validateCallActive(roomName);
  201 + ImRtcCallDO call = validateCallActive(room);
204 202 // 1.2 仅群通话支持「旁观者加入」
205 203 if (!ImConversationTypeEnum.isGroup(call.getConversationType())) {
206 204 throw exception(RTC_GROUP_REQUIRED);
... ... @@ -208,7 +206,7 @@ public class ImRtcCallServiceImpl implements ImRtcCallService {
208 206  
209 207 // 2. 入参与表:已有记录切回 JOINED;不在记录则以 ACTIVE_JOIN 角色 INSERT
210 208 LocalDateTime now = LocalDateTime.now();
211   - ImRtcParticipantDO existing = rtcParticipantMapper.selectByCallIdAndUserId(call.getCallId(), userId);
  209 + ImRtcParticipantDO existing = rtcParticipantMapper.selectByRoomAndUserId(call.getRoom(), userId);
212 210 if (existing != null) {
213 211 // 非 JOINED 状态切回 JOINED + accept_time;INVITER / INVITEE 重连 / 旁观点胶囊条都走这条
214 212 if (!ImRtcParticipantStatusEnum.isJoined(existing.getStatus())) {
... ... @@ -217,7 +215,7 @@ public class ImRtcCallServiceImpl implements ImRtcCallService {
217 215 }
218 216 } else {
219 217 // 旁观者主动加入:INSERT role=ACTIVE_JOIN
220   - rtcParticipantMapper.insert(new ImRtcParticipantDO().setCallId(call.getCallId())
  218 + rtcParticipantMapper.insert(new ImRtcParticipantDO().setRoom(call.getRoom())
221 219 .setUserId(userId).setRole(ImRtcParticipantRoleEnum.ACTIVE_JOIN.getRole())
222 220 .setStatus(ImRtcParticipantStatusEnum.JOINED.getStatus()).setInviteTime(now).setAcceptTime(now));
223 221 }
... ... @@ -231,13 +229,13 @@ public class ImRtcCallServiceImpl implements ImRtcCallService {
231 229 public void inviteMoreCall(Long userId, ImRtcCallInviteMoreReqVO reqVO) {
232 230 ensureEnabled();
233 231 // TODO @AI:校验的,按照 1.1 1.2 1.3 这样;
234   - ImRtcCallDO call = validateCallActive(reqVO.getRoomName());
  232 + ImRtcCallDO call = validateCallActive(reqVO.getRoom());
235 233 // 仅群通话支持追加邀请
236 234 if (!ImConversationTypeEnum.isGroup(call.getConversationType())) {
237 235 throw exception(RTC_GROUP_REQUIRED);
238 236 }
239 237 // 操作者必须是已在房间的参与者
240   - ImRtcParticipantDO operator = rtcParticipantMapper.selectByCallIdAndUserId(call.getCallId(), userId);
  238 + ImRtcParticipantDO operator = rtcParticipantMapper.selectByRoomAndUserId(call.getRoom(), userId);
241 239 if (operator == null || !ImRtcParticipantStatusEnum.isJoined(operator.getStatus())) {
242 240 throw exception(RTC_NOT_PARTICIPANT);
243 241 }
... ... @@ -246,7 +244,7 @@ public class ImRtcCallServiceImpl implements ImRtcCallService {
246 244 Set<Long> validMemberIds = new LinkedHashSet<>(
247 245 groupMemberService.getActiveGroupMemberUserIdsByGroupId(call.getGroupId()));
248 246 // TODO @AI:convertSet;
249   - Set<Long> existingUserIds = rtcParticipantMapper.selectListByCallId(call.getCallId()).stream()
  247 + Set<Long> existingUserIds = rtcParticipantMapper.selectListByRoom(call.getRoom()).stream()
250 248 .map(ImRtcParticipantDO::getUserId)
251 249 .collect(Collectors.toSet());
252 250 // TODO @AI:incomingUserIds;直接 remove 原始的元素;没必要;单独的;
... ... @@ -262,7 +260,7 @@ public class ImRtcCallServiceImpl implements ImRtcCallService {
262 260 LocalDateTime now = LocalDateTime.now();
263 261 for (Long inviteeId : incoming) {
264 262 rtcParticipantMapper.insert(new ImRtcParticipantDO()
265   - .setCallId(call.getCallId()).setUserId(inviteeId)
  263 + .setRoom(call.getRoom()).setUserId(inviteeId)
266 264 .setRole(ImRtcParticipantRoleEnum.INVITEE.getRole())
267 265 .setStatus(ImRtcParticipantStatusEnum.INVITING.getStatus())
268 266 .setInviteTime(now));
... ... @@ -276,11 +274,11 @@ public class ImRtcCallServiceImpl implements ImRtcCallService {
276 274 }
277 275  
278 276 @Override
279   - public ImRtcCallDO acceptCall(Long userId, String roomName) {
  277 + public ImRtcCallDO acceptCall(Long userId, String room) {
280 278 ensureEnabled();
281 279 // TODO @AI:按照 inviteMoreCall 风格,优化下注释;
282   - ImRtcCallDO call = validateCallActive(roomName);
283   - ImRtcParticipantDO participant = rtcParticipantMapper.selectByCallIdAndUserId(call.getCallId(), userId);
  280 + ImRtcCallDO call = validateCallActive(room);
  281 + ImRtcParticipantDO participant = rtcParticipantMapper.selectByRoomAndUserId(call.getRoom(), userId);
284 282 if (participant == null) {
285 283 throw exception(RTC_NOT_PARTICIPANT);
286 284 }
... ... @@ -305,11 +303,11 @@ public class ImRtcCallServiceImpl implements ImRtcCallService {
305 303 }
306 304  
307 305 @Override
308   - public void rejectCall(Long userId, String roomName) {
  306 + public void rejectCall(Long userId, String room) {
309 307 ensureEnabled();
310 308 // TODO @AI:按照 inviteMoreCall 风格,优化下注释;
311   - ImRtcCallDO call = validateCallActive(roomName);
312   - ImRtcParticipantDO participant = rtcParticipantMapper.selectByCallIdAndUserId(call.getCallId(), userId);
  309 + ImRtcCallDO call = validateCallActive(room);
  310 + ImRtcParticipantDO participant = rtcParticipantMapper.selectByRoomAndUserId(call.getRoom(), userId);
313 311 if (participant == null) {
314 312 throw exception(RTC_NOT_PARTICIPANT);
315 313 }
... ... @@ -337,10 +335,10 @@ public class ImRtcCallServiceImpl implements ImRtcCallService {
337 335 }
338 336  
339 337 @Override
340   - public void cancelCall(Long userId, String roomName) {
  338 + public void cancelCall(Long userId, String room) {
341 339 ensureEnabled();
342 340 // TODO @AI:按照 inviteMoreCall 风格,优化下注释;
343   - ImRtcCallDO call = validateCallActive(roomName);
  341 + ImRtcCallDO call = validateCallActive(room);
344 342 // TODO @AI:notEquals;
345 343 if (!Objects.equals(call.getInviterUserId(), userId)) {
346 344 throw exception(RTC_NOT_PARTICIPANT);
... ... @@ -355,11 +353,11 @@ public class ImRtcCallServiceImpl implements ImRtcCallService {
355 353 }
356 354  
357 355 @Override
358   - public void leaveCall(Long userId, String roomName) {
  356 + public void leaveCall(Long userId, String room) {
359 357 ensureEnabled();
360 358 // TODO @AI:按照 inviteMoreCall 风格,优化下注释;
361   - ImRtcCallDO call = validateCallActive(roomName);
362   - ImRtcParticipantDO participant = rtcParticipantMapper.selectByCallIdAndUserId(call.getCallId(), userId);
  359 + ImRtcCallDO call = validateCallActive(room);
  360 + ImRtcParticipantDO participant = rtcParticipantMapper.selectByRoomAndUserId(call.getRoom(), userId);
363 361 if (participant == null) {
364 362 throw exception(RTC_NOT_PARTICIPANT);
365 363 }
... ... @@ -373,7 +371,7 @@ public class ImRtcCallServiceImpl implements ImRtcCallService {
373 371 // TODO @AI:群聊的关房,本质和单聊,是不是一样的?是否有必要统一掉?
374 372 // 关房条件:私聊任一方离开 = 关;群通话仅在「无人在房 + 无人响铃」时关
375 373 if (ImConversationTypeEnum.isPrivate(call.getConversationType())
376   - || shouldCloseGroupRoom(call.getCallId())) {
  374 + || shouldCloseGroupRoom(call.getRoom())) {
377 375 endSession(call, userId, ImRtcCallEndReasonEnum.HANGUP);
378 376 }
379 377 // 群通话单人离开:LiveKit `ParticipantDisconnected` 自动通知房内成员;业务后端不另外推
... ... @@ -386,9 +384,9 @@ public class ImRtcCallServiceImpl implements ImRtcCallService {
386 384 * <p>
387 385 * 关房后 endSession 会把残留 INVITING 批量改 NO_ANSWER 并推 RTC_CALL_END,响铃端 UI 自动收敛
388 386 */
389   - private boolean shouldCloseGroupRoom(String callId) {
  387 + private boolean shouldCloseGroupRoom(String room) {
390 388 // TODO @AI:通过查询,计算情况?;感觉所有群聊的关闭条件:都是只有 1 个 join,剩余都处于结束,说白了没人可以和他电话了。。。。
391   - List<ImRtcParticipantDO> joined = rtcParticipantMapper.selectListByCallIdAndStatus(callId,
  389 + List<ImRtcParticipantDO> joined = rtcParticipantMapper.selectListByRoomAndStatus(room,
392 390 ImRtcParticipantStatusEnum.JOINED.getStatus());
393 391 return CollUtil.isEmpty(joined);
394 392 }
... ... @@ -406,13 +404,13 @@ public class ImRtcCallServiceImpl implements ImRtcCallService {
406 404 if (aPart == null) {
407 405 return null;
408 406 }
409   - ImRtcCallDO call = rtcCallMapper.selectByCallId(aPart.getCallId());
  407 + ImRtcCallDO call = rtcCallMapper.selectByRoom(aPart.getRoom());
410 408 if (call == null
411 409 || !ImConversationTypeEnum.isPrivate(call.getConversationType())
412 410 || ImRtcCallStatusEnum.isEnded(call.getStatus())) {
413 411 return null;
414 412 }
415   - ImRtcParticipantDO bPart = rtcParticipantMapper.selectByCallIdAndUserId(call.getCallId(), userIdB);
  413 + ImRtcParticipantDO bPart = rtcParticipantMapper.selectByRoomAndUserId(call.getRoom(), userIdB);
416 414 if (bPart == null
417 415 || !ImRtcParticipantStatusEnum.ACTIVE_STATUSES.contains(bPart.getStatus())) {
418 416 return null;
... ... @@ -422,11 +420,11 @@ public class ImRtcCallServiceImpl implements ImRtcCallService {
422 420  
423 421 // TODO @AI:怎么感觉这个要改下?是不是根据 userid + callid 更合理?
424 422 @Override
425   - public ImRtcCallDO refreshCallToken(Long userId, String roomName) {
  423 + public ImRtcCallDO refreshCallToken(Long userId, String room) {
426 424 ensureEnabled();
427 425 // TODO @AI:按照 inviteMoreCall 风格,优化下注释;
428   - ImRtcCallDO call = validateCallActive(roomName);
429   - ImRtcParticipantDO participant = rtcParticipantMapper.selectByCallIdAndUserId(call.getCallId(), userId);
  426 + ImRtcCallDO call = validateCallActive(room);
  427 + ImRtcParticipantDO participant = rtcParticipantMapper.selectByRoomAndUserId(call.getRoom(), userId);
430 428 if (participant == null) {
431 429 throw exception(RTC_NOT_PARTICIPANT);
432 430 }
... ... @@ -444,16 +442,16 @@ public class ImRtcCallServiceImpl implements ImRtcCallService {
444 442  
445 443 // TODO @AI:方法名,复数应该使用 List,不使用 s;
446 444 @Override
447   - public List<ImRtcParticipantDO> getCallParticipants(String callId) {
448   - return rtcParticipantMapper.selectListByCallId(callId);
  445 + public List<ImRtcParticipantDO> getCallParticipants(String room) {
  446 + return rtcParticipantMapper.selectListByRoom(room);
449 447 }
450 448  
451 449 @Override
452   - public String signCallToken(Long userId, String roomName) {
  450 + public String signCallToken(Long userId, String room) {
453 451 AdminUserRespDTO user = adminUserApi.getUser(userId);
454 452 // TODO @AI:不能为空。。。nickname 为空,则使用 userid;
455 453 String displayName = user == null ? null : user.getNickname();
456   - return signToken(userId, displayName, roomName);
  454 + return signToken(userId, displayName, room);
457 455 }
458 456  
459 457 // TODO DONE @AI:兼容 JDK8 —— 项目 Spring Boot 3 已要求 JDK17+,switch arrow case 可直接用
... ... @@ -483,8 +481,8 @@ public class ImRtcCallServiceImpl implements ImRtcCallService {
483 481 return;
484 482 }
485 483 // 前置检查
486   - String roomName = event.getRoom().getName();
487   - ImRtcCallDO call = rtcCallMapper.selectByRoomName(roomName);
  484 + String room = event.getRoom().getName();
  485 + ImRtcCallDO call = rtcCallMapper.selectByRoom(room);
488 486 if (call == null || ImRtcCallStatusEnum.isEnded(call.getStatus())) {
489 487 return;
490 488 }
... ... @@ -506,8 +504,8 @@ public class ImRtcCallServiceImpl implements ImRtcCallService {
506 504 return;
507 505 }
508 506 // 前置检查
509   - String roomName = event.getRoom().getName();
510   - ImRtcCallDO call = rtcCallMapper.selectByRoomName(roomName);
  507 + String room = event.getRoom().getName();
  508 + ImRtcCallDO call = rtcCallMapper.selectByRoom(room);
511 509 if (call == null || ImRtcCallStatusEnum.isEnded(call.getStatus())) {
512 510 return;
513 511 }
... ... @@ -515,7 +513,7 @@ public class ImRtcCallServiceImpl implements ImRtcCallService {
515 513 if (userId == null) {
516 514 return;
517 515 }
518   - ImRtcParticipantDO participant = rtcParticipantMapper.selectByCallIdAndUserId(call.getCallId(), userId);
  516 + ImRtcParticipantDO participant = rtcParticipantMapper.selectByRoomAndUserId(call.getRoom(), userId);
519 517 if (participant == null || !ImRtcParticipantStatusEnum.isJoined(participant.getStatus())) {
520 518 return;
521 519 }
... ... @@ -526,14 +524,14 @@ public class ImRtcCallServiceImpl implements ImRtcCallService {
526 524 if (updated == 0) {
527 525 return;
528 526 }
529   - log.info("[handleParticipantLeft][roomName={} userId={} 由 LiveKit Webhook 兜底]", roomName, userId);
  527 + log.info("[handleParticipantLeft][room={} userId={} 由 LiveKit Webhook 兜底]", room, userId);
530 528  
531 529 // 推 1603 通知参与方 / 全群参与方
532 530 pushParticipantDisconnectedNotification(call, userId);
533 531 // 关房条件与 leave 一致;群通话仅在「无人在房 + 无人响铃」时关
534 532 // TODO @AI:注释风格;感觉可以抽个 endSessionIfXXX;收口更统一;
535 533 if (ImConversationTypeEnum.isPrivate(call.getConversationType())
536   - || shouldCloseGroupRoom(call.getCallId())) {
  534 + || shouldCloseGroupRoom(call.getRoom())) {
537 535 endSession(call, userId, ImRtcCallEndReasonEnum.HANGUP);
538 536 }
539 537 }
... ... @@ -546,14 +544,14 @@ public class ImRtcCallServiceImpl implements ImRtcCallService {
546 544 return;
547 545 }
548 546 // 前置检查
549   - String roomName = event.getRoom().getName();
550   - ImRtcCallDO call = rtcCallMapper.selectByRoomName(roomName);
  547 + String room = event.getRoom().getName();
  548 + ImRtcCallDO call = rtcCallMapper.selectByRoom(room);
551 549 if (call == null || ImRtcCallStatusEnum.isEnded(call.getStatus())) {
552 550 return;
553 551 }
554 552  
555 553 // TODO @AI:注释。带序号的;
556   - log.info("[handleRoomFinished][roomName={} 由 LiveKit Webhook 兜底]", roomName);
  554 + log.info("[handleRoomFinished][room={} 由 LiveKit Webhook 兜底]", room);
557 555 endSession(call, null, ImRtcCallEndReasonEnum.HANGUP);
558 556 }
559 557  
... ... @@ -572,17 +570,15 @@ public class ImRtcCallServiceImpl implements ImRtcCallService {
572 570 for (ImRtcCallDO call : candidates) {
573 571 int count;
574 572 try {
575   - count = liveKitClient.listParticipants(call.getRoomName());
  573 + count = liveKitClient.listParticipants(call.getRoom());
576 574 } catch (Exception e) {
577   - log.warn("[cleanupZombieCalls][查询 LiveKit 失败 callId={} roomName={}]",
578   - call.getCallId(), call.getRoomName(), e);
  575 + log.warn("[cleanupZombieCalls][查询 LiveKit 失败 room={}]", call.getRoom(), e);
579 576 continue;
580 577 }
581 578 if (count != 0) {
582 579 continue;
583 580 }
584   - log.info("[cleanupZombieCalls][清理僵尸通话 callId={} roomName={}]",
585   - call.getCallId(), call.getRoomName());
  581 + log.info("[cleanupZombieCalls][清理僵尸通话 room={}]", call.getRoom());
586 582 endSession(call, null, ImRtcCallEndReasonEnum.HANGUP);
587 583 cleaned++;
588 584 }
... ... @@ -604,8 +600,8 @@ public class ImRtcCallServiceImpl implements ImRtcCallService {
604 600 /**
605 601 * 校验通话存在且活跃:不存在 / 已 ENDED 直接抛
606 602 */
607   - private ImRtcCallDO validateCallActive(String roomName) {
608   - ImRtcCallDO call = rtcCallMapper.selectByRoomName(roomName);
  603 + private ImRtcCallDO validateCallActive(String room) {
  604 + ImRtcCallDO call = rtcCallMapper.selectByRoom(room);
609 605 if (call == null || ImRtcCallStatusEnum.isEnded(call.getStatus())) {
610 606 throw exception(RTC_SESSION_NOT_EXISTS);
611 607 }
... ... @@ -729,29 +725,29 @@ public class ImRtcCallServiceImpl implements ImRtcCallService {
729 725 new ImRtcCallDO().setStatus(ImRtcCallStatusEnum.ENDED.getStatus())
730 726 .setEndReason(reason.getReason()).setEndTime(now));
731 727 if (updated == 0) {
732   - log.info("[endSession][已被另一路径终结,跳过 callId={} roomName={} operator={} reason={}]",
733   - call.getCallId(), call.getRoomName(), operatorId, reason);
  728 + log.info("[endSession][已被另一路径终结,跳过 room={} operator={} reason={}]",
  729 + call.getRoom(), operatorId, reason);
734 730 return;
735 731 }
736 732 // 1.2 更新参与表为已结束:残留 INVITING 改 NO_ANSWER;残留 JOINED 改 LEFT 并写 leaveTime
737   - rtcParticipantMapper.updateByCallIdAndStatus(call.getCallId(), ImRtcParticipantStatusEnum.INVITING.getStatus(),
  733 + rtcParticipantMapper.updateByRoomAndStatus(call.getRoom(), ImRtcParticipantStatusEnum.INVITING.getStatus(),
738 734 new ImRtcParticipantDO().setStatus(ImRtcParticipantStatusEnum.NO_ANSWER.getStatus()));
739   - rtcParticipantMapper.updateByCallIdAndStatus(call.getCallId(), ImRtcParticipantStatusEnum.JOINED.getStatus(),
  735 + rtcParticipantMapper.updateByRoomAndStatus(call.getRoom(), ImRtcParticipantStatusEnum.JOINED.getStatus(),
740 736 new ImRtcParticipantDO().setStatus(ImRtcParticipantStatusEnum.LEFT.getStatus()).setLeaveTime(now));
741 737  
742 738 // 2. 兜底删除 LiveKit 房间,强制断开异常残留客户端;失败仅记日志,不阻断业务
743 739 try {
744   - liveKitClient.deleteRoom(call.getRoomName());
  740 + liveKitClient.deleteRoom(call.getRoom());
745 741 } catch (Exception e) {
746   - log.warn("[endSession][删除 LiveKit 房间失败 callId={} roomName={} operator={} reason={}]",
747   - call.getCallId(), call.getRoomName(), operatorId, reason, e);
  742 + log.warn("[endSession][删除 LiveKit 房间失败 room={} operator={} reason={}]",
  743 + call.getRoom(), operatorId, reason, e);
748 744 }
749 745  
750 746 // 3. 推 RTC_CALL_END
751 747 Long durationSeconds = call.getAcceptTime() != null ?
752 748 Duration.between(call.getAcceptTime(), now).getSeconds() : null;
753 749 pushCallEndNotification(call, operatorId, reason, durationSeconds);
754   - log.info("[endSession][roomName={} operator={} reason={}]", call.getRoomName(), operatorId, reason);
  750 + log.info("[endSession][room={} operator={} reason={}]", call.getRoom(), operatorId, reason);
755 751 }
756 752  
757 753 // TODO @AI:getCallAudienceUserIdList?
... ... @@ -765,7 +761,7 @@ public class ImRtcCallServiceImpl implements ImRtcCallService {
765 761 return groupMemberService.getActiveGroupMemberUserIdsByGroupId(call.getGroupId());
766 762 }
767 763 return CollectionUtils.convertSet(
768   - rtcParticipantMapper.selectListByCallId(call.getCallId()), ImRtcParticipantDO::getUserId);
  764 + rtcParticipantMapper.selectListByRoom(call.getRoom()), ImRtcParticipantDO::getUserId);
769 765 }
770 766  
771 767 // TODO @AI:这里的 ========== 太短了;
... ... @@ -779,7 +775,7 @@ public class ImRtcCallServiceImpl implements ImRtcCallService {
779 775 * 不能走 imPrivateMessageService.send:persistent=false 时 send 仅推 sender 多端,receiver 不感知
780 776 */
781 777 private void pushCallInviteNotification(ImRtcCallDO call, AdminUserRespDTO inviter, Long inviteeId) {
782   - String token = signToken(inviteeId, inviter == null ? null : inviter.getNickname(), call.getRoomName());
  778 + String token = signToken(inviteeId, inviter == null ? null : inviter.getNickname(), call.getRoom());
783 779 ImRtcCallNotification payload = ImRtcCallNotification.ofInvite(
784 780 call, inviter, imProperties.getRtc().getLivekitUrl(), token);
785 781 webSocketService.sendPrivateMessageAsync(inviteeId, ImPrivateMessageDTO.ofRtcNotification(
... ... @@ -865,7 +861,7 @@ public class ImRtcCallServiceImpl implements ImRtcCallService {
865 861  
866 862 // 私聊:发起人总是 sender;receiver = 通话另一方
867 863 ImRtcParticipantDO peer = CollUtil.findOne(
868   - rtcParticipantMapper.selectListByCallId(call.getCallId()),
  864 + rtcParticipantMapper.selectListByRoom(call.getRoom()),
869 865 p -> !Objects.equals(p.getUserId(), senderId));
870 866 Long receiverId = peer != null ? peer.getUserId() : senderId;
871 867 ImPrivateMessageSendDTO dto = new ImPrivateMessageSendDTO().setReceiverId(receiverId)
... ... @@ -879,9 +875,9 @@ public class ImRtcCallServiceImpl implements ImRtcCallService {
879 875 * 签 LiveKit Token
880 876 */
881 877 // TODO @AI:sign 方法,是不是传递 adminuserdo?
882   - private String signToken(Long userId, String displayName, String roomName) {
883   - // TODO @AI:是不是抽一个 signJoinToken(userid, displayName, roomName)做减法
884   - return liveKitClient.signJoinToken(liveKitClient.buildIdentity(userId), displayName, roomName);
  878 + private String signToken(Long userId, String displayName, String room) {
  879 + // TODO @AI:是不是抽一个 signJoinToken(userid, displayName, room)做减法
  880 + return liveKitClient.signJoinToken(liveKitClient.buildIdentity(userId), displayName, room);
885 881 }
886 882  
887 883 }
... ...
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/dto/notification/rtc/ImRtcCallEndNotification.java
... ... @@ -25,7 +25,7 @@ public class ImRtcCallEndNotification {
25 25 /**
26 26 * 业务通话编号
27 27 */
28   - private String callId;
  28 + private String room;
29 29 /**
30 30 * 会话类型
31 31 */
... ... @@ -60,7 +60,7 @@ public class ImRtcCallEndNotification {
60 60 public static ImRtcCallEndNotification of(ImRtcCallDO call, ImRtcCallEndReasonEnum reason, Long durationSeconds,
61 61 Long operatorId, AdminUserRespDTO operator) {
62 62 ImRtcCallEndNotification notification = new ImRtcCallEndNotification();
63   - notification.callId = call.getCallId();
  63 + notification.room = call.getRoom();
64 64 notification.conversationType = call.getConversationType();
65 65 notification.mediaType = call.getMediaType();
66 66 notification.endReason = reason.getReason();
... ...
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/dto/notification/rtc/ImRtcCallNotification.java
... ... @@ -27,11 +27,7 @@ public class ImRtcCallNotification {
27 27 /**
28 28 * 业务通话编号
29 29 */
30   - private String callId;
31   - /**
32   - * LiveKit 房间名
33   - */
34   - private String roomName;
  30 + private String room;
35 31 /**
36 32 * 会话类型
37 33 */
... ... @@ -176,8 +172,7 @@ public class ImRtcCallNotification {
176 172 private static ImRtcCallNotification baseOf(ImRtcCallDO call, Integer status) {
177 173 ImRtcCallNotification notification = new ImRtcCallNotification();
178 174 notification.status = status;
179   - notification.callId = call.getCallId();
180   - notification.roomName = call.getRoomName();
  175 + notification.room = call.getRoom();
181 176 notification.conversationType = call.getConversationType();
182 177 notification.mediaType = call.getMediaType();
183 178 notification.groupId = call.getGroupId();
... ...
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/dto/notification/rtc/ImRtcCallStartNotification.java
... ... @@ -23,7 +23,7 @@ public class ImRtcCallStartNotification {
23 23 /**
24 24 * 业务通话编号
25 25 */
26   - private String callId;
  26 + private String room;
27 27 /**
28 28 * 会话类型:当前固定 GROUP(私聊无 START)
29 29 */
... ... @@ -47,7 +47,7 @@ public class ImRtcCallStartNotification {
47 47  
48 48 public static ImRtcCallStartNotification of(ImRtcCallDO call, AdminUserRespDTO inviter) {
49 49 ImRtcCallStartNotification notification = new ImRtcCallStartNotification();
50   - notification.callId = call.getCallId();
  50 + notification.room = call.getRoom();
51 51 notification.conversationType = call.getConversationType();
52 52 notification.mediaType = call.getMediaType();
53 53 notification.inviterUserId = call.getInviterUserId();
... ...
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/dto/notification/rtc/ImRtcParticipantConnectedNotification.java
... ... @@ -18,11 +18,7 @@ public class ImRtcParticipantConnectedNotification {
18 18 /**
19 19 * 业务通话编号
20 20 */
21   - private String callId;
22   - /**
23   - * LiveKit 房间名
24   - */
25   - private String roomName;
  21 + private String room;
26 22 /**
27 23 * 加入的参与者用户编号
28 24 */
... ... @@ -53,8 +49,7 @@ public class ImRtcParticipantConnectedNotification {
53 49 */
54 50 public static ImRtcParticipantConnectedNotification of(ImRtcCallDO call, Long userId) {
55 51 ImRtcParticipantConnectedNotification notification = new ImRtcParticipantConnectedNotification();
56   - notification.callId = call.getCallId();
57   - notification.roomName = call.getRoomName();
  52 + notification.room = call.getRoom();
58 53 notification.userId = userId;
59 54 notification.conversationType = call.getConversationType();
60 55 notification.groupId = call.getGroupId();
... ...
yudao-module-im/src/main/java/cn/iocoder/yudao/module/im/service/websocket/dto/notification/rtc/ImRtcParticipantDisconnectedNotification.java
... ... @@ -18,11 +18,7 @@ public class ImRtcParticipantDisconnectedNotification {
18 18 /**
19 19 * 业务通话编号
20 20 */
21   - private String callId;
22   - /**
23   - * LiveKit 房间名
24   - */
25   - private String roomName;
  21 + private String room;
26 22 /**
27 23 * 离开的参与者用户编号
28 24 */
... ... @@ -45,8 +41,7 @@ public class ImRtcParticipantDisconnectedNotification {
45 41 */
46 42 public static ImRtcParticipantDisconnectedNotification of(ImRtcCallDO call, Long userId) {
47 43 ImRtcParticipantDisconnectedNotification notification = new ImRtcParticipantDisconnectedNotification();
48   - notification.callId = call.getCallId();
49   - notification.roomName = call.getRoomName();
  44 + notification.room = call.getRoom();
50 45 notification.userId = userId;
51 46 notification.conversationType = call.getConversationType();
52 47 notification.groupId = call.getGroupId();
... ...