Лучший способ воспроизвести тишину с помощью AVAudioPlayer на iOS

#ios #swift #avaudioplayer #avkit

#iOS #swift #avaudioplayer #avkit

Вопрос:

Я оказался в ситуации, когда мне нужно имитировать воспроизведение звука, чтобы обмануть элементы управления ОС и MPNowPlayingInfoCenter заставить думать, что воспроизводится звук. Это потому, что я создаю проигрыватель, который воспроизводит несколько звуковых дорожек с паузами между ними, создавая одну непрерывную «звуковую» дорожку. У меня уже все настроено внутри самого приложения, и элементы управления экраном блокировки работают правильно, но единственная проблема, с которой я сталкиваюсь, заключается в том, что при фактической остановке звука и «воспроизведении» паузы информационный центр экрана блокировки останавливает таймер, и он продолжает показывать только правильное время и общее состояниекак только начнется воспроизведение другой звуковой дорожки.

Вот пример моей звуковой дорожки, созданной из аудиофайлов и элементов паузы:

 let items: [AudioItem] = [
    .audio("part-1.mp3"),
    .pause(duration: 5), // value of type: TimeInterval
    .audio("part-2.mp3"),
    .pause(duration: 3),
    ... // the list goes on
]
 

затем в моем пользовательском проигрывателе, после AVAudioPlayer завершения работы с текущим элементом, я получаю следующий элемент из массива и играю либо .pause с запланированным Timer , либо .audio с другим AVAudioPlayer .

 extension Player: AVAudioPlayerDelegate {
    func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
        playNextItem()
    }
}
 

И вот в чем проблема: как только AVAudioPlayer останавливается, воспроизводимый сейчас информационный центр автоматически тоже останавливается, даже если я продолжаю его обновлять nowPlayingInfo . Затем, когда он попадает на другой .audio элемент, он возобновляется правильно и показывает текущее время и т. Д.

И здесь возникает вопрос

как мне MPNowPlayingInfoCenter заставить думать, что звук воспроизводится, пока я «играю» свой .pause элемент?

Я понимаю, что все еще может быть неясно, чего я пытаюсь достичь, но я рад поделиться дополнительной информацией, если это необходимо. Спасибо!

Некоторые решения, о которых я сейчас думаю:

A. Сохранение пустой звуковой дорожки длиной в 1 секунду, которая будет воспроизводиться в цикле до тех пор, пока для воспроизведения требуется пауза.

B. Создание программно пустой звуковой дорожки соответствующей длины и воспроизведение ее вместо использования Timer для отслеживания продолжительности / хода паузы и полного использования AVAudioPlayer для обоих .audio .pause элементов и. Не уверен, что это возможно.

C. Может быть, есть способ сообщить MPNowPlayingInfoCenter , что звук продолжает воспроизводиться без необходимости использования AVAudioPlayer , но с каким-то API я не знаком?

Ответ №1:

AVAudioPlayer, вероятно, здесь не тот инструмент. Вам нужен AVAudioPlayerNode, который немного ниже уровня. Создайте AVAudioEngine и присоедините AVAudioPlayerNode. Затем вы можете вызвать, scheduleFile(_:at:completionHandler:) чтобы воспроизвести звук в нужное время.

Большая часть документации Apple по AVAudioEngine на данный момент выглядит неработающей, но, надеюсь, ссылки скоро снова будут доступны в ссылках на строительные блоки Audio Engine. (Если он не работает и у вас возникли проблемы с поиском документов, оставьте комментарий, и я найду видеоролики WWDC и другие учебные пособия по использованию AVAudioEngine. Это не особенно сложно для простых задач.)

Если вы заранее знаете, как вы хотите скомпоновать эти элементы (и похоже, что вы можете), см. Также AVMutableComposition, который позволяет очень эффективно склеивать ресурсы, включая добавление пустых сегментов тишины. См. раздел «Композиция и редактирование мультимедиа» для различных инструментов в этом разделе.

Комментарии:

1. спасибо за этот ответ! Я посмотрю на эти ссылки и отвечу вам, как только у меня будет какой-то результат.

2. Я переосмыслил все это, AVMutableComposition и это работает так, как ожидалось! Большое спасибо.