技术分享| 如何做一款容纳百人的视频会议?

在视频通话或直播场景中,如果多个用户同时发流,由于设备性能消耗和网络流量的上升,可能带来比较大的体验下降,本文就场景层面调用 API 进行讲解,采用 iOS 接口作为示例,其他端在文档中心自行查找。

懒人法

在多人音视频通信过程中,设备的网络流量会出现间接性的波动(突发流量、网络信号问题),影响通话质量,开发者需要对当前通话的质量指标做统计分析,经过分析结果,自行调用API结果进行问题解决,但业务频繁的进行切换或者API调用不当会导致通话异常等现象。anyRTC 从实际出发,根据内部多个指标对订阅用户的音视频质量进行分析,开发了自动音视频流回退功能。用户只需调用方法,监听状态回调,在视频的窗口中给予友好提醒即可。

前提

在使用音视频流回退功能之前,先调用 enableDualStreamMode 方法开启双流模式。下方的每种方式都需提前开启双流模式(小窗口拉取小流,大窗口拉取大流,可节省流量)

音视频流回退方法

- (int)setRemoteSubscribeFallbackOption:(ARStreamFallbackOptions)option;

在加入频道之后,调用该方法即可。ARStreamFallbackOptions有三个选项:

  • ARStreamFallbackOptionDisabled:不使用音视频流回退功能
  • ARStreamFallbackOptionVideoStreamLow:在下行网络条件较差的情况下,SDK 将接收视频小流(低分辨率、低码率视频流)。
  • ARStreamFallbackOptionAudioOnly:下行网络较弱时,先尝试只接收视频小流(低分辨率、低码率视频流),如果网络环境无法显示视频,则再回退到只接收音频流

音视频流回退回调

-(void)rtcEngine:(ARtcEngineKit * _Nonnull)engine didRemoteSubscribeFallbackToAudioOnly:(BOOL)isFallbackOrRecover byUid:(NSString *_Nonnull)uid;

在调用远端音视频流回退功能后,只需要监听对应的回调,通过回调的信息对通话的窗口做页面提示。

该回调信息确保跟对方的音视频开关状态做下区分,音视频开关状态是对方开启或关闭音视频流发送,该回调是本地是否接受该用户的视频与否。

技术分享| 如何做一款容纳百人的视频会议?

会议模式

进入会议前配置

进入会议前,根据自身的喜好进入会议,该配置项有效的保护了用户隐私,如果同时取消选中摄像头和麦克风,会议中的流量也会减小很多。

技术分享| 如何做一款容纳百人的视频会议?

调用方法

方法 说明 调用注意事项
- (int)muteLocalAudioStream:(BOOL)mute; 开关本地音频发送 在频道中不会发送自己的音频数据
- (int)muteLocalVideoStream:(BOOL)mute; 开关本地视频发送 在频道中不会发送自己的视频数据
- (int)enableDualStreamMode:(BOOL)enabled; 开关视频双流模式 多人通话建议使用双流模式
- (int)setRemoteVideoStream:(NSString *_Nonnull)uid type:(ARVideoStreamType)streamType; 设置订阅的视频流类型 视频流类型设定,大屏的时候订阅大流,小屏显示订阅小屏
- (int)setRemoteDefaultVideoStreamType:(ARVideoStreamType)streamType; 设置默认订阅的视频流类型 进会前,设定订阅所有流的类型,在页面切换的时候配合设置订阅流类型做动态切换

回调方法

方法 说明 调用注意事项
- (void)rtcEngine:(ARtcEngineKit *_Nonnull)engine remoteVideoStateChangedOfUid:(NSString *_Nonnull)uid state:(ARVideoRemoteState)state reason:(ARVideoRemoteStateReason)reason elapsed:(NSInteger)elapsed; 远端视频状态发生改变回调 监听对方的视频状态,页面做对应的提示
- (void)rtcEngine:(ARtcEngineKit * _Nonnull)engine remoteAudioStateChangedOfUid:(NSString *_Nonnull)uid state:(ARAudioRemoteState)state reason:(ARAudioRemoteStateReason)reason elapsed:(NSInteger)elapsed; 远端音频流状态发生改变回调 监听对方的音频状态,页面做对应的提示

在进入频道前或者进入频道后都可以进行方法调用,调用该方法后,本地的采集还在继续,只是不对外传输音视频数据,当打开发送的时候,速度比较快,建议使用该方法进行音视频开关操作。

由于视频采集还在继续,画面可以预览,可以在画面上方做一层遮罩,掩盖住视频画面,或者做一个状态图来标识本地的视频传输状态。

语音激励模式+锁定画面

为了节省带宽,语音激励模式是最好的模式,只显示一路视频,即当前说话声音最大的用户,其他人只接收音频。在实际开发过程中,开发者也可以手动接管画面,当该用户在语音激励时,大画面显示该用户视频图像,在页面中加入按钮“锁定”,此时只看该用户画面,满足小带宽多人通信场景。

调用方法

方法 说明 调用注意事项
- (int)enableAudioVolumeIndication:(NSInteger)interval smooth:(NSInteger)smooth report_vad:(BOOL)report_vad; 启用说话者音量提示 启用后监听主播的音量大小回到
- (int)muteRemoteVideoStream:(NSString *_Nonnull)uid mute:(BOOL)mute; 停止/恢复接收指定视频流 当在接收的视频流不是当前激励的用户的时候,先暂停接收,当检测到是激励用户的时候,调用方法进行接收

回调方法

除了监听说话者声音回调,同时也要监听对方视频的发布状态,本地调用接收该用户视频的时候,需要先判断该用户是否发布了视频,如果没有发布则不进行接收方法设定。

方法 说明 调用注意事项
- (void)rtcEngine:(ARtcEngineKit * _Nonnull)engine reportAudioVolumeIndicationOfSpeakers:(NSArray<ARtcAudioVolumeInfo *> * _Nonnull)speakers totalVolume:(NSInteger)totalVolume; 提示频道内谁正在说话、说话者音量及本地用户是否在说话的回调 请先启用说话者音量提示方法
- (void)rtcEngine:(ARtcEngineKit * _Nonnull)engine didVideoSubscribeStateChange:(NSString *_Nonnull)channel withUid:(NSString * _Nonnull)uid oldState:(ARStreamSubscribeState)oldState newState:(ARStreamSubscribeState)newState elapseSinceLastState:(NSInteger)elapseSinceLastState; 视频订阅状态发生改变回调 当订阅该用户的视频流的时候,可以根据当前的订阅状态做页面切换显示

难点

  • 当使用语音激励时,画面切换时要保证已经接收了该用户的画面后在进行切换,避免切换后出现黑屏的现象。
  • 语音激励不要频繁换视图,要有一定的缓冲时间,避免切换画面频繁导致视觉疲劳。

分页显示-画廊模式

当通话人数过多的时候,对视频数据分页显示也是一种优化方式,传统的每页显示4路画面,人数多进行分页显示。

整体流程

加入房间前设置:(joinChannel前)

1、enableDualStreamMode 开启双流

2、setRemoteDefaultVideoStreamType为小流模式

3、muteLocalAudioStreammuteLocalVideoStream可选,根据进会前的设置而定

5、调用私有方法:用户质量上报

NSDictionary *quality = [[NSDictionary alloc] initWithObjectsAndKeys:@"UserQuality", @"Cmd",[NSNumber numberWithBool:YES], @"Enable",nil];
[_rtcKit setParameters:[ARCommon returnJSONStringWithDictionary:quality]];
加入房间后的操作

1、监听didJoinedOfUid,有回调来向本地数组中插入该用户,并设置前3个用户不做操作,后续的用户对其调用muteRemoteVideoStream方法不接收后续用户的视频流,这样一屏加上自己和另外三个用户正好一屏数据,人数增加后根据逻辑每页显示4个做页数提示。

2、监听didOfflineOfUid,有回调向本地数组中删除该用户,同时更新显示画面,如果该用户在显示的画面里,需要去除该画面,后面的数据向前补位,补位的用户调用muteRemoteVideoStream来拉取该用户的视频流;如果该用户不在显示的画面里,在显示当前窗口的数组后方,不做操作,只需要在数组中删除该用户即可,如果该用户在线上窗口的数组前方,需要对当前画面的做位移,显示页前方的用户向前移动,并调用muteRemoteVideoStream不在订阅该用户的视频流,当前页后面的数组中的用户补在线上区域中,并调用muteRemoteVideoStream订阅该用户的视频流。

3、翻页:翻页的时候,翻到页面显示的区域的用户调用muteRemoteVideoStream订阅视频流,翻走的页面用户调用muteRemoteVideoStream取消订阅视频流。

4、音视频状态:客户端监听remoteVideoStateChangedOfUidremoteAudioStateChangedOfUid方法对当前页面的音视频状态做提示。

5、监听networkQuality回到,最每个画面上的用户做网络好坏提示。

难点

  • 分页场景下人员加入和离开:人员加入和离开会触发页数的变化,和当前页用户的布局改变
  • 人员订阅状态以及音视频状态:人员状态维护,用户会动态开关本地音视频流,页面要做对应的提示

总结

视频会议的玩法基本都是上述场景描述,通过一些上列手段来打破流量以及设备性能问题带来的通信不顺畅问题。随着技术的发展,设备性能的提高,超分辨率AI编解码等技术也会融入到多人视频会议当中,当然5G的普及以及6G的应用,流量问题也会被基础设施攻破。

技术分享| 如何做一款容纳百人的视频会议?

上一篇:SQL编程:存储过程+事务处理+回滚+数据迁移


下一篇:photoshop 多图合成暗紫色颓废风格签名效果