feat(harmony): stream screens over HDC without a companion app
Replace per-frame file capture with the unchanged official Hypium agent, bounded JPEG decoding, independent control RPC and scoped session cleanup. Remove the HAP build and account-signing experiment. All 85 automated checks pass; moving-screen performance and integrated phone input remain unverified because the USB device went offline. Keep published 0.3.2 artifacts unchanged.
This commit is contained in:
@@ -67,15 +67,15 @@ macOS 上的鸿蒙设备连接工具。通过 USB 收发文件与完整文件夹
|
||||
|
||||
在「设备与应用」选择已授权的 HDC 目标,点击「开始投屏」。默认仅观看;画面出现后勾选「启用鼠标与键盘控制」。功能依设备的 `uitest` 帮助和实际操作结果开放。
|
||||
|
||||
- 连续显示手机画面,显示真实分辨率、实测刷新帧率和采集耗时。可放大面板,将当前画面保存为 JPEG。
|
||||
- 连续显示手机画面,显示真实分辨率、接收/显示帧率和码率。可放大面板,将当前画面保存为 JPEG。
|
||||
- 点击、双击、长按、滑动、拖拽与滚轮滚动;坐标按实际手机尺寸映射,忽略画面周围留白。
|
||||
- 返回、主页、音量、方向键、回车、退格等按键。快捷键只在手机画面获得焦点时生效。
|
||||
- 用专用文字框发送文本,支持输入法;不读取系统剪贴板。文字能否进入目标输入框,以手机焦点和输入权限为准。
|
||||
- 一个屏幕会话只保留一项待发送操作。停止、切换工作区、页面隐藏、断线时清空队列和旧画面,不在重连后重放输入。横竖屏变化后需重新启用控制。
|
||||
|
||||
当前实现通过 HDC + UITest 连续采集截图,完成一帧再开始下一帧;不是 H.264/H.265 视频流,不承诺 scrcpy 的 30/60 FPS、音频或低延迟多点触控。拖动在松开时发送完整手势。采集临时文件使用每次唯一名称并清理;远端清理被断线阻断时,不扫描删除其他文件。
|
||||
当前源代码通过 HDC 部署官方 Hypium 代理,持续接收 JPEG 画面,并通过独立连接发送输入。用户无需开发者账号、编译、签名或安装手机应用。拖动在松开时发送完整手势。停止会删除本会话的代理和转发;其他调试工具占用设备时会提示。已发布 0.3.2 仍为逐帧截图,新路径的动态真机验收状态见[开发验证](harmony-realtime-development.md)。
|
||||
|
||||
图像解码限制内存与尺寸,传给 UI 的 JPEG 最长边不超过 1600 像素;坐标仍按手机原始尺寸计算。画面过旧、方向变化、会话过期或输入失败时会阻止控制。受保护画面和锁屏遵循系统限制,不自动解锁。自动化测试和真机结果分别记录,详见[投屏能力调研](research/harmony-screen-control.md)。
|
||||
JPEG 采用半尺寸采集,坐标按手机原始尺寸计算。画面不变化时保留显示,通过独立控制连接检查存活;方向变化、会话过期或输入失败时会阻止控制。受保护画面和锁屏遵循系统限制,不自动解锁。自动化测试和真机结果分别记录,详见[HDC 持续投屏调研](research/harmony-hdc-only-screen.md)。
|
||||
|
||||
## 重连问题与 debug
|
||||
|
||||
|
||||
@@ -1,78 +1,40 @@
|
||||
# Harmony Connector 连续视频开发验证
|
||||
# Harmony Connector 持续投屏开发验证
|
||||
|
||||
当前为待真机验证的开发组件,尚未接入插件播放器,也未发布新插件版本。已发布的 0.3.2 仍使用逐帧截图。不要将本篇的编码配置或本机生成视频测试结果描述成手机实测性能。
|
||||
运行路径为:已授权的 HDC USB 连接 → 官方 Hypium 设备代理 → 持续 JPEG 推送 → 插件显示。用户无需开发者账号、AppGallery Connect、HAP 安装、编译或签名。代理由插件自动部署到本次会话的临时文件,停止时删除。
|
||||
|
||||
## 已完成与待验证
|
||||
## 当前状态
|
||||
|
||||
2026-09-10 的原链路真机采集耗时为 696、803、802 ms,约 1.3 fps。截图命令、PNG 文件回传和图像转换是逐帧执行的;调整界面定时器不足以实现实时视频。
|
||||
2026-09-10:已发布的 0.3.2 仍使用逐张截图,真机原链路为 696、803、802 ms,约 1.3 fps。当前源代码已替换该路径,尚未发布新版本。
|
||||
|
||||
新增源码:
|
||||
官方 `xdevice-devicetest` 6.1.0.210 的 `uitest_agent_v1.2.2.so` 已在 HUAWEI Pura 70 Ultra 的商业系统上成功加载。独立探针收到真实 JPEG、屏幕尺寸 1260 × 2844,并成功调用尺寸、旋转和唤醒接口。设备端文件为 600245 字节,未改动签名原件。没有安装 HAP,也没有账号或系统共享确认步骤。
|
||||
|
||||
- `curios/harmony-connector/companion`:官方 Empty Ability 模板上的普通手机应用。用户点击共享后,经系统授权,将 AVScreenCapture Surface 接到 H.264 编码器。初始配置最长边 1280、30 fps、4 Mbps CBR、Baseline、1 秒关键帧间隔,不采集音频。
|
||||
- `tools/harmony-stream.py`:独立 Mac 开发验证程序,建立本会话 HDC 转发、启动组件、接收与解码视频,输出接收帧率、解码帧数和码率。默认不保存画面文件、不发送输入。`--view` 用于人工观看。
|
||||
- `tools/harmony-stream.test.py`:协议尺寸与长度限制、断流、超时、非 H.264 数据,以及真正经过 FFmpeg 编码与解码的 20 帧生成视频测试。
|
||||
探测期间手机主要处于锁屏或静止状态。黑色首帧、短暂变化及收包时间不能证明动态帧率或端到端延迟达标。接入生产后端时手机变为 Offline,后端的完整真机连通、持续动态画面、输入及重连仍待验收。自动化替身测试不替代这项验收。完整自动化检查通过 85 项:47 项原生、32 项 UI/格式/坐标、6 项 USB 桥接与底座协议检查。
|
||||
|
||||
已使用官方 Command Line Tools 26.0.0.821 编译出 arm64-v8a 未签名 HAP,包含 ArkTS 和本地 C++ 动态库;编译兼容级别 API 17,使用的采集接口最低 API 14。编译成功不代表商业设备运行授权与编码能力已经验证。
|
||||
之前的 HAP 实验源码和签名流程已移除。本机签名材料不属于插件或发行包。原方案的研究过程保留在[历史记录](research/harmony-realtime-stream.md),当前方案及来源见[HDC 持续投屏调研](research/harmony-hdc-only-screen.md)。
|
||||
|
||||
签名工具已登录,但调用 `signature generate` 返回账号尚未完成开发者实名认证。尚未安装伴随应用、取得真机 H.264 视频、测量呈现帧率或端到端延迟。
|
||||
|
||||
## 构建与签名
|
||||
|
||||
需要完整官方 Command Line Tools、Node.js 22+、官方 `@deveco/deveco-cli@1.3.0-stable`。`DEVECO_CLI_CLT_PATH` 指向包含 `sdk`、`tool`、`hvigor` 的 `command-line-tools` 根目录,不是单独的 HDC 所在目录。
|
||||
## 构建和验证
|
||||
|
||||
```sh
|
||||
cd curios/harmony-connector/companion
|
||||
# 首次准备;已有配置时保留本机签名。
|
||||
test -f build-profile.json5 || cp build-profile.template.json5 build-profile.json5
|
||||
node curios/harmony-connector/build.mjs
|
||||
node tools/test-harmony.mjs
|
||||
|
||||
# 预先按本机实际路径设置 DEVECO_CLI_CLT_PATH。
|
||||
npx --yes @deveco/deveco-cli@1.3.0-stable build --modules entry --build-mode debug
|
||||
# 手机开启 USB 调试并授权 Mac;多设备时在末尾加目标 ID。
|
||||
curios/harmony-connector/backend/harmony-connector --check-screen /absolute/path/to/hdc
|
||||
|
||||
# 连续 20 秒,通过与 UI 相同的后端接口接收并实际解码 JPEG。
|
||||
curios/harmony-connector/backend/harmony-connector --check-screen-stream /absolute/path/to/hdc
|
||||
```
|
||||
|
||||
得到 `entry/build/default/outputs/default/entry-default-unsigned.hap`。真实手机安装必须有合法签名;需要已实名认证的华为开发者账号,按官方流程配置可调试设备。认证入口是 [AppGallery Connect](https://developer.huawei.com/consumer/cn/service/josp/agc/index.html),见[官方开发准备](https://developer.huawei.com/consumer/cn/appgallery/devstart/)。
|
||||
动态测量时保持手机解锁,并连续滑动桌面或滚动页面。`receivedFps` 与 `mbps` 是最近一秒收到的帧数和码率;`consumerFps` 是此验证程序在完整观察期解码的不同帧数除以时长,不是 WebView 呈现帧率。`frameAgeMs` 是收到画面后经过的时间,不是端到端延迟。静止画面不重复计帧。
|
||||
|
||||
```sh
|
||||
npx --yes @deveco/deveco-cli@1.3.0-stable auth login
|
||||
npx --yes @deveco/deveco-cli@1.3.0-stable signature generate --product default
|
||||
npx --yes @deveco/deveco-cli@1.3.0-stable build --modules entry --build-mode debug
|
||||
```
|
||||
上述命令默认不保存画面、不启用控制,也不发送输入。基础连通命令的第三个参数可以是用户指定的保存目录。真实交互仍需在插件中检验:启用控制、点击、拖动、返回/主页、文字输入、停止后重新开始,以及拔线后旧画面清空。
|
||||
|
||||
`build-profile.json5`、签名证书、profile 和密码材料均属于本机文件,不提交到仓库。模板 `build-profile.template.json5` 不包含签名配置。不要将绑定调试设备的 HAP 当作所有用户均可安装的发行包;正式手机组件需要发布者签名和正式分发流程。
|
||||
## 会话与协议
|
||||
|
||||
## 真机验证
|
||||
- 插件只保留最新一张 JPEG,不积压视频队列。UI 用上一帧序号等待变化;静止时返回状态,不重复发送图片。
|
||||
- 图像与控制使用两个独立 socket,共用本会话的 HDC 转发。按键和手势通过持久 RPC 发送,文字使用已验证的 `uitest uiInput text`。
|
||||
- 代理回包包括 JSON 行与 JPEG;解析 JPEG 段长度,避免把 EXIF 数据中的字节误认作图像结尾。单帧上限 2 MiB,JSON 上限 64 KiB。
|
||||
- 静止画面不视为断线;独立控制连接查询尺寸检查存活。UI 停止请求超过 15 秒会结束会话。屏幕几何变化会关闭输入控制。
|
||||
- 每次部署使用唯一文件名,只结束加载该文件的进程,只删除本次转发和文件。发现其他 UITest 会话时提示占用,不接管或结束其他调试工具。
|
||||
|
||||
先确认 `hdc list targets -v` 显示目标为 `Connected`。安装刚构建的 **signed** HAP,包名为 `ink.render.trove.harmonyconnector`。安装应选择明确目标,不自动安装到其他设备。
|
||||
|
||||
在仓库根目录执行以下命令,将 HDC 路径替换为本机工具路径;连接多台设备时另加 `--target`:
|
||||
|
||||
```sh
|
||||
python3 tools/harmony-stream.py --hdc /absolute/path/to/hdc --seconds 20
|
||||
# 人工观看连续画面;需 ffplay。
|
||||
python3 tools/harmony-stream.py --hdc /absolute/path/to/hdc --seconds 20 --view
|
||||
```
|
||||
|
||||
运行时在手机点击「共享屏幕」,同意系统请求,滚动页面或移动窗口产生持续变化。默认验证需要 FFmpeg;它只用于开发测量,未引入生产插件依赖。
|
||||
|
||||
接收帧率目标至少 20 fps,默认解码模式同时要求解码帧数达到收到视频帧数的 95%。这些只是开发验收门槛,不能代替端到端延迟测量。`--view` 的 FFplay 不提供解码帧计数,需另外运行默认模式;人工确认的流畅程度应单独记录。静态画面可能由系统抑制重复帧,性能测试必须保持画面变化。
|
||||
|
||||
停止共享、系统拒绝、拔线、关闭验证程序都必须终止手机采集并清理仅本会话的转发。当前原型在屏幕尺寸变化时停止共享,提示重新开始;自动旋转重建、插件播放器集成及流式会话中的输入验证仍待完成。
|
||||
|
||||
## 传输与资源边界
|
||||
|
||||
手机仅监听 IPv4 loopback,由启动端提供随机远端端口和 32 字节会话随机值。连接后首先发送 64 个小写十六进制字符进行会话校验,不通过则断开。正常用户操作仍需手机点击共享以及系统录屏授权。
|
||||
|
||||
验证成功后,手机发送固定 24 字节头:`HCS1` + 5 个大端 u32,依次为编码宽、高、屏幕宽、高、配置帧率。随后每包为大端 `u32 payloadLength + u32 flags + i64 ptsUs + Annex B H.264 payload`,沿用公共编码器的 buffer flags。SPS/PPS 配置数据与编码帧均按输出顺序保留。
|
||||
|
||||
单包上限 2 MiB;采集回调复制数据后归还编码器 buffer。发送队列上限 6 包和 4 MiB,超过就结束会话,不积压旧帧,也不任意丢弃参考帧。Socket 发送超时 500 ms。主机发送一个零字节或断开连接可停止采集。系统停止与错误统一由资源所属线程收尾,释放 capture、encoder、surface、socket。
|
||||
|
||||
这仍是开发协议,尚未替代正式产品的配对、版本协商和播放器生命周期设计。普通录屏授权也不会赋予任意输入注入权限;后续控制需复用已授权的 UITest 能力并验证响应。
|
||||
|
||||
## 自动化验证
|
||||
|
||||
```sh
|
||||
python3 tools/harmony-stream.test.py -v
|
||||
```
|
||||
|
||||
测试不连接手机;使用本地 socket pair 验证接收行为,使用生成图案验证实际 H.264 解码。当前 8 项通过,20 帧均成功解码。它们不证明手机端授权、编码吞吐、后台保活或 USB 实时性。
|
||||
|
||||
API、权限和被拒绝的无安装路线见[连续视频调研](research/harmony-realtime-stream.md)。
|
||||
运行 HDC 不需要完整 SDK:本机独立验证了 `hdc` 与同目录 `libusb_shared.dylib` 的版本命令,总计约 6.4 MiB。完整工具包用于开发构建,不应成为普通投屏用户的依赖。本次尚未新增精简 HDC 发行包;插件继续使用已配置或自动发现的官方工具。
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
# Harmony Connector:仅通过 HDC 的连续投屏
|
||||
|
||||
调研日期:2026-09-10。产品约束:最终用户只启用 USB 调试并授权 Mac,不注册开发者账号、不安装 HAP、不修改手机安全策略。目标是可交互的连续画面,不限定 H.264;帧率和延迟必须在真机上测量。本篇研究未操作设备。
|
||||
|
||||
## 当前结论
|
||||
|
||||
找到了一条此前漏查的公开分发路线:**使用华为 Hypium 的公开 PyPI 依赖包中原样分发的 UITest agent,由设备内置 `uitest` 加载,通过 HDC 转发持续 JPEG 与触控 RPC。** 该路线无需用户编译、签名或安装手机应用;它仍会向设备临时推送一个 agent 文件,作用类似 scrcpy 的临时设备端服务。不能把自编 unsigned ELF 或 addon 被 XPM 拒绝,推广为所有官方签名 agent 均无法加载。
|
||||
|
||||
Hypium 的公开说明支持 USB/Wi-Fi 调试连接,并明确 Driver 模式可作为 SDK 集成到其他工具。其 `xdevice-devicetest` 包公开包含原生 agent;对应的 `xdevice-ohos` 包提供选择、推送、启动和转发实现。[Hypium 官方发布页](https://pypi.org/project/hypium/6.1.0.210/)、[设备测试资源包](https://pypi.org/project/xdevice-devicetest/6.1.0.210/)、[设备连接包](https://pypi.org/project/xdevice-ohos/6.1.0.210/)
|
||||
|
||||
**主任务真机进展:**官方 `v1.2.2.so` 使用唯一 `--extension-name` 已成功加载,Unix socket 能返回 JPEG,`Driver.create`、屏幕尺寸和旋转查询成功;不需要安装 HAP、开发者账号或录屏确认弹窗。初次收到的是 630 × 1422 黑帧,首帧约 195–235 ms,15 秒仅收到 3 帧;当时可能处于锁屏状态,**这些数字只证明链路连通,不能作为动态画面流畅度或端到端延迟的结论**。本文作者未操作手机,真机结果来自主任务当轮报告。
|
||||
|
||||
## 精确来源与许可证据
|
||||
|
||||
本轮从 PyPI 元数据取得 wheel 下载地址,在内存读取并校验 SHA256,没有安装或执行其中代码。
|
||||
|
||||
| 资源 | 版本、路径及 SHA256 |
|
||||
| --- | --- |
|
||||
| xdevice-devicetest wheel | `6.1.0.210`;`1c80f0da8d497d4e034f9873e966e8b2d8ef23ecc376c64c839c1493a813980e` |
|
||||
| 新版 ARM64 agent | `devicetest/res/prototype/native/uitest_agent_v1.2.2.so`;`e1b8e75fad983aa29640784ee4b457fe7ac1c916a15f72c8b899d5a7716da651` |
|
||||
| 旧版 ARM64 agent | `devicetest/res/prototype/native/uitest_agent_v1.1.10.so`;`1c9286456fb003ee15d86fef04e8c93f004027349e6dd2ef972c792e0a6d4bf8` |
|
||||
| xdevice-ohos wheel | `6.1.0.210`;`548a09bb6fc9fcfd92a7dbb5b69180de0159ce8959057e133dec34774054bb12` |
|
||||
|
||||
资源包的 `METADATA` 明确列出 `License-File: LICENSE`,`xdevice_devicetest-6.1.0.210.dist-info/LICENSE` 是完整 Apache License 2.0;本次清单未发现额外 EULA、NOTICE 或对 agent 的另行许可文件。Apache 2.0 提供商业使用及 object form 再分发条件;打包时保留该许可证、来源版本和校验值,保留现有版权声明,修改自有封装代码应说明。不要以第三方仓库的许可证替代原始发布包的许可。[原始 wheel](https://files.pythonhosted.org/packages/a2/b5/55bdfe4d669558331499848dbc68269506abb9b4a771e3524a65f9845127/xdevice_devicetest-6.1.0.210-py3-none-any.whl)、[Apache 2.0 条款](https://www.apache.org/licenses/LICENSE-2.0)
|
||||
|
||||
原始 `v1.2.2.so` 尾部包含 ELF 签名块标记,并含 Huawei CBG Software Signing Service CA 证书链字符串。这里只确认原件附带签名结构,**没有进行独立密码学验签,也没有据此声称目标设备必然接受**。部署必须保持字节不变,不 strip、不重链接、不截掉 ELF 尾部。该 wheel 没有提供 agent 的 C++ 源码,因此应称“公开分发的官方 agent”,不能称为设备端也能完全自行重建的开源实现。
|
||||
|
||||
## 真实选择与启动路径
|
||||
|
||||
当前手机 UITest 版本由主任务报告为 `6.0.2.3`。官方 `xdevice-ohos 6.1.0.210` 内:
|
||||
|
||||
- `ohos/environment/device.py::check_if_unix_socket_mode`:UITest 版本高于 `6.0.2.1` 且设备不是 x86_64 时使用 Unix socket。
|
||||
- `ohos/proxy/proxy_base.py::_init_so_resource`:此分支选择 `uitest_agent_v1.2.2.so`;旧分支才使用 v1.1.10/v1.1.5/v1.1.3。
|
||||
- `ohos/proxy/ui_proxy.py`:默认推送到 `/data/local/tmp/agent.so`,运行 `/system/bin/uitest start-daemon singleness`,连接 `localabstract:uitest_socket`。旧协议为设备 TCP 8012。
|
||||
|
||||
因此不能把“设备 6.x”硬编码为旧 TCP 8012,也不能只依据文件名相似选择第三方 agent。[对应公开 wheel](https://files.pythonhosted.org/packages/78/a6/8ac621bb958813cde648d515069c30188939b492ffcdd29e8d1e234550cf/xdevice_ohos-6.1.0.210-py3-none-any.whl)
|
||||
|
||||
以下最小命令形态已由主任务用本轮官方原件在当前手机验证;参数仍必须来自所选设备与本机会话:
|
||||
|
||||
```text
|
||||
hdc -t <device> file send <official-agent.so> /data/local/tmp/<session-agent.so>
|
||||
hdc -t <device> shell uitest start-daemon singleness --extension-name <session-agent.so>
|
||||
hdc -t <device> fport tcp:<local-port> localabstract:uitest_socket
|
||||
```
|
||||
|
||||
独有 `--extension-name` 来自 OpenHarmony UITest 的扩展加载器:它将名称解析到 `/data/local/tmp/` 并加载扩展。官方 Python 默认使用 `agent.so`,独有名已在本轮商业手机上验证,其他固件仍需兼容验证。不要覆盖其他工具已有的 `agent.so`;官方框架内部的通配清理、强杀其他进程不应照搬到插件。[扩展加载器](https://github.com/openharmony/testfwk_arkxtest/blob/b04e30c40cf266c9abfbd52933e43a0456eb99a2/uitest/addon/extension_executor.cpp)
|
||||
|
||||
## 持续 JPEG 与控制协议
|
||||
|
||||
公开客户端已有实际代码实现,不依赖教程中的口头描述。本节以 `devhelmkit` 锁定提交 `05c9bc0f7f9ea763d61c8b4b5d1cfbb076626b00` 为协议参考,设备 agent 原件仍从官方 wheel 获取。该项目的 `device/hdc.py`、`rpc/proxy_v2.py`、`screenshot_stream.py` 分别实现传输、RPC 和连续画面。[传输实现](https://github.com/yabi-zzh/devhelmkit/blob/05c9bc0f7f9ea763d61c8b4b5d1cfbb076626b00/src/devhelmkit/harmony/device/hdc.py)、[RPC](https://github.com/yabi-zzh/devhelmkit/blob/05c9bc0f7f9ea763d61c8b4b5d1cfbb076626b00/src/devhelmkit/harmony/rpc/proxy_v2.py)、[连续帧](https://github.com/yabi-zzh/devhelmkit/blob/05c9bc0f7f9ea763d61c8b4b5d1cfbb076626b00/src/devhelmkit/harmony/screenshot_stream.py)
|
||||
|
||||
客户端发送请求的 TCP 封包顺序:
|
||||
|
||||
```text
|
||||
ASCII "_uitestkit_rpc_message_head_"
|
||||
u32 big-endian session ID
|
||||
u32 big-endian UTF-8 JSON byte length
|
||||
JSON body
|
||||
ASCII "_uitestkit_rpc_message_tail_"
|
||||
```
|
||||
|
||||
初始化和控制使用独立连接。调用 `Driver.create` 后使用返回的实际引用值,不能把 `Driver#0` 当成所有连接的固定保证。外层 `request_id` 为本次唯一字符串,transport session ID 是另一字段。
|
||||
|
||||
```json
|
||||
{
|
||||
"module": "com.ohos.devicetest.hypiumApiHelper",
|
||||
"method": "callHypiumApi",
|
||||
"params": {
|
||||
"api": "Driver.create",
|
||||
"this": null,
|
||||
"args": [],
|
||||
"message_type": "hypium"
|
||||
},
|
||||
"request_id": "<unique-request>"
|
||||
}
|
||||
```
|
||||
|
||||
后续只替换 `params` 中的 API、引用与参数,外层保持相同。以下是主任务确认的**解析后结果值**,不代表复制完整回包结构:
|
||||
|
||||
| API | `this` / `args` | 当前手机结果 |
|
||||
| --- | --- | --- |
|
||||
| `Driver.create` | `null` / `[]` | `"Driver#0"` |
|
||||
| `Driver.getDisplaySize` | 返回的 Driver 引用 / `[]` | `{"displayId":0,"x":1260,"y":2844}` |
|
||||
| `Driver.getDisplayRotation` | 返回的 Driver 引用 / `[]` | `0` |
|
||||
| `Driver.wakeUpDisplay` | 返回的 Driver 引用 / `[]` | `null` |
|
||||
| `Driver.getDeviceInfo` | 返回的 Driver 引用 / `[]` | `No handler found`,当前手机不可用,不用于探活。 |
|
||||
|
||||
物理输入坐标应依据屏幕尺寸与旋转转换,不能直接使用 JPEG 缩小后的像素坐标。`getDisplaySize` 可作为独立控制连接的低频探活;无新图不等于连接已断。
|
||||
|
||||
在独立采集 socket 发送:
|
||||
|
||||
```json
|
||||
{
|
||||
"module": "com.ohos.devicetest.hypiumApiHelper",
|
||||
"method": "Captures",
|
||||
"params": {
|
||||
"api": "startCaptureScreen",
|
||||
"args": { "options": { "displayId": 0, "scale": 0.5 } }
|
||||
},
|
||||
"request_id": "<unique-request>"
|
||||
}
|
||||
```
|
||||
|
||||
注意 `Captures.args` 是对象,与 `callHypiumApi.args` 数组不同。JPEG 被推送到发送采集请求的 socket。**当前官方 v1.2.2 真机回包实测为 JSON 行 `{"result":true,"pts":...}\n` 与裸 JPEG `FF D8 … FF D9` 加换行,不使用上述 HEAD/TAIL 请求封包包住 JPEG。**不能只实现带 HEAD/TAIL 的接收器。参考客户端兼容协议封装与裸 JPEG;实现应依据实际格式使用有界长度及完整帧解析,不能假设一次 `recv` 对应一张图,也不能忽略 ACK/错误后无限等待。[采集请求与分帧](https://github.com/yabi-zzh/devhelmkit/blob/05c9bc0f7f9ea763d61c8b4b5d1cfbb076626b00/src/devhelmkit/harmony/screenshot_stream.py#L677)
|
||||
|
||||
实时触控使用相同外层与 `method: "Gestures"`,内层为 `api: "touchDown" | "touchMove" | "touchUp"`、`args: {"x": ..., "y": ...}`。客户端实现按下、移动、抬起接口,适合替换拖动后才发送整段 swipe 的延迟;必须限制 move 排队,并保证取消、失焦时结束本会话已按下触点。键盘、文字可继续使用现有已验证的 UITest 输入路径。[触控实现](https://github.com/yabi-zzh/devhelmkit/blob/05c9bc0f7f9ea763d61c8b4b5d1cfbb076626b00/src/devhelmkit/harmony/driver.py#L687)
|
||||
|
||||
未找到 `Gestures.keyDown`、`Gestures.keyUp` 或 `Gestures.text` 的公开调用依据。普通按键使用 `callHypiumApi`:`Driver.triggerKey` 的 `args` 为 `[keyCode]`;组合键 `Driver.triggerCombineKeys` 为 `[key1,key2]` 或三个键;Home/Back 分别是 `Driver.pressHome` / `Driver.pressBack`、`args:[]`。不要使用不存在的 `Driver.pressKey`。官方 `hypium/uidriver/arkuidriver.py` 声明 `triggerKey`、`triggerCombineKeys`、`pressBack`;其 Home 包装存在 `UiDriver.pressHome` 命名差异,因此仍应按当前设备能力验证客户端使用的 `Driver.pressHome`。[官方 Hypium wheel](https://files.pythonhosted.org/packages/b4/dc/f3b0abf2c518d11d57d8e9487026c133cc7eb0e3479af4b90d13c6db6169/hypium-6.1.0.210-py3-none-any.whl)、[客户端按键调用](https://github.com/yabi-zzh/devhelmkit/blob/05c9bc0f7f9ea763d61c8b4b5d1cfbb076626b00/src/devhelmkit/harmony/driver.py#L712)
|
||||
|
||||
官方 Python 的 `Driver.inputText` 参数为 `[{"x":x,"y":y},"text"]`,有定位输入的语义;它并不是已确认的 `Gestures` 当前光标文字接口。公开客户端对当前焦点使用 `uitest uiInput text <quoted text>`。当前阶段保留已有验证的文字通道,可避免引入未经验证的光标、追加与清空语义。[当前焦点输入](https://github.com/yabi-zzh/devhelmkit/blob/05c9bc0f7f9ea763d61c8b4b5d1cfbb076626b00/src/devhelmkit/harmony/driver.py#L1487)
|
||||
|
||||
停止时在采集连接发送 `method: "Captures"`、`params: {"api":"stopCaptureScreen","args":{}}`,随后关闭 socket、停止本机接收线程、移除本会话转发。若启用设备守护进程清理,仅结束自己创建并持有身份的进程,不使用 `killall uitest`。主机解码与渲染只保留最新完整帧;静止画面没有新帧不应误判断线,可用独立控制通道探活。[停止实现](https://github.com/yabi-zzh/devhelmkit/blob/05c9bc0f7f9ea763d61c8b4b5d1cfbb076626b00/src/devhelmkit/harmony/screenshot_stream.py#L565)
|
||||
|
||||
`startCaptureScreen` 是 agent 提供的 RPC 名称,**不是**设备 `uitest help` 中能直接运行的 CLI 子命令。设备帮助没有它,不证明公开 agent 不能提供它。
|
||||
|
||||
## 画面变化、帧率与保活
|
||||
|
||||
公开 UITest `screen_copy.cpp` 的采集线程调用 `DisplayManager::GetScreenshot`,通过 `memcmp` 比较前后像素,只有变化才通知 JPEG 编码线程。屏幕关闭时提供黑色画面并暂停常规采集,50 ms 的 `usleep` 仅用于检查关闭的屏幕是否重新亮起,**不能据此推算正常采集被限制在 20 fps**。常规采集循环没有显式 fps 计时上限,编码线程取最新帧。商业 agent 未提供其 C++ 源码,此处解释公开 UITest 实现,不能当作官方 v1.2.2 每一项内部行为均相同的证明;本机静止画面不连续发帧与这套行为一致。[变化检测与屏幕关闭](https://github.com/openharmony/testfwk_arkxtest/blob/b04e30c40cf266c9abfbd52933e43a0456eb99a2/uitest/addon/screen_copy.cpp#L153)、[消费最新帧](https://github.com/openharmony/testfwk_arkxtest/blob/b04e30c40cf266c9abfbd52933e43a0456eb99a2/uitest/addon/screen_copy.cpp#L245)
|
||||
|
||||
核查的公开扩展与客户端只暴露 `displayId`、`scale`,没有可据以实现的 fps 或 JPEG quality 参数。`scale` 在获取原屏截图后缩放像素,能降低输出尺寸与编码、传输成本,但不消除原屏截图成本。Devhelmkit 的 `MAX_RECORD_FPS=30` 只约束事后 MP4 合成,与实时采集上限无关。不要把虚构的 `fps:60` 参数加入产品后声称已提速。[缩放位置](https://github.com/openharmony/testfwk_arkxtest/blob/b04e30c40cf266c9abfbd52933e43a0456eb99a2/uitest/addon/screen_copy.cpp#L221)、[实际采集参数](https://github.com/yabi-zzh/devhelmkit/blob/05c9bc0f7f9ea763d61c8b4b5d1cfbb076626b00/src/devhelmkit/harmony/screenshot_stream.py#L670)
|
||||
|
||||
参考客户端的采集 socket 连接后设为阻塞读取,没有周期发送采集心跳;尚无“必须在采集 socket 定期发送心跳”的源码证据。可保留本机读取超时用来检查取消状态,但超时本身不应标为失败;用独立控制连接的 `Driver.getDisplaySize` 区分静态画面与设备失联。若控制连接也无响应、TCP 关闭或 HDC 确认失联,再终止会话。[socket 建立与持续读取](https://github.com/yabi-zzh/devhelmkit/blob/05c9bc0f7f9ea763d61c8b4b5d1cfbb076626b00/src/devhelmkit/harmony/screenshot_stream.py#L651)
|
||||
|
||||
## 两个开源客户端的来源核对
|
||||
|
||||
| 项目 | 本轮源码与文件核对 | 结论 |
|
||||
| --- | --- | --- |
|
||||
| `yabi-zzh/devhelmkit` | Apache 2.0;有连续 JPEG、独立控制 socket、down/move/up 和采集帧率统计;仓库 `agent_v2.so` SHA256 与本次官方 wheel 的 agent 不一致。 | 可参考其客户端协议,不把其未核清来源的 blob 作为发行原件。 |
|
||||
| `yiyifred/Cloud-Phone` | Apache 2.0;包含 `uitest_agent_v1.1.10.so`,其 SHA256 **完全匹配**官方 wheel v1.1.10;`Gestures` 代码注释中的 ECHO/hdckit 指同类 RPC 操作,并不是设备原生内置 H.264 服务。 | 证明实际客户端采用 Hypium agent;其旧 agent/TCP 假设不能直接用于当前设备。 |
|
||||
|
||||
[devhelmkit 许可](https://github.com/yabi-zzh/devhelmkit/blob/05c9bc0f7f9ea763d61c8b4b5d1cfbb076626b00/LICENSE)、[Cloud-Phone agent](https://github.com/yiyifred/Cloud-Phone/blob/98d130b20474cf8b18d51161d3bb0b65472c4778/backend/assets/harmony/uitest_agent_v1.1.10.so)、[Cloud-Phone RPC](https://github.com/yiyifred/Cloud-Phone/blob/98d130b20474cf8b18d51161d3bb0b65472c4778/backend/node/src/services/harmony-cast/uitest-rpc.js)、[Cloud-Phone 许可](https://github.com/yiyifred/Cloud-Phone/blob/98d130b20474cf8b18d51161d3bb0b65472c4778/LICENSE)
|
||||
|
||||
## H.264 与其他路径的边界
|
||||
|
||||
同一官方资源 wheel 包含 `devicetest/res/recorder/libscrcpy_server1.z.so` 到 `libscrcpy_server4.z.so`。其 `controllers/tools/recorder/record_agent.py` 推送为 `/data/local/tmp/libscreen_recorder.z.so`,通过 UITest extension 启动,参数为 `-p <port> -m 1 -screenId <id>`,默认 gRPC 端口 5001;对应 `rpc_manager.py` 和生成的 protobuf 定义含 `ScrcpyService/onStart`、`onEnd`、`onRequestIDRFrame`。当前 Python 调用方主要用于步骤视频,停止后拉取 `mytest.mp4`。**仅凭资源名不能认定它是可直接使用的实时 H.264 投屏服务**;格式、stream payload 与当前固件兼容性仍需专门验证。它不是本轮 JPEG 路线的前置条件。[官方资源 wheel](https://pypi.org/project/xdevice-devicetest/6.1.0.210/)
|
||||
|
||||
设备内置 UITest 公开 CLI 的 screenCap 是单张 PNG,uiRecord 是操作记录,start-daemon 是测试服务入口;不提供已确认的直接视频 stdout 命令。官方系统录屏组件的公开流程是录制后导出文件。对已经确认不存在的 `screenrecord`,不应反复尝试 Android 参数。[UITest 命令](https://github.com/openharmony/docs/blob/f41b9345badd47c7ab0c263344cd7f4b5a549afb/zh-cn/application-dev/application-test/uitest-guidelines.md)、[官方系统录屏](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/ide-screen-recording)
|
||||
|
||||
自编 ELF 的执行权限错误与自编 addon 的 XPM 加载拒绝已由主任务复现;它们不应作为继续尝试关闭 XPM、SELinux、root 或借用私人签名的理由。公开 Hypium 原件是另一条正常工具分发与加载链路,需按原件、版本、协议重新验证。
|
||||
|
||||
## 产品验收与明确未知
|
||||
|
||||
- 当前证据确认公开来源、许可文件、官方选择和加载方式,以及开源客户端连续帧/触控协议;主任务已验证当前手机原件加载、Unix socket、Driver 初始化、JPEG 解码与屏幕尺寸查询。
|
||||
- 初测黑帧只证明连通,仍需设备解锁后的真实内容与交互画面验证;不得把收到 JPEG 等同于已达到 scrcpy 的流畅体验。
|
||||
- 用手机实际动画/滑动测量收到与呈现的帧率,独立记录排队及输入往返;静止画面频率不能当作最大帧率。没有实际结果前不承诺 30/60 fps。
|
||||
- 验证拖动跟手、旋转后的物理坐标、拒绝/断开、停止后不再采集与控制,以及重复启动清理;不影响其他使用 UITest 的工具。
|
||||
- 未确认 `Captures/Gestures` 跨版本稳定性;应固定已验收的 agent,报告能力与错误,避免无提示降为旧截图模式。
|
||||
|
||||
最终用户流程可以保持“连接 USB → 允许调试 → 开始投屏”。官方 agent 的获取、校验、部署、转发和清理应由插件完成,不能再把开发者账号或 HAP 签名作为该流程的要求。
|
||||
@@ -1,5 +1,7 @@
|
||||
# Harmony Connector 实时视频流调研
|
||||
|
||||
> 历史方案记录:本文的 H.264/HAP 实验已停止,实验源码和账号签名流程已移除。当前采用无需用户开发者账号的[官方 Hypium/HDC 路线](harmony-hdc-only-screen.md),状态及验证命令见[持续投屏开发验证](../harmony-realtime-development.md)。下文的早期“无安装”失败仅涉及自编未签名原件,不能推导为必须安装 HAP。
|
||||
|
||||
调研日期:2026-09-10。承接 [投屏与控制调研](harmony-screen-control.md),本篇只核查替换逐张截图链路所需的公开 API、进程授权和构建条件。文献研究与本机集成验证分别记录;尚未验证真机 H.264 视频性能。
|
||||
|
||||
## 结论与实现顺序
|
||||
@@ -140,7 +142,7 @@ devecocli build --modules entry --build-mode debug
|
||||
|
||||
UITest addon 未进入 `OnInit`。随后读取设备日志确认:MUSL-LDSO 报 `Xpm check failed`、`errno for mmap is:13`,UiTestKit_Addon 的 `dlopen` 返回 `Permission denied`。这将本次失败定位到临时未签名模块的加载校验,不能解释为 ABI 不兼容;没有尝试关闭或绕过 XPM。临时程序、模块和手机上的本会话文件均已清理。
|
||||
|
||||
华为公开 LLDB 调试矩阵将 user 镜像、SELinux 开启场景的支持范围列为签名 debug HAP;并区分其与 root 镜像上的普通可执行文件调试。它与上述限制相符,但不能仅凭该文档判定具体拒绝来自 SELinux、代码签名还是其他策略。继续走正常应用签名路径,不以关闭安全策略推进。[华为 Native 调试条件](https://developer.huawei.com/consumer/cn/doc/doccenter-capabilities/debug-lldb)
|
||||
华为公开 LLDB 调试矩阵将 user 镜像、SELinux 开启场景的支持范围列为签名 debug HAP;并区分其与 root 镜像上的普通可执行文件调试。它与上述限制相符,但不能仅凭该文档判定具体拒绝来自 SELinux、代码签名还是其他策略。当时选择了普通应用签名实验;该路线随后已停止,当前改用官方分发且无需用户签名的 Hypium 代理。[华为 Native 调试条件](https://developer.huawei.com/consumer/cn/doc/doccenter-capabilities/debug-lldb)
|
||||
|
||||
## 最小验收
|
||||
|
||||
@@ -156,4 +158,4 @@ UITest addon 未进入 `OnInit`。随后读取设备日志确认:MUSL-LDSO 报
|
||||
|
||||
集成方已创建普通手机应用 `ink.render.trove.harmonyconnector`,实现系统授权的 Surface 采集、H.264 编码、带会话校验的 loopback TCP 和停止收尾。官方 CLI 已成功构建 ArkTS 与 arm64-v8a native 模块并生成未签名 HAP。独立 Mac 接收器的 8 项测试通过,其中生成的 20 帧视频经过真实 H.264 解码全部返回。
|
||||
|
||||
官方 CLI 登录成功,但签名预检返回账号尚未完成开发者实名认证,未生成真机可安装的调试签名。因此未安装组件、未取得手机视频流,插件播放器集成、旋转重建和端到端时延验收仍未完成。源码和可复现命令见[开发验证说明](../harmony-realtime-development.md)。
|
||||
最初签名预检被账号认证状态阻塞;用户认证并刷新官方授权后,曾成功生成正常调试签名、构建并安装 HAP,收到首个 H.264 帧。接收器在第一帧统计时发生除零错误,故没有取得持续帧率或端到端延迟结果。随后按用户要求停止 HAP 路线,实验源码已从主分支移除;历史实现保留于提交 `ca382e6`。当前无需账号的实现和验证状态见[开发验证说明](../harmony-realtime-development.md)。
|
||||
|
||||
Reference in New Issue
Block a user