Function bodies 21 total
SyphonOpenGLContextIsLegacy function · c · L33-L42 (10 LOC)Sources/CSyphon/SyphonCGL.c
bool SyphonOpenGLContextIsLegacy(CGLContextObj context)
{
CGLPixelFormatObj format = CGLGetPixelFormat(context);
GLint profile;
CGLDescribePixelFormat(format, 0, kCGLPFAOpenGLProfile, &profile);
if (profile == kCGLOGLPVersion_Legacy)
return true;
return false;
}SyphonOpenGLCreateSharedContext function · c · L45-L56 (12 LOC)Sources/CSyphon/SyphonCGL.c
CGLContextObj SyphonOpenGLCreateSharedContext(CGLContextObj context)
{
CGLPixelFormatObj format = CGLGetPixelFormat(context);
CGLContextObj result;
CGLError error = CGLCreateContext(format, context, &result);
if (error == kCGLNoError)
{
return result;
}
return NULL;
}finalizer function · c · L120-L135 (16 LOC)Sources/CSyphon/SyphonDispatch.c
static void finalizer(void)
{
struct timeval start;
if(gettimeofday(&start, NULL) == 0)
{
uint64_t elapsed = 0; // in usec
while (atomic_load(&mActiveC) && elapsed < (kSyphonDispatchUnloadTimeout * USEC_PER_SEC)) {
dispatch_time_t timeout = dispatch_time(DISPATCH_TIME_NOW, (kSyphonDispatchUnloadTimeout * USEC_PER_SEC) - elapsed);
dispatch_semaphore_wait(_SyphonDispatchGetWorkSemaphore(), timeout);
struct timeval now;
if (gettimeofday(&now, NULL) != 0) break;
elapsed = ((now.tv_sec - start.tv_sec) * USEC_PER_SEC) + (now.tv_usec - start.tv_usec);
}
}
dispatch_release(_SyphonDispatchGetWorkSemaphore());
}_SyphonDispatchGetWorkSemaphore function · c · L183-L199 (17 LOC)Sources/CSyphon/SyphonDispatch.c
static dispatch_semaphore_t _SyphonDispatchGetWorkSemaphore(void)
{
dispatch_semaphore_t sem = (dispatch_semaphore_t)atomic_load(&mWorkDoneSignal);
if (!sem)
{
sem = dispatch_semaphore_create(0);
uintptr_t expected = (uintptr_t)NULL;
if (!atomic_compare_exchange_strong(&mWorkDoneSignal, &expected, (uintptr_t)sem))
{
// setting failed, some other thread must have got there first
dispatch_release(sem);
sem = (dispatch_semaphore_t)expected;
}
}
return sem;
}SyphonDispatchSourceRetain function · c · L235-L243 (9 LOC)Sources/CSyphon/SyphonDispatch.c
SyphonDispatchSourceRef SyphonDispatchSourceRetain(SyphonDispatchSourceRef source)
{
if (source)
{
atomic_fetch_add(&source->retainc, 1);
}
return source;
}SyphonDispatchSourceRelease function · c · L244-L248 (5 LOC)Sources/CSyphon/SyphonDispatch.c
void SyphonDispatchSourceRelease(SyphonDispatchSourceRef source)
{
_SyphonDispatchSourceRelease(source, false);
}_SyphonDispatchSourceRelease function · c · L249-L305 (57 LOC)Sources/CSyphon/SyphonDispatch.c
static void _SyphonDispatchSourceRelease(SyphonDispatchSourceRef source, bool onChannel)
{
if (source && (atomic_fetch_sub(&source->retainc, 1) == 1))
{
void (^cblock)(void) = (void (^)(void))atomic_load(&source->cblock);
if (cblock)
{
if (onChannel)
{
// fire the completion block
cblock();
}
else
{
// fire the completion block on a new source so it too happens in the background
SyphonDispatchSourceRef csource = SyphonDispatchSourceCreate(cblock);
SyphonDispatchSourceFire(csource);
SyphonDispatchSourceRelease(csource);
}
Block_release(cblock);
}
Block_release(source->fblock);
free(source);
atomic_fetch_sub(&mSourceC, 1);
bool overLimit;
int_fast32_t channelC = atomic_load(&mChannelC);
do {
overLimit = (channelC > atomic_load(&mSourceC));
if (overLimit)
{
SyphonDispatchChannel *channel = _SyphonDispatchChannelTryFromPool();
if (channel)
{
if (atomic_compare_exchange_Repobility (the analyzer behind this table) · https://repobility.com
SyphonDispatchSourceFire function · c · L306-L319 (14 LOC)Sources/CSyphon/SyphonDispatch.c
void SyphonDispatchSourceFire(SyphonDispatchSourceRef source)
{
if (source)
{
if (atomic_fetch_add(&source->firec, 1) == 0)
{
// if we incremented to 1 then this source is not currently on a channel
// so launch it
atomic_fetch_add(&mActiveC, 1);
_SyphonDispatchChannelLaunchFromPool(source);
}
}
}_SyphonDispatchChannelLaunchFromPool function · c · L322-L366 (45 LOC)Sources/CSyphon/SyphonDispatch.c
static inline void _SyphonDispatchChannelLaunchFromPool(SyphonDispatchSourceRef source)
{
// we retain the source until it has finished this and any subsequent fires
SyphonDispatchSourceRetain(source);
// look for an existing free channel
SyphonDispatchChannel *channel = _SyphonDispatchChannelTryFromPool();
if (channel)
{
// we found an existing channel in the pool
channel->activeSource = source;
// signal the channel to wake
dispatch_semaphore_signal(channel->signal);
}
else
{
// we didn't find a free channel, so create a new one
channel = malloc(sizeof(SyphonDispatchChannel));
if (channel)
{
channel->next = NULL;
channel->activeSource = source;
channel->signal = dispatch_semaphore_create(0);
atomic_store(&channel->done, 0);
// create a detached thread so it will clean itself up when it exits
pthread_t thread;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
if (p_SyphonDispatchChannelDestroy function · c · L367-L373 (7 LOC)Sources/CSyphon/SyphonDispatch.c
static void _SyphonDispatchChannelDestroy(SyphonDispatchChannel *channel)
{
atomic_store(&channel->done, true);
dispatch_semaphore_signal(channel->signal);
// channel will be freed on its own thread
}SyphonOpenGLContextSupportsExtension function · c · L35-L66 (32 LOC)Sources/CSyphon/SyphonOpenGLFunctions.c
GLboolean SyphonOpenGLContextSupportsExtension(CGLContextObj cgl_ctx, const char *extension)
{
const GLubyte *extensions = NULL;
const GLubyte *start;
GLubyte *where, *terminator;
// Check for illegal spaces in extension name
where = (GLubyte *) strchr(extension, ' ');
if (where || *extension == '\0')
return GL_FALSE;
extensions = glGetString(GL_EXTENSIONS);
start = extensions;
for (;;) {
where = (GLubyte *) strstr((const char *) start, extension);
if (!where)
break;
terminator = where + strlen(extension);
if (where == start || *(where - 1) == ' ')
if (*terminator == ' ' || *terminator == '\0')
return GL_TRUE;
start = terminator;
}
return GL_FALSE;
}CaptureWindow class · swift · L6-L107 (102 LOC)Sources/Indigo/CaptureWindow.swift
final class CaptureWindow: NSObject, WKNavigationDelegate {
let window: NSWindow
let webView: WKWebView
private var currentURL: String?
private var customCSS: String?
init(width: Int, height: Int, customCSS: String? = nil) {
let config = WKWebViewConfiguration()
config.preferences.setValue(true, forKey: "developerExtrasEnabled")
// Inject custom CSS via user script if provided
if let css = customCSS, !css.isEmpty {
let cssEscaped = css.replacingOccurrences(of: "\\", with: "\\\\")
.replacingOccurrences(of: "'", with: "\\'")
.replacingOccurrences(of: "\n", with: "\\n")
let js = """
(function() {
var style = document.createElement('style');
style.textContent = '\(cssEscaped)';
document.head.appendChild(style);
})();
"""
let script = WKUserScript(source: js, injectionTime: .atDocumentEndAppDelegate class · swift · L28-L44 (17 LOC)Sources/Indigo/IndigoApp.swift
class AppDelegate: NSObject, NSApplicationDelegate {
let outputManager = OutputManager()
func applicationDidFinishLaunching(_ notification: Notification) {
// Ensure the app activates properly when launched from terminal
NSApplication.shared.activate(ignoringOtherApps: true)
}
func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
return true
}
func applicationWillTerminate(_ notification: Notification) {
outputManager.syphonOutput.stop()
outputManager.ndiOutput.stop()
}
}NDIOutput class · swift · L5-L126 (122 LOC)Sources/Indigo/NDIOutput.swift
final class NDIOutput {
// NDI sender instance.
private var sender: NDIlib_send_instance_t?
private var isRunning = false
private var audioFrameCount = 0
func start(name: String) {
guard NDIlib_initialize() else {
print("NDI: Failed to initialize")
return
}
name.withCString { ptr in
var createSettings = NDIlib_send_create_t()
createSettings.p_ndi_name = ptr
createSettings.p_groups = nil
createSettings.clock_video = true
createSettings.clock_audio = true
sender = NDIlib_send_create(&createSettings)
}
if sender != nil {
isRunning = true
print("NDI: started — name: \(name)")
} else {
print("NDI: Failed to create sender")
NDIlib_destroy()
}
}
func stop() {
if let sender = sender {
NDIlib_send_destroy(sender)
}
sender = nil
OutputManager class · swift · L6-L129 (124 LOC)Sources/Indigo/OutputManager.swift
final class OutputManager: ObservableObject, StreamCaptureDelegate {
let streamCapture = StreamCapture()
let syphonOutput: SyphonOutput
let ndiOutput = NDIOutput()
private let device: MTLDevice
private var frameCount = 0
private var isStopping = false
@Published var isCapturing = false
@Published var error: String?
/// Set by ContentView — the WKWebView reference for getting its frame
weak var webViewStore: WebViewStore?
init() {
guard let device = MTLCreateSystemDefaultDevice() else {
fatalError("Metal is not available on this system")
}
self.device = device
self.syphonOutput = SyphonOutput(device: device)
streamCapture.delegate = self
}
func startCapture(settings: AppSettings) async {
guard !isCapturing && !isStopping else { return }
NSLog("OutputManager: startCapture called")
streamCapture.captureWidth = settings.width
streamCapture.captureHeiRepobility analyzer · published findings · https://repobility.com
AppSettings class · swift · L4-L41 (38 LOC)Sources/Indigo/Settings.swift
final class AppSettings: ObservableObject {
@Published var url: String {
didSet { UserDefaults.standard.set(url, forKey: "lastURL") }
}
@Published var width: Int {
didSet { UserDefaults.standard.set(width, forKey: "width") }
}
@Published var height: Int {
didSet { UserDefaults.standard.set(height, forKey: "height") }
}
@Published var fps: Int {
didSet { UserDefaults.standard.set(fps, forKey: "fps") }
}
@Published var customCSS: String {
didSet { UserDefaults.standard.set(customCSS, forKey: "customCSS") }
}
@Published var syphonEnabled: Bool {
didSet { UserDefaults.standard.set(syphonEnabled, forKey: "syphonEnabled") }
}
@Published var ndiEnabled: Bool {
didSet { UserDefaults.standard.set(ndiEnabled, forKey: "ndiEnabled") }
}
@Published var audioEnabled: Bool {
didSet { UserDefaults.standard.set(audioEnabled, forKey: "audioEnabled") }
}
init() {
leStreamCapture class · swift · L10-L124 (115 LOC)Sources/Indigo/StreamCapture.swift
final class StreamCapture: NSObject, SCStreamOutput, SCStreamDelegate {
weak var delegate: StreamCaptureDelegate?
private var videoStream: SCStream?
private var audioStream: SCStream?
var captureWidth: Int = 1920
var captureHeight: Int = 1080
var captureFPS: Int = 60
var captureAudio: Bool = true
var sourceRect: CGRect = .zero
func startCapture() async throws {
let content = try await SCShareableContent.excludingDesktopWindows(false, onScreenWindowsOnly: true)
let pid = ProcessInfo.processInfo.processIdentifier
guard let window = content.windows
.filter({ $0.owningApplication?.processID == pid && $0.isOnScreen })
.max(by: { $0.frame.width * $0.frame.height < $1.frame.width * $1.frame.height })
else {
throw CaptureError.windowNotFound
}
NSLog("StreamCapture: window [%d] frame=%@", window.windowID, NSStringFromRect(window.frame))
// --- Video stream: windSyphonOutput class · swift · L6-L57 (52 LOC)Sources/Indigo/SyphonOutput.swift
final class SyphonOutput {
private var server: SyphonMetalServer?
private let device: MTLDevice
private let commandQueue: MTLCommandQueue?
var isRunning: Bool { server != nil }
init(device: MTLDevice) {
self.device = device
self.commandQueue = device.makeCommandQueue()
}
func start(name: String) {
guard server == nil else { return }
server = SyphonMetalServer(name: name, device: device, options: nil)
if server != nil {
print("Syphon: started server — name: \(name)")
} else {
print("Syphon: failed to create server")
}
}
func stop() {
server?.stop()
server = nil
print("Syphon: stopped")
}
func publishFrame(from sampleBuffer: CMSampleBuffer) {
guard let server = server else { return }
guard let pixelBuffer = sampleBuffer.imageBuffer else { return }
guard let surface = CVPixelBufferGetIOSurface(pixelBuffer)?.takeUnrCoordinator class · swift · L33-L71 (39 LOC)Sources/Indigo/URLBarView.swift
class Coordinator: NSObject, NSTextFieldDelegate {
@Binding var text: String
var onSubmit: () -> Void
var isEditing = false
init(text: Binding<String>, onSubmit: @escaping () -> Void) {
_text = text
self.onSubmit = onSubmit
}
func controlTextDidBeginEditing(_ obj: Notification) {
isEditing = true
}
func controlTextDidChange(_ obj: Notification) {
guard let field = obj.object as? NSTextField else { return }
text = field.stringValue
}
func controlTextDidEndEditing(_ obj: Notification) {
isEditing = false
guard let field = obj.object as? NSTextField else { return }
text = field.stringValue
}
func control(_ control: NSControl, textView: NSTextView, doCommandBy commandSelector: Selector) -> Bool {
if commandSelector == #selector(NSResponder.insertNewline(_:)) {
if lWebViewStore class · swift · L4-L23 (20 LOC)Sources/Indigo/WebRenderer.swift
class WebViewStore: ObservableObject {
@Published var webView: WKWebView?
func loadURL(_ urlString: String) {
guard let url = URL(string: urlString) else { return }
webView?.load(URLRequest(url: url))
}
func goBack() { webView?.goBack() }
func goForward() { webView?.goForward() }
func reload() { webView?.reload() }
func refreshCache() {
guard let webView = webView, let url = webView.url else { return }
let dataStore = WKWebsiteDataStore.default()
dataStore.removeData(ofTypes: WKWebsiteDataStore.allWebsiteDataTypes(), modifiedSince: .distantPast) {
webView.load(URLRequest(url: url))
}
}
}Coordinator class · swift · L57-L68 (12 LOC)Sources/Indigo/WebRenderer.swift
class Coordinator: NSObject, WKNavigationDelegate {
var lastLoadedURL: String?
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
print("WebView navigation failed: \(error.localizedDescription)")
}
func webViewWebContentProcessDidTerminate(_ webView: WKWebView) {
print("WebContent process terminated, reloading...")
webView.reload()
}
}