package cn.iocoder.yudao.module.im.service.websocket.notification.rtc;
import cn.iocoder.yudao.module.im.dal.dataobject.rtc.ImRtcCallDO;
import cn.iocoder.yudao.module.im.enums.rtc.ImRtcParticipantStatusEnum;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import lombok.Data;
import java.util.Collection;
import java.util.List;
/**
* RTC_CALL 通话信令通知(通话信令统一入口)
*
* 不入库;走 imWebSocketService 仅推参与方
*
* status 字段复用 {@link ImRtcParticipantStatusEnum},表达「本次信令对应的参与者状态变迁」
*
* @author 芋道源码
*/
@Data
public class ImRtcCallNotification {
/**
* 信令对应的参与者状态
*
* 取值参见 {@link ImRtcParticipantStatusEnum}
*/
private Integer status;
/**
* 业务通话编号
*/
private String room;
/**
* 会话类型
*/
private Integer conversationType;
/**
* 媒体类型
*/
private Integer mediaType;
/**
* 群编号:群通话场景必填
*/
private Long groupId;
// ========== INVITE 专属字段 ==========
/**
* LiveKit Server WebSocket 地址;INVITE 专属
*/
private String livekitUrl;
/**
* 该被叫专属的 LiveKit 接听 Token;接通后直接 connect 用;INVITE 专属
*/
private String token;
/**
* 发起人用户编号;INVITE 专属
*/
private Long inviterUserId;
/**
* 发起人昵称;INVITE 专属,前端来电界面展示
*/
private String inviterNickname;
/**
* 发起人头像;INVITE 专属,前端来电界面展示
*/
private String inviterAvatar;
/**
* 本次被邀请人列表;INVITE 专属,前端来电界面展示「邀请的其他人」
*
* 注意:包含收件人自身,前端按需过滤
*/
private List inviteeIds;
// ========== REJECT 专属字段 ==========
/**
* 操作者用户编号;REJECT 触发本次状态变迁的人
*/
private Long operatorUserId;
/**
* 操作者昵称;前端按需展示(被某某拒接);普通文案不依赖
*/
private String operatorNickname;
/**
* 操作者头像;前端按需展示;普通文案不依赖
*/
private String operatorAvatar;
/**
* 构造 INVITE 信令;推被邀请人,invitee 状态变为 INVITING
*
* @param call 通话主表
* @param inviter 发起人;可空,缺失时 inviterNickname / inviterAvatar 留空
* @param livekitUrl LiveKit Server WebSocket 地址
* @param token 被叫的接听 Token;按收件人单独签发
* @param inviteeIds 本次被邀请人列表;前端来电界面展示「邀请的其他人」用
* @return INVITE 信令
*/
public static ImRtcCallNotification ofInvite(ImRtcCallDO call, AdminUserRespDTO inviter,
String livekitUrl, String token,
Collection inviteeIds) {
ImRtcCallNotification notification = baseOf(call, ImRtcParticipantStatusEnum.INVITING.getStatus());
notification.livekitUrl = livekitUrl;
notification.token = token;
notification.inviterUserId = call.getInviterUserId();
if (inviter != null) {
notification.inviterNickname = inviter.getNickname();
notification.inviterAvatar = inviter.getAvatar();
}
notification.inviteeIds = inviteeIds != null ? new java.util.ArrayList<>(inviteeIds) : null;
return notification;
}
/**
* 构造 REJECT 信令;仅群通话场景;推主叫
*
* @param call 通话主表
* @param operatorUserId 拒接者用户编号
* @param operator 拒接者;可空,缺失时 operatorNickname / operatorAvatar 留空
* @return REJECT 信令
*/
public static ImRtcCallNotification ofReject(ImRtcCallDO call, Long operatorUserId, AdminUserRespDTO operator) {
ImRtcCallNotification notification = baseOf(call, ImRtcParticipantStatusEnum.REJECTED.getStatus());
notification.operatorUserId = operatorUserId;
if (operator != null) {
notification.operatorNickname = operator.getNickname();
notification.operatorAvatar = operator.getAvatar();
}
return notification;
}
/**
* 构造 NO_ANSWER 信令;仅群通话场景;推主叫;超时未接听语义独立于 REJECT
*
* @param call 通话主表
* @param operatorUserId 未接听者用户编号
* @param operator 未接听者;可空,缺失时 operatorNickname / operatorAvatar 留空
* @return NO_ANSWER 信令
*/
public static ImRtcCallNotification ofNoAnswer(ImRtcCallDO call, Long operatorUserId, AdminUserRespDTO operator) {
ImRtcCallNotification notification = baseOf(call, ImRtcParticipantStatusEnum.NO_ANSWER.getStatus());
notification.operatorUserId = operatorUserId;
if (operator != null) {
notification.operatorNickname = operator.getNickname();
notification.operatorAvatar = operator.getAvatar();
}
return notification;
}
/**
* 公共骨架;填充 call 上下文 + status
*/
private static ImRtcCallNotification baseOf(ImRtcCallDO call, Integer status) {
ImRtcCallNotification notification = new ImRtcCallNotification();
notification.status = status;
notification.room = call.getRoom();
notification.conversationType = call.getConversationType();
notification.mediaType = call.getMediaType();
notification.groupId = call.getGroupId();
return notification;
}
}