diff --git a/Sources/SJSAssetExportSession/SampleWriter.swift b/Sources/SJSAssetExportSession/SampleWriter.swift index 52cff1e..7052485 100644 --- a/Sources/SJSAssetExportSession/SampleWriter.swift +++ b/Sources/SJSAssetExportSession/SampleWriter.swift @@ -101,7 +101,26 @@ actor SampleWriter { try await CMTimeRange(start: .zero, duration: asset.load(.duration)) } - try await setUpAudio(audioTracks: audioTracks) + // This used to be a separate method but that doesn't build in Xcode 26.0 RC + if !audioTracks.isEmpty { + let audioOutput = AVAssetReaderAudioMixOutput(audioTracks: audioTracks, audioSettings: nil) + audioOutput.alwaysCopiesSampleData = false + audioOutput.audioMix = audioMix + guard reader.canAdd(audioOutput) else { + throw Error.setupFailure(.cannotAddAudioOutput) + } + reader.add(audioOutput) + self.audioOutput = audioOutput + + let audioInput = AVAssetWriterInput(mediaType: .audio, outputSettings: audioOutputSettings) + audioInput.expectsMediaDataInRealTime = false + guard writer.canAdd(audioInput) else { + throw Error.setupFailure(.cannotAddAudioInput) + } + writer.add(audioInput) + self.audioInput = audioInput + } + try await setUpVideo(videoTracks: videoTracks) } @@ -167,27 +186,6 @@ actor SampleWriter { // MARK: - Setup - private func setUpAudio(audioTracks: [AVAssetTrack]) throws { - guard !audioTracks.isEmpty else { return } - - let audioOutput = AVAssetReaderAudioMixOutput(audioTracks: audioTracks, audioSettings: nil) - audioOutput.alwaysCopiesSampleData = false - audioOutput.audioMix = audioMix - guard let reader, reader.canAdd(audioOutput) else { - throw Error.setupFailure(.cannotAddAudioOutput) - } - reader.add(audioOutput) - self.audioOutput = audioOutput - - let audioInput = AVAssetWriterInput(mediaType: .audio, outputSettings: audioOutputSettings) - audioInput.expectsMediaDataInRealTime = false - guard let writer, writer.canAdd(audioInput) else { - throw Error.setupFailure(.cannotAddAudioInput) - } - writer.add(audioInput) - self.audioInput = audioInput - } - private func setUpVideo(videoTracks: [AVAssetTrack]) throws { precondition(!videoTracks.isEmpty, "Video tracks must be provided") diff --git a/Tests/SJSAssetExportSessionTests/AVAsset+sending.swift b/Tests/SJSAssetExportSessionTests/AVAsset+sending.swift deleted file mode 100644 index ad2545c..0000000 --- a/Tests/SJSAssetExportSessionTests/AVAsset+sending.swift +++ /dev/null @@ -1,14 +0,0 @@ -// -// AVAsset+sending.swift -// SJSAssetExportSessionTests -// -// Created by Sami Samhuri on 2024-07-07. -// - -import AVFoundation - -extension AVAsset { - func sendTracks(withMediaType mediaType: AVMediaType) async throws -> sending [AVAssetTrack] { - try await loadTracks(withMediaType: mediaType) - } -} diff --git a/Tests/SJSAssetExportSessionTests/SJSAssetExportSessionTests.swift b/Tests/SJSAssetExportSessionTests/SJSAssetExportSessionTests.swift index e9375ae..4b20572 100644 --- a/Tests/SJSAssetExportSessionTests/SJSAssetExportSessionTests.swift +++ b/Tests/SJSAssetExportSessionTests/SJSAssetExportSessionTests.swift @@ -30,16 +30,16 @@ final class ExportSessionTests: BaseTests { let exportedAsset = AVURLAsset(url: destinationURL.url) #expect(try await exportedAsset.load(.duration) == .seconds(1)) // Audio - try #require(try await exportedAsset.sendTracks(withMediaType: .audio).count == 1) - let audioTrack = try #require(await exportedAsset.sendTracks(withMediaType: .audio).first) + try #require(try await exportedAsset.loadTracks(withMediaType: .audio).count == 1) + let audioTrack = try #require(await exportedAsset.loadTracks(withMediaType: .audio).first) let audioFormat = try #require(await audioTrack.load(.formatDescriptions).first) #expect(audioFormat.mediaType == .audio) #expect(audioFormat.mediaSubType == .mpeg4AAC) #expect(audioFormat.audioChannelLayout?.numberOfChannels == 2) #expect(audioFormat.audioStreamBasicDescription?.mSampleRate == 44_100) // Video - try #require(await exportedAsset.sendTracks(withMediaType: .video).count == 1) - let videoTrack = try #require(await exportedAsset.sendTracks(withMediaType: .video).first) + try #require(await exportedAsset.loadTracks(withMediaType: .video).count == 1) + let videoTrack = try #require(await exportedAsset.loadTracks(withMediaType: .video).first) #expect(try await videoTrack.load(.naturalSize) == CGSize(width: 1280, height: 720)) #expect(try await videoTrack.load(.nominalFrameRate) == 24.0) let dataRate = try await videoTrack.load(.estimatedDataRate) @@ -79,16 +79,16 @@ final class ExportSessionTests: BaseTests { let exportedAsset = AVURLAsset(url: destinationURL.url) #expect(try await exportedAsset.load(.duration) == .seconds(1)) // Audio - try #require(try await exportedAsset.sendTracks(withMediaType: .audio).count == 1) - let audioTrack = try #require(await exportedAsset.sendTracks(withMediaType: .audio).first) + try #require(try await exportedAsset.loadTracks(withMediaType: .audio).count == 1) + let audioTrack = try #require(await exportedAsset.loadTracks(withMediaType: .audio).first) let audioFormat = try #require(await audioTrack.load(.formatDescriptions).first) #expect(audioFormat.mediaType == .audio) #expect(audioFormat.mediaSubType == .mpeg4AAC) #expect(audioFormat.audioChannelLayout?.numberOfChannels == 2) #expect(audioFormat.audioStreamBasicDescription?.mSampleRate == 44_100) // Video - try #require(await exportedAsset.sendTracks(withMediaType: .video).count == 1) - let videoTrack = try #require(await exportedAsset.sendTracks(withMediaType: .video).first) + try #require(await exportedAsset.loadTracks(withMediaType: .video).count == 1) + let videoTrack = try #require(await exportedAsset.loadTracks(withMediaType: .video).first) #expect(try await videoTrack.load(.naturalSize) == CGSize(width: 1280, height: 720)) #expect(try await videoTrack.load(.nominalFrameRate) == 24.0) let dataRate = try await videoTrack.load(.estimatedDataRate) @@ -169,7 +169,7 @@ final class ExportSessionTests: BaseTests { ) let exportedAsset = AVURLAsset(url: destinationURL.url) - let videoTrack = try #require(await exportedAsset.sendTracks(withMediaType: .video).first) + let videoTrack = try #require(await exportedAsset.loadTracks(withMediaType: .video).first) let naturalSize = try await videoTrack.load(.naturalSize) #expect(naturalSize == CGSize(width: 1920, height: 1080)) let fps = try await videoTrack.load(.nominalFrameRate)