ヘッド トラッカー ヒューマン インターフェース デバイス(HID)プロトコルは、Android 13 以降を搭載しているデバイスで利用でき、ヘッド トラッキング デバイスを USB または Bluetooth 経由で Android デバイスに接続することを可能にします。また、センサー フレームワークを通じて Android フレームワークとアプリに公開されます。このプロトコルは、オーディオ バーチャライザー効果(3D オーディオ)の制御に使用されます。このページでは「デバイス」と「ホスト」という用語を、Bluetooth の意味で使用します。ここで「デバイス」はヘッド トラッキング デバイスを意味し、「ホスト」は Android ホストを意味します。
デバイス メーカーは、ヘッド トラッカー HID プロトコルのサポートを有効にするように Android デバイスを設定する必要があります。設定の詳細については、動的センサーの README をご覧ください。
このページは、次の資料を理解していることを前提としています。
最上位の構造
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
)プロパティが存在しないかすべてゼロに設定されている場合、ヘッド トラッカー デバイスが永続的にオーディオ デバイスに接続されているのではなく、個別に使用できることを意味します。たとえば、ヘッド トラッカー デバイスをユーザーが別のオーディオ デバイスに手動で関連付けることができます。
Bluetooth の 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 | Bluetooth の MAC |
このスキームでは、最初の 8 オクテットは 0
で、オクテット 8 と 9 にはそれぞれ ASCII 値 B
と T
を含む必要があり、次の 6 オクテットは Bluetooth の MAC アドレスとして解釈されます。ただし、ヘッド トラッカー デバイスがこの MAC アドレスを持つ任意のオーディオ デバイスにあてはまることを前提とします。
UUID を使用した参照
オクテット 8 の最上位ビット(MSB)がセットされている場合(≥0x80
)、このフィールドは RFC 4122 で規定されているとおりの UUID だと解釈されます。対応するオーディオ機器は、使用されるトランスポート タイプに固有の不特定のメカニズムを通じて、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 ルールに従って解釈されます。ただし、物理量と単位は重要ではありません。ホストに関連する情報は、変更された値のみです。論理単位から物理単位への変換における精度の低下に関連する数値的問題を回避するために、このフィールドに関しては物理最小値、物理最大値、単位指数の値をそれぞれ 0 に設定することを推奨します。
レポートの構造
各プロパティをレポートにグループ化する(各レポート ID を割り当てる)ことは柔軟に行えます。効率を高めるために、読み取り専用プロパティと読み書きプロパティを分離することを推奨します。
データ フィールドに関しては、Custom Value 1、2、3 の各フィールドは同じレポートに含まれていて、特定のデバイス(アプリ コレクション)について 1 つのレポートにのみ含まれている必要があります。
入力レポートを送信する
デバイスは、以下のすべての条件が満たされた場合に、定期的かつ非同期に(HID INPUT メッセージを使って)入力レポートを送信する必要があります。
- Power State プロパティが Full Power に設定されている。
- Reporting State プロパティが All Events に設定されている。
- Reporting Interval プロパティがゼロ以外である。
Reporting Interval プロパティは、レポートを送信する頻度を決定します。上記の条件のいずれかが満たされない場合、デバイスがレポートを送信しないようにする必要があります。
上位互換性と下位互換性
ヘッド トラッカー HID プロトコルは、異なるバージョンのプロトコルを使用するホストとデバイスの間の相互運用性を確保しながら、アップデートを可能にするバージョニング スキームを使用します。プロトコルのバージョンは、メジャーとマイナーの 2 つの数字で識別されます。これらには、以降のセクションで説明するように、異なるセマンティクスがあります。
デバイスでサポートされているバージョンは、Sensor Description(0x0308
)プロパティを調べることで特定できます。
マイナー バージョンの互換性
マイナー バージョンの変更は、同じメジャー バージョンをベースにした以前のマイナー バージョンとの下位互換性があります。マイナー バージョンの更新では、ホストは追加のデータ フィールドとプロパティを無視します。たとえば、プロトコル バージョン 1.6 を使用するデバイスは、バージョン 1.5 を含め、プロトコル バージョン 1.x をサポートするホストと互換性があります。
メジャー バージョンの互換性
下位互換性のない変更は、メジャー バージョンの変更に対して許可されます。古いホストと新しいホストの相互運用性のために複数のメジャー バージョンをサポートするには、デバイスのレポート記述子で複数のアプリ コレクションを指定します。次に例を示します。
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 プロパティを調べてそれぞれが実装するプロトコル バージョンを特定してから、ホストがサポートしている最新のプロトコル バージョンを選択できます。選択すると、ホストはデバイス接続の有効期間内に選択された 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,
};