近期架设一次webrtc另一种开源实现simplewebrtc用于学习webrtc整体实现及架构。现在单纯P2P架构的webrtc开源服务器已经很少了且近乎没有维护。大部分都是Webrtc SFU和MCU网络模型实现,但对于物联网设备一般情况下下都是一对一通话且P2P十分重要(转发服务器开销很大)。
开源实现里面稍微靠谱一点就是SimpleWebrtc方案了,但该方案也在18年中旬停止维护了,今天部署发现也是一堆坑。
关于simplewebrtc 源码学习可以参见另一篇文章:
https://andyli.blog.csdn.net/article/details/93894837
本文基于ubuntu环境架设
这里引用一下网易云信的架构图及基础流程说明来对webrtc链接建立进行介绍
1) WebRTC A通过Signal Server转发SDP OFFER到WebRTC B。WebRTC B做完本地处理以后,通过 Signal Server转发SDP ANSWER到A。
2)A、B同时向STUN Server发送Binding request请求自身的外网地址,并从STUN Server回包的MAPPED-ADDRESS中得到各自的外网地址;
3)A、B收集完内外网ICE Candidate,并通过Signal Server发送给对方;
4)双方开始做NAT穿越,互相给对方的ICE Candidate发送STUN Binding Request;
5)NAT穿越成功,A、B之间的P2P连接建立,进入媒体互通阶段。
从上文流程描述上既可以看到有三种角色参与webrtc通信流程,一般情况下可以理解为由三个部分组成:
STUN/TURN Server
Signal Server
WebRTC Client端(App Server)
信令服务器中需要配置turn 和stun 地址。stun 可以获取NAT后的地址从而建立连接,turn 可以在打洞失败情况下通过服务器转发保证功能正常, ice 是一个框架,可以包含 turn或stun等穿透协议。具体参考STUN, TURN, ICE介绍。
simplewebrtc 是一套webrtc 开源方案提供了WebRTC Client Server及信令服务器,使用它即可实现一个简单demo,并通过阅读实现流程,可熟悉webrtc通信建立过程。
本文基于simplewebrtc进行架设,
打洞服务器:开源coturn 项目地址:https://github.com/coturn/coturn
信令服务器:simplewebrtc配套的signalmaster ** 项目地址:https://github.com/andyet/signalmaster
Web APP:simplewebrtc ** ** 项目地址:**https://github.com/andyet/SimpleWebRTC
P2P连接建立会涉及到三个概念:STUN, TURN,ICE
而coturn即由Google开源方案发展而来TURN和STUN
Server的免费开源实现。
sudo apt-get install coturn
生成tls证书
因为coturn可以支持tls 所以这里需要生成一份用于tls通信的证书及密匙。
mkdir pem
openssl req -x509 -newkey rsa:2048 -keyout ./pem/turn_server_pkey.pem -out ./pem/turn_server_cert.pem -days 1095 -nodes
-days 有效天数
-node 不加密密匙 加密密匙后则需要解压密码,需要填入部分信息,然后得到证书和密匙:turn_server_pkey.pem turn_server_cert.pem
编辑文件/etc/turnserver.conf配置TURN服务器。并将下下列配置相应修改后复制到文档末尾保存退出
下面配置参数在该文件中均有注释说明。可自行搜索阅读。
listening-device=eth0
listening-port=3478
tls-listening-port=5349
listening-ip=172.17.19.101
relay-device=eth0
relay-ip=172.17.19.101
external-ip=60.70.80.91/172.17.19.101
min-port=49152
max-port=65535
fingerprint
lt-cred-mech
realm=demo
use-auth-secret
static-auth-secret=12345
stale-nonce
cert=/home/usera/coturn/pem/turn_server_cert.pem
pkey=/home/usera/coturn/pem/turn_server_pkey.pem
no-loopback-peers
no-multicast-peers
mobility
no-cli
这里通过上诉使用到参数的相应注释可对照参考
listening-device=eth0 #本地监听网卡
listening-port=3478 #监听端口
tls-listening-port=5349 #tls监听端口
listening-ip=172.17.19.101 #监听内网ip 如果本身网卡绑定的公网ip 则填为公网ip,若为AWS 阿里云等云主机则为内网ip
relay-device=eth0 # 本地用于转发的网卡设备
relay-ip=172.17.19.101 #Relay 地址,用于turn服务器在穿透失败的情况下用于转发地址
external-ip=60.70.80.91/172.17.19.101 #如果是云主机 则需配置这样 且为云主机公网ip/内网ip
min-port=49152 #relay用于转发端口 最小值 云主机 注意开安全组/防火墙
max-port=65535 #relay用于转发端口 最大值 默认端口范围为49152 and 65535
fingerprint # turn 消息中使用指纹进行消息验证
lt-cred-mech #使用长期凭证机制 需要支持WebRTC服务器coTurn必须开启长期凭证机制
realm=demo #管理员用户登录域 必须用长期凭证机制或转变为REST API。
use-auth-secret # TURN REST API flag. 设置基于身份 验证密匙的特殊授权选项的标志。、
static-auth-secret=north # 仅用于turn rest api的“static”身份验证机密值(字符串)
stale-nonce #session寿命,默认为无限时间,配置后为600s
pkey-pwd = #密匙解压密码
cert=/home/ubuntu/pem/turn_server_cert.pem #tls 证书路径
pkey=/home/ubuntu/pem/turn_server_pkey.pem #tls 密匙路径
no-loopback-peers #禁用peer 回环地址 如(127.x.x.x and ::1).
no-multicast-peers #禁用peer 已知广播地址(224.0.0.0 and above, and FFXX:*).
mobility #Mobility with ICE , MICE规格支持. peer在网络之间移动时,端点必须更改其IP地址。 MICE即为解决该情况的方案
no-cli #关闭turn 服务Cli支持
这里因为signalmaster信令服务器使用turn rest API 静态身份验证方式 与apprtc 有一定差异。所以直接配置的是use-auth-secret 和static-auth-secret=north 这两个参数而不是配置user=demo:12345 这种验证方式。
关于身份验证 启用use-auth-secret 及 static-auth-secret=north 行为:
将直接对每个用户生成 username 及凭证名
您无需直接向TURN服务器发出任何请求,也无需控制TURN服务器的REST API。
您在启动TURN服务器时分配了一个秘密密钥,可以从数据库中获取一个秘密密钥(因此可以动态更改),但是我很懒,只是经过硬编码,并在turn config文件中提供了它,还记得启用REST API。作为转弯命令的一部分,turnserver … --use-auth-secret --static-auth-secret=MySecretKey
现在,在您的应用程序服务器中,您将使用相同的密钥来生成凭据,对于用户名,它是UNIX时间戳记,并以一些字符串(可以是随机或用户ID或其他名称)分隔,:而密码将是用户名的HMAC,您的秘密密钥。
关于UNIX时间戳,这是TURN服务器中您的凭据必须有效的时间,因此在计算此时间时,请确保您考虑了应用程序服务器和Turn服务器之间的时钟时间差。
https://stackoverflow.com/questions/35766382/coturn-how-to-use-turn-rest-api
启动及查看状态
先使用命令启动
sudo /usr/bin/turnserver -c /etc/turnserver.conf -o -v
守护启动:
修改 /etc/default/coturn,把TURNSERVER_ENABLED=1的注释去掉。
sudo systemctl daemon-reload
sudo service coturn start
查看状态
service coturn status
如果在云主机上运行请确认相应端口安全组已开放 比如实例中的3478
5349 的TCP UDP端口
测试STUN:
turnutils_stunclient -p 3478 60.70.80.91
结果如下:这里能看到 UDP
reflexive addr 为当前网络的出口IP及端口
0: IPv4. UDP reflexive addr: 101.204.xxx.xxx:60040
测试TURN:
turnutils_uclient -v -t -T -W 12345 54.222.207.42
使用静态密码进行链接测试
-W:TURN REST API “plain text” secret.
这两个参数需与coturn中static-auth-secret保持一致
测试成功后打印类似于下面内容:
4: start_mclient: tot_send_msgs=10, tot_recv_msgs=10
4: start_mclient: tot_send_bytes ~ 1000, tot_recv_bytes ~ 1000
4: Total transmit time is 3
4: Total lost packets 0 (0.000000%), total send dropped 0 (0.000000%)
4: Average round trip delay 68.300000 ms; min = 36 ms, max = 104 ms
4: Average jitter 24.000000 ms; min = 17 ms, max = 64 ms
到这里coturn部署完毕。
1 作为turn/stun服务器对外提供服务器则肯定会涉及到身份验证相关内容,一种方案是使用使用数据库存储用户或Restful API向自有账户服务器验证。第二种就是简单粗暴设置密码验证。
2 在一些文章提到turnadmin 创建管理员账户
sudo turnadmin -a -u
用户名 -p 密码 -r 域名
因为coTurn还提供了一个HTTPS页面:可以进行一些系统设置,比如修改领域,查看用户等,admin用户就是用来访问这个页面。所以不需要的情况下不用执行该步骤。
3 coturn性能
coturn当用作ICE解决方案的一部分时,对于VoIP连接,此TURN服务器可以处理每个CPU的数千个同时呼叫(当使用TURN协议时)或仅使用STUN协议时的数万个呼叫。对于几乎无限的可扩展性,可以使用负载平衡方案。可以使用以下工具(一个或它们的组合)实现负载平衡:该方案由谷歌开源发展而来
signalmaster 一个简单的信令服务器,供客户端连接并为WebRTC进行信令。
本节需要node环境,因signalmaster 同样长期未维护,所以需要node版本降到8.16.0,且package.json中socket.io版本也需要修改为1.37
安装node环境并降级
apt install nodejs #下载nodejs
nodejs -v #查看版本
apt install npm #下载npm 工具
sudo npm install -g n #下载node 版本管理工具n
n list #查看有哪些版本可用
sudo n 8.16.0 #切换版本到8.16.0
node -v #查看版本,如果没有更新到,可以删掉原文件,手动把n模块安装的node链接过去。
sudo ln -s /usr/local/bin/node /usr/bin/node #版本已经切换成功可不执行这步
下载signalmaster并配置依赖
git clone https://github.com/andyet/signalmaster.git # 下载源码
vi package.json # 修改依赖 修改socket io版本为1.3.7
npm install #安装依赖 确保当前node版本为8.16.0
配置signalmaster 参数
修改config/development.json 配置 支持ssl 及 stun 配置
"server": {
"port": 8888,
"/* secure */": "/* whether this connects via https */",
"secure": true,
"key": "/home/usera/certs/webrtc.xxxx.top.key",
"cert": "/home/usera/certs/webrtc.xxxx.top.pem",
"password": null
},
"rooms": {
"/* maxClients */": "/* maximum number of clients per room. 0 = no limit */",
"maxClients": 0
},
"stunservers": [
{
"urls": "stun::60.70.80.91:3478"
}
],
"turnservers": [
{
"urls": ["turn:60.70.80.91:3478"],
"secret": "12345",
"expiry": 86400
}
这里如果不配置这些参数,会导致信令报错。建议直接使用域名加证书的方式启动信令服务器
npm start
打印
&yet -- signal master is running at: http://localhost:8888
说明启动成功。
http://localhost:8888/socket.io/
访问地址得到下列放回即为部署成功。PS:云主机中则需要开启8888端口及用云主机ip替换掉localhost。
返回如下 内容signal master 已经工作起来
{"code":0,"message":"Transport unknown"}
node版本不降 会导致错误:
validation.target.mk:102:
recipe for target ‘Release/obj.target/validation/src/validation.o’ failed
Socket.io使用最新版会导致
TypeError: Cannot read
property ‘resources’ of undefined
下载源码安装依赖
git clone https://github.com/andyet/SimpleWebRTC.git #下载源码
npm install #安装依赖
修改源码
修改simplewebrtc-with-adapter.bundle.js:
vi out/simplewebrtc-with-adapter.bundle.js
反向搜索url参数: SimpleWebRTC 构造函数中this.config中 修改url为信令服务器地址
搜索iceServer参数修改为2.1中coturn地址: iceServers: [{‘urls’: ‘stun:地址:3478’}]
修改test/index.html :
vi test/index.html
test/index.html 中引用了Google路径Jquery代码,国内无法访问会导致界面卡住。可以将这个JQuery 在线引用改为百度cdn地址
将地址:
https://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js 改为https://libs.baidu.com/jquery/1.9.0/jquery.min.js
修改package.json:
将scripts 中 test-page 中stupid-server -s 后加入证书及密匙路径 以支持https。
stupid-server -s -c /home/usera/certs/webrtc.xxx.top.pem -k /home/usera/certs/webrtc.xxx.top.key -h 0.0.0.0
npm run test-page
打印以下内容启动成功:
open https://0.0.0.0:8443/test/
Listening on 0.0.0.0:8443…
两端使用笔记本和手机进行测试,均使用firefox浏览器测试
https://60.70.80.91:8443/test/
填入公网ip访问 ,请填入自己云服务器公网ip。这里可能会报证书错误,适应被没有配置ssl证书 直接忽略警告继续访问。
两端填入同一房间建立链接
测试效果如下:
建立链接前:
建立链接后:
默认设置情况下每路码流码流大约在2Mbps,网络较好情况下,时延在300~400ms(p2p - relay)