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 de 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 mais informações 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 rastreamento 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 descritor HID.
No nível mais alto, o dispositivo de rastreamento de cabeça é 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 (inputs) e propriedades (features).
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
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, cada um de 8 bits (total de 128 bits). Nenhum terminador nulo é esperado. Essa
propriedade é 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 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
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 |
Nesse esquema, os primeiros 8 octetos precisam ser 0
, os octetos 8 e 9 precisam conter
os valores ASCII B
e T
, respectivamente, e os 6 octetos seguintes são
interpretados como um endereço MAC Bluetooth, supondo que o dispositivo de rastreamento da cabeça
seja aplicado 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 Bluetooth LE HID 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, por um mecanismo não especificado específico do
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 por ele, apenas pelo host.
Propriedade: Intervalo do relatório (0x030E
)
A propriedade Intervalo de relatório (0x030E
) é 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 com que frequência informar 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 de 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 informar as
informações reais de rastreamento de 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,
representando 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 informar as
informações reais de rastreamento de 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]
seja um
vetor de rotação,
que representa a velocidade angular do frame da cabeça (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
de tamanho. 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 de relatórios 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 futuras e anteriores
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 de 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 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 anunciadas pelo dispositivo, examinando a propriedade Sensor Description para determinar as versões do protocolo que cada uma implementa e, em seguida, escolher a versão mais recente do protocolo com suporte ao host. Quando escolhido, o host funciona com o único protocolo escolhido para a vida útil 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 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,
};