4、分布式硬件接口开发:分布式硬件接口API、设备能力集查询、硬件资源调用示例

好,咱们进入正题。分布式硬件接口开发,说白了就是让鸿蒙系统里的各个设备能互相“打招呼”,然后调用对方的硬件资源。比如手机调用平板的摄像头,手表调用手机的扬声器——这些都不是魔法,背后就是一套API在干活。

我个人习惯把分布式硬件接口分成三层来看:发现层、能力层、调用层。发现层负责找到设备,能力层负责问清楚“你能干啥”,调用层才是真正用起来。今天咱们重点讲后两层。

4.1 分布式硬件接口API概览

鸿蒙提供的分布式硬件API,核心就几个头文件。我刚开始接触时也被一堆接口搞晕过,后来发现常用的其实不超过10个。

API名称 功能说明 使用场景
GetDeviceCapability() 查询远端设备的能力集 调用前必查,避免“拿不到”
OpenRemoteHardware() 打开远端硬件资源 摄像头、麦克风等
CloseRemoteHardware() 关闭远端硬件资源 用完必须释放
RegisterHardwareCallback() 注册硬件状态回调 监听设备插拔、状态变化

嗯,这里要注意:所有分布式硬件调用都是异步的。你想想看,网络有延迟,设备可能突然掉线,如果搞成同步阻塞,那用户体验就崩了。所以API设计上,回调函数是标配。

核心原则:先查能力,再调资源。跳过查询直接调用,是我见过最多的翻车现场。

4.2 设备能力集查询

设备能力集,说白了就是一份“设备简历”。上面写着:我有摄像头,分辨率最高1080p;我有扬声器,支持AAC编码;我有陀螺仪,采样率200Hz。

为什么要查这个?我在项目中遇到过这么个事:手机想调用平板的摄像头拍文档,结果平板摄像头只有200万像素,拍出来根本看不清。如果提前查了能力集,就能提示用户“当前设备摄像头分辨率不足”。

查询接口长这样:

// 查询远端设备能力集
int32_t ret = GetDeviceCapability(deviceId, &capability);
if (ret != 0) {
    // 查询失败,可能是设备离线了
    printf("查询能力集失败,错误码:%d\n", ret);
    return;
}

// 解析能力集
if (capability.hasCamera) {
    printf("摄像头分辨率:%dx%d\n", 
           capability.cameraWidth, 
           capability.cameraHeight);
}

if (capability.hasSpeaker) {
    printf("扬声器编码格式:%s\n", 
           capability.speakerCodec);
}

能力集的数据结构,我一般会重点关注这几个字段:

  • hasCamera / hasMic / hasSpeaker —— 有没有这个硬件
  • cameraWidth / cameraHeight —— 摄像头分辨率上限
  • speakerCodec —— 扬声器支持的音频编码
  • sensorType —— 传感器类型列表(加速度、陀螺仪等)

小技巧:能力集查询结果建议缓存起来。每次调用都查一遍,网络开销不小。我一般会在设备连接成功后查一次,然后监听设备状态变化事件,只有变化时才重新查询。

4.3 硬件资源调用示例

好,到了最激动人心的部分——真正调用远端硬件。咱们拿“手机调用平板的摄像头拍照”这个场景来演示。

第一步,打开远端摄像头:

// 打开远端摄像头
RemoteHardwareParam param;
param.deviceId = targetDeviceId;
param.hardwareType = HARDWARE_CAMERA;
param.callback = OnCameraFrameCallback;

int32_t handle = OpenRemoteHardware(¶m);
if (handle < 0) {
    printf("打开远端摄像头失败\n");
    return;
}

第二步,注册帧回调,接收摄像头数据:

// 帧回调函数
void OnCameraFrameCallback(const FrameData* frame, void* context) {
    if (frame == NULL) {
        printf("帧数据为空,可能设备断连\n");
        return;
    }
    
    // 处理图像数据
    // 比如保存到本地,或者实时显示
    ProcessImage(frame->data, frame->size, frame->width, frame->height);
}

第三步,用完记得关闭:

// 关闭远端摄像头
int32_t ret = CloseRemoteHardware(handle);
if (ret != 0) {
    printf("关闭失败,但别慌,系统会自动回收\n");
}

警告:我曾经因为忘记关闭远端摄像头,导致平板摄像头一直被占用,其他应用打不开。分布式资源不像本地资源,系统回收有延迟。所以一定要在合适的时机(比如页面销毁、用户退出)主动关闭。

4.4 避坑指南

做分布式硬件开发,坑不少。我踩过的几个典型:

  • 设备突然离线:调用过程中设备断连,回调会收到空指针。一定要做空值检查,否则直接崩溃。
  • 权限问题:远端设备也需要申请对应权限。比如调用远端摄像头,远端设备上必须已经授予了相机权限。
  • 性能开销:视频流传输很吃带宽。1080p 30fps的视频流,WiFi环境下勉强能跑,4G网络就卡成PPT了。建议根据网络质量动态调整分辨率。

嗯,最后说一句:分布式硬件开发,本质上就是远程过程调用 + 资源管理。把本地硬件调用的经验迁移过来,再注意一下网络异常处理,基本就能上手了。下一章咱们会讲更高级的——如何实现硬件资源的动态迁移,比如手机没电了,自动把摄像头调用切换到平板上。