Я использую AVAudioEngine для аудио в игровом приложении iOS. Проблема, с которой я столкнулся, заключается в том, что AVAudioPlayerNode.play () занимает много времени для выполнения, что может быть проблемой в приложениях реального времени, таких как игры.
play () просто активирует узел игрока - выне нужно звонить каждый раз, когда вы играете звук. Как таковой, он не должен вызываться так часто, но он должен вызываться время от времени, например, чтобы активировать игрока изначально или после того, как он был деактивирован (что происходит в некоторых ситуациях). Даже если время от времени вызывается, длительное время выполнения может быть проблемой, особенно если вам нужно вызывать play () сразу для нескольких игроков.
Время выполнения play () кажется пропорциональным значениюAVAudioSession.ioBufferDuration, которую вы можете запросить об изменении, используя AVAudioSession.setPreferredIOBufferDuration (). Вот некоторый код, который я использую для проверки этого:
import AVFoundation
import UIKit
class ViewController: UIViewController {
private let engine = AVAudioEngine()
private let player = AVAudioPlayerNode()
private let ioBufferSize = 1024.0 // Or 256.0
override func viewDidLoad() {
super.viewDidLoad()
let audioSession = AVAudioSession.sharedInstance()
try! audioSession.setPreferredIOBufferDuration(ioBufferSize / 44100.0)
try! audioSession.setActive(true)
engine.attach(player)
engine.connect(player, to: engine.mainMixerNode, format: nil)
try! engine.start()
print("IO buffer duration: \(audioSession.ioBufferDuration)")
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if player.isPlaying {
player.stop()
} else {
let startTime = CACurrentMediaTime()
player.play()
let endTime = CACurrentMediaTime()
print("\(endTime - startTime)")
}
}
}
Вот несколько примеров таймингов для play (), которые я получил, используя размер буфера 1024 (который я считаю значением по умолчанию):
0.0218
0.0147
0.0211
0.0160
0.0184
0.0194
0.0129
0.0160
Вот некоторые примеры таймингов с использованием размера буфера 256:
0.0014
0.0029
0.0033
0.0023
0.0030
0.0039
0.0031
0.0032
Как вы можете видеть выше, для размера буфера 1024 время выполнения обычно составляет 15-20Диапазон мс (около полного кадра при 60 FPS). С размером буфера 256 это составляет около 3 мс - не так уж плохо, но все же дорого, когда у вас есть только ~ 17 мс на кадр для работы.
Это на iPad Mini 2 под управлением iOS 12.4.2,Это, очевидно, старое устройство, но результаты, которые я вижу на симуляторе, кажутся одинаково пропорциональными, поэтому, похоже, он больше связан с размером буфера и поведением самой функции, чем с используемым оборудованием. Я не знаю, что происходит под капотом, но кажется возможным, что блоки play () до начала следующего звукового цикла или что-то в этом роде.
Запрос меньшего размера буфера выглядит как частичныйрешение, но есть некоторые потенциальные недостатки. Согласно документации здесь , меньший размер буфера может означать больший доступ к диску при потоковой передаче из файла, и, независимо от этого, запрос может не выполняться вообще. Также, здесь , кто-то сообщает о проблемах воспроизведения, связанных с малым размером буфера. Принимая все это во внимание, я не склонен рассматривать это как решение.
Это оставляет мне время выполнения play () в диапазоне 15-20 мс, что обычно означает пропущенный кадр при 60 FPS. ,Если я устрою так, что за один раз будет сделан только один вызов play (), и только изредка, может быть, это будет незаметно, но это не идеально.
Я искал информацию и спрашивалоб этом в других местах, но, похоже, на практике такое поведение встречается не у многих, или для них это не проблема.
AVAudioEngine предназначен для использования в приложениях реального времени, так что если яПравильно, что AVAudioPlayerNode.play () блокируется в течение значительного времени, пропорционального размеру буфера, что кажется проблемой проектирования. Я понимаю, что, вероятно, это не та проблема, с которой сталкиваются многие, но я пишу здесь, чтобы спросить, сталкивался ли кто-либо с этой конкретной проблемой с AVAudioEngine, и если да, то есть ли какие-либо идеи, предложения или обходные пути, которые кто-либо может предложить.