使用小鱼易连Web SDK加入多人音视频会议后,需要展示参会者的画面。SDK 提供两种布局方式:自动布局和自定义布局,分别适用于不同的需求。
布局方式 | 优势 | 局限 |
自动布局 |
| 不支持业务扩展布局模式 |
|
|
本文将重点介绍如何使用小鱼易连 Web SDK 进行自动布局,快速完成多人会议画面的接入和展示。
自动布局:SDK 提供了桌面端和移动端浏览器下的布局模板,会基于参会人数和会控控制状态自动请求画面数据流并计算布局。并通过layout
事件上报布局结果数据,开发者只需根据该数据进行渲染画面即可。
自动布局下,单页最多支持展示 9 个画面,超过 9 人的会议仅接收音频。移动端最多支持 7 个画面;
桌面端和移动端浏览器下支持的布局模型如下所示;
备注:
事件 | 是否订阅 | 描述 |
必须 |
| |
必须 | 自动布局时上报参会者页码数据 |
事件 | 描述 |
配置 container 容器信息,SDK 会响应屏幕和容器大小变化,自动调整布局 | |
翻页查看更多参会者画面 | |
快速切换宫格布局和演讲者布局模式 | |
设置桌面端布局、移动端横/竖屏布局方式,建议在移动端下响应横竖屏切换时调用 | |
配置共享时宫格布局模式 | |
设置视频播放容器元素,SDK接管控制视频的播放和画面渲染 |
通过 XYRTC.createClient 创建客户端时:
body
容器计算;padding
效果,单位是px;const XYClient = XYRTC.createClient({
...
layout: 'AUTO',
container: {
// 配置显示容器节点 ID
elementId: 'meeting',
offset: [0, 0, 0, 0]
}
});
监听 screen-info 事件,实时获取显示容器的大小,支持响应屏幕和容器大小变化;
// AUTO模式回调数据,推送最新的Layout容器大小信息
XYClient.on('screen-info', (e) => {
console.log('screen info: ', e);
// 以style样式的形式更新到显示容器上,见下示意图
// 此处使用JS处理样式更新
updateLayoutContainerStyle(e);
});
// 处理容器样式函数
const updateLayoutContainerStyle = (style) => {
const container = document.getElementById('layout');
container.style.width = `${style.rateWidth}px`;
container.style.height = `${style.rateHeight}px`;
};
示意图:
当参会人员的状态或数量发生变化时,SDK 会自动拉取画面流并计算布局。开发者通过监听 layout 事件获取布局数据,进行画面渲染。
每一路参会者画面在初始渲染时需要调用一次 setVideoRenderer 方法,用来绑定渲染的容器信息,由SDK内部管理渲染操作,后续如果 id 没有变化,则无需重新调用;
提示
1、此处使用JS+HTML演示集成流程
2、正式开发时,建议使用React、Vue等框架实现,更便捷,可参考Demo示例程序;
let layoutList = [];
// 参会成员布局列表数据,包含参会者基本信息、位置、尺寸、旋转等数据
XYClient.on('layout', (e: ILayout[]) => {
console.log('layout: ', e);
layoutList = e;
// 获取成员列表布局数据,直接渲染使用即可
renderLayoutList();
});
// 此处使用JS+HTML演示集成流程
// 正式开发时,建议使用React、Vue等框架实现,更便捷,可参考Demo示例程序
const renderLayoutList = () => {
const meetingContainer = document.getElementById('layout');
layoutList.forEach((item) => {
const { positionStyle = {}, rotate = {}, id, state } = item;
const { displayName = '' } = item?.roster || {};
const layoutItemId = 'wrap-' + id;
const isExist = document.getElementById(layoutItemId);
const { width, height, left, top } = positionStyle;
// Layout外围容器样式
const layoutItemStyle = `width: ${width}; height: ${height}; left: ${left}; top: ${top}`;
const isPause = state === 'MUTE';
// video样式,包含竖屏旋转样式
let layoutVideoStyle = '';
for (let key in rotate) {
layoutVideoStyle += `${key}: ${rotate[key]};`;
}
// 判断layout id对应的元素是否已经渲染过
if (!isExist) {
// 初始渲染
const layoutItemString = `
<div class="layout_item" style="${layoutItemStyle}" id=${layoutItemId}>
<div class="layout_name">${displayName}</div>
<div class="layout_pause center ${isPause ? 'show' : 'hidden'}">视频暂停</div>
<div class="center layout_video">
<video class="video" style="${layoutVideoStyle}" playsinline autoplay muted></video>
</div>
</div>`;
// 向布局容器中追加新的参会者画面Dom
meetingContainer.insertAdjacentHTML('beforeend', layoutItemString);
// 不变的情况下,执行一次渲染方法即可
XYClient.setVideoRenderer(id, layoutItemId);
} else {
// 已渲染,更新样式和状态
const layoutItemEle = document.getElementById(layoutItemId);
const layoutNameEle = layoutItemEle.querySelector('.layout_name');
const layoutVideoEle = layoutItemEle.querySelector('.video');
const layoutPauseEle = layoutItemEle.querySelector('.layout_pause');
layoutItemEle.style.cssText = layoutItemStyle;
layoutNameEle.innerHTML = displayName;
layoutVideoEle.style.cssText = layoutVideoStyle;
layoutPauseEle.className = `center layout_pause ${isPause ? 'show' : 'hidden'}`;
}
});
};
// UI信息
<div id="meeting">
<div id="layout"></div>
</div>
回调参数类型:ILayout
监听 page-info 事件,获取页码信息,并使用
XYClient.on('page-info', (pageInfo: IPageInfo) => {
console.log('page info: ', pageInfo);
})
const nextPage = async () => {
await XYClient.setPageInfo(1);
}
// 模拟
<div onClick={nextPage}>下一页</div>
调用完成后,通过第三步获取布局列表数据并渲染即可;