Protocole HID de suivi de tête

Le protocole HID (Head Tracker Human Interface Device), disponible pour les appareils fonctionnant sous Android 13 et versions ultérieures, permet à un appareil de suivi de la tête d'être connecté à un appareil Android via USB ou Bluetooth et d'être exposé au cadre et aux applications Android via les capteurs. cadre. Ce protocole est utilisé pour contrôler un effet de virtualisation audio (audio 3D). Cette page utilise les termes appareil et hôte dans leur sens Bluetooth, où appareil désigne le dispositif de suivi de la tête et hôte désigne l'hôte Android.

Les fabricants d'appareils doivent configurer leurs appareils Android pour activer la prise en charge du protocole Head Tracker HID. Pour des informations plus détaillées sur la configuration, consultez le fichier README des capteurs dynamiques .

Cette page suppose une connaissance des ressources suivantes :

Structure de niveau supérieur

Le framework Android identifie le dispositif de suivi de tête comme un périphérique HID.

Pour un exemple complet de descripteur HID valide, voir Annexe 1 : Exemple de descripteur HID .

Au niveau supérieur, le dispositif de suivi de tête est une collection d'applications avec la page Sensors ( 0x20 ) et Other: Custom ( 0xE1 ). À l'intérieur de cette collection se trouvent plusieurs champs de données ( entrées ) et propriétés ( fonctionnalités ).

Propriétés et champs de données

Cette section décrit les propriétés et les champs de données d'une collection d'applications d'un dispositif de suivi de tête.

Propriété : Description du capteur ( 0x0308 )

La propriété Sensor Description ( 0x0308 ) est une propriété de chaîne ASCII (8 bits) en lecture seule qui doit contenir la valeur suivante :

#AndroidHeadTracker#1.0

Aucun terminateur nul n'est attendu, ce qui signifie que la taille totale de cette propriété est de 23 caractères de 8 bits.

Cette propriété sert de discriminateur pour éviter les collisions avec d'autres capteurs personnalisés.

Propriété : ID unique persistant ( 0x0302 )

La propriété Persistent Unique ID ( 0x0302 ) est un tableau en lecture seule de 16 éléments, de 8 bits chacun (total 128 bits). Aucun terminateur nul n'est attendu. Cette propriété est facultative.

Cette propriété permet aux appareils de suivi de tête intégrés aux appareils audio de référencer le périphérique audio auquel ils sont connectés. Les schémas suivants sont pris en charge.

Tracker de tête autonome

Si la propriété Persistent Unique ID ( 0x0302 ) n'existe pas ou est définie sur des zéros, cela signifie que le périphérique de suivi de tête n'est pas connecté de manière permanente à un périphérique audio et peut être utilisé séparément, par exemple, en permettant à l'utilisateur de manuellement associer le dispositif de suivi de tête à un périphérique audio distinct.

Référence à l'aide de l'adresse MAC Bluetooth

Octuor 0 1 2 3 4 5 6 7 8 9 dix 11 12 13 14 15
Valeur 0 0 0 0 0 0 0 0 B T Bluetooth-MAC

Dans ce schéma, les 8 premiers octets doivent être 0 , les octets 8 et 9 doivent contenir respectivement les valeurs ASCII B et T , et les 6 octets suivants sont interprétés comme une adresse MAC Bluetooth, en supposant que le dispositif de suivi de tête s'applique à tout périphérique audio ayant cette adresse MAC.

Référence utilisant l'UUID

Chaque fois que le bit le plus significatif (MSB) de l'octet 8 est défini ( ≥0x80 ), le champ est interprété comme un UUID, comme spécifié dans la RFC-4122 . Le périphérique audio correspondant fournit le même UUID, qui est enregistré sur le framework Android, via un mécanisme non spécifié et spécifique au type de transport utilisé.

Propriété : État de rapport ( 0x0316 )

La propriété Reporting State ( 0x0316 ) est une propriété en lecture/écriture qui possède la sémantique standard définie dans la spécification HID. L'hôte utilise cette propriété pour indiquer à l'appareil les événements à signaler. Seules les valeurs No Events ( 0x0840 ) et All Events ( 0x0841 ) sont utilisées.

La valeur initiale de ce champ doit être No Events et elle ne doit jamais être modifiée par l'appareil, uniquement par l'hôte.

Propriété : État d'alimentation ( 0x0319 )

La propriété Power State ( 0x0319 ) est une propriété en lecture/écriture qui possède la sémantique standard telle que définie dans la spécification HID. L'hôte utilise cette propriété pour indiquer à l'appareil dans quel état d'alimentation il doit se trouver. Seules les valeurs Full Power ( 0x0851 ) et Power Off ( 0x0855 ) sont utilisées.

La valeur initiale de ce champ est déterminée par l'appareil et ne doit jamais être modifiée par l'appareil, uniquement par l'hôte.

Propriété : Intervalle de rapport ( 0x030E )

La propriété Report Interval ( 0x030E ) est une propriété en lecture/écriture qui possède la sémantique standard définie dans la spécification HID. L'hôte utilise cette propriété pour indiquer à l'appareil à quelle fréquence il doit signaler ses lectures de données. Les unités sont les secondes. La plage valide pour cette valeur est déterminée par l'appareil et décrite à l'aide du mécanisme Min/Max physique. Un taux de rapport d'au moins 50 Hz doit être pris en charge et le taux de rapport maximum recommandé est de 100 Hz. Par conséquent, l’intervalle de rapport minimum doit être inférieur ou égal à 20 ms et il est recommandé qu’il soit supérieur ou égal à 10 ms.

Champ de données : Valeur personnalisée 1 ( 0x0544 )

Le champ Valeur personnalisée 1 ( 0x0544 ) est un champ de saisie utilisé pour signaler les informations réelles de suivi de la tête. Il s'agit d'un tableau à 3 éléments, interprété selon les règles HID normales pour les valeurs physiques spécifiées dans la section 6.2.2.7 de la spécification HID. La plage valide pour chaque élément est [-π, π] rad. Les unités sont toujours des radians.

Les éléments sont interprétés comme : [rx, ry, rz] , de telle sorte que [rx, ry, rz] est un vecteur de rotation , représentant la transformation du cadre de référence au cadre de tête. La magnitude doit être comprise dans la plage [0..π].

Le référentiel est arbitraire, mais il est généralement fixe et doit être droitier. Une petite quantité de dérive est acceptable. Les axes de tête sont :

  • X de l'oreille gauche vers la droite
  • Y de l'arrière de la tête jusqu'au nez (de l'arrière vers l'avant)
  • Z du cou jusqu'au sommet de la tête

Champ de données : Valeur personnalisée 2 ( 0x0545 )

Le champ Valeur personnalisée 2 ( 0x0545 ) est un champ de saisie utilisé pour signaler les informations réelles de suivi de la tête. Il s'agit d'un tableau à virgule fixe à 3 éléments, interprété selon les règles HID normales pour les valeurs physiques. Les unités sont toujours des radians/seconde.

Les éléments sont interprétés comme : [vx, vy, vz] , de telle sorte que [vx, vy, vz] est un vecteur de rotation , représentant la vitesse angulaire du cadre de tête (par rapport à lui-même).

Champ de données : Valeur personnalisée 3 ( 0x0546 )

Le champ Valeur personnalisée 3 ( 0x0546 ) est un champ de saisie utilisé pour suivre les discontinuités dans le cadre de référence. Il s’agit d’un entier scalaire de 8 bits. Il doit être incrémenté (avec bouclage) par l'appareil à chaque fois que le référentiel est modifié, par exemple si un algorithme de filtre d'orientation utilisé pour déterminer l'orientation a vu son état réinitialisé. Cette valeur est interprétée selon les règles HID normales pour les valeurs physiques. Cependant, la valeur physique et les unités n'ont pas d'importance. La seule information pertinente pour l'hôte est une valeur modifiée. Pour éviter les problèmes numériques liés à la perte de précision lors de la conversion d'unités logiques en unités physiques, il est recommandé de définir les valeurs de min physique, de max physique et d'exposant unitaire sur zéro pour ce champ.

Structure du rapport

Le regroupement des propriétés dans des rapports (par attribution d'ID de rapport) est flexible. Pour plus d'efficacité, nous vous recommandons de séparer les propriétés en lecture seule des propriétés en lecture/écriture.

Pour les champs de données, les champs Valeur personnalisée 1, 2 et 3 doivent figurer dans le même rapport et dans un seul rapport pour un appareil donné (collection d'applications).

Envoyer des rapports d'entrée

L'appareil doit périodiquement et de manière asynchrone (via des messages HID INPUT) envoyer des rapports d'entrée lorsque toutes ces conditions sont remplies :

  • La propriété Power State est définie sur Pleine puissance.
  • La propriété État du rapport est définie sur Tous les événements.
  • La propriété Reporting Interval est différente de zéro.

La propriété Reporting Interval détermine la fréquence d'envoi des rapports. Lorsqu'une des conditions ci-dessus n'est pas remplie, l'appareil ne doit envoyer aucun rapport.

Compatibilité ascendante et ascendante

Le protocole Head Tracker HID utilise un schéma de version qui permet les mises à jour, tout en permettant l'interopérabilité entre un hôte et un appareil utilisant différentes versions du protocole. Les versions du protocole sont identifiées par deux nombres, majeur et mineur, qui ont une sémantique distincte comme décrit dans les sections suivantes.

Les versions prises en charge par un appareil peuvent être déterminées en examinant sa propriété Sensor Description ( 0x0308 ).

Compatibilité des versions mineures

Les modifications apportées à la version mineure sont rétrocompatibles avec les versions mineures antérieures basées sur la même version majeure. Dans les mises à jour de la version mineure, l'hôte ignore les champs de données et les propriétés supplémentaires. Par exemple, un appareil utilisant la version 1.6 du protocole est compatible avec un hôte prenant en charge la version 1.x du protocole, y compris la version 1.5.

Compatibilité des versions majeures

Les modifications non rétrocompatibles sont autorisées pour les modifications apportées aux versions majeures. Pour prendre en charge plusieurs versions majeures pour l'interopérabilité avec les anciens et les nouveaux hôtes, les appareils peuvent spécifier plusieurs collections d'applications dans leurs descripteurs de rapport. Par exemple:

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

Dans ce cas, l'hôte peut énumérer toutes les différentes collections d'applications annoncées par l'appareil, en examinant leur propriété Sensor Description pour déterminer les versions de protocole qu'elles implémentent chacune, puis en sélectionnant la dernière version de protocole prise en charge par l'hôte. Une fois choisi, l'hôte fonctionne avec le protocole unique choisi pour la durée de vie de la connexion de l'appareil.

Annexe : Exemple de descripteur HID

L'exemple suivant illustre un descripteur HID valide typique. Il utilise les macros C couramment utilisées, fournies dans Utilisations des capteurs HID (section 4.1).

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