AVAudioPlayerNode lastRenderTime
Я использую несколько AVAudioPlayerNode
в AVAudioEngine
смешивать аудио файлы для воспроизведения. Как только все настройки сделаны (двигатель подготовлен, запущен, сегменты аудиофайлов запланированы), я звоню play()
метод на каждом узле игрока, чтобы начать воспроизведение.
Поскольку для прохождения всех узлов плеера требуется время, я делаю снимок первых узлов lastRenderTime
значение и использовать его для вычисления времени начала для узлов play(at:)
метод, чтобы синхронизировать воспроизведение между узлами:
let delay = 0.0
let startSampleTime = time.sampleTime // time is the snapshot value
let sampleRate = player.outputFormat(forBus: 0).sampleRate
let startTime = AVAudioTime(
sampleTime: startSampleTime + AVAudioFramePosition(delay * sampleRate),
atRate: sampleRate)
player.play(at: startTime)
Проблема в текущем времени воспроизведения.
Я использую это вычисление, чтобы получить значение, где seekTime
это значение, которое я отслеживаю в случае, если мы ищем игрока. Это 0.0
в начале:
private var _currentTime: TimeInterval {
guard player.engine != nil,
let lastRenderTime = player.lastRenderTime,
lastRenderTime.isSampleTimeValid,
lastRenderTime.isHostTimeValid else {
return seekTime
}
let sampleRate = player.outputFormat(forBus: 0).sampleRate
let sampleTime = player.playerTime(forNodeTime: lastRenderTime)?.sampleTime ?? 0
if sampleTime > 0 && sampleRate != 0 {
return seekTime + (Double(sampleTime) / sampleRate)
}
return seekTime
}
Хотя это дает относительно правильное значение, я слышу задержку между временем воспроизведения и первым слышимым звуком. Поскольку lastRenderTime
сразу начинает продвигаться, как только я позвоню play(at:)
и должно быть какое-то смещение времени обработки / буферизации.
Заметная задержка составляет около 100 мс, что очень велико, и мне нужно точное текущее значение времени для параллельного визуального рендеринга.
Это, вероятно, не имеет значения, но каждый аудиофайл является аудио AAC, и я планирую сегменты их в узлах проигрывателя, я не использую буферы напрямую. Длина сегментов может варьироваться. Я тоже звоню prepare(withFrameCount:)
на каждом узле плеера, когда у меня есть запланированные аудиоданные.
Итак, мой вопрос: задержка, которую я наблюдаю, является проблемой буферизации? (Я имею в виду, должен ли я планировать более короткие сегменты, например), есть ли способ вычислить именно это значение, чтобы я мог настроить текущее вычисление времени воспроизведения?
Когда я устанавливаю блок крана на одном AVAudioPlayerNode
блок вызывается с буфером длины 4410
и частота дискретизации 44100 Hz
, это означает 0,1 с аудио данных. Должен ли я рассчитывать на это для вычисления задержки?
Мне интересно, могу ли я доверять длине буфера, который я получаю в блоке tap. В качестве альтернативы я пытаюсь вычислить общую задержку для моего звукового графика. Может ли кто-нибудь дать представление о том, как точно определить это значение?
1 ответ
Из сообщения theanalogkid на форумах разработчиков Apple :
В системе задержка измеряется:
Размер кадра буфера ввода-вывода аудиоустройства + безопасное смещение вывода + задержка выходного потока + задержка выходного устройства
Если вы пытаетесь рассчитать общую задержку туда и обратно, вы можете добавить:
Задержка ввода + безопасное смещение ввода к вышеуказанному.
Временная метка, которую вы видите в процедуре рендеринга. учитывают размер кадра буфера и безопасное смещение, но задержки потока и устройства не учитываются.
iOS дает вам доступ к наиболее важной из вышеуказанной информации через AVAudioSession, и, как уже упоминалось, вы также можете использовать «предпочтительные» настройки сеанса.
- setPreferredIOBufferDuration
а также
preferredIOBufferDuration
для дальнейшего контроля.
/ The current hardware input latency in seconds. */
@property(readonly) NSTimeInterval inputLatency NS_AVAILABLE_IOS(6_0);
/ The current hardware output latency in seconds. */
@property(readonly) NSTimeInterval outputLatency NS_AVAILABLE_IOS(6_0);
/ The current hardware IO buffer duration in seconds. */
@property(readonly) NSTimeInterval IOBufferDuration NS_AVAILABLE_IOS(6_0);
Аудиоустройства также имеют
kAudioUnitProperty_Latency
свойство, которое вы можете запросить.