// // AVAssetMods.swift // WOKA // // Created by MacBook Pro on 09/07/24. // import Foundation import AVKit extension AVAsset { // func writeAudioTrackToURL(_ url: URL, completion: @escaping (Bool, Error?, URL?) -> ()) { // DispatchQueue.global(qos: .userInitiated).async { [weak self] in // do { // guard let audioAsset = try self?.audioAsset() else { // completion(false, nil, nil) // return // } // audioAsset.writeToURL(url, completion: completion) // } catch let error as NSError { // DispatchQueue.main.async { // completion(false, error, nil) // } // } // } // } // // func writeToURL(_ url: URL, completion: @escaping (Bool, Error?, URL?) -> ()) { // DispatchQueue.global(qos: .userInitiated).async { // guard let exportSession = AVAssetExportSession(asset: self, presetName: AVAssetExportPresetAppleM4A) else { // DispatchQueue.main.async { // completion(false, nil, nil) // } // return // } // // let audioMix = AVMutableAudioMix() // var inputParameters = [AVMutableAudioMixInputParameters]() // let volume: Float = 0.4 // // for track in self.tracks(withMediaType: .audio) { // let audioInputParams = AVMutableAudioMixInputParameters(track: track) // audioInputParams.setVolume(volume, at: .zero) // inputParameters.append(audioInputParams) // } // // audioMix.inputParameters = inputParameters // exportSession.audioMix = audioMix // exportSession.outputFileType = .m4a // exportSession.outputURL = url // // DispatchQueue.main.async { // Utilities.startProgressHUD(msg: "Preparing") // } // // exportSession.exportAsynchronously { // DispatchQueue.main.async { // switch exportSession.status { // case .completed: // Utilities.dismissProgressHUD() // completion(true, nil, url) // case .unknown, .waiting, .exporting, .failed, .cancelled: // Utilities.dismissProgressHUD() // completion(false, nil, nil) // @unknown default: // Utilities.dismissProgressHUD() // completion(false, nil, nil) // } // } // } // } // } func writeAudioTrackToURL(_ url: URL, completion: @escaping (Bool, Error?, URL?) -> ()) { do { let audioAsset = try self.audioAsset() audioAsset.writeToURL(url, completion: completion) } catch (let error as NSError){ completion(false, error, nil) } } func writeToURL(_ url: URL, completion: @escaping (Bool, Error?, URL?) -> ()) { guard let exportSession = AVAssetExportSession(asset: self, presetName: AVAssetExportPresetAppleM4A) else { completion(false, nil , nil) return } // Utilities.startProgressHUD(msg: "Preparing") // Create an AVMutableAudioMix to adjust the volume let audioMix = AVMutableAudioMix() var inputParameters = [AVMutableAudioMixInputParameters]() // Decrease the volume by setting the volume to a value less than 1.0 let volume : Float = 0.4 // Adjust the volume level as needed (e.g., 0.5 for half volume) // Create an AVMutableAudioMixInputParameters instance for each audio track for track in self.tracks(withMediaType: .audio) { let audioInputParams = AVMutableAudioMixInputParameters(track: track) audioInputParams.setVolume(volume, at: .zero) // Set the volume for the audio track inputParameters.append(audioInputParams) } // Assign the input parameters to the audio mix audioMix.inputParameters = inputParameters // Set the audio mix for the export session exportSession.audioMix = audioMix // Configure export session and start exporting exportSession.outputFileType = .m4a exportSession.outputURL = url exportSession.exportAsynchronously { switch exportSession.status { case .completed: Utilities.dismissProgressHUD() completion(true, nil, url) case .unknown, .waiting, .exporting, .failed, .cancelled: Utilities.dismissProgressHUD() completion(false, nil, nil) @unknown default: Utilities.dismissProgressHUD() completion(false, nil, nil) } } } func audioAsset() throws -> AVAsset { let composition = AVMutableComposition() let audioTracks = tracks(withMediaType: .audio) for track in audioTracks { let compositionTrack = composition.addMutableTrack(withMediaType: .audio, preferredTrackID: kCMPersistentTrackID_Invalid) try compositionTrack?.insertTimeRange(track.timeRange, of: track, at: track.timeRange.start) compositionTrack?.preferredTransform = track.preferredTransform } return composition } } extension FileManager { func clearTmpDirectory() { do { let tmpDirURL = FileManager.default.temporaryDirectory let tmpDirectory = try contentsOfDirectory(atPath: tmpDirURL.path) try tmpDirectory.forEach { file in let fileUrl = tmpDirURL.appendingPathComponent(file) try removeItem(atPath: fileUrl.path) } } catch { //catch the error somehow } } }