| 1 | import AppKit |
| 2 | |
| 3 | // Headless pipeline test: sequencer --selftest <mediafile> |
| 4 | if CommandLine.arguments.count >= 3, CommandLine.arguments[1] == "--selftest" { |
| 5 | runSelftest(path: CommandLine.arguments[2]) |
| 6 | exit(0) |
| 7 | } |
| 8 | |
| 9 | // Headless cache-budget test: sequencer --cachetest <file.sq> [capGB] |
| 10 | if CommandLine.arguments.count >= 3, CommandLine.arguments[1] == "--cachetest" { |
| 11 | let cap = CommandLine.arguments.count >= 4 ? Int(CommandLine.arguments[3]) ?? 0 : 0 |
| 12 | runCacheTest(path: CommandLine.arguments[2], capGB: cap) |
| 13 | exit(0) |
| 14 | } |
| 15 | |
| 16 | if CommandLine.arguments.contains("--uitest") { |
| 17 | _ = NSApplication.shared // AppKit needs an app instance for views/windows |
| 18 | MainActor.assumeIsolated { runUITest() } |
| 19 | } |
| 20 | |
| 21 | // Diagnostic: bare AVPlayerLayer window on a stitched composition, using the |
| 22 | // app's own bundle/signing — isolates layer rendering from the app machinery. |
| 23 | if CommandLine.arguments.count >= 3, CommandLine.arguments[1] == "--layertest" { |
| 24 | let app = NSApplication.shared |
| 25 | app.setActivationPolicy(.regular) |
| 26 | MainActor.assumeIsolated { |
| 27 | runLayerTest(specs: Array(CommandLine.arguments.dropFirst(2))) |
| 28 | } |
| 29 | app.run() |
| 30 | } |
| 31 | |
| 32 | if CommandLine.arguments.count >= 3, CommandLine.arguments[1] == "--perftest" { |
| 33 | _ = NSApplication.shared |
| 34 | MainActor.assumeIsolated { runPerfTest(path: CommandLine.arguments[2]) } |
| 35 | } |
| 36 | |
| 37 | // pkill/SIGTERM (run.sh does one per rebuild) must also take the ffmpeg |
| 38 | // children down — the default handler kills only this process, minting the |
| 39 | // orphan encoders that exhaust VideoToolbox and black out the next launch. |
| 40 | // A background queue, NOT main: a wedged main thread must not make the app |
| 41 | // unkillable (pkill looked ignored while main was frozen). |
| 42 | signal(SIGTERM, SIG_IGN) |
| 43 | signal(SIGINT, SIG_IGN) |
| 44 | let signalQueue = DispatchQueue(label: "sequencer.signals", qos: .userInteractive) |
| 45 | let termSource = DispatchSource.makeSignalSource(signal: SIGTERM, queue: signalQueue) |
| 46 | let intSource = DispatchSource.makeSignalSource(signal: SIGINT, queue: signalQueue) |
| 47 | for src in [termSource, intSource] { |
| 48 | src.setEventHandler { |
| 49 | MediaPipeline.terminateChildren() |
| 50 | exit(0) |
| 51 | } |
| 52 | src.resume() |
| 53 | } |
| 54 | |
| 55 | HangMonitor.start() |
| 56 | // SEQ_HANGTEST=1: deliberately stall the main thread once, to verify the |
| 57 | // watchdog end-to-end (a [hang] line with this frame should hit the log). |
| 58 | if ProcessInfo.processInfo.environment["SEQ_HANGTEST"] != nil { |
| 59 | DispatchQueue.main.asyncAfter(deadline: .now() + 2) { hangTestStall() } |
| 60 | } |
| 61 | |
| 62 | let app = SeqApplication.shared |
| 63 | let delegate = AppDelegate() |
| 64 | app.delegate = delegate |
| 65 | // Instantiate our controller before anything opens a document: the first |
| 66 | // NSDocumentController created becomes the shared instance. Retained here so it |
| 67 | // stays the shared controller for the app's lifetime. |
| 68 | let documentController = ProjectDocumentController() |
| 69 | app.setActivationPolicy(.regular) |
| 70 | app.run() |