头部跟踪器人机接口设备 (HID) 协议适用于搭载 Android 13 及更高版本的设备。借助该协议,头部跟踪设备可通过 USB 或蓝牙连接到 Android 设备,并通过传感器框架提供给 Android 框架和应用。此协议用于控制音频虚拟器效果(3D 音频)。本页中蓝牙方面的内容使用了词语“设备”和“主机”,其中“设备”指头部跟踪设备,“主机”指 Android 主机。
设备制造商必须在其 Android 设备配置中支持头部跟踪器 HID 协议。如需详细了解配置,请参阅动态传感器自述文件。
本页面假定您熟悉以下资源:
顶级结构
Android 框架将头部跟踪器设备识别为 HID 设备。
如需查看有效 HID 描述符的完整示例,请参阅附录 1:HID 描述符示例。
在顶层,头部跟踪器设备是一个具有 Sensors
页面 (0x20
) 和 Other: Custom
用法 (0xE1
) 的应用集合。此集合中包含多个数据字段(输入)和属性(功能)。
属性和数据字段
本部分将介绍头部跟踪器设备的应用集合中的属性和数据字段。
属性:Sensor Description (0x0308
)
“Sensor Description”(0x0308
) 属性是只读 ASCII(8 位)字符串属性,必须包含以下值:
#AndroidHeadTracker#1.0
预计不会出现 null 终止符,这意味着此属性的总大小为 23 个 8 位字符。
此属性起到判别器的作用,用于避免与其他自定义传感器发生冲突。
属性:Persistent Unique ID (0x0302
)
“Persistent Unique ID”(0x0302
) 属性是包含 16 个元素的只读数组,每个元素 8 位(总计 128 位)。预计不会出现 null 终止符。该属性是可选属性。
此属性允许集成在音频设备中的头部跟踪器设备引用其连接的音频设备。 支持以下方案。
独立头部跟踪器
如果“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 | B | T | 蓝牙 MAC |
在该方案中,前 8 个八位字节必须为 0
,八位字节 8 和 9 必须分别包含 ASCII 值 B
和 T
,并且后面的 6 个八位字节将解释为蓝牙 MAC 地址(假设头部跟踪器设备适用于任何使用此 MAC 地址的音频设备)。
使用 UUID 进行引用
每当设置八位字节 8 的最高有效位 (MSB) 时≥0x80
,该字段将被解释为 UUID,如 RFC-4122 中所指定。相应的音频设备通过特定于所用传输类型的未指定机制,提供在 Android 框架上注册的那个 UUID。
属性:Reporting State (0x0316
)
“Reporting State”(0x0316
) 属性是一项具有 HID 规范中定义的标准语义的读取/写入属性。主机使用此属性向设备指明要报告哪些事件。仅使用“No Events”(0x0840
) 和“All Events”(0x0841
) 值。
此字段的初始值必须为“No Events”,且绝不能由设备修改,只能由主机修改。
属性:Power State (0x0319
)
“Power State”(0x0319
) 属性是一项具有 HID 规范中定义的标准语义的读取/写入属性。主机使用此属性向设备指明其必须处于哪个电源状态。仅使用“Full Power”(0x0851
) 和“Power Off”(0x0855
) 值。
此字段的初始值由设备决定,且绝不能由设备修改,只能由主机修改。
属性:Report Interval (0x030E
)
“Report Interval”(0x030E
) 属性是一项具有 HID 规范中定义的标准语义的读取/写入属性。主机使用此属性向设备指明报告其数据读数的频率。
单位为秒。此值的有效范围由设备决定,并使用 Physical Min/Max 机制进行描述。必须支持至少 50 Hz 报告速率,并且建议的最高报告速率为 100 Hz。因此,最短报告间隔必须小于或等于 20 毫秒,建议大于或等于 10 毫秒。
数据字段:Custom Value 1 (0x0544
)
“Custom Value 1”(0x0544
) 字段是用于报告实际头部跟踪信息的输入字段。这是一个包含 3 个元素的数组,根据 HID 规范第 6.2.2.7 节中针对物理值的常规 HID 规则进行解释。每个元素的有效范围是 [-π, π] rad。单位始终为弧度。
这些元素被解释为:[rx, ry, rz]
,这样 [rx, ry, rz]
就是一个旋转矢量,表示从参考系到头部坐标系的转换。向量大小必须在 [0..π] 范围内。
参考系是任意的,但通常是固定的,必须为右手坐标系。可接受少量偏移。头部坐标轴如下:
- X:从左耳到右耳
- Y:从头部背面到鼻子(从后往前)
- Z:从颈部到头顶
数据字段:Custom Value 2 (0x0545
)
“Custom Value 2”(0x0545
) 字段是用于报告实际头部跟踪信息的输入字段。这是一个包含 3 个元素的定点数组,会根据物理值的常规 HID 规则进行解释。单位始终为弧度/秒。
这些元素被解释为:[vx, vy, vz]
,这样 [vx, vy, vz]
就是一个旋转矢量,表示头部坐标系的角速度(相对于其自身)。
数据字段:Custom Value 3 (0x0546
)
Custom Value 3 (0x0546
) 字段是用于跟踪参考系中不连续情况的输入字段。它是一个大小为 8 位的标量整数。每当参考系发生变化时(例如,用于确定方向的方向滤波器算法将其状态重置时),设备都必须递增(循环)该整数。此值根据物理值的常规 HID 规则进行解释。不过,物理值和单位无关紧要。与主机有关的唯一信息是已更改的值。为避免在从逻辑单位转换为物理单位时发生与精度损失相关的数值问题,建议将此字段的物理最小值、物理最大值和单位指数值设为零。
报告结构
您可以灵活地将属性分组加入报告中(通过分配报告 ID)。为了提高效率,我们建议将只读属性与读取/写入属性分开。
对于数据字段,“Custom Value 1”“Custom Value 2”和“Custom Value 3”字段必须在同一报告中,并必须在一部给定设备的一个报告中(应用集合)。
发送输入报告
当满足所有这些条件时,设备必须定期异步(通过 HID INPUT 消息)发送输入报告:
- “Power State”属性设为“Full Power”。
- “Reporting State”属性设为“All Events”。
- “Reporting Interval”属性为非零值。
“Reporting Interval”属性用于确定报告的发送频率。如果上述条件有任一条不符合,设备不得发送任何报告。
向前和向后兼容性
头部跟踪器 HID 协议采用的版本控制方案允许更新,同时允许主机与使用该协议不同版本的设备之间互操作。该协议的版本由两个数字标识(主版本号和次版本号),数字具有不同的语义,如以下部分所述。
您可以通过检查“Sensor Description”(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,
};
在这种情况下,主机可以枚举设备通告的所有不同应用集合,检查其 Sensor Description 属性以确定各个集合实现的协议版本,然后选择主机支持的最新协议版本。选择后,主机会在设备连接的整个生命周期内都使用所选的单个协议。
附录: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,
};