OpenVidu 的搭建
介绍
应用场景
要安装的服务
OpenVidu Server (openvidu-server) :OpenVidu 的核心服务,管理kurento server之外的业务功能
Kurento Media Server (kms) : Kurento 媒体服务器提供核心的webrtc 接入、转化、过滤等功能。
Coturn (coturn) : 提供Stun, trun 等服务,用于nat 穿透功能
Redis (redis) : database to manage users in Coturn server
Nginx (nginx): a reverse proxy used to configure SSL certificate and to allow both Openvidu Server and the Application to be served in the standard https port (443)
ideoconference Application (app): OpenVidu Call application or any other application Can be disabled
所有的这些服务通过docker container 的方式安装。
安装
1。 确定以安装docker 和docker compose
如果未安装,可以参考 ubuntu下docker, docker compose安装 的说明
检查文件,发现没有copy隐藏文件env, 于是使用同样的命令显示copy env文件。
#cp env -t /opt/openvidu
前言
STUN,首先在RFC3489中定义,作为一个完整的NAT穿透解决方案,英文全称是Simple Traversal of UDP Through NATs,即简单的用UDP穿透NAT。
TURN,首先在RFC5766中定义,英文全称是Traversal Using Relays around NAT:Relay Extensions to Session Traversal Utilities for NAT,即使用中继穿透NAT:STUN的扩展
简单的说,TURN与STURN的共同点都是通过修改应用层中的私网地址达到NAT穿透的效果,异同点是TURN是通过两方通讯的“中间人”方式实现穿透。
ICE的全称Interactive Connectivity Establshment(互动式连接建立),由IETF的MMUSIC工作组开发出来的,它所提供的是一种框架,使各种NAT穿透技术可以实现统一。
STUN和TURN服务器和ICE可以参考阅读: P2P技术详解(三):P2P技术之STUN、TURN、ICE详解
本文介绍如何通过DOCKER搭建STUN和TURN服务器,步骤如下
1:创建Dockerfile,内容如下:
FROM ubuntu:1404
MAINTAINER Patxi Gortázar <patxigortazar@gmailcom>
RUN apt-get update && apt-get install -y \
curl \
libevent-core-20-5 \
libevent-extra-20-5 \
libevent-openssl-20-5 \
libevent-pthreads-20-5 \
libhiredis010 \
libmysqlclient18 \
libpq5 \
telnet \
wget
RUN wget http://turnserveropen-sysorg/downloads/v4422/turnserver-4422-debian-wheezy-ubuntu-mint-x86-64bitstargz \
&& tar xzf turnserver-4422-debian-wheezy-ubuntu-mint-x86-64bitstargz \
&& dpkg -i coturn_4422-1_amd64deb
COPY /turnserversh /turnserversh
ENV TURN_USERNAME test
ENV TURN_PASSWORD test
ENV REALM kurentoorg
ENV NAT true
EXPOSE 3478 3478/udp
ENTRYPOINT ["/turnserversh"]
2:创建turnserversh,内容如下
#!/bin/bash
set-e
if[$NAT="true"-a-z"$EXTERNAL_IP"];then
#Try to get public IP
PUBLIC_IP=$(curl http://169254169254/latest/meta-data/public-ipv4)||echo"No public ip found on http://169254169254/latest/meta-data/public-ipv4"
if[-z"$PUBLIC_IP"];then
PUBLIC_IP=$(curl http://icanhazipcom)||exit1
fi
#Try to get private IP
PRIVATE_IP=$(ifconfig|awk'/inet addr/{print substr($2,6)}'|grep -v 127001)||exit1
exportEXTERNAL_IP="$PUBLIC_IP/$PRIVATE_IP"
echo"Starting turn server with external IP:$EXTERNAL_IP"
fi
echo'min-port=49152'>/etc/turnserverconf
echo'max-port=65535'>>/etc/turnserverconf
echo'fingerprint'>>/etc/turnserverconf
echo'lt-cred-mech'>>/etc/turnserverconf
echo"realm=$REALM">>/etc/turnserverconf
echo'log-file stdout'>>/etc/turnserverconf
echo"user=$TURN_USERNAME:$TURN_PASSWORD">>/etc/turnserverconf
[$NAT="true"]&&echo"external-ip=$EXTERNAL_IP">>/etc/turnserverconf
exec/usr/bin/turnserver"$@"
3:使用docker build 创建镜像,执行结果如下
[root@www]# docker build -t teststurn_1
Sending build context to Docker daemon 4096kB
Step 1/11 : FROM ubuntu:1404
---> 6e4f1fe62ff1
Step 2/11 : MAINTAINER Patxi Gortázar <patxigortazar@gmailcom>
---> Using cache
---> 4460f9f84053
Step 3/11 : RUN apt-get update && apt-get install -y curl libevent-core-20-5 libevent-extra-20-5 libevent-openssl-20-5 libevent-pthreads-20-5 libhiredis010 libmysqlclient18 libpq5 telnet wget
---> Using cache
---> 05ed9ced48a5
Step 4/11 : RUN wget http://turnserveropen-sysorg/downloads/v4422/turnserver-4422-debian-wheezy-ubuntu-mint-x86-64bitstargz && tar xzf turnserver-4422-debian-wheezy-ubuntu-mint-x86-64bitstargz && dpkg -i coturn_4422-1_amd64deb
---> Using cache
---> d82ed28fdac9
Step 5/11 : COPY /turnserversh /turnserversh
---> Using cache
---> 1d37a488282c
Step 6/11 : ENV TURN_USERNAME test
---> Running in bfd88f08db42
Removing intermediate container bfd88f08db42
---> cf8af0504b95
Step 7/11 : ENV TURN_PASSWORD test
---> Running in b8ef33b7c213
Removing intermediate container b8ef33b7c213
---> 32a832f23169
Step 8/11 : ENV REALM kurentoorg
---> Running in bbe129edf5b3
Removing intermediate container bbe129edf5b3
---> 21fdfe34689b
Step 9/11 : ENV NAT true
---> Running in 5bdfe8555d5e
Removing intermediate container 5bdfe8555d5e
---> dc7fc896841c
Step 10/11 : EXPOSE 3478 3478/udp
---> Running in 67aaa1966f68
Removing intermediate container 67aaa1966f68
---> a12646ed45ff
Step 11/11 : ENTRYPOINT ["/turnserversh"]
---> Running in b8fc2ff09265
Removing intermediate container b8fc2ff09265
---> f5e5acad0f81
Successfully built f5e5acad0f81
Successfully tagged teststurn_1:latest
执行完后可以看到自己创建的镜像名称为teststurn_1
4:启动docker的镜像,并开启端口3478
docker run -d -p 3478:3478 -p 3478:3478/udp teststurn_1
启动后需要等待一两分钟才能测试顺畅
5:测试服务器效果
打开 https://webrtcgithubio/samples/src/content/peerconnection/trickle-ice/ 并输入自己的本机IP和端口,分别测试两种协议服务是否生效
Kurento 是一个不错的基于webRTC的音视频媒体服务器。 Openvidu在kurento的基础上实现了音视频会议的功能。我们部署了Openvidu的社区版,在单机上实现了webRTC音视频会议的搭建。为了更进一步了解openvidu,我们有必要花些时间看看openvidu做了什么和怎么实现webRTC通信的。
有了ICE的帮助, 浏览器可以知道自己的外网IP和映射端口等信息,但是在建立webRTC连接前,仍需要互相交换各自的信息, 这个过程并没有在WebRTC框架里定义,所以需要自己来实现。webrtc规范制定组认为,信息的交换应该支持任意方式。这些需要交换的信息被称为signal,而实现signal交换就要借助signaling server 下面是一个更全的webRTC通信模型。
-- PeerB 想和PeerA通信, 首先他需要告诉B,我想和你通信,所以PeerA 通过signal Server 发送给PeerB 一条自己要建立连接的音视频媒体信息(称为offer,包含webrtc建立需要的信息,但并不包含IP和端口等连接信息)
Notes:这里的offer只包含媒体信息,不包含通信连接信息(IP, 端口等)
-- peer B 收到A 的offer后,保存在本地,并生成自己的offfer返回给A(成为answer offer)
-- PeeA 与PeerB 告诉浏览器开始连接, 浏览器通过ICE框架,不断的发送给可能建立连接的IP和端口。他们封装为candidate,通过 Signal Server发送给彼此。
--- 收到对方的candidate后,PeerA ,peer B开始尝试建立连接。
---双方最终完成连接的建立,开始音视频通信。
上面就是一个基本的WebRTC的通信模型。可以看到需要通信,需要STUN Server, TURN Server, 还有signal server
a 在openvidu中,一个激活的会议由kurentoSession实例表示。当创参会者加入会议时,openvidu会创建一个kurentoSession实例。
b 在kurento服务器上,一个会议由一个pipeLine 和N N个mediaEndpoint表示。N表是参会方数量,每一个参会方会创建一个发布媒体用的MediaElement和(n-1)个订阅其它媒体流用的MediaElement,它们被编排入一个PepleLine中, 形成N N的连接。
所以,当第一个用户加入会议室时,系统会在Openvidu上创建一个KurentoSession实例,同时在Kurento上创建一个pipleLine, KurentoSession 实例引用了这个pipepline N个用户会有N个kurentoSession, 但只有一个pipleline。PipleLine的描述是在Kurento Client包里。
管理器中另外一个重要的是sessionManager,session代表的是会议,所以sessionMananger 实际就是所有具体会议的管理 在ioopenviduservercore包下的SessionManager只是一个虚类,它声明了一些会议的操作方法:
这些方法都和会议有关, 可以发现,上面的功能通常对应我们音视频软件进入会议室的功能。
开openvidu中,它的具体的实现是KurentoSessionManager,它会在server启动的时候初始化。
在III中说了,sessionid 代表的会议号,创建会议的时候会创建一个sessionNotActive(Session类)对象,代表的是还未正式使用的会议,当第一个用户首次加入的时候,才会正式使用这个会议,KurentoSessionManager的joinRoom方法描述了相关的逻辑。
与sessionNotActive不同,一个开始使用的会议用KurentoSession来表示(继承自Session),首次加入会议, 需要创建这个Ksession, 它会指定一个具体的Kurrento Server,ksession的创建需要指定具体kms,用来表示在具体哪个KMS创建会议。社区版实际上只有一个KMS,但在实现上如下图, 已经默认使用获取最小负载的方式获得kms。
sessionManager对外提供会议操作功能的统一入口,每个会议对应的kurentoSession负责实际与kurento server的通信,来完具体的会议操作。所以在kurentoSession中我们可以看到相类似的会议功能定义:
上图是一个包含有浏览器、application 、 openvidu server, 、kurento server 等在内的一个逻辑通讯图。
浏览器端加载会议应用程序,通过http协议与application server通信,完成业务请求和获取用于会议的token和sessionID
applicaiton server只负责业务请求,它通过与openvidu server通信来生成浏览器客户端加入会议需要的token和sessionID信息。
浏览器获取token和sessionid后,与openvidu建立websocket连接,它将openvidu作为webrtc中的singal server,与openvidu通信,完成建立webrtc所需要的singal通信。
与webrtc中描述的P2P通讯不同,kurento server 充当代理,与每一个参与方建立p2p连接,通过创建pipleline和编排media endpoint完成多方的通讯。 但是Kurento Server与任意参与方建立的通讯仍旧是P2P通讯。所以,浏览器会与kurento server建立webrtc连接。 他们的通讯默认是RTP over UPD, 也可以是RTP over TCP。
openvidu与kurento也是通过websocket连接进行通讯的,与kurento的通信包含两个方面:
a 作为控制方,创建pipleline,根据加入的用户创建media endpoint, 并编排他们。
b。 作为信号服务器, 与Kurento进行webrtc连接时需要的信号通讯:例如发送sdp, icecandidate,sdp响应等,由于kurento并不是浏览器端,Sdp answser的创建,也是由openvidu完成的。
Openvidu与Kurento之间的通讯编码使用json RPC方式。 kurento 提供了client 包,方便opnvidu 实现rpc调用。
41 PipleLine
orgkurentoclient包里包含一个pipleLIne类,它代表kurento server上的media pipleLine元素; 前面已经提到,一个会议对应一个kurencto pipleLine。而在openvidu中kurentoSession代表一个会议,它包含有一个pipleliene属性:
private MediaPipeline pipeline;
在首个用户加入会议的时候,会创建PipleLine实例:
查看createPipeline方法可以看到,pipleLine使用kurentoclient来创建的。
kmsgetKurentoClient()createMediaPipeline()
PipleLine创建好一个,将作为会议的具体Rpc对象负责其它对象的创建和方法调用。
42 MediaEndpoint,publisherEndpoint、SubscriberEndpoint
openvidu里定义了一个个类:MediaEndpoint。 它对应的是kurento server上MediaElement的抽象,下图是Kurento上的元素概念:
在MediaEndpoint类中,定义了三个endpoint属性,代表三种连接类型:
···
···
WebRtcEndpoint 、RtpEndpoint 、PlayerEndpoint 这三个类来自kurent client包,代表JSonrpc的客户端类,在上图的kurento元素中能够找到对应的元素。
MediaEndpoint对三个类做了风中,使用endpointType来表示当前是那种类型(也就是哪个引用有值)。它有两个子类publisherEndpoint和SubscriberEndpoint,分别表示一个用于publish的mediaElement 和用于subscribe的mediaElement 。 在前文提到, openvidu的会议在kurento server上表示NN 模型的media element关系, Server会为每一个参会者创建一个用于音视频发布的mediaElement 和(n-1)个用于订阅其它用户发布的音视频的media element,publisherEndpoint和SubscriberEndpoint对应的就是这个概念。
无论publisherEndpoint和SubscriberEndpoint是WebRtcEndpoint 、 RtpEndpoint,PlayerEndpoint中的哪个类型,它们封装的rpc对象都由 pipeline创建。
43 KurentoParticipant
openvidu中的KurentoParticipant类代表的是参会方(不同于我们平时理解的用户),每个用户加入会议后才会创建KurentoParticipant,在 "3Openvidu Server与WebRTC的通信" 的示例图中表征的是一个浏览器与Kurento server的连接。一个用户可以打开多个浏览器页面,每个加入会议的页面实际上都代表一个KurentoParticipant。
KurentoParticipant没有具体的JsonPRC对象,相反它拥有一个PublisherEndpoint和
一组subscribers,它们在kurento server刚好表示一个会议参与方:
由于KurentoParticipant代表的是会议的参会方,这个类中定义了几乎所有与publisher和subscribers 有关的操作:
44 KurentoSession
KurentoSession 代表的是一个会议,在kurento上对应的是pipeline mediaElement,但它不属于JsonRPC对象,它对pipeline mediaElement的操作是由PipleLine Jsonrpc对象来完成的,所以它包含由pipeline属性:
这个类中定义了很多会议操作的方法:
浏览器客户端在创建连接获取token和session时,并不会直接创建KurentoSession,默认的只会创建一个session对象,并把它放在sessionNotActive组里。当用户Join会议的时候(调用 KurentoSessionManagerjoinRoom(Participant participant, String sessionId, Integer transactionId) ),才会创建KurentoSession 实例。
Kurento和Jitsi是基于WebRTC的开源媒体服务器开发的两大开源框架,乍看到这两个项目,很难知道他们有什么具体区别,本文对这两个框架进行点对点的比较。
如果你仅仅想获得一个简单的类似“项目中应该用Kurento”或者“Jitsi解决所有问题”的结论,无疑这篇文章很难帮助到你。Kurento和Jitsi的选择往往取决与你的项目目标。由于这个问题很多人在不同的场合问过我,所以我觉得有必要分享下我的观点。现在,我来解释下我是如何区分这两个项目的。
Jitsi是一个SFU开源框架,由Atlassian维护,被集成到HipChat中。Github上的介绍如下:
Kurento是一个媒体服务框架,由Kurento Technologies维护。借助Kurento, 你可以构建任何类型的后端媒体处理功能:SFU,MCU,recording,transcoding,gateway等等。这是优势,也是劣势。
如果你能够在实践中使用它,那么这就是优势。但这总是需要比其他目标简单、聚焦的框架付出更多的工作。有很多软件供应商可以帮助你定制和集成Kurento到你的项目中,其中一个就是项目的实际作者和维护者。
哪个好?
这两个框架都非常流行,每个都有超过10年的实际使用和产品验证。因此,从中选择一个并不总是那么容易。如果你只是需要单纯的XMPP的SFU,那么请使用Jitsi如果你的需求比较复杂,需要做很多集成,那么最好还是使用Kurento。
原文阅读
0条评论