含 UI 集成方案

诚邀爱技术、爱分享的你,成为文档内容共建者> HOT
本文针对新版云端录制功能的回调事件进行具体说明。

配置信息

实时音视频 TRTC 控制台支持自助配置回调信息,配置完成后即可接收事件回调通知。详细操作指引请参见 回调配置
注意
您需要提前准备以下信息并在控制台完成回调配置
必要项:接收回调通知的 HTTP/HTTPS 服务器地址。
可选项计算签名的密钥 key,由您自定义一个最大32个字符的 key,以大小写字母及数字组成。

超时重试

事件回调服务器在发送消息通知后,5秒内没有收到您的服务器的响应,即认为通知失败。首次通知失败后会立即重试,后续失败会以10秒的间隔继续重试,直到消息存续时间超过1分钟,不再重试。

回调接口

您可以提供一个接收回调的 HTTP / HTTPS 服务网关来订阅回调消息。当相关事件发生时,云录制系统会回调事件通知到您的消息接收服务器。

事件回调消息格式

事件回调消息以 HTTP/HTTPS POST 请求发送给您的服务器,其中:
字符编码格式:UTF-8。
请求:body 格式为 JSON。
应答:HTTP STATUS CODE = 200,服务端忽略应答包具体内容,为了协议友好,建议客户应答内容携带 JSON: {"code":0}。

参数说明

事件回调消息的 header 中包含以下字段

字段名
Content-Type
application/json
Sign
签名值
SdkAppId
sdk application id

事件回调消息的 body 中包含以下字段:

字段名
类型
含义
EventGroupId
Number
事件组 ID, 云端录制固定为3
EventType
Number
回调通知的事件类型
CallbackTs
Number
事件回调服务器向您的服务器发出回调请求的 Unix 时间戳,单位为毫秒
EventInfo
JSON Object
事件信息

事件类型说明

字段名
类型
含义
EVENT_TYPE_CLOUD_RECORDING_RECORDER_START
301
云端录制录制模块启动
EVENT_TYPE_CLOUD_RECORDING_RECORDER_STOP
302
云端录制录制模块退出
EVENT_TYPE_CLOUD_RECORDING_FAILOVER
306
云端录制发生迁移,原有的录制任务被迁移到新负载上时触发
EVENT_TYPE_CLOUD_RECORDING_DOWNLOAD_IMAGE_ERROR
309
云端录制下载解码图片文件发生错误
EVENT_TYPE_CLOUD_RECORDING_VOD_COMMIT
311
云端录制 VOD 录制任务上传媒体资源完成
EVENT_TYPE_CLOUD_RECORDING_VOD_STOP
312
云端录制 VOD 录制任务结束
注意:
301-309区间的回调状态为实时录制的中间状态,可以更加清晰的知晓录制任务的进行过程并记录状态,实际录制文件上传到点播成功会回调311事件,整体任务结束回调312事件。

事件信息说明

字段名
类型
含义
RoomId
String/Number
房间名(类型与客户端房间号类型一致)
EventTs
Number
时间发生的 Unix 时间戳,单位为秒
UserId
String
录制机器人的用户 ID
TaskId
String
录制 ID,一次云端录制任务唯一的 ID
Payload
JsonObject
根据不同事件类型定义不同

事件类型为301
(EVENT_TYPE_CLOUD_RECORDING_RECORDER_START)时 Payload 的定义:
字段名
类型
含义
Status
Number
0:代表录制模块启动成功
1:代表录制模块启动失败
{
"EventGroupId": 3,
"EventType": 301,
"CallbackTs": 1622186275913,
"EventInfo": {
"RoomId": "xx",
"EventTs": "1622186275",
"UserId": "xx",
"TaskId": "xx",
"Payload": {
"Status": 0
}
}
}

事件类型为302
(EVENT_TYPE_CLOUD_RECORDING_RECORDER_STOP)时 Payload 的定义:
字段名
类型
含义
LeaveCode
Number
0:代表录制模块正常调用停止录制退出
1:录制机器人被客户踢出房间
2:客户解散房间
3:服务器将录制机器人踢出
4:服务器解散房间
99:代表房间内除了录制机器人没有其他用户流,超过指定时间退出
100:房间超时退出
101:同一用户重复进入相同房间导致机器人退出
{
"EventGroupId": 3,
"EventType": 302,
"CallbackTs": 1622186354806,
"EventInfo": {
"RoomId": "xx",
"EventTs": "1622186354",
"UserId": "xx",
"TaskId": "xx",
"Payload": {
"LeaveCode": 0
}
}
}

事件类型为306
(EVENT_TYPE_CLOUD_RECORDING_FAILOVER)时 Payload 的定义:
字段名
类型
含义
Status
Number
0:代表此次迁移已经完成
{
"EventGroupId": 3,
"EventType": 306,
"CallbackTs": 1622191989674,
"EventInfo": {
"RoomId": "20015",
"EventTs": 1622191989,
"UserId": "xx",
"TaskId": "xx",
"Payload": {
"Status": 0
}
}
}

事件类型为309
(EVENT_TYPE_CLOUD_RECORDING_DOWNLOAD_IMAGE_ERROR)时 Payload 的定义:
段名
类型
含义
Url
String
下载失败的 URL
{
"EventGroupId": 3,
"EventType": 309,
"CallbackTs": 1622191989674,
"EventInfo": {
"RoomId": "20015",
"EventTs": 1622191989,
"UserId": "xx",
"TaskId": "xx",
"Payload": {
"Url": "http://xx",
}
}
}

事件类型为311
(EVENT_TYPE_CLOUD_RECORDING_VOD_COMMIT)时 Payload 的定义:
字段名
类型
含义
Status
Number
0:代表本录制文件正常上传至点播平台
1:代表本录制文件滞留在服务器或者备份存储上
2:代表本录制文件上传点播任务异常
UserId
String
本录制文件对应的用户 ID(当录制模式为合流模式时,此字段为空)
TrackType
String
audio/video/audio_video
MediaId
String
main/aux(main 代表主流,aux 代表辅流)
FileId
String
本录制文件在点播平台的唯一 ID
VideoUrl
String
本录制文件在点播平台的播放地址
CacheFile
String
本录制文件对应的 MP4/HLS 文件名
StartTimeStamp
Number
本录制文件开始的 UNIX 时间戳(毫秒)
EndTimeStamp
Number
本录制文件结束的 UNIX 时间戳(毫秒)
Errmsg
String
statue 不为0时,对应的错误信息
上传成功的回调:
{
"EventGroupId": 3,
"EventType": 311,
"CallbackTs": 1622191965320,
"EventInfo": {
"RoomId": "20015",
"EventTs": 1622191965,
"UserId": "xx",
"TaskId": "xx",
"Payload": {
"Status": 0,
"TencentVod": {
"UserId": "xx",
"TrackType": "audio_video",
"MediaId": "main",
"FileId": "xxxx",
"VideoUrl": "http://xxxx",
"CacheFile": "xxxx.mp4",
"StartTimeStamp": xxxx,
"EndTimeStamp": xxxx
}
}
}
}
上传失败的回调:
{
"EventGroupId": 3,
"EventType": 311,
"CallbackTs": 1622191965320,
"EventInfo": {
"RoomId": "20015",
"EventTs": 1622191965,
"UserId": "xx",
"TaskId": "xx",
"Payload": {
"Status": 1,
"Errmsg": "xxx",
"TencentVod": {
"UserId": "123",
"TrackType": "audio_video",
"CacheFile": "xxx.mp4"
}
}
}
}

事件类型为312
(EVENT_TYPE_CLOUD_RECORDING_VOD_STOP)时 Payload 的定义:
字段名
类型
含义
Status
Number
0:代表本次上传 VOD 任务已经正常退出
1:代表本次上传 VOD 任务异常退出
{
"EventGroupId": 3,
"EventType": 312,
"CallbackTs": 1622191965320,
"EventInfo": {
"RoomId": "20015",
"EventTs": 1622191965,
"UserId": "xx",
"TaskId": "xx",
"Payload": {
"Status": 0
}
}
}

计算签名

签名由 HMAC SHA256 加密算法计算得出,您的事件回调接收服务器收到回调消息后,通过同样的方式计算出签名,相同则说明是腾讯云的实时音视频的事件回调,没有被伪造。签名的计算如下所示:
//签名 Sign 计算公式中 key 为计算签名 Sign 用的加密密钥。
Sign = base64(hmacsha256(key, body))
注意
body 为您收到回调请求的原始包体,不要做任何转化,示例如下:
body="{\\n\\t\\"EventGroupId\\":\\t1,\\n\\t\\"EventType\\":\\t103,\\n\\t\\"CallbackTs\\":\\t1615554923704,\\n\\t\\"EventInfo\\":\\t{\\n\\t\\t\\"RoomId\\":\\t12345,\\n\\t\\t\\"EventTs\\":\\t1608441737,\\n\\t\\t\\"UserId\\":\\t\\"test\\",\\n\\t\\t\\"UniqueId\\":\\t1615554922656,\\n\\t\\t\\"Role\\":\\t20,\\n\\t\\t\\"Reason\\":\\t1\\n\\t}\\n}"

签名校验示例

java

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
//# 功能:第三方回调sign校验
//# 参数:
//#   key:控制台配置的密钥key
//#   body:腾讯云回调返回的body体
//#   sign:腾讯云回调返回的签名值sign
//# 返回值:
//#   Status:OK 表示校验通过,FAIL 表示校验失败,具体原因参考Info
//#   Info:成功/失败信息

public class checkSign {
    public 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()));
    }
    public static void main(String[] args) throws Exception {
        String key = "123654";
        String body = "{\\n" + "\\t\\"EventGroupId\\":\\t2,\\n" + "\\t\\"EventType\\":\\t204,\\n" + "\\t\\"CallbackTs\\":\\t1664209748188,\\n" + "\\t\\"EventInfo\\":\\t{\\n" + "\\t\\t\\"RoomId\\":\\t8489,\\n" + "\\t\\t\\"EventTs\\":\\t1664209748,\\n" + "\\t\\t\\"EventMsTs\\":\\t1664209748180,\\n" + "\\t\\t\\"UserId\\":\\t\\"user_85034614\\",\\n" + "\\t\\t\\"Reason\\":\\t0\\n" + "\\t}\\n" + "}";
        String Sign = "kkoFeO3Oh2ZHnjtg8tEAQhtXK16/KI05W3BQff8IvGA=";
        String resultSign = getResultSign(key, body);

        if (resultSign.equals(Sign)) {
            System.out.println("{'Status': 'OK', 'Info': '校验通过'}");
        } else {
            System.out.println("{'Status': 'FAIL', 'Info': '校验失败'}");
        }
    }
}

python

# -*- coding: utf8 -*-
import hmac
import base64
from hashlib import sha256

# 功能:第三方回调sign校验
# 参数:
#   key:控制台配置的密钥key
#   body:腾讯云回调返回的body体
#   sign:腾讯云回调返回的签名值sign
# 返回值:
#   Status:OK 表示校验通过,FAIL 表示校验失败,具体原因参考Info
#   Info:成功/失败信息

def checkSign(key, body, sign):
    temp_dict = {}
    computSign = base64.b64encode(hmac.new(key.encode('utf-8'), body.encode('utf-8'), digestmod=sha256).digest()).decode('utf-8')
    print(computSign)
    if computSign == sign:
        temp_dict['Status'] = 'OK'
        temp_dict['Info'] = '校验通过'
        return temp_dict
    else:
        temp_dict['Status'] = 'FAIL'
        temp_dict['Info'] = '校验失败'
        return temp_dict

if __name__ == '__main__':
    key = '123654'
    body = "{\\n" + "\\t\\"EventGroupId\\":\\t2,\\n" + "\\t\\"EventType\\":\\t204,\\n" + "\\t\\"CallbackTs\\":\\t1664209748188,\\n" + "\\t\\"EventInfo\\":\\t{\\n" + "\\t\\t\\"RoomId\\":\\t8489,\\n" + "\\t\\t\\"EventTs\\":\\t1664209748,\\n" + "\\t\\t\\"EventMsTs\\":\\t1664209748180,\\n" + "\\t\\t\\"UserId\\":\\t\\"user_85034614\\",\\n" + "\\t\\t\\"Reason\\":\\t0\\n" + "\\t}\\n" + "}"
    sign = 'kkoFeO3Oh2ZHnjtg8tEAQhtXK16/KI05W3BQff8IvGA='
    result = checkSign(key, body, sign)
    print(result)
目录