基于 kurento 实现的浏览器 p2p 视频通话。首先上效果图:
kurento 官网提供了 springboot 一对一的视频通话的 demo,我需要将它移植到我们的 springboot+vue 的前后端分离的类似于 QQ 聊天项目中。移植时遇到了不少问题,于是放弃了 demo 中使用的 Spring-websocket 方案,使用 spring-boot-starter-websocket 重写。
1、环境配置
1. 安装 kurento 媒体服务器
WebRTC是一组协议和 api ,可通过对等连接为浏览器和移动应用程序提供实时通信(RTC)功能。而 kurento 在它的基础上提供了更多的功能:媒体传输,处理,记录和播放等。详细介绍请前往 kurento 官网 查看。
kurento 媒体服务器仅支持直接安装在 Ubuntu 上。为了能够在 win10 平台安装测试、在 centos7 服务器上运行,只能通过 docker 安装。安装命令如下:
docker pull kurento/kurento-media-server:latest
docker run -itd --name kms -p 8888:8888 kurento/kurento-media-server:latest /bin/bash
安装完成后可用如下命令验证:
curl \
--include \
--header "Connection: Upgrade" \
--header "Upgrade: websocket" \
--header "Host: 127.0.0.1:8888" \
--header "Origin: 127.0.0.1" \
http://127.0.0.1:8888/kurento
如果出现如下结果,则说明安装成功:
HTTP/1.1 500 Internal Server Error
Server: WebSocket++/0.7.0
2. 安装 stun/turn 打洞服务器
由于 NAT 隐藏了端点的真实IP地址,端点之间建立端到端直接连接就非常困难。这就需要 stun 和 turn 服务器的协助。stun 为端点提供公共 IP 地址建立 p2p 连接,如果连接成功,则不再需要中继的协助。如果 NAT 穿透失败,那么就需要使用 turn 服务器提供中继服务进行通讯。
网上关于 stun/turn 服务器的部署教程非常多。由于安装 kurento 时使用了 docker,所以这里直接使用 docker 安装。github 上有人将所有操作写在了 dockerfile 里,直接使用这个安装更方便,避免踩坑。https://github.com/konoui/kurento-coturn-docker.git
cd /kurento-coturn-docker/coturn/
# 记住加点
sudo docker build --tag coturn .
# 后台运行 coturn
sudo docker run -p 3478:3478 -p 3478:3478/udp coturn
该 dockerfile 配置 turn 的用户名和密码都是 kurento。如需自定义,请在 dockerfile 文件中的 26-27 行中自定义。
ENV TURN_USERNAME kurento
ENV TURN_PASSWORD kurento
然后前往 https://webrtc.github.io/samples/src/content/peerconnection/trickle-ice/ 该网站中输入 turn:ip:3478
以及用户名密码,出现如图所示的 relay 和 done 说明成功。
3. kurento 设置打洞服务器地址
直接进入 docker 找到 kurento 的配置文件:
docker exec -it kms /bin/bash
apt-get update
apt-get install vim
cd /etc/kurento/modules/kurento/
vim WebRtcEndpoint.conf.ini
添加一行:
turnURL=用户名:密码@ip:3478?transport=udp
1.5、运行 kurento 官网提供的 demo
这是官网提供的一对一视频 demo。按照里面提供的 github 地址克隆到本地然后可以打包运行。
注意,如果要运行 kurento 官网中的 demo,可能会无法正常通话。默认情况下,demo 调用的 stun 服务器是它自己的。正如官网所说,如果需要使用自己配置好的 stun 服务器,需要执行如下命令:
mvn -U clean spring-boot:run -Dkms.url=ws://kms_host:kms_port/kurento
但我依然无法成功。所以需要在 demo 中的 index.js 中添加自己的配置。在 function call()
和 function incomingcall()
的 var options = {...}
之前添加:
// 添加自己的中继服务器的配置,否则会默认指向谷歌的服务器
var iceservers = {
"iceServers": [
{
urls:"stun:your_server_ip:3478"
},
{
urls: ["turn:your_server_ip:3478"],
username: "kurento",
credential: "kurento"
}
]
};
然后对 options 进行如下修改:
var options = {
localVideo: videoInput,
remoteVideo: videoOutput,
onicecandidate: onIceCandidate,
onerror: onError,
configuration: iceservers
};
这样就能运行成功。
2、后端实现
springboot 所需依赖为:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>org.kurento</groupId>
<artifactId>kurento-client</artifactId>
</dependency>
<dependency>
<groupId>org.kurento</groupId>
<artifactId>kurento-utils-js</artifactId>
</dependency>
前后端使用 websocket 进行通信。VideoHandler 类注册为一个实例,负责处理 /videoCall
的通信。方法 onMessage()
用于接受消息,根据消息类型调用不同的方法进行处理:
@OnMessage
public void onMessage(Session session, String message) throws Exception {
JsonObject jsonMessage = gson.fromJson(message, JsonObject.class);
UserSession user = getUserSessionBySession(session);
switch (jsonMessage.get("type").getAsString()) {
case "login":
try {
login(session, jsonMessage);
} catch (Throwable t