超低延时直播RTS是以WebRTC信令交互方式为基础,借助阿里云直播节点的全球覆盖及优秀调度算法能力,实现功能。通过阅读本文,您可以了解WebRTC标准接入GRTN信令协议的详细信息。本文适合具有WebRTC基础的开发人员阅读。

背景信息

阿里云视频直播服务(ApsaraVideo Live)为解决使用TCP协议引起的3~6秒以上延时的问题,提供使用UDP协议的超低延时直播RTS(Real-time Streaming)增值功能,具备易接入、毫秒级别延迟、千万级高并发、高清流畅的直播观看体验。RTS产品设计重视开放、标准的生态建设,在使用阿里云提供的专用RTS SDK基础上,还支持自研客户端以类似WebRTC信令交互方式从直播节点推拉音视频流,借助阿里云直播节点的全球覆盖及优秀调度算法能力,帮助客户大规模实现自主可控方式便利地使用阿里云超低延时直播服务。

目前GRTN对外开放抗弱网能力。

前提条件

信令交互流程

信令交互图如下所示:

001

信令交互流程

  1. 客户端发送offer请求。
    1. 客户端本地创建RTCPeerConnection,设置接收音视频属性Stream Direction,并创建offer SDP。
      // 开启音视频, recvonly or sendonly
      { offerToReceiveVideo: true, offerToReceiveAudio: true }
    2. 客户端向直播服务发送拉流请求,通过HTTPS POST协议方式将JSON格式的请求信息发送至直播服务。协议格式请参见信令协议定义
      • version字段为协议版本,当前版本固定为2。
      • sdk_version字段为SDK版本,您可以自定义该字段。
    3. 生成协议内容后,通过POST方式将信令地址给直播服务完成信令交互,在请求的JSON包体中包含要拉取的流地址。
      POST /app/streamname?auth=xxx HTTP/1.1
      Host: domain
      Connection: keep-alive
      Content-Length: 2205
      Content-Type: application/json
      说明 信令地址与流地址基本一致,协议头不同,如下所示:
      • 信令地址:https://domain/app/streamname?auth=xxx
      • 流地址:artc://domain/app/streamname?auth=xxx
  2. 服务端SDP Answer响应。

    直播服务端校验安全性后生成SDP Answer, 节点信息封装在响应包体中返回给客户端。协议格式请参见信令协议定义

  3. 客户端ICE建联。
    1. 客户端收到SDP Answer响应后,设置到RTCPeerConnection中。
      peerConnection.setRemoteDescription(new RTCSessionDescription(answer.jsep));
    2. RTCPeerConnection启动ICE建连流程以及后续的DTLS流程,媒体通道建立成功后可以获取到直播服务输出的媒体流,实现WebRTC标准接入拉流播放。
  4. 断开连接。

    客户端需要断开连接停止推流或播放,使用DTLS的Alert消息表达。

    断开连接
H5 Demo示例
// Create peer connection and local offer sdp.
peerConnection = new RTCPeerConnection();
peerConnection.onicecandidate = iceCandidateCallback;
peerConnection.ontrack = remoteStreamCallback;
peerConnection.createOffer({ offerToReceiveVideo: true, offerToReceiveAudio: true })
      .then(signaling_pull).catch(errorHandler);


// CDN live post pull stream request.
function signaling_pull(offer_sdp) {
  console.log('local offer sdp', offer_sdp);

  peerConnection.setLocalDescription(offer_sdp).then(function() {
    // Get pull stream url.
    var stream_url = $("#stream_url").val();
    console.log("stream url:" , stream_url);

    // Add sdk and protocol versions.
    var protocol_version = 2;
    var sdk_version = "0.0.1";

    $.ajax({url: stream_url, data: JSON.stringify({
          mode: "live",
          version: protocol_version,
          sdk_version: sdk_version,
          jsep:description,
      }),
      type: "post",
      success:function(result){
          var signal = JSON.parse(result);
          peerConnection.setRemoteDescription(new RTCSessionDescription(signal.jsep)).then(function() {
              console.log("get remote answer sdp: ", signal.jsep.sdp);
          }).catch(errorHandler);
      }});
  }).catch(errorHandler);
}
                

信令协议定义

RTS信令协议通道为HTTPS(短链接),格式为JSON。样例如下所示:

{
    "version":2,
    "sdk_version":"0.0.1",
    "mode":"live",
    "pull_streams":[
        {
            "url":"artc://your.domain.com/live/testname",
            "amsid":[
                "rts audio"
            ],
            "vmsid":[
                "rts video"
            ]
        }
    ],
    "jsep":{
        "type":"offer",
        "sdp":"v=0\n\ro=- 6839248142876176651 2 IN IP4 127.0.0.1\n\rs=-\n\r以下省略"
    }
}

播放

  • 播放相关协议描述
    表 1. 请求参数
    参数 类型 是否必选 描述
    mode string 模式,取值:live。
    version int 协议版本号,取值:2。
    push_stream string 推流URL。
    pull_streams []object 拉流对象,支持多个拉流。详情请参见下表。
    sdk_version string SDK版本号。
    jsep.type string SDP类型,取值:offer。
    jsep.sdp string SDP描述。
    表 2. pull_stream参数
    字段 类型 是否必填 描述
    url string 拉流URL,例如:artc://<拉流地址>
    amsid []string 拉流音频msid,直播场景取值rts audio
    vmsid []string 拉流视频msid,直播场景取值rts video
    表 3. 应答参数
    字段 类型 是否必填 描述
    code int 返回码。正确返回200,错误码请参见下表错误码描述。
    trace_id string 全局唯一请求标识ID,由CDN生成,请客户尽量做好保存,用于对请求进行定位和问题排查。
    jsep.type string SDP类型,取值:answer。
    jsep.sdp string 直播CDN回源拉流生成SDP
  • 播放请求示例
    Request:
    {
        "version":2,
        "sdk_version":"0.0.1",
        "mode":"live",
        "pull_streams":[
            {
                "url":"artc://your.domain.com/live/testname",
                "amsid":[
                    "rts audio"
                ],
                "vmsid":[
                    "rts video"
                ]
            }
        ],
        "jsep":{
            "type":"offer",
            "sdp":"v=0\n\ro=- 6839248142876176651 2 IN IP4 127.0.0.1\n\rs=-\n\r以下省略"
        }
    }
    
    Response:
    {
        "trace_id":"2_1591173296_101.227.0.169_702080732320_dec327eb6eed0e0b07b349c8a5653eca",
        "code":200,
        "jsep":{
            "type":"answer",
            "sdp":"v=0\r\no=- 1591173291 2 IN IP4 127.0.0.1\n\r 以下省略"
        }
    }

    sps-pps-idr-in-keyframe:推荐以下操作,可以避免浏览器在弱网场景播放部分直播流的时候出现视频花屏。

    在H5订阅流(recvonly)生成offer之后(createOfferOnSuccess)调用setLocalDescription之前,修改SDP,将H.264视频属性中类似下面的行:
    a=fmtp:127 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f
    添加sps-pps-idr-in-keyframe=1,变为:
    a=fmtp:127 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f;sps-pps-idr-in-keyframe=1

    GRTN会进行响应,让浏览器开启本特性。

  • 错误处理

    信令请求合法的情况下响应200 ,具体的处理结果需要解析响应body的JSON内的code属性。code为HTTP响应码模式,具体定义如下:

    Response:
    {
       "code": 200, // 200-成功 非200-见后续定义
       "message": "success"  // 非200错误码描述
    }
    表 4. 应答参数
    参数 类型 描述
    code int 响应码,格式和定义参见下表。
    message string 错误描述。
    表 5. 错误码描述
    错误码 描述
    403 鉴权失败。
    404 流不存在。
    611 需要客户端强制降级到TCP播放。
    302 需要客户端向新的服务地址发起信令请求。

推流

  • 推流相关协议描述
    表 6. 请求参数
    参数 类型 是否必选 描述
    mode string 模式,取值:live。
    version int 协议版本号,取值:2。
    push_stream string 推流URL。
    sdk_version string SDK版本号。
    jsep.type string SDP类型,取值:offer。
    jsep.sdp string SDP描述。
    表 7. 应答参数
    字段 类型 是否必填 描述
    code int 返回码。正确返回200,错误码请参见下表错误码描述。
    trace_id string 全局唯一请求标识ID,由CDN生成,请客户尽量做好保存,用于对请求进行定位和问题排查。
    jsep.type string SDP类型,取值:answer。
    jsep.sdp string 直播CDN回源拉流生成SDP
  • 推流请求示例
    Request:
    {
        "version":2,
        "sdk_version":"0.0.1",
        "mode":"rtc",
        "push_stream":"artc://host/app/name",
        "jsep":{
            "type":"offer",
            "sdp":"v=0\r\no=- 1385856200224536561 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE 0 1 2\r\na=extmap-allow-mixed\r\na=msid-semantic: WMS rts\r\nm=audio 9 UDP/TLS/RTP/SAVPF 111 63 103 104 9 0 8 106 105 13 110 112 113 126\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:iQyM\r\na=ice-pwd:D3GXKCcUGvW9djaAozff5ppT\r\na=ice-options:trickle\r\na=fingerprint:sha-256 20:50:72:9B:A2:C0:D8:50:AD:D0:EF:A7:62:8F:EF:C3:AB:86:D5:B6:3E:17:22:69:79:5B:CE:E8:42:33:B5:E4\r\na=setup:actpass\r\na=mid:0\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid\r\na=sendrecv\r\na=msid:rts audio\r\na=rtcp-mux\r\na=rtpmap:111 opus/48000/2\r\na=rtcp-fb:111 transport-cc\r\na=rtcp-fb:111 nack\r\na=fmtp:111 minptime=10;useinbandfec=1\r\na=rtpmap:63 red/48000/2\r\na=fmtp:63 111/111\r\na=rtpmap:103 ISAC/16000\r\na=rtpmap:104 ISAC/32000\r\na=rtpmap:9 G722/8000\r\na=rtpmap:0 PCMU/8000\r\na=rtpmap:8 PCMA/8000\r\na=rtpmap:106 CN/32000\r\na=rtpmap:105 CN/16000\r\na=rtpmap:13 CN/8000\r\na=rtpmap:110 telephone-event/48000\r\na=rtpmap:112 telephone-event/32000\r\na=rtpmap:113 telephone-event/16000\r\na=rtpmap:126 telephone-event/8000\r\na=ssrc:3411287802 cname:s4eR7OuKnnPL0vKS\r\na=ssrc:3411287802 msid:rts audio\r\na=ssrc:3411287802 mslabel:rts\r\na=ssrc:3411287802 label:audio\r\nm=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 127 121 125 107 108 109 124 120 123 119 35 36 41 42 114 115 116 117 118\r\nc=IN IP4 0.0.0.0\r\na=rtcp:9 IN IP4 0.0.0.0\r\na=ice-ufrag:iQyM\r\na=ice-pwd:D3GXKCcUGvW9djaAozff5ppT\r\na=ice-options:trickle\r\na=fingerprint:sha-256 20:50:72:9B:A2:C0:D8:50:AD:D0:EF:A7:62:8F:EF:C3:AB:86:D5:B6:3E:17:22:69:79:5B:CE:E8:42:33:B5:E4\r\na=setup:actpass\r\na=mid:1\r\na=extmap:14 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time\r\na=extmap:13 urn:3gpp:video-orientation\r\na=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01\r\na=extmap:5 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay\r\na=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type\r\na=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-timing\r\na=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/color-space\r\na=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid\r\na=extmap:10 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id\r\na=extmap:11 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id\r\na=sendrecv\r\na=msid:rts video\r\na=rtcp-mux\r\na=rtcp-rsize\r\na=rtpmap:96 VP8/90000\r\na=rtcp-fb:96 goog-remb\r\na=rtcp-fb:96 transport-cc\r\na=rtcp-fb:96 ccm fir\r\na=rtcp-fb:96 nack\r\na=rtcp-fb:96 nack pli\r\na=rtpmap:97 rtx/90000\r\na=fmtp:97 apt=96\r\na=rtpmap:98 VP9/90000\r\na=rtcp-fb:98 goog-remb\r\na=rtcp-fb:98 transport-cc\r\na=rtcp-fb:98 ccm fir\r\na=rtcp-fb:98 nack\r\na=rtcp-fb:98 nack pli\r\na=fmtp:98 profile-id=0\r\na=rtpmap:99 rtx/90000\r\na=fmtp:99 apt=98\r\na=rtpmap:100 VP9/90000\r\na=rtcp-fb:100 goog-remb\r\na=rtcp-fb:100 transport-cc\r\na=rtcp-fb:100 ccm fir\r\na=rtcp-fb:100 nack\r\na=rtcp-fb:100 nack pli\r\na=fmtp:100 profile-id=2\r\na=rtpmap:101 rtx/90000\r\na=fmtp:101 apt=100\r\na=rtpmap:127 H264/90000\r\na=rtcp-fb:127 goog-remb\r\na=rtcp-fb:127 transport-cc\r\na=rtcp-fb:127 ccm fir\r\na=rtcp-fb:127 nack\r\na=rtcp-fb:127 nack pli\r\na=fmtp:127 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\r\na=rtpmap:121 rtx/90000\r\na=fmtp:121 apt=127\r\na=rtpmap:125 H264/90000\r\na=rtcp-fb:125 goog-remb\r\na=rtcp-fb:125 transport-cc\r\na=rtcp-fb:125 ccm fir\r\na=rtcp-fb:125 nack\r\na=rtcp-fb:125 nack pli\r\na=fmtp:125 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f\r\na=rtpmap:107 rtx/90000\r\na=fmtp:107 apt=125\r\na=rtpmap:108 H264/90000\r\na=rtcp-fb:108 goog-remb\r\na=rtcp-fb:108 transport-cc\r\na=rtcp-fb:108 ccm fir\r\na=rtcp-fb:108 nack\r\na=rtcp-fb:108 nack pli\r\na=fmtp:108 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f\r\na=rtpmap:109 rtx/90000\r\na=fmtp:109 apt=108\r\na=rtpmap:124 H264/90000\r\na=rtcp-fb:124 goog-remb\r\na=rtcp-fb:124 transport-cc\r\na=rtcp-fb:124 ccm fir\r\na=rtcp-fb:124 nack\r\na=rtcp-fb:124 nack pli\r\na=fmtp:124 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f\r\na=rtpmap:120 rtx/90000\r\na=fmtp:120 apt=124\r\na=rtpmap:123 H264/90000\r\na=rtcp-fb:123 goog-remb\r\na=rtcp-fb:123 transport-cc\r\na=rtcp-fb:123 ccm fir\r\na=rtcp-fb:123 nack\r\na=rtcp-fb:123 nack pli\r\na=fmtp:123 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d001f\r\na=rtpmap:119 rtx/90000\r\na=fmtp:119 apt=123\r\na=rtpmap:35 H264/90000\r\na=rtcp-fb:35 goog-remb\r\na=rtcp-fb:35 transport-cc\r\na=rtcp-fb:35 ccm fir\r\na=rtcp-fb:35 nack\r\na=rtcp-fb:35 nack pli\r\na=fmtp:35 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=4d001f\r\na=rtpmap:36 rtx/90000\r\na=fmtp:36 apt=35\r\na=rtpmap:41 AV1/90000\r\na=rtcp-fb:41 goog-remb\r\na=rtcp-fb:41 transport-cc\r\na=rtcp-fb:41 ccm fir\r\na=rtcp-fb:41 nack\r\na=rtcp-fb:41 nack pli\r\na=rtpmap:42 rtx/90000\r\na=fmtp:42 apt=41\r\na=rtpmap:114 H264/90000\r\na=rtcp-fb:114 goog-remb\r\na=rtcp-fb:114 transport-cc\r\na=rtcp-fb:114 ccm fir\r\na=rtcp-fb:114 nack\r\na=rtcp-fb:114 nack pli\r\na=fmtp:114 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=64001f\r\na=rtpmap:115 rtx/90000\r\na=fmtp:115 apt=114\r\na=rtpmap:116 red/90000\r\na=rtpmap:117 rtx/90000\r\na=fmtp:117 apt=116\r\na=rtpmap:118 ulpfec/90000\r\na=ssrc-group:FID 4075787827 945566690\r\na=ssrc:4075787827 cname:s4eR7OuKnnPL0vKS\r\na=ssrc:4075787827 msid:rts video\r\na=ssrc:4075787827 mslabel:rts\r\na=ssrc:4075787827 label:video\r\na=ssrc:945566690 cname:s4eR7OuKnnPL0vKS\r\na=ssrc:945566690 msid:rts video\r\na=ssrc:945566690 mslabel:rts\r\na=ssrc:945566690 label:video\r\nm=application 9 UDP/DTLS/SCTP webrtc-datachannel\r\nc=IN IP4 0.0.0.0\r\na=ice-ufrag:iQyM\r\na=ice-pwd:D3GXKCcUGvW9djaAozff5ppT\r\na=ice-options:trickle\r\na=fingerprint:sha-256 20:50:72:9B:A2:C0:D8:50:AD:D0:EF:A7:62:8F:EF:C3:AB:86:D5:B6:3E:17:22:69:79:5B:CE:E8:42:33:B5:E4\r\na=setup:actpass\r\na=mid:2\r\na=sctp-port:5000\r\na=max-message-size:262144\r\n"
        }
    }
    
    Response:
    {
        "trace_id":"...",
        "code":200,
        "jsep":{
            "type":"answer",
            "sdp":"v=0\r\no=- 1657264764 2 IN IP4 127.0.0.1 以下省略"
        }
    }
                        
    上述信令中,push_stream表明了推流的url, 与RTMP推流是类似的。需注意:
    • SDP中需要指定好msid, GRTN使用msid作为媒体的唯一标识。
    • 推流的媒体不支持协商,客户端指定的同一个媒体msid ,只允许发送一种编码,GRTN不进行选择。目前GRTN支持AAC、OPUS、H.264和H.265。
    • audioaudio1audio2
    • videovideo1video2
  • 错误处理

    信令请求合法的情况下响应200 ,具体的处理结果需要解析响应body的JSON内的code属性。code为HTTP响应码模式,具体定义如下:

    Response:
    {
       "code": 200, // 200-成功 非200-见后续定义
       "message": "success"  // 非200错误码描述
    }
    表 8. 应答参数
    参数 类型 描述
    code int 响应码,格式和定义参见下表。
    message string 错误描述。
    表 9. 错误码描述
    错误码 描述
    403 鉴权失败。
    611 需要客户端强制降级到TCP。
    302 需要客户端向新的服务地址发起信令请求。

增强的SDP

在信令交互中,SDP用来描述媒体信息。通用的SDP协商是基于RFC 4566展开的,阿里云RTS在其基础上扩展出了更多丰富的语义,兼容直播行业的特点,支持更多的音视频封装和通信协议,突破了WebRTC仅支持音频OPUS、不支持视频B帧等的窘境,满足了如今流媒体业界日益扩大的协议族。

推拉流支持AAC音频

RTS支持传输任何能在RTMP中传输的AAC格式的音频,包括AAC-LC、HE-AACv1和HE-AACv2。

RTS支持以LATM格式进行AAC音频传输。LATM可根据传输中的音频是否自带音频编码信息来决定是带内(每个音频都发)或带外(只发一次)音频编码信息,即由Audio Mux Element中的muxconfigPresent决定AudioSpecificConfig是带内或带外传输。因此,LATM相对ADTS更灵活,其AudioSpecificConfig如果保持不变,则可以通过SDP会话先传输StreamMuxConfig(AudioSpecificConfig)信息。

  • 推流支持AAC音频

    支持offer SDP中携带AAC信息告知服务端所推音频格式。另外,也支持通过在FMTP中添加config=StreamMuxConfig(其由推流AudioSpecificConfig信息组装而来),将AudioSpecificConfig信息携带给服务端,生成AAC Header。

    offer SDP:
    a=rtpmap:125 MP4A-LATM/48000/2
    a=fmtp:125 config=4000232000;cpresent=0;object=2;profile-level-id=1
  • 拉流支持AAC音频

    在信令交互阶段,RTS会解析推流侧音频编码信息,并在协商响应中返回对应的信息。如下所示:

    offer SDP answer SDP
    AAC-LC HE-AACv1 HE-AACv2
    m=audio 9 UDP/RTP/AVPF 120 96 
    a=rtpmap:120 MP4A-LATM/44100/2   
    AudioSpecificConfig = 0x1210
    AudioSpecificConfig = 2b920800
    AudioSpecificConfig = eb8a0800
    a=rtpmap:120 MP4A-LATM/44100/2
    a=fmtp:120 cpresent=0;profile-level-id=1;object=2;config=400024203fc0
    a=rtpmap:120 MP4A-LATM/44100/2 
    a=fmtp:120 cpresent=0;profile-level-id=1;object=2;config=4000572410003fc0;SBR-enabled=1
    a=rtpmap:120 MP4A-LATM/44100/2 
    a=fmtp:120 cpresent=0;object=2;profile-level-id=1;config=4001d71410003fc0;PS-enabled=1;SBR-enabled=1

    此处,通过在answer SDP音频MP4A-LATM的fmtp中添加SBR-enabled=1表示AAC-HE,添加SBR-enabled=1PS-enabled=1表示HE-AACv2。由于从AAC-LC到HE-AACv2有技术递进关系,因此在表示fmtp时,递进地增加SBR、PS的标识来表示不同的AAC格式。此外,在fmtp中添加config=StreamMuxConfig,其由推流AudioSpecificConfig信息组装而来,具体的描述了音频编码的各种参数信息,客户端可以各取所需。

    002

推拉流支持H.265视频

  • 推流支持H.265视频

    支持offer SDP中携带H.265信息告知服务端所推视频格式。

    Offer SDP:
    a=rtpmap:102 H265/90000 
  • 拉流支持H.265视频

    在拉流的信令交互阶段,服务端会获取源流的视频编码信息(H.264、H.265等),并在依据此进行协商。

    offer SDP answer SDP
    a=rtpmap:102 H265/90000
    a=rtpmap:122 H265/90000
    a=fmtp:122

推拉流支持带B帧视频

  • 推流支持B帧

    支持推流源流中携带B帧。

  • 拉流支持B帧

    在信令交互阶段,客户端可以在offer SDP中增加字段标识其是否支持解析B帧视频。例如:在视频fmtp中增加BFrame-enabled = 1标识以表示支持B帧,此时,RTP timestamp = PTS,sequence number递增,正常情况下客户端按照sequence number解码即可。如果不支持B帧,RTS可以对视频源流进行转码,去掉B帧。

    在带B帧的情况下,RTP timestamp = PTS,sequence number递增,正常情况下客户端按照sequence number解码即可。

    此外,服务端还支持额外返回CTS扩展头以支持需要精确计算DTS的客户端(PTS=DTS+CTS),如果offer SDP中带有a=extmap:{$id} uri:webrtc:rtc:rtp-hdrext:video:CompositionTime,RTS会在每一帧视频的第一个RTP包上增加extension identifier = {$id}的CTS扩展头,id由offer SDP来决定。

    RTS给予客户端充分的表达能力,将决定权下放给客户,让其决定是否接受视频带B帧,以及是否需要额外的CTS信息。以更通用的方式构建通信能力也是RTS的初衷。

offer SDP片段及拉流抓包示例如下所示:

Offer SDP片段004

推流支持通过信令携带metadata

RTMP推流会通过RTMP metadata携带相关元信息,可用于给推流回调、拉流客户端提供元信息。由于WebRTC传输本身没有metadata,RTS支持通过在信令中携带额外信息,从而在推流源流中生成metadata。

在推流信令body中添加metadata字段:

{
    "version":2,
    "sdk_version":"0.0.1",
    "mode":"rtc",
    "push_stream":"artc://host/app/name",
    "jsep":{
        "type":"offer",
        "sdp":"..."
    },
    "metadata":{
        "framerate":"20",
        "platform":"iOS",
        "audiodatarate":"200",
        "videodatarate":"2000"
    }
}

MSID相关概念

关于MSID详细信息,请参见The Msid Mechanism。请重点关注以下内容:Msid