Android: звуковой API (детерминированный, низкая задержка)

Я рассматриваю все виды звукового API для Android и хотел бы знать, какой из них мне следует использовать. Моя цель - получить звук с низкой задержкой или, по крайней мере, детерминированное поведение в отношении задержки воспроизведения.

У нас было много проблем, и кажется, что Android Sound API - это дерьмо, поэтому я изучаю возможности.

Проблема в том, что между sound_out.write(sound_samples); и реальный звук воспроизводится из динамиков. Обычно это около 300 мс. Проблема в том, что на всех устройствах это отличается; некоторые не имеют такой проблемы, но большинство покалечены (однако CS-вызов имеет нулевую задержку). Самая большая проблема с этой нелепой задержкой заключается в том, что на некоторых устройствах эта задержка представляется случайной величиной (т.е. она не всегда составляет 300 мс).

Я читаю об OpenSL ES, и я хотел бы знать, имел ли кто-нибудь опыт с этим, или это то же самое дерьмо, но обернутое в другой пакет?

Я предпочитаю иметь собственный доступ, но я не возражаю против косвенного обращения к слою Java, если могу получить детерминированное поведение: либо задержка должна быть постоянной (для данного устройства), либо я хочу получить доступ к текущему воспроизведению положение вместо угадывания с диапазоном ошибок ±300 мс...

РЕДАКТИРОВАТЬ:
Спустя 1,5 года я попробовал несколько телефонов Android, чтобы увидеть, как я могу получить максимально возможную задержку для голосовой связи в реальном времени. Используя специализированные инструменты, я измерил задержку волнового пути. Лучшие результаты были более 100 мс, большинство телефонов были в диапазоне 180 мс. У кого-нибудь есть идеи?

5 ответов

Решение

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

Почему OpenSL? AudioTrack и OpenSL имеют одинаковые задержки с одним важным отличием: обратные вызовы буфера AudioTrack обслуживаются в Dalvik, а обратные вызовы OpenSL обслуживаются в собственных потоках. Текущая реализация Dalvik не способна обслуживать обратные вызовы с чрезвычайно малыми задержками, потому что нет способа приостановить сборку мусора во время звуковых обратных вызовов. Это означает, что минимальный размер для буферов AudioTrack должен быть больше минимального размера для буферов OpenSL, чтобы поддерживать воспроизведение без сбоев.

В большинстве выпусков Android эта разница между AudioTrack и OpenSL не имела никакого значения. Но с Jellybean Android теперь имеет аудиотракт с малой задержкой. Фактическая задержка все еще зависит от устройства, но она может быть значительно ниже, чем ранее. Например, http://code.google.com/p/music-synthesizer-for-android/ использует 384-кадровые буферы на Galaxy Nexus для общей задержки вывода менее 30 мс. Это требует, чтобы аудиопоток обслуживал буферы примерно один раз каждые 8 ​​мс, что было невозможно в предыдущих выпусках Android. Это все еще не осуществимо в потоке Dalvik.

Это объяснение предполагает две вещи: во-первых, вы запрашиваете наименьшие возможные буферы из OpenSL и выполняете свою обработку в обратном вызове буфера, а не в очереди буфера. Во-вторых, ваше устройство поддерживает путь с низкой задержкой. На большинстве современных устройств вы не увидите большой разницы между AudioTrack и OpenSL ES. Но на устройствах, которые поддерживают Jellybean+ и аудио с низкой задержкой, OpenSL ES обеспечит вам путь с самой низкой задержкой.

IIRC, OpenSL передается через тот же интерфейс, что и AudioTrack, поэтому в лучшем случае он будет соответствовать AudioTrack. (FWIW, я в настоящее время использую OpenSL для вывода с "низкой задержкой")

Печальная правда в том, что на Android нет такой вещи, как звук с низкой задержкой. Нет даже правильного способа помечать и / или фильтровать устройства по задержке звука.

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

Если вы хотите вызвать статические выстрелы, вы можете использовать SoundPool. Для статических ударов SoundPool будет иметь низкую задержку, поскольку сэмплы предварительно загружены в аппаратное обеспечение. Я думаю, что есть возможность предварительно загружать снимки с помощью OpenSL, но я не пробовал.

Самая низкая задержка, которую вы можете получить от SoundPool. Существует ограничение на то, насколько велик звук, который вы можете воспроизводить таким образом, но если вы ограничены (1Mb, IIRC), это довольно низкая задержка. Даже это, вероятно, не 40 мс, хотя.

Но это быстрее, чем то, что вы можете получить с помощью потоковой передачи, по крайней мере, по моему опыту.

Предостережение. Вы можете увидеть случайные сбои в SoundPool на устройствах Samsung. У меня есть теория, что это происходит только при доступе к SoundPool из нескольких потоков, но я не проверял это.

РЕДАКТИРОВАТЬ: OpenSL ES, очевидно, имеет очень высокую задержку на Kindle Fire, в то время как SoundPool намного лучше, но обратное может быть верно для других платформ.

О проблеме детерминированной / постоянной задержки, здесь вы можете найти интересную статью:

ПОДХОДЫ ДЛЯ ПОСТОЯННОЙ АУДИО-ЛАТЕНЦИИ НА АНДРОИДЕ

Суть их исследований заключается в следующем: поскольку Audio HAL, который является одним из более глубоких уровней аудиопата и отвечает за синхронизацию событий аудиозвонка, реализуется поставщиком, относительные задержки могут варьироваться, особенно в дешевом оборудовании. Таким образом, они предлагают два подхода к уменьшению дисперсии задержки. Один из них заключается в том, чтобы позаботиться о синхронизации обратного вызова, вставляя звук с фиксированными интервалами, другой - отфильтровать время обратного вызова, чтобы оценить время, в которое должен был произойти обратный вызов с постоянной задержкой, применяя фильтр сглаживания. С помощью этих двух подходов можно значительно уменьшить дисперсию задержки.

Также следует отметить, что появился новый Android-Audio-API, AAudio.

AAudio API

Это доступно / стабильно с Android Oreo 8.1 (API уровень 27). Существует также оболочка, которая динамически выбирает между OpenSL ES и AAudio и намного проще кодировать OpenSL ES. Это все еще в предварительном просмотре разработчика.

Oboe Audio Library

Лучший способ получить низкую задержку для нативного кода на Android - это использовать Oboe.

https://github.com/google/oboe

Гобой обертывает AAudio на новых устройствах. AAudio предлагает пути с наименьшей возможной задержкой. Если AAudio недоступен, тогда Oboe вызывает OpenSL ES. Гобой гораздо проще в использовании, чем OpenSL ES.

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

Другие вопросы по тегам