Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get rid of warning: Passing argument of non-sendable type 'AVAssetExportSession' outside of main actor-isolated context may introduce data races

How can I get rid of this warning for await exportSession.export():

enter image description here

Code:

func extractAudioFromImportedVideo(videoURL: URL, success: @escaping ((URL) -> Void), failure: @escaping ((Error?) -> Void)) async {
        
        do {
            let asset = AVURLAsset(url: videoURL)
            let audioTracks = try await asset.loadTracks(withMediaType: .audio)
            
            guard !audioTracks.isEmpty else {
                failure(NSError(domain: "Audio Extraction Error", code: 0, userInfo: [NSLocalizedDescriptionKey: "Video does not contain audio"]))
                return
            }
            
            guard let exportSession = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetAppleM4A) else {
                failure(NSError(domain: "Audio Extraction Error", code: 0, userInfo: [NSLocalizedDescriptionKey: "Failed to create export session"]))
                return
            }
            
            guard let audioURL = makeFileOutputURL(fileName: "ExtractedAudio.m4a") else {
                failure(NSError(domain: "Audio Extraction Error", code: 0, userInfo: [NSLocalizedDescriptionKey: "Failed to create output URL"]))
                return
            }
            
            print("audioTracks", audioTracks)
            exportSession.outputURL = audioURL
            exportSession.outputFileType = .m4a

            
            await exportSession.export()
            print("exportSession.status", exportSession.status.rawValue)
            if exportSession.status == .completed {
                // Audio extraction succeeded
                print("Audio extraction succeeded")
                success(audioURL)
            } else {
                // Audio extraction failed
                print("Audio extraction failed: \(exportSession.error?.localizedDescription ?? "")")
                failure(exportSession.error)
            }
        }
        catch {
            print("extractAudioFromImportedVideo Error:", error.localizedDescription)
        }
    }
like image 455
Hassan Taleb Avatar asked Nov 02 '25 13:11

Hassan Taleb


1 Answers

The error is:

Passing argument of non-sendable type 'AVAssetExportSession' outside of main actor-isolated context may introduce data races; this is an error in the Swift 6 language mode

This is telling you that the problem is arising because you are performing this in a main actor-isolated function.

The easy fix is to remove this actor-isolation, to make the function nonisolated:

nonisolated func extractAudioFromImportedVideo(videoURL: URL, success: @escaping ((URL) -> Void), failure: @escaping ((Error?) -> Void)) async {
    …
}

Personally, I would eliminate these closures and just follow async patterns:

nonisolated func extractAudioFromImportedVideo(videoURL: URL) async throws -> URL {
    do {
        let asset = AVURLAsset(url: videoURL)
        let audioTracks = try await asset.loadTracks(withMediaType: .audio)

        guard !audioTracks.isEmpty else {
            throw AudioExtractionError.noAudio
        }

        guard let exportSession = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetAppleM4A) else {
            throw AudioExtractionError.exportFailed
        }

        guard let audioURL = makeFileOutputURL(fileName: "ExtractedAudio.m4a") else {
            throw AudioExtractionError.outputUrlFailed
        }

        print("audioTracks", audioTracks)
        exportSession.outputURL = audioURL
        exportSession.outputFileType = .m4a


        await exportSession.export()
        print("exportSession.status", exportSession.status.rawValue)
        if let error = exportSession.error {
            throw error
        }

        print("Audio extraction succeeded")
        return audioURL
    } catch {
        print("extractAudioFromImportedVideo Error:", error.localizedDescription)
        throw error
    }
}

Note, I also retired NSError, replacing it with:

enum AudioExtractionError: LocalizedError {
    case noAudio
    case exportFailed
    case outputUrlFailed

    nonisolated var errorDescription: String? {
        return switch self {
        case .noAudio: String(localized: "Video does not contain audio", comment: "AudioExtractionError")
        case .exportFailed: String(localized: "Failed to create export session", comment: "AudioExtractionError")
        case .outputUrlFailed: String(localized: "Failed to create output URL", comment: "AudioExtractionError")
        }
    }
}

That is actually localized, isolates the details from this function, and enumerated errors support richer error handling.


FWIW, once you have this working, you can simplify further:

nonisolated func extractAudioFromImportedVideo(videoURL: URL) async throws -> URL {
    let asset = AVURLAsset(url: videoURL)
    let audioTracks = try await asset.loadTracks(withMediaType: .audio)

    guard !audioTracks.isEmpty else {
        throw AudioExtractionError.noAudio
    }

    guard let exportSession = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetAppleM4A) else {
        throw AudioExtractionError.exportFailed
    }

    guard let audioURL = makeFileOutputURL(fileName: "ExtractedAudio.m4a") else {
        throw AudioExtractionError.outputUrlFailed
    }

    exportSession.outputURL = audioURL
    exportSession.outputFileType = .m4a

    await exportSession.export()
    if let error = exportSession.error {
        throw error
    }

    return audioURL
}
like image 173
Rob Avatar answered Nov 04 '25 05:11

Rob



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!