From eb09ba6ae9598d45e353da39e5e32f4300d7a939 Mon Sep 17 00:00:00 2001 From: 18792927508 <1322446236@qq.com> Date: Wed, 15 Nov 2023 16:12:48 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A7=86=E9=A2=91=E5=BD=95=E5=88=B6=EF=BC=8C?= =?UTF-8?q?=E5=81=9C=E6=AD=A2=E5=BD=95=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wisdomarbitrate/VideoController.java | 37 +++++- .../src/main/resources/application.yml | 6 +- .../wisdomarbitrate/service/VideoService.java | 9 ++ .../impl/CaseApplicationServiceImpl.java | 10 +- .../service/impl/VideoServiceImpl.java | 108 ++++++++++++++++++ .../wisdomarbitrate/CaseApplicationMapper.xml | 8 +- 6 files changed, 167 insertions(+), 11 deletions(-) diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/wisdomarbitrate/VideoController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/wisdomarbitrate/VideoController.java index 24595ce..0c6c929 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/wisdomarbitrate/VideoController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/wisdomarbitrate/VideoController.java @@ -1,24 +1,34 @@ package com.ruoyi.web.controller.wisdomarbitrate; import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSON; import com.ruoyi.common.annotation.Anonymous; import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.domain.AjaxResult; 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.WeChatUserVO; import com.ruoyi.wisdomarbitrate.service.VideoService; 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.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletRequest; import javax.validation.Valid; +import java.io.IOException; /** * @author wangqiong - * @description 视频录制 + * @description trtc实时音视频 * @date 2023-10-26 11:25 */ @RestController @@ -59,4 +69,29 @@ public class VideoController extends BaseController { 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); + } + } diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml index 3b9ca78..06bc003 100644 --- a/ruoyi-admin/src/main/resources/application.yml +++ b/ruoyi-admin/src/main/resources/application.yml @@ -178,4 +178,8 @@ imConfig: # sdkAppId sdkAppId: 1600011167 # 密钥 - secretKey: 17d136d9327576a247f991bdfed3a6d14cebc7d540a52245086829c3a1421a86 \ No newline at end of file + sdkSecretKey: 17d136d9327576a247f991bdfed3a6d14cebc7d540a52245086829c3a1421a86 + # 腾讯云账户 SecretId + secretId: AKID3xfHgroY4MQHvLXUXMwIQL1UjmbBX1Tv + # 腾讯云密钥 + secretKey: INDrIXcT8YmomZBcsy0oNirnU0LTN4X7 \ No newline at end of file diff --git a/ruoyi-system/src/main/java/com/ruoyi/wisdomarbitrate/service/VideoService.java b/ruoyi-system/src/main/java/com/ruoyi/wisdomarbitrate/service/VideoService.java index 9242840..8b65973 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/wisdomarbitrate/service/VideoService.java +++ b/ruoyi-system/src/main/java/com/ruoyi/wisdomarbitrate/service/VideoService.java @@ -17,4 +17,13 @@ public interface VideoService { AjaxResult bindCaseId(Long caseId, String roomId); AjaxResult videoList(Long caseId); + + /** + * 开启腾讯云录制 + * @param roomId + * @return + */ + AjaxResult openCloudRecording(long caseId,String roomId); + + AjaxResult closeDeleteCloudRecording(String taskId); } diff --git a/ruoyi-system/src/main/java/com/ruoyi/wisdomarbitrate/service/impl/CaseApplicationServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/wisdomarbitrate/service/impl/CaseApplicationServiceImpl.java index 729025e..e14492e 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/wisdomarbitrate/service/impl/CaseApplicationServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/wisdomarbitrate/service/impl/CaseApplicationServiceImpl.java @@ -79,8 +79,8 @@ public class CaseApplicationServiceImpl implements ICaseApplicationService { @Value("${imConfig.sdkAppId}") private long sdkAppId; // 腾讯云即时通信密钥 - @Value("${imConfig.secretKey}") - private String secretKey; + @Value("${imConfig.sdkSecretKey}") + private String sdkSecretKey; @Autowired private CaseApplicationMapper caseApplicationMapper; @@ -113,8 +113,7 @@ public class CaseApplicationServiceImpl implements ICaseApplicationService { private DeptIdentifyMapper deptIdentifyMapper; @Autowired private ReservedConferenceMapper reservedConferenceMapper; - @Autowired - private SysDeptMapper deptMapper; + // 手机号正则 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}$"); @@ -2520,7 +2519,7 @@ public class CaseApplicationServiceImpl implements ICaseApplicationService { * @return */ public String generateUserSign(String userId) { - TLSSigAPIv2 tlsSigAPIv2 = new TLSSigAPIv2(sdkAppId, secretKey); + TLSSigAPIv2 tlsSigAPIv2 = new TLSSigAPIv2(sdkAppId, sdkSecretKey); return tlsSigAPIv2.genUserSig(userId, 60 * 60 * 10); } @@ -2543,6 +2542,7 @@ public class CaseApplicationServiceImpl implements ICaseApplicationService { } // 生成房间号id String roomId = generateRoomId(); +// String roomId = reservedConferenceVO.getRoomId(); Date startTime = reservedConferenceVO.getScheduleStartTime(); Date endTime = reservedConferenceVO.getScheduleEndTime(); Random rand = new Random(); diff --git a/ruoyi-system/src/main/java/com/ruoyi/wisdomarbitrate/service/impl/VideoServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/wisdomarbitrate/service/impl/VideoServiceImpl.java index bb62362..bb781e8 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/wisdomarbitrate/service/impl/VideoServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/wisdomarbitrate/service/impl/VideoServiceImpl.java @@ -31,11 +31,15 @@ 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.tencentcloudapi.vod.v20180717.VodClient; import com.tencentcloudapi.vod.v20180717.models.DescribeMediaInfosRequest; import com.tencentcloudapi.vod.v20180717.models.DescribeMediaInfosResponse; +import com.tencentyun.TLSSigAPIv2; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.ResourceUtils; @@ -63,6 +67,18 @@ import static com.ruoyi.common.utils.file.FileUploadUtils.getPathFileName; @Service @Slf4j 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 private CaseApplicationMapper caseApplicationMapper; @Autowired @@ -149,6 +165,98 @@ public class VideoServiceImpl implements VideoService { 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(Long.valueOf(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 + + StorageParams storageParams1 = new StorageParams(); + CloudVod cloudVod1 = new CloudVod(); + TencentVod tencentVod1 = new TencentVod(); + // 录制的文件永久保存 + tencentVod1.setExpireTime(0L); + // 录制文件名拼接前缀 + tencentVod1.setUserDefineRecordId(caseId+"@"); + cloudVod1.setTencentVod(tencentVod1); // 腾讯云点播相关参数。 + storageParams1.setCloudVod(cloudVod1); // 必填】腾讯云云点播的账号信息,目前仅支持存储至腾讯云点播VOD。 + req.setRecordParams(recordParams); // 云端录制控制参数 + req.setStorageParams(storageParams1); // 云端录制文件上传到云存储的参数(目前只支持使用腾讯云点播作为存储) + // 返回的resp是一个CreateCloudRecordingResponse的实例,与请求对象对应 + CreateCloudRecordingResponse resp = client.CreateCloudRecording(req); + // 输出json格式的字符串回包 + String s = JSON.toJSONString(resp); + return AjaxResult.success(s); + } catch (TencentCloudSDKException e) { + return AjaxResult.error(e.toString()); + } + } + + @Override + public AjaxResult closeDeleteCloudRecording(String taskId) { + // 实例化一个认证对象,入参需要传入腾讯云账户 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(); + + // 返回的resp是一个DeleteCloudRecordingResponse的实例,与请求对象对应 + DeleteCloudRecordingResponse resp = null; + try { + resp = client.DeleteCloudRecording(req); + } catch (TencentCloudSDKException e) { + return AjaxResult.error(e.toString()); + } + return AjaxResult.success(DeleteCloudRecordingResponse.toJsonString(resp)); + } + + /** * 查询出音视频集合,并下载,在将云点播上面的音视频删除 * @param fileIds 点播平台唯一ID集合 diff --git a/ruoyi-system/src/main/resources/mapper/wisdomarbitrate/CaseApplicationMapper.xml b/ruoyi-system/src/main/resources/mapper/wisdomarbitrate/CaseApplicationMapper.xml index 88ad061..c950c9e 100644 --- a/ruoyi-system/src/main/resources/mapper/wisdomarbitrate/CaseApplicationMapper.xml +++ b/ruoyi-system/src/main/resources/mapper/wisdomarbitrate/CaseApplicationMapper.xml @@ -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 from case_log_record r 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 @@ -125,7 +125,7 @@ applicantName, c.arbitrator_id,ca.identity_num , ca.identity_type,c.filearbitra_url,c.lock_status 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 AND c.case_status = #{caseStatus} @@ -219,7 +219,7 @@ c.case_status,ca.application_organ_id, c.arbitrator_id,ca.identity_num , ca.identity_type 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 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.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 - 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 AND c.case_status = #{caseStatus}