Зацикливание звука на определенное время на iOS - PullRequest
0 голосов
/ 19 октября 2018

Мне интересно, каково лучшее решение для зацикливания звука в течение определенного времени на iOS.В настоящее время я играю с

  • AVAudioPlayer (где я могу определить количество повторений, но не могу определить время окончания)
  • AVPlayer (где я могу определитьforwardPlaybackEndTime бот, а не число циклов)
  • AVPlayerLooper (что я еще не до конца понимаю)

Итак, мне нужно определить продолжительность, для которойопределенный звуковой файл повторяется.Например, у меня есть 8-секундный mp3, и я хочу воспроизвести его, например, одну минуту.

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

1 Ответ

0 голосов
/ 19 октября 2018

Вы были на правильном пути с AVPlayerLooper .

Вот как вы настраиваете AVPlayerLooper

var playerLooper: AVPlayerLooper!
var player: AVQueuePlayer!

func play(_ url: URL) {
    let asset = AVAsset(url: url)
    let playerItem = AVPlayerItem(asset: asset)

    player = AVQueuePlayer(playerItem: playerItem)
    playerLooper = AVPlayerLooper(player: player, templateItem: playerItem)

    player.play()
}

Чтобы остановить цикл после установленного количествавремя, когда вы можете использовать addBoundaryTimeObserver (forTimes: queue: using:) Например:

let assetDuration = CMTimeGetSeconds(asset.duration)
let maxDuration = 60.0 // Define max duration
let maxLoops = floor(maxDuration / assetDuration)
let lastLoopDuration = maxDuration - (assetDuration * maxLoops)
let boundaryTime = CMTimeMakeWithSeconds(lastLoopDuration, preferredTimescale: 1)
let boundaryTimeValue = NSValue(time: boundaryTime)

player.addBoundaryTimeObserver(forTimes: [boundaryTimeValue], queue: DispatchQueue.main) { [weak self] in
    if self?.playerLooper.loopCount == Int(maxLoops) {
        self?.player.pause()
    }
}

Для ввода / вывода вы должны установить для свойства audioMix значение AVPlayerItemэкземпляр перед его использованием.

let introRange = CMTimeRangeMake(start: CMTimeMakeWithSeconds(0, preferredTimescale: 1), duration: CMTimeMakeWithSeconds(1, preferredTimescale: 1))
let endingSecond = CMTimeRangeMake(start: CMTimeMakeWithSeconds(assetDuration - 1, preferredTimescale: 1), duration: CMTimeMakeWithSeconds(1, preferredTimescale: 1))

let inputParams = AVMutableAudioMixInputParameters(track: asset.tracks.first! as AVAssetTrack)
inputParams.setVolumeRamp(fromStartVolume: 0, toEndVolume: 1, timeRange: introRange)
inputParams.setVolumeRamp(fromStartVolume: 1, toEndVolume: 0, timeRange: endingSecond)

let audioMix = AVMutableAudioMix()
audioMix.inputParameters = [inputParams]
playerItem.audioMix = audioMix

Полная функция:

func play(_ url: URL) {
    let asset = AVAsset(url: url)
    let playerItem = AVPlayerItem(asset: asset)

    let assetDuration = CMTimeGetSeconds(asset.duration)

    let introRange = CMTimeRangeMake(start: CMTimeMakeWithSeconds(0, preferredTimescale: 1), duration: CMTimeMakeWithSeconds(1, preferredTimescale: 1))
    let endingSecond = CMTimeRangeMake(start: CMTimeMakeWithSeconds(assetDuration - 1, preferredTimescale: 1), duration: CMTimeMakeWithSeconds(1, preferredTimescale: 1))

    let inputParams = AVMutableAudioMixInputParameters(track: asset.tracks.first! as AVAssetTrack)
    inputParams.setVolumeRamp(fromStartVolume: 0, toEndVolume: 1, timeRange: introRange)
    inputParams.setVolumeRamp(fromStartVolume: 1, toEndVolume: 0, timeRange: endingSecond)

    let audioMix = AVMutableAudioMix()
    audioMix.inputParameters = [inputParams]
    playerItem.audioMix = audioMix

    player = AVQueuePlayer(playerItem: playerItem)
    playerLooper = AVPlayerLooper(player: player, templateItem: playerItem)
    player.play()

    let maxDuration = 60.0 // Define max duration
    let maxLoops = floor(maxDuration / assetDuration)
    let lastLoopDuration = maxDuration - (assetDuration * maxLoops)
    let boundaryTime = CMTimeMakeWithSeconds(lastLoopDuration, preferredTimescale: 1)
    let boundaryTimeValue = NSValue(time: boundaryTime)

    player.addBoundaryTimeObserver(forTimes: [boundaryTimeValue], queue: DispatchQueue.main) { [weak self] in
        if self?.playerLooper.loopCount == Int(maxLoops) {
            self?.player.pause()
        }
    }
}
...