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 un dispositivo 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 su sentido de Bluetooth, en el que dispositivo significa el dispositivo de seguimiento de cabeza y host significa 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 Dynamic Sensors.

En esta página, se supone que estás familiarizado con 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 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 Other: Custom (0xE1). Dentro de esta colección, 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 en una colección de aplicaciones de un dispositivo de seguimiento de cabeza.

Propiedad: Sensor Description (0x0308)

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

Head tracker versión 1.0:

#AndroidHeadTracker#1.0

Head tracker versión 2.0 (disponible en Android 15 o versiones posteriores), que incluye compatibilidad con audio LE:

#AndroidHeadTracker#2.0#x

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

  • 1: ACL
  • 2: ISO
  • 3: ACL + ISO

No se espera ningún 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 sirve como discriminador para evitar colisiones con otros sensores personalizados.

Propiedad: Persistent Unique ID (0x0302)

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

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

Dispositivo de seguimiento de cabeza independiente

Si la propiedad Persistent Unique ID (0x0302) no existe o está configurada en todos los ceros, significa que el dispositivo de seguimiento 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 seguimiento de cabeza con un dispositivo de audio independiente.

Referencia con la 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 MAC de Bluetooth

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 Classic (formato HID v1.0) y Bluetooth de bajo consumo (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 Bluetooth de bajo consumo HID con el dispositivo principal de modo dual en lugar del dispositivo secundario solo LE.

Referencia con UUID

Cada vez que se establece el bit más significativo (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 se registra en el framework de Android, a través de un mecanismo no especificado que es específico del tipo de transporte que se usa.

Propiedad: Reporting State (0x0316)

La propiedad Reporting State (0x0316) es una propiedad de lectura y escritura que tiene la semántica estándar definida en la especificación HID. El host usa esta propiedad para indicarle al dispositivo qué eventos informar. Solo se usan los valores No Events (0x0840) y All Events (0x0841).

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

Propiedad: Power State (0x0319)

La propiedad Power State (0x0319) es una propiedad de lectura y escritura que tiene la semántica estándar definida en la especificación 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 valor inicial de este campo lo determina el dispositivo y nunca debe modificarse, solo el host.

Propiedad: Report Interval (0x030E)

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

Propiedad: Vendor-reserved LE Transport (0xF410)

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

Esta propiedad se configura antes de los estados de energía o de informes.

Campo de datos: Custom Value 1 (0x0544)

El campo Custom Value 1 (0x0544) es un campo de entrada que se usa para informar la información real de seguimiento de cabeza. Es un array de 3 elementos, interpretado según las reglas HID normales para valores físicos, como se especifica en la sección 6.2.2.7 de la especificación 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 de cabeza. La magnitud debe estar en el rango [0..π].

El marco de referencia es arbitrario, pero generalmente es fijo y debe ser diestro. Se acepta una pequeña cantidad de desviación. Los ejes de la cabeza son los siguientes:

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

Campo de datos: Custom Value 2 (0x0545)

El campo Custom Value 2 (0x0545) es un campo de entrada que se usa para informar la información real de seguimiento de cabeza. Es un array de punto fijo de 3 elementos, interpretado según las reglas HID normales para valores físicos. Las unidades siempre son radianes/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 cabeza (en relación con sí mismo).

Campo de datos: Custom Value 3 (0x0546)

El campo Custom Value 3 (0x0546) es un campo de entrada que se usa para realizar un seguimiento de las discontinuidades en el marco de referencia. Es un número entero escalar de 8 bits de tamaño. El dispositivo debe incrementarlo (con ajuste) cada vez que se cambia el marco de referencia, por ejemplo, si un algoritmo de filtro de orientación que se usa para determinar la orientación restableció su estado. Este valor se interpreta según las reglas HID normales para 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 min físico, max físico y exponente de unidad en cero para este campo.

Estructura del informe

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

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

Enviar informes de entrada

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 como Full Power.
  • La propiedad Reporting State está configurada como All Events.
  • La propiedad Reporting Interval no es cero.

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

Compatibilidad con versiones anteriores y posteriores

El protocolo HID 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, principal y secundario, que tienen una semántica distinta, como se describe en las siguientes secciones.

Las versiones compatibles con un dispositivo se pueden determinar examinando 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 secundaria, el host ignora los campos de datos y las propiedades adicionales. Por ejemplo, un dispositivo que usa la versión 1.6 del protocolo es compatible con un host que admite la versión 1.x del protocolo, incluida la versión 1.5.

Compatibilidad con versiones principales

Se permiten cambios no retrocompatibles para los cambios en las versiones principales. Para admitir varias versiones principales para la interoperabilidad con hosts antiguos y nuevos, 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 diferentes colecciones de apps que anuncia el dispositivo, examinar su propiedad Sensor Description para determinar las versiones del protocolo que implementan cada una y, luego, elegir la versión más reciente del protocolo que admite el host. Cuando se elige, el host funciona con el protocolo único que se eligió durante 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 común, que se proporcionan en Usos de sensores 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 ACL de Bluetooth de bajo consumo.

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