// // CamExtensionProvider.swift // CamExtension // // Created by Vlad on 9/12/26. // import Foundation import CoreMediaIO import CoreVideo import CoreGraphics import CoreImage import IOKit.audio import IOSurface import Security import ObjectiveC import os.log let kFrameRate: Int = 30 let kPortalCamDeviceUUID = UUID(uuidString: "7B1E8C4B-8D2E-4A0D-9B95-8F5C1C7D9B11")! let kPortalCamSourceStreamUUID = UUID(uuidString: "7B1E8C4B-8D2E-4A0D-9B95-8F5C1C7D9B12")! let kPortalCamSinkStreamUUID = UUID(uuidString: "7B1E8C4B-8D2E-4A0D-9B95-8F5C1C7D9B13")! let kStreamStartedNotification = "com.kovtash.portalcam.streamStarted" let kStreamStoppedNotification = "com.kovtash.portalcam.streamStopped" @_silgen_name("csops") func csops(_ pid: pid_t, _ ops: UInt32, _ useraddr: UnsafeMutableRawPointer?, _ usersize: Int) -> Int32 // MARK: - Device Source class CamExtensionDeviceSource: NSObject, CMIOExtensionDeviceSource { private(set) var device: CMIOExtensionDevice! private var _streamSource: CamExtensionStreamSource! private var _sinkStreamSource: CamExtensionSinkStreamSource! private var _streamingCounter: UInt32 = 0 private var _videoDescription: CMFormatDescription! private var _bufferPool: CVPixelBufferPool! private var _placeholderPixelBuffer: CVPixelBuffer? private var _lastSinkFrameDate: Date? private let _lastSinkFrameLock = NSLock() private var _placeholderTimer: DispatchSourceTimer? private let _timerQueue = DispatchQueue(label: "com.kovtash.portalcam.cmio", qos: .userInteractive) private var _sentFrames = 0 init(localizedName: String) { super.init() self.device = CMIOExtensionDevice( localizedName: localizedName, deviceID: kPortalCamDeviceUUID, legacyDeviceID: nil, source: self ) let dims = CMVideoDimensions(width: 1280, height: 720) CMVideoFormatDescriptionCreate( allocator: kCFAllocatorDefault, codecType: kCVPixelFormatType_32BGRA, width: dims.width, height: dims.height, extensions: nil, formatDescriptionOut: &_videoDescription ) let pixelBufferAttributes: NSDictionary = [ kCVPixelBufferWidthKey: dims.width, kCVPixelBufferHeightKey: dims.height, kCVPixelBufferPixelFormatTypeKey: _videoDescription.mediaSubType, kCVPixelBufferIOSurfacePropertiesKey: [:] as NSDictionary ] CVPixelBufferPoolCreate(kCFAllocatorDefault, nil, pixelBufferAttributes, &_bufferPool) let videoStreamFormat = CMIOExtensionStreamFormat( formatDescription: _videoDescription, maxFrameDuration: CMTime(value: 1, timescale: Int32(kFrameRate)), minFrameDuration: CMTime(value: 1, timescale: Int32(kFrameRate)), validFrameDurations: nil ) _streamSource = CamExtensionStreamSource( localizedName: "PortalCam", streamID: kPortalCamSourceStreamUUID, streamFormat: videoStreamFormat, device: device ) _sinkStreamSource = CamExtensionSinkStreamSource( localizedName: "PortalCam Sink", streamID: kPortalCamSinkStreamUUID, streamFormat: videoStreamFormat, device: device, deviceSource: self ) do { try device.addStream(_streamSource.stream) try device.addStream(_sinkStreamSource.stream) } catch { fatalError("Failed to add streams: \(error.localizedDescription)") } createPlaceholderBuffer(width: Int(dims.width), height: Int(dims.height)) } private func createPlaceholderBuffer(width: Int, height: Int) { let attrs: [CFString: Any] = [ kCVPixelBufferCGImageCompatibilityKey: true, kCVPixelBufferCGBitmapContextCompatibilityKey: true, kCVPixelBufferIOSurfacePropertiesKey: [:] as NSDictionary ] let status = CVPixelBufferCreate( kCFAllocatorDefault, width, height, kCVPixelFormatType_32BGRA, attrs as CFDictionary, &_placeholderPixelBuffer ) guard status == kCVReturnSuccess, let buffer = _placeholderPixelBuffer else { return } CVPixelBufferLockBaseAddress(buffer, []) defer { CVPixelBufferUnlockBaseAddress(buffer, []) } guard let base = CVPixelBufferGetBaseAddress(buffer) else { return } let bytesPerRow = CVPixelBufferGetBytesPerRow(buffer) let colorSpace = CGColorSpaceCreateDeviceRGB() let bitmapInfo = CGBitmapInfo.byteOrder32Little.rawValue | CGImageAlphaInfo.premultipliedFirst.rawValue guard let ctx = CGContext( data: base, width: width, height: height, bitsPerComponent: 8, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo ) else { return } // Fill dark slate background ctx.setFillColor(red: 0.10, green: 0.12, blue: 0.16, alpha: 1.0) ctx.fill(CGRect(x: 0, y: 0, width: width, height: height)) // Rounded border let insetRect = CGRect(x: 40, y: 40, width: width - 80, height: height - 80) let path = CGPath(roundedRect: insetRect, cornerWidth: 20, cornerHeight: 20, transform: nil) ctx.addPath(path) ctx.setStrokeColor(red: 0.28, green: 0.45, blue: 0.75, alpha: 0.8) ctx.setLineWidth(4) ctx.strokePath() } var availableProperties: Set { return [.deviceTransportType, .deviceModel] } func deviceProperties(forProperties properties: Set) throws -> CMIOExtensionDeviceProperties { let deviceProperties = CMIOExtensionDeviceProperties(dictionary: [:]) if properties.contains(.deviceTransportType) { deviceProperties.transportType = kIOAudioDeviceTransportTypeVirtual } if properties.contains(.deviceModel) { deviceProperties.model = "PortalCam Camera" } return deviceProperties } func setDeviceProperties(_ deviceProperties: CMIOExtensionDeviceProperties) throws { // Settable properties } func startStreaming() { _streamingCounter += 1 os_log(.default, "PortalCam extension: startStreaming (counter=%{public}u)", _streamingCounter) if _streamingCounter == 1 { // Notify main app that a client has opened the camera if let center = CFNotificationCenterGetDarwinNotifyCenter() { CFNotificationCenterPostNotification( center, CFNotificationName(kStreamStartedNotification as CFString), nil, nil, true ) } // Schedule fallback/standby timer _placeholderTimer = DispatchSource.makeTimerSource(queue: _timerQueue) _placeholderTimer?.schedule(deadline: .now(), repeating: 1.0 / Double(kFrameRate), leeway: .milliseconds(2)) _placeholderTimer?.setEventHandler { [weak self] in self?.sendPlaceholderIfNeeded() } _placeholderTimer?.resume() } } func stopStreaming() { if _streamingCounter > 1 { _streamingCounter -= 1 } else { _streamingCounter = 0 os_log(.default, "PortalCam extension: stopStreaming - posting stop notification") _placeholderTimer?.cancel() _placeholderTimer = nil _lastSinkFrameLock.lock() _lastSinkFrameDate = nil _lastSinkFrameLock.unlock() if let center = CFNotificationCenterGetDarwinNotifyCenter() { CFNotificationCenterPostNotification( center, CFNotificationName(kStreamStoppedNotification as CFString), nil, nil, true ) } } } private func sendPlaceholderIfNeeded() { guard _streamingCounter > 0 else { return } _lastSinkFrameLock.lock() let lastDate = _lastSinkFrameDate _lastSinkFrameLock.unlock() // If live sink frames are actively arriving within the last 500ms, don't send placeholder if let lastDate = lastDate, Date().timeIntervalSince(lastDate) < 0.5 { return } guard let placeholder = _placeholderPixelBuffer else { return } let hostTime = CMClockGetTime(CMClockGetHostTimeClock()) var timing = CMSampleTimingInfo( duration: CMTime(value: 1, timescale: Int32(kFrameRate)), presentationTimeStamp: hostTime, decodeTimeStamp: .invalid ) var sample: CMSampleBuffer? let status = CMSampleBufferCreateForImageBuffer( allocator: kCFAllocatorDefault, imageBuffer: placeholder, dataReady: true, makeDataReadyCallback: nil, refcon: nil, formatDescription: _videoDescription, sampleTiming: &timing, sampleBufferOut: &sample ) if status == noErr, let sample = sample { let nano = UInt64(hostTime.seconds * Double(NSEC_PER_SEC)) _streamSource.stream.send(sample, discontinuity: [], hostTimeInNanoseconds: nano) } } func deliverSinkSampleBuffer(_ sampleBuffer: CMSampleBuffer) { _lastSinkFrameLock.lock() _lastSinkFrameDate = Date() _lastSinkFrameLock.unlock() guard _streamingCounter > 0 else { return } let hostTime = CMClockGetTime(CMClockGetHostTimeClock()) let nano = UInt64(hostTime.seconds * Double(NSEC_PER_SEC)) _sentFrames += 1 if _sentFrames <= 3 { os_log(.default, "PortalCam extension: forwarded sink frame %{public}d to source stream", self._sentFrames) } _streamSource.stream.send(sampleBuffer, discontinuity: [], hostTimeInNanoseconds: nano) } } // MARK: - Source Stream (FaceTime, Zoom, Photo Booth) class CamExtensionStreamSource: NSObject, CMIOExtensionStreamSource { private(set) var stream: CMIOExtensionStream! let device: CMIOExtensionDevice private let _streamFormat: CMIOExtensionStreamFormat init(localizedName: String, streamID: UUID, streamFormat: CMIOExtensionStreamFormat, device: CMIOExtensionDevice) { self.device = device self._streamFormat = streamFormat super.init() self.stream = CMIOExtensionStream( localizedName: localizedName, streamID: streamID, direction: .source, clockType: .hostTime, source: self ) } var formats: [CMIOExtensionStreamFormat] { return [_streamFormat] } var activeFormatIndex: Int = 0 { didSet { if activeFormatIndex >= 1 { os_log(.error, "Invalid index: %{public}d", activeFormatIndex) } } } var availableProperties: Set { return [.streamActiveFormatIndex, .streamFrameDuration] } func streamProperties(forProperties properties: Set) throws -> CMIOExtensionStreamProperties { let streamProperties = CMIOExtensionStreamProperties(dictionary: [:]) if properties.contains(.streamActiveFormatIndex) { streamProperties.activeFormatIndex = 0 } if properties.contains(.streamFrameDuration) { streamProperties.frameDuration = CMTime(value: 1, timescale: Int32(kFrameRate)) } return streamProperties } func setStreamProperties(_ streamProperties: CMIOExtensionStreamProperties) throws { if let activeFormatIndex = streamProperties.activeFormatIndex { self.activeFormatIndex = activeFormatIndex } } func authorizedToStartStream(for client: CMIOExtensionClient) -> Bool { return true } func startStream() throws { guard let deviceSource = device.source as? CamExtensionDeviceSource else { fatalError("Unexpected source type \(String(describing: device.source))") } deviceSource.startStreaming() } func stopStream() throws { guard let deviceSource = device.source as? CamExtensionDeviceSource else { fatalError("Unexpected source type \(String(describing: device.source))") } deviceSource.stopStreaming() } } // MARK: - Sink Stream (fed by PortalCam.app) class CamExtensionSinkStreamSource: NSObject, CMIOExtensionStreamSource { private(set) var stream: CMIOExtensionStream! let device: CMIOExtensionDevice weak var deviceSource: CamExtensionDeviceSource? private let _streamFormat: CMIOExtensionStreamFormat private let _consumeQueue = DispatchQueue(label: "com.kovtash.portalcam.sink.consume", qos: .userInteractive) private var _isStreaming: Bool = false private var _activeClient: CMIOExtensionClient? init( localizedName: String, streamID: UUID, streamFormat: CMIOExtensionStreamFormat, device: CMIOExtensionDevice, deviceSource: CamExtensionDeviceSource ) { self.device = device self.deviceSource = deviceSource self._streamFormat = streamFormat super.init() self.stream = CMIOExtensionStream( localizedName: localizedName, streamID: streamID, direction: .sink, clockType: .hostTime, source: self ) } var formats: [CMIOExtensionStreamFormat] { return [_streamFormat] } var activeFormatIndex: Int = 0 { didSet { if activeFormatIndex >= 1 { os_log(.error, "Invalid sink format index: %{public}d", activeFormatIndex) } } } var availableProperties: Set { return [ .streamActiveFormatIndex, .streamFrameDuration, .streamSinkBufferQueueSize, .streamSinkBuffersRequiredForStartup ] } func streamProperties(forProperties properties: Set) throws -> CMIOExtensionStreamProperties { let streamProperties = CMIOExtensionStreamProperties(dictionary: [:]) if properties.contains(.streamActiveFormatIndex) { streamProperties.activeFormatIndex = 0 } if properties.contains(.streamFrameDuration) { streamProperties.frameDuration = CMTime(value: 1, timescale: Int32(kFrameRate)) } if properties.contains(.streamSinkBufferQueueSize) { streamProperties.sinkBufferQueueSize = 8 } if properties.contains(.streamSinkBuffersRequiredForStartup) { streamProperties.sinkBuffersRequiredForStartup = 1 } return streamProperties } func setStreamProperties(_ streamProperties: CMIOExtensionStreamProperties) throws { if let activeFormatIndex = streamProperties.activeFormatIndex { self.activeFormatIndex = activeFormatIndex } } func authorizedToStartStream(for client: CMIOExtensionClient) -> Bool { guard isValidPortalCamClient(client: client) else { os_log(.error, "PortalCam extension: rejected unauthorized sink client PID %d, signingID %{public}@", client.pid, client.signingID ?? "unknown") return false } _activeClient = client os_log(.default, "PortalCam extension: authorized verified sink client PID %d, signingID %{public}@", client.pid, client.signingID ?? "unknown") return true } private func isValidPortalCamClient(client: CMIOExtensionClient) -> Bool { let pid = client.pid // 1. Check code signing status via kernel csops // CS_OPS_STATUS = 0, CS_VALID = 0x00000001 var status: UInt32 = 0 let statusRet = csops(pid, 0, &status, MemoryLayout.size) guard statusRet == 0 else { os_log(.error, "PortalCam extension: csops CS_OPS_STATUS failed for PID %d: errno %d", pid, errno) return false } guard (status & 0x00000001) != 0 else { os_log(.error, "PortalCam extension: process %d code signature is not valid (status 0x%{public}x)", pid, status) return false } // 2. Check code signing identity (Bundle Identifier) struct CSHeader { var magic: UInt32 = 0 var length: UInt32 = 0 } let CS_OPS_IDENTITY: UInt32 = 11 var idHeader = CSHeader() let idHeaderRet = csops(pid, CS_OPS_IDENTITY, &idHeader, MemoryLayout.size) guard idHeaderRet == 0 || errno == ERANGE else { os_log(.error, "PortalCam extension: csops CS_OPS_IDENTITY header failed for PID %d: errno %d", pid, errno) return false } let idLen = Int(UInt32(bigEndian: idHeader.length)) guard idLen >= MemoryLayout.size else { os_log(.error, "PortalCam extension: invalid identity length %d for PID %d", idLen, pid) return false } var idBuf = [UInt8](repeating: 0, count: idLen) guard csops(pid, CS_OPS_IDENTITY, &idBuf, idLen) == 0 else { os_log(.error, "PortalCam extension: csops CS_OPS_IDENTITY failed for PID %d", pid) return false } let identity = String(cString: Array(idBuf[MemoryLayout.size...])) // 3. Check Team Identifier let CS_OPS_TEAMID: UInt32 = 14 var teamHeader = CSHeader() let teamHeaderRet = csops(pid, CS_OPS_TEAMID, &teamHeader, MemoryLayout.size) guard teamHeaderRet == 0 || errno == ERANGE else { os_log(.error, "PortalCam extension: csops CS_OPS_TEAMID header failed for PID %d: errno %d", pid, errno) return false } let teamLen = Int(UInt32(bigEndian: teamHeader.length)) guard teamLen >= MemoryLayout.size else { os_log(.error, "PortalCam extension: invalid team length %d for PID %d", teamLen, pid) return false } var teamBuf = [UInt8](repeating: 0, count: teamLen) guard csops(pid, CS_OPS_TEAMID, &teamBuf, teamLen) == 0 else { os_log(.error, "PortalCam extension: csops CS_OPS_TEAMID failed for PID %d", pid) return false } let teamID = String(cString: Array(teamBuf[MemoryLayout.size...])) os_log(.default, "PortalCam extension: verified client PID %d: identity='%{public}@', teamID='%{public}@', flags=0x%{public}x", pid, identity, teamID, status) guard identity == "com.kovtash.portalcam", teamID == "ENT9X9U544" else { os_log(.error, "PortalCam extension: rejected client PID %d: identity mismatch ('%{public}@' != 'com.kovtash.portalcam') or team mismatch ('%{public}@' != 'ENT9X9U544')", pid, identity, teamID) return false } return true } func startStream() throws { os_log(.default, "PortalCam extension: sink startStream called") _isStreaming = true _consumeQueue.async { [weak self] in self?.consumeNext() } } func stopStream() throws { os_log(.default, "PortalCam extension: sink stopStream called") _isStreaming = false _activeClient = nil } private func consumeNext() { guard _isStreaming, let stream = self.stream else { return } guard let client = _activeClient ?? stream.streamingClients.first else { // No client connected yet; wait briefly and check again _consumeQueue.asyncAfter(deadline: .now() + .milliseconds(50)) { [weak self] in self?.consumeNext() } return } stream.consumeSampleBuffer(from: client) { [weak self] sampleBuffer, sequenceNumber, discontinuity, hasMore, error in guard let self = self, self._isStreaming else { return } if let error = error { os_log(.default, "PortalCam extension: sink consume error: %{public}@", error.localizedDescription) self._consumeQueue.asyncAfter(deadline: .now() + .milliseconds(100)) { [weak self] in self?.consumeNext() } return } if let sampleBuffer = sampleBuffer { self.deviceSource?.deliverSinkSampleBuffer(sampleBuffer) let pts = sampleBuffer.presentationTimeStamp let nano = pts.isValid && pts.seconds > 0 ? UInt64(pts.seconds * Double(NSEC_PER_SEC)) : mach_absolute_time() let output = CMIOExtensionScheduledOutput(sequenceNumber: sequenceNumber, hostTimeInNanoseconds: nano) stream.notifyScheduledOutputChanged(output) // Pull next buffer immediately self._consumeQueue.async { [weak self] in self?.consumeNext() } } else { // Queue is empty, wait half a frame duration (~16ms) self._consumeQueue.asyncAfter(deadline: .now() + .milliseconds(16)) { [weak self] in self?.consumeNext() } } } } } // MARK: - Provider Source class CamExtensionProviderSource: NSObject, CMIOExtensionProviderSource { private(set) var provider: CMIOExtensionProvider! private var deviceSource: CamExtensionDeviceSource! init(clientQueue: DispatchQueue?) { super.init() provider = CMIOExtensionProvider(source: self, clientQueue: clientQueue) deviceSource = CamExtensionDeviceSource(localizedName: "PortalCam") do { try provider.addDevice(deviceSource.device) } catch { fatalError("Failed to add device: \(error.localizedDescription)") } } func connect(to client: CMIOExtensionClient) throws { // Client connected } func disconnect(from client: CMIOExtensionClient) { // Client disconnected } var availableProperties: Set { return [.providerManufacturer] } func providerProperties(forProperties properties: Set) throws -> CMIOExtensionProviderProperties { let providerProperties = CMIOExtensionProviderProperties(dictionary: [:]) if properties.contains(.providerManufacturer) { providerProperties.manufacturer = "PortalCam" } return providerProperties } func setProviderProperties(_ providerProperties: CMIOExtensionProviderProperties) throws { // Settable properties } }