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свойство, которое вы можете запросить.

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