Search code examples
iosavaudioplayer

AVAudioPlayer loops are not seamless


I am creating and playing an AVAudioPlayer as the following:

playerOne = try AVAudioPlayer(contentsOf: URL.init(fileURLWithPath: path))
playerOne.numberOfLoops = -1
playerOne.prepareToPlay()

I am playing an AAC file. I am using

playerOne.play(atTime: startTime)

to schedule a play in future and sync multiple AVAudioPlayers.

All works fine but my problem is when sounds loop they go out of sync, this is due to loops not being seamless.

What happens here is that due to aac decoders I believe that there is an exra small silence is added to the decoded audio data which causes the sync between audio players to be lost. I expected this loop to be perfect with 0 gap between looping from end to beginning.

How may I achieve seamless looping with AVAudioPlayer?


Solution

  • Using AVAudioEngine will give you a lot of flexibility but it's overhead if you don't need anything else but sync your tracks.

    In this case you can try to use a single player with AVComposition containing all your tracks, something like this:

    func generateComposition(urls: [URL]) throws -> AVComposition {
        let composition = AVMutableComposition()
        let audioTracks = urls
            .map(AVAsset.init(url:))
            .flatMap { $0.tracks(withMediaType: .audio) }
        
        for audioTrack in audioTracks {
            guard
                let compositionTrack = composition.addMutableTrack(withMediaType: .audio, preferredTrackID: kCMPersistentTrackID_Invalid)
            else { continue }
            
            try compositionTrack.insertTimeRange(
                audioTrack.timeRange,
                of: audioTrack,
                at: .zero
            )
        }
        return composition
    }
    

    And play it using AVPlayer:

    AVPlayer(playerItem: AVPlayerItem(asset: composition))