Сколько звуков можно воспроизводить одновременно на iOS — AVAudioPlayer против AVAudioEngine и AVAudioPlayerNode

У меня есть приложение, в котором есть набор из примерно 50 звуков, длина которых варьируется от примерно 300 мс до примерно 4 секунд. Различные комбинации звуков должны воспроизводиться в точное время (до 10 из них могут быть вызваны одновременно). Некоторые звуки необходимо повторять с интервалом в 100 мс.

Я реализовал это как двумерный массив AVAudioPlayers, каждый из которых загружается звуком при запуске приложения. Для каждого звука есть несколько проигрывателей, чтобы приспособить быстро повторяющиеся звуки. Плееры для определенного звука повторно используются в строгой ротации. Когда планируется новый звук, самый старый проигрыватель для этого звука останавливается, а его текущее время устанавливается равным 0, поэтому звук будет повторяться с самого начала в следующий раз, когда он будет запланирован с помощью player.play(atTime:). Есть поток, который планирует новые наборы звуков примерно за 300 мс до их воспроизведения.

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

Я подумываю о переходе на AVAudioEngine и AVAudioPlayerNodes, используя узел микшера. Кто-нибудь знает, может ли этот подход обрабатывать больше одновременных звуков? Я предполагаю, что оба подхода преобразуются в довольно похожий набор функций CoreAudio, но на самом деле я не писал код для проверки этой гипотезы — прежде чем я это сделаю, я надеюсь, что кто-то еще исследовал эту проблему до меня. Раньше я был глубоко в CoreAudio, и я надеюсь, что вместо этого смогу использовать эти удобные высокоуровневые функции!

Кроме того, кто-нибудь знает способ вызвать закрытие, когда звук инициируется? Задокументированная функциональность позволяет закрытие обратного вызова, но единственный способ, которым я смог инициировать события при запуске звуков, — это создать очередь обслуживания высокого качества для DispatchQueue. К сожалению, в зависимости от загрузки системы, события в очереди могут выполняться во время, отличающееся от запланированного примерно на 50 мс, что не так точно, как хотелось бы.


person Andromeda    schedule 27.04.2020    source источник


Ответы (1)


Использование AVAudioEngine с AVAudioPlayersNodes обеспечивает гораздо лучшую производительность, хотя и за счет небольшого усложнения кода. Мне удалось легко увеличить скорость воспроизведения в пять раз благодаря лучшему управлению буфером.

Основным недостатком перехода на этот подход было то, что документация Apple не очень хороша. Несколько дополнений к документации Apple сделали бы эту задачу НАМНОГО проще:

Узлы микшера задокументированы как способные преобразовывать частоты дискретизации и количество каналов, поэтому я попытался настроить audioEngine.mainMixerNode для преобразования монофонических буферов в настройки выходного узла. Установка выходного узла основного микшера в формат выходного узла, казалось, была принята, но во время выполнения возникали непрозрачные ошибки, которые жаловались на несоответствие количества каналов.

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

Кроме того, простое планирование буфера ничего не воспроизводит. Вам нужно вызвать play() на узле игрока, прежде чем что-либо произойдет. Документация Apple здесь сбивает с толку — в ней говорится, что вызов play() без аргументов приведет к немедленному воспроизведению, чего я не хотел. Потребовались некоторые эксперименты, чтобы определить, что play() просто сообщает узлу игрока о пробуждении, и что запланированные буферы фактически будут воспроизводиться в запланированное время, а не немедленно.

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

Хорошо написанная статья Криса Адамсона «Learning Core Audio» очень помогла мне, когда я работал с Core Audio — жаль, что более новая функциональность AVAudioEngine практически не документирована.

person Andromeda    schedule 02.05.2020