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

Protocolo de dispositivo de interface humana (HID, na sigla em inglês) do monitor de posições da cabeça, disponível para dispositivos com o Android 13 e versões mais recentes, um dispositivo de rastreamento de cabeça seja conectado a um dispositivo Android por USB ou Bluetooth e ser exposto ao framework e aos apps do Android por meio da de sensores. Esse protocolo é usado para controlando um efeito de virtualizador de áudio (áudio 3D). Esta página usa os termos dispositivo e host no sentido de Bluetooth, em que device 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 do Terraform, consulte a README de sensores dinâmicos (link em inglês).

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

Estrutura de nível superior

O framework do Android identifica o rastreador de posições 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 rastreador da cabeça é uma coleção de aplicativos com o Sensors página (0x20) e o uso de Other: Custom (0xE1). Dentro são diversos 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: Sensor Description (0x0308)

A propriedade Sensor Description (0x0308) é uma propriedade de string ASCII (8 bits) de leitura somente, que precisa conter os seguintes valores:

Head Tracker versão 1.0:

#AndroidHeadTracker#1.0

Versão 2.0 do monitor de posições da cabeça (disponível no Android 15 ou superior), o que inclui compatibilidade com LE Audio:

#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

Não é esperado um "null-terminator", o que significa que o tamanho total dessa propriedade tem 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)

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

Essa propriedade permite que dispositivos de rastreamento de 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 de ID exclusivo persistente (0x0302) não existir ou estiver definida como "todos" zeros, isso significa que o rastreador da cabeça não está permanentemente conectado a um dispositivo de áudio e podem ser usados separadamente, por exemplo, permitindo que o usuário associar manualmente o tracker a um dispositivo de áudio separado.

Referência que usa o endereço MAC do 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 do Bluetooth

Neste esquema, os primeiros 8 octetos precisam ser 0, e os octetos 8 e 9 precisam conter os valores ASCII B e T respectivamente e os seis octetos a seguir são interpretado como um endereço MAC Bluetooth, supondo que o rastreador principal se aplica 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 dual modo conectados por Bluetooth clássico (formato HID v1.0) e Bluetooth LE (formato HID v2.0) precisam expor dois HID descritores com o mesmo endereço de identidade. Dispositivos de modo birregional com controles separados os dispositivos esquerdo e direito precisam expor o Bluetooth LE HID usando o dispositivo duplo 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, por meio de um mecanismo não especificado que é específico da 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 este para indicar ao dispositivo quais eventos serão relatados. Somente os valores "No Events" (0x0840) e "All Events" (0x0841) são usados.

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

Propriedade: estado de energia (0x0319)

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

O valor inicial deste campo é determinado pelo dispositivo e nunca deve 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 que tem o semântica padrão, conforme definido na especificação HID. O host usa este para indicar ao dispositivo com que frequência informar as leituras de dados. As unidades são informadas em segundos. O intervalo válido para este valor é determinado pelo dispositivo e são descritos usando o mecanismo Mín./Máx. físico. Pelo menos 50 Hz deve ser suportada, e a taxa máxima recomendada de geração de relatórios é 100 Hz. Portanto, o intervalo mínimo do relatório precisa ser menor ou igual a 20 ms e recomendamos 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 organizador usa essa propriedade para indicar o transporte selecionado (ACL ou ISO). Somente o de valores ACL (0xF800) e ISO (0xF801) são usados, e ambos devem 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 informar o informações reais de rastreamento da cabeça. É uma matriz de 3 elementos, interpretada de acordo às regras normais de HID para valores físicos, conforme especificado na seção 6.2.2.7 do a 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 deriva é 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 informar o 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] é uma vetor de rotação, que representa a velocidade angular do frame da cabeça (em relação a si mesma).

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 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 aumentar a 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 potência está definida como Potência total.
  • A propriedade "Estado do relatório" está definida como "Todos os eventos".
  • A propriedade Intervalo do relatório é diferente de 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 monitor 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 usam 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 em um dispositivo podem ser determinadas examinando-se a propriedade "Descrição do sensor" (0x0308).

Compatibilidade de versões secundárias

As mudanças à versão secundária são compatíveis com versões anteriores. com base na mesma versão principal. Em atualizações para o item menor versão, 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 da versão principal

Alterações não compatíveis com versões anteriores são permitidas para alterações nas 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 de relatórios. 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 anunciada pelo dispositivo, examinando a propriedade "Descrição do sensor" para determinar as versões de protocolo que cada uma implementa e escolher as 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 o as macros C mais usadas, fornecidas nas 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,
};