This commit is contained in:
hejinbo
2023-11-16 10:54:52 +08:00
6 changed files with 178 additions and 11 deletions
@@ -1,24 +1,34 @@
package com.ruoyi.web.controller.wisdomarbitrate; package com.ruoyi.web.controller.wisdomarbitrate;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.ruoyi.common.annotation.Anonymous; import com.ruoyi.common.annotation.Anonymous;
import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.wisdomarbitrate.domain.IdentityAuthentication; import com.ruoyi.wisdomarbitrate.domain.IdentityAuthentication;
import com.ruoyi.wisdomarbitrate.domain.vo.ReservedConferenceVO;
import com.ruoyi.wisdomarbitrate.domain.vo.SendRoomNoMessageVO; import com.ruoyi.wisdomarbitrate.domain.vo.SendRoomNoMessageVO;
import com.ruoyi.wisdomarbitrate.domain.vo.WeChatUserVO; import com.ruoyi.wisdomarbitrate.domain.vo.WeChatUserVO;
import com.ruoyi.wisdomarbitrate.service.VideoService; import com.ruoyi.wisdomarbitrate.service.VideoService;
import com.ruoyi.wisdomarbitrate.service.WeChatUserService; import com.ruoyi.wisdomarbitrate.service.WeChatUserService;
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.common.profile.ClientProfile;
import com.tencentcloudapi.common.profile.HttpProfile;
import com.tencentcloudapi.trtc.v20190722.TrtcClient;
import com.tencentcloudapi.trtc.v20190722.models.*;
import com.tencentyun.TLSSigAPIv2;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid; import javax.validation.Valid;
import java.io.IOException;
/** /**
* @author wangqiong * @author wangqiong
* @description 视频录制 * @description trtc实时音视频
* @date 2023-10-26 11:25 * @date 2023-10-26 11:25
*/ */
@RestController @RestController
@@ -59,4 +69,29 @@ public class VideoController extends BaseController {
return videoService.videoList(caseId); return videoService.videoList(caseId);
} }
/**
* 开启腾讯云录制
* @param vo
* @return
* @throws Exception
*/
@Anonymous
@PostMapping("/openCloudRecording")
private AjaxResult openCloudRecording( @RequestBody ReservedConferenceVO vo) {
if(vo.getCaseId()==null || StrUtil.isEmpty(vo.getRoomId())){
return AjaxResult.error("参数错误");
}
return videoService.openCloudRecording(vo.getCaseId(),vo.getRoomId());
}
/**
* 关闭腾讯云录制
* @param taskId 任务ID
* @return
*/
@Anonymous
@PostMapping("/closeDeleteCloudRecording")
public AjaxResult closeDeleteCloudRecording(@RequestParam("taskId") String taskId){
return videoService.closeDeleteCloudRecording(taskId);
}
} }
@@ -178,4 +178,8 @@ imConfig:
# sdkAppId # sdkAppId
sdkAppId: 1600011167 sdkAppId: 1600011167
# 密钥 # 密钥
secretKey: 17d136d9327576a247f991bdfed3a6d14cebc7d540a52245086829c3a1421a86 sdkSecretKey: 17d136d9327576a247f991bdfed3a6d14cebc7d540a52245086829c3a1421a86
# 腾讯云账户 SecretId
secretId: AKID3xfHgroY4MQHvLXUXMwIQL1UjmbBX1Tv
# 腾讯云密钥
secretKey: INDrIXcT8YmomZBcsy0oNirnU0LTN4X7
@@ -17,4 +17,13 @@ public interface VideoService {
AjaxResult bindCaseId(Long caseId, String roomId); AjaxResult bindCaseId(Long caseId, String roomId);
AjaxResult videoList(Long caseId); AjaxResult videoList(Long caseId);
/**
* 开启腾讯云录制
* @param roomId
* @return
*/
AjaxResult openCloudRecording(long caseId,String roomId);
AjaxResult closeDeleteCloudRecording(String taskId);
} }
@@ -79,8 +79,8 @@ public class CaseApplicationServiceImpl implements ICaseApplicationService {
@Value("${imConfig.sdkAppId}") @Value("${imConfig.sdkAppId}")
private long sdkAppId; private long sdkAppId;
// 腾讯云即时通信密钥 // 腾讯云即时通信密钥
@Value("${imConfig.secretKey}") @Value("${imConfig.sdkSecretKey}")
private String secretKey; private String sdkSecretKey;
@Autowired @Autowired
private CaseApplicationMapper caseApplicationMapper; private CaseApplicationMapper caseApplicationMapper;
@@ -113,10 +113,10 @@ public class CaseApplicationServiceImpl implements ICaseApplicationService {
private DeptIdentifyMapper deptIdentifyMapper; private DeptIdentifyMapper deptIdentifyMapper;
@Autowired @Autowired
private ReservedConferenceMapper reservedConferenceMapper; private ReservedConferenceMapper reservedConferenceMapper;
@Autowired
private SysDeptMapper deptMapper;
@Autowired @Autowired
private SealManageMapper sealManageMapper; private SealManageMapper sealManageMapper;
// 手机号正则 // 手机号正则
private static final Pattern TELEPHONE_REGX = Pattern.compile("^1(3\\d|4[5-9]|5[0-35-9]|6[2567]|7[0-8]|8\\d|9[0-35-9])\\d{8}$"); private static final Pattern TELEPHONE_REGX = Pattern.compile("^1(3\\d|4[5-9]|5[0-35-9]|6[2567]|7[0-8]|8\\d|9[0-35-9])\\d{8}$");
@@ -2548,7 +2548,7 @@ public class CaseApplicationServiceImpl implements ICaseApplicationService {
* @return * @return
*/ */
public String generateUserSign(String userId) { public String generateUserSign(String userId) {
TLSSigAPIv2 tlsSigAPIv2 = new TLSSigAPIv2(sdkAppId, secretKey); TLSSigAPIv2 tlsSigAPIv2 = new TLSSigAPIv2(sdkAppId, sdkSecretKey);
return tlsSigAPIv2.genUserSig(userId, 60 * 60 * 10); return tlsSigAPIv2.genUserSig(userId, 60 * 60 * 10);
} }
@@ -2571,6 +2571,7 @@ public class CaseApplicationServiceImpl implements ICaseApplicationService {
} }
// 生成房间号id // 生成房间号id
String roomId = generateRoomId(); String roomId = generateRoomId();
// String roomId = reservedConferenceVO.getRoomId();
Date startTime = reservedConferenceVO.getScheduleStartTime(); Date startTime = reservedConferenceVO.getScheduleStartTime();
Date endTime = reservedConferenceVO.getScheduleEndTime(); Date endTime = reservedConferenceVO.getScheduleEndTime();
Random rand = new Random(); Random rand = new Random();
@@ -31,11 +31,15 @@ import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.exception.TencentCloudSDKException; import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.common.profile.ClientProfile; import com.tencentcloudapi.common.profile.ClientProfile;
import com.tencentcloudapi.common.profile.HttpProfile; import com.tencentcloudapi.common.profile.HttpProfile;
import com.tencentcloudapi.trtc.v20190722.TrtcClient;
import com.tencentcloudapi.trtc.v20190722.models.*;
import com.tencentcloudapi.vod.v20180717.VodClient; import com.tencentcloudapi.vod.v20180717.VodClient;
import com.tencentcloudapi.vod.v20180717.models.DescribeMediaInfosRequest; import com.tencentcloudapi.vod.v20180717.models.DescribeMediaInfosRequest;
import com.tencentcloudapi.vod.v20180717.models.DescribeMediaInfosResponse; import com.tencentcloudapi.vod.v20180717.models.DescribeMediaInfosResponse;
import com.tencentyun.TLSSigAPIv2;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ResourceUtils; import org.springframework.util.ResourceUtils;
@@ -63,6 +67,18 @@ import static com.ruoyi.common.utils.file.FileUploadUtils.getPathFileName;
@Service @Service
@Slf4j @Slf4j
public class VideoServiceImpl implements VideoService { public class VideoServiceImpl implements VideoService {
// 腾讯云即时通信sdkAppId
@Value("${imConfig.sdkAppId}")
private long sdkAppId;
// 腾讯云即时通信密钥
@Value("${imConfig.sdkSecretKey}")
private String sdkSecretKey;
// 腾讯云个人账户secretId
@Value("${imConfig.secretId}")
private String secretId;
// 腾讯云个人账户密钥
@Value("${imConfig.secretKey}")
private String secretKey;
@Autowired @Autowired
private CaseApplicationMapper caseApplicationMapper; private CaseApplicationMapper caseApplicationMapper;
@Autowired @Autowired
@@ -149,6 +165,108 @@ public class VideoServiceImpl implements VideoService {
return AjaxResult.success(caseAttachList); return AjaxResult.success(caseAttachList);
} }
/**
* 开启腾讯云录制
* @param roomId
* @return
*/
@Override
public AjaxResult openCloudRecording(long caseId,String roomId) {
try {
String userId="recorder_"+roomId;
Credential cred = new Credential(secretId, secretKey);
// 实例化一个http选项,可选的,没有特殊需求可以跳过
HttpProfile httpProfile = new HttpProfile();
httpProfile.setEndpoint("trtc.tencentcloudapi.com");
// 实例化一个client选项,可选的,没有特殊需求可以跳过
ClientProfile clientProfile = new ClientProfile();
clientProfile.setHttpProfile(httpProfile);
// 实例化要请求产品的client对象,clientProfile是可选的
TrtcClient client = new TrtcClient(cred, "ap-beijing", clientProfile);
// 实例化一个请求对象,每个接口都会对应一个request对象
CreateCloudRecordingRequest req = new CreateCloudRecordingRequest();
req.setSdkAppId(sdkAppId); // SdkAppId – TRTC的[SdkAppId](https://cloud.tencent.com/document/product/647/46351#sdkappid),和录制的房间所对应的SdkAppId相同
req.setRoomId(roomId); // RoomId – TRTC的[RoomId](https://cloud.tencent.com/document/product/647/46351#roomid),录制的TRTC房间所对应的RoomId
req.setRoomIdType(1L);
/**
* 录制机器人用于进入TRTC房间拉流的[UserId](https://cloud.tencent.com/document/product/647/46351#userid),
* 注意这个UserId不能与其他TRTC房间内的主播或者其他录制任务等已经使用的UserId重复,建议可以把房间ID作为userId的标识的一部分,
* 即录制机器人进入房间的userid应保证独立且唯一
*/
req.setUserId(userId);
TLSSigAPIv2 api = new TLSSigAPIv2(sdkAppId, sdkSecretKey);
String userSign = api.genUserSig(userId, 60 * 60 * 10);
req.setUserSig(userSign); // 录制机器人用于进入TRTC房间拉流的用户签名,当前 UserId 对应的验证签名,相当于登录密码
RecordParams recordParams = new RecordParams();
// 混流录制
recordParams.setMaxIdleTime(60L*5); // 5分钟内房间里面没有主播,自动停止录制
recordParams.setStreamType(0L); // 0:录制音频+视频流(默认); 1:仅录制音频流; 2:仅录制视频流
recordParams.setRecordMode(2L); // 1:单流录制,分别录制房间的订阅UserId的音频和视频,将录制文件上传至云存储; 2:混流录制,将房间内订阅UserId的音视频混录成一个音视频文件,将录制文件上传至云存储;
recordParams.setOutputFormat(0L); // 0:(默认)输出文件为hls格式。1:输出文件格式为hls+mp4。2:输出文件格式为hls+aac
MixLayoutParams mixLayoutParams = new MixLayoutParams();
// 布局模式: 1:悬浮布局;2:屏幕分享布局;3:九宫格布局(默认);4:自定义布局;
mixLayoutParams.setMixLayoutMode(1L);
req.setMixLayoutParams(mixLayoutParams);
StorageParams storageParams1 = new StorageParams();
CloudVod cloudVod = new CloudVod();
TencentVod tencentVod = new TencentVod();
tencentVod.setSubAppId(1304001529L);
// 录制的文件永久保存
tencentVod.setExpireTime(0L);
// 录制文件名拼接前缀
tencentVod.setUserDefineRecordId(caseId+"");
cloudVod.setTencentVod(tencentVod); // 腾讯云点播相关参数。
storageParams1.setCloudVod(cloudVod); // 必填】腾讯云云点播的账号信息,目前仅支持存储至腾讯云点播VOD。
req.setRecordParams(recordParams); // 云端录制控制参数
req.setStorageParams(storageParams1); // 云端录制文件上传到云存储的参数(目前只支持使用腾讯云点播作为存储)
// 返回的resp是一个CreateCloudRecordingResponse的实例,与请求对象对应
CreateCloudRecordingResponse resp = client.CreateCloudRecording(req);
return AjaxResult.success((JSONObject) JSON.toJSON(resp));
} catch (TencentCloudSDKException e) {
return AjaxResult.error(e.toString());
}
}
@Override
public AjaxResult closeDeleteCloudRecording(String taskId) {
try {
if (taskId != null) {
taskId = taskId.replaceAll(" ", "+");
}
// 实例化一个认证对象,入参需要传入腾讯云账户 SecretId 和 SecretKey,此处还需注意密钥对的保密
// 代码泄露可能会导致 SecretId 和 SecretKey 泄露,并威胁账号下所有资源的安全性。以下代码示例仅供参考,建议采用更安全的方式来使用密钥,请参见:https://cloud.tencent.com/document/product/1278/85305
// 密钥可前往官网控制台 https://console.cloud.tencent.com/cam/capi 进行获取
Credential cred = new Credential(secretId, secretKey);
// 实例化一个http选项,可选的,没有特殊需求可以跳过
HttpProfile httpProfile = new HttpProfile();
httpProfile.setEndpoint("trtc.tencentcloudapi.com");
// 实例化一个client选项,可选的,没有特殊需求可以跳过
ClientProfile clientProfile = new ClientProfile();
clientProfile.setHttpProfile(httpProfile);
// 实例化要请求产品的client对象,clientProfile是可选的
TrtcClient client = new TrtcClient(cred, "ap-beijing", clientProfile);
// 实例化一个请求对象,每个接口都会对应一个request对象
DeleteCloudRecordingRequest req = new DeleteCloudRecordingRequest();
req.setSdkAppId(sdkAppId); // SdkAppId – TRTC的SDKAppId,和录制的房间所对应的SDKAppId相同
req.setTaskId(taskId); // TaskId – 录制任务的唯一Id,在启动录制成功后会返回
// 返回的resp是一个DeleteCloudRecordingResponse的实例,与请求对象对应
DeleteCloudRecordingResponse resp = client.DeleteCloudRecording(req);
// 输出json格式的字符串回包
return AjaxResult.success((JSONObject) JSON.toJSON(resp));
} catch (TencentCloudSDKException e) {
return AjaxResult.error(e.toString());
}
}
/** /**
* 查询出音视频集合,并下载,在将云点播上面的音视频删除 * 查询出音视频集合,并下载,在将云点播上面的音视频删除
* @param fileIds 点播平台唯一ID集合 * @param fileIds 点播平台唯一ID集合
@@ -68,7 +68,7 @@
c.update_by ,c.update_time , c.arbitrator_name,ca.application_organ_id applicationOrganId ,ca.application_organ_name as applicantName,c.filearbitra_url c.update_by ,c.update_time , c.arbitrator_name,ca.application_organ_id applicationOrganId ,ca.application_organ_name as applicantName,c.filearbitra_url
from case_log_record r from case_log_record r
join case_application c on r.case_appli_id=c.id join case_application c on r.case_appli_id=c.id
LEFT JOIN case_affiliate ca ON ca.case_appli_id = c.id AND ca.identity_type=1 JOIN case_affiliate ca ON ca.case_appli_id = c.id AND ca.identity_type=1
<where> <where>
<if test="lockStatus != null"> <if test="lockStatus != null">
@@ -125,7 +125,7 @@
applicantName, applicantName,
c.arbitrator_id,ca.identity_num , ca.identity_type,c.filearbitra_url,c.lock_status c.arbitrator_id,ca.identity_num , ca.identity_type,c.filearbitra_url,c.lock_status
from case_application c from case_application c
LEFT JOIN case_affiliate ca ON ca.case_appli_id = c.id JOIN case_affiliate ca ON ca.case_appli_id = c.id
<where> <where>
<if test="caseStatus != null"> <if test="caseStatus != null">
AND c.case_status = #{caseStatus} AND c.case_status = #{caseStatus}
@@ -219,7 +219,7 @@
c.case_status,ca.application_organ_id, c.case_status,ca.application_organ_id,
c.arbitrator_id,ca.identity_num , ca.identity_type c.arbitrator_id,ca.identity_num , ca.identity_type
from case_application c from case_application c
LEFT JOIN case_affiliate ca ON ca.case_appli_id = c.id JOIN case_affiliate ca ON ca.case_appli_id = c.id
<where> <where>
<if test="caseStatus != null"> <if test="caseStatus != null">
AND c.case_status = #{caseStatus} AND c.case_status = #{caseStatus}
@@ -298,7 +298,7 @@
c.begin_video_date ,c.online_video_person ,c.contract_number ,c.create_by ,c.create_time ,c.lock_status, c.begin_video_date ,c.online_video_person ,c.contract_number ,c.create_by ,c.create_time ,c.lock_status,
c.update_by ,c.update_time , c.arbitrator_name,ca.application_organ_id applicationOrganId ,ca.application_organ_name as applicantName,c.filearbitra_url c.update_by ,c.update_time , c.arbitrator_name,ca.application_organ_id applicationOrganId ,ca.application_organ_name as applicantName,c.filearbitra_url
from case_application c from case_application c
LEFT JOIN case_affiliate ca ON ca.case_appli_id = c.id AND ca.identity_type=1 JOIN case_affiliate ca ON ca.case_appli_id = c.id AND ca.identity_type=1
<where> <where>
<if test="caseStatus != null"> <if test="caseStatus != null">
AND c.case_status = #{caseStatus} AND c.case_status = #{caseStatus}