頭部追蹤器 HID 協定

頭部追蹤人機介面裝置 (HID) 通訊協定適用於搭載 Android 13 以上版本的裝置,可讓頭部追蹤裝置透過 USB 或藍牙連線至 Android 裝置,並透過 sensors 架構公開至 Android 架構和應用程式。這個通訊協定可用來控制音訊虛擬化效果 (3D 音訊)。本頁面使用「裝置」和「主機」一詞,指的是藍牙裝置,其中「裝置」是指頭部追蹤裝置,「主機」則是指 Android 主機。

裝置製造商必須設定 Android 裝置,才能支援頭戴式追蹤器 HID 通訊協定。如要進一步瞭解設定,請參閱 Dynamic Sensors README

本頁面假設您熟悉下列資源:

頂層結構

Android 架構會將頭部追蹤器裝置視為 HID 裝置。

如需有效 HID 描述元的完整範例,請參閱附錄 1:HID 描述元範例

在頂層,頭戴式追蹤裝置是應用程式集合,其中包含 Sensors 頁面 (0x20) 和 Other: Custom 用途 (0xE1)。這個集合內含多個資料欄 (輸入內容) 和資源 (功能)。

屬性和資料欄位

本節說明頭部追蹤工具裝置應用程式集合的屬性和資料欄位。

屬性:感應器說明 (0x0308)

感應器說明 (0x0308) 屬性是只讀 ASCII (8 位元) 字串屬性,必須包含下列值:

Head Tracker 1.0 版:

#AndroidHeadTracker#1.0

頭戴式追蹤器 2.0 版 (適用於 Android 15 以上版本),其中包括 LE 音訊支援:

#AndroidHeadTracker#2.0#x

x 是整數 (123),表示支援傳輸:

  • 1:存取控制清單 (ACL)
  • 2:ISO
  • 3:ACL + ISO

系統不會預期空值終止符,也就是說,在 1.0 版中,這個屬性的總大小為 23 個 8 位元字元。

這項屬性可做為區別器,避免與其他自訂感應器發生衝突。

資源:永久專屬 ID (0x0302)

永久專屬 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 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,系統就會依 RFC-4122 的規定,將欄位解讀為 UUID。對應的音訊裝置會提供相同的 UUID,並透過特定傳輸類型的不明機制,在 Android 架構上註冊。

屬性:報表狀態 (0x0316)

回報狀態 (0x0316) 屬性為讀取/寫入屬性,具有符合 HID 規格的標準語意。主機會利用這項屬性,向裝置指明要回報的事件。系統只會使用「No Events」(0x0840) 和「All Events」(0x0841) 的值。

這個欄位的初始值不得為「無事件」,且不得由裝置修改,只能由主機修改。

屬性:電源狀態 (0x0319)

電源狀態 (0x0319) 屬性是讀/寫屬性,具有 HID 規格中定義的標準語意。主機會使用這項屬性來指示裝置必須處於哪個電源狀態。僅使用 Full Power (0x0851) 和 Power Off (0x0855) 值。

這個欄位的初始值由裝置決定,且絕對不能由裝置修改,只能由主機修改。

資源:報表間隔 (0x030E)

「Report Interval」(0x030E) 屬性是讀/寫屬性,具有 HID 規格中定義的標準語義。主機會使用這個屬性,向裝置指出要多久回報一次資料讀數。單位為秒。這個值的有效範圍由裝置決定,並使用 Physical Min/Max 機制說明。必須支援至少 50 Hz 的回報率,建議回報率上限為 100 Hz。因此,最小回報間隔必須小於或等於 20 毫秒,建議大於或等於 10 毫秒。

屬性:供應商保留的 LE 傳輸 (0xF410)

供應商保留的 LE Transport (0xF410) 屬性是一個讀取/寫入屬性,具有符合 HID 規格中定義的標準語意。主機會使用這項屬性,指出所選的傳輸方式 (ACL 或 ISO)。系統只會使用值 ACL (0xF800) 和 ISO (0xF801),而且這兩者都必須加入邏輯集合。

這項屬性會在電源或回報狀態之前設定。

資料欄位:自訂值 1 (0x0544)

自訂值 1 (0x0544) 欄位是用於回報實際頭部追蹤資訊的輸入欄位。這是一個 3 元素陣列,會根據 HID 規格第 6.2.2.7 節所述的一般 HID 規則,解讀物理值。每個元素的有效範圍為 [-π, π] 弧度。單位一律為弧度。

這些元素會解讀為:[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,
};

在此情況下,主機可以列舉裝置通告的所有不同應用程式集合,檢查感應器說明屬性,判斷每個實作的通訊協定版本,然後挑選主機支援的最新通訊協定版本。選取後,主機會使用在裝置連線期間所選的單一通訊協定。

附錄: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 傳輸的裝置適用的 2.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,
};