Протокол HID для отслеживания движений головой

Протокол HID для отслеживания движений головы, доступный на устройствах с Android 13 и более поздними версиями, позволяет подключать устройство отслеживания движений головы к устройству Android через USB или Bluetooth и предоставлять к нему доступ фреймворку Android и приложениям через фреймворк sensors. Этот протокол используется для управления эффектом виртуализации звука (3D-аудио). На этой странице термины устройство и хост используются в контексте Bluetooth. Устройство – это устройство отслеживания положения головы, а хост – это хост Android.

Производители устройств Android должны настроить их так, чтобы они поддерживали протокол HID для отслеживания положения головы. Подробную информацию о конфигурации можно найти в файле README для динамических датчиков.

Для работы с этой страницей необходимо ознакомиться со следующими ресурсами:

Структура верхнего уровня

Фреймворк Android идентифицирует устройство отслеживания движений головы как устройство HID.

Полный пример допустимого дескриптора HID приведен в Приложении 1.

На верхнем уровне устройство отслеживания движений головы представляет собой коллекцию приложений со страницей Sensors (0x20) и использованием Other: Custom (0xE1). Внутри этой коллекции есть несколько полей данных (входные данные) и свойств (функции).

Свойства и поля данных

В этом разделе описаны свойства и поля данных в коллекции приложений устройства отслеживания положения головы.

Свойство: описание датчика (0x0308)

Свойство "Описание датчика" (0x0308) представляет собой строку ASCII (8 бит) только для чтения, которая должна содержать следующие значения:

Отслеживание движения головы, версия 1.0:

#AndroidHeadTracker#1.0

Версия 2.0 функции отслеживания положения головы (доступна в Android 15 и более поздних версиях), которая включает поддержку LE Audio:

#AndroidHeadTracker#2.0#x

x – целое число (1, 2, 3), указывающее на поддерживаемый транспорт:

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

Нулевой символ не ожидается, поэтому общий размер этого свойства составляет 23 восьмибитных символа для версии 1.0.

Это свойство используется в качестве дискриминатора, чтобы избежать конфликтов с другими пользовательскими датчиками.

Свойство: постоянный уникальный идентификатор (0x0302)

Свойство Persistent Unique ID (0x0302) – это массив из 16 элементов по 8 бит каждый (всего 128 бит), доступный только для чтения. Нулевой символ не ожидается. Это свойство необязательно.

Это свойство позволяет устройствам отслеживания движения головы, которые интегрированы в аудиоустройства, ссылаться на аудиоустройство, к которому они подключены. Поддерживаются следующие схемы:

Отдельное отслеживание движения головы

Если свойство "Постоянный уникальный идентификатор" (0x0302) не существует или для него задано значение "все нули", это означает, что устройство отслеживания положения головы не прикреплено к аудиоустройству и может использоваться отдельно, например если пользователь вручную связывает его с другим аудиоустройством.

Ссылка с использованием MAC-адреса Bluetooth

Октет 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Значение 0 0 0 0 0 0 0 0 B T MAC-адрес Bluetooth

В этой схеме первые восемь октетов должны быть 0, восьмой и девятый октеты должны содержать значения ASCII B и T соответственно, а следующие шесть октетов интерпретируются как MAC-адрес Bluetooth. При этом приложение для отслеживания движений головы применяется к любому аудиоустройству с этим MAC-адресом. Это должен быть адрес устройства, даже если для установления связи используется случайный MAC-адрес. Устройства с двумя режимами, подключающиеся через наушники Bluetooth (формат HID версии 1.0) и Bluetooth LE (формат HID версии 2.0), должны предоставлять два дескриптора HID с одним и тем же адресом идентификации. Устройства с двумя режимами работы, в которых левый и правый наушники являются отдельными устройствами, должны поддерживать Bluetooth LE HID через основное устройство с двумя режимами работы, а не через дополнительное устройство, работающее только в режиме LE.

Как ссылаться на объекты с помощью UUID

Если установлен старший бит октета 8 (≥0x80), поле интерпретируется как UUID, как указано в RFC-4122. Соответствующее аудиоустройство предоставляет тот же UUID, зарегистрированный в фреймворке Android, с помощью неуказанного механизма, который зависит от типа используемого транспорта.

Ресурс: Reporting State (0x0316)

Свойство Reporting State (0x0316) – это свойство для чтения и записи со стандартной семантикой, определенной в спецификации HID. Хост использует это свойство, чтобы указать устройству, о каких событиях нужно сообщать. Используются только значения "Нет событий" (0x0840) и "Все события" (0x0841).

Изначально в этом поле должно быть указано значение "Нет событий". Устройство не должно изменять его – это может делать только хост.

Свойство "Состояние питания" (0x0319)

Свойство Power State (0x0319) доступно для чтения и записи и имеет стандартную семантику, определенную в спецификации HID. Хост использует это свойство, чтобы указать устройству, в каком состоянии питания оно должно находиться. Используются только значения "Полная мощность" (0x0851) и "Выключено" (0x0855).

Первоначальное значение этого поля определяется устройством и не должно изменяться устройством, только хостом.

Ресурс: интервал отчета (0x030E)

Свойство "Интервал отчета" (0x030E) – это свойство для чтения и записи, которое имеет стандартную семантику, определенную в спецификации HID. Хост использует это свойство, чтобы указать устройству, как часто передавать данные. Единица измерения – секунды. Допустимый диапазон значений определяется устройством и описывается с помощью механизма "Физический минимум/максимум". Частота передачи данных должна быть не менее 50 Гц, а рекомендуемая максимальная частота – 100 Гц. Таким образом, минимальный интервал передачи данных должен быть не более 20 мс, а рекомендуемый – не менее 10 мс.

Свойство: Vendor-reserved LE Transport (0xF410)

Свойство Vendor-reserved LE Transport (0xF410) является свойством для чтения и записи, которое имеет стандартную семантику, определенную в спецификации HID. Хост использует это свойство, чтобы указать выбранный транспорт (ACL или ISO). Используются только значения ACL (0xF800) и ISO (0xF801), и оба должны быть включены в логическую коллекцию.

Это свойство настраивается до состояний питания или отчетов.

Поле данных: "Пользовательское значение 1" (0x0544)

Поле "Специальное значение 1" (0x0544) – это поле ввода, которое используется для передачи информации об отслеживании головы. Это массив из трех элементов, интерпретируемый в соответствии с обычными правилами HID для физических значений, указанными в разделе 6.2.2.7 спецификации HID. Допустимый диапазон для каждого элемента – от -π до π рад. Единицы измерения всегда радианы.

Элементы интерпретируются следующим образом: [rx, ry, rz], где [rx, ry, rz] – это вектор поворота, представляющий преобразование из системы координат, связанной с головой, в опорную систему координат. Значение должно быть в диапазоне [0..π].

Система координат может быть произвольной, но обычно она фиксирована и должна быть правой. Небольшое расхождение допустимо. Оси головы:

  • X – из левого уха в правое
  • Y от затылка к носу (сзади наперед)
  • Z от шеи до макушки

Поле данных: "Собственное значение 2" (0x0545)

Поле "Специальное значение 2" (0x0545) – это поле ввода, используемое для передачи данных отслеживания движений головы. Это массив с фиксированной точкой, состоящий из трех элементов, которые интерпретируются в соответствии со стандартными правилами HID для физических значений. Единица измерения – радиан в секунду.

Элементы интерпретируются следующим образом: [vx, vy, vz], где [vx, vy, vz] – это вектор поворота, представляющий угловую скорость системы координат головы (относительно самой себя).

Поле данных: специальное значение 3 (0x0546)

Поле "Специальное значение 3" (0x0546) – это поле ввода, которое используется для отслеживания разрывов в системе координат. Это скалярное целое число размером 8 бит. Устройство должно увеличивать его (с переходом на начало диапазона) каждый раз, когда меняется система координат, например если алгоритм фильтра ориентации, используемый для определения ориентации, сбрасывает свое состояние. Это значение интерпретируется в соответствии со стандартными правилами HID для физических величин. Однако физическое значение и единицы измерения не имеют значения. Единственная информация, которая имеет значение для хоста, – это измененное значение. Чтобы избежать проблем с точностью при преобразовании логических единиц в физические, рекомендуется установить для этого поля нулевые значения физического минимума, физического максимума и экспоненты единицы измерения.

Структура отчета

Группировка ресурсов в отчеты (путем назначения идентификаторов отчетов) является гибкой. Для повышения эффективности рекомендуем разделять свойства, доступные только для чтения, и свойства, доступные для чтения и записи.

Поля данных "Специальное значение 1", "Специальное значение 2" и "Специальное значение 3" должны находиться в одном и том же отчете и только в одном отчете для определенного устройства (коллекции приложений).

Отправка отчетов о вводе

Устройство должно периодически и асинхронно (с помощью сообщений HID INPUT) отправлять отчеты о вводе, если выполняются все следующие условия:

  • Для свойства "Состояние питания" задано значение "Полная мощность".
  • Для свойства "Состояние отчетов" задано значение "Все события".
  • Свойство "Интервал создания отчетов" имеет ненулевое значение.

Свойство "Интервал отправки отчетов" определяет, как часто отправляются отчеты. Если какое-либо из перечисленных выше условий не выполняется, устройство не должно отправлять отчеты.

Прямая и обратная совместимость

Протокол HID для отслеживания движений головы использует схему управления версиями, которая позволяет выполнять обновления, обеспечивая при этом совместимость между хостом и устройством, использующими разные версии протокола. Версии протокола обозначаются двумя числами – основным и дополнительным. Их значения описаны в разделах ниже.

Версии, поддерживаемые устройством, можно определить, изучив его свойство "Описание датчика" (0x0308).

Совместимость с промежуточными версиями

Изменения в промежуточной версии обратно совместимы с более ранними промежуточными версиями, основанными на той же основной версии. При обновлении промежуточной версии хост игнорирует дополнительные поля данных и свойства. Например, устройство, использующее протокол версии 1.6, совместимо с хостом, который поддерживает протокол версии 1.x, включая версию 1.5.

Совместимость с основными версиями

При переходе на новую основную версию допускаются изменения, несовместимые с предыдущими версиями. Чтобы поддерживать несколько основных версий для взаимодействия со старыми и новыми хостами, устройства могут указывать несколько коллекций приложений в дескрипторах отчетов. Пример:

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

В этом случае хост может перечислить все коллекции приложений, рекламируемые устройством, изучить их свойство Sensor Description, чтобы определить, какие версии протокола они реализуют, а затем выбрать последнюю версию протокола, поддерживаемую хостом. В этом случае хост будет работать с одним протоколом, выбранным на все время подключения устройства.

Приложение. Пример дескриптора HID

Ниже приведен пример типичного действительного дескриптора HID. В нем используются распространенные макросы C, приведенные в разделе 4.1 HID Sensor Usages.

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

Приложение 2. Пример дескриптора HID версии 2.0

В примере ниже показан дескриптор HID версии 2.0 для устройства, поддерживающего только транспорт Bluetooth LE ACL.

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