背景
在之前的WebRTC实时音视频通话之语音通话设计与实践中介绍了58 TEG部门基于 WebRTC 的实时音视频通话解决方案。
考虑到腾讯微信的小程序平台提供了音视频通话与直播的支持,如果能打通基于 WebRTC 的实时音视频通话与微信小程序,就能够极大地扩展音视频直播的能力范围,为业务线的产品和服务提供更多更好的选择。
本文主要介绍打通 WebRTC 端和微信小程序端的音视频互通方案,实现在尽量不需要改动 WebRTC 端代码的情况下,添加对主叫和被叫微信小程序端的支持。
基于 WebRTC 的实时音视频方案
58 已搭建了成熟的基于 WebRTC 的实时音视频方案,能够有效地支持多端(iOS/Android/Web)之间的音视频会话。其通过后端的 Room Server 服务来管理会话;某端需要发起音视频会话,首先需要到 Room Server 中注册一个房间,之后基于房间来进行信令的交互;主叫端和被叫端的音视频数据传输通过 PeerConnection 进行。
WebRTC 端的媒体流方案是采用标准的 RTP[1] 和 RTCP[2] 协议。
微信小程序的音视频支持
微信的小程序对外开放了音视频直播[3] 的能力,使用方可以通过 live-pusher 标签实现基于 RTMP[4] 的音视频推流(录制),live-player 标签实现基于 RTMP 的音视频拉流(播放)。
- 微信 App iOS 最低版本要求:6.5.21
- 微信 App Android 最低版本要求:6.5.19
- 小程序基础库最低版本要求:1.7.0
微信小程序的音视频方案是基于 RMTP 流媒体协议的。
互通方案
总体架构
方案的总体架构如下:
- WebRTC Gateway 作为一个特殊的 WebRTC 端与指定的另一个 WebRTC 端通过 Room Server 交换信令并建立会话
- 会话建立后,WebRTC 端与 WebRTC Gateway 直接(P2P)或间接(TURN)交换音视频流
- WebRTC Gateway 将 WebRTC 端之音视频流经 Streaming Server 转发至微信小程序端;微信小程序音视频输入流经 Streaming Server 转发至WebRtc 端
其中,WebRTC Gateway 使用成熟的服务来搭建,主要作为微信小程序端的 WebRTC 代理辅助微信小程序端参与 WebRTC 的会话,主要进行信令的沟通、Offer/Answer 的协商和媒体流数据的转发;Streaming Server 包括 RTMP 中继模块和转码模块,主要提供 RTP&RTCP 媒体流和 RTMP 媒体流数据的转换和中继;在已有的 Room Server 上扩展,添加了与接入微信小程序端相关的信令处理逻辑。
会话建立
需要支持 WebRTC 端与微信小程序端的音视频流的互通,首先需要添加对其建立会话的支持;WebRTC 端与微信小程序端的会话建立,具体来说是指:
- WebRTC 音视频(主叫) 与 微信小程序音视频(被叫)
- WebRTC 音视频(被叫) 与 微信小程序音视频(主叫)
- WebRTC 音视频(主叫) 与 WebRTC音视频(被叫)
- 微信小程序音视频(主叫) 与 微信小程序音视频(被叫)
其中,case 3 和 case 4 不会涉及到 WebRTC 端与微信小程序端的交互:case 3 由 WebRTC 支持;case 4 由 RTMP 中继方案可解决。
基于 WebRTC 音视频和微信小程序音视频的互通方案,需要能支持 case 1 和 case 2。由于 WebRTC 端需要信令交互,所以需要分别讨论这两种情况。
WebRTC 音视频(主叫) 与 微信小程序音视频(被叫)
在此case中,WebRTC Gateway 以被叫的身份与 WebRTC 端建立标准 WebRTC 会话。
- WebRTC 端首先初始化房间
- WebRTC 端加入房间
- 微信小程序端加入房间:Room Server 中添加了新的信令类型支持微信小程序以被叫的方式接入;此信令的处理过程中,回调 WebRTC Gateway 和 Streaming Server 进行资源初始化准备
- WebRTC 端发送 Offer 至 Room Server
- Room Server 接收到 Offer 之后,将该 Offer 信息转发至 WebRTC Gateway;WebRTC Gateway 需要响应该 Offer,如果正常的话应该返回一个Answer 至 Room Server;Room Server 转发 Answer 至 WebRTC 端
- 进入 ICE 协商和连接建立流程
此case下,WebRTC Gateway 作为微信小程序端的代理接入标准 WebRTC 栈,复用已有的 WebRTC 协议栈基础设施(STUN/TURN/ICE/SDP),以减少对原 WebRTC 栈的侵入影响。
WebRTC 音视频(被叫) 与 微信小程序音视频(主叫)
在此case中,WebRTC Gateway 需要以主叫的身份与 WebRTC 端建立标准 WebRTC 会话。
- 微信小程序端首先初始化房间
- 微信小程序端加入房间:Room Server 中添加了新的信令类型支持微信小程序以主叫的方式接入;此信令的处理过程中,回调 WebRTC Gateway 和 Streaming Server 进行资源初始化准备
- WebRTC 端加入房间
- WebRTC Gateway 生成固定 Offer,发送至 Room Server
- Room Server 接收到 Offer 之后,将该 Offer 信息转发至 WebRTC 端;WebRTC 端需要响应该 Offer,如果正常的话应该返回一个Answer 至 Room Server;Room Server 转发 Answer 至 WebRTC Gateway
- 进入 ICE 协商和连接建立流程
此case下,WebRTC Gateway 作为微信小程序端的代理接入标准 WebRTC 栈,复用已有的 WebRTC 协议栈基础设施(STUN/TURN/ICE/SDP),以减少对原 WebRTC 栈的侵入影响。
此 case 与前一个 case 的区别在于 SDP 信息(Offer/Answer)的生成和处理。微信小程序端主叫时,由于微信小程序端不能正常参与到 WebRTC 栈的协议协商过程中来,需要在生成Offer时做一些针对性的优化和处理。
媒体流交换
由于 WebRTC 端和微信小程序端分别是用不同的媒体协议:WebRTC 端使用 RTP&RTCP;微信小程序端使用 RTMP,因此采用了 WebRTC Gateway 转发 RTP 流和 Streaming Server 居中转换的方案。
RTP 转发
RTP 转发即是将 WebRTC Gateway 作为微信小程序端的 WebRTC 代理,在通话过程中,将 WebRTC 端上传的的 RTP 媒体流转发至 Streaming Server,同时将微信小程序端上传的经 Streaming Server 转换过的 RTP 流转发至 WebRTC 端。
具体实现基于 WebRTC Gateway 的扩展机制:为每一通会话预分配两组音视频端口(A & B),并:
- 收到 WebRTC 端的媒体数据后转发至音视频端口 A
- 收到音视频端口 B 的媒体数据后转发至 WebRTC 端
其中,音视频端口 A 转发的是 WebRTC 端发向微信小程序端的媒体流,由 Streaming Server 监听;音视频端口 B 收到的是微信小程序端发向 WebRTC 端的媒体流,来源是 Streaming Server,由 WebRTC Gateway 监听。
转码模块
Streaming Server 的转码模块将 WebRTC Gateway 转发的 RTP&RTCP 流转换为 RTMP 流输出至微信小程序端,也将微信小程序端上传的 RTMP 流转为 RTP&RTCP 流输出至 WebRTC Gateway;最初的实现使用成熟的音视频编解码方案搭建,可以很好地支持 RTP&RTCP 与 RTMP 的双向转换。
具体来说,即:
- 将 RTP&RTCP 的媒体封包格式转为RTMP的封包格式,反之亦然
- 将 RTP&RTCP 中的视频(H264/vp8/vp9)转为 RTMP 支持的H264,反之亦然
- 将 RTP&RTCP 中的音频(opus)转为 RTMP 支持的 AAC,反之亦然
中转流程优化
在实际使用过程中,发现 Streaming Server 的转码模块可以进行优化:WebRTC Gateway 转发的 RTP&RTCP 流中的视频编码格式可以为 H264/VP8/VP9 等,具体格式由协商决定;微信小程序端支持的 RTMP 中可用的视频流编码格式为 H264;如果能够限制 WebRTC 端使用的视频编码格式为 H264,可以优化为只解包不解码,减少视频编解码耗时。
基于以上分析,本文对中转流程进行了重构,限制会话使用 H264 编码传输视频数据,并使用自研的 H264 裸流编解包代码替换原有的视频编解码逻辑进行音视频流中转。实现微信小程序端通话时延从之前的 1-5s 优化到 500ms-1s,效果明显。
实现细节如下:
- 修改 WebRTC Gateway 的 SDP 响应机制,在生成 Offer 或者响应 Answer 时只返回 H264 的视频协商信息。由于 58 的 WebRTC 端保证肯定支持 H264,所以不会导致协商失败
- 解析带 H264 数据的 RTP 报文之后直接包装成 RTMP 报文发出,不进行编解码操作和视频帧操作
- 音频数据仍然进行编解码。由于音频数据数据包小,不会对通话时延造成明显影响
RTMP 首帧优化
微信小程序端与 Streaming Server 之间通过 RTMP 传输音视频数据,在通话开始时可能会有多于 2s 的黑屏现象。这是由于微信小程序端在显示视频流时需要根据 H264 流中的 IDR帧[5]的数据进行绘制,如果微信小程序端在建立连接时刻附近没有可用的 IDR帧数据,播放器会进行等待,出现黑屏。
基于以上分析,本文优化了 Streaming Server 的 RTMP 中继模块中的逻辑,在推流就绪而拉流未就绪时会开始缓存数据帧,缓存的数据帧包含最新一帧 IDR帧及其后的所有数据帧。在拉流就绪之前,新的非 IDR帧持续加入缓冲队列,新的 IDR帧重建缓重队列;在拉流就绪之后,使用已有逻辑,拉流消费推流生产的数据流。实现微信小程序端通话建立时延从之前的 2-3s 优化到 1-1.5s,效果明显。
会话保持
在会话的过程中,由于参与者多,数据链路比较复杂,本文采取了以下策略实现错误恢复和通话保持。
- WebRTC Gateway 作为 WebRTC 代理人,需要在整通会话中保持可用;如果不可用,Room Server 会使当前会话失败,并将该服务器从可用的列表中删去。可用性的检测目前是在 Room Server 中使用 WebSocket 保持心跳实现的
- Streaming Server 作为中转服务维持着双向的媒体流,需要在整通会话中保持可用;如果不可用,Room Server 会使当前会话失败,并将该服务器从可用的列表中删去。可用性的检测是在 Room Server 中通过 58 RPC 周期性轮循实现的
- Streaming Server 在单通会话中会保持双向的媒体流,其任一媒体流失败的概率都较高,因此实现了失败重试逻辑;由于媒体流是有状态的,在多服务器部署环境下,重试任务时能根据服务器进行隔离
出现错误或不可用的情况下,当前的通话会受到影响,在几秒钟内会被关闭;后续的新通话不会受到影响。
总结
本文主要介绍了在保持已有 WebRTC 的音视频通话系统的基础上实现的基于 WebRTC Gateway 的 WebRTC 端和微信小程序端的互通方案,分析了总体的架构方案和各个组件的实现逻辑细节。目前该方案已经成功落地,能提供稳定的音视频通话能力;后续将继续在整体方案的基础之上,在 WebRTC Gateway 和 Streaming Server 进行持续优化,最终形成成熟可推广的综合方案。
参考:
[1]: https://en.wikipedia.org/wiki/Real-time_Transport_Protocol
[2]: https://en.wikipedia.org/wiki/RTP_Control_Protocol
[3]: https://cloud.tencent.com/document/product/454/12517
[4]: https://en.wikipedia.org/wiki/Real-Time_Messaging_Protocol
[5]: https://en.wikipedia.org/wiki/Network_Abstraction_Layer#Coded_Video_Sequences
欢迎大家关注“58架构师”微信公众号,定期分享云计算、AI、区块链、大数据、搜索、推荐、存储、中间件、移动、前端、运维等方面的前沿技术和实践经验。