两年前写的笔记,可能有些链接和方式已经不对了,自己评估!
用一张图片来说明客户端A向客户端B发起通话这个过程中,信令服务和STUN服务承担怎样的角色
房间服务
房间服务用于创建和管理通话会话的状态。Google搭建了一个可用的房间服务appr.tc,而且Google也给出这个房间服务的源码,我们可以依据它的代码去搭建我们自己的房间服务用于本地测试以及项目使用。
信令服务
信令服务主要工作是会话控制,网络和媒体信息交换。具体阅读WebRTC的一篇官方文章Getting Started with WebRTC,找到Signaling: session control, network and media information
。
会话控制消息:初始化或者关闭通信并报告错误
网络配置:获取NAT外的ip和port
媒体能力:获取当前终端和其他终端{浏览器、Android、IOS}支持的编码解码器{格式、能力}、采集分辨率、采样率、位宽等信息。
ICE服务
ICE服务是对STUN和TURN服务的整合,用于处理peers间的打洞和打洞不通的情况下的转发。
Google推荐的服务安装平台是ubuntu,所以我们需要准备一个ubuntu版本为14.04及以上的系统。
房间服务是负责房间的创建于管理,也负责整合其他的服务。
这里采用webrtc提供的apprtc项目去架设我们自己的房间服务,此项目依赖Google_App_Engine_SDK_for_Python和Grunt
依据官方的说明能很快就能装好房间服务
~/webrtc_server$ sudo apt install nodejs nodejs-legacy npm pip
~/webrtc_server$ git clone https://github.com/webrtc/apprtc.git
npm
,安装js构建工具grunt
;-g
安装到全局目录下,默认全局目录为/usr/local/lib/node_modules
~/webrtc_server/apprtc$ sudo npm install -g npm grunt-cli
安装依赖包;安装在当前目录的node_modules
目录
~/webrtc_server/apprtc$ npm install
编译apprtc
;生成的文件在再当前目录下的out
目录
~/webrtc_server/apprtc$ grunt build
下载运行apprtc工具-GAE
此房间服务需要依赖Google的应用引擎(Google APP Engine)来执行;用浏览器打开GAE仓库,把网页拉到最后,找到最新的版本号,然后把刚刚的参考地址+版本号去下载;例如google_appengine_1.9.49.zip
~/webrtc_server/apprtc$ wget https://storage.googleapis.com/appengine-sdks/featured/google_appengine_1.9.49.zip
~/webrtc_server/apprtc$ unzip google_appengine_1.9.49.zip
constants.py
修改如下:
-TURN_BASE_URL = 'https://computeengineondemand.appspot.com'
-TURN_URL_TEMPLATE = '%s/turn?username=%s&key=%s'
-CEOD_KEY = '4080218913'
+TURN_BASE_URL = 'http://192.168.201.64:2016' #Web服务地址
+TURN_URL_TEMPLATE = '%s/turn/%s/%s' # web服务的地址,rest样式
+CEOD_KEY = 'boyaa_media' # key,这个需要与coturn的配置相同
WSS_INSTANCES = [{
- WSS_INSTANCE_HOST_KEY: 'apprtc-ws.webrtc.org:443',
+ WSS_INSTANCE_HOST_KEY: '192.168.201.64:8089', #信令服务器
WSS_INSTANCE_NAME_KEY: 'wsserver-std',
WSS_INSTANCE_ZONE_KEY: 'us-central1-a'
}, {
- WSS_INSTANCE_HOST_KEY: 'apprtc-ws-2.webrtc.org:443',
+ WSS_INSTANCE_HOST_KEY: '192.168.201.64:8089', #信令服务器
WSS_INSTANCE_NAME_KEY: 'wsserver-std-2',
WSS_INSTANCE_ZONE_KEY: 'us-central1-f'
}]
apprtc.py
修改如下:
- wss_url = 'wss://' + wss_host_port_pair + '/ws'
- wss_post_url = 'https://' + wss_host_port_pair
+ wss_url = 'ws://' + wss_host_port_pair + '/ws'
+ wss_post_url = 'http://' + wss_host_port_pair
~/webrtc_server/apprtc$ export PAHT=$PATH:${PWD}/google_appengine
启动服务
选项--host
房间服务监听地址,选项--port
房间服务监听端口;选项--admin_host
后台管理监听地址,选项--admin_port
后台管理监听端口;选项--log_level
打印级别{debug,info,warning,critical,error};选项--skip_sdk_update_check
运行dev_appserver.py命令时不检查更新;
~/webrtc_server/apprtc$ dev_appserver.py --host=0.0.0.0 --admin_host=0.0.0.0 --storage_path=/home/stone/mywork/webrtc_server/log --logs_path=apprtc.log out/app_engine/ --log_level debug
房间服务apprtc
里自带了一个信令服务[Collider](https://github.com/webrtc/apprtc/blob/master/src/collider)
,是一个Go语言编写的基于WebSocket实现的一个信令服务器。
~/webrtc_server$ sudo apt install go
collider
;由于go的语言的安装会从环境变量GOPATH
寻找可安装的目录,所以需要把创建的目录collider
加入到环境变量GOPATH
中。~/webrtc_server$ mkdir -p collider/src && export GOPATH=${PWD}/collider
~/webrtc_server/apprtc$ ln -s ${PWD}/src/collider/collider $GOPATH/src
~/webrtc_server/apprtc$ ln -s ${PWD}/src/collider/collidermain $GOPATH/src
~/webrtc_server/apprtc$ ln -s ${PWD}/src/collider/collidertest $GOPATH/src
get
下载指定包以及相关依赖资源;选项install
编译指定包,编译后的文件存放在$GOPATH/bin
目录下;如果get失败,请检查下环境变量GOPATH
。~/webrtc_server/apprtc$ go get collidermain
~/webrtc_server/apprtc$ go install collidermain
go install collidermain
-var tls = flag.Bool("tls", true, "whether TLS is used")
-var port = flag.Int("port", 443, "The TCP port that the server listens on")
-var roomSrv = flag.String("room-server", "https://appr.tc", "The origin of the room server")
+var tls = flag.Bool("tls", false, "whether TLS is used")
+var port = flag.Int("port", 8089, "The TCP port that the server listens on")
+var roomSrv = flag.String("room-server", "http://192.168.201.64:8080", "The origin of the room server")
GOPATH/src/collidermain/main.go
;命令行参数:-port
指定监听端口,-tls
设置是否采用tls模式,-room-server
设定房间服务地址。$ $GOPATH/bin/collidermain
Google实现的
$ sudo apt install openssl libevent-core-2.0-5 libevent-dev sqlite sqlite3
~/webrtc_server$ git clone https://github.com/coturn/coturn.git
~/webrtc_server/coturn$ ./configure && make -j && sudo make install
默认配置
配置文件: /usr/local/etc/turnserver.conf
认证证书: 私钥/usr/local/etc/turn_server_pkey.pem
,公钥/usr/local/etc/turn_server_cert.pem
Log文件: /var/tmp/turn.log
数据库文件: /usr/local/var/db/turndb
配置
初始化数据库,我们采用sqlite3,利用coturn的配置创建数据库文件并创建相应的表
~/webrtc_server/coturn$ sudo rm -f /usr/local/var/db/turndb
~/webrtc_server/coturn$ cat turndb/schema.sql | sudo sqlite3 /usr/local/var/db/turndb
创建证书,并拷贝到默认目录,此证书用到的密码应该与配置文件turnserver.conf
中static-auth-secret
的一样
~/webrtc_server/coturn$ openssl req -new -x509 -newkey rsa:4096 -days 3650 -keyout privkey.pem -out server.pem
~/webrtc_server/coturn$ openssl rsa -in privkey.pem -out privkey.pem
~/webrtc_server/coturn$ sudo mv privkey.pem /usr/local/etc/turn_server_pkey.pem
~/webrtc_server/coturn$ sudo mv server.pem /usr/local/etc/turn_server_cert.pem
配置文件,由于项目需求,我们暂时不考虑stun,所以会去掉stun的监听以减轻服务器监听负担(占用的资源感觉可以忽略不计),采用REST API方式认证;创建一个空配置文件\/usr\/local\/etc\/turnserver.conf
,配置文件内容如下:
listening-device=ens32 #监听设备名字,通过ifconfig查看
listening-port=3478 #stun/turn共用的监听端口,根据看到的文档没有发现分离方式
listening-ip=192.168.201.64 #监听的ip,如果不设置会默认监听ipv4/v6的本地地址以及host地址,我只需要监听ipv4的host地址,所以需要指定它;可以存在多个监听地址,写多个listening-ip即可
relay-device=ens32 #转发设备名字
relay-ip=192.168.201.64 #转发地址,我也仅仅需要ipv4的host地址,所以手动指定,也可以多个
verbose #开启普通打印
fingerprint #取设备server的fingerprint给到client
use-auth-secret #使用瞬时认证
static-auth-secret=boyaa_media #瞬时认证的key
realm=boyaa.com #域名,一定需要设置的
no-dtls #不支持dtls模式
no-stdout-log #不在终端输出日志
log-file=/var/log/turnserver.log #指定log存放位置及名字类型,最后的文件名字会是turnserver_日期.log
no-stun #不支持stun,我们只需要转发
no-loopback-peers #不支持perr使用loopback地址(127.0.0.1 和 ::1)
no-multicast-peers #不支持使用广播地址(224.0.0.0及以上地址)
mobility #移动ICE规范支持,我也不懂啥意思
cli-ip=192.168.201.64 #command-line-interface地址,也就是telnet登陆地址,一般调试用,我需要用它看turnserver的状态
cli-password=coturn #telnet登陆密码
-o
选项以守护进程方式启动;-c
指定配置文件;-n
仅仅采用命令行方式配置;-v
普通模式的Log输出;-V
很啰嗦的打印,官方都不建议打开;-S
仅仅使用stun服务。$ sudo turnserver
-l
仅显示监听的socket;-n
显示数字地址和端口(192.168.1.102:3487这类地址);-p
显示socket所属的pid和进程名;-t
显示tcp协议的socket;-u
显示udp协议的socket。$ sudo netstat -lnptu | grep turnserver | uniq | grep tcp
GET
方法;这个Web服务还需要向turn服务写入这个“瞬时密码”。python实现如下:
import web
import json
import hmac
import sqlite3
from hashlib import sha1
import time, datetime
urls = ('/turn/([^/]+)/[^/]+','turn')
class turn:
def GET(self,username):
ttl = 86400
end_time = int(time.time()) + ttl
turn_username = str(end_time)+":"+username
key = 'boyaa_media'
hashed = hmac.new(key, turn_username, sha1)
credential = hashed.digest().encode("base64").rstrip('\n')
data = {
'ttl': ttl,
'iceServers': [
{
'urls': [
"turn:192.168.201.64:3478?transport=udp",
"turn:192.168.201.64:3478?transport=tcp",
"turn:192.168.201.64:5349?transport=tcp",
"turn:192.168.201.64:5766?transport=tcp",
],
'username': turn_username,
'credential': credential
},
],
}
conn = sqlite3.connect('/usr/local/var/db/turndb')
conn.execute("insert into turn_secret (realm,value) values (?,?)",(realm,credential));
conn.commit()
conn.close()
return json.dumps(data)
if __name__=="__main__":
app = web.application(urls, globals())
app.run()
$ sudo python webrtc_restapi_server.py 2016
选项 | 说明 |
---|---|
listening-device | 监听的网络设备名字,通过命令ifconfig 查看 |
listening-port | TURN的监听端口 |
tls-listening-port | TURN TLS监听端口 |
listening-ip | 转发服务器监听ip,可以有多个(设置多个listening-ip即可),同时支持IPv4 IPv6,默认使用本ip |
aux-server | 辅助服务,用于stun/turn |
relay-device | 转发服务器的设备名字 |
relay-ip | 转发ip,默认采用本地ip地址作为转发地址,端口号为服务器自动分配 |
external-ip | turn server共有地址和私有地址的隐射,书写形式: external-ip=60.70.80.91 或者 external-ip=60.70.80.91/172.17.19.101 |
relay-threads | 单个连接的最大并发数,如果不设置这个字段默认为当前设备的CPU个数 |
min-port | 最小分配端口号,转发服务器申请的最小端口号 |
max-port | 最大分配端口号,转发服务器申请的最大端口号 |
verbose | 详细日志,默认关闭,调试的时候或许可以用到 |
Verbose | 这个是verbose的扩展,会输出更加详细的日志,官方都推荐打开 |
fingerprint | 指纹,默认关闭,TODO |
lt-cred-mech | long-term认证,可以通过turnadmin -k -u user -p pass -r realm 获取key |
no-auth | 和lt-cred-mech的作用是相反的,允许匿名访问turn server,如果没有定义任何用户并且没有定义定义此选择,那么默认是开启的,如果存在一个用户或者开启lt-cred-mech,那么默认是关闭的 |
use-auth-secret | 静态认证密码,这是一种较安全的做法,客户端通过http向服务器请求一组加密后的密码,客户端返回一个lt认证过的密码,用户可以使用这组密码与turn server通信。具体查看TURN REST API |
static-auth-secret | 给TURN REST API 使用的静态密码,否则动态生成一个秘密 |
server-name | 认证服务器 |
oauth | 开启认证 |
user | 设置用户以及密码,这个和use-auth-secret是对立存在的。客户端可以直接通过这个用户名和密码来访问turn server,使用形式:user=username1:key1 user=username1:password1 ,存在多个用户就使用使用多次;key通过turnadmin生成 |
userdb | SQLite数据库文件的位置,使用形式:userdb=/var/db/turndb |
psql-userdb | PostgreSQL数据库的连接配置,使用形式:psql-userdb="host= |
mysql-userdb | MySQL数据库的连接配置,使用形式:mysql-userdb="host= |
mongo-userdb | MongoDB数据库的连接配置,使用形式:mongo-userdb="mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]" |
redis-statsdb | Redis数据库的连接配置,使用形式:redis-statsdb="ip= |
realm | 域名,任意字符串,例如boyaa.com |
user-quota | 每一个用户可以申请的名额个数 |
total-quota | 总共可以申请的名额个数 |
max-bps | 输入和输出的最大码率 |
bps-capacity | 总吞吐量 |
no-udp | 不监听upd客户端,默认监听 |
no-tcp | 不监听tcp客户端,默认监听 |
no-tls | 不监听tls客户端,默认监听 |
no-dtls | 不监听dtls客户端,默认监听 |
no-udp-relay | 不转发到upd peer,默认转发 |
no-tcp-relay | 不转发到tcp peer,默认转发 |
max-allocate-lifetime | allocate失效时间,默认是3600秒 |
channel-lifetime | channel通道失效时间,默认是600秒 |
permission-lifetime | 权限失效时间,默认死300秒 |
cert | 证书位置 |
pkey | 私钥位置 |
no-stdout-log | 日志不输出到终端,默认输出 |
log-file | 日志输出位置,如果设定,默认情况会同时输出到终端和log文件内 |
simple-log | 日志的输出格式(without PID and date appendage) |
alternate-server | 交替server,用户轮流接收客户端的ALLOCATE requests 请求,存在多个server就定义多次 |
stun-only | 只提供stun功能 |
no-stun | 不提供stun功能 |
rest-api-separator | 设置TURN REST API 的分隔符号 |
no-loopback-peers | 不允许peer使用loopback地址(127.x.x.x and ::1) |
no-multicast-peers | 不允许peer使用广播地址(224.0.0.0 and above, and FFXX:*) |
max-allocate-timeout | 设置allocate超时时间,单位是秒,使用形式:max-allocate-timeout=60 , |
denied-peer-ip | 不允许访问的ip范围 |
allowed-peer-ip | 允许访问的ip范围 |
no-cli | 关闭telnet支持 |
cli-ip | 设置telnet登陆ip |
cli-port | 设置telnet端口号 |
sessiondescription.h
包含了对SDP的拆分的封装;此文档主要以例子为主