Protocolo HID para seguimiento de cabeza

El protocolo de dispositivo de interfaz humana (HID) con seguimiento de cabeza, disponible para dispositivos que ejecutan Android 13 y versiones posteriores, permite que un dispositivo de seguimiento de cabeza se conecte a uno Android mediante USB o Bluetooth y que se exponga al framework y las apps de Android a través del framework de sensores. Este protocolo se usa para controlar un efecto de virtualizador de audio (audio 3D). En esta página, se usan los términos dispositivo y host en el sentido de Bluetooth, en el que dispositivo significa el dispositivo de seguimiento de cabeza, y host, el host de Android.

Los fabricantes de dispositivos deben configurar sus dispositivos Android para habilitar la compatibilidad con el protocolo HID de seguimiento de cabeza. Para obtener información más detallada sobre la configuración, consulta el archivo README de sensores dinámicos.

En esta página, se asume que conoces los siguientes recursos:

Estructura de nivel superior

El framework de Android identifica el dispositivo de seguimiento de cabeza como un dispositivo HID.

Para obtener un ejemplo completo de un descriptor HID válido, consulta el Apéndice 1: Ejemplo de un descriptor HID.

En el nivel superior, el dispositivo de seguimiento de cabeza es una colección de apps con la página Sensors (0x20) y el uso de Other: Custom (0xE1). Dentro de ella, hay varios campos de datos (entradas) y propiedades (funciones).

Propiedades y campos de datos

En esta sección, se describen las propiedades y los campos de datos de una colección de aplicaciones de un dispositivo de rastreo de cabeza.

Propiedad: Descripción del sensor (0x0308)

La propiedad Sensor Description (0x0308) es una propiedad de cadena ASCII (8 bits) de solo lectura que debe contener los siguientes valores:

Seguidor de cabeza versión 1.0:

#AndroidHeadTracker#1.0

Versión 2.0 del monitor de cabeza (disponible en Android 15 o versiones posteriores), que incluye compatibilidad con LE Audio:

#AndroidHeadTracker#2.0#x

x es un número entero (1, 2, 3) que indica el transporte compatible:

  • 1: LCA
  • 2: ISO
  • 3: LCA + ISO

No se espera un terminador nulo, lo que significa que el tamaño total de esta propiedad es de 23 caracteres de 8 bits para la versión 1.0.

Esta propiedad funciona como un discriminador para evitar colisiones con otros sensores personalizados.

Propiedad: ID único persistente (0x0302)

La propiedad de ID único persistente (0x0302) es un array de solo lectura de 16 elementos, cada uno de 8 bits (128 bits en total). No se espera un terminador nulo. Esta propiedad es opcional.

Esta propiedad permite que los dispositivos de seguimiento de cabeza integrados en dispositivos de audio hagan referencia al dispositivo de audio al que están conectados. Se admiten los siguientes esquemas.

Seguimiento de cabeza independiente

Si la propiedad ID único persistente (0x0302) no existe o está configurada en todos los ceros, significa que el dispositivo de rastreo de cabeza no está conectado de forma permanente a un dispositivo de audio y se puede usar por separado, por ejemplo, permitiendo que el usuario asocie manualmente el dispositivo de rastreo de cabeza con un dispositivo de audio independiente.

Referencia con dirección MAC de Bluetooth

Octeto 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Valor 0 0 0 0 0 0 0 0 B T Bluetooth MAC

En este esquema, los primeros 8 octetos deben ser 0, los octetos 8 y 9 deben contener los valores ASCII B y T, respectivamente, y los siguientes 6 octetos se interpretan como una dirección MAC de Bluetooth, suponiendo que el dispositivo de seguimiento de cabeza se aplica a cualquier dispositivo de audio que tenga esta dirección MAC. Esta dirección debe ser la dirección de identidad, incluso si el dispositivo usa una dirección MAC aleatoria para establecer conexiones. Los dispositivos de modo dual que se conectan a través de Bluetooth clásico (formato HID v1.0) y Bluetooth LE (formato HID v2.0) deben exponer dos descriptores HID con la misma dirección de identidad. Los dispositivos de modo dual con dispositivos izquierdo y derecho separados deben exponer el HID Bluetooth LE con el dispositivo principal de modo dual en lugar del dispositivo secundario solo para LE.

Referencia con UUID

Cuando se establece el bit más importante (MSB) del octeto 8 (≥0x80), el campo se interpreta como un UUID, como se especifica en RFC-4122. El dispositivo de audio correspondiente proporciona el mismo UUID, que está registrado en el framework de Android, a través de un mecanismo no especificado específico para el tipo de transporte utilizado.

Propiedad: Estado de los informes (0x0316)

La propiedad del estado del informe (0x0316) es una propiedad de lectura/escritura que tiene una semántica estándar, como se define en la especificación HID. El host usa esta propiedad para indicar al dispositivo qué eventos informar. Solo se usan los valores Sin eventos (0x0840) y Todos los eventos (0x0841).

El valor inicial de este campo debe ser No Events y el dispositivo nunca debe modificarlo, solo el host.

Propiedad: Estado de energía (0x0319)

La propiedad de estado de la batería (0x0319) es una propiedad de lectura y escritura que tiene la semántica estándar como se define en la especificación de HID. El host usa esta propiedad para indicarle al dispositivo en qué estado de energía debe estar. Solo se usan los valores Full Power (0x0851) y Power Off (0x0855).

El dispositivo determina el valor inicial de este campo, que nunca debe modificarse, solo el host.

Propiedad: Intervalo de informes (0x030E)

La propiedad Report Interval (0x030E) es una propiedad de lectura y escritura que tiene la semántica estándar como se define en la especificación HID. El host usa esta propiedad para indicarle al dispositivo con qué frecuencia informar sus lecturas de datos. Las unidades están en segundos. El dispositivo determina el rango válido para este valor, y se describe con el mecanismo Mínimo/Máximo físico. Se debe admitir una frecuencia de informes de al menos 50 Hz, y la frecuencia máxima recomendada es de 100 Hz. Por lo tanto, el intervalo de informes mínimo debe ser inferior o igual a 20 ms, y se recomienda que sea superior o igual a 10 ms.

Propiedad: Transporte LE reservado por el proveedor (0xF410)

La propiedad de transporte LE reservado por el proveedor (0xF410) es una propiedad de lectura y escritura que tiene la semántica estándar como se define en la especificación de HID. El host usa esta propiedad para indicar el transporte seleccionado (ACL o ISO). Solo se usan los valores de la LCA (0xF800) y la ISO (0xF801), y ambos deben incluirse en la colección lógica.

Esta propiedad se configuró antes de los estados de alimentación o de informes.

Campo de datos: Valor personalizado 1 (0x0544)

El campo Custom Value 1 (0x0544) es un campo de entrada que se usa para informar la información real del seguimiento de la cabeza. Es un array de 3 elementos, interpretado según las reglas normales de HID para valores físicos, como se especifica en el artículo 6.2.2.7 de la especificación de HID. El rango válido para cada elemento es [-π, π] rad. Las unidades siempre son radianes.

Los elementos se interpretan como: [rx, ry, rz], de modo que [rx, ry, rz] es un vector de rotación que representa la transformación del marco de referencia al marco principal. La magnitud debe estar en el rango [0..π].

El marco de referencia es arbitrario, pero en general es fijo y debe ser para diestros. Se acepta una pequeña cantidad de deriva. Los ejes principales son los siguientes:

  • X de la oreja izquierda a la derecha
  • Y desde la parte posterior de la cabeza hasta la nariz (de atrás hacia adelante)
  • Z desde el cuello hasta la parte superior de la cabeza

Campo de datos: valor personalizado 2 (0x0545)

El campo Valor personalizado 2 (0x0545) es un campo de entrada que se usa para informar la información real de seguimiento de cabeza. Es un array de 3 elementos de punto fijo, que se interpreta de acuerdo con las reglas HID normales para los valores físicos. Las unidades siempre son radianes por segundo.

Los elementos se interpretan como: [vx, vy, vz], de modo que [vx, vy, vz] es un vector de rotación que representa la velocidad angular del marco de la cabeza (en relación con sí mismo).

Campo de datos: Valor personalizado 3 (0x0546)

El campo Valor personalizado 3 (0x0546) es un campo de entrada que se usa para hacer un seguimiento de las discontinuidades en el marco de referencia. Es un número entero escalar de 8 bits. El dispositivo debe incrementarlo (con unión) cada vez que se cambia el marco de referencia, por ejemplo, si se restablece el estado de un algoritmo de filtro de orientación que se usa para determinar la orientación. Este valor se interpreta según las reglas normales de HID para los valores físicos. Sin embargo, el valor físico y las unidades no importan. La única información relevante para el host es un valor modificado. Para evitar problemas numéricos relacionados con la pérdida de precisión durante la conversión de unidades lógicas a físicas, se recomienda establecer los valores de mínimo físico, máximo físico y exponente de unidad en cero para este campo.

Estructura del informe

La agrupación de propiedades en informes (por asignación de IDs de informes) es flexible. Para mayor eficiencia, te recomendamos separar las propiedades de solo lectura de las propiedades de lectura y escritura.

En el caso de los campos de datos, los campos de valor personalizado 1, 2 y 3 deben estar en el mismo informe y en un solo informe para un dispositivo determinado (colección de aplicaciones).

Cómo enviar informes de entradas

El dispositivo debe enviar informes de entrada de forma periódica y asíncrona (a través de mensajes HID INPUT) cuando se cumplan todas estas condiciones:

  • La propiedad Power State está configurada en Full Power.
  • La propiedad Estado de los informes se establece en Todos los eventos.
  • La propiedad de intervalo de informes no es cero.

La propiedad Intervalo de informes determina la frecuencia con la que se envían los informes. Si no se cumple alguna de las condiciones anteriores, el dispositivo no debe enviar ningún informe.

Compatibilidad con versiones anteriores y posteriores

El protocolo HID del dispositivo de seguimiento de cabeza usa un esquema de control de versiones que permite actualizaciones y, al mismo tiempo, interoperabilidad entre un host y un dispositivo que usan diferentes versiones del protocolo. Las versiones del protocolo se identifican con dos números, principales y secundarios, que tienen semánticas distintas, como se describe en las siguientes secciones.

Para determinar las versiones compatibles con un dispositivo, examina su propiedad Sensor Description (0x0308).

Compatibilidad con versiones secundarias

Los cambios en la versión secundaria son retrocompatibles con versiones secundarias anteriores que se basan en la misma versión principal. En las actualizaciones de la versión menor, el host ignora los campos y las propiedades de datos adicionales. Por ejemplo, un dispositivo que usa la versión 1.6 del protocolo es compatible con un host que admite la versión del protocolo 1.x, incluida la versión 1.5.

Compatibilidad con versiones principales

Se permiten los cambios no retrocompatibles para las modificaciones en versiones principales. Para admitir varias versiones principales para la interoperabilidad con hosts nuevos y antiguos, los dispositivos pueden especificar varias colecciones de apps en sus descriptores de informes. Por ejemplo:

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

En este caso, el host puede enumerar todas las colecciones de apps anunciadas por el dispositivo, examinar su propiedad de descripción del sensor para determinar las versiones de protocolo que implementa cada uno y, luego, elegir la última versión de protocolo que admite el host. Cuando se elige, el host funciona con el único protocolo que se eligió para toda la vida útil de la conexión del dispositivo.

Apéndice: ejemplo de un descriptor HID

En el siguiente ejemplo, se ilustra un descriptor HID válido típico. Usa las macros C de uso general, que se proporcionan en Usos del sensor HID (sección 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,
};

Apéndice 2: Ejemplo de un descriptor HID v2.0

En el siguiente ejemplo, se ilustra un descriptor HID v2.0 para un dispositivo que solo admite el transporte de ACL de Bluetooth LE.

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