BigBlueButton音视频框架分析

本文深入分析了BigBlueButton(BBB)的音视频框架,基于WEBRTC,利用Kurento媒体服务器处理视频和freeswitch处理音频。BBB采用SFU架构,通过信令服务器实现客户端与Kurento的通信。文中详细描述了从用户分享视频到多用户交互的步骤,揭示了BBB中节点创建、连接和流传输的过程。此外,文章提出了构建MCU模型的设想,讨论了音频处理和NAT穿透技术,为理解BBB系统提供了宝贵的洞察。
摘要由CSDN通过智能技术生成

              BigBlueButton音视频框架分析

前言: BBB的音视频框架是基于WEBRTC的,视频服务端是Kurento媒体服务器,音频服务端用的是freeswitch,信令的传递用的是websocket和SIP(音频)。 此文档的目的是分析BBB系统音视频的整体架构,包括音视频WEBRT节点的创建,连接,流的传输过程,整体模块架构,从源码中详细剖析整个过程。

在阅读本文档时可结合Bigbluebutton源码分析一文一起查阅。

本文档很多是个人观点,不能保证所有都是正确的,如发现问题,欢迎指正。

BBB音视频系统框架图分析:

先看BBB整体框架图。

而信令服务器和kurento,freswitch服务器 是属于html5 server的一部分。

BBB webrtc架构框架图

BBB中是采用SFU架构,所以它的数据模型图如下所示:

 

这是BBB音视频相关的各模块的交互图:

freeSwitch和kurento server的源码未包含在BBB的源码中,需自行从开源项目中下载。

详细框架图:

此图的应用场景是属于房间A的两个客户端已正在使用webrtc通信,属性房间B的两个客户端也正在通信(为简化过程,些图先忽略音频)。

上图概述了在BBB上的WEBRTC系统 的主要模块之间是怎样交互的。从图中可以看到信令服务器中框架中的作用,它沟通了webrtc客户端 与 kurento服务器,webrtc客户端只需要与信令服务器通信,然后由信令服务器通过kurent-client模块调用kurento 服务器创建相应的WebrtcEndpoint,并控制各WebRTCENDPoing之间的连接,流的转输,就实现了BBB的SFU服务器。对于开发WEBRTC客户端 来说,kurento服务器是透明的,只需要信令服务器交互,当然最终kurento服务器端的节点会和客户端的节点建立连接并传输媒体流。但是这些连接和传输过程对应用开发者也是透明的,开发者只需要操作几个接口实现节点间必要的信息交互 SDP信息,ICECandiate信息就行了。

我们的研究目的是为了弄清楚BBB系统中WebRTC节点的建立 ,连接,与输入输出的过程,所以关键点就是nodejs实现的信令服务器。

信令服务器几个主要的类图关系如下:

BBB音视频系统详细服层次构架图:

信令服务器包含五个模块:

serverjs,Video, audio,screenshare,media process center . media process center控制了,Kurent 服务器,相对于服务器来说信令服务器就是客户端了。

每个模块是独立进程,也是通过websocket沟通的。

在bbb系统 中,调用到kurento服务器的接口在 kurento.js 和 banlancer.js中,kurento.js和banlancer.js的下面是kurent-client模块,这是标准的nodejs模块。

const VIDEO_TRANSPOSING_CEILING = config.get('video-transposing-ceiling');

这里配置了最多允许多少个流传输,默认的是50,这是代表一个主机默认最多50个,要想多于50个人的视频会议可以把这个参考调大,也可以新增kurento服务器。它这里是可以配置多台服务器的并设置每台服务器最大的视频流数量。  

信令的信息是私有的,信令的内容和信令交互的过程是客户端和服务器共同约定的。

无论信令的组织形式是什么,要实现webrtc节点之间的连接和通信,它们之间必须交互的信息是,两个节点的SDP信息,两个节点的icecandiate信息(可以简单理解成节点的IP和端口信息) 两个无打洞服务器的webrtc节目之间的连接过程如下图所示:

https://i-blog.csdnimg.cn/blog_migrate/6b28536f4c16f9e6e42976d3d9427ac4.png

为了搞清楚bbb系统 ,有个重要的地方一定要明白,在bbb中/Callee实际上是在kurento server中,也就是说在bbb中上图的server 和 callee实现上callee 这个Webrtc中的节点就在Server中,也就是在Kurento服务器中。

通过前面对整体框架的分析我们已经有了大体印象,接下来再从源码的角度来剖析理解音视频的整体详细过程。

场景和源码剖析

在同一房间中有A,B两个浏览器客户端 ,此时A,B客户端的音频和视频均是关闭的,也就是说此是未开始任何音视频相关的处理。

第一步:A用户开开始分享自己的视频。

如图所示:

当客户端发起start请求并携带了自身的sdp信息上来,客户端和信令服务器端的连接方式是websocket,url 是固定的 wss://serverip/webrtc/?sessionToken = ** , 就是说客户端是直接控制信令服务器的。

我们可以借助浏览器调试工具分析了解详细过程:

首先连接到了 websocket。

然后发送了Json 信息到服务器。

可以看到这个Json信息中主要带了cameraId(这是用户身份标识),meetId(所属房间标识),SDP信息(主要描述本机的视频的编解码能力信息,此时只有视频的描述,未有音视频描述,这是因为音视频和视频在BBB中完全是单独处理的),type:video(视频相关),role:”share”(表示这是分享视频)。

这一步骤在浏览器客户端的处理主要在这里:

。看源码可知,这里是创建了webrtc节点,并收集了本地SDP信息后发送了刚才那个json消息,之后这个webrtc节点还会收集本地ICEcandidate信息发出去。

可以看到icecandiate主要是些本地的IP和端口信息,这是为了webrtc节点之间建立数据通道的。

服务器端收到这个Json消息后分发给video模块。 代码在:

我们在来看接下来的处理过程:

创建了Video对象,并调用了start函数。

再看start函数干了什么:

调用了mcs的join,和publish函数,由于这里的role是share,意味着这是分享视频,所有这里调用的是pulish发布函数意思是将流发到服务器 ,对应的还有subscribe,意思是订阅意味着希望将某个流拉到本地 ,得到了sdp anwser,并设置了一系统媒体状态监听函数 ,这一过程很重要我们接着往下分析。 从Video.js调用到MediaController.js实现中是通过websocket网络通信实现的。

是从MSCApiStub.js调到了MediaController.js,函数名都是一一对应的。

现在我们来分析MedaiController.js中的Join和public方法。

 Join实际上是得到了房间和用户对应。 我们前面有介绍过信令服务器中相关的类和层次结构。 其实就是User管理着Mediassesion,崦Mediassesion通过控制krent 的 adater 来实现真正媒体管道 和 媒体节点的创建 和媒体节点之前的连接。 这里的逻辑其实并不复杂。

对应管关系就是每一个客户端对应一个user,一个user在分享一个流的时候就会创建一个mediasession,而一个mediassesion中可能创建了多个webrtc节点。

当调用到sdp-session.js(继承于mediasession)的 process时就会处理sdp并建立 webrtc节点并返回sdp anwser。

在调用negotiate创建了媒体管道和webrtc节点之后 就收集在ice信息并发给浏览器客户端 。 在加到videomanger中,拿到sdpanwser后发送了 startResponse。

在浏览器客户端拿到startResponse消息之后 ,就将sdpAnwser 在对应的节点中设置中remoteSDp信息,拿到服务器发来的icecandiate就通过setIcecandiate接口设置下去。这样浏览器端和 kurento服务器端 都得到了双方的sdp和icecandaite信息,就可以建立媒体通道了。之后浏览器摄像头采集的数据流发送到服务器(这一过程在应用上不好看见)之后 ,kurento服务器会发送一个媒体流开始的事件。如代码:

请注意这条消息的cameraId,其实也就标识用户的唯一ID,这个ID和用户A的ID是一样,而这时的role是viewer,代表要订阅用户A的视频。 服务器就是根据这个cameraID找到用户A的视频流并传给用户B的。

都整个webrtc交互完成之后,这时候浏览器B建立了WEBRTC连接Kurento中新建的WEBRTC节点,然后将kurent中A的webrtc的src连接到B中的webrtc节点的sink。

如代码所示,source session代表A的session,新建的ssesion 代码为用户B创建的session,将A的session 连接到B的session,其实最终就是调到kurento中,kurento中将A的src端连接到B的sink端 ,这样B中就有A的流了,再将流传会到B中的浏览器。

过程一样,在B的浏览器得到playstart消息后,从webrtc节点中取出远程流并渲染在video标签上。

此时webrtc节点之间的连接如图所示:

此时是A中在显示 A摄像头的视频,B中也在显示A摄像头的视频。

第三步:用户B也分享自己的摄像头。

过程与用户A分享摄像头一致,也就是在浏览器B中又会新那一个webrtc节点,在kurento中也会新建一个webrtc节点,并将B的流传到kureto中。

第四步:用户A得到用户B分享视频的消息。

这时候和第二步很像,用户A中会新创webrtc节点,Kurento中会新建webrtc节点,并将这个点节点的sink和用户B分享流的节点的src相连,这样用户A也得到了用户B的流,并显示出来。 此时webrtc节点之前的连接是这样的:

   

,试想此时用户A,用户B取消分享的过程是怎样的呢,这一过程倒是简单取消分享就是客户端发送stop消息给服务器,这时候客户端和服务器把相应的资源给释放掉,然后客户端重刷一下UI就行了。

设想一下:如果此时用户C也进入房间,那么过程是怎样的呢?

用户C会从h5服务器中知道此时有A,B正在分享视频流,然后用户C需要拉A,B的流并显示。 用户C中会创建两个webrtc的节点,kurent服务器中也会创建两个webrtc,并将这两个webrtc的sink端分别连接到用户A,B节点的src端。 在客户端完全和服务器端 webrtc节点的连接后,用户C就能够得到用户A,B的流并渲染了。

视频框架总结:

我们到现在已经基本把脉络都理顺了,如果你能很明白的想清楚在某个场景中整个系统有多少个webrtc节点,每个节点的是如何连接的,那么相信已经对这个系统理解得差不多了。 我们看到这里不免疑惑:每个客户端中有多少个流就存在多少个webrtc节点,而在kurento服务器端就更多了,它应该是客户端所有webrtc节点的总和,试想100个人同时在一个房间中互相通话的场景,天啊,这些webrtc节点真的太多了,现在还是没考虑音频的情况。为什么要创这么的webrtc节点呢,明明一个节点就可以传输多路流了,也许是为了写代码更方便,管理起来更方便,我这里只能想到这么多了,暂时不知道其他原因。

关于写一个MCU模型的的设想:

如何是用MCU的方式那么每个客户端应该只要一个webrtc节点就够了,而服务器端就还是只需要客户端 webrtc节点的总和,这样看起来应该清爽多了。  Kruento是支持合流的,例代码:

WebRtcEndpoint webrtc = new WebRtcEndpoint.Builder(pipeline).build();
Composite composite = new Composite.Builder(pipeline).build();
HubPort hubport = new HubPort.Builder(composite).build();
webrtc.connect(hubport, MediaType.AUDIO);

只需要用一个composite就可以把一个pipeline中所有的流合起来了,看起来也蛮简单的,但是这也得考虑服务器压力,毕竟合流不是一件简单的事。

现在看起来信令服务器还有h5客户端的代码都只考虑了SFU的场景。如果要用MCU的方式要改的逻辑还有挺多,比如现有代码都是创了很多webrtc节点的,然后那些webrtc连接管理都是现有系统的核心。 如果要使用MCU的方式看来得改动挺大,只能把nodejs信令服务器和h5 client都新启一份代码写了,网上看到类似例子也是把信令服务器的SFU和MCU形式分成了两份代码。

音频模块分析

音频的操作分为麦克分和聆听,也就是对应了视频模块的分享和观看。它和视频模块的处理非常相似,过程基本一致,也是通过webrtc节点实现音频流的交互,这里就不多做分析了,只分析一下它们的差异的地方吧。 首先音频这块多了个SIP的概念,好像麦克风功能用的是SIP格式的信令,如图所示:

如图所示。

但是webrtc节点之间的连接怎么办,他们所需要的端口不是固定的,也就是不能采用端口映射的方式,这时候客户端也在局域网,kurento服务器也在局域网中,如何才能建立 客户端和kurento服务器的webrtc节点连接呢?

这时候就必要需要STUN和TURN服务器了。

而Webrtc中是集成了ICE框架的,只要配置一下STUN和TURN服务器地址,底层就能自动通过STUN服务器打通它们之间的连接,当然如果两端都是对称型NAT的时候就打不通了,只能借助TURN服务器转发了。

在了解STUN和TURN的工作原理之前,先搞清NAT的概念。

当网络包穿越NAT设备时都会对源IP和端口的产生转换,而NAT设备保存了这种转换关系,以用来将外部进来的包的再转换成该局域网内对应设备的IP和PORT。

四种NAT模式:

RFC3489 中将 NAT 的实现分为四大类:

  1. Full Cone NAT (完全锥形 NAT)
  2. Restricted Cone NAT (限制锥形 NAT ,可以理解为 IP 限制,Port不限制)
  3. Port Restricted Cone NAT (端口限制锥形 NAT,IP+Port 限制)
  4. Symmetric NAT (对称 NAT)

当外部网络包到来时

第一种类型不较验本NAT设备是否往该网络包的源IP和端口发过数据的记录。

第二种类型:要确认本NAT设备之前往网络的包源IP发过数据才允许包进入。

第三种类型: 要碓本NAT设备之前往网络包的源IP+PORT发过数据才允许包进入。

第四种类型:和第3种很像,也是IP+port限制。当本局域网内设备给外部设置发送网络包时,它会根据 本地设备的IP+PORT 和目的IP+PORT 在NAT设备上转换成一个唯一的端口,也就是说只有 源IP+PORT 和目的IP+PORT 一样是在NAT设备上转换出的port才可能一致。 它在NAT端口转换时和前面三种是有区别的,前面是根据本地IP+PORT转换,不管目的IP。  这种类型是最安全的,在NAT打洞时也是最麻烦的,有可能会打不通。

打洞的本质就是使用目标主机的IP+PORT的包进来 ,在非Full Cone NAT模式的设备上 在所以你首先得发个包给目标IP+PORT,这样NAT设备上有目标IP+PORT的缓存,这样下次有目标IP+PORT的包过来时就不会阻拦了。

STUN和TURN服务器是如何打洞的呢:

STUN服务器主要有两个功能:

一.发现主机的在公网的IP和PORT

二.探索目标设备处于哪种NAT类型环境(NAT类型指的是最靠近公网那台NAT设备的类型,其他之前的是没影响的,这是为什么呢?试想当你知道了一台设备的公网IP和PORT,那么肯定在它之前所有的NAT节点都是打通了的(其实还是有个打通过程),所以只要这个最靠近公网的NAT设备能够让包进来,就能到达目标主机了。):

  • 判断是否为FULL CONE:

TUNN服务器在IP1:PORT1 收到主机的网络包后用 IP2发送包给主机看是否能得到回应。有则为FULL CONE,没有则为其他。

  • 判断是否为Restrict CONE: 再用 IP1:PORT2发给包给看主机看是否能得到回应,有则为Restrict Cone,没有则为其他。
  • 判断是否为Port Restrict CONE:

如果为 IP1:PORT1发送包给主机能收到回应这时候可能为 Port Restrcit CONE,也可能是Symetric NAT 。

  

  • 再让主机给IP2:PORT2发包,然后查看源PORT 和在PORT1 上的PORT是否一致?非一致则为Symetric NAT。

打洞原理:

所示说webrtc是P2P不需要服务器的模型这种说法不完全准确,因为在某些环境中是无法打洞的,所以实际上还是有C/S这种架构。

参考链接:

Kurento架构 - 简书

如何打造自己的WebRTC 服务器_webrtc server-CSDN博客

webrtc - How to implement MCU for Audio conference using Kurento Media Server? - Stack Overflow

GitHub - srigaurav1986/KurentoExample: This is an example of group communication(MCU) using Kurento Media Server 6.0

从通信到AI FreeSWITCH与WebRTC-CSDN博客

ICE协议下NAT穿越的实现(STUN&TURN) - 简书

P2P中NAT之间的打洞可能性 - 不急不徐,持之以恒。 - BlogJava

FreeSwitch Sip【转】 - 木瓜脑袋 - 博客园

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值