VisionOS, passthrough through broadcast shows a black background

Hey, I have Enterprise Access on the account and have added the passthrough capability and the entitlement on the main project and the "Broadcast Upload" extension, too.

The broadcast works except it returns a black screen.

I am attaching some screenshots below of the entitlement file. I have tried searching online to no avail, so any help would be greatly appreciated. I am also attaching the code.

import Foundation
import AVFoundation
import ReplayKit

class VideoAssetWriter {
    private var isRecording = false
    private var outputStream: OutputStream?
    
    private func setupConnection() {
        guard outputStream == nil else { return }
        print("setting up connection.")
        let serverIP = macIP
        let port = 12345
        
        var readStream: Unmanaged<CFReadStream>?
        var writeStream: Unmanaged<CFWriteStream>?
        
        CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault,
                                         serverIP as CFString,
                                         UInt32(port),
                                         &readStream,
                                         &writeStream)
        
        guard let writeStream = writeStream?.takeRetainedValue() else {
            print("Failed to create write stream")
            return
        }
        
        self.outputStream = writeStream as OutputStream
        self.outputStream?.open()
    }
    
    func startRecording() {
        isRecording = true
    }
    
    func processVideoSampleBuffer(_ sampleBuffer: CMSampleBuffer) {
        print("Processing Sample 1")
        guard isRecording else { return }
        print("Processing Sample 2")
        sendVideoChunkToServer(sampleBuffer)
    }
    
    private func sendVideoChunkToServer(_ sampleBuffer: CMSampleBuffer) {
        guard let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return }
        print("Processing Sample 3")    
        let ciImage = CIImage(cvPixelBuffer: imageBuffer)
        let context = CIContext()
        guard let cgImage = context.createCGImage(ciImage, from: ciImage.extent) else { return }
        print("Processing Sample 4")
    
        let image = UIImage(cgImage: cgImage)
        
        if let imageData = image.jpegData(compressionQuality: 0.5) {
            guard imageData.count <= 10_000_000 else {
                print("Frame too large: \(imageData.count) bytes")
                return
            }
            
            if outputStream == nil {
                setupConnection()
            }
            
            print("sending frame size up connection.")
            // Convert to network byte order (big-endian)
            var frameSize = UInt32(imageData.count).bigEndian
            let sizeData = Data(bytes: &frameSize, count: MemoryLayout<UInt32>.size)
            _ = sizeData.withUnsafeBytes { outputStream?.write($0.baseAddress!.assumingMemoryBound(to: UInt8.self), maxLength: sizeData.count) }
            
            print("sending image data up connection.")
            
            // Send frame data
            _ = imageData.withUnsafeBytes { outputStream?.write($0.baseAddress!.assumingMemoryBound(to: UInt8.self), maxLength: imageData.count) }
        }
    }
    
    func stopRecording() {
        isRecording = false
        outputStream?.close()
        outputStream = nil
    }
}

This is the broadcast picker view wrapper:

// Broadcast Picker View wrapper
struct BroadcastButtonView: UIViewRepresentable {
    func makeUIView(context: Context) -> RPSystemBroadcastPickerView {
        let broadcastPickerView = RPSystemBroadcastPickerView(
            frame: CGRect(x: 0, y: 0, width: 200, height: 200)
        )
        // Make sure this matches your broadcast extension bundle identifier
        broadcastPickerView.preferredExtension = "my-extension-bundle-identifier"
        broadcastPickerView.showsMicrophoneButton = false
        
        
        return broadcastPickerView
    }
    
    func updateUIView(_ uiView: RPSystemBroadcastPickerView, context: Context) {
    }
}

The extension SampleHandler:

    override func broadcastPaused() {
        print("paused broadcast")
        // User has requested to pause the broadcast. Samples will stop being delivered.
    }
    
    override func broadcastResumed() {
        print("resumed broadcast")
        // User has requested to resume the broadcast. Samples delivery will resume.
    }
    
    override func processSampleBuffer(_ sampleBuffer: CMSampleBuffer, with sampleBufferType: RPSampleBufferType) {
        print("broadcast received")
        assetWriter?.processVideoSampleBuffer(sampleBuffer)
        
    }

Looking forward to any and all help.

Information Property list:

Information property list for the extension:

The capabilities:

Hi [@Krish Shah](https://developer.apple.com/forums/profile/Krish Shah)

The behavior you're describing happens when the license file is not included as part of the build target. Did you add the license file to build target?

VisionOS, passthrough through broadcast shows a black background
 
 
Q