Reputation: 499
I'm trying to create a an audio loop in Swift and it works very well 9/10 times. But then suddenly, the 10th time (or so) the insertTimeRange function seems to fail in some way.
I can see that the player has the correct length, but instead of taking the full 60 seconds of audio from every loop, it just seems to take a very, very short part of it and loop every minute. Illustration of the problem with five loops:
.----------.----------.----------.----------.----------
(short but hearable audio = ., complete silence = -)
Unfortunately, it doesn't throw any error. Here's how I create the composition:
private func createComposition(audioURL: URL, minutesToLoop: UInt) -> AVMutableComposition? {
// Initiate new composition
let composition = AVMutableComposition()
// Add one audio track (channel) to the composition
let compositionAudioTrack: AVMutableCompositionTrack? = composition.addMutableTrack(withMediaType: AVMediaType.audio, preferredTrackID: 0)
// Create AVAsset from audio file (mp3 -> React Native bundle string -> URL -> AVAsset)
let asset = AVURLAsset(url: audioURL)
// Extract (now compatible) audio track from AVAsset
let track = asset.tracks(withMediaType: AVMediaType.audio)[0]
// Create a time range from 0 - 60 seconds that we can use to cut that out from the track
let timeRange = CMTimeRangeMake(start: .zero, duration: CMTimeMakeWithSeconds(60, preferredTimescale: 600))
if (compositionAudioTrack != nil) {
// Repeat for as many minutes as user specified in the app
for _ in 0...(minutesToLoop - 1) {
do {
// Take first 60 seconds from the audio file (timeRange, of: track) and paste over and over again exactly at the end of the track (at: composition.duration)
try compositionAudioTrack!.insertTimeRange(timeRange, of: track, at: composition.duration)
} catch {
print("FAILED TO MERGE AUDIO")
return nil
}
}
}
return composition
}
Upvotes: 0
Views: 102
Reputation: 499
For future AVMutableComposition lovers, I found the solution. You needed to add a boolean to your asset options, like so:
let asset = AVURLAsset(url: audioURL, options: [AVURLAssetPreferPreciseDurationAndTimingKey: true])
Upvotes: 0