rtc
This commit is contained in:
parent
1d2961c09a
commit
3bbaa78528
@ -46,6 +46,8 @@ red-circle:
|
|||||||
endpoint: ${LIKEI_TRTC_ENDPOINT}
|
endpoint: ${LIKEI_TRTC_ENDPOINT}
|
||||||
region: ${LIKEI_TRTC_REGION:ap-singapore}
|
region: ${LIKEI_TRTC_REGION:ap-singapore}
|
||||||
sdkAppId: ${LIKEI_TRTC_SDK_APP_ID}
|
sdkAppId: ${LIKEI_TRTC_SDK_APP_ID}
|
||||||
|
userSigKey: ${LIKEI_TRTC_USER_SIG_KEY:${LIKEI_TRTC_SECRET_KEY}}
|
||||||
|
userSigExpireSeconds: ${LIKEI_TRTC_USER_SIG_EXPIRE_SECOND:7200}
|
||||||
tencet-im:
|
tencet-im:
|
||||||
appId: ${LIKEI_IM_APP_ID}
|
appId: ${LIKEI_IM_APP_ID}
|
||||||
key: ${LIKEI_IM_KEY}
|
key: ${LIKEI_IM_KEY}
|
||||||
|
|||||||
@ -0,0 +1,74 @@
|
|||||||
|
package com.red.circle.common.business.dto.rtc;
|
||||||
|
|
||||||
|
import com.red.circle.framework.dto.ClientObject;
|
||||||
|
import java.io.Serial;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RTC credential returned to compatible clients.
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Accessors(chain = true)
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class RtcCredentialCO extends ClientObject {
|
||||||
|
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AGORA or TRTC.
|
||||||
|
*/
|
||||||
|
private String rtcProvider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Legacy Agora token.
|
||||||
|
*/
|
||||||
|
private String agoraToken;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Agora channel name, currently the business room id.
|
||||||
|
*/
|
||||||
|
private String agoraChannelName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tencent TRTC sdkAppId.
|
||||||
|
*/
|
||||||
|
private Long trtcSdkAppId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TRTC user id. Use business userId string.
|
||||||
|
*/
|
||||||
|
private String trtcUserId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TRTC UserSig.
|
||||||
|
*/
|
||||||
|
private String trtcUserSig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Numeric TRTC room id when available.
|
||||||
|
*/
|
||||||
|
private Long trtcRoomId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* String TRTC room id fallback.
|
||||||
|
*/
|
||||||
|
private String trtcStrRoomId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TRTC role: 20 anchor, 21 audience.
|
||||||
|
*/
|
||||||
|
private Integer trtcRole;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UserSig lifetime in seconds.
|
||||||
|
*/
|
||||||
|
private Long trtcUserSigExpireSeconds;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UserSig expire timestamp in milliseconds.
|
||||||
|
*/
|
||||||
|
private Long trtcUserSigExpireAt;
|
||||||
|
}
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
package com.red.circle.common.business.dto.rtc;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RTC provider used by voice rooms.
|
||||||
|
*/
|
||||||
|
public enum RtcProviderEnum {
|
||||||
|
AGORA,
|
||||||
|
TRTC;
|
||||||
|
|
||||||
|
public static RtcProviderEnum of(String provider) {
|
||||||
|
if (provider == null || provider.isBlank()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
for (RtcProviderEnum value : values()) {
|
||||||
|
if (value.name().equalsIgnoreCase(provider.trim())) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,66 @@
|
|||||||
|
package com.red.circle.common.business.dto.rtc;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Version based RTC compatibility rules.
|
||||||
|
*/
|
||||||
|
public final class RtcVersionSupport {
|
||||||
|
|
||||||
|
public static final String TRTC_MIN_VERSION = "1.4.0";
|
||||||
|
public static final String ROOM_PROVIDER_KEY_PREFIX = "RTC:ROOM:PROVIDER:";
|
||||||
|
public static final long ROOM_PROVIDER_TTL_SECONDS = 12 * 60 * 60L;
|
||||||
|
|
||||||
|
private RtcVersionSupport() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RtcProviderEnum defaultProvider(String version) {
|
||||||
|
return compareVersion(version, TRTC_MIN_VERSION) <= 0
|
||||||
|
? RtcProviderEnum.AGORA
|
||||||
|
: RtcProviderEnum.TRTC;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String roomProviderKey(Object roomId) {
|
||||||
|
return ROOM_PROVIDER_KEY_PREFIX + roomId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int compareVersion(String left, String right) {
|
||||||
|
int[] leftParts = parseVersion(left);
|
||||||
|
int[] rightParts = parseVersion(right);
|
||||||
|
int length = Math.max(leftParts.length, rightParts.length);
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
int leftPart = i < leftParts.length ? leftParts[i] : 0;
|
||||||
|
int rightPart = i < rightParts.length ? rightParts[i] : 0;
|
||||||
|
if (leftPart != rightPart) {
|
||||||
|
return Integer.compare(leftPart, rightPart);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int[] parseVersion(String version) {
|
||||||
|
if (version == null || version.isBlank()) {
|
||||||
|
return new int[]{0};
|
||||||
|
}
|
||||||
|
String normalized = version.trim().split("-", 2)[0];
|
||||||
|
String[] parts = normalized.split("\\.");
|
||||||
|
int[] values = new int[parts.length];
|
||||||
|
for (int i = 0; i < parts.length; i++) {
|
||||||
|
values[i] = parseVersionPart(parts[i]);
|
||||||
|
}
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int parseVersionPart(String part) {
|
||||||
|
if (part == null || part.isBlank()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
String digits = part.replaceAll("[^0-9].*$", "");
|
||||||
|
if (digits.isBlank()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return Integer.parseInt(digits);
|
||||||
|
} catch (NumberFormatException ignored) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,8 +1,9 @@
|
|||||||
package com.red.circle.external.inner.endpoint.message.api;
|
package com.red.circle.external.inner.endpoint.message.api;
|
||||||
|
|
||||||
import com.red.circle.external.inner.model.cmd.message.TrtcRemoveUserCmd;
|
import com.red.circle.common.business.dto.rtc.RtcCredentialCO;
|
||||||
import com.red.circle.external.inner.model.cmd.message.TrtcUserBlockedCmd;
|
import com.red.circle.external.inner.model.cmd.message.TrtcRemoveUserCmd;
|
||||||
import com.red.circle.framework.dto.ResultResponse;
|
import com.red.circle.external.inner.model.cmd.message.TrtcUserBlockedCmd;
|
||||||
|
import com.red.circle.framework.dto.ResultResponse;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
@ -50,10 +51,20 @@ public interface TrtcClientApi {
|
|||||||
@RequestParam("type") String channelName
|
@RequestParam("type") String channelName
|
||||||
);
|
);
|
||||||
|
|
||||||
@GetMapping("/createAgoraTokenGoUp")
|
@GetMapping("/createAgoraTokenGoUp")
|
||||||
ResultResponse<String> createAgoraTokenGoUp(
|
ResultResponse<String> createAgoraTokenGoUp(
|
||||||
@RequestParam("userId") Long userId,
|
@RequestParam("userId") Long userId,
|
||||||
@RequestParam("type") String channelName
|
@RequestParam("type") String channelName
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
/**
|
||||||
|
* 创建 TRTC 入房凭证.
|
||||||
|
*/
|
||||||
|
@GetMapping("/createTrtcCredential")
|
||||||
|
ResultResponse<RtcCredentialCO> createTrtcCredential(
|
||||||
|
@RequestParam("userId") Long userId,
|
||||||
|
@RequestParam("roomIdentifier") String roomIdentifier,
|
||||||
|
@RequestParam(value = "publisher", required = false) Boolean publisher
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@ -1,15 +1,21 @@
|
|||||||
package com.red.circle.external.adapter.app.imtrtc;
|
package com.red.circle.external.adapter.app.imtrtc;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.JsonSyntaxException;
|
import com.google.gson.JsonSyntaxException;
|
||||||
import com.red.circle.auth.inner.endpoint.AuthClient;
|
import com.red.circle.auth.inner.endpoint.AuthClient;
|
||||||
import com.red.circle.common.business.dto.cmd.AppExtCommand;
|
import com.red.circle.common.business.dto.cmd.AppExtCommand;
|
||||||
import com.red.circle.component.instant.msg.agora.AgoraAuthentication;
|
import com.red.circle.common.business.dto.rtc.RtcCredentialCO;
|
||||||
import com.red.circle.component.instant.msg.tencet.service.endpoint.api.im.account.ImAccountManagerService;
|
import com.red.circle.common.business.dto.rtc.RtcProviderEnum;
|
||||||
import com.red.circle.component.instant.msg.tencet.service.endpoint.api.im.group.ImGroupAvManagerService;
|
import com.red.circle.common.business.dto.rtc.RtcVersionSupport;
|
||||||
import com.red.circle.component.instant.msg.tencet.service.endpoint.api.trtc.TencentTrtcService;
|
import com.red.circle.component.instant.msg.InstantMessageProperties;
|
||||||
import com.red.circle.component.instant.msg.tencet.service.result.OnlineStatusResult;
|
import com.red.circle.component.instant.msg.agora.AgoraAuthentication;
|
||||||
import com.red.circle.component.instant.msg.tencet.service.result.OnlineStatusResult.OnlineStatus;
|
import com.red.circle.component.instant.msg.tencet.props.TrtcTencetProperties;
|
||||||
|
import com.red.circle.component.instant.msg.tencet.service.endpoint.api.im.account.ImAccountManagerService;
|
||||||
|
import com.red.circle.component.instant.msg.tencet.service.endpoint.api.im.group.ImGroupAvManagerService;
|
||||||
|
import com.red.circle.component.instant.msg.tencet.service.endpoint.api.trtc.TencentTrtcService;
|
||||||
|
import com.red.circle.component.instant.msg.tencet.service.result.OnlineStatusResult;
|
||||||
|
import com.red.circle.component.instant.msg.tencet.service.result.OnlineStatusResult.OnlineStatus;
|
||||||
|
import com.red.circle.component.redis.service.RedisService;
|
||||||
import com.red.circle.external.clienobject.TmpSigCO;
|
import com.red.circle.external.clienobject.TmpSigCO;
|
||||||
import com.red.circle.external.cmd.imtrtc.ImRoomRemoveUserCmd;
|
import com.red.circle.external.cmd.imtrtc.ImRoomRemoveUserCmd;
|
||||||
import com.red.circle.external.infra.database.redis.service.UserAgoraTokenCacheService;
|
import com.red.circle.external.infra.database.redis.service.UserAgoraTokenCacheService;
|
||||||
@ -23,13 +29,15 @@ import com.red.circle.framework.web.controller.BaseController;
|
|||||||
import com.red.circle.tool.core.collection.CollectionUtils;
|
import com.red.circle.tool.core.collection.CollectionUtils;
|
||||||
import com.red.circle.tool.core.regex.RegexConstant;
|
import com.red.circle.tool.core.regex.RegexConstant;
|
||||||
import com.red.circle.tool.core.text.StringPool;
|
import com.red.circle.tool.core.text.StringPool;
|
||||||
import com.red.circle.other.inner.asserts.user.UserErrorCode;
|
import com.red.circle.other.inner.asserts.user.UserErrorCode;
|
||||||
import com.red.circle.other.inner.endpoint.user.user.UserProfileClient;
|
import com.red.circle.other.inner.endpoint.user.user.UserProfileClient;
|
||||||
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
|
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
|
||||||
import java.util.Collections;
|
import com.tencentyun.TLSSigAPIv2;
|
||||||
import java.util.List;
|
import java.util.Collections;
|
||||||
import java.util.Objects;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import io.agora.media.RtcTokenBuilder2;
|
import io.agora.media.RtcTokenBuilder2;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
@ -41,8 +49,9 @@ import org.springframework.web.bind.annotation.GetMapping;
|
|||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IM操作.
|
* IM操作.
|
||||||
@ -62,14 +71,22 @@ public class ImRestController extends BaseController {
|
|||||||
private final UserProfileClient userProfileClient;
|
private final UserProfileClient userProfileClient;
|
||||||
private final TencentTrtcService tencentTrtcService;
|
private final TencentTrtcService tencentTrtcService;
|
||||||
private final AgoraAuthentication agoraAuthentication;
|
private final AgoraAuthentication agoraAuthentication;
|
||||||
private final ImGroupAvManagerService imGroupAvManagerService;
|
private final ImGroupAvManagerService imGroupAvManagerService;
|
||||||
private final ImAccountManagerService imAccountManagerService;
|
private final ImAccountManagerService imAccountManagerService;
|
||||||
private final UserAgoraTokenCacheService userAgoraTokenCacheService;
|
private final UserAgoraTokenCacheService userAgoraTokenCacheService;
|
||||||
|
private final RedisService redisService;
|
||||||
@Value("${rtc.appId}")
|
private final InstantMessageProperties instantMessageProperties;
|
||||||
private String appId;
|
|
||||||
@Value("${rtc.certificate}")
|
@Value("${rtc.appId}")
|
||||||
private String certificate;
|
private String appId;
|
||||||
|
@Value("${rtc.certificate}")
|
||||||
|
private String certificate;
|
||||||
|
|
||||||
|
@Value("${red-circle.instant-message.tencet-trtc.userSigExpireSeconds:7200}")
|
||||||
|
private long trtcUserSigExpireSeconds;
|
||||||
|
|
||||||
|
@Value("${red-circle.instant-message.tencet-trtc.userSigKey:${red-circle.instant-message.tencet-trtc.secretKey:}}")
|
||||||
|
private String trtcUserSigKey;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 认证签名(腾讯).
|
* 认证签名(腾讯).
|
||||||
@ -127,13 +144,16 @@ public class ImRestController extends BaseController {
|
|||||||
* @eo.method get
|
* @eo.method get
|
||||||
* @eo.request-type formdata
|
* @eo.request-type formdata
|
||||||
*/
|
*/
|
||||||
@GetMapping("/tmp/agora/sig")
|
@GetMapping("/tmp/agora/sig")
|
||||||
public TmpSigCO userSig(Long userId, String channelName,Boolean isPublisher) {
|
public TmpSigCO userSig(AppExtCommand cmd, Long userId, String channelName, Boolean isPublisher) {
|
||||||
log.warn("/tmp/agora/sig {}, {}, {}", userId, channelName, isPublisher);
|
log.warn("/tmp/agora/sig {}, {}, {}", userId, channelName, isPublisher);
|
||||||
if (isPublisher == null){
|
if (isPublisher == null){
|
||||||
isPublisher = false;
|
isPublisher = false;
|
||||||
}
|
}
|
||||||
String token;
|
RtcProviderEnum provider = resolveRoomProvider(channelName, currentVersion(cmd));
|
||||||
|
ResponseAssert.isTrue(CommonErrorCode.UPGRADE_VERSION,
|
||||||
|
!Objects.equals(RtcProviderEnum.TRTC, provider));
|
||||||
|
String token;
|
||||||
if (isPublisher){
|
if (isPublisher){
|
||||||
token = userAgoraTokenCacheService.getUserAgoraToken(userId, Long.valueOf(channelName));
|
token = userAgoraTokenCacheService.getUserAgoraToken(userId, Long.valueOf(channelName));
|
||||||
} else {
|
} else {
|
||||||
@ -156,36 +176,160 @@ public class ImRestController extends BaseController {
|
|||||||
|
|
||||||
if (Objects.nonNull(json)) {
|
if (Objects.nonNull(json)) {
|
||||||
return getTmpSigByUserCredential(userId, token, json, gson);
|
return getTmpSigByUserCredential(userId, token, json, gson);
|
||||||
} else {
|
} else {
|
||||||
return new TmpSigCO()
|
RtcCredentialCO credential = createAgoraCredential(channelName, token);
|
||||||
.setRtcToken(token)
|
return new TmpSigCO()
|
||||||
.setNewServiceToken(authClient.createIfAbsentUserCredentialToken(userId).getBody());
|
.setRtcToken(token)
|
||||||
}
|
.setRtcProvider(RtcProviderEnum.AGORA.name())
|
||||||
|
.setRtcCredential(credential)
|
||||||
}
|
.setNewServiceToken(authClient.createIfAbsentUserCredentialToken(userId).getBody());
|
||||||
|
}
|
||||||
/**
|
|
||||||
* 根据用户信息获取用户Servicetoken
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RTC 凭证,支持按客户端版本和房间级 provider 在 Agora/TRTC 间分流.
|
||||||
|
*
|
||||||
|
* @param userId 用户id
|
||||||
|
* @param roomId 业务房间id,作为房间级 provider 缓存 key
|
||||||
|
* @param channelName 历史 Agora channel,可为空
|
||||||
|
* @param roomAccount TRTC 房间号,优先使用
|
||||||
|
* @param isPublisher 是否主播/上麦
|
||||||
|
*/
|
||||||
|
@GetMapping("/tmp/rtc/sig")
|
||||||
|
public TmpSigCO rtcSig(
|
||||||
|
AppExtCommand cmd,
|
||||||
|
@RequestParam("userId") Long userId,
|
||||||
|
@RequestParam(value = "roomId", required = false) Long roomId,
|
||||||
|
@RequestParam(value = "channelName", required = false) String channelName,
|
||||||
|
@RequestParam(value = "roomAccount", required = false) String roomAccount,
|
||||||
|
@RequestParam(value = "isPublisher", required = false) Boolean isPublisher) {
|
||||||
|
String providerRoomKey = Objects.nonNull(roomId) ? roomId.toString() : channelName;
|
||||||
|
ResponseAssert.isTrue(ResponseErrorCode.REQUEST_PARAMETER_ERROR,
|
||||||
|
StringUtils.hasText(providerRoomKey));
|
||||||
|
|
||||||
|
RtcProviderEnum provider = resolveRoomProvider(providerRoomKey, currentVersion(cmd));
|
||||||
|
boolean publisher = Boolean.TRUE.equals(isPublisher);
|
||||||
|
if (Objects.equals(RtcProviderEnum.AGORA, provider)) {
|
||||||
|
String agoraChannelName = StringUtils.hasText(channelName) ? channelName : providerRoomKey;
|
||||||
|
String token = publisher
|
||||||
|
? createChannelPublisherToken(agoraChannelName, userId)
|
||||||
|
: createChannelSubscriberToken(agoraChannelName, userId);
|
||||||
|
RtcCredentialCO credential = createAgoraCredential(agoraChannelName, token);
|
||||||
|
return new TmpSigCO()
|
||||||
|
.setRtcToken(token)
|
||||||
|
.setRtcProvider(RtcProviderEnum.AGORA.name())
|
||||||
|
.setRtcCredential(credential)
|
||||||
|
.setNewServiceToken(authClient.createIfAbsentUserCredentialToken(userId).getBody());
|
||||||
|
}
|
||||||
|
|
||||||
|
String trtcRoomIdentifier = firstText(roomAccount, channelName, providerRoomKey);
|
||||||
|
RtcCredentialCO credential = createTrtcCredential(userId, trtcRoomIdentifier, publisher);
|
||||||
|
return new TmpSigCO()
|
||||||
|
.setRtcToken(credential.getTrtcUserSig())
|
||||||
|
.setRtcProvider(RtcProviderEnum.TRTC.name())
|
||||||
|
.setRtcCredential(credential)
|
||||||
|
.setNewServiceToken(authClient.createIfAbsentUserCredentialToken(userId).getBody());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据用户信息获取用户Servicetoken
|
||||||
*
|
*
|
||||||
* @param userId
|
* @param userId
|
||||||
* @param token
|
* @param token
|
||||||
* @param json
|
* @param json
|
||||||
* @param gson
|
* @param gson
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private TmpSigCO getTmpSigByUserCredential(Long userId, String token, String json, Gson gson) {
|
private TmpSigCO getTmpSigByUserCredential(Long userId, String token, String json, Gson gson) {
|
||||||
try {
|
RtcCredentialCO credential = createAgoraCredential(null, token);
|
||||||
UserCredential userCredential = gson.fromJson(json, UserCredential.class);
|
try {
|
||||||
return new TmpSigCO()
|
UserCredential userCredential = gson.fromJson(json, UserCredential.class);
|
||||||
.setRtcToken(token)
|
return new TmpSigCO()
|
||||||
.setNewServiceToken(userCredential.token());
|
.setRtcToken(token)
|
||||||
} catch (JsonSyntaxException e) {
|
.setRtcProvider(RtcProviderEnum.AGORA.name())
|
||||||
log.error("/tmp/agora/sig类型转换错误", e);
|
.setRtcCredential(credential)
|
||||||
return new TmpSigCO()
|
.setNewServiceToken(userCredential.token());
|
||||||
.setRtcToken(token)
|
} catch (JsonSyntaxException e) {
|
||||||
.setNewServiceToken(authClient.createIfAbsentUserCredentialToken(userId).getBody());
|
log.error("/tmp/agora/sig类型转换错误", e);
|
||||||
}
|
return new TmpSigCO()
|
||||||
}
|
.setRtcToken(token)
|
||||||
|
.setRtcProvider(RtcProviderEnum.AGORA.name())
|
||||||
|
.setRtcCredential(credential)
|
||||||
|
.setNewServiceToken(authClient.createIfAbsentUserCredentialToken(userId).getBody());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private RtcProviderEnum resolveRoomProvider(String roomKey, String version) {
|
||||||
|
if (!StringUtils.hasText(roomKey)) {
|
||||||
|
return RtcVersionSupport.defaultProvider(version);
|
||||||
|
}
|
||||||
|
String cacheKey = RtcVersionSupport.roomProviderKey(roomKey.trim());
|
||||||
|
RtcProviderEnum cached = RtcProviderEnum.of(redisService.getString(cacheKey));
|
||||||
|
if (Objects.nonNull(cached)) {
|
||||||
|
return cached;
|
||||||
|
}
|
||||||
|
RtcProviderEnum provider = RtcVersionSupport.defaultProvider(version);
|
||||||
|
redisService.setIfAbsent(cacheKey, provider.name(),
|
||||||
|
RtcVersionSupport.ROOM_PROVIDER_TTL_SECONDS, TimeUnit.SECONDS);
|
||||||
|
RtcProviderEnum resolved = RtcProviderEnum.of(redisService.getString(cacheKey));
|
||||||
|
return Objects.nonNull(resolved) ? resolved : provider;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String currentVersion(AppExtCommand cmd) {
|
||||||
|
return Optional.ofNullable(cmd)
|
||||||
|
.map(AppExtCommand::getReqAppIntel)
|
||||||
|
.map(reqAppIntel -> reqAppIntel.getVersion())
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private RtcCredentialCO createAgoraCredential(String channelName, String token) {
|
||||||
|
return new RtcCredentialCO()
|
||||||
|
.setRtcProvider(RtcProviderEnum.AGORA.name())
|
||||||
|
.setAgoraChannelName(channelName)
|
||||||
|
.setAgoraToken(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
private RtcCredentialCO createTrtcCredential(Long userId, String roomIdentifier,
|
||||||
|
boolean publisher) {
|
||||||
|
TrtcTencetProperties trtcProperties = instantMessageProperties.getTencetTrtc();
|
||||||
|
ResponseAssert.notNull(CommonErrorCode.CONFIGURATION_ERROR, trtcProperties);
|
||||||
|
ResponseAssert.notNull(CommonErrorCode.CONFIGURATION_ERROR, trtcProperties.getSdkAppId());
|
||||||
|
ResponseAssert.isTrue(CommonErrorCode.CONFIGURATION_ERROR, StringUtils.hasText(trtcUserSigKey));
|
||||||
|
|
||||||
|
String trtcUserId = userId.toString();
|
||||||
|
String userSig = new TLSSigAPIv2(trtcProperties.getSdkAppId(), trtcUserSigKey)
|
||||||
|
.genUserSig(trtcUserId, trtcUserSigExpireSeconds);
|
||||||
|
RtcCredentialCO credential = new RtcCredentialCO()
|
||||||
|
.setRtcProvider(RtcProviderEnum.TRTC.name())
|
||||||
|
.setTrtcSdkAppId(trtcProperties.getSdkAppId())
|
||||||
|
.setTrtcUserId(trtcUserId)
|
||||||
|
.setTrtcUserSig(userSig)
|
||||||
|
.setTrtcRole(publisher ? 20 : 21)
|
||||||
|
.setTrtcUserSigExpireSeconds(trtcUserSigExpireSeconds)
|
||||||
|
.setTrtcUserSigExpireAt(
|
||||||
|
System.currentTimeMillis() + trtcUserSigExpireSeconds * 1000L);
|
||||||
|
applyTrtcRoomIdentifier(credential, roomIdentifier);
|
||||||
|
return credential;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyTrtcRoomIdentifier(RtcCredentialCO credential, String roomIdentifier) {
|
||||||
|
String normalizedRoomIdentifier = roomIdentifier.trim();
|
||||||
|
try {
|
||||||
|
credential.setTrtcRoomId(Long.valueOf(normalizedRoomIdentifier));
|
||||||
|
} catch (NumberFormatException ignored) {
|
||||||
|
credential.setTrtcStrRoomId(normalizedRoomIdentifier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String firstText(String... values) {
|
||||||
|
for (String value : values) {
|
||||||
|
if (StringUtils.hasText(value)) {
|
||||||
|
return value.trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -1,9 +1,10 @@
|
|||||||
package com.red.circle.external.clienobject;
|
package com.red.circle.external.clienobject;
|
||||||
|
|
||||||
import com.red.circle.framework.dto.ClientObject;
|
import com.red.circle.common.business.dto.rtc.RtcCredentialCO;
|
||||||
import lombok.Data;
|
import com.red.circle.framework.dto.ClientObject;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.Data;
|
||||||
import lombok.experimental.Accessors;
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 临时签名(兼容服务).
|
* 临时签名(兼容服务).
|
||||||
@ -20,8 +21,18 @@ public class TmpSigCO extends ClientObject {
|
|||||||
*/
|
*/
|
||||||
private String rtcToken;
|
private String rtcToken;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 新服务token.
|
* 新服务token.
|
||||||
*/
|
*/
|
||||||
private String newServiceToken;
|
private String newServiceToken;
|
||||||
}
|
|
||||||
|
/**
|
||||||
|
* RTC provider: AGORA or TRTC.
|
||||||
|
*/
|
||||||
|
private String rtcProvider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provider specific credential.
|
||||||
|
*/
|
||||||
|
private RtcCredentialCO rtcCredential;
|
||||||
|
}
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
package com.red.circle.external.inner.endpoint.message;
|
package com.red.circle.external.inner.endpoint.message;
|
||||||
|
|
||||||
import com.red.circle.external.inner.endpoint.message.api.TrtcClientApi;
|
import com.red.circle.common.business.dto.rtc.RtcCredentialCO;
|
||||||
import com.red.circle.external.inner.model.cmd.message.TrtcRemoveUserCmd;
|
import com.red.circle.external.inner.endpoint.message.api.TrtcClientApi;
|
||||||
import com.red.circle.external.inner.model.cmd.message.TrtcUserBlockedCmd;
|
import com.red.circle.external.inner.model.cmd.message.TrtcRemoveUserCmd;
|
||||||
|
import com.red.circle.external.inner.model.cmd.message.TrtcUserBlockedCmd;
|
||||||
import com.red.circle.external.inner.service.message.TrtcClientService;
|
import com.red.circle.external.inner.service.message.TrtcClientService;
|
||||||
import com.red.circle.framework.dto.ResultResponse;
|
import com.red.circle.framework.dto.ResultResponse;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
@ -45,8 +46,15 @@ public class TrtcClientEndpoint implements TrtcClientApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ResultResponse<String> createAgoraTokenGoUp(Long userId, String channelName) {
|
public ResultResponse<String> createAgoraTokenGoUp(Long userId, String channelName) {
|
||||||
return ResultResponse.success(trtcClientService.createAgoraTokenGoUp(userId, channelName));
|
return ResultResponse.success(trtcClientService.createAgoraTokenGoUp(userId, channelName));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
@Override
|
||||||
|
public ResultResponse<RtcCredentialCO> createTrtcCredential(Long userId, String roomIdentifier,
|
||||||
|
Boolean publisher) {
|
||||||
|
return ResultResponse.success(
|
||||||
|
trtcClientService.createTrtcCredential(userId, roomIdentifier, publisher));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
package com.red.circle.external.inner.service.message;
|
package com.red.circle.external.inner.service.message;
|
||||||
|
|
||||||
import com.red.circle.external.inner.model.cmd.message.TrtcRemoveUserCmd;
|
import com.red.circle.common.business.dto.rtc.RtcCredentialCO;
|
||||||
import com.red.circle.external.inner.model.cmd.message.TrtcUserBlockedCmd;
|
import com.red.circle.external.inner.model.cmd.message.TrtcRemoveUserCmd;
|
||||||
|
import com.red.circle.external.inner.model.cmd.message.TrtcUserBlockedCmd;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* trtc 服务.
|
* trtc 服务.
|
||||||
@ -33,8 +34,13 @@ public interface TrtcClientService {
|
|||||||
/**
|
/**
|
||||||
* 创建声网令牌.
|
* 创建声网令牌.
|
||||||
*/
|
*/
|
||||||
String createAgoraToken(Long userId, String channelName);
|
String createAgoraToken(Long userId, String channelName);
|
||||||
|
|
||||||
String createAgoraTokenGoUp(Long userId, String channelName);
|
String createAgoraTokenGoUp(Long userId, String channelName);
|
||||||
|
|
||||||
}
|
/**
|
||||||
|
* 创建 TRTC 入房凭证.
|
||||||
|
*/
|
||||||
|
RtcCredentialCO createTrtcCredential(Long userId, String roomIdentifier, Boolean publisher);
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@ -1,17 +1,23 @@
|
|||||||
package com.red.circle.external.inner.service.message.impl;
|
package com.red.circle.external.inner.service.message.impl;
|
||||||
|
|
||||||
import com.red.circle.component.instant.msg.agora.AgoraAuthentication;
|
import com.red.circle.common.business.dto.rtc.RtcCredentialCO;
|
||||||
import com.red.circle.component.instant.msg.agora.AgoraProperties;
|
import com.red.circle.common.business.dto.rtc.RtcProviderEnum;
|
||||||
import com.red.circle.component.instant.msg.tencet.service.endpoint.api.trtc.TencentTrtcService;
|
import com.red.circle.component.instant.msg.InstantMessageProperties;
|
||||||
import com.red.circle.external.inner.model.cmd.message.TrtcRemoveUserCmd;
|
import com.red.circle.component.instant.msg.tencet.props.TrtcTencetProperties;
|
||||||
import com.red.circle.external.inner.model.cmd.message.TrtcUserBlockedCmd;
|
import com.red.circle.component.instant.msg.tencet.service.endpoint.api.trtc.TencentTrtcService;
|
||||||
import com.red.circle.external.inner.service.message.TrtcClientService;
|
import com.red.circle.external.inner.model.cmd.message.TrtcRemoveUserCmd;
|
||||||
import com.red.circle.other.inner.endpoint.user.user.UserProfileClient;
|
import com.red.circle.external.inner.model.cmd.message.TrtcUserBlockedCmd;
|
||||||
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
|
import com.red.circle.external.inner.service.message.TrtcClientService;
|
||||||
import io.agora.media.RtcTokenBuilder2;
|
import com.red.circle.framework.core.asserts.ResponseAssert;
|
||||||
import lombok.RequiredArgsConstructor;
|
import com.red.circle.framework.core.response.CommonErrorCode;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import com.red.circle.other.inner.endpoint.user.user.UserProfileClient;
|
||||||
import org.springframework.stereotype.Service;
|
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
|
||||||
|
import com.tencentyun.TLSSigAPIv2;
|
||||||
|
import io.agora.media.RtcTokenBuilder2;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* trtc 服务.
|
* trtc 服务.
|
||||||
@ -22,17 +28,22 @@ import org.springframework.stereotype.Service;
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class TrtcClientServiceImpl implements TrtcClientService {
|
public class TrtcClientServiceImpl implements TrtcClientService {
|
||||||
|
|
||||||
private final UserProfileClient userProfileClient;
|
private final UserProfileClient userProfileClient;
|
||||||
private final TencentTrtcService tencentTrtcService;
|
private final TencentTrtcService tencentTrtcService;
|
||||||
// private final AgoraAuthentication agoraAuthentication;
|
private final InstantMessageProperties instantMessageProperties;
|
||||||
// private final AgoraProperties agoraProperties;
|
|
||||||
|
@Value("${rtc.appId}")
|
||||||
@Value("${rtc.appId}")
|
private String appId;
|
||||||
private String appId;
|
|
||||||
|
@Value("${rtc.certificate}")
|
||||||
@Value("${rtc.certificate}")
|
private String certificate;
|
||||||
private String certificate;
|
|
||||||
|
@Value("${red-circle.instant-message.tencet-trtc.userSigExpireSeconds:7200}")
|
||||||
|
private long trtcUserSigExpireSeconds;
|
||||||
|
|
||||||
|
@Value("${red-circle.instant-message.tencet-trtc.userSigKey:${red-circle.instant-message.tencet-trtc.secretKey:}}")
|
||||||
|
private String trtcUserSigKey;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean removeUser(TrtcRemoveUserCmd cmd) {
|
public boolean removeUser(TrtcRemoveUserCmd cmd) {
|
||||||
return tencentTrtcService.removeUser(cmd.getRoomId(),
|
return tencentTrtcService.removeUser(cmd.getRoomId(),
|
||||||
@ -61,10 +72,50 @@ public class TrtcClientServiceImpl implements TrtcClientService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String createAgoraTokenGoUp(Long userId, String channelName) {
|
public String createAgoraTokenGoUp(Long userId, String channelName) {
|
||||||
UserProfileDTO userProfile = userProfileClient.getByUserId(userId).getBody();
|
UserProfileDTO userProfile = userProfileClient.getByUserId(userId).getBody();
|
||||||
RtcTokenBuilder2 var3 = new RtcTokenBuilder2();
|
RtcTokenBuilder2 var3 = new RtcTokenBuilder2();
|
||||||
return var3.buildTokenWithUid(appId, certificate, channelName, Integer.parseInt(userProfile.getAccount()), RtcTokenBuilder2.Role.ROLE_PUBLISHER, 21600, 21600);
|
return var3.buildTokenWithUid(appId, certificate, channelName, Integer.parseInt(userProfile.getAccount()), RtcTokenBuilder2.Role.ROLE_PUBLISHER, 21600, 21600);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
@Override
|
||||||
|
public RtcCredentialCO createTrtcCredential(Long userId, String roomIdentifier,
|
||||||
|
Boolean publisher) {
|
||||||
|
ResponseAssert.notNull(CommonErrorCode.REQUIRED_FIELDS_CANNOT_BE_IGNORED, userId);
|
||||||
|
ResponseAssert.isTrue(CommonErrorCode.REQUIRED_FIELDS_CANNOT_BE_IGNORED,
|
||||||
|
StringUtils.hasText(roomIdentifier));
|
||||||
|
|
||||||
|
TrtcTencetProperties trtcProperties = instantMessageProperties.getTencetTrtc();
|
||||||
|
ResponseAssert.notNull(CommonErrorCode.CONFIGURATION_ERROR, trtcProperties);
|
||||||
|
ResponseAssert.notNull(CommonErrorCode.CONFIGURATION_ERROR, trtcProperties.getSdkAppId());
|
||||||
|
ResponseAssert.isTrue(CommonErrorCode.CONFIGURATION_ERROR, StringUtils.hasText(trtcUserSigKey));
|
||||||
|
|
||||||
|
String trtcUserId = userId.toString();
|
||||||
|
String userSig = new TLSSigAPIv2(
|
||||||
|
trtcProperties.getSdkAppId(),
|
||||||
|
trtcUserSigKey
|
||||||
|
).genUserSig(trtcUserId, trtcUserSigExpireSeconds);
|
||||||
|
|
||||||
|
RtcCredentialCO credential = new RtcCredentialCO()
|
||||||
|
.setRtcProvider(RtcProviderEnum.TRTC.name())
|
||||||
|
.setTrtcSdkAppId(trtcProperties.getSdkAppId())
|
||||||
|
.setTrtcUserId(trtcUserId)
|
||||||
|
.setTrtcUserSig(userSig)
|
||||||
|
.setTrtcRole(Boolean.TRUE.equals(publisher) ? 20 : 21)
|
||||||
|
.setTrtcUserSigExpireSeconds(trtcUserSigExpireSeconds)
|
||||||
|
.setTrtcUserSigExpireAt(
|
||||||
|
System.currentTimeMillis() + trtcUserSigExpireSeconds * 1000L);
|
||||||
|
applyTrtcRoomIdentifier(credential, roomIdentifier);
|
||||||
|
return credential;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyTrtcRoomIdentifier(RtcCredentialCO credential, String roomIdentifier) {
|
||||||
|
String normalizedRoomIdentifier = roomIdentifier.trim();
|
||||||
|
try {
|
||||||
|
credential.setTrtcRoomId(Long.valueOf(normalizedRoomIdentifier));
|
||||||
|
} catch (NumberFormatException ignored) {
|
||||||
|
credential.setTrtcStrRoomId(normalizedRoomIdentifier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
package com.red.circle.live.app.command.mic;
|
package com.red.circle.live.app.command.mic;
|
||||||
|
|
||||||
import com.red.circle.component.redis.service.RedisService;
|
import com.red.circle.common.business.dto.rtc.RtcCredentialCO;
|
||||||
|
import com.red.circle.common.business.dto.rtc.RtcProviderEnum;
|
||||||
|
import com.red.circle.common.business.dto.rtc.RtcVersionSupport;
|
||||||
|
import com.red.circle.component.redis.service.RedisService;
|
||||||
import com.red.circle.external.inner.endpoint.message.TrtcClient;
|
import com.red.circle.external.inner.endpoint.message.TrtcClient;
|
||||||
import com.red.circle.framework.core.asserts.ResponseAssert;
|
import com.red.circle.framework.core.asserts.ResponseAssert;
|
||||||
import com.red.circle.framework.core.response.CommonErrorCode;
|
import com.red.circle.framework.core.response.CommonErrorCode;
|
||||||
@ -29,7 +32,8 @@ import org.slf4j.LoggerFactory;
|
|||||||
import org.springframework.data.redis.core.RedisTemplate;
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
@ -52,16 +56,25 @@ public class LiveMicGoUpCmdExe {
|
|||||||
private final RedisService redisService;
|
private final RedisService redisService;
|
||||||
private final RoomDailyTaskClient roomDailyTaskClient;
|
private final RoomDailyTaskClient roomDailyTaskClient;
|
||||||
private final RoomManagerClient roomManagerClient;
|
private final RoomManagerClient roomManagerClient;
|
||||||
private final RedisTemplate redisTemplate;
|
private final RedisTemplate redisTemplate;
|
||||||
private final RoomMemberClient roomMemberClient;
|
private final RoomMemberClient roomMemberClient;
|
||||||
|
|
||||||
public LiveMicrophoneCO execute(MicUpDownCmd cmd) {
|
public LiveMicrophoneCO execute(MicUpDownCmd cmd) {
|
||||||
boolean targetMicAlreadySelf = false;
|
boolean targetMicAlreadySelf = false;
|
||||||
boolean goUpCompleted = false;
|
boolean goUpCompleted = false;
|
||||||
|
RtcProviderEnum rtcProvider = null;
|
||||||
try {
|
try {
|
||||||
checkPermissions(cmd);
|
checkPermissions(cmd);
|
||||||
targetMicAlreadySelf = checkTargetMicAvailableOrSelf(cmd);
|
targetMicAlreadySelf = checkTargetMicAvailableOrSelf(cmd);
|
||||||
String roomToken = createPublisherToken(cmd);
|
rtcProvider = resolveRoomProvider(cmd);
|
||||||
|
String roomToken = null;
|
||||||
|
RtcCredentialCO rtcCredential;
|
||||||
|
if (Objects.equals(RtcProviderEnum.AGORA, rtcProvider)) {
|
||||||
|
roomToken = createPublisherToken(cmd);
|
||||||
|
rtcCredential = createAgoraCredential(cmd, roomToken);
|
||||||
|
} else {
|
||||||
|
rtcCredential = createTrtcCredential(cmd, true);
|
||||||
|
}
|
||||||
|
|
||||||
LiveMicrophoneNoticeDTO noticeDTO = liveMicrophoneGateway.goUp(
|
LiveMicrophoneNoticeDTO noticeDTO = liveMicrophoneGateway.goUp(
|
||||||
cmd.getRoomId(),
|
cmd.getRoomId(),
|
||||||
@ -70,16 +83,22 @@ public class LiveMicGoUpCmdExe {
|
|||||||
);
|
);
|
||||||
goUpCompleted = true;
|
goUpCompleted = true;
|
||||||
|
|
||||||
cachePublisherToken(cmd, roomToken);
|
if (Objects.equals(RtcProviderEnum.AGORA, rtcProvider)) {
|
||||||
|
cachePublisherToken(cmd, roomToken);
|
||||||
|
}
|
||||||
LiveMicrophoneCO notice = returnMicrophoneCO(cmd, noticeDTO);
|
LiveMicrophoneCO notice = returnMicrophoneCO(cmd, noticeDTO);
|
||||||
notice.setRoomToken(roomToken);
|
notice.setRoomToken(roomToken)
|
||||||
|
.setRtcProvider(rtcProvider.name())
|
||||||
|
.setRtcCredential(rtcCredential);
|
||||||
|
|
||||||
// 房主邀请成员上麦
|
// 房主邀请成员上麦
|
||||||
handleRoomDailyTask(cmd);
|
handleRoomDailyTask(cmd);
|
||||||
return notice;
|
return notice;
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
if (goUpCompleted) {
|
if (goUpCompleted) {
|
||||||
rollbackPublisherToken(cmd);
|
if (Objects.equals(RtcProviderEnum.AGORA, rtcProvider)) {
|
||||||
|
rollbackPublisherToken(cmd);
|
||||||
|
}
|
||||||
if (!targetMicAlreadySelf) {
|
if (!targetMicAlreadySelf) {
|
||||||
rollbackMicSeat(cmd, e);
|
rollbackMicSeat(cmd, e);
|
||||||
}
|
}
|
||||||
@ -103,6 +122,60 @@ public class LiveMicGoUpCmdExe {
|
|||||||
userAgoraTokenCacheService.save(roomToken, cmd.requiredReqUserId(), cmd.getRoomId());
|
userAgoraTokenCacheService.save(roomToken, cmd.requiredReqUserId(), cmd.getRoomId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private RtcProviderEnum resolveRoomProvider(MicUpDownCmd cmd) {
|
||||||
|
if (Objects.isNull(redisService)) {
|
||||||
|
return RtcVersionSupport.defaultProvider(currentVersion(cmd));
|
||||||
|
}
|
||||||
|
String cacheKey = RtcVersionSupport.roomProviderKey(cmd.getRoomId());
|
||||||
|
RtcProviderEnum requestedProvider = RtcVersionSupport.defaultProvider(currentVersion(cmd));
|
||||||
|
RtcProviderEnum cachedProvider = RtcProviderEnum.of(redisService.getString(cacheKey));
|
||||||
|
if (Objects.nonNull(cachedProvider)) {
|
||||||
|
ResponseAssert.isTrue(CommonErrorCode.UPGRADE_VERSION,
|
||||||
|
!Objects.equals(RtcProviderEnum.AGORA, requestedProvider)
|
||||||
|
|| !Objects.equals(RtcProviderEnum.TRTC, cachedProvider));
|
||||||
|
return cachedProvider;
|
||||||
|
}
|
||||||
|
redisService.setIfAbsent(cacheKey, requestedProvider.name(),
|
||||||
|
RtcVersionSupport.ROOM_PROVIDER_TTL_SECONDS, TimeUnit.SECONDS);
|
||||||
|
RtcProviderEnum resolvedProvider = RtcProviderEnum.of(redisService.getString(cacheKey));
|
||||||
|
return Objects.nonNull(resolvedProvider) ? resolvedProvider : requestedProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String currentVersion(MicUpDownCmd cmd) {
|
||||||
|
return Optional.ofNullable(cmd)
|
||||||
|
.map(MicUpDownCmd::getReqAppIntel)
|
||||||
|
.map(reqAppIntel -> reqAppIntel.getVersion())
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private RtcCredentialCO createAgoraCredential(MicUpDownCmd cmd, String token) {
|
||||||
|
return new RtcCredentialCO()
|
||||||
|
.setRtcProvider(RtcProviderEnum.AGORA.name())
|
||||||
|
.setAgoraChannelName(cmd.getRoomId().toString())
|
||||||
|
.setAgoraToken(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
private RtcCredentialCO createTrtcCredential(MicUpDownCmd cmd, boolean publisher) {
|
||||||
|
ResultResponse<RtcCredentialCO> response = trtcClient.createTrtcCredential(
|
||||||
|
cmd.requiredReqUserId(),
|
||||||
|
resolveTrtcRoomIdentifier(cmd),
|
||||||
|
publisher
|
||||||
|
);
|
||||||
|
RtcCredentialCO credential = Objects.nonNull(response) ? response.getBody() : null;
|
||||||
|
ResponseAssert.notNull(CommonErrorCode.THIRD_PARTY_SERVER_ERROR, credential);
|
||||||
|
return credential;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String resolveTrtcRoomIdentifier(MicUpDownCmd cmd) {
|
||||||
|
ResultResponse<RoomProfileDTO> response = roomManagerClient.getById(cmd.getRoomId());
|
||||||
|
RoomProfileDTO roomProfile = Objects.nonNull(response) ? response.getBody() : null;
|
||||||
|
if (Objects.nonNull(roomProfile) && Objects.nonNull(roomProfile.getRoomAccount())
|
||||||
|
&& !roomProfile.getRoomAccount().isBlank()) {
|
||||||
|
return roomProfile.getRoomAccount();
|
||||||
|
}
|
||||||
|
return cmd.getRoomId().toString();
|
||||||
|
}
|
||||||
|
|
||||||
private boolean checkTargetMicAvailableOrSelf(MicUpDownCmd cmd) {
|
private boolean checkTargetMicAvailableOrSelf(MicUpDownCmd cmd) {
|
||||||
boolean targetMicAlreadySelf = liveMicCacheService.checkEqSelf(
|
boolean targetMicAlreadySelf = liveMicCacheService.checkEqSelf(
|
||||||
cmd.getRoomId(),
|
cmd.getRoomId(),
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
package com.red.circle.live.app.dto.clientobject;
|
package com.red.circle.live.app.dto.clientobject;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||||
import com.red.circle.framework.dto.ClientObject;
|
import com.red.circle.common.business.dto.rtc.RtcCredentialCO;
|
||||||
import java.io.Serial;
|
import com.red.circle.framework.dto.ClientObject;
|
||||||
import lombok.Data;
|
import java.io.Serial;
|
||||||
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.experimental.Accessors;
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
@ -47,9 +48,19 @@ public class LiveMicrophoneCO extends ClientObject {
|
|||||||
*/
|
*/
|
||||||
private LiveMicUserCO user;
|
private LiveMicUserCO user;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 上麦token信息
|
* 上麦token信息
|
||||||
*/
|
*/
|
||||||
private String roomToken;
|
private String roomToken;
|
||||||
|
|
||||||
}
|
/**
|
||||||
|
* RTC provider: AGORA or TRTC.
|
||||||
|
*/
|
||||||
|
private String rtcProvider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RTC credential for clients that support provider negotiation.
|
||||||
|
*/
|
||||||
|
private RtcCredentialCO rtcCredential;
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
package com.red.circle.other.app.command.room;
|
package com.red.circle.other.app.command.room;
|
||||||
|
|
||||||
import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
|
import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
|
||||||
|
import com.red.circle.common.business.dto.rtc.RtcCredentialCO;
|
||||||
|
import com.red.circle.common.business.dto.rtc.RtcProviderEnum;
|
||||||
|
import com.red.circle.common.business.dto.rtc.RtcVersionSupport;
|
||||||
import com.red.circle.external.inner.endpoint.message.ImGroupClient;
|
import com.red.circle.external.inner.endpoint.message.ImGroupClient;
|
||||||
import com.red.circle.external.inner.endpoint.message.TrtcClient;
|
import com.red.circle.external.inner.endpoint.message.TrtcClient;
|
||||||
import com.red.circle.external.inner.model.cmd.message.CreateGroupCmd;
|
import com.red.circle.external.inner.model.cmd.message.CreateGroupCmd;
|
||||||
@ -121,13 +124,21 @@ public class RoomEnterCmdExe {
|
|||||||
);
|
);
|
||||||
|
|
||||||
ResponseAssert.notNull(UserErrorCode.USER_INFO_NOT_FOUND, ownUserProfile);
|
ResponseAssert.notNull(UserErrorCode.USER_INFO_NOT_FOUND, ownUserProfile);
|
||||||
//String token = createAgoraToken(cmd);
|
RtcProviderEnum rtcProvider = resolveRoomProvider(cmd);
|
||||||
String token = userAgoraTokenCacheService.getUserAgoraToken(cmd.getReqUserId(), cmd.getRoomId());
|
String token = null;
|
||||||
if (Objects.isNull(token)) {
|
RtcCredentialCO rtcCredential;
|
||||||
token = trtcClient.createAgoraToken(cmd.getReqUserId(), cmd.getRoomId().toString()).getBody();
|
if (Objects.equals(RtcProviderEnum.AGORA, rtcProvider)) {
|
||||||
log.warn("进房间token:{}", token);
|
token = userAgoraTokenCacheService.getUserAgoraToken(cmd.getReqUserId(), cmd.getRoomId());
|
||||||
userAgoraTokenCacheService.save(token, cmd.getReqUserId(), cmd.getRoomId());
|
if (Objects.isNull(token)) {
|
||||||
}
|
token = trtcClient.createAgoraToken(cmd.getReqUserId(), cmd.getRoomId().toString())
|
||||||
|
.getBody();
|
||||||
|
log.warn("进房间token:{}", token);
|
||||||
|
userAgoraTokenCacheService.save(token, cmd.getReqUserId(), cmd.getRoomId());
|
||||||
|
}
|
||||||
|
rtcCredential = createAgoraCredential(cmd, token);
|
||||||
|
} else {
|
||||||
|
rtcCredential = createTrtcCredential(cmd, manager, false);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 无法操作,错误归属
|
// 无法操作,错误归属
|
||||||
@ -159,10 +170,12 @@ public class RoomEnterCmdExe {
|
|||||||
.setEntrants(
|
.setEntrants(
|
||||||
new EntryRoomEntrantsCO()
|
new EntryRoomEntrantsCO()
|
||||||
.setRoles(roomManagerCacheService.getRoomUserRoles(cmd.getReqUserId(),
|
.setRoles(roomManagerCacheService.getRoomUserRoles(cmd.getReqUserId(),
|
||||||
cmd.getRoomId()))
|
cmd.getRoomId()))
|
||||||
.setLevel(getUserLevel(cmd.requireReqSysOriginEnum(), cmd.getReqUserId()))
|
.setLevel(getUserLevel(cmd.requireReqSysOriginEnum(), cmd.getReqUserId()))
|
||||||
.setNobleVipAbility(listUserPropsVipActualEquity(cmd))
|
.setNobleVipAbility(listUserPropsVipActualEquity(cmd))
|
||||||
.setRoomToken(token)
|
.setRoomToken(token)
|
||||||
|
.setRtcProvider(rtcProvider.name())
|
||||||
|
.setRtcCredential(rtcCredential)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -210,9 +223,9 @@ public class RoomEnterCmdExe {
|
|||||||
* @param cmd
|
* @param cmd
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private String createAgoraToken(RoomEntryCmd cmd) {
|
private String createAgoraToken(RoomEntryCmd cmd) {
|
||||||
ExecutorService executor = Executors.newSingleThreadExecutor();
|
ExecutorService executor = Executors.newSingleThreadExecutor();
|
||||||
AtomicReference<String> agoraToken = new AtomicReference<>("BaHrIypJdFWqwWtoZLToRucRyoGrVgYCONBFvGynmlJsevFYsWBfEIcaWUUGijQBjycTtmSvkmBINoSltJMmgiPeBnkaWErixaxg");
|
AtomicReference<String> agoraToken = new AtomicReference<>("BaHrIypJdFWqwWtoZLToRucRyoGrVgYCONBFvGynmlJsevFYsWBfEIcaWUUGijQBjycTtmSvkmBINoSltJMmgiPeBnkaWErixaxg");
|
||||||
Future<?> future = executor.submit(() -> {
|
Future<?> future = executor.submit(() -> {
|
||||||
agoraToken.set(trtcClient.createAgoraToken(cmd.getReqUserId(), cmd.getRoomId().toString()).getBody());
|
agoraToken.set(trtcClient.createAgoraToken(cmd.getReqUserId(), cmd.getRoomId().toString()).getBody());
|
||||||
});
|
});
|
||||||
@ -227,13 +240,63 @@ public class RoomEnterCmdExe {
|
|||||||
log.error("上麦获取声网token其他异常: {}", e.getMessage());
|
log.error("上麦获取声网token其他异常: {}", e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
executor.shutdown();
|
executor.shutdown();
|
||||||
return agoraToken.get();
|
return agoraToken.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<PropsVipActualEquityEnum> listUserPropsVipActualEquity(RoomEntryCmd cmd) {
|
private RtcProviderEnum resolveRoomProvider(RoomEntryCmd cmd) {
|
||||||
return userProfileGateway.listUserActualEquityEnum(cmd.requiredReqUserId());
|
String cacheKey = RtcVersionSupport.roomProviderKey(cmd.getRoomId());
|
||||||
}
|
RtcProviderEnum requestedProvider = RtcVersionSupport.defaultProvider(currentVersion(cmd));
|
||||||
|
RtcProviderEnum cachedProvider = RtcProviderEnum.of(redisService.getString(cacheKey));
|
||||||
|
if (Objects.nonNull(cachedProvider)) {
|
||||||
|
ResponseAssert.isTrue(CommonErrorCode.UPGRADE_VERSION,
|
||||||
|
!Objects.equals(RtcProviderEnum.AGORA, requestedProvider)
|
||||||
|
|| !Objects.equals(RtcProviderEnum.TRTC, cachedProvider));
|
||||||
|
return cachedProvider;
|
||||||
|
}
|
||||||
|
redisService.setIfAbsent(cacheKey, requestedProvider.name(),
|
||||||
|
RtcVersionSupport.ROOM_PROVIDER_TTL_SECONDS, TimeUnit.SECONDS);
|
||||||
|
RtcProviderEnum resolvedProvider = RtcProviderEnum.of(redisService.getString(cacheKey));
|
||||||
|
return Objects.nonNull(resolvedProvider) ? resolvedProvider : requestedProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String currentVersion(RoomEntryCmd cmd) {
|
||||||
|
return Optional.ofNullable(cmd)
|
||||||
|
.map(RoomEntryCmd::getReqAppIntel)
|
||||||
|
.map(reqAppIntel -> reqAppIntel.getVersion())
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private RtcCredentialCO createAgoraCredential(RoomEntryCmd cmd, String token) {
|
||||||
|
return new RtcCredentialCO()
|
||||||
|
.setRtcProvider(RtcProviderEnum.AGORA.name())
|
||||||
|
.setAgoraChannelName(cmd.getRoomId().toString())
|
||||||
|
.setAgoraToken(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
private RtcCredentialCO createTrtcCredential(RoomEntryCmd cmd, RoomProfileManager manager,
|
||||||
|
boolean publisher) {
|
||||||
|
ResultResponse<RtcCredentialCO> response = trtcClient.createTrtcCredential(
|
||||||
|
cmd.getReqUserId(),
|
||||||
|
resolveTrtcRoomIdentifier(cmd, manager),
|
||||||
|
publisher
|
||||||
|
);
|
||||||
|
RtcCredentialCO credential = Objects.nonNull(response) ? response.getBody() : null;
|
||||||
|
ResponseAssert.notNull(CommonErrorCode.THIRD_PARTY_SERVER_ERROR, credential);
|
||||||
|
return credential;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String resolveTrtcRoomIdentifier(RoomEntryCmd cmd, RoomProfileManager manager) {
|
||||||
|
if (Objects.nonNull(manager) && Objects.nonNull(manager.getRoomAccount())
|
||||||
|
&& !manager.getRoomAccount().isBlank()) {
|
||||||
|
return manager.getRoomAccount();
|
||||||
|
}
|
||||||
|
return cmd.getRoomId().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<PropsVipActualEquityEnum> listUserPropsVipActualEquity(RoomEntryCmd cmd) {
|
||||||
|
return userProfileGateway.listUserActualEquityEnum(cmd.requiredReqUserId());
|
||||||
|
}
|
||||||
|
|
||||||
private WealthAndCharmLevelDTO getUserLevel(SysOriginPlatformEnum sysOrigin, Long userId) {
|
private WealthAndCharmLevelDTO getUserLevel(SysOriginPlatformEnum sysOrigin, Long userId) {
|
||||||
return Optional.ofNullable(
|
return Optional.ofNullable(
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
package com.red.circle.other.app.dto.clientobject.room;
|
package com.red.circle.other.app.dto.clientobject.room;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
import com.red.circle.framework.dto.ClientObject;
|
import com.red.circle.common.business.dto.rtc.RtcCredentialCO;
|
||||||
import com.red.circle.other.inner.enums.live.RoomUserRolesEnum;
|
import com.red.circle.framework.dto.ClientObject;
|
||||||
import com.red.circle.other.inner.enums.material.PropsVipActualEquityEnum;
|
import com.red.circle.other.inner.enums.live.RoomUserRolesEnum;
|
||||||
import com.red.circle.other.inner.model.dto.user.WealthAndCharmLevelDTO;
|
import com.red.circle.other.inner.enums.material.PropsVipActualEquityEnum;
|
||||||
|
import com.red.circle.other.inner.model.dto.user.WealthAndCharmLevelDTO;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
@ -36,9 +37,19 @@ public class EntryRoomEntrantsCO extends ClientObject {
|
|||||||
*/
|
*/
|
||||||
private List<PropsVipActualEquityEnum> nobleVipAbility;
|
private List<PropsVipActualEquityEnum> nobleVipAbility;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 进入房间token信息
|
* 进入房间token信息
|
||||||
*/
|
*/
|
||||||
private String roomToken;
|
private String roomToken;
|
||||||
|
|
||||||
}
|
/**
|
||||||
|
* RTC provider: AGORA or TRTC.
|
||||||
|
*/
|
||||||
|
private String rtcProvider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RTC credential for clients that support provider negotiation.
|
||||||
|
*/
|
||||||
|
private RtcCredentialCO rtcCredential;
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user