基于Kurento的webRTC音视频开发
Kurento的坑基本已填,包括安卓和web端的实现,。文章大致讲下思路,里面坑由于时间问题,就没一点一点列出来。欢迎有各种各样的小伙伴咨询服务器搭建1、安装环境版本Kurento只能运行在unbuntu系统下,官方建议为 14、16、18版本。具体centos等其他操作系统下能否能运行未进行实测,官方也有docker安装版本,笔者暂未进行测试。要搭建测试环境有没有合适的服...
Kurento的坑基本已填,包括安卓和web端的实现,。
文章大致讲下思路,里面坑由于时间问题,就没一点一点列出来。欢迎有各种各样的小伙伴咨询
- 服务器搭建
1、安装环境版本
Kurento只能运行在unbuntu系统下,官方建议为 14、16、18版本。具体centos等其他操作系统下能否能运行未进行实测,官方也有docker安装版本,笔者暂未进行测试。
要搭建测试环境有没有合适的服务器,只能在工作站上安装虚拟机来解决。
实测了windows10系统下,安装VMware Workstation Pro虚拟机,可安装unbuntu14发行版。更高版本的16、18由于系统安装时需要再国外服务器更新相关软件,未能安装成功,因此后续测试在unbuntu14下完成。
2、kurento服务器的安装没有其他需要注意的,安装官方教程命令逐步安装即可。
Kurento存储库添加到系统配置中。
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 5AFA7A83
sudo tee "/etc/apt/sources.list.d/kurento.list" >/dev/null <<EOF
# Kurento Media Server - Release packages 建议设置为当前最新的版本号
deb [arch=amd64] http://ubuntu.openvidu.io/6.13.0 $DISTRO kms6
EOF
安装KMS
sudo apt-get update && sudo apt-get install --yes kurento-media-server
启动和停止命令
sudo service kurento-media-server start
sudo service kurento-media-server stop
注意,这里是6.0版本以后的启动方式,如果是6.0及以下的版本 要在kurento-media-server后面跟当前安装的具体版本
这里主要说6.0: 启动方式
sudo service kurento-media-server-6.0 start
启动成功后 显示 starting kurento media server …done.
或者通过
sudo service kurento-media-server-6.0 status
查看状态。
返回信息中 server is running with pid xxx
则表示启动成功了,可以开始进行开发。
默认kurento通过 ws://youip:8888/kurento 地址和你的java应用服务端 通过json进行通信和控制。
- 如何使用kurento
- 笔者直接使用kurento提供的java配套库进行相关操作。
相关的操作均是通过json来远程控制,因此java应用服务器需要在创建kurento对象时连接ws://youip:8888/kurento进行一次初始通讯。后续所有的控制则都可以通过java应用服务器的kurento对象进行操作了。
- 为何webrtc可以点对点通信了,还要加一个流媒体服务器
实际上客户端之间可以直接通过webrtc建立点对点的交互,并不需要服务器进行流媒体数据的中转,只需要信令服务器交换两个客户端的网络信息和控制信令后即可实现。为何要通过kurento进行一次中转,意义何在,这里不做展开,商业应用必然需要进行服务器流媒体中转处理,通过服务器中转可以解决包括不同协议的转换、数据存储、流数据的实时分析以及多点交互后客户端性能不足等问题。而众多开源服务器中kurento无疑是功能强大而且社区和文档支持力度较大的方案之一(应该没有之一)。
- 如何通过kurento服务器进行一次点对点的webrtc流媒体交互
首先说明,该教程是你基于笔者自己对kurento使用的理解,详细的文档请直接访问官方教程。
MediaPipeline
媒体管道,顾名思义 是用于传输、连接 各类流媒体、文件、数据的对象。要完成无论1个视频还是多个视频的交互,MediaPipeline是基础。所有的其他媒体原件都和他有关联。
例如网络端点WebRtcEndpoint创建方式
WebRtcEndpoint callerWebRtcEp = new WebRtcEndpoint.Builder(pipeline).build();
比需在builder里面传入一个pipeline。
WebRtcEndpoint
Webrtc接入点,顾名思义,所有通过webrtc协议接入的客户端 需要通过这个接口进行交互。因此WebRtcEndpoint可以理解为和客户端1对1的数据交换连接,类似restful风格的接口。但是区别是,这个WebRtcEndpoint只能和1个客户端进行连接。因此在创建端点后,当客户端通过websoket发过来了offer,信令服务器可以通过webRtcEndpoint.processOffer(offerSDP)来让kurento服务器来接受这个offer并返回一个answerSDP,这个answerSDP再通过信令服务器的websocket返回给客户端设置。双方在设置之前监听candidateFound的事件,candidate(既客户端和kurento服务器的网络端口数据)在监听到后,需要立即通过websokcet发送给对端进行candidate数据的添加。
经过上诉的信令和协议交换后,客户端和kurento服务器既完成连接建立,最后通过webRtcEndpoint. gatherCandidates(),表示candidate数据已经收集完成,可以进行数据交互了。
另外需要注意的是,有可能因为网络传输速度的问题, 被叫客户端进行了answer后,部分candidate先传输到信令服务器,这个时候需要把candidate先存下,待webRtcEndpoint创建后,再添加到webRtcEndpoint对象。具体处理代码如下:
public void setWebRtcEndpoint(WebRtcEndpoint webRtcEndpoint) {
this.webRtcEndpoint = webRtcEndpoint;
for (IceCandidate e : candidateList) {
this.webRtcEndpoint.addIceCandidate(e);
}
//这里添加到webRtcEndpoint后,临时存candidate的List也要清空。
this.candidateList.clear();
}
//下面同样的方法,如果webRtcEndpoint被创建了,直接添加到webRtcEndpoint对象,否则先放到临时的list,待webRtcEndpoint创建后添加。
public void addCandidate(IceCandidate candidate) {
if (this.webRtcEndpoint != null) {
this.webRtcEndpoint.addIceCandidate(candidate);
} else {
candidateList.add(candidate);
}
}
webRtcEndpoint建立后,原则上只有来自客户端所推的流,并没有下发到客户端的流。因此如果A客户端推送给webRtcEndpointA对的流要转发给webRtcEndpointB作为输入后发送给B客户端,则需要webRtcEndpointA.connect(webRtcEndpointB),如果是
webRtcEndpointB.connect(webRtcEndpointA),侧是把B的流推给A。因此如果是两个客户端要进行视频交互,侧需要A.connect(B)同时B.connect(A)。当然也是可以A.conect(A),自己传的流在服务器跑一圈后传给自己播放(做测试时可以这样用,官方helloworld的例子就是这样)。
另外,这些端点需要建立连接,则都要依托同一个MediaPipeline。因此可以理解在初始化webRtcEndpoint的时候要传入一个MediaPipeline,这个MediaPipeline相当于一条路。大家都在这条路上,当然可以数据互通。
1个webRtcEndpoint可以推送给多个其他端点,但是1个webRtcEndpoint只能接受来自1个其他端点的流。
webRtcEndpoint建立后可以只等待对方推流,而自己不推流。
webRtc可以只单独推音频、单独推视频和同时推,但不能同时不推。
客户端推的 b流可以是来自硬件的摄像头、麦克风、也可以是音视频,还是获取的桌面截屏。
PlayEndpoint
可以用于直接播放url视频连接,视频可以是rstp地址,也可以是mp4等视频地址(MP4视频地址这个有待确认)。
RecordEndpoint
录像端点,可以将视频流存储到指定位置。可以通过第三方插件实时将视频流转码推送到rmtp服务器,实现各种协议的兼容。
- 客户端的配合
1、最新的API,获取屏幕进行共享
navigator.mediaDevices.getDisplayMedia({video:true}).then(stream => {
this.$refs.uiLocalVideo.srcObject = stream;
}).catch(error => {
console.log(error);
});
2、客户端摄像头调用则参考官方文档即可。
更多推荐
所有评论(0)