布局与流管理功能提供了会议中视频布局控制和流数据订阅管理。该功能允许应用层根据需求请求相应的视频流数据,控制视频布局模式,并管理参会者列表订阅,实现灵活的会议视频显示控制。
在会议中订阅参会者信息:
// 订阅参会者列表 - 订阅指定参会者URI列表
XYArray<const char*> uriList;
uriList.push_back("user1@example.com");
uriList.push_back("user2@example.com");
NemoSdkAdaptor::getInstance()->subscribeRoster(uriList);
// 请求布局流数据 - 请求布局配置
XYLayoutReq layoutReq;
layoutReq.mode = XYLayoutMode_Gallery;
layoutReq.maxParticipants = 9;
NemoSdkAdaptor::getInstance()->requestLayout(layoutReq);
// 更改布局模式 - 切换到画廊模式
NemoSdkAdaptor::getInstance()->changeLayout(XYLayoutMode_Gallery);
控制视频布局显示模式:
// 切换到画廊模式 - 显示多个参会者视频
NemoSdkAdaptor::getInstance()->changeLayout(XYLayoutMode_Gallery);
// 切换到演讲者模式 - 突出显示当前发言者
NemoSdkAdaptor::getInstance()->changeLayout(XYLayoutMode_Speaker);
// 切换到全屏模式 - 全屏显示视频内容
NemoSdkAdaptor::getInstance()->changeLayout(XYLayoutMode_FullScreen);
管理会议中的动态分组:
// 返回主会场 - 结束动态分组,返回主会场
NemoSdkAdaptor::getInstance()->endDynamicGroup();
API: subscribeRoster
接口定义:
virtual void subscribeRoster(const XYArray<const char*>& uriList) = 0;
参数:
uriList
: XYArray返回值: 无
示例:
// 订阅参会者列表,获取参会者信息
XYArray<const char*> uriList;
uriList.push_back("user1@example.com");
uriList.push_back("user2@example.com");
NemoSdkAdaptor::getInstance()->subscribeRoster(uriList);
API: requestLayout
接口定义:
virtual void requestLayout(const XYLayoutReq& layoutReq) = 0;
参数:
layoutReq
: XYLayoutReq - 请流的配置信息返回值: 无
示例:
// 请求画廊模式布局
XYLayoutReq galleryReq;
galleryReq.mode = XYLayoutMode_Gallery;
galleryReq.maxParticipants = 9;
galleryReq.resolution = XYVideoResolution_720P;
NemoSdkAdaptor::getInstance()->requestLayout(galleryReq);
// 请求演讲者模式布局
XYLayoutReq speakerReq;
speakerReq.mode = XYLayoutMode_Speaker;
speakerReq.mainSpeaker = "user123";
speakerReq.resolution = XYVideoResolution_1080P;
NemoSdkAdaptor::getInstance()->requestLayout(speakerReq);
API: changeLayout
接口定义:
virtual void changeLayout(const XYArray<XYUnityLayoutRequest>& unityLayoutRequests) = 0;
参数:
unityLayoutRequests
: XYArray<XYUnityLayoutRequest> - 改变布局的配置信息返回值: 无
示例:
// 切换到画廊模式
XYArray<XYUnityLayoutRequest> requests;
XYUnityLayoutRequest request;
request.layoutMode = XYLayoutMode_Gallery;
requests.push_back(request);
NemoSdkAdaptor::getInstance()->changeLayout(requests);
// 切换到演讲者模式
XYArray<XYUnityLayoutRequest> speakerRequests;
XYUnityLayoutRequest speakerRequest;
speakerRequest.layoutMode = XYLayoutMode_Speaker;
speakerRequests.push_back(speakerRequest);
NemoSdkAdaptor::getInstance()->changeLayout(speakerRequests);
API: endDynamicGroup
接口定义:
virtual void endDynamicGroup(const char* meetingId, const char* meetingNumber) = 0;
参数:
meetingId
: const char* - 会议idmeetingNumber
: const char* - 会议号返回值: 无
示例:
// 结束动态分组,返回主会场
NemoSdkAdaptor::getInstance()->endDynamicGroup("meeting123", "123456789");
class LayoutStreamManager {
private:
bool _isRosterSubscribed = false;
XYLayoutMode _currentLayoutMode = XYLayoutMode_Gallery;
std::vector<std::string> _participantList;
bool _isInDynamicGroup = false;
public:
// 参会者管理
void subscribeRoster() {
if (!_isRosterSubscribed) {
NemoSdkAdaptor::getInstance()->subscribeRoster();
_isRosterSubscribed = true;
}
}
// 布局控制
void requestGalleryLayout(int maxParticipants = 9, const std::string& resolution = "720p") {
std::string config = R"({
"mode": "gallery",
"maxParticipants": )" + std::to_string(maxParticipants) + R"(,
"resolution": ")" + resolution + R"("
})";
NemoSdkAdaptor::getInstance()->requestLayout(config);
}
void requestSpeakerLayout(const std::string& mainSpeaker = "", const std::string& resolution = "1080p") {
std::string config = R"({
"mode": "speaker",
"mainSpeaker": ")" + mainSpeaker + R"(",
"resolution": ")" + resolution + R"("
})";
NemoSdkAdaptor::getInstance()->requestLayout(config);
}
void requestFullScreenLayout(const std::string& targetUser = "", const std::string& resolution = "1080p") {
std::string config = R"({
"mode": "fullscreen",
"targetUser": ")" + targetUser + R"(",
"resolution": ")" + resolution + R"("
})";
NemoSdkAdaptor::getInstance()->requestLayout(config);
}
void changeLayoutMode(XYLayoutMode mode) {
_currentLayoutMode = mode;
NemoSdkAdaptor::getInstance()->changeLayout(mode);
}
// 动态分组管理
void endDynamicGroup() {
if (_isInDynamicGroup) {
NemoSdkAdaptor::getInstance()->endDynamicGroup();
_isInDynamicGroup = false;
}
}
// 参会者变化回调
void onRosterChanged(const XYString& rosterInfo) {
QString rosterStr(rosterInfo.str());
qDebug() << "Roster changed:" << rosterStr;
// 解析参会者列表
parseParticipantList(rosterStr);
emit rosterChanged(rosterStr);
}
// 视频流变化回调
void onVideoStreamChanged(const XYString& streamInfo) {
QString streamStr(streamInfo.str());
qDebug() << "Video stream changed:" << streamStr;
emit videoStreamChanged(streamStr);
}
// 动态分组结束回调
void onEndDynamicGroupResult(const XYString& code, const XYString& result) {
QString errCode(code.str());
QString resultStr(result.str());
if (errCode == SDKError_NoError) {
qDebug() << "Dynamic group ended successfully:" << resultStr;
_isInDynamicGroup = false;
emit dynamicGroupEnded(resultStr);
} else {
qDebug() << "Failed to end dynamic group:" << errCode;
emit dynamicGroupEndFailed(errCode);
}
}
private:
void parseParticipantList(const QString& rosterInfo) {
// 解析参会者列表JSON
QJsonDocument doc = QJsonDocument::fromJson(rosterInfo.toUtf8());
if (doc.isArray()) {
_participantList.clear();
QJsonArray array = doc.array();
for (const QJsonValue& value : array) {
if (value.isObject()) {
QJsonObject obj = value.toObject();
if (obj.contains("userId")) {
_participantList.push_back(obj["userId"].toString().toStdString());
}
}
}
}
}
public:
// Getter方法
bool isRosterSubscribed() const { return _isRosterSubscribed; }
XYLayoutMode getCurrentLayoutMode() const { return _currentLayoutMode; }
std::vector<std::string> getParticipantList() const { return _participantList; }
bool isInDynamicGroup() const { return _isInDynamicGroup; }
};
布局模式 | 说明 | 适用场景 |
| 画廊模式 - 显示多个参会者 | 多人会议,需要同时看到多个参会者 |
| 演讲者模式 - 突出显示当前发言者 | 演讲、培训等场景 |
| 全屏模式 - 全屏显示单个参会者 | 重要发言、演示等场景 |
| 自定义模式 - 自定义布局 | 特殊需求场景 |
分辨率 | 说明 | 适用场景 |
| 1280x720 | 标准清晰度,适合大多数场景 |
| 1920x1080 | 高清,适合重要会议 |
| 3840x2160 | 超高清,适合特殊需求 |
布局控制功能提供以下特性:
流管理功能包括:
动态分组功能支持:
方法 | 描述 | 链接 |
订阅参会者列表 | ||
按需请流 根据配置请求相应流数据 | ||
统一layout更改布局模式 | ||
返回主会场 |
回调 | 描述 | 链接 |
参会者列表变化回调 | ||
视频流变化回调 | ||
结束动态分组结果回调 |
枚举 | 描述 | 链接 |
布局模式枚举 |