虎牙开放平台文档

外部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/

二、技术框架

2022 03 22 18 11 12

三、整体方案

前端调用如下接口下载独立进程包(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) })
  • 前端投屏演示

2022 03 22 18 20 22

投屏独立进程画面

开发者需要关注投屏方式。

共享纹理方式:如果第三方 EXE 能方便使用 DX 共享纹理,则优先使用共享纹理(效率高)

前端与独立进程通信,前端拿到 EXE 投屏相关参数(位置、宽度、高度,共享纹理句柄),然后前端调用如下接口:

2022 03 22 18 21 22

  • 独立进程投屏演示

2022 03 22 18 22 22

独立进程投屏参数(位置、宽度、高度,共享纹理句柄)变动时,独立进程发送通知给前端,前端再一次调用添加白板接口(见上)即可改变投屏内容。

备注:开放平台会自动检测添加白板接口的调用,如果是第一次调用就会添加白板,重复调用会修改原白板参数。

如果开放平台检测到共享纹理投屏失败会发送通知给前端,前端发送切换通知给独立进程,独立进程收到通知后调用如下接口发送帧数据:

  • 开放平台返回错误:
{"res":9022,"msg":"{"errcode":1,"errmsg":"invalid shared handle."}"}

其他错误码详情,请点击跳转查看。

// 发送图像帧数据 client.send\_frame\_data(handle, frameData,frameLen, frameInfo);
  • 撤销独立进程投屏

2022 03 22 18 23 22

图像帧数据:

前端与独立进程通信,前端拿到 EXE 投屏相关参数(位置、宽度、高度,共享纹理置空),然后前端调用如下接口:

2022 03 22 18 24 21

  • 发送图像帧数据
client.send\_frame\_data(handle, frameData,frameLen, frameInfo);
  • 撤销独立进程投屏

2022 03 22 18 25 21