import AppKit @_spi(Fixtures) import CallsKit import Foundation import LiveKitWebRTC import ScreenCaptureKit import SwiftUI // A separate test executable: synthetic video and fixture credentials are never // compiled into CallsMac. Input travels on stdin, not argv or a saved file. struct Input: Decodable { let origin: String let room: String let cookies: String let chatSnapshot: String? let invitation: String? } @main struct Interop { @MainActor static var screen: SyntheticScreen? @MainActor static var display: DisplayCapture? @MainActor static var webrtcLogger: LKRTCCallbackLogger? @MainActor static let cameras = SyntheticCameras() // A defaults domain of its own, so the gate's camera choices are never // remembered into anyone's real preferences. @MainActor static let camera = ManagedCamera( backend: cameras, defaults: UserDefaults(suiteName: "calls-interop-\(UUID().uuidString)")!) @MainActor static func main() async { if CommandLine.arguments.count == 3, CommandLine.arguments[1] == "--lobby-snapshots" { do { try await LobbySnapshots.save(to: CommandLine.arguments[2]) } catch { exit(1) } return } if CommandLine.arguments.count == 3, CommandLine.arguments[1] == "--call-snapshots" { do { try await CallSnapshots.save(to: URL(fileURLWithPath: CommandLine.arguments[2])) } catch { exit(1) } return } if CommandLine.arguments.count == 3, CommandLine.arguments[1] == "--connecting-snapshots" { do { try await CallSnapshots.saveConnecting(to: URL(fileURLWithPath: CommandLine.arguments[2])) } catch { exit(1) } return } if CommandLine.arguments.count == 3, CommandLine.arguments[1] == "--glass-snapshots" { do { try await CallSnapshots.saveGlass(to: URL(fileURLWithPath: CommandLine.arguments[2])) } catch { exit(1) } return } if CommandLine.arguments.count == 3, CommandLine.arguments[1] == "--speaker-snapshots" { do { try await CallSnapshots.saveSpeaker(to: URL(fileURLWithPath: CommandLine.arguments[2])) } catch { exit(1) } return } if CommandLine.arguments.count == 2, CommandLine.arguments[1] == "--mini-clicks" { // Under NSApplication's own run loop, as the app is: the surface // tracks a press with a nested event loop, which Swift's async main // alone does not survive. NSApplication.shared.setActivationPolicy(.accessory) Task { @MainActor in let call = Call(playAudio: false) CallFixture.grid.apply(to: call) let results = await MiniWindowProbe.run(call: call) for r in results { print((r.passed ? "ok " : "FAIL ") + r.name + (r.passed ? "" : " — " + r.detail)) } print("mini-clicks: \(results.filter(\.passed).count) of \(results.count) presses did what they should") fflush(stdout) exit(results.allSatisfy(\.passed) ? 0 : 1) } NSApplication.shared.run() } if CommandLine.arguments.count == 3, CommandLine.arguments[1] == "--stage-snapshots" { do { try await StageSnapshots.save(to: URL(fileURLWithPath: CommandLine.arguments[2])) } catch { exit(1) } return } if CommandLine.arguments.count == 3, CommandLine.arguments[1] == "--bar-layout" { exit(await BarLayoutHarness.run(to: URL(fileURLWithPath: CommandLine.arguments[2])) ? 0 : 1) } if CommandLine.arguments.count == 2, CommandLine.arguments[1] == "--audio-start-stall" { exit(await AudioStartStallHarness.run() ? 0 : 1) } if CommandLine.arguments.count == 2, CommandLine.arguments[1] == "--audio-selftest" { exit(await AudioSelfTestHarness.run() ? 0 : 1) } guard let line = readLine(), let input = try? JSONDecoder().decode(Input.self, from: Data(line.utf8)), let url = URL(string: input.origin), url.scheme == "http", url.host == "127.0.0.1" else { exit(2) } // Decoders the gate can wedge (spec §15.22), set before the call's // factory is made; only for the scenarios that ask, so every other // gate decodes exactly as the apps do. if ProcessInfo.processInfo.environment["CALLS_DECODER_WEDGE"] == "1" { DecoderWedge.enabled = true } let call = Call(playAudio: false, audioInput: SyntheticVoice()) if ProcessInfo.processInfo.environment["CALLS_SCREEN_WATCHDOG"] == "0" { Call.screenWatchdogEnabled = false } // Quality reports every N seconds rather than thirty (spec §15.26), so // the gate sees one inside its call. A number of seconds, at least one. if let seconds = ProcessInfo.processInfo.environment["CALLS_QUALITY_INTERVAL"].flatMap(Double.init), seconds >= 1 { Call.qualityInterval = seconds } // WebRTC's own log, filtered to the video encoder, into a file: for // diagnosing the gate's screen scenarios by hand. Never credentials: // the filter keeps encoder lines only. if let base = ProcessInfo.processInfo.environment["CALLS_WEBRTC_LOG"] { let path = "\(base).\(getpid())" FileManager.default.createFile(atPath: path, contents: nil) let handle = FileHandle(forWritingAtPath: path) let logger = LKRTCCallbackLogger() logger.severity = .info let everything = ProcessInfo.processInfo.environment["CALLS_WEBRTC_LOG_ALL"] == "1" logger.start { message in let lower = message.lowercased() guard everything || ["h264", "encod", "videotoolbox", "vtcompression", "resolution", "adapt", "quality"].contains(where: lower.contains) else { return } let stamp = String(format: "%.3f ", Date().timeIntervalSince1970) handle?.write(Data((stamp + message).utf8)) } Interop.webrtcLogger = logger } // 0.4.1's motion sizing, without the H.264 level cap, for measuring it. if ProcessInfo.processInfo.environment["CALLS_SCREEN_UNCAPPED"] == "1" { ScreenSendPolicy.levelCapped = false } let preview = input.chatSnapshot.map { ChatPreview(call: call, path: $0) } do { try await call.join( origin: input.origin, room: input.room, cookies: input.cookies, capture: Interop.camera) } catch { print("FAIL native start") exit(1) } Task.detached { while let command = readLine() { if command == "leave" { await call.leave() exit(0) } if command == "mute" { await call.mute() print("{\"muted\":\(await call.muted)}") fflush(stdout) } if command == "chat" { await call.sendChat("native chat probe") print("{\"chatCommandHandled\":true}") fflush(stdout) } if command == "snapshot" { let saved = await preview?.save() ?? false _ = await preview?.saveCall(call: call) print("{\"chatSnapshotSaved\":\(saved)}") fflush(stdout) } if command == "share" { await call.loadInvitation() let invitation = await call.invitationURL?.absoluteString let refused = await !call.invitationError.isEmpty let ready = invitation != nil && invitation == input.invitation print("{\"invitationReady\":\(ready),\"invitationRefused\":\(refused)}") fflush(stdout) } if command == "audio-default" || command == "audio-missing" { let succeeded = await MainActor.run { do { try call.audio.use(input: command == "audio-default" ? "" : "no-such-device") try call.audio.use(output: "") return true } catch { return false } } print("{\"audioSwitched\":\(succeeded)}") fflush(stdout) } // The camera stops sending, and the watchdog has to notice and // restart it: frames come back on the next open. if command == "camera-stall" { await MainActor.run { Interop.cameras.stalled = true } print("{\"cameraStalled\":true}") fflush(stdout) } if command.hasPrefix("camera ") { let id = String(command.dropFirst("camera ".count)) await call.useCamera(id) let now = await call.currentCamera ?? "" let note = await call.deviceNote print("{\"camera\":\"\(now)\",\"cameraRefused\":\(note.isEmpty ? "false" : "true")}") fflush(stdout) } // §5.4, sending. `screen-end` is the capture ending on its own, // which is the path the system's stop control takes. if command == "screen-on" { let screen = await SyntheticScreen() await MainActor.run { Interop.screen = screen } await call.shareScreen(screen) let on = await call.sharingScreen print("{\"screenSharing\":\(on)}") fflush(stdout) } // "Optimise for", as the device panel sets it. if command.hasPrefix("screen-mode ") { let mode = ScreenShareMode(rawValue: String(command.dropFirst("screen-mode ".count))) if let mode { await MainActor.run { call.screenMode = mode } } print("{\"screenMode\":\"\(mode?.rawValue ?? "")\"}") fflush(stdout) } // The motion gate: a 1080p page scrolling at 30 fps. if command == "screen-motion" { let screen = await SyntheticScreen(motion: true) await MainActor.run { Interop.screen = screen } await call.shareScreen(screen) let on = await call.sharingScreen print("{\"screenSharing\":\(on)}") fflush(stdout) } // A thin uplink, for the same gate: `uplink 1200000`, or `uplink 0` // to lift it. if command.hasPrefix("uplink ") { let bps = Int(command.dropFirst("uplink ".count)) ?? 0 await call.limitUplink(bps > 0 ? bps : nil) print("{\"uplink\":\(bps)}") fflush(stdout) } if command == "screen-off" { await call.stopSharingScreen() print("{\"screenSharing\":false}") fflush(stdout) } // The synthetic screen stops producing anything, as a capture // with every surface held does; the watchdog has to restart it. if command == "screen-stall" { await MainActor.run { Interop.screen?.stall() } print("{\"screenStalled\":true}") fflush(stdout) } // Every screen encoding switched off behind the watchdog's back: // frames go in and nothing comes out. if command == "screen-encoder-stall" { await call.stallScreenEncoderForTest() print("{\"encoderStalled\":true}") fflush(stdout) } // The real thing: this Mac's main display through ScreenCaptureKit // and the hardware encoder, at the given queue depth. Needs Screen // Recording permission for the process running the gate. if command.hasPrefix("screen-display") { let depth = Int(command.split(separator: " ").dropFirst().first ?? "") ?? 6 await MainActor.run { MacScreenCapture.queueDepth = depth } let display = await DisplayCapture() await MainActor.run { Interop.display = display } await call.shareScreen(display) let on = await call.sharingScreen print("{\"screenSharing\":\(on)}") fflush(stdout) } // The receiving side's watch treats every screen as frozen. if command.hasPrefix("screen-freeze-test ") { let ms = Double(command.dropFirst("screen-freeze-test ".count)) ?? 0 await call.freezeScreenWatchForTest(seconds: ms / 1000) print("{\"screenFrozenForTest\":true}") fflush(stdout) } // §15.22: this app's screen decoders stop putting out pictures // while packets keep arriving — a wedge no keyframe mends and a // new transceiver does. `sticky` wedges the new ones too. if command == "screen-decoder-wedge" || command == "screen-decoder-wedge sticky" { let n = DecoderWedge.wedgeScreens(sticky: command.hasSuffix("sticky")) print("{\"decoderWedged\":\(n)}") fflush(stdout) } if command == "screen-decoder-release" { DecoderWedge.release() print("{\"decoderReleased\":true}") fflush(stdout) } // "Copy call diagnostics", as the panel would copy it. if command == "diagnostics" { let text = await call.audioDiagnosticsText() if let data = try? JSONSerialization.data(withJSONObject: ["diagnostics": text]), let line = String(data: data, encoding: .utf8) { print(line) fflush(stdout) } } if command == "screen-reshare-test" { await call.reshareScreenForTest() print("{\"reshared\":true}") fflush(stdout) } if command == "screen-end" { await Interop.screen?.end() let on = await call.sharingScreen print("{\"screenSharing\":\(on)}") fflush(stdout) } if command == "share-snapshot" { let saved = await preview?.saveInvitation(call: call) ?? false print("{\"invitationSnapshotSaved\":\(saved)}") fflush(stdout) } } } // Long enough for the member scenario, screens and all, and for the // motion gate's three modes: the gate always says `leave` long before // this runs out. // CALLS_INTEROP_SECONDS for the soaks, which outlast that (§15.22). let life = Int(ProcessInfo.processInfo.environment["CALLS_INTEROP_SECONDS"] ?? "") ?? 400 for _ in 0.. Void) async throws { let content = try await SCShareableContent.excludingDesktopWindows(false, onScreenWindowsOnly: true) guard let display = content.displays.first else { throw CancellationError() } try await mac.start(display: display, source: source, ended: ended) } func stop() { mac.stop() } var counts: ScreenCaptureCounts { mac.counts } func restart() async -> Bool { await mac.restart() } var frameSize: (width: Int, height: Int)? { mac.frameSize } } // Render the shipping chat view against real received messages. This fixture // window sits off-screen and never activates or interrupts the user's call. @MainActor private final class ChatPreview { let window: NSWindow let view: NSHostingView let path: String init(call: Call, path: String) { NSApplication.shared.setActivationPolicy(.prohibited) self.path = path view = NSHostingView( rootView: AnyView( ChatView(call: call).padding(12).background(Color.white).environment(\.colorScheme, .light)) ) window = NSWindow( contentRect: NSRect(x: -2000, y: -2000, width: 600, height: 200), styleMask: [.borderless], backing: .buffered, defer: false) window.isReleasedWhenClosed = false window.contentView = view window.orderFront(nil) } func save() -> Bool { view.layoutSubtreeIfNeeded() guard let bitmap = view.bitmapImageRepForCachingDisplay(in: view.bounds) else { return false } view.cacheDisplay(in: view.bounds, to: bitmap) guard let data = bitmap.representation(using: .png, properties: [:]) else { return false } do { try data.write(to: URL(fileURLWithPath: path)) return true } catch { return false } } func saveCall(call: Call) async -> Bool { var saved = true for (name, grid, chat) in [ ("call-focus.png", false, false), ("call-chat.png", false, true), ("call-grid.png", true, false), ] { view.rootView = AnyView( MacCallView(call: call, grid: grid, showingChat: chat, style: .classic, leave: {}).id(name) .padding(20).tint(CallsAppearance.accent).background(Color.white) .environment(\.colorScheme, .light)) window.setContentSize(NSSize(width: 900, height: 540)) try? await Task.sleep(for: .milliseconds(300)) saved = saveImage(named: name) && saved } view.rootView = AnyView( VStack(alignment: .leading, spacing: 0) { Text("Devices").font(.headline).padding(.horizontal, 16).padding(.top, 16) DevicePanel(call: call) Spacer(minLength: 0) }.frame(width: 300) .background(Color.white).environment(\.colorScheme, .light)) window.setContentSize(NSSize(width: 300, height: 340)) try? await Task.sleep(for: .milliseconds(300)) saved = saveImage(named: "call-devices.png") && saved view.rootView = AnyView( ChatView(call: call).padding(12) .background(Color.white).environment(\.colorScheme, .light)) window.setContentSize(NSSize(width: 600, height: 200)) return saved } private func saveImage(named name: String) -> Bool { view.layoutSubtreeIfNeeded() guard let bitmap = view.bitmapImageRepForCachingDisplay(in: view.bounds) else { return false } view.cacheDisplay(in: view.bounds, to: bitmap) guard let data = bitmap.representation(using: .png, properties: [:]) else { return false } let target = URL(fileURLWithPath: path).deletingLastPathComponent().appendingPathComponent(name) do { try data.write(to: target) return true } catch { return false } } func saveInvitation(call: Call) async -> Bool { view.rootView = AnyView( MeetingInvitationView(call: call, close: {}) .background(Color.white).environment(\.colorScheme, .light)) window.setContentSize(NSSize(width: 440, height: 340)) try? await Task.sleep(for: .milliseconds(250)) view.layoutSubtreeIfNeeded() guard let bitmap = view.bitmapImageRepForCachingDisplay(in: view.bounds) else { return false } view.cacheDisplay(in: view.bounds, to: bitmap) guard let data = bitmap.representation(using: .png, properties: [:]) else { return false } let target = URL(fileURLWithPath: path).deletingLastPathComponent().appendingPathComponent( "share-meeting.png") do { try data.write(to: target) return true } catch { return false } } }