前言
STUN
Session Traversal Utilities for NAT,NAT 会话传输应用程序,一种网络协议,它允许位于 NAT(或多重 NAT)后的客户端找出自己的公网地址,查出自己位于哪种类型的 NAT 之后以及NAT为某一个本地端口所绑定的 Internet 端端口。这些信息被用来在两个同时处于 NAT 路由器之后的主机之间建立 UDP 通信。
WebRTC的常见的几个组成部分
- 流媒体服务器
- 信令服务器
- 客户端
安装coturn
NAT穿透服务器 STUN Server
假如该服务器的公网IP为:39.104.20.110
Github:https://github.com/coturn/coturn
1 | #安装依赖 |
这样就说明已经可以启动了,接下来我们先停掉turnserver,重新配置。
turnserver 默认加载配置文件是etc/turnserver.conf
或/usr/local/etc/turnserver.conf
。
1 | cp /usr/local/etc/turnserver.conf.default /usr/local/etc/turnserver.conf |
生成证书
1 | openssl req -x509 -newkey rsa:2048 -keyout /usr/local/etc/turn_server_pkey.pem -out /usr/local/etc/turn_server_cert.pem -days 99999 -nodes |
修改的turnserver.conf内容:
1 | vi /usr/local/etc/turnserver.conf |
修改为如下
1 | # 设置转发的ip(局域网ip),如果不设置,他会自己选择默认的 |
默认的turnserver日志没有时间,可以借助于工具包:moreutils。 这个工具包的一个 ts 工具就是可以让输出的内容加上时间格式。
注意:服务器内置也有一个 ts 命令,但是这个不是我们要的,而是 openssl 的一个指令。
1 | yum install moreutils |
然后接下来试着输出:
1 | echo -e "hello world" | ts '[%Y-%m-%d %H:%M:%S]' |
这样就会自动带上时间格式了。重新启动turnserver
1 | nohup turnserver -c /usr/local/etc/turnserver.conf -v | ts '[%Y-%m-%d %H:%M:%S]' >> /usr/local/etc/turn.log 2>&1 & |
记得开放使用的端口:
可以用这个网址去测试stun和turn的有效性:
https://webrtc.github.io/samples/src/content/peerconnection/trickle-ice/
先移出默认的
stun:stun.l.google.com:19302
测试stun
测试stun的时候不需要输入账号密码,只需要输入第一行,以stun:
开头
stun:39.104.20.110:3478
注意
只要出现Done即为成功,下面提示的fail不用在意。
测试turn
需要输入turn地址,以turn:
开头,以及账号密码
turn:39.104.20.110:3478
kurento
kurento
注意
只要出现Done即为成功,下面提示的fail不用在意。
Kurento服务端
假如该服务器的公网IP为:39.104.20.110
官方网址:https://github.com/Kurento/kurento-media-server
官网教程:https://doc-kurento.readthedocs.io/en/latest/user/installation.html
Kurento是一个WebRTC媒体服务器,同时提供了一系列的客户端API,可以简化供浏览器、移动平台使用的视频类应用程序的开发。Kurento支持:
- 群组通信(group communications)
- 媒体流的转码(transcoding)、录制(recording)、广播(broadcasting)、路由(routing)
- 高级媒体处理特性,包括:机器视觉(CV)、视频索引、增强现实(AR)、语音分析
Kurento的模块化架构使其与第三方媒体处理算法 —— 语音识别、人脸识别 —— 很容易集成。
和大部分多媒体通信技术一样,Kurento应用的整体架构包含两个层(layer)或者叫平面(plane):
- 信号平面(Signaling Plane):负责通信的管理,例如媒体协商、QoS、呼叫建立、身份验证等
- 媒体平面(Media Plane):负责媒体传输、编解码等
WebRTC让浏览器能够进行实时的点对点通信(在没有服务器的情况下)。但是要想实现群组通信、媒体流录制、媒体广播、转码等高级特性,没有媒体服务器是很难实现的。
Kurento的核心是一个媒体服务器(Kurento Media Server,KMS),负责媒体的传输、处理、加载、录制,主要基于 GStreamer实现。此媒体服务器的特性包括:
- 网络流协议处理,包括HTTP、RTP、WebRTC
- 支持媒体混合(mixing)、路由和分发的群组通信(MCU、SFU功能)
- 对机器视觉和增强现实过滤器的一般性支持
- 媒体存储支持,支持对WebM、MP4进行录像操作,可以播放任何GStreamer支持的视频格式
- 对于GStreamer支持的编码格式,可以进行任意的转码,例如VP8, H.264, H.263, AMR, OPUS, Speex, G.711
安装Docker
1 | # 卸载旧版本(如果安装过旧版本的话) |
安装kurento
1 | docker pull kurento/kurento-media-server:latest |
运行
1 | docker run -d --name kms \ |
运行
1 | docker ps -a |
显示
ede4f883c11d kurento/kurento-media-server:latest “/entrypoint.sh” 5 seconds ago Up 4 seconds (health: starting) 0.0.0.0:8888->8888/tcp
进入Docker
1 | sudo docker exec -it 704d3ed68a49 bash |
测试服务是否正常
1 | curl \ |
正常启动会显示
HTTP/1.1 500 Internal Server Error
Server: WebSocket++/0.7.0
退出容器
1 | exit |
查看KMS日志
1 | docker logs kms |
实时查看日志
1 | docker logs -f kms |
该Kurento媒体服务器的端口(KMS)过程中默认监听8888客户端WebSocket连接。
服务的地址为
ws://39.104.20.110:8888/kurento
配置kurento服务器
进入kurento的镜像编辑kurento的配置文件:
1 | #进入镜像 |
修改stun和turn信息
1 | stunServerAddress=39.104.20.110 |
退出容器
1 | exit |
重启kurento容器
1 | #查看当前启动的容器 |
测试
1 | git clone https://gitee.com/psvmc/kurento-tutorial-java.git |
在函数function uiStart()里,增加一个叫iceservers的变量,格式如下:
1 | let iceservers={ |
再修改底下的options变量:
1 | const options = { |
启动项目
1 | mvn -U clean spring-boot:run -Dkms.url=ws://39.104.20.110:8888/kurento |
启动完之后用谷歌或者火狐浏览器打开demo页面https://localhost:8443/
点击start
启动
或者
使用Idea的可以在启动配置中添加
启动的配置项中添加
-Dkms.url=ws://39.104.20.110:8888/kurento
Kurento客户端
Kurento客户端API基于所谓媒体元素(Media Element)的概念。一个媒体元素持有一种特定的媒体特性。例如:
- 媒体元素WebRtcEndpoint的特性是,接收WebRTC媒体流
- 媒体元素RecorderEndpoint的特性是,将接收到的媒体流录制到文件系统
- 媒体元素FaceOverlayFilter则能够检测人脸,在其上方显示一个特定的图像
WebRTC的标准API
https://developer.mozilla.org/zh-CN/docs/Web/API/WebRTC_API
三方库
https://github.com/feross/simple-peer
兼容不同浏览器
https://github.com/webrtcHacks/adapter
Java
1 | <dependency> |
Node.js
1 | "dependencies": { |
Web客户端
为了简化浏览器客户端的WebRTC流处理,Kurento提供了工具WebRtcPeer,你仍然可以使用WebRTC的标准API,以及连接到WebRtcEndpoint。
1 | "dependencies": { |
安装
1 | npm install kurento-client --save |
引用
1 | var utils = require('kurento-utils'); |
或者
1 | <script type="text/javascript" |
创建连接
WebRtcPeer对RTCPeerConnection进行了包装。连接可以是单向的(进行发送或者接收),也可以是双向的(同时发送接收)。
下面的例子示意了如何基于Utils JS创建一个RTCPeerConnection,并与其它Peer进行会话协商:
1 | // 信号处理通道,由你自己决定如何实现,它能够让客户端知道可以和谁通信、如何通信 |
简述一下上例对应的业务流程:
- 通信发起方A,根据接受方B的标识符,向服务器发送WS请求 —— 我要和B通信
- 服务器通过WS推送信息给B,A想和你通信,你愿意吗?
- 如果B愿意,服务器通过WS推送消息给A、B,你们可以通信了
- A、B分别创建连接对象(WebRtcPeer)
- WebRtcPeer会自动收集Candidate,你应该通过WS把Candidate发回服务器,服务器再中转给Peer
- 一单A、B都收集到Candidate,它们就有可能进行点对点通信了(如果是局域网内)
- A发起(Offer)一个会话描述(SDP),B接收到后,给出Answer
- 根据双方的SDP,建立媒体流交换
使用数据通道
数据通道允许你通过活动WebRTC连接传递二进制、文本数据。WebRtcPeer对数据通道的使用也提供了封装,将dataChannels选项设置为true即可使用:
1 | var options = { |
一旦webRtcPeer对象被创建,你就可以调用下面的方法,通过数据通道发送信息:
1 | // 发送的数据类型取决于应用 |