头部追踪器 HID 协议

头部跟踪器人机接口设备 (HID) 协议适用于运行 Android 13 及更高版本的设备,允许头部跟踪设备通过 USB 或蓝牙连接到 Android 设备,并通过传感器暴露给 Android 框架和应用程序框架。该协议用于控制音频虚拟器效果(3D 音频)。本页使用蓝牙意义上的设备主机这两个术语,其中设备表示头部跟踪设备,主机表示 Android 主机。

设备制造商必须配置其 Android 设备以启用对头部跟踪器 HID 协议的支持。有关配置的更多详细信息,请参阅动态传感器自述文件

此页面假定您熟悉以下资源:

顶层结构

Android 框架将头部跟踪设备识别为 HID 设备。

有关有效 HID 描述符的完整示例,请参阅附录 1:HID 描述符示例

在顶层,头部跟踪器设备是一个应用程序集合,其中包含Sensors页面 ( 0x20 ) 和Other: Custom使用 ( 0xE1 )。这个集合里面有几个数据字段(输入)和属性(特性)。

属性和数据字段

本节介绍头部跟踪设备的应用程序集合中的属性和数据字段。

属性:传感器描述( 0x0308

传感器描述 ( 0x0308 ) 属性是只读 ASCII(8 位)字符串属性,必须包含以下值:

#AndroidHeadTracker#1.0

不需要空终止符,这意味着此属性的总大小为 23 个 8 位字符。

此属性用作鉴别器,以避免与其他自定义传感器发生冲突。

属性:持久唯一 ID ( 0x0302 )

Persistent Unique ID ( 0x0302 ) 属性是一个只读数组,包含 16 个元素,每个元素 8 位(总共 128 位)。预计没有空终止符。该属性是可选的。

此属性允许集成在音频设备中的头部跟踪设备引用它们所连接的音频设备。支持以下方案。

独立头部追踪器

如果 Persistent Unique ID ( 0x0302 ) 属性不存在或设置为全零,则意味着头部跟踪器设备并未永久连接到音频设备,并且可以单独使用,例如,让用户手动将头部跟踪器设备与单独的音频设备相关联。

使用蓝牙MAC地址参考

八位字节0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
价值0 0 0 0 0 0 0 0蓝牙 MAC

在此方案中,前 8 个八位字节必须为0 ,八位字节 8 和 9 必须分别包含 ASCII 值BT ,接下来的 6 个八位字节被解释为蓝牙 MAC 地址,假设头部跟踪器设备适用于任何具有这个 MAC 地址。

使用 UUID 引用

每当设置八位字节的最高有效位 (MSB) ( ≥0x80 ) 时,该字段就被解释为 UUID,如RFC-4122中所指定。相应的音频设备通过特定于所用传输类型的未指定机制提供相同的 UUID,该 UUID 在 Android 框架上注册。

属性:报告状态( 0x0316

报告状态 ( 0x0316 ) 属性是具有 HID 规范中定义的标准语义的读/写属性。主机使用此属性向设备指示要报告哪些事件。仅使用值 No Events ( 0x0840 ) 和 All Events ( 0x0841 )。

此字段的初始值必须为 No Events,并且不得由设备修改,只能由主机修改。

属性:电源状态 ( 0x0319 )

电源状态 ( 0x0319 ) 属性是一个读/写属性,具有 HID 规范中定义的标准语义。主机使用此属性向设备指示它必须处于哪种电源状态。仅使用值 Full Power ( 0x0851 ) 和 Power Off ( 0x0855 )。

该字段的初始值由设备确定,决不能由设备修改,只能由主机修改。

属性:报告间隔( 0x030E

报告间隔 ( 0x030E ) 属性是具有 HID 规范中定义的标准语义的读/写属性。主机使用此属性向设备指示报告其数据读数的频率。单位是秒。此值的有效范围由设备确定,并使用物理最小值/最大值机制进行描述。必须支持至少 50 Hz 的上报速率,建议的最大上报速率为 100 Hz。因此,最小上报间隔必须小于等于20ms,建议大于等于10ms。

数据字段:自定义值 1 ( 0x0544 )

自定义值 1 ( 0x0544 ) 字段是用于报告实际头部跟踪信息的输入字段。它是一个 3 元素数组,根据 HID 规范第 6.2.2.7 节中指定的物理值的正常 HID 规则进行解释。每个元素的有效范围是 [-π, π] rad。单位总是弧度。

元素被解释为: [rx, ry, rz] ,使得[rx, ry, rz]是一个旋转向量,表示从参考帧到头帧的变换。幅度必须在 [0..π] 范围内。

参考系是任意的,但它通常是固定的并且必须是右手的。少量的漂移是可以接受的。头轴是:

  • X 从左耳到右耳
  • Y 从后脑勺到鼻子(从后到前)
  • Z 从脖子到头顶

数据字段:自定义值 2 ( 0x0545 )

自定义值 2 ( 0x0545 ) 字段是用于报告实际头部跟踪信息的输入字段。它是一个 3 元素定点数组,根据物理值的正常 HID 规则进行解释。单位总是弧度/秒。

元素被解释为: [vx, vy, vz] ,使得[vx, vy, vz]是一个旋转向量,表示头部框架的角速度(相对于自身)。

数据字段:自定义值 3 ( 0x0546 )

自定义值 3 ( 0x0546 ) 字段是用于跟踪参考帧中的不连续性的输入字段。它是一个 8 位的标量整数。每次更改参考系时,设备必须将其递增(使用环绕),例如,如果用于确定方向的方向过滤器算法重置其状态。此值根据物理值的正常 HID 规则进行解释。但是,物理值和单位并不重要。与主机相关的唯一信息是更改的值。为避免在从逻辑单位转换为物理单位时与精度损失相关的数字问题,建议将此字段的物理最小值、物理最大值和单位指数的值设置为零。

报告结构

将属性分组到报告中(通过分配报告 ID)是灵活的。为了提高效率,我们建议将只读属性与读/写属性分开。

对于数据字段,自定义值 1、2 和 3 字段必须在同一个报告中,并且只在给定设备(应用程序集合)的一个报告中。

发送输入报告

当满足以下所有条件时,设备必须定期和异步(通过 HID INPUT 消息)发送输入报告:

  • Power State 属性设置为 Full Power。
  • 报告状态属性设置为所有事件。
  • 报告间隔属性不为零。

报告间隔属性确定发送报告的频率。不满足上述任一条件时,设备不得发送任何报告。

向前和向后兼容性

头部跟踪器 HID 协议使用允许更新的版本控制方案,同时允许使用不同版本协议的主机和设备之间的互操作性。协议的版本由两个数字标识,主要和次要,它们具有不同的语义,如以下部分所述。

设备支持的版本可以通过检查其传感器描述 ( 0x0308 ) 属性来确定。

次要版本兼容性

对次要版本的更改与基于相同主要版本的早期次要版本向后兼容。在次要版本的更新中,主机会忽略其他数据字段和属性。例如,使用协议版本 1.6 的设备与支持协议版本 1.x(包括版本 1.5)的主机兼容。

主要版本兼容性

对主要版本的更改允许进行非向后兼容的更改。为了支持多个主要版本与新旧主机的互操作性,设备可以在其报告描述符中指定多个应用程序集合。例如:

const unsigned char ReportDescriptor[] = {
    HID_USAGE_PAGE_SENSOR,
    HID_USAGE_SENSOR_TYPE_OTHER_CUSTOM,

    HID_COLLECTION(HID_APPLICATION),
        // Feature report 2 (read-only).
        HID_REPORT_ID(2),

        // Magic value: "#AndroidHeadTracker#1.5"
        HID_USAGE_SENSOR_PROPERTY_SENSOR_DESCRIPTION,
        HID_LOGICAL_MIN_8(0),
        HID_LOGICAL_MAX_8(0xFF),
        HID_REPORT_SIZE(8),
        HID_REPORT_COUNT(23),
        HID_FEATURE(HID_CONST_VAR_ABS),

      ...

    HID_END_COLLECTION,

    HID_COLLECTION(HID_APPLICATION),
        // Feature report 12 (read-only).
        HID_REPORT_ID(12),

        // Magic value: "#AndroidHeadTracker#2.4"
        HID_USAGE_SENSOR_PROPERTY_SENSOR_DESCRIPTION,
        HID_LOGICAL_MIN_8(0),
        HID_LOGICAL_MAX_8(0xFF),
        HID_REPORT_SIZE(8),
        HID_REPORT_COUNT(23),
        HID_FEATURE(HID_CONST_VAR_ABS),

      ...

    HID_END_COLLECTION,
};

在这种情况下,主机可以枚举设备发布的所有不同应用程序集合,检查其传感器描述属性以确定它们各自实现的协议版本,然后选择主机支持的最新协议版本。选择后,主机将使用为设备连接的生命周期选择的单一协议。

附录 1:HID 描述符示例

以下示例说明了一个典型的有效 HID 描述符。它使用HID 传感器用法(第 4.1 节)中提供的常用 C 宏。

const unsigned char ReportDescriptor[] = {
    HID_USAGE_PAGE_SENSOR,
    HID_USAGE_SENSOR_TYPE_OTHER_CUSTOM,
    HID_COLLECTION(HID_APPLICATION),
        // Feature report 2 (read-only).
        HID_REPORT_ID(2),

        // Magic value: "#AndroidHeadTracker#1.0"
        HID_USAGE_SENSOR_PROPERTY_SENSOR_DESCRIPTION,
        HID_LOGICAL_MIN_8(0),
        HID_LOGICAL_MAX_8(0xFF),
        HID_REPORT_SIZE(8),
        HID_REPORT_COUNT(23),
        HID_FEATURE(HID_CONST_VAR_ABS),

        // UUID.
        HID_USAGE_SENSOR_PROPERTY_PERSISTENT_UNIQUE_ID,
        HID_LOGICAL_MIN_8(0),
        HID_LOGICAL_MAX_8(0xFF),
        HID_REPORT_SIZE(8),
        HID_REPORT_COUNT(16),
        HID_FEATURE(HID_CONST_VAR_ABS),

        // Feature report 1 (read/write).
        HID_REPORT_ID(1),

        // 1-bit on/off reporting state.
        HID_USAGE_SENSOR_PROPERTY_REPORTING_STATE,
        HID_LOGICAL_MIN_8(0),
        HID_LOGICAL_MAX_8(1),
        HID_REPORT_SIZE(1),
        HID_REPORT_COUNT(1),
        HID_COLLECTION(HID_LOGICAL),
            HID_USAGE_SENSOR_PROPERTY_REPORTING_STATE_NO_EVENTS,
            HID_USAGE_SENSOR_PROPERTY_REPORTING_STATE_ALL_EVENTS,
            HID_FEATURE(HID_DATA_ARR_ABS),
        HID_END_COLLECTION,

        // 1-bit on/off power state.
        HID_USAGE_SENSOR_PROPERTY_POWER_STATE,
        HID_LOGICAL_MIN_8(0),
        HID_LOGICAL_MAX_8(1),
        HID_REPORT_SIZE(1),
        HID_REPORT_COUNT(1),
        HID_COLLECTION(HID_LOGICAL),
            HID_USAGE_SENSOR_PROPERTY_POWER_STATE_D4_POWER_OFF,
            HID_USAGE_SENSOR_PROPERTY_POWER_STATE_D0_FULL_POWER,
            HID_FEATURE(HID_DATA_ARR_ABS),
        HID_END_COLLECTION,

        // 6-bit reporting interval, with values [0x00..0x3F] corresponding to [10ms..100ms].
        HID_USAGE_SENSOR_PROPERTY_REPORT_INTERVAL,
        HID_LOGICAL_MIN_8(0x00),
        HID_LOGICAL_MAX_8(0x3F),
        HID_PHYSICAL_MIN_8(10),
        HID_PHYSICAL_MAX_8(100),
        HID_REPORT_SIZE(6),
        HID_REPORT_COUNT(1),
        HID_USAGE_SENSOR_UNITS_SECOND,
        HID_UNIT_EXPONENT(0xD),  // 10^-3
        HID_FEATURE(HID_DATA_VAR_ABS),

        // Input report 1

        // Orientation as rotation vector (scaled to [-pi..pi] rad).
        HID_USAGE_SENSOR_DATA_CUSTOM_VALUE_1,
        HID_LOGICAL_MIN_16(0x01, 0x80), // LOGICAL_MINIMUM (-32767)
        HID_LOGICAL_MAX_16(0xFF, 0x7F), // LOGICAL_MAXIMUM (32767)
        HID_PHYSICAL_MIN_32(0x60, 0x4F, 0x46, 0xED),  // -314159265
        HID_PHYSICAL_MAX_32(0xA1, 0xB0, 0xB9, 0x12),  // 314159265
        HID_UNIT_EXPONENT(0x08),  // 10^-8
        HID_REPORT_SIZE(16),
        HID_REPORT_COUNT(3),
        HID_INPUT(HID_DATA_VAR_ABS),

        // Angular velocity as rotation vector (scaled to [-32..32] rad/sec).
        HID_USAGE_SENSOR_DATA_CUSTOM_VALUE_2,
        HID_LOGICAL_MIN_16(0x01, 0x80), // LOGICAL_MINIMUM (-32767)
        HID_LOGICAL_MAX_16(0xFF, 0x7F), // LOGICAL_MAXIMUM (32767)
        HID_PHYSICAL_MIN_8(0xE0),
        HID_PHYSICAL_MAX_8(0x20),
        HID_UNIT_EXPONENT(0x00),  // 10^0
        HID_REPORT_SIZE(16),
        HID_REPORT_COUNT(3),
        HID_INPUT(HID_DATA_VAR_ABS),

        // Reference frame reset counter.
        HID_USAGE_SENSOR_DATA_CUSTOM_VALUE_3,
        HID_LOGICAL_MIN_16(0x00, 0x00), // LOGICAL_MINIMUM (0)
        HID_LOGICAL_MAX_16(0xFF, 0x00), // LOGICAL_MAXIMUM (255)
        HID_PHYSICAL_MIN_8(0x00),
        HID_PHYSICAL_MAX_8(0x00),
        HID_UNIT_EXPONENT(0x00),  // 10^0
        HID_REPORT_SIZE(8),
        HID_REPORT_COUNT(1),
        HID_INPUT(HID_DATA_VAR_ABS),

    HID_END_COLLECTION,
};