Files
Scream/Scream/ScreenRecorder.swift
2026-01-01 22:54:06 +00:00

106 lines
3.0 KiB
Swift

//
// ScreenRecorder.swift
// Scream
//
// Created by neon443 on 31/12/2025.
//
import Foundation
import ScreenCaptureKit
class ScreenRecorder: NSObject {
var isRunning: Bool = false
var isAppExluded: Bool = true
var isAudioEnabled: Bool = false
var filter: SCContentFilter?
// var filter: SCContentFilter
//
// var excludedApps = [SCRunningApplication]()
// //if users exclude Scream from the screen share
// //exclude by matching bundleid
//// if isAppExluded {
//// excludedApps = availableContent.applications.filter { app in
//// Bundle.main.bundleIdentifier == app.bundleIdentifier
//// }
//// }
// filter = SCContentFilter(display: availableContent.displays.first!, excludingApplications: excludedApps, exceptingWindows: [])
// }
var scaleFactor: Int { Int(NSScreen.main?.backingScaleFactor ?? 2) }
var streamConfig: SCStreamConfiguration {
var streamConfig = SCStreamConfiguration()
//TODO: hdr
// streamConfig.capturesAudio = isAudioEnabled
// streamConfig.excludesCurrentProcessAudio = false
// streamConfig.captureMicrophone = true
streamConfig.width = Int(NSScreen.main?.frame.width ?? 100) * scaleFactor
streamConfig.height = Int(NSScreen.main?.frame.height ?? 100) * scaleFactor
streamConfig.minimumFrameInterval = CMTime(value: 1, timescale: 60)
streamConfig.queueDepth = 5
return streamConfig
}
let captureEngine = CaptureEngine()
var contentLayer = CALayer()
var canRecord: Bool {
true
}
func start() async {
guard !isRunning else { return }
let availableContent: SCShareableContent
do {
availableContent = try await SCShareableContent.excludingDesktopWindows(false, onScreenWindowsOnly: true)
} catch {
print(error.localizedDescription)
return
}
var excludedApps = [SCRunningApplication]()
//if users exclude Scream from the screen share
//exclude by matching bundleid
if isAppExluded {
excludedApps = availableContent.applications.filter { app in
Bundle.main.bundleIdentifier == app.bundleIdentifier
}
}
filter = SCContentFilter(display: availableContent.displays.first!, excludingApplications: excludedApps, exceptingWindows: [])
do {
isRunning = true
for try await frame in captureEngine.startCapture(config: streamConfig, filter: filter!) {
contentLayer.contents = frame.surface
}
} catch {
isRunning = false
print(error.localizedDescription)
}
//TODO: update the config using stream.updateConfiguration or .updateContentFilter
}
func stop() async {
guard isRunning else { return }
await captureEngine.stopCapture()
isRunning = false
}
}
extension ScreenRecorder: SCContentSharingPickerObserver {
@available(macOS 14, *)
func contentSharingPicker(_ picker: SCContentSharingPicker, didCancelFor stream: SCStream?) {
print("canceleed picker")
}
@available(macOS 14, *)
func contentSharingPicker(_ picker: SCContentSharingPicker, didUpdateWith filter: SCContentFilter, for stream: SCStream?) {
print(picker.description)
}
func contentSharingPickerStartDidFailWithError(_ error: any Error) {
print(error.localizedDescription)
}
}