Protocolo HID do rastreador de posições da cabeça

O protocolo de dispositivo de interface humana (HID, na sigla em inglês) do monitor da posição da cabeça do usuário, disponível para dispositivos com o Android 13 e versões mais recentes, permite que um dispositivo de rastreamento da posição da cabeça seja conectado a um dispositivo Android por USB ou Bluetooth e exposto ao framework e aos apps Android pelo framework de sensores. Esse protocolo é usado para controlar um efeito de virtualizador de áudio (áudio 3D). Esta página usa os termos dispositivo e host no sentido de Bluetooth, em que dispositivo significa o dispositivo de rastreamento da cabeça e host significa o host do Android.

Os fabricantes de dispositivos precisam configurar os dispositivos Android para ativar o suporte ao protocolo HID do rastreador de cabeça. Para informações mais detalhadas sobre a configuração, consulte o README dos sensores dinâmicos.

Nesta página, consideramos que você esteja familiarizado com os seguintes recursos:

Estrutura de nível superior

O framework do Android identifica o dispositivo de monitor da posição da cabeça como um dispositivo HID.

Para conferir um exemplo completo de um descritor HID válido, consulte Apêndice 1: exemplo de um descritor HID.

No nível superior, o dispositivo rastreador principal é uma coleção de apps com a página Sensors (0x20) e o uso de Other: Custom (0xE1). Dentro dessa coleção há vários campos de dados (entradas) e propriedades (recursos).

Propriedades e campos de dados

Esta seção descreve as propriedades e os campos de dados em uma coleção de aplicativos de um dispositivo de rastreamento de cabeça.

Propriedade: descrição do sensor (0x0308)

A propriedade de descrição do sensor (0x0308) é uma propriedade de string ASCII (8 bits) somente leitura que precisa conter os seguintes valores:

Head Tracker versão 1.0:

#AndroidHeadTracker#1.0

Head Tracker versão 2.0 (disponível no Android 15 ou mais recente), que inclui suporte para áudio LE:

#AndroidHeadTracker#2.0#x

O x é um número inteiro (1, 2, 3) que indica o transporte de suporte:

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

Nenhum terminador nulo é esperado, o que significa que o tamanho total dessa propriedade é de 23 caracteres de 8 bits para a versão 1.0.

Essa propriedade serve como um discriminador para evitar colisões com outros sensores personalizados.

Propriedade: ID exclusivo persistente (0x0302)

A propriedade de ID exclusivo persistente (0x0302) é uma matriz somente leitura de 16 elementos, de 8 bits cada (total de 128 bits). Nenhum terminador nulo é esperado. Essa propriedade é opcional.

Essa propriedade permite que dispositivos de rastreamento da cabeça integrados a dispositivos de áudio façam referência ao dispositivo de áudio ao qual estão conectados. Os esquemas a seguir são compatíveis.

Rastreador de cabeça independente

Se a propriedade Persistent Unique ID (0x0302) não existir ou estiver definida como todos zeros, significa que o dispositivo de rastreamento da cabeça não está permanentemente conectado a um dispositivo de áudio e pode ser usado separadamente, por exemplo, permitindo que o usuário associe manualmente o dispositivo de rastreamento da cabeça a um dispositivo de áudio separado.

Referência que usa o endereço MAC do Bluetooth

Octet 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 do Bluetooth

Nesse esquema, os primeiros 8 octetos precisam ser 0, os octetos 8 e os 9 precisam conter os valores ASCII B e T, respectivamente, e os seis octetos a seguir são interpretados como um endereço MAC Bluetooth, supondo que o dispositivo de rastreamento principal se aplique a qualquer dispositivo de áudio que tenha esse endereço MAC. Esse endereço precisa ser o endereço de identidade, mesmo que o dispositivo use um endereço MAC aleatório para estabelecer conexões. Dispositivos de modo duplo que se conectam por Bluetooth clássico (formato HID v1.0) e Bluetooth LE (formato HID v2.0) precisam expor dois descritores HID com o mesmo endereço de identidade. Dispositivos de modo duplo com dispositivos esquerdo e direito separados precisam expor o HID Bluetooth LE usando o dispositivo de modo duplo principal em vez do dispositivo secundário somente LE.

Referência usando UUID

Sempre que o bit mais significativo (MSB) do octeto 8 for definido (≥0x80), o campo será interpretado como um UUID, conforme especificado na RFC-4122. O dispositivo de áudio correspondente fornece o mesmo UUID, que é registrado no framework do Android, usando um mecanismo não especificado específico para o tipo de transporte usado.

Propriedade: estado do relatório (0x0316)

A propriedade "Reporting State" (0x0316) é uma propriedade de leitura/gravação que tem a semântica padrão conforme definido na especificação HID. O host usa essa propriedade para indicar ao dispositivo quais eventos relatar. Somente os valores "No Events" (0x0840) e "All Events" (0x0841) são usados.

O valor inicial desse campo precisa ser "Sem eventos" e nunca ser modificado pelo dispositivo, apenas pelo host.

Propriedade: estado de energia (0x0319)

A propriedade "Estado de energia" (0x0319) é uma propriedade de leitura/gravação que tem a semântica padrão conforme definido na especificação HID. O host usa essa propriedade para indicar ao dispositivo em qual estado de energia ele precisa estar. Somente os valores "Full Power" (0x0851) e "Power Off" (0x0855) são usados.

O valor inicial desse campo é determinado pelo dispositivo e nunca pode ser modificado pelo dispositivo, apenas pelo host.

Propriedade: intervalo do relatório (0x030E)

A propriedade Intervalo do relatório (0x030E) é uma propriedade de leitura/gravação com a semântica padrão, conforme definido na especificação HID. O host usa essa propriedade para indicar ao dispositivo com que frequência relata as leituras de dados. As unidades são informadas em segundos. O intervalo válido para esse valor é determinado pelo dispositivo e descrito usando o mecanismo mínimo/máximo físico. É necessário oferecer suporte a uma taxa de relatório de pelo menos 50 Hz, e a taxa máxima recomendada é de 100 Hz. Portanto, o intervalo mínimo de relatório precisa ser menor ou igual a 20 ms, e é recomendável que seja maior ou igual a 10 ms.

Propriedade: transporte LE reservado pelo fornecedor (0xF410)

A propriedade de transporte LE reservada pelo fornecedor (0xF410) é uma propriedade de leitura/gravação que tem a semântica padrão conforme definido na especificação HID. O host usa essa propriedade para indicar o transporte selecionado (ACL ou ISO). Somente os valores ACL (0xF800) e ISO (0xF801) são usados, e ambos precisam ser incluídos na coleção lógica.

Essa propriedade é configurada antes dos estados de energia ou de geração de relatórios.

Campo de dados: valor personalizado 1 (0x0544)

O campo "Valor personalizado 1" (0x0544) é um campo de entrada usado para relatar as informações reais de rastreamento da cabeça. É uma matriz de três elementos, interpretada de acordo com as regras normais de HID para valores físicos, conforme especificado na seção 6.2.2.7 da especificação HID. O intervalo válido para cada elemento é [-π, π] rad. As unidades são sempre radianos.

Os elementos são interpretados como: [rx, ry, rz], de modo que [rx, ry, rz] seja um vetor de rotação, que representa a transformação do frame de referência para o frame da cabeça. A magnitude precisa estar no intervalo [0..π].

O frame de referência é arbitrário, mas geralmente é fixo e precisa ser direito. Uma pequena quantidade de deslocamento é aceitável. Os eixos da cabeça são:

  • X do ouvido esquerdo para o direito
  • Y da parte de trás da cabeça até o nariz (de trás para a frente)
  • Z do pescoço até o topo da cabeça

Campo de dados: valor personalizado 2 (0x0545)

O campo "Valor personalizado 2" (0x0545) é um campo de entrada usado para relatar as informações reais de rastreamento da cabeça. É uma matriz de ponto fixo de três elementos, interpretada de acordo com as regras normais de HID para valores físicos. As unidades são sempre radianos/segundo.

Os elementos são interpretados como: [vx, vy, vz], de modo que [vx, vy, vz] é um vetor de rotação, que representa a velocidade angular do frame principal (em relação a si mesmo).

Campo de dados: valor personalizado 3 (0x0546)

O campo "Valor personalizado 3" (0x0546) é um campo de entrada usado para rastrear descontinuidades no frame de referência. É um número inteiro escalar de 8 bits. Ele precisa ser incrementado (com o recurso de wraparound) pelo dispositivo sempre que o frame de referência for alterado, por exemplo, se um algoritmo de filtro de orientação usado para determinar a orientação tiver o estado redefinido. Esse valor é interpretado de acordo com as regras normais de HID para valores físicos. No entanto, o valor físico e as unidades não importam. A única informação relevante para o host é um valor alterado. Para evitar problemas numéricos relacionados à perda de precisão ao converter de unidades lógicas para físicas, é recomendável definir os valores de mínimo físico, máximo físico e expoente de unidade como zero para esse campo.

Estrutura do relatório

O agrupamento de propriedades em relatórios (por atribuição de IDs de relatórios) é flexível. Para eficiência, recomendamos separar as propriedades somente leitura das propriedades de leitura/gravação.

Para os campos de dados, os campos "Valor personalizado 1", "Valor personalizado 2" e "Valor personalizado 3" precisam estar no mesmo relatório e em apenas um relatório para um determinado dispositivo (coleção de apps).

Enviar relatórios de entrada

O dispositivo precisa enviar relatórios de entrada de forma periódica e assíncrona (por mensagens HID INPUT) quando todas essas condições forem atendidas:

  • A propriedade "Estado de energia" está definida como "Potência total".
  • A propriedade "Estado do relatório" está definida como "Todos os eventos".
  • A propriedade "Intervalo de relatórios" não é igual a zero.

A propriedade "Intervalo do relatório" determina a frequência de envio dos relatórios. Quando qualquer uma das condições acima não for atendida, o dispositivo não poderá enviar relatórios.

Compatibilidade com versões anteriores e futuras

O protocolo HID do rastreador de posições da cabeça usa um esquema de controle de versões que permite atualizações, além de permitir a interoperabilidade entre um host e um dispositivo que usa versões diferentes do protocolo. As versões do protocolo são identificadas por dois números, principal e secundário, que têm semânticas distintas, conforme descrito nas seções a seguir.

As versões com suporte a um dispositivo podem ser determinadas examinando a propriedade Sensor Description (0x0308).

Compatibilidade com versões secundárias

As mudanças na versão secundária são compatíveis com versões secundárias anteriores com base na mesma versão principal. Nas atualizações da versão secundária, o host ignora campos e propriedades de dados adicionais. Por exemplo, um dispositivo que usa a versão 1.6 do protocolo é compatível com um host que oferece suporte à versão 1.x do protocolo, incluindo a versão 1.5.

Compatibilidade com a versão principal

Mudanças não compatíveis com versões anteriores são permitidas para mudanças em versões principais. Para oferecer suporte a várias versões principais para interoperabilidade com hosts antigos e novos, os dispositivos podem especificar várias coleções de apps nos descritores do relatório. Exemplo:

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

Nesse caso, o host pode enumerar todas as diferentes coleções de apps divulgadas pelo dispositivo, examinando a propriedade "Sensor Description" para determinar as versões de protocolo que cada uma implementa e escolhendo a versão mais recente do protocolo compatível com o host. Quando escolhido, o host funciona com o único protocolo escolhido para o ciclo de vida da conexão do dispositivo.

Apêndice: exemplo de um descritor HID

O exemplo a seguir ilustra um descritor HID válido típico. Ele usa as macros C usadas com frequência, fornecidas em Usos do sensor HID (seção 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: exemplo de um descritor HID v2.0

O exemplo a seguir ilustra um descritor HID v2.0 para um dispositivo que oferece suporte apenas ao transporte de ACL 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,
};