SFU在WebRTC中的最佳实践
前置知识
- 构建rtc云服务需要具备的要素
高并发:
需要同时支持海量并发用户和海量的房间创建与维护高性能:
- 更高的单机性能:可以抗拒更多的流次攻击
- 更高的连通性:保证通信的稳定性
- 很强的抗弱网性
高可用性:
单机单节点出现故障时不影响系统的可用性弹性伸缩:
- 可以方便的进行扩容操作
- 扩容时尽可能减少相应的配置
- 上述两点的目的:可以使得系统迅速进行扩容
Mesh结构在WebRTC中的应用
Mesh结构的定义:完全使用P2P方式的网络拓扑结构称为Mesh结构,WebRTC中最常见的就是P2P连接进行数据交换,不论是单人直播还是多人连麦,区别只是1VX的区别,此外还有P2P无法打通的情况,就需要通过TURN Server来中转数据给对方;这个TURN Server是指支持TURN协议的服务器,其扮演者一种网络中继的角色,支持将一个client的数据包透明的转发到多个其他的client客户端;
- WebRTC Mesh网络拓扑结构的优劣
- 优点
- 逻辑简单,容易实现
- 服务端比较轻量,TURN服务器比较简单,一定比例的P2P成功率可极大的减轻服务端的压力
- 缺点:
- 每新增一个客户端,所有客户端都需要新增一路数据上行,客户端上行带宽占用大, → 通话人数越多,效果越差
- 无法在服务器端对视频进行额外的处理,如录制、实时转码、智能分析、多路合流、转推直播等
- 优点
SFU浅析
SFU(Selective Forwarding Unit)是一种路由和转发WebRTC客户端音视频流的额服务端程序;其SFU服务器最核心的功能就是与每一个WebRTC Peer客户端连接起来,分别接受来自他们的音视频数据,并实现one-to-more的能力;
该模型下,无论参与的客户端有多少,每个客户端只需要连接一个SFU服务器即上行一路数据即可,极大减少了多人视频通话场景下Mesh模型给客户端带来的
上行宽带
压力;
- SFU服务器最核心的特点是:
- 把自己「伪装」成一个WebRTC的Peer客户端,与其他WebRTC的客户端进行互联,可以简单理解成
P2S(Peer to Server)
- 具备了one-to-many的能力,即将一个的client端的数据转发到其他多个Client端
- 把自己「伪装」成一个WebRTC的Peer客户端,与其他WebRTC的客户端进行互联,可以简单理解成
- SFU服务器与TURN服务器区别
- TURN服务器仅仅是为WebRTC客户端提供的一种辅助的数据转发通道,是在P2P不通的时候进行透明的数据转发
- SFU是懂业务的,和WebRTC客户端是平等的关系,甚至接管了WebRTC客户端的数据转发的申请和控制
- 常见的SFU服务器
- Licode,Janus,Jitsi,mediasoup,Medooze
- Janus:
- 不支持单端口
- 信令和媒体耦合在一起
- 信令一般基于tcp协议,媒体一般基于UDP协议,当耦合在一起后就需要客户端将tcp的信令和UDP的流媒体数据发送到服务端的同一台机器上,当发送到不同服务端的机器上后是没法进行tcp信令和UDP流媒体数据的初始化和后续逻辑处理
- SRS4:
- 只支持WebRTC拉流
- mediasoup:
- NodeJS Model
- 不支持单端口
- 不支持单端口的原因
- SFU在启动时会配置一个可用的UDP的端口范围,用于客户端的数据传输;服务端在接受到客户端的请求后,会从配置的端口范围中为客户端分配一个从未被使用的端口,通过SDP将服务端的端口传给客户端,客户端在收到SDP端口并进行解析,然后就可以向服务端发送或接收数据了
- 存在的问题:
- 服务端需要同时暴露过多的端口,对于服务端自身、网络安全相关、可运维性也会有较大负担
- 对于客户端来说,会有分配的端口在限制范围之外,导致整个的连通失败
- Janus:
- Licode,Janus,Jitsi,mediasoup,Medooze
MCU浅析
SFU主要解决了客户端的数据上行压力问题,但是数据下行还是存在多路流的问题,随着通话人数越多,下行的宽带压力就越来越大;因此就产生了MCU的结构模型用来在服务器端合流后再下发即可解决上述的问题;
- 特点
- MCU服务器将各个客户端的上行的视频流合成一路,然后再转发给其他客户端,从而解决了SFU中的客户端下行的带宽压力
- 因为SFU服务器合流需要转码操作,因此对服务端的压力就比较大,且下发给客户端的流是固定的合流画面,灵活性不是很好
- 常规逻辑点 合流服务、画面合成、混音、转多高清度、直播推流、录制;
- 画面合成:
- 依照布局将多路画面合成单路
- 协议转化
- 将合成画面通过RTMP协议推送到直播系统的CDN上
- 多高清度
- 单路主播画面转高清度,回推给连麦节点
- 在下行链路中,一般通过JitterBuffer实现抗抖动缓存,且对丢包进行检测,请求重传,保证输出包有序无花屏的现象;同时在下行从MCU拉流转码后,需要依据下行能力动态切换
- 画面合成:
- SFU与MCU对比
- 纯的Mesh方案(即P2P方案)无法适应多人视频通话,也无法实现服务端的各种视频的处理,因此一般都排除在商业应用之外
- SFU的服务器压力更小(纯转发,无转码合流)
- 灵活性更好(可选择性开关任意一路数据的上下行等)
信令和传输通道浅析
信令和传输通道是分开的,信令没有标准化实现方案,可以使用任何自定义的方案进行实现,数据并不会走这条信令链路,而是走单独的UDP端口;并且UDP没有链接的概念,客户端只知道服务器的UDP端口,但不能提前预判传输通道是否真的OK(NAT网关类型的限制会导致并不是所有的UDP传输都可以通过),需要借助一些框架预判UDP通道的可用性(即ICE协议)
- 实现SFU信令和传输通道的步骤
- 实现HTTP Web Server服务(或SIP或基于tcp自定义协议),用于提供
信令支持
(如推流命令、拉流命令等) - 通过libnice库或者自己实现的额方式,实现ICE协议,用于提供
数据通道
的检测赫尔建联 - 实现UDP数据监听和发送,用于接收客户端的数据,然后转发其他客户端的数据
- 实现HTTP Web Server服务(或SIP或基于tcp自定义协议),用于提供
- WebRTC客户端和SFU服务器之间需要协商的点
- ICE建联:交换ICE信息(用户相关信息、UDP端口、ID地址等)
- 发布流/取消发布流:客户端通知服务器准备好接收的数据
- 订阅流/取消订阅流:客户端通知服务器准备好转发数据
- 总结:SFU服务器通过任意一种方式(HTTP/TCP等),提供ICE Connection、publish、Subscribe信令即可
- SFU在信令背后需要实现的逻辑
- ICE Connection:添加一路UDP通道
- publish:添加一个逻辑上的数据Producer,通过UDP通道接收客户端的数据,通知逻辑上的Consumer
- Subscribe:添加一个逻辑上的数据Consumer,收到Producer通知后,通过UDP通道send到客户端;
- 实现
one-to-many
的原理 是SFU最核心的功能,此外如RTMP直播流服务器也需要实现该功能,从而将客户端推上来的数据实时转发给其他多个拉流的客户端,此功能适用于所有数据实时产生实时消费的场景需求中;- 其最重要的一点就是需要将数据的生产者(Publish)和数据的消费者(Subscriber)关联起来;主要是利用了音视频数据包中的SSRC(同步源标识)
- WebRTC传输的音视频数据,实际上是封装在RTP包里,RTP包头有个很重要的字段,叫做SSRC(同步源标识),就是这路流的唯一标识;也是数据的生产者和消费者互联的标准,当SFU接收到Publisher发送上来的数据后,轮训一下所有的Subscribers,如果SSRC匹配成功,就将数据转发给这个客户端
- 其最重要的一点就是需要将数据的生产者(Publish)和数据的消费者(Subscriber)关联起来;主要是利用了音视频数据包中的SSRC(同步源标识)
相关实践
RTSP流在Web端的最佳实践
原理
RTSP(Real Time Streaming Protocol)实时流传输协议,是TCP/IP协议体系中的一个基于文本的多媒体播放控制协议,属于应用层协议,该协议定义了一对多应用程序如何高效的通过IP网络传输多媒体数据。RTSP在体系结构上位于RTP和RTCP之上,其使用TCP或UDP完成数据传输,此外RTSP可以是双向的,即客户端和服务端都可以发出请求 在Web端播放RTSP流方案有很多,但最终原理都是一样的,只是依赖的相关包和库有所区别而已;
RTSP属于应用层协议,提供了一个可以拓展的框架,使得流媒体的受控和点播变得可能,其主要用来控制具有实时特性的额数据的发送,但其本身并不用于传输流媒体,而必须依赖下层传输协议(如RTP/RTCP)所提供的服务来完成流媒体数据的传输。RTSP负责定义具体的控制信息、操作方法、状态码以及描述与RTP之间的交互操作;
在现有的HTML技术中是无法直接使用现有的Web技术进行播放RTSP直播流数据的,需要进行特定方法的实现进行转化播放
方案
总体流程原理: RTSP流 → Web端可以应用的流(如WebSocket或WebRTC) → Web端媒体播放器
细分流程
- RTSP流 → WebSocket/WebRTC
- WebSocket/WebRTC → Web-video
具体方案
- 基于 ffmpeg 的 Node 后端推流方案 + 基于 jspmeg / flvjs 的前端视频展示
- 基于 WebRTC 的推流方案
RTSP的URL格式
- rtsp://host[:port]/[abs_path]/content_name
- host:有效的域名或IP地址
- post:端口号,缺省为554
方案一
后端实现
后端可以通过nodejs配合一些依赖库来实现将RTSP流转化为
WebSocket/WebRTC
的Web端可以接受的流格式,常用的依赖库有node-rtsp-stream、node-media-server、rtsp-streaming-server和fluent-ffmpeg,本方案采用第一个库;前置条件:需要在系统中安装一个用于录制、转换和流式传输音频和视频的完整的跨平台解决方案 →ffmpeg库,原因是RTSP流转WebSocket就是通过底层调用FFMPEG来实现的;具体安装方案如ffmpeg安装及使用(macbook)👍🏻👍🏻
方案二 → RTMP方案
方案描述:
ffmpeg将RTSP视频流转为RTMP视频流,通过nginx代理,Web接入RTMP协议进行播放,但是需要Flash支持
后端技术:
ffmpeg + nginx + nginx-rtmp-module,利用docker搭建nginx rtmp流媒体服务器,将摄像头的RTSP视频流推送到流媒体服务器,在Web端用video.js播放
方案三 → HLS方案
其基本原理就是服务端把文件或媒体流按照不同的马路切分成一个个小片段进行传输,客户端在播放码流时,可以根据自身的额宽带和性能限制,在同一视频内容的不同码率的备用源中,选择合适码率的码流进行下载播放。当然客户端首先需要下载描述不同码率元数据的M3U8索引文件;
方案描述
ffmpeg 将rtsp视频流切片转存为多个视频缓存起来,并通过nginx代理出去,web接入hls协议(m3u8)播放
后端技术:
ffmpeg + nginx + nginx-rtmp-module
方案四 → WebSocket方案
主要流程: 摄像头 → 通过RTSP → ffmpeg → 编码为webm → NodeJS → 客户端通过HTML5视频进行播放 后端技术:
服务端使用WebSocket接收RTSP,然后推送到客户端
Web端:
Web直接转换成MP4,所以直接使用video标签就可以实现播放
推荐文献
RTC-实时音视频通信技术介绍与应用👍🏻👍🏻 如何使用开源SFU构建RTC云服务
web端实现rtsp实时推流视频播放可行性方案
Web下播放rtsp视频流的方案