Java集成腾讯云音视频录制功能
为什么要实现音视频录制功能
因为我们做的是一个医院的项目,医生和患者可能进行视频通话和语音通话,为了保证通话的质量以及后续的问题,
我们就需要进行音视频录制,以便后续的问题解决
为什么选择使用腾讯云实现音视频录制功能
因为我们做的是微信小程序
- 腾讯云是基于腾讯的技术支撑,大厂技术比较稳定;
- 微信和腾讯云都是腾讯的产品,两者兼容性更好;
- 腾讯云提供的有uni-app的例子,参考资料更充分,可以基于demo和现有系统集成。
注意:userId需要保持在整个房间是唯一的,不管是录制还是音视频通话,进入房间的userId必须唯一,不然就会造成录制不了的情况
1.导入依赖
因为我们是Gradle项目,与我们之前Maven项目导入依赖的方式不一样,Gradle项目导入依赖的方式如下所示
implementation 'com.tencentcloudapi:tencentcloud-sdk-java-common:3.1.691' implementation 'com.tencentcloudapi:tencentcloud-sdk-java-trtc:3.1.691' implementation 'com.tencentcloudapi:tencentcloud-sdk-java-vod:3.1.704'
讯享网
2.实现云端录制
流程图
2.1 添加配置文件
访问秘钥和key

SDKAppID和SDKSecretKey
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W2EGXXrF-1680487013380)(C:\Users\11\AppData\Roaming\Typora\typora-user-images\image-20230401100744076.png)]](https://img-blog.csdnimg.cn/c34d0ad8dbac4884946fbe98f3910748.png)
在application.properties添加一下配置
讯享网secretid=访问秘钥ID secretkey=访问秘钥Key expiretime=过期时间 sdkappid=SDKAppID key=SDKSecretKey
2.2 回调地址设置
打开音视频控制台 --》应用管理 --》回调配置
跟着下面配置就可以了
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VC5U95iR-1680487013381)(C:\Users\11\AppData\Roaming\Typora\typora-user-images\image-20230401121640938.png)]](https://img-blog.csdnimg.cn/575bed8a5f854f0c9625f1f5c5ac9898.png)
2.3 签名 Sign
/ * @param key 回调秘钥 * @param body 入参 * @return 签名 Sign 计算公式中 key 为计算签名 Sign 用的加密密钥。 * @throws Exception */ private static String getResultSign(String key, String body) throws Exception {
Mac hmacSha256 = Mac.getInstance("HmacSHA256"); SecretKeySpec secret_key = new SecretKeySpec(key.getBytes(), "HmacSHA256"); hmacSha256.init(secret_key); return Base64.getEncoder().encodeToString(hmacSha256.doFinal(body.getBytes())); }
2.4 实现房间回调
房间回调API文档地址:https://cloud.tencent.com/document/product/647/51586
使用房间回调事件可以监听进入房间和退出房间时间,分别对应开始录制和退出录制(当我们进入房间开始录制,退出房间就退出录制)
入参是body加上请求头的方式,详细信息大家可以查阅文档,这里我就不一一赘述了
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iCLNAmjP-1680487013381)(C:\Users\11\AppData\Roaming\Typora\typora-user-images\image-20230401095115187.png)]](https://img-blog.csdnimg.cn/adc507f021cd4ee5b8c2158c63539cc1.png)
代码实现
讯享网//# 功能:第三方回调sign校验 //# 参数: //# key:控制台配置的密钥key //# body:腾讯云回调返回的body体 //# sign:腾讯云回调返回的签名值sign //# 返回值: //# Status:OK 表示校验通过,FAIL 表示校验失败,具体原因参考Info //# Info:成功/失败信息 @ApiOperation(value = "音视频房间回调接口") @PostMapping("/roomCallback") public void roomCallback(@RequestBody String body, HttpServletRequest request) throws Exception {
String key = "key"; String sdkAppId = request.getHeader("SdkAppId"); String sign = request.getHeader("Sign"); String resultSign = getResultSign(key,body); ValueOperations ops = redisTemplate.opsForValue(); if (resultSign.equals(sign)) {
JSONObject jsonObject = (JSONObject) JSON.parse(body); Integer eventType = jsonObject.getInteger("EventType"); // 事件类型 String eventInfo = jsonObject.getString("EventInfo"); // 事件信息 JSONObject jsonObject1 = (JSONObject) JSON.parse(eventInfo); String roomId = jsonObject1.getString("RoomId"); // 房间号 String userId = jsonObject1.getString("UserId"); // 用户ID if (!StringUtils.isEmpty(userId)) {
// 执行业务逻辑,判断是医生端还是患者端进入房间,查询出相关的问诊订单 } // 创建房间事件(创建房间事件只会进入一次房间回调接口,可以防止重复两次调用录制接口) if (eventType == 101) {
logger.debug("{'Status': 'OK', 'Info': '校验通过'}"); String openCloudRecording = openCloudRecording(userId, roomId); // 开启录制 JSONObject jsonObject2 = (JSONObject) JSON.parse(openCloudRecording); String taskId = jsonObject2.getString("taskId"); // 任务ID if (!StringUtils.isEmpty(taskId)) {
// 执行相关业务 } } else if (eventType == 104) {
// 104 退出房间事件 logger.debug("{'Status': 'FAIL', 'Info': '退出房间'}"); closeDeleteCloudRecording("录制任务ID"); // 退出录制 } } else {
logger.debug("{'Status': 'FAIL', 'Info': '校验失败'}"); } logger.debug("腾讯云测试成功"); }
2.5 开启音视频录制
开启云端录制API文档地址:https://cloud.tencent.com/document/api/647/73786
当房间回调事件监听到进入房间事件我们就开启语音(视频)通话了,就会调用开启音视频录制接口
输入参数我就不做赘述了(输出参数开启云端录制和关闭云端录制都是一致的),详细信息请看API文档
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0SIXel2V-1680487013381)(C:\Users\11\AppData\Roaming\Typora\typora-user-images\image-20230401103201717.png)]](https://img-blog.csdnimg.cn/c2ff65d2e6af4a2d975c310adb31c873.png)

代码实现
/ * 开启腾讯云录制 * @param userId * @param roomId * @return * @throws Exception */ private String openCloudRecording(String userId, String roomId) throws Exception {
try {
//创建文件对象 Properties properties = new Properties(); //加载文件获取数据 文件带后缀 properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream ("application.properties")); //根据key来获取value String secretId = properties.getProperty("secretid"); String secretKey = properties.getProperty("secretkey"); String ExpireTime = properties.getProperty("expiretime"); String sdkAppId = properties.getProperty("sdkappid"); String key = properties.getProperty("key"); 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(); // 实例化一个请求对象,每个接口都会对应一个request对象 CreateCloudRecordingRequest req = new CreateCloudRecordingRequest(); req.setSdkAppId(Long.valueOf(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), key); String userSign = api.genUserSig(userId, Long.valueOf(ExpireTime)); req.setUserSig(userSign); // 录制机器人用于进入TRTC房间拉流的用户签名,当前 UserId 对应的验证签名,相当于登录密码 RecordParams recordParams = new RecordParams(); // 单流录制 recordParams.setMaxIdleTime(30L); // 30 秒内房间里面没有主播,自动停止录制 recordParams.setStreamType(0L); // 0:录制音频+视频流(默认); 1:仅录制音频流; 2:仅录制视频流 recordParams.setRecordMode(1L); // 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(); 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 s; } catch (TencentCloudSDKException | IOException e) {
return e.toString(); } catch (Exception e) {
return e.toString(); } }
2.6 关闭音视频录制
关闭云端录制API文档地址:https://cloud.tencent.com/document/api/647/73785
当房间回调事件监听到退出房间事件我们就退出语音(视频)通话了,就会调用关闭音视频录制接口
输入参数我就不做赘述了(输出参数开启云端录制和关闭云端录制都是一致的),详细信息请看API文档
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KxY5ogdD-1680487013381)(C:\Users\11\AppData\Roaming\Typora\typora-user-images\image-20230401103201717.png)]](https://img-blog.csdnimg.cn/b06496345e7d4f39b99e2e024bce4e77.png)
代码实现
讯享网/ * 关闭腾讯云录制 * @param taskId 任务ID * @return */ public String 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 进行获取 //创建文件对象 Properties properties = new Properties(); //加载文件获取数据 文件带后缀 properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream ("application.properties")); //根据key来获取value String SecretId = properties.getProperty("secretid"); String SecretKey = properties.getProperty("secretkey"); String sdkAppId = properties.getProperty("sdkappid"); 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(Long.valueOf(sdkAppId)); // SdkAppId – TRTC的SDKAppId,和录制的房间所对应的SDKAppId相同 req.setTaskId(taskId); // TaskId – 录制任务的唯一Id,在启动录制成功后会返回 // 返回的resp是一个DeleteCloudRecordingResponse的实例,与请求对象对应 DeleteCloudRecordingResponse resp = client.DeleteCloudRecording(req); // 输出json格式的字符串回包 String s = JSON.toJSONString(resp); return s; } catch (TencentCloudSDKException | IOException e) {
return e.toString(); } }
2.7 云端录制回调
云端录制回调API文档地址:https://cloud.tencent.com/document/product/647/81113
当云端录制回调监听到录制上传成功事件,就会调用下载音视频接口,我们根据我们给我们数据库存储地址的表中标记,
未下载的进行下载。
输入(出)参数我就不做赘述了详细信息请看API文档
//# 功能:第三方回调sign校验 //# 参数: //# key:控制台配置的密钥key //# body:腾讯云回调返回的body体 //# sign:腾讯云回调返回的签名值sign //# 返回值: //# Status:OK 表示校验通过,FAIL 表示校验失败,具体原因参考Info //# Info:成功/失败信息 @ApiOperation(value = "音视频录制回调接口") @PostMapping("/recordingCallback") public void recordingCallback(@RequestBody String body, HttpServletRequest request) throws Exception {
String key = "key"; String sdkAppId = request.getHeader("SdkAppId"); String sign = request.getHeader("Sign"); logger.info("body:"+body); logger.info("sdkAppId:"+sdkAppId); logger.info("sign:"+sign); String resultSign = getResultSign(key,body); logger.info("resultSign:"+resultSign); if (resultSign.equals(sign)) {
JSONObject jsonObject = (JSONObject) JSON.parse(body); Integer eventType = jsonObject.getInteger("EventType"); // 事件类型 String eventInfo = jsonObject.getString("EventInfo"); // 事件信息 JSONObject jsonObject1 = (JSONObject) JSON.parse(eventInfo); String taskId = jsonObject1.getString("TaskId"); // 任务ID String payload = jsonObject1.getString("Payload"); // 根据不同事件类型定义不同 JSONObject jsonObject2 = (JSONObject) JSON.parse(payload); String tencentVod = jsonObject2.getString("TencentVod"); // 点播平台信息 JSONObject jsonObject3 = (JSONObject) JSON.parse(tencentVod); if (eventType == 311) {
// 录制视频上传成功 String fileId = jsonObject3.getString("FileId"); // 点播平台的唯一 ID String videoUrl = jsonObject3.getString("VideoUrl"); // 点播平台的播放地址 // 进行相关业务逻辑处理 // 311事件证明视频已成功上传到云点播, // 建立相关的数据库用来存储音视频录制地址并和相关的业务ID绑定,用于后续下载 / * 使用线程池进行音视频下载,控制最大并发数,防止资源抢占导致服务崩溃 */ ExecutorService executorService = Executors.newCachedThreadPool(); executorService.submit(() -> {
try {
downloadVideo(fileIds); TimeUnit.SECONDS.sleep(1000 * 60 * 30); // 等待30分钟 } catch (Exception e) {
e.printStackTrace(); } }); } } else {
logger.debug("{'Status': 'FAIL', 'Info': '校验失败'}"); } logger.debug("腾讯云测试成功"); }
2.8 音视频下载
2.8.1 音视频列表查询接口
为了保证数据的安全性,我们需要把云点播的音视频存储到医院的服务器上面,然后将云点播上面的音视频删除掉,然后将存储地址表中的视频路径改成服务器的路径。
音视频下载API文档地址:https://cloud.tencent.com/document/product/266/84093
https://cloud.tencent.com/document/product/266/31763
通过fileIds查询出在云点播上面存储的音视频列表,然后下载,再删除
输入(出)参数我就不做赘述了详细信息请看API文档
讯享网 / * 查询出音视频集合,并下载,在将云点播上面的音视频删除 * @param fileIds 点播平台唯一ID集合 * @throws Exception */ private void downloadVideo(String [] fileIds) throws Exception {
try{
//创建文件对象 Properties properties = new Properties(); //加载文件获取数据 文件带后缀 properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream ("application.properties")); //根据key来获取value String secretId = properties.getProperty("secretid"); String secretKey = properties.getProperty("secretkey"); // 实例化一个认证对象,入参需要传入腾讯云账户 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("vod.tencentcloudapi.com"); // 实例化一个client选项,可选的,没有特殊需求可以跳过 ClientProfile clientProfile = new ClientProfile(); clientProfile.setHttpProfile(httpProfile); // 实例化要请求产品的client对象,clientProfile是可选的 VodClient client = new VodClient(cred, "ap-beijing", clientProfile); // 实例化一个请求对象,每个接口都会对应一个request对象 DescribeMediaInfosRequest req = new DescribeMediaInfosRequest(); req.setFileIds(fileIds); String[] basicInfos = {
"basicInfo"}; req.setFilters(basicInfos); // 返回的resp是一个DescribeMediaInfosResponse的实例,与请求对象对应 DescribeMediaInfosResponse resp = client.DescribeMediaInfos(req); // 输出json格式的字符串回包 logger.info(DescribeMediaInfosResponse.toJsonString(resp)); String json = DescribeMediaInfosResponse.toJsonString(resp); JSONObject jsonObject = (JSONObject) JSON.parse(json); JSONArray jsonArray = jsonObject.getJSONArray("MediaInfoSet"); // 媒体文件信息列表。 for (int i = 0; i < jsonArray.size(); i++) {
JSONObject jsonObject1 = jsonArray.getJSONObject(i); String fileId = jsonObject1.getString("FileId"); // 点播平台的唯一 ID String basicInfo = jsonObject1.getString("BasicInfo"); // 基础信息 JSONObject jsonObject2 = (JSONObject) JSON.parse(basicInfo); String mediaUrl = jsonObject2.getString("MediaUrl"); // 文件地址 String downPath = downloadImage(mediaUrl); // 下载音视频(返回本地下载地址) // 将未下载的音视频列表查询出来,进行下载到服务器上面,并更新数据库数据 // 业务逻辑处理 delVideo(fileId); // 删除音视频 logger.info(downPath); // 本地地址 } logger.info("下载音视频成功"); } catch (TencentCloudSDKException e) {
logger.debug(e.toString()); } catch (IOException e) {
e.printStackTrace(); } logger.debug("腾讯云测试成功"); }
2.8.2 音视频下载接口
通过fileIds查询出在云点播上面存储的音视频列表,然后下载,再删除
下载地址:https://blog.csdn.net/_/article/details/
代码
/ * 将视频下载到本地 * @param fileUrl 视频路径 * @return */ public String downloadImage(String fileUrl) {
long l = 0L; String path = null; String staticAndMksDir = null; if (fileUrl != null) {
//下载时文件名称 String fileName = fileUrl.substring(fileUrl.lastIndexOf(".")); try {
String dataStr = new SimpleDateFormat("yyyyMMdd").format(new Date()); String uuidName = UUID.randomUUID().toString(); path = "resources/images/"+dataStr+"/"+uuidName+fileName; staticAndMksDir = Paths.get(ResourceUtils.getURL("classpath:").getPath(),"resources", "images",dataStr).toFile().toString(); HttpUtil.downloadFile(fileUrl, staticAndMksDir + File.separator + uuidName + fileName); } catch (Exception e) {
e.printStackTrace(); } finally {
logger.debug("下载成功"); } } log.info(System.currentTimeMillis()-l); return path; }
2.9 删除音视频
为了保证数据的安全性,我们需要把云点播的音视频存储到医院的服务器上面,然后将云点播上面的音视频删除掉,然后将存储地址表中的视频路径改成服务器的路径。
音视频删除API文档地址:https://cloud.tencent.com/document/product/266/31764
输入(出)参数我就不做赘述了详细信息请看API文档
讯享网 / * 删除音视频 * @param fileId 通过点播平台唯一ID删除掉音视频 * @throws Exception */ private void delVideo(String fileId) throws Exception {
try{
//创建文件对象 Properties properties = new Properties(); //加载文件获取数据 文件带后缀 properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream ("application.properties")); //根据key来获取value String secretId = properties.getProperty("secretid"); String secretKey = properties.getProperty("secretkey"); // 实例化一个认证对象,入参需要传入腾讯云账户 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("vod.tencentcloudapi.com"); // 实例化一个client选项,可选的,没有特殊需求可以跳过 ClientProfile clientProfile = new ClientProfile(); clientProfile.setHttpProfile(httpProfile); // 实例化要请求产品的client对象,clientProfile是可选的 VodClient client = new VodClient(cred, "", clientProfile); // 实例化一个请求对象,每个接口都会对应一个request对象 DeleteMediaRequest req = new DeleteMediaRequest(); req.setFileId(fileId); // 返回的resp是一个DeleteMediaResponse的实例,与请求对象对应 DeleteMediaResponse resp = client.DeleteMedia(req); // 输出json格式的字符串回包 // 输出json格式的字符串回包 logger.info("删除音视频成功"); logger.info("删除音视频:", DeleteMediaResponse.toJsonString(resp)); } catch (TencentCloudSDKException e) {
logger.debug(e.toString()); } }
至此我们集成腾讯音视频就结束了
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YaUQaOLH-1680487013379)(C:\Users\11\AppData\Roaming\Typora\typora-user-images\image-20230403092937476.png)]](https://img-blog.csdnimg.cn/5decc1a66d904d45bcc8338bd75c7d15.png)
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/27689.html