产品文档

音视频通信 JRTC

2025-04-23 05:27:23

回调配置说明

  • 回调配置用于设置接收各类回调事件通知的信息

  • 房间回调事件:进入房间/退出房间等事件通知。

  • 媒体回调事件:支持开始/停止推送视频数据、开始/停止推送音频数据 等事件通知。

  • JRTC 后续将支持更多回调类型。

事件回调服务支持将实时音视频业务下的事件,以 HTTP/HTTPS 请求的形式通知到您的服务器。

配置信息

实时音视频 JRTC 控制台支持自助配置回调地址,添加回调通知秘钥及超时时间(秒),配置完成后即可接收带鉴权的事件回调通知。

回调鉴权

签名及验证规则

1、通知消息体按参数名key的字典顺序排列拼接成字符转,每个参数(key-value)直接用&链接

1.1、消息源

{
  "appId": "92bc34004019265a7b1ad17c6c7",
  "notifyType": "MEDIA",
  "notifyTs": "1625126096801",
  "eventName": "EVENT_START_VIDEO",
  "eventTs": "1644204008651",
  "eventInfo": {
    "roomId": 6666,
    "userRoomId": "room-6666",
    "peerId": 6666,
    "userId": "userId-6666",
    "nickName": "6666",
    "streamInfo": {
      "streamId": "6666.6666.2.1.480",
      "kind": "VIDEO",
      "deviceType": 1
    }
  }
}

1.2、待签名字符串

appId=92bc34004019265a7b1ad17c6c7&eventInfo={nickName=6666&peerId=6666&roomId=6666&streamInfo={deviceType=1&kind=VIDEO&streamId=6666.6666.2.1.480}&userId=userId-6666&userRoomId=room-6666}&eventName=EVENT_START_VIDEO&eventTs=1644204008651&notifyType=MEDIA

1.3、签名后

b01NWGFiSi9USHdlQUlFdDQzQ0JSeXgybGpLaSs0dzZveXpaYndpUUtWdz0_

2、根据业务方配置的回调URL,拼接回调鉴权等信息后,通知业务方

https://test/callback?ts=1644204702826&tk=b01NWGFiSi9USHdlQUlFdDQzQ0JSeXgybGpLaSs0dzZveXpaYndpUUtWdz0_&nonce=e069cebccde3406da7111aece977deb3


3、签名及验证算法

业务方收到回调信息后对回调信息签名后与url中获取的tk(回调鉴权)进行比对,来判断是否为来自京东云视音频通讯服务的合法回调

参数及来源

字段名 类型 参数来源
appId String jrtc应用ID
notifyKey String 官网控制台回调中配置的通知秘钥
notifyMessage String 接收到的回调消息
nonce String 随机数-回调地址中获取
timestamp long 时间戳-回调地址中获取 ts ,单位:毫秒
notifyToken String 回调鉴权-回调地址中获取tk

签名校验算法

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
 
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.*;
 
/**
 * Created on 2月 07, 2022.
 *
 * @author Zhangxi19
 */
@Slf4j
public class NotifyTokenUtil {
 
    private static final String H_MAC_SHA_256 = "HmacSHA256";
 
    public static Boolean validate(String appId, String notifyKey, String notifyMessage, String nonce, Long timestamp, String notifyToken) {
        Long now = Instant.now().toEpochMilli();
        if (now < timestamp) {
            Map sourceMap = new TreeMap();
            sourceMap.put("appId", appId);
            sourceMap.put("notifyKey", notifyKey);
            sourceMap.put("timestamp", timestamp);
            sourceMap.put("notifyMessage", message2UriString(new StringBuffer(), notifyMessage, true));
 
            String check = encrypt(JSONObject.toJSONString(sourceMap), nonce);
            return check.equals(notifyToken);
        }
        log.info("NotifyTokenUtil.validate.warn, timestamp is expire......");
        return false;
    }
 
    public static String message2UriString(StringBuffer buffer, String notifyMessage, boolean flag) {
        if (StringUtils.isEmpty(notifyMessage)) {
            return buffer.toString();
        }
        TreeMap treeMap = JSONObject.parseObject(notifyMessage, TreeMap.class);
        Set<Map.Entry<Object, Object>> set = treeMap.entrySet();
        Iterator<Map.Entry<Object, Object>> iterator = set.iterator();
 
        while (iterator.hasNext()) {
            Map.Entry<Object, Object> next = iterator.next();
            Object key = next.getKey();
            Object val = next.getValue();
            if (buffer.length() == 0 || flag == true) {
                buffer.append(key).append("=");
                flag = false;
            } else {
                buffer.append("&").append(key).append("=");
            }
            if (val instanceof JSONObject) {
                buffer.append("{");
                message2UriString(buffer, JSONObject.toJSONString(val), true);
                buffer.append("}");
            } else {
                buffer.append(val);
            }
        }
        return buffer.toString();
    }
 
    public static String encrypt(String strSrc, String nonce) {
        try {
            Mac hmac = Mac.getInstance(H_MAC_SHA_256);
            SecretKeySpec keySpec256 = new SecretKeySpec(nonce.getBytes(StandardCharsets.UTF_8), H_MAC_SHA_256);
            hmac.init(keySpec256);
            byte[] byteSig = hmac.doFinal(strSrc.getBytes(StandardCharsets.UTF_8));
            String origin = new String(Base64.getEncoder().encode(byteSig), StandardCharsets.UTF_8);
 
            return replaceCharacter(Base64.getEncoder().encode(origin.getBytes(StandardCharsets.UTF_8)));
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }
 
    private static String replaceCharacter(byte[] input) {
        byte[] base64 = new String(input, StandardCharsets.UTF_8).getBytes(StandardCharsets.UTF_8);
        for (int i = 0; i < base64.length; ++i) {
            switch (base64[i]) {
                case '+':
                    base64[i] = '*';
                    break;
                case '/':
                    base64[i] = '-';
                    break;
                case '=':
                    base64[i] = '_';
                    break;
                default:
                    break;
            }
        }
        return new String(base64, StandardCharsets.UTF_8);
    }
}

超时重试

事件回调服务器在发送消息通知后,7秒内没有收到您的服务器的响应,即认为通知失败。首次通知失败后,第一次重试为1秒,第二次为2秒,第三次为4秒。

事件回调消息格式

事件回调消息以 HTTP/HTTPS POST 请求发送给您的服务器,其中:

  • 字符编码格式:UTF-8。

  • 请求:body 格式为 JSON。

  • 应答:HTTP STATUS CODE = 200,服务端忽略应答包具体内容。

1、房间通知

  • 示例:下述为“房间通知-进入房间”事件的消息示例

{
  "appId": "92bc34004019265a7b1ad17c6c7",
  "notifyType": "ROOM",
  "notifyTs": "1625127894779",
  "eventName": "EVENT_ENTER_ROOM",
  "eventTs": "1625127894775",
  "eventInfo": {
    "roomId": 8926,
    "userRoomId":"room-8926",
    "peerId": 1222,
    "userId":"test-ee124",
    "nickName": "1222",
    "streamInfo": null
  }
}

2、媒体通知

示例:下述为“媒体通知-开始推送视频流”事件的消息示例

{
  "appId": "92bc34004019265a7b1ad17c6c7",
  "notifyType": "MEDIA",
  "notifyTs": "1625126096801",
  "eventName": "EVENT_START_VIDEO",
  "eventTs": "1644204008651",
  "eventInfo": {
    "roomId": 6666,
    "userRoomId":"room-6666",
    "peerId": 6666,
    "userId":"userId-6666",
    "nickName": "6666",
    "streamInfo": {
      "streamId": "6666.6666.2.1.480",
      "kind": "VIDEO",
      "deviceType": 1    
    }
  }
}

回调消息参数说明

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

NotifyMessage

字段名 类型 含义
appId String jrtc应用ID
notifyType String 通知类型 ROOM-房间通知 MEDIA-媒体通知
notifyTs Number 事件回调服务器向您的服务器发出回调请求的 Unix 时间戳,单位为毫秒
eventName String 事件名称
eventInfo EventInfo 事件消息

EventInfo

字段名 类型 含义
userRoomId String 用户自定义房间号
roomId Number 房间ID
peerId Number peerId
userId String 用户自定义id
nickName String 用户在房间内的昵称
streamInfo StreamInfo 流信息

StreamInfo

字段名 类型 含义
streamId String 流ID
kind String 标识音视频 VIDEO-视频 AUDIO-音频
deviceType String 标识推流设备类型    业务方传递再回调给业务方
  • 通知类型及事件说明

通知类型-notifyType

字段名 含义
ROOM 房间事件通知
MEDIA 媒体事件通知

事件名称-eventName

字段名 含义
EVENT_ENTER_ROOM 进入房间
EVENT_EXIT_ROOM 退出房间
EVENT_START_VIDEO 开始推送视频数据
EVENT_STOP_VIDEO 停止推送视频数据
EVENT_START_AUDIO 开始推送音频数据
EVENT_STOP_AUDIO 停止推送音频数据

3、录制通知

示例:下述为“录制通知” 事件的消息示例

{
  "vFramerate": "24.958",
  "ver": "1.0",
  "format": "mp4",
  "userRoomId": "room-6666",
  "bitrate": 4185250,
  "aSampleRate": 16000,
  "url": "https://xxx.com/meeting/record/92bc34004019265a7b1ad17c6c7/room-6666/room-6666_1cad6904-a399-44c3-95d6-30fbea3cb99a_20250418110100.mp4",
  "duration": "1215294",
  "aProfile": "LC",
  "aChannel": 2,
  "fileSize": "635788720",
  "appId": "92bc34004019265a7b1ad17c6c7",
  "width": 1920,
  "event": "record_done",
  "taskId": "6h93e1ca829b31676666667f0429",
  "aCodec": "aac",
  "height": 1080,
  "md5": "a94510f2d38c43311114df99ac9ee",
  "status": "success",
  "vCodec": "h264"
}
字段名 类型 含义
appId String jrtc应用ID
userRoomId String 用户自定义房间号
event String 事件名
taskId String 录制任务ID
url String 录制文件地址 https://endpoint/bucket/path
format String 文件格式
duration Long 录制时长(秒)
md5 String md5
status String 录制状态
fileSize Long 录制文件大小 Byte
width int 视频宽
height int 视频高
bitrate Long 视频码率
vCodec String 视频编码
vFramerate Double 视频帧率
aSampleRate int 音频采样率
aCodec String 音频编码
aProfile String 音频编码档次
aChannel int 声道
ver String 版本
文档反馈

开始与售前顾问沟通

可直接拨打电话 400-098-8505转1

我们的产品专家为您找到最合适的产品/解决⽅案

在线咨询 5*8⼩时

1v1线上咨询获取售前专业咨询

点击咨询
企微服务助手

专业产品顾问,随时随地沟通