使用AVMutableComposition合并AKAudioFile仅导出首轨问题求助
Hey there! Let's dig into why your combined AKAudioFile only plays the first track when using AVMutableComposition with AudioKit. This is a common gotcha, and the issue is almost always tied to how you're building the composition or exporting it to an AKAudioFile—let's break down the most likely culprits and fixes:
1. Most Common Issue: Incorrect Time Offsets in AVMutableComposition
If you're inserting all audio tracks at CMTime.zero, you're overwriting each subsequent file instead of appending them. You need to track the cumulative duration of the composition and insert each new file at the end of the last one.
Fix Your Track Insertion Logic
Here's how to adjust your loop to properly append files:
private func createCombinedRecordingFrom(_ files: [AKAudioFile], completion: @escaping (AKAudioFile?) -> ()) { let composition = AVMutableComposition() var currentEndTime = CMTime.zero // Track where the last file ends for audioFile in files { guard let asset = AVURLAsset(url: audioFile.url) else { print("Skipping invalid audio file URL") continue } guard let audioAssetTrack = asset.tracks(withMediaType: .audio).first else { print("No audio track found in file") continue } guard let compositionTrack = composition.addMutableTrack(withMediaType: .audio, preferredTrackID: kCMPersistentTrackID_Invalid) else { print("Failed to add track to composition") continue } let trackTimeRange = CMTimeRange(start: .zero, duration: asset.duration) do { // Insert the new track at the END of the composition, not at zero try compositionTrack.insertTimeRange(trackTimeRange, of: audioAssetTrack, at: currentEndTime) // Update the end time for the next track currentEndTime = CMTimeAdd(currentEndTime, asset.duration) } catch { print("Error inserting track: \(error.localizedDescription)") } } // Now export the composition to an AKAudioFile exportComposition(composition, completion: completion) } // Helper to export composition to AKAudioFile private func exportComposition(_ composition: AVMutableComposition, completion: @escaping (AKAudioFile?) -> ()) { guard let exportSession = AVAssetExportSession(asset: composition, presetName: AVAssetExportPresetAppleM4A) else { completion(nil) return } let tempURL = FileManager.default.temporaryDirectory.appendingPathComponent("combined_recording.m4a") // Clean up any existing file at the temp URL try? FileManager.default.removeItem(at: tempURL) exportSession.outputURL = tempURL exportSession.outputFileType = .m4a exportSession.shouldOptimizeForNetworkUse = true exportSession.exportAsynchronously { DispatchQueue.main.async { switch exportSession.status { case .completed: guard let url = exportSession.outputURL else { completion(nil) return } do { let combinedFile = try AKAudioFile(forReading: url) completion(combinedFile) } catch { print("Failed to create AKAudioFile: \(error)") completion(nil) } case .failed, .cancelled: print("Export failed: \(exportSession.error?.localizedDescription ?? "Unknown error")") completion(nil) default: completion(nil) } } } }
2. Possible AudioKit Export Misstep: Skipping Proper Composition Rendering
If you're trying to directly copy AKAudioFile data (like appending raw PCM buffers) instead of using AVAssetExportSession to render the composition, you'll run into issues with audio headers and format mismatches. The AVMutableComposition needs to be rendered into a proper audio file first before loading it into AKAudioFile.
3. Edge Case: Mismatched Audio Formats
If your input AKAudioFiles have different sample rates, channel counts, or bit depths, AVMutableComposition might fail to properly mix/append them, resulting in only the first track being playable.
Check File Formats
Add a quick check to verify consistency:
for (index, file) in files.enumerated() { let sampleRate = file.settings[AVSampleRateKey] as? Double ?? 0 let channels = file.settings[AVNumberOfChannelsKey] as? Int ?? 0 print("File \(index): Sample rate = \(sampleRate), Channels = \(channels)") }
If formats differ, you can use AudioKit's AKConverter to normalize them before adding to the composition, or let AVMutableComposition handle conversion (it usually does this automatically, but explicit conversion avoids surprises).
Final Notes
The most probable fix is adjusting your track insertion time offsets—double-check that you're not inserting every track at CMTime.zero. If that doesn't solve it, confirm you're using AVAssetExportSession to render the full composition before loading into AKAudioFile.
内容的提问来源于stack exchange,提问作者Grant Emerson

