deafmutemagic
deafmutemagic

Reputation: 123

AVURLAsset returning empty array-Trying to Concatenate two files

I'm trying to concatenate two (multiple) audio files. I found a relevant post and solution at Concatenate Two Audio Files Swift

Here's the solution:


func mergeAudioFiles(audioFileUrls: NSArray) {
    let composition = AVMutableComposition()

    for i in 0 ..< audioFileUrls.count {

        let compositionAudioTrack :AVMutableCompositionTrack = composition.addMutableTrack(withMediaType: AVMediaTypeAudio, preferredTrackID: CMPersistentTrackID())

        let asset = AVURLAsset(url: (audioFileUrls[i] as! NSURL) as URL)

        let track = asset.tracks(withMediaType: AVMediaTypeAudio)[0]

        let timeRange = CMTimeRange(start: CMTimeMake(0, 600), duration: track.timeRange.duration)

        try! compositionAudioTrack.insertTimeRange(timeRange, of: track, at: composition.duration)
    }

    let documentDirectoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! as NSURL
    self.mergeAudioURL = documentDirectoryURL.appendingPathComponent("FinalAudio.m4a")! as URL as NSURL

    let assetExport = AVAssetExportSession(asset: composition, presetName: AVAssetExportPresetAppleM4A)
    assetExport?.outputFileType = AVFileTypeAppleM4A
    assetExport?.outputURL = mergeAudioURL as URL
    assetExport?.exportAsynchronously(completionHandler:
        {
            switch assetExport!.status
            {
            case AVAssetExportSessionStatus.failed:
                print("failed \(assetExport?.error)")
            case AVAssetExportSessionStatus.cancelled:
                print("cancelled \(assetExport?.error)")
            case AVAssetExportSessionStatus.unknown:
                print("unknown\(assetExport?.error)")
            case AVAssetExportSessionStatus.waiting:
                print("waiting\(assetExport?.error)")
            case AVAssetExportSessionStatus.exporting:
                print("exporting\(assetExport?.error)")
            default:
                print("Audio Concatenation Complete")
            }
    })
}

Some parameters are out of date and I used the suggested fixes from Xcode, resulting in :

        let composition = AVMutableComposition()

        for i in 0 ..< audioFileUrls.count {

            let compositionAudioTrack :AVMutableCompositionTrack = composition.addMutableTrack(withMediaType: AVMediaType.audio, preferredTrackID: CMPersistentTrackID())!

            let asset : AVURLAsset = AVURLAsset(url: (audioFileUrls[i] as! NSURL) as URL)

            let track : AVAssetTrack = asset.tracks(withMediaType: AVMediaType.audio)[0]

            let timeRange = CMTimeRange(start: CMTimeMake(value: 0, timescale: 600), duration: track.timeRange.duration)
            try! compositionAudioTrack.insertTimeRange(timeRange, of: track, at: composition.duration)
        }

        let documentDirectoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! as NSURL
        self.mergeAudioURL = documentDirectoryURL.appendingPathComponent("FinalAudio.m4a")! as URL as NSURL

        let assetExport = AVAssetExportSession(asset: composition, presetName: AVAssetExportPresetAppleM4A)
        assetExport?.outputFileType = AVFileType.m4a
        assetExport?.outputURL = mergeAudioURL as URL
        assetExport?.exportAsynchronously(completionHandler:
            {
                switch assetExport!.status
                {
                case AVAssetExportSessionStatus.failed:
                    print("failed \(assetExport?.error)")
                case AVAssetExportSessionStatus.cancelled:
                    print("cancelled \(assetExport?.error)")
                case AVAssetExportSessionStatus.unknown:
                    print("unknown\(assetExport?.error)")
                case AVAssetExportSessionStatus.waiting:
                    print("waiting\(assetExport?.error)")
                case AVAssetExportSessionStatus.exporting:
                    print("exporting\(assetExport?.error)")
                default:
                    print("Audio Concatenation Complete")
                }
        })

        print("asset url \(mergeAudioURL)")
    }

when I used the solution I get

2020-05-11 13:09:14.771381-0600 TimeCapsule[88538:12022916] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArray0 objectAtIndex:]: index 0 beyond bounds for empty NSArray'

The error occurs on the let track = asset.tracks(withMediaType: AVMediaTypeAudio)[0] line. Before that line, print outs show that asset.tracks.count = 0 asset.trackGroups.count = 0. When I remove the [0] index at the end of the line, the following line throws an error that "track has no member 'timeRange'". I can't figure out how to add a track to my newly created asset so that I can use the assets audio duration. Any help would be greatly appreciated, Im assuming it's just outdated syntax for the new Swift.

Upvotes: 0

Views: 212

Answers (2)

海涛乌
海涛乌

Reputation: 1

Please note that the sandbox environment will change every time 'url', I have encountered this problem before!

Upvotes: 0

Shehata Gamal
Shehata Gamal

Reputation: 100503

The error is clear

let tracks = asset.tracks(withMediaType: AVMediaTypeAudio)
guard !tracks.isEmpty else { return }
let track = tracks.first!

the file you try to concatenate has no audio tracks , hence array is empty

Upvotes: 0

Related Questions