外部EXE能力
本章节介绍如何使用外部EXE能力。
一、前置说明
客户端版本>=4.11.2 CEF 版本 >= 1.4.0 IPC SDK (进程通信 SDK)
通信方式:字符串(管道)、图像帧数据(共享内存)
SDK 结构:ipc_module_client.h HuyaIPC.dll HuyaIPC.lib
备注:SDK 负责在前端和 EXE 之间透传字符串,不负责具体数据协议,开发者可自定义消息格式,例如使用 json 等
虎牙开放平台开发者中心:https://dev.huya.com/docs/
二、技术框架
三、整体方案
前端调用如下接口下载独立进程包(zip),开放平台负责下载(解压)到特定目录(%appdata%\HuyaPc\presenter\business\yygamelive\appletRes)
hyExt.pc.downloadRes({
url: "https://xxx.com/path/to/res.zip",
md5: "adfgafasiofdas0239032dfdf",
unzip: true
}).then(() => {
hyExt.logger.info("添加下载资源任务成功")
}).catch(err => {
hyExt.logger.info("添加下载资源任务失败", err)
})
- 前端监听下载进程:
hyExt.context.on("downloadProgress", (response) => {
const {
res, // 状态码,0-下载成功或者文件已经存在,1-正在下载,-1-下载失败
msg, // 下载成功失败提示信息
url, // 下载资源的url
md5, // 下载资源的md5
bytesLoaded, // 已下载的字节数(res=1时有效)
bytesTotal, // 总字节数(res=1时有效)
path // 文件路径,仅res为0的时候才有效
} = response || {}
if (res === 0) {
console.info("下载完毕", url, path)
} else if (res === 1) {
console.info("下载中", url, `${bytesLoaded}/${bytesTotal}`)
} else {
console.warn("下载失败", url, msg)
}
})
- 前端封装示例:
const downLoadRes = ({ url, md5, unzip }) => {
return new Promise((resolve, reject) => {
// 调用批量下载接口
hyExt.pc.downloadRes([{ url, md5, unzip }]).then(() => {
// 下载进度变化消息的处理函数
const handler = ({
res,
msg,
url: hUrl,
md5: hMd5,
bytesLoaded,
bytesTotal,
path,
}) => {
if (url === hUrl && md5 === hMd5) {
if (res === 0) {
console.info("下载完毕");
hyExt.context.off("downloadProgress", handler);
resolve({ res, url, md5, bytesLoaded, bytesTotal, msg, path });
} else if (res === 1) {
console.info("下载中");
} else {
console.info("下载失败");
hyExt.context.off("downloadProgress", handler);
reject(new Error(`${msg}(${res})`));
}
}
};
// 监听下载进度变化消息
hyExt.context.on("downloadProgress", handler);
});
});
};
- 前端调用如下接口启动独立进程:
hyExt.pc.launchExe({
md5: "adfgafasiofdas0239032dfdf",
exeName: "3rd.exe",
params: "xxx"
}).then(() => {
hyExt.logger.info("拉起exe成功")
}).catch(err => {
hyExt.logger.warn("拉起exe失败", err)
})
独立进程加载虎牙 IPC SDK,与前端建立通信
四、通信方式
独立进程发送数据到前端
独立进程侧:
从进程启动参数中获取,-p 自定义的启动参数,-c 通信服务器名,-i 通信客户端名。
// 客户端接口结构体
client\_module client;
// 回调接口结构体
client\_watch watch;
// 收到数据时回调接口
watch.recv\_data = yourRecvDataCallback;
// 通信断开时回调接口
watch.disconnect = yourNetDisconnectCallback;
// 创建客户端实例
void\* handle = create\_huya\_ipc\_client(&client, &watch);
// 连接到服务器
client.connect(handle, "通信服务器名", "通信客户端名");
// 异步发送字符串数据接口
client.send\_data\_async(handle, "someMsg", strlen("someMsg"));
// 发送图像帧数据
client.send\_frame\_data(handle, frameData,frameLen, frameInfo);
// 断开连接
client.disconnect(handle);
// 释放客户端实例
release\_huya\_ipc\_client(handle);
前端侧:
hyExt.pc.onExeMessage({
md5: "sdfafda",
callback: data => {
hyExt.logger.info("收到独立exe的消息:" + data)
}
})
前端发送数据到独立进程
前端侧:
hyExt.pc.sendToExe({
md5: "sfasdafsf",
data: "dafjaklfjafda"
}).then(({ data }) => {
hyExt.logger.info("调用成功", data)
}).catch(err => {
hyExt.logger.warn("调用失败", err)
})
独立进程侧:
// 收到数据时回调接口
watch.recv\_data = yourRecvDataCallback;
五、投屏实现
目前支持将小程序画面或者 EXE 画面投送到视频流中。实现方式有两种,一种是使用共享纹理指针,另一种是发送图像帧数据。
投屏小程序画面
开发者在前端页面调用如下接口添加/撤销投屏,开发者无需关注投屏方式,开放平台内部会优先使用共享纹理方式,如果共享纹理投屏失败会自动切换到图像帧数据方式。
- 投屏前端画面
hyExt.stream.addWhiteBoard({
elem: decodeURIComponent.getElementById("zone"),
alpha: 50
}).then(() => {
hyExt.logger.info("增加支持背景透明的白板成功")
}).catch(err => {
hyExt.logger.warn("增加支持背景透明的白板失败", err)
})
- 撤销前端画面
hyExt.stream.removeWhiteBoard().then(() => {
hyExt.logger.info("删除支持背景透明的白板成功")
}).catch(err => {
hyExt.logger.warn("删除支持背景透明的白板失败", err)
})
- 前端投屏演示
投屏独立进程画面
开发者需要关注投屏方式。
共享纹理方式:如果第三方 EXE 能方便使用 DX 共享纹理,则优先使用共享纹理(效率高)
前端与独立进程通信,前端拿到 EXE 投屏相关参数(位置、宽度、高度,共享纹理句柄),然后前端调用如下接口:
- 独立进程投屏演示
独立进程投屏参数(位置、宽度、高度,共享纹理句柄)变动时,独立进程发送通知给前端,前端再一次调用添加白板接口(见上)即可改变投屏内容。
备注:开放平台会自动检测添加白板接口的调用,如果是第一次调用就会添加白板,重复调用会修改原白板参数。
如果开放平台检测到共享纹理投屏失败会发送通知给前端,前端发送切换通知给独立进程,独立进程收到通知后调用如下接口发送帧数据:
- 开放平台返回错误:
{"res":9022,"msg":"{"errcode":1,"errmsg":"invalid shared handle."}"}
其他错误码详情,请点击跳转查看。
// 发送图像帧数据
client.send\_frame\_data(handle, frameData,frameLen, frameInfo);
- 撤销独立进程投屏
图像帧数据:
前端与独立进程通信,前端拿到 EXE 投屏相关参数(位置、宽度、高度,共享纹理置空),然后前端调用如下接口:
- 发送图像帧数据
client.send\_frame\_data(handle, frameData,frameLen, frameInfo);
- 撤销独立进程投屏