通过参会者事件回调开发者可获取到参会者信息,根据参会者信息可通过平台拉取音视频流。平台默认返回 20 路以内的音视频流,如需获取更多,可咨询技术支持人员。将拉流的数据结合布局策略开发者可自由定义多种布局。从v3.3.3版本开始支持上报300路roster,如需使用全量roster需要联系小鱼技术支持打开企业开关。
入会成功后通过 nemoSDKDidRosterChanged 回调获取到当前参会者信息,参会者信息中的 participantId 属性标记了参会者的唯一性,拉流接口需要传入参会者的 participantId,同时还可以设置每一位参会者视频流的分辨率等信息,您可以根据展示的需求配置拉流策略。
- (void)nemoSDKDidRosterChanged:(NemoRosters *)rosters {
//参会者数组
NSArray *prArray = rosters.peopleRosters;
for (NemoRosterInfo *rinfo in prArray) {
//参会者id
int pId = rinfo.participantId;
}
/**
根据当前UI展示的状态,结合业务逻辑,组成不同的请流策略
假如会中有10人,即rosters.peopleRosters.count == 10
当前屏幕要展示6个人的视频,则需要一次请求6路视频流
*/
//创建可变数组
NSMutableArray *peoplesArray = [[NSMutableArray alloc] init];
for (NSInteger i = 0; i < 6; i++) {
//设置请求参数
NemoCustomLayoutInfo *info = [[NemoCustomLayoutInfo alloc] init];
info.participantId = @"第i个人的参会者id";
//设置分辨率,我们请1路720P,5路180P
info.resolution = (i == 0?NemoVideoResolution_720P:NemoVideoResolution_180P);
//设置视频质量,我们对720P设置高质量,其余设置较低质量
info.quality = (i == 0?NemoVideoQuality_High:NemoVideoQuality_Base);
//设置布局优先级,一般等级
info.priority = NemoLayoutPriority_Normal;
//添加到数组
[peoplesArray addObject:info];
}
//发起请流
[[NemoSDK sharedInstance] setCustomLayout:peoplesArray];
}
//如果您开通了全量roster上报服务,可以监听以下回调
- (void)nemoSDKDidBulkRosterChanged:(NemoBulkRosters *)rosters {
//全量roster回调,最多回调300个参会者信息,您需要先订阅这些参会者,被订阅的
//参会者会从nemoSDKDidRosterChanged接口中回调,回调后自定义请流即可
}
- (void)nemoSDKDidVideoChanged:(NSArray<NemoLayout *> *)videos {
//videos数组返回请到的视频流信息,接下来就可以在UI上展示了
/**
例如请求了6路视频,则videos.count == 6
您需要创建6个负责展示视频的view
注意:远端参会者视频状态发生变化也会触发回调,不一定全部是请流的结果
所以您要关注这种场景: videos中返回的视频流可能已经在展示中了,此时
需要调用updateVideo方法更新视频即可,不能再调用setupVideo,避免
创建了多个同一路视频流渲染,videos中返回的视频流不包含正在展示的视频,
说明远端有人退会了,需要销毁对应的NemoVideoCanvas对象。
*/
CGSize screenSize = [UIScreen mainScreen].bounds.size;
CGFloat scale_16_9 = (CGFloat)16/9;
NSMutableArray *allVideos = [NSMutableArray arrayWithArray:videos];
NSMutableArray *removeVideos = [NSMutableArray array];
/**
首先要检查正在展示的视频,如果videos中包含正在展示的视频,只需要调用updateVideo更新即可
过滤video,更新存在video,保存不存在video
*/
for (NemoVideoCanvas *canvas in self.layoutArray) {
BOOL found = NO;
for (NemoLayout *layout in allVideos) {
if ([canvas.layout.participantId isEqualToString:layout.participantId]) {
//正在展示中,需要更新视频流
found = YES;
canvas.layout = layout;
[[NemoSDK sharedInstance] updateVideo:canvas];
[allVideos removeObject:layout];
break;
}
}
if (!found) {
//返回的视频流中,不包含本地正在展示的视频,说明有参会者退会了,需要销毁对应的view
[removeVideos addObject:canvas];
}
}
//移除不存在video,并且移除View
for (NemoVideoCanvas *canvas in removeVideos) {
[self.layoutArray removeObject:canvas];
[canvas clear];
[canvas.view removeFromSuperview];
}
//创建新的video
for (NSInteger i = 0; i < allVideos.count; i++) {
//第i个view
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, i*screenSize.width*scale_16_9, screenSize.width, screenSize.width*scale_16_9)];
NemoVideoCanvas *canvas = [[NemoVideoCanvas alloc] init];
canvas.isLocal = NO; //是否是本地视频
canvas.layout = videos[i]; //绘制第一路视频流
canvas.view = view; //SDK会将对应的视频绘制到view上
[[NemoSDK sharedInstance] setupVideo:canvas];
//本地数组保存正在展示的视频
[self.layoutArray addObject:canvas];
}
}
拉流&布局