Звук с низкой задержкой

Звук с низкой задержкой делает игры более реалистичными и отзывчивыми.

Заполните следующий контрольный список, чтобы включить звук с низкой задержкой в ​​вашей игре на Android:

  1. Используйте гобой
  2. Запросить режим производительности «малая задержка»
  3. Запросить режим обмена «эксклюзивный»
  4. Используйте частоту 48000 Гц или преобразователь частоты дискретизации гобоя.
  5. Установите использование AAUDIO_USAGE_GAME.
  6. Используйте обратные вызовы данных
  7. Избегайте блокировки операций в обратном вызове
  8. Настройте размер буфера на «двойной буфер»

1. Используйте API гобоя

API гобоя — это оболочка C++, которая вызывает AAudio на Android 8.1 (уровень API 27) или выше. В более ранних версиях Android гобой использует OpenSL ES.

Гобой доступен на GitHub или в виде готового двоичного файла . У гобоя также есть QuirksManager, который исправляет проблемы на определенных устройствах, что делает ваше приложение совместимым с большим количеством устройств. Если вы не можете использовать гобой, используйте напрямую AAudio.

2. Запросить режим с низкой задержкой.

Для гобоя или AAudio запросите режим с низкой задержкой. В противном случае по умолчанию вы получаете режим с более высокой задержкой.

Гобой

builder.setPerformanceMode(oboe::PerformanceMode::LowLatency);

ААудио

AAudioStreamBuilder_setPerformanceMode(builder, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);

3. Запросить эксклюзивный режим

Вы также можете запросить эксклюзивный доступ к буферу MMAP. Ваше приложение может не иметь монопольного доступа, но если он есть, ваше приложение записывает данные непосредственно в буфер, который считывается DSP, что обеспечивает минимально возможную задержку.

Гобой

builder.setSharingMode(oboe::SharingMode::Exclusive);

ААудио

AAudioStreamBuilder_setSharingMode(builder, AAUDIO_SHARING_MODE_EXCLUSIVE);

4. Избегайте преобразования частоты дискретизации

Используйте естественную частоту дискретизации устройства. Вы можете сделать это, не указывая частоту дискретизации, и вы почти наверняка получите 48000 Гц. Если вы укажете частоту дискретизации, звуковая платформа отправит ваши данные по другому пути, который может иметь гораздо более высокую задержку.

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

builder->setSampleRateConversionQuality(oboe::SampleRateConversionQuality::Medium);

5. Правильно обозначьте свой вариант использования

Указание причины, по которой ваше приложение воспроизводит звук, имеет решающее значение для того, чтобы система применяла правильные настройки маршрутизации, громкости и производительности. Например, в играх должно быть указано использование AAUDIO_USAGE_GAME чтобы в полной мере воспользоваться преимуществами оптимизации задержки, особенно при подключении к гарнитурам Bluetooth.

Гобой

builder.setUsage(oboe::Usage::Game);

ААудио

AAudioStreamBuilder_setUsage(builder, AAUDIO_USAGE_GAME);

6. Используйте функцию обратного вызова

Используйте обратный вызов для выходного потока. Если вы используете блокировку записи и используете устройство, которое не поддерживает режим AAudio MMAP, задержка может быть намного выше.

Гобой

builder.setDataCallback(&myCallbackObject);

ААудио

AAudioStreamBuilder_setDataCallback(builder, &my_callback_proc);

7. Избегайте блокировки обратного вызова

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

Избегайте выполнения следующих действий при обратном вызове:

  • Выделение или освобождение памяти
  • Файловый или сетевой ввод-вывод
  • Ожидание мьютекса или блокировки
  • Спать
  • Тяжелые одноразовые вычисления ЦП

Обратные вызовы должны выполнять математические операции равномерно, чтобы обеспечить плавное воспроизведение без сбоев.

8. Настройте размер буфера

Как только ваше приложение откроет аудиопоток, вам необходимо настроить полезный размер буфера для оптимальной задержки. Гобой автоматически устанавливает размер буфера на два пакета. Но с AAudio значение по умолчанию намного выше. Используйте двойную буферизацию, установив размер буфера в два раза больше размера пакета. Размер пакета — это максимальный размер обратного вызова.

ААудио:

int32_t frames = AAudioStream_getFramesPerBurst() * 2;
AAudioStream_setBufferSizeInFrames(stream, frames);

Если размер буфера слишком мал, могут возникнуть сбои, вызванные опустошением буфера. Вы можете получить количество сбоев, вызвав AAudioStream_getXRunCount(stream) . При необходимости увеличьте размер буфера.

См. документацию GitHub Oboe для объяснения терминологии, связанной с буфером.

OpenSL ES

Если вы поддерживаете версии Android до 8.1, вам необходимо использовать OpenSL ES. Если вы используете гобой, вы можете настроить свое приложение так, чтобы уменьшить задержку. См. раздел «Получение оптимальной задержки» в документации GitHub.

Результаты контрольного списка

В следующей таблице приведены измерения OboeTester двусторонней задержки (вход-выход).

Конфигурация Задержка (мс)
Следуйте всем рекомендациям 20
Режим производительности не с низкой задержкой 205
НЕ ЭКСКЛЮЗИВНО (РАЗДЕЛЕНО) 26
44100 Гц (ААудио) 160
44100 Гц (гобой SRC) 23
Не использовать выходной обратный вызов (MMAP) 21
Не использовать выходной обратный вызов (не MMAP) 62
Размер буфера установлен на максимум 53