How to change the speed of an audio track (mp3)?

I have this theory that AVMutableComposition does not work without a video track. I'm trying to change the speed of an audio track (mp3) using the



func scaleTimeRange(_ timeRange: CMTimeRange, toDuration duration: CMTime)



function. Below is the code I have so far,



static func changeSpeed(audio: AVURLAsset, factor: Float64, outputURL: URL, completionHandler:@escaping ((_ success: Bool) -> Void)) {
            print(#function + " started: " + Date().description)
           
            guard factor > 0 else {
                DispatchQueue.main.async {
                    print(#function + ": Speed factor must be a positive value")
                    completionHandler(false)
                }
                return
            }
           
            guard let assetAudioTrack = audio.tracks(withMediaType: .audio).first else {
                DispatchQueue.main.async {
                    print(#function + ": No asset track found")
                    completionHandler(false)
                }
                return
            }
           
            let composition = AVMutableComposition()
           
            let audioTrack = composition.addMutableTrack(
                withMediaType: AVMediaType.audio,
                preferredTrackID: kCMPersistentTrackID_Invalid
            )
            do {
                try audioTrack?.insertTimeRange(
                    CMTimeRangeMake(start: CMTime.zero, duration: audio.duration),
                    of: assetAudioTrack,
                    at: CMTime.zero
                )
            } catch {
                DispatchQueue.main.async {
                    print(#function + ": Failed to add " + audio.url.absoluteString)
                    completionHandler(false)
                }
                return
            }
           
            let exporter = AVAssetExportSession(
                asset: composition,
                presetName: AVAssetExportPresetAppleM4A
            )
           
            exporter?.outputURL = outputURL
            exporter?.outputFileType = AVFileType.m4a
           
            audioTrack?.scaleTimeRange(CMTimeRange.init(start: CMTime.zero, end: audio.duration), toDuration: CMTimeMultiplyByFloat64(audio.duration, multiplier: 1/factor))
           
            exporter?.exportAsynchronously {
                if exporter?.status == .completed {
                    DispatchQueue.main.async {
                        completionHandler(true)
                        print(#function + " ended: " + Date().description)
                    }
                } else {
                    DispatchQueue.main.async {
                        completionHandler(false)
                        print(#function + " ended with error: " + Date().description)
    if let errorString = exporter?.error.debugDescription {
                            print(errorString)
                        }
                    }
                }
            }
        }


Above code fails with or without the *scaleTimeRange* function. That is why I'm thinking that AVMutableComposition will work only when there are video tracks.



I did play around a little by changing the preset and output file type. Below are my observations,



preset: AVAssetExportPresetAppleM4A

file type: AVFileType.m4a



Error Domain=AVFoundationErrorDomain Code=-11800 "The operation could

not be completed" UserInfo={NSLocalizedFailureReason=An unknown error

occurred (-12780), NSLocalizedDescription=The operation could not be

completed, NSUnderlyingError=0x281164960 {Error

Domain=NSOSStatusErrorDomain Code=-12780 "(null)"}}



preset: AVAssetExportPresetPassthrough

file type: AVFileType.m4a



Error Domain=AVFoundationErrorDomain Code=-11822 "Cannot Open"

UserInfo={NSLocalizedFailureReason=This media format is not

supported., NSLocalizedDescription=Cannot Open,

NSUnderlyingError=0x28178fc30 {Error Domain=NSOSStatusErrorDomain

Code=-16976 "(null)"}}



I printed the supported file types of AVAssetExportSession when the preset is AVAssetExportPresetPassthrough.



print(#function + ": Supported file types -> " + String.init(format: "%@", exporter?.supportedFileTypes ?? []))



Below is the output of the above. I can clearly see m4a in the list.



"com.apple.quicktime-movie",

"com.apple.m4a-audio",

"public.mpeg-4",

"com.apple.m4v-video",

"public.3gpp",

"org.3gpp.adaptive-multi-rate-audio",

"com.microsoft.waveform-audio",

"public.aiff-audio",

"public.aifc-audio",

"com.apple.coreaudio-format"



I need help to build a function that would change the speed of an audio track for me. The audio track could be an asset in the bundle or picked from the MPMediaPickerController.



Thanks!