Найти тему
roadToDev

Немного о AVAudioSession. Правильное воспроизведение звука в приложениях iOS

Оглавление

Когда вы пытаетесь найти способ воспроизведения звука в своем iOS приложении, вы обычно находите подобный код:

player = try AVAudioPlayer(contentsOf: url)
player.prepareToPlay()
player.play()

Хотя это рабочий код и будет воспроизводить аудиофайл, он не учитывает всех нюансов воспроизведения звука.

Представьте, что пользователь воспроизводит подкаст или музыку. Хотели бы вы, чтобы воспроизведение остановилось? Или переиграть его снова?

Ключом к правильному воспроизведению звука является понимание категорий AVAudioSession. Давайте рассмотрим это на примере.

Воспроизведение сторонних(.ambient) звуков поверх существующего аудио

Если вы хотите воспроизвести аудиофайл в своем приложении, не влияя на уже играющую музыку или подкаст, то следует использовать категорию .ambient .

Вы можете использовать эту категорию, например, для воспроизведения звуковых эффектов, таких как звук сообщения, отправляемого в приложении чата, где звук не так важен и определенно не стоит влиять на другое воспроизведение в iOS.

Установите данную категорию для общего экземпляра AVAudioSession

try AVAudioSession.sharedInstance().setCategory(.ambient, mode: .default)

и сделайте ее активной

try AVAudioSession.sharedInstance().setActive(true)

Все звуки, которые вы воспроизводите с помощью AVAudioPlayer, будут воспроизводиться поверх других.

Остановка существующего аудио для воспроизведения вашего звука

Если аудиофайл, который вы хотите воспроизвести в своем приложении, важен, например, воспроизведение голосового сообщения в чате, то вы можете остановить воспроизводимый на тот момент звук на iOS.

Вы можете добиться этого, установив значение для категории .playback

try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default)
try AVAudioSession.sharedInstance().setActive(true)

Помните, что при настройке категории она сохраняется для всего последовательного воспроизведения звука до тех пор, пока вы не установите для нее другое значение.

Теперь, когда вы будете воспроизводить звук с помощью AVAudioPlayer, он остановит музыку или подкаст, который пользователь слушал.

Но что, если вы хотите, чтобы музыка или подкаст пользователя продолжались после воспроизведения вашего звука?

Сброс категории и уведомление других приложений о том, что они могут возобновить воспроизведение

Рекомендуется отключить AVAudioSession и отправить уведомление всем другим приложениям, когда вы закончили воспроизводить звук

try AVAudioSession.sharedInstance().setActive(false, options: .notifyOthersOnDeactivation)

и сбросьте сеанс обратно в категорию .ambient

try AVAudioSession.sharedInstance().setCategory(.ambient, mode: .default)
try AVAudioSession.sharedInstance().setActive(true)

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

Проблема в том, что не все приложения делают это правильно, даже те, что от Apple, поэтому результат будет варьироваться в зависимости от используемого приложения.

Приглушение существующего звука для воспроизведения вашего

Существует еще один вариант, который вы можете использовать, представляющий собой нечто вроде гибрида между двумя уже упомянутыми подходами. Вы можете установить категорию .playback с опцией .duckOthers.

try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: [.duckOthers])
try AVAudioSession.sharedInstance().setActive(true)

Если сейчас вы воспроизведете свой аудиофайл, iOS «приглушит» существующее воспроизведение, сделает его менее громким, но не остановит, и воспроизведет ваш звуковой файл поверх него.

Это гарантирует, что музыка или подкаст, которые может воспроизводить пользователь, не будут остановлены, но в то же время звук, который вы воспроизводите в своем приложении, будет более или менее четко слышен пользователю.

Узнать, когда AVAudioPlayer закончил воспроизведение

Чтобы сбросить AVAudioSession обратно в категорию ambient и уведомить другие приложения о завершении воспроизведения, вам нужно знать, когда AVAudioPlayer завершил воспроизведение звукового файла.

Вы можете легко сделать это с помощью AVAudioPlayerDelegate, его метода делегирования audioPlayerDidFinishPlaying(_: AVAudioPlayer, successfully _: Bool), который срабатывает по завершении воспроизведения звука.

Я бы рекомендовал также сделать то же самое в методе делегирования audioPlayerDecodeErrorDidOccur(_ player: AVAudioPlayer, error: Error?), который срабатывает при ошибке, потому что, если вы внесли изменения в AVAudioSession перед попыткой воспроизведения аудио с ошибкой, не имеет значения, удалось это или нет, вам все равно нужно сделать очистку.

Источник