|导语 使用企业微信跨组织间会议门槛较高,要求外部客户或合作伙伴先建立在企业微信的线上组织才可入会,通过引入小程序入会能力,降低跨组织会议的门槛; 为解决微信用户发起会议,邀请企业微信、微信好友入会的场景,企业微信会议小程序也提供在微信侧接入和发起会议的能力,实现微信用户发起会议邀请企业成员加入会议的能力;
产品功能说明
企业微信的会议是接入了腾讯云提供的XCast SDK,腾讯会议后台提供了Rest APi接口用于创建会议、加入会议、获取会议信息等;
企业微信app发起的会议,虽然支持邀请微信好友加入会议,但是需要用户下载和安装企业微信,注册企业微信后才可以加入会议,加入会议的门槛较高;
虽然有利于企业微信引流拉新,但是对于用户而言是不太友好的,所以我们启动了微信小程序可以直接加入会议的方案;
功能表现: 企业微信app发起会议后通过邀请微信好友,好友会收到小程序卡片,打开小程序可以直接加入会议;或是微信用户发起会议,发起邀请企业微信或微信用户入会;
视频会议在小程序侧的UI表现:
视频会议支持美颜、会议附件、文档共享和屏幕共享等能力:
音频会议及会议管理:
支持企业微信发起的预约会议,邀请微信用户参加,在会议开始时会收到微信的服务通知,提醒进入会议;
会议技术流程介绍
首先要介绍一下TRTC
腾讯云提供了多人音视频通话方案和低延时互动直播方案两种服务,提供覆盖手机、桌面全平台的客户端 SDK 以及云端 API,终端用户还可以在微信、QQ、企业微信的小程序中使用 TRTC 服务,Web 网页也可轻松使用。
下图是TRTC官方的一个产品架构图:
腾讯会议与TRTC的关系
腾讯会议基础服务是基于TRTC的音视频媒体服务+进房权限保护(建立私有的房间集合,与TRTC的房间是不互通的),再结合腾讯会议自己建设的会控能力、会议模式下强悍的混音模块等,也包括腾讯会议自己扩展的一些功能;
TRTC进房权限保护机制
privateMapKey 是 TRTCParamEnc 中的一个可选字段,它的作用是让腾讯云检查用户是否拥有进入指定房间的权限。
privateMapKey是由服务器端计算提供,是在加入会议房间时腾讯会议的后台会返回web_user_signature,也就是获取RoomSIg时必要的privateMapKey字段;
小程序接入会议的整体技术方案
企业微信会议依赖模块示意图
TRTC官方提供的小程序demo,是使用微信小程序提供的live-pusher和live-player组件实现的,小程序加入腾讯会议私有域的房间,主体技术流程如下图所示:
会议小程序接入整体架构示意图:
接入腾讯会议的整体流程概述:
企业微信会议完整技术方案示意图:
会议终端接入方案以及注意事项
会议小程序独立会议控制
企业微信会议过程中的会议控制,是通过单独的逻辑房间长链接通道实现,会控逻辑相关的时序操作流程如下图所示:
企业微信的会议控制包括主持人控制人员上下台,或单独控制开启关闭视频、音频等能力;
企业微信用户在会议中发起文档共享,是企业微信提供的私有能力,发起者共享文档时,通过企业微信后台转换为共享的数据流,通过长链推送到其它用户,小程序接受共享的数据后实时更新,包括发起者共享中的翻页、画箭头等行为,同步在小程序中渲染;
音视频RestAPI接入层
音视频引擎介绍
来自腾讯会议的同学提供的引擎介绍
IO流是引擎很重要的一个抽象概念(有点类似响应式编程和TensorFlow的思想),各个数据处理模块(比如解包、FEC、音频解码、混音等)通过IO流串联成一条或者多条单向流动的树形链路,各个模块的处理按照顺序分布在各节点上,IO流的拓扑结构由CTopoNode组织构成。
引擎的基本处理流程,引擎有两条主要的流:
1. 接收流
接收流从网络收包以后再Dmx节点进行解包,然后根据uin分成若干个DecChannel,每个DecChannel都有单独的IO调用链,分别对应FEC解码(也包括ARQ)、QT解码、抗抖、音频解码。然后所有的DecChannel合并到一起,进入混音模块,最后输出到终端播放。
2. 发送流
发送流是从录音设备采集开始,然后数据流经过3A、编码、QT编码、FEC编码,最后送到网络发送。
我们遇到的问题及解决方案
我们在开发会议小程序的过程中遇到了各种各样的问题,下面记录分享一下我们遇到的问题以及解决思路;
如果也有遇到类似的问题的同学,可以企业微信联系一起交流经验;
1、文档共享/屏幕共享相关的问题
文档共享、屏幕共享时live-pusher临时断开导致数据流无法渲染;
问题:
腾讯会议提供的音视频服务都依赖于live-pusher建立的通道,如果在文档共享或屏幕共享时view的切换导致live-pusher组件有临时中断的情况,会导致会议音视频中断,只有再建立成功后才可以恢复;
解决办法:
避免view的重新渲染,通过class控制view节点的布局调整,保持live-pusher一直在链接状态;
文档共享的技术实现
简企业微信app的会议主持人可以发起文档共享时,通过标注图标绘制在文档上,小程序会接受文档共享的文档内容以及指令信息,指令信息为箭头开始的坐标x/y,以及结束坐标的x/y;
小程序提供一个文档共享查看的窗口,同时调整live-pusher和live-player的表现,通过长链接接受指令的信息后,在文档内容的上层创建一个同样大小的canvas用于绘制箭头,指令的实时变化会通过长链通知,实现演示中箭头指向的问题;
目前遇到一个比较严重的bug是canvas在缩放一定的比例后,会有一个超出绘制范围的bug,导致箭头的绘制不会被渲染(老版本canvas api存在的问题);
屏幕共享的技术实现流程
会议中的屏幕共享是使用一个辅助视频流上行推送,其它侧用户会通过live-pusher的onPush事件进行推送的,在推送的用户列表信息中会出现一个userlist_aux用于标识屏幕共享的视频流信息;
小程序在接收到有屏幕共享视频流的情况下,会切换到屏幕共享的状态下,大屏显示屏幕共享的数据,同时将共享人的视频画面使用live-player中正常播放;
屏幕共享的视频流使用live-player播放;
2、音视频控制相关的问题
音视频上下台时推流中断出现画面闪烁的问题
音视频房间与逻辑房间userID不一致的问题
音量控制动画
视频画面方面各个端采集方向不同(移动端、小程序、桌面端的差异性)
3、其它一些问题
腾讯会议房间鉴权的问题
前期遇到最多的问题是来自于此,首先这里存在2个概念,一个是逻辑房间,一个是音视频房间,所需的鉴权信息不同,另外腾讯会议测试环境与正式环境不互通,导致这里出问题会比较多;
加入房间时用户身份信息与签名时使用的字段差异,依赖腾讯会议后台提供必要的字段
因音视频媒体房间所需要的签名是腾讯会议center处理的,依赖他们转换后的UserID以及SDKAppID去生成userSig,这里同样存在测试环境与正式环境不互通的问题;
测试环境不稳定的情况
涉及原生组件同层渲染相关的问题
一、 小程序原生组件存在的问题
小程序的原生组件的层级是最高的,所以页面中的其他组件无论设置 z-index 为多少,都无法盖在原生组件上。同层渲染是为了解决小程序中普通元素之间无法覆盖native的原生组件,解决特定组件下UI表现的各种异常问题;
会议小程序中使用的native-component组件有以下这些(查看更多原生组件,可以参考官方文档): - live-player - live-pusher - input(仅在focus时表现为原生组件) - canvas
官方介绍的原生组件的使用限制:
由于原生组件脱离在 WebView 渲染流程外,因此在使用时有以下限制:
二、Cover-View适配原生组件的方案
存在严重缺陷,但在不支持同层渲染的原生组件需要使用
cover-view 与 cover-image
为了解决原生组件层级最高的限制。小程序专门提供了 cover-view 和 cover-image 组件,可以覆盖在部分原生组件上面。
这两个组件也是原生组件,但是使用限制与其他原生组件有所不同。为了解决依赖button按钮的事件行为,cover-view中支持嵌套button的view类型;
使用Cover-View覆盖live-pusher和live-player的view元素
严重缺陷:
cover-view是不支持滚动列表响应滚动事件和行为的,导致有涉及滚动页面的列表会有问题;
三、同层渲染遇到的问题及解决方法
如果发现同层渲染有无法解决的问题,可以强制关闭同层渲染
//app.json window 中配置
{ "renderingMode": "seperated" }
同层渲染是为了解决原生组件的层级问题,在支持同层渲染后,原生组件与其它组件可以随意叠加,有关层级的限制将不再存在。
但需要注意的是,组件内部仍由原生渲染,样式一般还是对原生组件内部无效。当前 video, map, live-player, live-pusher, canvas(2d) 组件已支持同层渲染。
原生组件相对层级,为了可以调整原生组件之间的相对层级位置,支持在样式中声明 z-index 来指定原生组件的层级。该 z-index 仅调整原生组件之间的层级顺序,其层级仍高于其他非原生组件。
1、 组件live-player和live-pusher不支持点击事件,支持全屏操作的切换;
2、 同层渲染情况下view元素跳动的问题
问题表现:
覆盖在原生组件上的普通view元素,在列表滚动时位置会跟随变化,偶尔会跳出live-player的视图之外,无法跟随容器的范围变化;
解决办法:
在普通的view的根节点下增加will-change和transform,告知webview该元素会有哪些变化的方法,这里也就是会有transform缩放的变化,强制触发webview的重新渲染;
will-change: transform;
transform: scale(1);
3、 视频流出现黑屏
问题表现:
视频流地址有推送的情况下,播放中并没有视图流信息导致播放窗口黑屏;
解决方案:
在live-player的change事件监听中判断当前视频流的帧率是否正常,如果不正常则使用头像显示,覆盖黑屏的表现;
4、 屏幕共享视频流中断续传
问题表现:
企业微信app用户发起屏幕共享过程中,如果用户未结束共享,但是视频流推送中断了,导致画面暂停或黑屏;
解决方案:
在感知用户结束屏蔽共享行为时,我们在逻辑房间补充一个通知逻辑,告知小程序主动结束屏幕共享的状态; 如果是用户还在共享,腾讯会议音视频房间推送的视频流中断了,则为用户提示重新进出房间恢复画面(同时反馈给腾讯会议修复此bug);
5、 live-player可滚动的问题(遗留)
问题表现:
当用户点击某个用户头像全屏后,再回列表,有一定概率出现小窗口可以滚动的情况;
解决方案:
初步确定的方案是在全屏视图下把普通view节点与live-player进行分离,以同层级并列关系存在,因调整较大,后续做为技术优化完善;