WebRTC

更新时间:2023-02-09 08:30:39下载pdf

涂鸦针对具备音视频传输能力的 IoT 设备,提供了 WebRTC 协议的方式接入实时音视频。本文以智能摄像机 IPC 为例,介绍如何接入实时视频能力。

交互流程

业务流程

WebRTC

模块组成

  • 涂鸦 IoT 开发平台

    • 提供开放平台各种 HTTPS 接口。
  • Web 前端

    • 提供用于 Chrome 访问观看设备 WebRTC 实时流的页面。关于 WebRTC 协议的基础介绍,请参考 构建 WebRTC 所需的后端服务
    • 与 Web 后端通过 WebSocket 协议通信。
    • 调用 JavaScript API 生成 WebRTC offer 和 candidate。
  • Web 后端

    • 托管 Web 页面。
    • 访问涂鸦 IoT 开发平台,通过 HTTPS 协议获取需要的各种配置信息。
    • 连接涂鸦 MQTT 服务。
  • 涂鸦 MQTT 服务

    • 提供异步的数据传输通道。
  • IPC 设备

接入实时音视频

前提条件

  • 已关联 IPC 至涂鸦 智能生活 App。
  • 已创建云开发项目,操作方法请参考 创建项目
  • 已关联涂鸦智能账号至云项目,操作方法请参考 关联自有 App

操作步骤

  1. 克隆 webrtc-demo-go 项目至本地。
    WebRTC

  2. 在源码根目录,执行:

    go get && go build
    
    WebRTC
  3. webrtc.json 文件中配置参数。

    WebRTC
    • clientId:即云项目的 Access ID,获取方法请参考 云项目参数
    • secret:即云项目的 Access Secret。获取方法请参考 云项目参数
    • autoMode:选择 easy 授权方式。在 uid 填写关联 App 账号的 UID。UID 查询方法请参考 设备参数
      WebRTC
    • deviceId:设备的 ID,查询方法请参考 设备参数
  4. 执行:

    ./webrtc-demo-go
    
  5. 使用 Chrome 登录 http://localhost:3333

  6. 在 Web 页面,单击 Call

    WebRTC

API

生成 MQTT 配置

接口描述

用于为用户生成连接 MQTT 的配置。

接口地址

POST /v1.0/open-hub/access/config

请求参数

参数 类型 位置 说明 是否必需
link_id String BODY 用户连接的唯一标志,用户客户端下唯一,最长 8 位
uid String BODY 用户 ID,授权码模式可不填
link_type String BODY 连接方式,支持:mqtt
topics String BODY ipc,指 WebRTC 业务的 MQTT topic 类型

响应参数

参数 类型 说明
result MQTT MQTT 登录信息
success Boolean 响应结果的状态
t Long 响应结果的时间戳,单位:毫秒

MQTT

参数 类型 说明
url String 连接地址
username String 连接用户名
password String 连接密码
client_id String 连接 client_id
source_topic String 订阅 Topic
sink_topic String 投递 Topic
expire_time Integer 有效时长

请求示例

{
    "uid": "ay1564026880284v****",
    "link_id": "123456",
    "link_type": "mqtt",
    "topics": "ipc"
}

响应示例

{
    "result": {
        "client_id": "cloud_7ef68bc84629ea3f51152760cdf2****",
        "expire_time": 7200,
        "password": "0426d6917bfd8b88f037c4a598a0****",
        "sink_topic": {
            "ipc": "/av/moto/moto_id/u/{device_id}"
        },
        "source_topic": {
            "ipc": "/av/u/d09735be24f4b7eb3583b30bcaa2****"
        },
        "url": "ssl://m1-cn.wgine.com:8883",
        "username": "cloud_d09735be24f4b7eb3583b30bcaa2****"
        },
        "success": true,
        "t": 1600847208953
}

获取 WebRTC 配置

接口地址

GET /v1.0/users/{uId}/devices/{deviceId}/webrtc-configs

请求参数

参数 类型 位置 说明 是否必需
uId String URI 用户 ID
deviceId String URI 设备 ID

响应参数

参数 类型 说明
audio_attributes AudioAttributes 对讲属性
auth String 授权信息
id String 设备 ID
moto_id String 连接的实例 ID
p2p_config P2PConfig 连接服务相关配置信息
skill String Skill 技能
supports_webrtc Boolean 是否支持 WebRTC
vedio_clarity Integer 视频清晰度
  • AudioAttributes

    参数 类型 说明
    call_mode Integer 对讲模式,1 为单向,2 为双向
    hardware_capability Integer 硬件能力,1 为 Mic,2 为 Speaker
  • P2PConfig

    参数 类型 说明
    ices Token p2p Token 列表
  • Token

    参数 类型 说明
    urls String ICE 服务地址
    username String ICE 服务用户名
    credential String ICE 服务密码
    ttl Integer ICE 服务有效时长,单位:秒

响应示例

{
    "result":{
        "audio_attributes":{
            "call_mode":[
                1,
                2
            ],
            "hardware_capability":[
                1,
                2
            ]
        },
        "auth":"h85L4pljbuHFR0a/iTgViwA35xi3yTl3NyMsFQL5****",
        "id":"6cf2b6d2b09a2f8597****",
        "moto_id":"moto_cnpre002",
        "p2p_config":{
            "ices":[
                {
                    "urls":"stun:49.234.141.77:3478"
                },
                {
                    "urls":"stun:tx1stun.tuyacn.com:3478"
                },
                {
                    "urls":"nat:tx1nat.tuyacn.com:3478"
                },
                {
                    "urls":"nat:tx2nat.tuyacn.com:3478"
                },
                {
                    "credential":"kb/EA2whGCcNSM5FjXV2dxAM1MU=",
                    "ttl":36000,
                    "urls":"turn:49.234.141.77:3478",
                    "username":"1600883205:6cf2b6d2b09a2f8597****"
                },
                {
                    "credential":"kb/EA2whGCcNSM5FjXV2dxAM****",
                    "ttl":36000,
                    "urls":"turn:tx1turn.tuyacn.com:3478",
                    "username":"1600883205:6cf2b6d2b09a2f8597****"
                }
            ]
        },
        "skill":"{"webrtc":3,"audios":[{"channels":1,"dataBit":16,"codecType":101,"sampleRate":8000}],"videos":[{"streamType":2,"profileId":"","width":1920,"codecType":2,"sampleRate":90000,"height":1080},{"streamType":4,"width":640,"codecType":2,"height":360}]}",
        "supports_webrtc":true,
        "vedio_clarity":4
    },
    "success":true,
    "t":1600847205437
}

接入 WebRTC 的信令报文

响应参数

参数 类型 说明
protocol Integer MQTT 消息的协议号,WebRTC 属于实时流服务,取值为 302
pv String 通讯协议版本号
t Integer Unix 时间戳,单位:秒
data Data MQTT 消息帧
  • Data

    参数 类型 说明
    header Header MQTT 消息帧头
    msg Msg MQTT 消息体,可为 offer candidate answer disconnect
  • Header

    参数 类型 说明
    type String MQTT 消息类型,offer candidate answer disconnect
    from String 客户端填 msid,设备端填 device_id
    to String 填对方的 ID,例如:device_id or msid
    sub_dev_id String 子设备 node_id,NVR 设备才会用到
    sessionid String 每次连接随机生成,32 字节,同一个连接的所有信令使用相同的 sessionid
    moto_id String 通过 /v1.0/users/{uId}/devices/{deviceId}/webrtc-configs 接口获取,如果返回结果中缺少 moto_id 字段,则表示不支持
  • Msg

    当前支持offercandidatedisconnet三种不同的 MQTT 消息类型,不同 MQTT 消息类型的 msg 格式不同。

    type=offer 时 Msg 格式如下。

    参数 类型 说明
    mode String 连接模式,WebRTC
    sdp String Web 端生成的 WebRTC offer
    stream_type Interger 码流类型,默认为 1 辅码流
    auth String 通过 /v1.0/users/{uId}/devices/{deviceId}/webrtc-configs 接口获取,字段为 auth

响应示例

{
    "protocol":302,
    "pv":"2.2",
    "t":1600820048671,
    "data":{
        "header":{
            "from":"AY1600819753305aHO5Sdj8pQMtLZ68XHMUpHKlRKJ87s",
            "to":"6c9a943f2ea6929675ymcq",
            "sessionid":"00b00036521743319b4d4c01f1705c48",
            "moto_id":"moto_5f685396jK",
            "type":"offer"
        },
        "msg":{
            "sdp":"v=0 o=- 4529163812828363188 2 IN IP4 127.0.0.1 s=- t=0 0 a=group:BUNDLE 0 1 a=msid-semantic: WMS 1VpYoJaai0xSYjWhYxPHqySybB3PaQ6Y3wXP m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126 c=IN IP4 0.0.0.0 a=rtcp:9 IN IP4 0.0.0.0 a=ice-ufrag:Q93I a=ice-pwd:P58s/ZyBRNVnuIxcrcmEmRG5 a=ice-options:trickle a=fingerprint:sha-256 E1:01:E0:B3:F1:97:7F:86:07:61:54:BE:42:5F:56:E8:84:58:76:E3:E4:22:94:F1:33:2A:A3:C2:FC:67:05:3E a=setup:actpass a=mid:0 a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01 a=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid a=extmap:5 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id a=extmap:6 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id a=sendrecv a=msid:1VpYoJaai0xSYjWhYxPHqySybB3PaQ6Y3wXP 1c7d25a4-9948-4165-bf4d-62fc39b8b528 a=rtcp-mux a=rtpmap:111 opus/48000/2 a=rtcp-fb:111 transport-cc a=fmtp:111 minptime=10;useinbandfec=1 a=rtpmap:103 ISAC/16000 a=rtpmap:104 ISAC/32000 a=rtpmap:9 G722/8000 a=rtpmap:0 PCMU/8000 a=rtpmap:8 PCMA/8000 a=rtpmap:106 CN/32000 a=rtpmap:105 CN/16000 a=rtpmap:13 CN/8000 a=rtpmap:110 telephone-event/48000 a=rtpmap:112 telephone-event/32000 a=rtpmap:113 telephone-event/16000 a=rtpmap:126 telephone-event/8000 a=ssrc:724809951 cname:7UznE7uyn6JBJ4PA a=ssrc:724809951 msid:1VpYoJaai0xSYjWhYxPHqySybB3PaQ6Y3wXP 1c7d25a4-9948-4165-bf4d-62fc39b8b528 a=ssrc:724809951 mslabel:1VpYoJaai0xSYjWhYxPHqySybB3PaQ6Y3wXP a=ssrc:724809951 label:1c7d25a4-9948-4165-bf4d-62fc39b8b528 m=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 122 102 120 127 119 125 107 108 109 121 114 115 124 118 123 c=IN IP4 0.0.0.0 a=rtcp:9 IN IP4 0.0.0.0 a=ice-ufrag:Q93I a=ice-pwd:P58s/ZyBRNVnuIxcrcmEmRG5 a=ice-options:trickle a=fingerprint:sha-256 E1:01:E0:B3:F1:97:7F:86:07:61:54:BE:42:5F:56:E8:84:58:76:E3:E4:22:94:F1:33:2A:A3:C2:FC:67:05:3E a=setup:actpass a=mid:1 a=extmap:14 urn:ietf:params:rtp-hdrext:toffset a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time a=extmap:13 urn:3gpp:video-orientation a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01 a=extmap:12 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay a=extmap:11 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type a=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-timing a=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/color-space a=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid a=extmap:5 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id a=extmap:6 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id a=recvonly a=rtcp-mux a=rtcp-rsize a=rtpmap:96 VP8/90000 a=rtcp-fb:96 goog-remb a=rtcp-fb:96 transport-cc a=rtcp-fb:96 ccm fir a=rtcp-fb:96 nack a=rtcp-fb:96 nack pli a=rtpmap:97 rtx/90000 a=fmtp:97 apt=96 a=rtpmap:98 VP9/90000 a=rtcp-fb:98 goog-remb a=rtcp-fb:98 transport-cc a=rtcp-fb:98 ccm fir a=rtcp-fb:98 nack a=rtcp-fb:98 nack pli a=fmtp:98 profile-id=0 a=rtpmap:99 rtx/90000 a=fmtp:99 apt=98 a=rtpmap:100 VP9/90000 a=rtcp-fb:100 goog-remb a=rtcp-fb:100 transport-cc a=rtcp-fb:100 ccm fir a=rtcp-fb:100 nack a=rtcp-fb:100 nack pli a=fmtp:100 profile-id=2 a=rtpmap:101 rtx/90000 a=fmtp:101 apt=100 a=rtpmap:122 VP9/90000 a=rtcp-fb:122 goog-remb a=rtcp-fb:122 transport-cc a=rtcp-fb:122 ccm fir a=rtcp-fb:122 nack a=rtcp-fb:122 nack pli a=fmtp:122 profile-id=1 a=rtpmap:102 H264/90000 a=rtcp-fb:102 goog-remb a=rtcp-fb:102 transport-cc a=rtcp-fb:102 ccm fir a=rtcp-fb:102 nack a=rtcp-fb:102 nack pli a=fmtp:102 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f a=rtpmap:120 rtx/90000 a=fmtp:120 apt=102 a=rtpmap:127 H264/90000 a=rtcp-fb:127 goog-remb a=rtcp-fb:127 transport-cc a=rtcp-fb:127 ccm fir a=rtcp-fb:127 nack a=rtcp-fb:127 nack pli a=fmtp:127 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f a=rtpmap:119 rtx/90000 a=fmtp:119 apt=127 a=rtpmap:125 H264/90000 a=rtcp-fb:125 goog-remb a=rtcp-fb:125 transport-cc a=rtcp-fb:125 ccm fir a=rtcp-fb:125 nack a=rtcp-fb:125 nack pli a=fmtp:125 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f a=rtpmap:107 rtx/90000 a=fmtp:107 apt=125 a=rtpmap:108 H264/90000 a=rtcp-fb:108 goog-remb a=rtcp-fb:108 transport-cc a=rtcp-fb:108 ccm fir a=rtcp-fb:108 nack a=rtcp-fb:108 nack pli a=fmtp:108 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f a=rtpmap:109 rtx/90000 a=fmtp:109 apt=108 a=rtpmap:121 H264/90000 a=rtcp-fb:121 goog-remb a=rtcp-fb:121 transport-cc a=rtcp-fb:121 ccm fir a=rtcp-fb:121 nack a=rtcp-fb:121 nack pli a=fmtp:121 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d0015 a=rtpmap:114 H264/90000 a=rtcp-fb:114 goog-remb a=rtcp-fb:114 transport-cc a=rtcp-fb:114 ccm fir a=rtcp-fb:114 nack a=rtcp-fb:114 nack pli a=fmtp:114 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640015 a=rtpmap:115 rtx/90000 a=fmtp:115 apt=114 a=rtpmap:124 red/90000 a=rtpmap:118 rtx/90000 a=fmtp:118 apt=124 a=rtpmap:123 ulpfec/90000 ",
            "auth":"3iHAObTiJ+P1o/OeX8My208vis9Ar6JQygHSLrBxv5U=",
            "mode":"webrtc",
            "stream_type":1
        }
    }
}

type=candidate 时 Msg 格式如下。

参数 类型 说明
mode String 连接模式,WebRTC
candidate String 双方收集的 WebRTC 候选地址

响应示例

{
    "protocol":302,
    "pv":"2.2",
    "t":1600820048672,
    "data":{
        "header":{
            "from":"AY1600819753305aHO5Sdj8pQMtLZ68XHMUpHKlRKJ87s",
            "to":"6c9a943f2ea6929675ymcq",
            "sessionid":"00b00036521743319b4d4c01f1705c48",
            "moto_id":"moto_5f685396jK",
            "type":"candidate"
        },
        "msg":{
            "mode":"webrtc",
            "candidate":"a=candidate:512512433 1 udp 2122260223 192.168.0.227 50828 typ host generation 0 ufrag Q93I network-id 1"
        }
    }
}

type=disconnect 时 Msg 格式如下。

参数 类型 说明
mode String 连接模式,WebRTC

响应示例

{
    "protocol":302,
    "pv":"2.2",
    "t":1600820048679,
    "data":{
        "header":{
            "from":"AY1600819753305aHO5Sdj8pQMtLZ68XHMUpHKlRKJ87s",
            "to":"6c9a943f2ea6929675ymcq",
            "sessionid":"00b00036521743319b4d4c01f1705c48",
            "moto_id":"moto_5f685396jK",
            "type":"disconnect"
        },
        "msg":{
            "mode":"webrtc"
        }
    }
}

常见问题

如何接收涂鸦 MQTT 服务的消息?

获取开放平台 configs 后,需要将 result.source_topic.ipc JSON 字段中 /av/u/ 后的字符串,作为 MQTT Header 中的 from,这样才能正确接受 MQTT 服务的消息。