頭戴式追蹤器 HID 通訊協定

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

裝置製造商必須設定 Android 裝置,才能支援頭部追蹤器 HID 通訊協定。如要進一步瞭解設定,請參閱動態感應器 README

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

頂層結構

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

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

在頂層,頭部追蹤器裝置是應用程式集合,包含 Sensors 頁面 (0x20) 和 Other: Custom 使用情形 (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

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

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

屬性:永久不重複 ID (0x0302)

「Persistent Unique ID」(永久不重複 ID) (0x0302) 屬性是 16 個元素的唯讀陣列,每個元素 8 位元 (總共 128 位元)。系統不會預期有空值終止符。這是選用屬性。

這項屬性可讓整合至音訊裝置的頭部追蹤裝置,參照所連結的音訊裝置。系統支援下列配置。

獨立頭部追蹤器

如果「永久不重複 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 格式) 和藍牙低功耗 (v2.0 HID 格式) 連線的雙模裝置必須公開兩個 HID 描述元,且兩者具有相同的身分位址。左右耳機分開的雙模裝置必須使用主要雙模裝置公開顯示 Bluetooth LE HID,而非僅支援 LE 的次要裝置。

使用 UUID 參照

只要將八位元組 8 的最高有效位元 (MSB) 設為 (≥0x80),該欄位就會解讀為 UUID,如 RFC-4122 所述。相應的音訊裝置會透過未指定的機制 (視使用的傳輸類型而定),提供在 Android 架構中註冊的相同 UUID。

屬性:報表狀態 (0x0316)

「回報狀態」(0x0316) 屬性是讀取/寫入屬性,具有 HID 規格中定義的標準語意。主機會使用這項屬性向裝置指出要回報哪些事件。系統只會使用「沒有事件」(0x0840) 和「所有事件」(0x0841) 這兩個值。

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

屬性:電源狀態 (0x0319)

電源狀態 (0x0319) 屬性是讀取/寫入屬性,具有 HID 規格中定義的標準語意。主機會使用這項屬性向裝置指出必須處於哪種電源狀態。僅使用「Full Power」(0x0851) 和「Power Off」(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 規則解讀。每個元素的有效範圍為 [-π, π] 弧度。單位一律為弧度。

這些元素會解讀為 [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 描述元範例

以下範例說明裝置的 v2.0 HID 描述元,該裝置僅支援 Bluetooth LE ACL 傳輸。

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