头部追踪器 HID 协议

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

设备制造商必须配置其 Android 设备,以启用对头部跟踪器 HID 协议的支持。如需详细了解配置,请参阅动态传感器 README

本页假定您熟悉以下资源

顶层结构

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

如需查看有效 HID 描述符的完整示例,请参阅附录 1:HID 描述符示例

在顶层,头部跟踪器设备是一个应用合集,其中包含 Sensors 页面 (0x20) 和其他:自定义用法 (0xE1)。此合集内部包含多个数据字段(输入)和属性(功能)。

属性和数据字段

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

属性:传感器描述 (0x0308)

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

头部跟踪器版本 1.0

#AndroidHeadTracker#1.0

头部跟踪器版本 2.0(在 Android 15 或更高版本中提供),其中包括对 LE 音频的支持

#AndroidHeadTracker#2.0#x

x 是一个整数 (123),表示支持的传输方式

  • 1:ACL
  • 2:ISO
  • 3:ACL + ISO

不应有 null 终止符,这意味着对于版本 1.0,此属性的总大小为 23 个 8 位字符。

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

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

持久唯一 ID (0x0302) 属性是一个包含 16 个元素(每个元素 8 位,总共 128 位)的只读数组。不应有 null 终止符。此属性是可选的。

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

独立头部跟踪器

如果持久唯一 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 B T 蓝牙 MAC

在此方案中,前 8 个八位字节必须为 0,第 8 和第 9 个八位字节必须分别包含 ASCII 值 BT,接下来的 6 个八位字节将被解释为蓝牙 MAC 地址,前提是头部跟踪器设备适用于任何具有此 MAC 地址的音频设备。即使设备使用随机 MAC 地址建立连接,此地址也必须是身份地址。通过蓝牙经典 (v1.0 HID 格式) 和蓝牙 LE (v2.0 HID 格式) 连接的双模设备必须公开两个具有相同身份地址的 HID 描述符。具有分离的左右设备的双模设备必须使用主双模设备而不是仅 LE 的辅助设备公开蓝牙 LE HID。

使用 UUID 引用

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

属性:报告状态 (0x0316)

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

此字段的初始值必须为“无事件”,并且绝不能由设备修改,只能由主机修改。

属性:电源状态 (0x0319)

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

此字段的初始值由设备确定,并且绝不能由设备修改,只能由主机修改。

属性:报告间隔 (0x030E)

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

属性:供应商保留的 LE 传输 (0xF410)

供应商保留的 LE 传输 (0xF410) 属性是读/写属性,具有 HID 规范中定义的标准语义。主机使用此属性指示选定的传输方式(ACL 或 ISO)。仅使用 ACL (0xF800) 和 ISO (0xF801) 值,并且两者都必须包含在逻辑合集中。

此属性在电源或报告状态之前配置。

数据字段:自定义值 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 消息)发送输入报告

  • 电源状态属性设置为“全功率”。
  • 报告状态属性设置为“所有事件”。
  • 报告间隔属性为非零值。

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

向前和向后兼容性

头部跟踪器 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,
};

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

附录: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,
};

附录 2:v2.0 HID 描述符示例

以下示例说明了仅支持蓝牙 LE ACL 传输的设备的 v2.0 HID 描述符。

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#2.0#1"
        HID_USAGE_SENSOR_PROPERTY_SENSOR_DESCRIPTION,
        HID_LOGICAL_MIN_8(0),
        HID_LOGICAL_MAX_8(0xFF),
        HID_REPORT_SIZE(8),
        HID_REPORT_COUNT(25),
        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),

        // 1-bit transport selection
        HID_USAGE_SENSOR_PROPERTY_VENDOR_LE_TRANSPORT,
        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_VENDOR_LE_TRANSPORT_ACL,
            HID_USAGE_SENSOR_PROPERTY_VENDOR_LE_TRANSPORT_ISO,
            HID_FEATURE(HID_DATA_ARR_ABS),
        HID_END_COLLECTION,

        // 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,
};