Воспроизведение звука с низкой задержкой на Android

В настоящее время я пытаюсь минимизировать задержку звука для простого приложения:

У меня есть видео на ПК, и я передаю аудио видео через RTP на мобильный клиент. С очень похожим алгоритмом буферизации я могу добиться задержки в 90 мс на iOS, но ужасных ± 180 мс на Android.

Я предполагаю, что разница связана с хорошо известной задержкой issues на Android.

Однако, немного почитав, Я наткнулся на эту статью, в которой говорится, что:

  1. Звук с низкой задержкой доступен на некоторых устройствах начиная с Android 4.1 / 4.2.

  2. Звук с низкой задержкой можно получить с помощью libpd, библиотеки Pure Data для Android.

У меня есть 2 вопроса, напрямую связанных с этими двумя утверждениями:

  1. Где я могу найти дополнительную информацию о новом аудио с низкой задержкой в ​​Jellybean? Это все, что я могу найти, но конкретной информации крайне не хватает. Должны ли изменения быть прозрачными для меня или есть какие-то новые вызовы классов / API, которые я должен реализовать, чтобы я заметил какие-либо изменения в моем приложении? Я использую AudioTrack API, и я даже не уверен, должен ли он получить выгоду от этого улучшения или мне следует изучить какой-то другой механизм для воспроизведения звука.

  2. Стоит ли мне изучить использование libpd? Мне кажется, что это единственный шанс добиться более низких задержек, но поскольку я всегда думал о PD как об утилите для синтеза звука, действительно ли она подходит для проекта, который просто захватывает кадры из сетевого потока и воспроизводит их? ? На самом деле я не занимаюсь синтезом. Я иду по неправильному пути?

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

«Поскольку OpenSL ES является собственным API-интерфейсом C, потоки приложений, не относящиеся к Dalvik, которые вызывают OpenSL ES, не имеют связанных с Dalvik накладных расходов, таких как паузы при сборке мусора. Однако использование OpenSL ES не дает дополнительных преимуществ производительности, кроме В частности, использование OpenSL ES не приводит к более низкой задержке звука, более высокому приоритету планирования и т. д. по сравнению с тем, что обычно предоставляет платформа ».


person Sergio Morales    schedule 12.02.2013    source источник
comment
Я член команды Android и тесно сотрудничаю с авторами статьи, которую вы цитируете. Процитированный вами отрывок уже не совсем верен. На момент написания статьи самые маленькие буферы, доступные для OpenSL, были еще довольно большими. Теперь, когда размер буфера в Jellybean уменьшен, задержка упала до такой степени, что накладные расходы, связанные с Dalvik, такие как паузы при сборке мусора, становятся очень важным фактором. Единственный способ надежно использовать преимущества буферов Jellybean меньшего размера - это использовать OpenSL.   -  person Ian Ni-Lewis    schedule 25.04.2013


Ответы (7)


Для минимальной задержки на Android начиная с версии 4.2.2 вы должны сделать следующее в порядке от наименее до наиболее очевидного:

  1. Выберите устройство, которое поддерживает FEATURE_AUDIO_PRO, если возможно, или FEATURE_AUDIO_LOW_LATENCY, если нет. («Низкая задержка» - 50 мс в одну сторону; pro - 20 мс туда и обратно.)

  2. Используйте OpenSL. Dalvik GC имеет низкую амортизированную стоимость, но при его запуске требуется больше времени, чем может позволить аудиопоток с малой задержкой.

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

  4. Сделайте размер буфера кратным AudioManager.getProperty (PROPERTY_OUTPUT_FRAMES_PER_BUFFER). В противном случае ваш обратный вызов будет иногда получать два вызова за интервал времени, а не один. Если ваш процессор не используется действительно низко, это, вероятно, закончится сбоем. (В Android M очень важно использовать ТОЧНО размер системного буфера из-за ошибки в коде обработки буфера.)

  5. Используйте частоту дискретизации, предоставленную AudioManager.getProperty (PROPERTY_OUTPUT_SAMPLE_RATE). В противном случае ваши буферы будут обходиться через системный ресамплер.

  6. Никогда не выполняйте системный вызов и не блокируйте объект синхронизации внутри обратного вызова буфера. Если необходимо синхронизировать, используйте структуру без блокировок. Для достижения наилучших результатов используйте структуру, полностью свободную от ожидания, такую ​​как кольцевой буфер с одним считывателем и одной записью. Множество разработчиков ошибаются, и в конечном итоге возникают непредсказуемые и трудно поддающиеся отладке сбои.

  7. Используйте векторные инструкции, такие как NEON, SSE или любой другой аналогичный набор инструкций на вашем целевом процессоре.

  8. Протестируйте и оцените свой код. Отслеживайте, сколько времени требуется для запуска, и помните, что вам нужно знать производительность в худшем случае, а не в среднем, потому что именно в худшем случае возникают сбои. И будьте консервативны. Вы уже знаете, что если для обработки звука требуется больше времени, чем для его воспроизведения, у вас никогда не будет низкой задержки. Но на Android это еще важнее, потому что частота процессора сильно колеблется. Вы можете использовать, возможно, 60-70% ЦП для звука, но имейте в виду, что это изменится, когда устройство станет горячее или холоднее, или когда Wi-Fi или радиомодули LTE будут запускаться и останавливаться, и так далее.

Звук с низкой задержкой больше не является новой функцией для Android, но для ее реализации по-прежнему требуются специфические для устройства изменения в оборудовании, драйверах, ядре и структуре. Это означает, что существует много различий в задержке, которую вы можете ожидать от разных устройств, и, учитывая, сколько разных ценовых пунктов продаются телефоны Android, вероятно, всегда будут различия. Ищите FEATURE_AUDIO_PRO или FEATURE_AUDIO_LOW_LATENCY, чтобы определить устройства, которые соответствуют критериям задержки, требуемым вашим приложением.

person Ian Ni-Lewis    schedule 25.04.2013
comment
По пункту 5. Если исходный звук записан, скажем, на 44100, но PROPERTY_OUTPUT_SAMPLE_RATE равен 48000, тогда звук будет воспроизводиться слишком быстро. Как лучше всего обойти это? - person Ian1971; 16.09.2013
comment
Ян, я считаю, что PROPERTY_OUTPUT_SAMPLE_RATE (POSR) относится к собственной частоте дискретизации звука звукового процессора вашего устройства. Это означает, что если вы подаете на него звук с дискретизацией 48 кГц, а POSR вашего устройства составляет 48 кГц, то системе не придется выполнять дополнительную работу, и, следовательно, ее можно будет воспроизводить без дополнительной задержки. - person rmigneco; 17.03.2014
comment
Предоставление ему звука с дискретизацией, скажем, 44,1 кГц, не означает, что он будет воспроизводиться с другой скоростью, но вам требуется, чтобы ОС / устройство выполняли дополнительный шаг повторной дискретизации для обработки звука с частотой 48 кГц, что увеличивает задержку. - person rmigneco; 17.03.2014
comment
Дело в том, чтобы инициализировать воспроизведение звука на частоте устройства и выполнить возможную передискретизацию аудиоданных на стороне приложения. - person Pointer Null; 25.04.2014
comment
Re. # 4 Сделайте размер вашего буфера кратным AudioManager.getProperty (PROPERTY_OUTPUT_FRAMES_PER_BUFFER) ... Я считаю, что размер буфера OpenSL должен быть 1x, 2x, 3x и т. Д. PROPERTY_OUTPUT_FRAMES_PER_BUFFER. Это все еще правда? Это свойство различается для разных устройств, но я видел до 3840, что приводит к высокой задержке. Или вместо этого, вы имеете в виду, что OpenSL может быть фактором PROPERTY_OUTPUT_FRAMES_PER_BUFFER (т.е. 64)? - person windup; 03.11.2014
comment
Хм, хороший вопрос. Я думаю, что теоретически это может быть фактором, потому что OpenSL будет вызывать ваш обратный вызов несколько раз, пока не будет достаточно данных. Но это было бы менее эффективно, чем просто сделать буфер достаточно большим, и это вообще не повлияло бы на задержку. 3840 довольно большой, но помните, что более высокая задержка == меньшая мощность, поэтому неудивительно, что некоторые устройства могут пойти на такой компромисс. У этих устройств просто паршивая задержка, и с этим ничего не поделать. - person Ian Ni-Lewis; 03.02.2015
comment
Спасибо. Пункт 5 действительно важен и действительно должен быть №1, поскольку каждый может использовать его, независимо от проекта. Это помогло мне победить орков-вауза. - person sbaar; 17.11.2015
comment
На Android M очень важно использовать ТОЧНО размер системного буфера из-за ошибки в коде обработки буфера. Есть ли дополнительная информация по этому поводу? Кажется, у меня есть эта проблема. Думаю, в этом случае люди вынуждены использовать звук с малой задержкой. - person Matthew Mitchell; 16.09.2016
comment
@PointerNull Спасибо за ваш комментарий. Скажите, правильно ли я вас понял? Скажем, у меня есть звуковой файл, записанный с частотой 24000 Гц, и устройство с частотой 48000 Гц. В этом случае у меня есть два варианта. 1. Выполните инициализацию на 24000 и позвольте системному ресамплеру выполнить свою работу. 2. Выполните инициализацию на 48000 и передискретизируйте источник звука самостоятельно. - person Jenix; 19.05.2019
comment
Но последний вариант лучше по задержке. Это верно? - person Jenix; 19.05.2019
comment
Да @Jenix, ты прав. Но, возможно, если вы попытаетесь добиться низкой задержки, передискретизацию источника следует проводить заранее, а не на лету. - person Stéphane; 09.06.2019

При использовании OpenSL ES вы должны выполнить следующие требования для получения вывода с низкой задержкой в ​​Jellybean и более поздних версиях Android:

  • Звук должен быть моно или стерео, линейный PCM.

  • Частота дискретизации звука должна быть такой же, как собственная частота дискретизации выходного сигнала (на некоторых устройствах это может не потребоваться, поскольку FastMixer может выполнять повторную дискретизацию, если производитель настраивает его для этого. Но в своих тестах я обнаружил очень заметные артефакты при повышении частоты дискретизации с 44,1 до 48 кГц в FastMixer).

  • Ваш BufferQueue должен иметь как минимум 2 буфера. (С тех пор это требование было ослаблено. См. эту фиксацию Гленн Кастен. Я не уверен, в какой версии Android это впервые появилось, но предполагаю, что это 4.4).

  • Вы не можете использовать определенные эффекты (например, реверберацию, усиление низких частот, эквализацию, виртуализацию и т. Д.).

Класс SoundPool также будет пытаться использовать быстрые AudioTrack внутри, когда это возможно (применяются те же критерии, что и выше, за исключением части BufferQueue).

person Michael    schedule 21.02.2013

По ссылке в вашем пункте 1:

"Звук с малой задержкой

В Android 4.2 улучшена поддержка воспроизведения звука с малой задержкой, начиная с улучшений, внесенных в выпуск Android 4.1 для задержки вывода звука с использованием API OpenSL ES, Soundpool и тон-генератора. Эти улучшения зависят от поддержки оборудования - устройства, которые предлагают эти звуковые функции с малой задержкой, могут объявлять о своей поддержке приложениям с помощью константы аппаратной функции ".

Ваша цитата в полной форме:

"Представление

Поскольку OpenSL ES является собственным API-интерфейсом C, потоки приложений, не относящиеся к Dalvik, которые вызывают OpenSL ES, не имеют накладных расходов, связанных с Dalvik, таких как паузы при сборке мусора. Тем не менее, нет никаких дополнительных преимуществ в производительности от использования OpenSL ES, кроме этого. В частности, использование OpenSL ES не приводит к более низкой задержке звука, более высокому приоритету планирования и т. Д., Чем то, что обычно предоставляет платформа. С другой стороны, поскольку платформа Android и реализации конкретных устройств продолжают развиваться, приложение OpenSL ES может рассчитывать на получение выгоды от любых будущих улучшений производительности системы ».

Итак, api для связи с драйверами, а затем hw - это OpenSl (так же, как Opengl делает с графикой). Однако более ранние версии Android имеют плохой дизайн драйверов и / или аппаратного обеспечения. Эти проблемы были решены и исправлены в версиях 4.1 и 4.2, поэтому, если у жесткого диска есть питание, вы получите низкую задержку с использованием OpenSL.

Опять же, из этой заметки с веб-сайта библиотеки puredata очевидно, что библиотека использует сам OpenSL для достижения низкой задержки:

Поддержка малой задержки для совместимых устройств Последняя версия Pd для Android (по состоянию на 28.12.2012) поддерживает звук с низкой задержкой для совместимых устройств Android. При обновлении копии обязательно загрузите последнюю версию pd-for-android и подмодуля libpd с GitHub.

На момент написания статьи Galaxy Nexus, Nexus 4 и Nexus 10 предоставляют дорожку с низкой задержкой для вывода звука. Чтобы попасть на трек с низкой задержкой, приложение должно использовать OpenSL, и оно должно работать с правильной частотой дискретизации и размером буфера. Эти параметры зависят от устройства (Galaxy Nexus и Nexus 10 работают на частоте 44100 Гц, а Nexus 4 - на частоте 48000 Гц; размер буфера для каждого устройства разный).

Как это обычно бывает, Pd for Android максимально подробно описывает все эти сложности, предоставляя доступ к новым функциям с низкой задержкой, когда они доступны, оставаясь при этом обратно совместимой с более ранними версиями Android. Под капотом аудиокомпоненты Pd для Android будут использовать OpenSL на Android 2.3 и более поздних версиях, а также будут использовать старый API AudioTrack / AudioRecord в Java на Android 2.2 и более ранних версиях.

person AndrewBloom    schedule 21.02.2013

Те из вас, кто больше интересуется проблемой 10 миллисекунд Android, то есть звуком с низкой задержкой на Android. Мы в Superpowered создали объяснение задержки звукового пути Android. Пожалуйста, смотрите здесь:

http://superpowered.com/androidaudiopathlatency/#axzz3fDHsEe56

person Patrick Vlaskovits    schedule 07.07.2015
comment
Это хорошее объяснение, но оно не на 100% актуально. Буферизация AudioFlinger была уменьшена в L, удалив в общей сложности два буфера из пути. В настоящее время существует один эффективный буфер задержки между приложением и HAL (похоже, что больше, но часть кода синхронна - большее количество memcpys не всегда означает большую задержку). Кроме того, не уверен, где находится значение задержки шины 6 мс. приходящий из. Это кажется слишком высоким. - person Ian Ni-Lewis; 05.04.2016
comment
Привет, Ян. Надеюсь, с тобой все в порядке. У нас есть более новая обновленная версия здесь: superpowered.com/android-marshmallow-latency - person Patrick Vlaskovits; 07.04.2016
comment
Это выглядит примерно правильно. Единственное, чего не хватает, так это Nexus 9 DSP - он называется AHUB в техническом описании Tegra K1. Я предполагаю, что у FIFO больше задержек после программного обеспечения, чем у шины. Я думаю, вы также могли упустить из виду тот факт, что вызов записи HAL блокируется. Вызов не возвращается, пока не сработает следующее прерывание, поэтому весь механизм планируется на основе звукового прерывания, а не на монотонном планировщике скорости. Здесь есть несколько серьезных проблем, многие из которых уникальны для ОС на базе Linux, но я не думаю, что модель push является одной из них. - person Ian Ni-Lewis; 11.04.2016
comment
Привет, Ян, ну, GIF на superpowered.com/ images / показывает задержку приема-передачи с использованием коннектора обратной связи, при котором ни один из процессоров Tegra DSP не активен. Вызов записи HAL может блокировать одни HAL и не блокировать другие. Из-за текущей архитектуры AudioFlinger, основанной на режиме сна, и других факторов, AudioFlinger и сторона пользовательского приложения (AudioTrack и др.) Добавляют более 1 буфера к задержке приема-передачи. - person Patrick Vlaskovits; 12.04.2016
comment
DSP не активен - вы, вероятно, имели в виду, что эффекты OpenSL отключены. Эти эффекты - не единственное, что делает DSP - он также обрабатывает микширование, маршрутизацию, защиту динамиков и т.д. содержать сон. Что не очевидно из кода, так это то, как часто этот код вызывается, потому что почти все HAL блокируют запись. Мы не знаем ничего такого. Тем не менее, у нас есть некоторые данные, которые подразумевают, что HAL с асинхронной записью + засыпанием фактически получает большую задержку, чем HAL с блокирующей записью. - person Ian Ni-Lewis; 13.05.2016
comment
Привет, Патрик, я действительно думаю, что мне нужно немного отреагировать на свое заявление о толчке. Базовая архитектура Android - это не совсем то, что я бы назвал моделью push, но я думаю, что это спорно. А вот что - это модель проталкивания, так это OpenSL ES. Вы не можете сказать, насколько велики вы хотите, чтобы ваши буферы были (только сколько их), и он не может сказать вам, сколько звука ему нужно (только то, что он потребляет часть). Можно аппроксимировать вытягивающую модель, правильно получив все числа и сделав некоторые осторожные предположения, но это ни в коем случае не легко и не надежно. - person Ian Ni-Lewis; 13.05.2016
comment
Привет, Ян, внимательно следи за нашими последними новостями. Сверхмощный медиа-сервер для Android. Мы едем туда и обратно на расстояние менее 10 мс. Подробнее здесь: superpowered.com/ - person Patrick Vlaskovits; 16.06.2016

Еще одна база данных о задержках звука и размерах буферов:

http://superpowered.com/latency/#table

Исходный код:

https://github.com/superpoweredSDK/SuperpoweredLatency

person Christopher Fraser    schedule 10.03.2015

Приложение для измерения sampleRate и bufferSize: https://code.google.com/p/high-performance-audio/source/checkout и http://audiobuffersize.appspot.com/ БД результатов

person Mickey Tin    schedule 19.08.2013

Существует новая библиотека C ++ Oboe, которая помогает уменьшить задержку звука. Я использовал его в своих проектах, и он хорошо работает. Он имеет следующие функции, которые помогают уменьшить задержку звука:

  • Автоматическая настройка задержки
  • Выбирает аудио API (OpenSL ES на API 16+ или AAudio на API 27+)
person Wrobel    schedule 09.11.2018
comment
Хммм, а как преобразовать любой тип файла для исправления необработанного чтения с помощью примера алгоритма Oboe? - person Ráfagan; 23.11.2018
comment
Я использую бесплатное приложение Audacity для преобразования аудио в Android raw - person Wrobel; 26.11.2018
comment
Вы используете какой-то алгоритм, основанный на примерах гобоя? Они читают необработанные файлы с частотой 48000 Гц и 16-битным целым числом. Вы тоже используете этот необработанный формат? - person Ráfagan; 26.11.2018
comment
Я использую 16-битный формат 44100 Гц, но вы можете использовать 48000 или другую частоту - person Wrobel; 27.11.2018
comment
@Wrobel Вы тестировали гобой с гарнитурой Bluetooth? Есть ли значительная задержка при использовании? - person Roman Samoilenko; 18.01.2019