LinkRTC API 说明¶
目录¶
概念¶
账号和项目¶
用户在第一次使用 LinkRTC 之前,必须先注册一个账户(Account)。
账户的作用 blablabla...
一个账户名下可以建立多个项目(Project)。 项目的作用 blabla...
WebRTC¶
blabla...
SIP¶
blabla...
呼出过程¶
定义¶
步骤说明¶
以下分步骤说明呼出过程。
- 在顺序图中:
1. 请求呼出¶
1.1. 客户端 c1 向 LinkRTC 提交呼出请求,在这个请求中,他要求以主叫号码 x 、被叫号码 y 的名义,向 SIP 端点 s1 发起呼叫。
1.2. LinkRTC 收到请求后,询问用户应用服务程序是否允许这次呼出。
请求呼出,并被允许
请求呼出,并被拒绝
呼入过程¶
定义¶
步骤说明¶
以下分步骤说明呼入过程。
- 在顺序图中:
1. 呼入选择¶
1.1. LinkRTC 收到了来自 s1 的呼入请求
1.2. LinkRTC 向 s1 回复 SIP 状态码 100 TRYING
1.3. LinkRTC 询问用户的服务程序,是否允许这个呼入,以及要将这个呼入交换到哪个客户端
1.3.1 如果用户的服务程序禁止该呼入,则结束呼叫过程
1.3.2 如果用户的服务程序指定了目标客户端,则继续后续过程
呼入选择
呼入拒绝
服务器 API¶
目录
服务器 API 介绍¶
服务器 API 用于 LinkRTC 后台与用户的应用服务程序之间的通信。
它们之间的通信以 HTTP 的形式在互联网上进行。
LinkRTC 与 用户的应用服务程序 既充当 HTTP 服务器又充当 HTTP 客户端 : 以客户端的身份向对方发送请求,同时也以服务器的身份接受对方的请求。
设计原则¶
格式规范¶
HTTP 地址¶
用户应用服务程序调用 LinkRTC 的 API 时候,URL 的路径部分的格式是:
/<api_version>/sapi/*
其中 api_version 是 LinkRTC API 的版本,跨版本访问可能有兼容问题。
sapi 表示服务应用程序接口( Service Application Program Interface ),所有的服务器API的访问路径均具有该部分。
HTTP 头和内容¶
POST 或 PUT 请求、以及回复的正文部分 必须 是 采用 UTF-8 编码的 JSON 格式字符串, Content-Type 头域的值应是 application/json。
例如:
用户应用程序服务发出的请求:
POST /v0.l/sapi/client/create HTTP/1.1
Host: api.linkrtc.com
Content-Type: application/json; charset=utf-8
Content-Length: xxx
{
"name": "client-01",
"capability": {
"audio": true,
"video": false
}
}
api.linkrtc.com 的回复:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: xxx
{
"id": "fg430mu3ojfg398u4"
}
如果 POST 、 PUT 请求不包含内容,或回复不包含内容, 其 Content-Length 头域的值应为 0,例如:
请求:
POST /v0.1/sapi/ping HTTP/1.1
Host: api.linkrtc.com
Content-Length: 0
回复:
HTTP/1.1 200 OK
Content-Length: 0
HTTP 状态码¶
如果服务器在响应API调用期间出现错误,或者出现意料之外的情况,应返回该状态码。
LinkRTC 在许多情况下,会提供具体的错误编码以及错误信息,这些错误信息用 JSON 对象格式存放在回复数据的内容部分。
其中 code
属性记录错误编码, text
属性记录错误文本信息。
如:
HTTP/1.1 500 Internal Server Error
Content-Type: application/json; charset=utf-8
Content-Length: xxx
{"code": 10013, "text": "calee not allowed"}
注意
LinkRTC 后台服务无法在所有情况下都提供 JSON 格式错误信息。 调用方可以根据 Content-Type 进行判断。
安全¶
身份认证¶
用户应用服务程序向 LinkRTC 发送的请求需要提供 HTTP Basic Authentication (HTTP 基本认证)信息。 LinkRTC 根据认证信息中的用户名和密码对调用者进行身份认证。
如果用户应用服务程序缺少或者没有提供正确 Authorization 信息, LinkRTC 将返回 401 Unauthorized 。
注意
由于项目的访问密码以 MD5 散列形式存放在系统中,所以,进行验证时,密码应使用 MD5 散列后的字符串。
例如,某用户在 LinkRTC 拥有一个 name 为 Project1
的 项目 ,
该项目的访问密码是 abc123
,Authorization 头域的字符串值的算法可用以下伪代码描述:
name = b"Project1"
password = b"abc123"
txt = name + b":" + md5(password).hexdigest().encode()
txt_enc = b64encode(txt)
上面的伪代码得到结果 UHJvamVjdDE6ZTk5YTE4YzQyOGNiMzhkNWYyNjA4NTM2Nzg5MjJlMDM=
用户应用服务程序发送的 HTTP 请求 必须 带有正确的 Authorization 头:
GET /v0.1/sapi/webrtcclient/5 HTTP/1.1
Host: api.linkrtc.com
Authorization: Basic UHJvamVjdDE6ZTk5YTE4YzQyOGNiMzhkNWYyNjA4NTM2Nzg5MjJlMDM=
消息签名¶
LinkRTC 在其向用户应用服务程序发送的 HTTP 请求中附加了签名和时间戳。 用户应用服务程序可以对签名进行验证,防止冒充的消息。
- 签名算法所需参数有:
- 计算步骤:
- 分别计算上述三个字符串参数的MD5散列值的十六进制表达式(字母部分 大写 )。
- 将这三个散列值按照字符顺序排序后,依次首尾连接,得到一个新字符串。
- 计算上一个步骤中得到的新字符串的MD5散列值的十六进制表达式(字母部分 大写 ),即为签名。
- 签名和Unix时间戳被附加在 HTTP 请求的头域中,
- 时间戳的头域: X-LinkRTC-Signature
- 签名的头域: X-LinkRTC-Timestamp
带有签名信息的 HTTP 请求形如:
POST /your/script.php HTTP/1.1
Host: your.app.com
Content-Type: application/json; charset=utf-8
Content-Length: xxx
X-LinkRTC-Timestamp: 1453543759
X-LinkRTC-Signature: E6E157A9FA805921DA12A86A40CC2A15
{
"type": "xxxx",
"data": "xxxx",
}
签名算法¶
- 在下面的代码片段中:
- 项目 SID :
Project1
- AppSecret :
123abc
- Timestamp :
1453543759
- 项目 SID :
得到的签名应该是:
E6E157A9FA805921DA12A86A40CC2A15
以下几个小节是几种常见语言的签名算法实现代码片段:
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collections;
public class SignatureExample {
public static String byteArrayToHex(byte[] byteArray) {
char[] hexDigits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
char[] resultCharArray = new char[byteArray.length * 2];
int index = 0;
for (byte b : byteArray) {
resultCharArray[index++] = hexDigits[b >>> 4 & 0xf];
resultCharArray[index++] = hexDigits[b & 0xf];
}
return new String(resultCharArray);
}
public static String md5Str(String input)
throws NoSuchAlgorithmException {
MessageDigest messageDigest = MessageDigest.getInstance("MD5");
byte[] inputByteArray = input.getBytes();
messageDigest.update(inputByteArray);
byte[] resultByteArray = messageDigest.digest();
return byteArrayToHex(resultByteArray);
}
public static void main(String[] args) {
try {
String projectSid = "Project1";
String appSecret = "123abc";
String timestamp = "1453543759";
ArrayList<String> tmpList = new ArrayList<String>();
tmpList.add(md5Str(projectSid);
tmpList.add(md5Str(appSecret);
tmpList.add(md5Str(timestamp);
Collections.sort(tmpList);
String signature = md5Str(String.join("", tmpList));
System.out.format("signature = %s", signature);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
}
var crypto = require('crypto');
(function() {
var projectSid = "Project1";
var appSecret = "123abc";
var timestamp = "1453543759";
var md5Str = function(s) {
var hasher = crypto.createHash('md5');
hasher.update(s);
return hasher.digest('hex').toUpperCase();
}
var tmpArr = [projectSid, appSecret, timestamp].map(md5Str);
tmpArr.sort();
var signature = md5Str(tmpArr.join(''));
console.log(`signature = ${signature}`);
})();
<?php
$project_sid = 'Project1';
$app_secret = '123abc';
$timestamp = '1453543759';
function md5_str($s) {
return strtoupper(md5($s));
}
$tmp_arr = array_map(md5_str, array($project_sid, $app_secret, $timestamp));
sort($tmp_arr, SORT_STRING);
$signature = md5_str(implode($tmp_arr));
echo('signature = ' . $signature);
from hashlib import md5
project_sid = b'Project1'
app_secret = b'123abc'
timestamp = b'1453543759'
def md5_str(s):
return md5(s).hexdigest().upper().encode()
signature = md5_str(b''.join(sorted(map(md5_str, [project_sid, app_secret, timestamp]))))
print('signature = %s' % signature)
WebRTC 客户端管理 API¶
获取客户端列表¶
-
POST
/v0.1/sapi/Client/list
¶ 获取
sapi.Client
实例列表Request JSON Object: - page (int) – 要返回的页码。如果不指定,默认为0(从0开始)。
- per_page (int) – 每页长度。如果不指定,服务器采用其默认设置。
Response JSON Object: - current_page (int) – 当前返回结果的页码(从0开始)。
- per_page (int) – 每页长度。
- total_pages (int) – 总页数。
- total_entries (int) – 总条目数。
- entries (list) –
sapi.Client
对象列表。
举例
客户端调用:
POST /v0.1/sapi/Client/list HTTP/1.1
Host: api.linkrtc.com
Content-Type: application/json; charset=utf-8
Content-Length: xxx
{
"page": 1,
"per_page": 20
}
服务器回复:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: xxx
{
"current_page": 1,
"per_page": 20,
"total_pages": 3,
"total_entries": 57,
"entries": [
{"..": "...", "..": "...", "..": "..."},
{"..": "...", "..": "...", "..": "..."}
]
}
获取客户端详情¶
-
POST
/v0.1/sapi/Client/detail
¶ 获取指定 id (client_id) 的
sapi.Client
实例的详情Request JSON Object: - name (str) – 客户端的名称
Response JSON Object: - data (object) –
sapi.Client
对象
举例
客户端调用:
POST /v0.1/sapi/client/1001/detail HTTP/1.1 Host: api.linkrtc.com Content-Type: application/json; charset=utf-8 Content-Length: xxx {"name": "client-01"}
服务器回复:
HTTP/1.1 200 OK Content-Type: application/json; charset=utf-8 Content-Length: xxx { "data": { "id": "xxxxx", "name": "xxxxx", "...": "..." } }
新建客户端¶
-
POST
/v0.1/sapi/Client/create
¶ 新建一个
sapi.client
对象Request JSON Object: - name (str) – 要新建的
sapi.Client
对象的名称,对应sapi.Client.name
属性.
Response JSON Object: - data (object) – 新建的
sapi.Client
对象
- name (str) – 要新建的
呼叫 API¶
获取呼叫列表¶
-
POST
/v0.1/sapi/Call/list
¶ 获取当前正在进行的呼叫
sapi.Call
实例列表Request JSON Object: - page (int) – 要返回的页码。如果不指定,默认为1(从1开始)。
- perPage (int) – 每页长度。如果不指定,服务器采用其默认设置。
Response JSON Object: - currentPage (int) – 当前返回结果的页码(从1开始)。
- perPage (int) – 每页长度。
- totalPages (int) – 总页数。
- totalEntries (int) – 总条目数。
- entries (list) –
sapi.Call
对象列表。
获取呼叫详情¶
通知 API¶
LinkRTC 后台服务通过通知 API 将通知类型的消息数据 POST 到用户的应用服务程序。
用户应用服务程序通过这些通知数据判断呼叫或者客户端的状态,以便对其进行控制。
接收通知消息的 URL 通过 用户控制台 设置。
通知消息的内容是 JSON 对象格式。
- 该 JSON 对象的最外层包括两个属性:
- type: 消息类型字符串。
- data: 消息参数,其数据类型随事件类型不同而各异。
例如:
{
"type": "call.CallStateChanged",
"data": {
"call": {
"id": "2341",
"dir": "incoming",
"from": "13283484795",
"to": "400666255343",
"...": "... ..."
}
}
}
本节文档使用面向对象语言类型定义的伪代码形式,描述通知消息 data 部分的数据结构。
呼叫状态变化¶
type: | event.CallStateChanged |
---|
举例:
ID 为 2341 的入方向呼叫产生:
POST /your/script.php HTTP/1.1
Host: your.company.com
Content-Type: application/json; charset=utf-8
Content-Length: xxx
X-LinkRTC-Timestamp: 1453543759
X-LinkRTC-Signature: E6E157A9FA805921DA12A86A40CC2A15
{
"type": "event.CallStateChanged",
"data": {
"call": {
"id": "2341",
"dir": "incoming",
"current_state": "pending",
"...": "... ..."
}
}
}
警告
当用户应用服务程序收到呼叫状态变化事件通知中,
data 部分的 sapi.Call
对象的当前状态属性 sapi.Call.current_state
值为 待定 (pending
) ,
且呼叫方向属性 sapi.Call.dir
值为 出方向 (outgoing
) 时,
用户应用服务程序需要在呼叫超时或者被放弃之前调用
POST /v0.1/sapi/call/(str:call_id)/allow
允许此次呼叫,方可使出方向呼叫继续进行。
同理,当 data 部分的 sapi.Call
对象的当前状态属性 sapi.Call.current_state
值为 待定 (pending
) ,
且呼叫方向属性 sapi.Call.dir
值为 入方向 (incoming
) 时,
用户应用服务程序需要在呼叫超时或者被放弃之前调用
POST /v0.1/sapi/call/(str:call_id)/switch
允许此次呼叫,方可使入方向呼叫继续进行。
WebRTC 客户端连接状态变化¶
WebRTC 客户端连接建立或者连接断开
type: | event.WebRtcClientConnectStateChanged |
---|
-
class
sapi.event.
WebRtcClientConnected
¶ -
connected
¶ true
: 连接建立false
: 连接断开
返回类型: bool
-
client
¶ 连接状态发生变化的客户端
返回类型: sapi.WebRtcClient
-
举例:
ID 为 sx3kerjs 的 WebRTC 客户端建立连接:
POST /your/script.php HTTP/1.1
Host: your.company.com
Content-Type: application/json; charset=utf-8
Content-Length: xxx
X-LinkRTC-Timestamp: 1453543759
X-LinkRTC-Signature: E6E157A9FA805921DA12A86A40CC2A15
{
"type": "event.WebRtcClientConnectStateChanged",
"data": {
"connected": true,
"client": {
"id": "sx3kerjs",
"..": "....",
"...": "... ..."
}
}
}
数据结构定义¶
在服务器API中,用 JSON 对象格式记录各个实体的属性。
本章节使用面向对象语言类型定义的伪代码形式描述各个实体以及其属性的含义与数据类型。
注意
事件通知数据的结构定义不在本章,具体请参见 通知 API
呼叫信息¶
-
class
sapi.
Call
¶ -
id
¶ 呼叫ID
返回类型: str
-
dir
¶ 呼叫方向
返回类型: str - 定义:
方向 表达式 呼入 incoming 呼出 outgoing
-
current_state
¶ -
返回类型: str - 定义:
状态 表达式 待定 pending
呼叫中 calling
等待应答 ringing
已接通 confirmed
结束 dropped
-
prior_state
¶ 上一个呼叫状态,其属性值含义与
current_state
一致。返回类型: str 注解
当呼叫刚刚建立时,其当前状态
current_state
为 pending ,prior_state
值是null
。
-
from
¶ 返回类型: str
-
to
¶ 返回类型: str
-
客户端 API¶
目录
介绍¶
客户端 API 用于 LinkRTC 后台与具有 WebRTC 功能的浏览器/客户端之间的通信。
它们之间的通信基于 WebSocket ,遵照 JSON-RPC 2.0 标准。
在浏览器上,开发者可以通过 JavaScript 脚本使用这些 API 。
LinkRTC 与 浏览器/客户端 既充当调用者,用充当被调用者 ,所以,它们之间的通信是双向的。
设计原则¶
格式规范¶
URL¶
WebRTC 客户端访问这个 URL 建立 WebSocket 连接:
-
GET
/v0.1/capi/
(str: client_id)¶ 为名为 ID 为 client_id 的客户端建立基于 WebSocket 的 JSON-RPC 连接。
用户应用程序服务器通过 WebRTC 客户端对象
sapi.WebRtcClient.id
属性获取该 ID。
注解
- 路径的第一部分 v0.1 是 LinkRTC API 的版本,跨版本访问可能有兼容问题。
- capi 表示客户端程序接口( Client Application Program Interface )。
举例
在浏览器上使用 JavaScript 建立 WebSocket 连接:
var projId = "your_project_sid";
var wsKey = "your_client_wskey";
var url = `wss://api.linkrtc.com/v0.1/capi/${projId}?id=${wsKey}`;
var wsRpc = new WebSocket(url);
/**
* RPC's response
*/
wsRpc.addEventListener('onmessage', (event) => {
var data = JSON.parse(event.data);
/// "id" is RPC's id
id = data.id;
/// "result" is RPC's returned result
result = data.result;
});
wsRpc.addEventListener("readyState", (state) => {
if (state == 0) {
console.log("CONNECTING");
} else if (state == 1) {
console.log("OPEN");
/**
* Send JSON-RPC
*/
wsRpc.send(JSON.stringify({
jsonrpc: '2.0',
id: 'Unique-RPC-ID',
method: 'name_of_method',
params: ['param0', 'param1', 'param2', 'param3'],
}))
} else if (state == 2) {
console.log("CLOSING");
} else if (state == 3) {
console.log("CLOSED");
}
});
服务器提供的远程方法¶
发起出方向呼叫¶
-
capi.webrtcclient.
make_call
(sdp, from, to)¶ 参数: 返回: 呼叫 ID,对应
sapi.Call.id
属性返回类型: str
举例
客户端调用:
{
"jsonrpc": "2.0",
"id": "2372",
"method": "capi.webrtcclient.make_call",
"params": {
"sdp": "v=0\r\no=user2 1413 2673 IN IP4 192.168.100.105\r\ns=Talk\r\nc=IN IP4 192.168.100.105\r\nt=0 0\r\na=ice-pwd:37605d4ae30266e29a893f3f\r\na=ice-ufrag:55cf1b68\r\na=rtcp-xr:rcvr-rtt=all:10000 stat-summary=loss,dup,jitt,TTL voip-metrics\r\nm=audio 7078 UDP/TLS/RTP/SAVPF 96 97 98 99 0 8 100 101 102 103\r\nc=IN IP4 119.32.243.210\r\na=rtpmap:96 opus/48000/2\r\na=fmtp:96 useinbandfec=1\r\na=rtpmap:97 SILK/16000\r\na=rtpmap:98 speex/16000\r\na=fmtp:98 vbr=on\r\na=rtpmap:99 speex/8000\r\na=fmtp:99 vbr=on\r\na=rtpmap:100 iLBC/8000\r\na=fmtp:100 mode=30\r\na=rtpmap:101 telephone-event/48000\r\na=rtpmap:102 telephone-event/16000\r\na=rtpmap:103 telephone-event/8000\r\na=setup:actpass\r\na=fingerprint:SHA-256 AC:4C:AA:6D:50:AF:CF:BA:31:4D:A0:22:50:DF:CA:E0:67:1B:D4:55:B2:1F:B9:7C:92:9F:DB:F6:78:90:53:AA\r\na=ssrc:4121415948 cname:sip:user2@sip.web2sip.hes86.net\r\na=candidate:1 1 UDP 2130706431 192.168.100.105 7078 typ host\r\na=candidate:1 2 UDP 2130706430 192.168.100.105 7079 typ host\r\na=candidate:2 1 UDP 1694498815 119.32.243.210 7078 typ srflx raddr 192.168.100.105 rport 7078\r\na=candidate:2 2 UDP 1694498814 119.32.243.210 7079 typ srflx raddr 192.168.100.105 rport 7079\r\na=rtcp-fb:* trr-int 5000",
"from": "sip:40099998888@project1.sip.linkrtc.com",
"to": "sip:13899922288@your_sip_provider.com"
}
}
服务器回复:
{
"jsonrpc": "2.0",
"id": "2372",
"result": "f3kjfee"
}
接受入方向呼叫¶
-
capi.webrtcclient.
accept_call
(call_id)¶ 参数: call_id (str) – 要接受的呼叫 ID,对应 sapi.Call.id
属性
拒绝入方向呼叫¶
-
capi.webrtcclient.
reject_call
(call_id)¶ 参数: call_id (str) – 要拒绝的呼叫 ID,对应 sapi.Call.id
属性
结束呼叫¶
由该客户端发起,或者交换到该客户端的任何呼叫,无论方向、状态,都被断开。
-
capi.webrtcclient.
drop_call
(call_id)¶ 参数: call_id (str) – 要结束的呼叫 ID,对应 sapi.Call.id
属性
术语表¶
- LinkRTC
- 见 http://linkrtc.com/
- WebRTC
- 见 http://webrtc.org/
- WebSocket
- 见 https://tools.ietf.org/html/rfc6455
- SIP
- 见 http://www.ietf.org/rfc/rfc3261.txt
- SDP
- 见 http://www.ietf.org/rfc/rfc2327.txt
- HTTP 1.1
- 见 http://www.w3.org/Protocols/rfc2616/rfc2616.html
- HTTPS
- 见 http://en.wikipedia.org/wiki/HTTPS
- HTTP Basic Authentication
- 见 https://tools.ietf.org/html/rfc2617
- UTF-8
- 见 http://en.wikipedia.org/wiki/UTF-8
- JSON
- 见 http://www.json.org/
- JSON-RPC
- 见 http://www.jsonrpc.org/specification
- Restful
- 见 http://en.wikipedia.org/wiki/Representational_state_transfer