Use ScreenCaptureKit-enabled LiveKit SDK and add display_sources function

Nathan Sobo and Antonio Scandurra created

Co-Authored-By: Antonio Scandurra <antonio@zed.dev>

Change summary

crates/capture/src/main.rs                                              |  5 
crates/live_kit/LiveKitBridge/Package.resolved                          |  6 
crates/live_kit/LiveKitBridge/Package.swift                             |  2 
crates/live_kit/LiveKitBridge/Sources/LiveKitBridge/LiveKitBridge.swift |  9 
crates/live_kit/src/live_kit.rs                                         | 39 
5 files changed, 56 insertions(+), 5 deletions(-)

Detailed changes

crates/capture/src/main.rs 🔗

@@ -38,6 +38,11 @@ fn main() {
         let live_kit_secret = std::env::var("LIVE_KIT_SECRET").unwrap();
 
         cx.spawn(|mut cx| async move {
+            match live_kit::display_sources().await {
+                Ok(sources) => println!("found {} sources", sources.len()),
+                Err(error) => println!("error finding display sources {}", error),
+            }
+
             let user1_token = live_kit_token::create_token(
                 &live_kit_key,
                 &live_kit_secret,

crates/live_kit/LiveKitBridge/Package.resolved 🔗

@@ -6,7 +6,7 @@
         "repositoryURL": "https://github.com/livekit/client-sdk-swift.git",
         "state": {
           "branch": null,
-          "revision": "5cc3c001779ab147199ce3ea0dce465b846368b4",
+          "revision": "a90ecba800f65bebfc31f5c9c59f635c8587ec7e",
           "version": null
         }
       },
@@ -42,8 +42,8 @@
         "repositoryURL": "https://github.com/apple/swift-protobuf.git",
         "state": {
           "branch": null,
-          "revision": "b8230909dedc640294d7324d37f4c91ad3dcf177",
-          "version": "1.20.1"
+          "revision": "88c7d15e1242fdb6ecbafbc7926426a19be1e98a",
+          "version": "1.20.2"
         }
       }
     ]

crates/live_kit/LiveKitBridge/Package.swift 🔗

@@ -15,7 +15,7 @@ let package = Package(
             targets: ["LiveKitBridge"]),
     ],
     dependencies: [
-        .package(url: "https://github.com/livekit/client-sdk-swift.git", revision: "5cc3c001779ab147199ce3ea0dce465b846368b4"),
+        .package(url: "https://github.com/livekit/client-sdk-swift.git", revision: "a90ecba800f65bebfc31f5c9c59f635c8587ec7e"),
     ],
     targets: [
         // Targets are the basic building blocks of a package. A target can define a module or a test suite.

crates/live_kit/LiveKitBridge/Sources/LiveKitBridge/LiveKitBridge.swift 🔗

@@ -103,3 +103,12 @@ public func LKVideoTrackAddRenderer(track: UnsafeRawPointer, renderer: UnsafeRaw
     let renderer = Unmanaged<LKVideoRenderer>.fromOpaque(renderer).takeRetainedValue()
     track.add(videoRenderer: renderer)
 }
+
+@_cdecl("LKDisplaySources")
+public func LKDisplaySources(data: UnsafeRawPointer, callback: @escaping @convention(c) (UnsafeRawPointer, CFArray?, CFString?) -> Void) {
+    MacOSScreenCapturer.displaySources().then { displaySources in
+        callback(data, displaySources as CFArray, nil)
+    }.catch { error in
+        callback(data, nil, error.localizedDescription as CFString)
+    }
+}

crates/live_kit/src/live_kit.rs 🔗

@@ -1,6 +1,6 @@
 use anyhow::{anyhow, Context, Result};
 use core_foundation::{
-    array::CFArray,
+    array::{CFArray, CFArrayRef},
     base::{TCFType, TCFTypeRef},
     dictionary::CFDictionary,
     number::CFNumber,
@@ -56,6 +56,14 @@ extern "C" {
     fn LKVideoTrackAddRenderer(track: *const c_void, renderer: *const c_void);
 
     fn LKCreateScreenShareTrackForWindow(windowId: u32) -> *const c_void;
+    fn LKDisplaySources(
+        callback_data: *mut c_void,
+        callback: extern "C" fn(
+            callback_data: *mut c_void,
+            sources: CFArrayRef,
+            error: CFStringRef,
+        ),
+    );
 }
 
 pub struct Room {
@@ -274,3 +282,32 @@ pub fn list_windows() -> Vec<WindowInfo> {
             .collect()
     }
 }
+
+pub struct MacOSDisplay(*const c_void);
+
+pub fn display_sources() -> impl Future<Output = Result<Vec<MacOSDisplay>>> {
+    extern "C" fn callback(tx: *mut c_void, sources: CFArrayRef, error: CFStringRef) {
+        unsafe {
+            let tx = Box::from_raw(tx as *mut oneshot::Sender<Result<Vec<MacOSDisplay>>>);
+
+            if sources.is_null() {
+                let _ = tx.send(Err(anyhow!("{}", CFString::wrap_under_get_rule(error))));
+            } else {
+                let sources = CFArray::wrap_under_get_rule(sources);
+                let sources = sources
+                    .into_iter()
+                    .map(|source| MacOSDisplay(*source))
+                    .collect();
+                let _ = tx.send(Ok(sources));
+            }
+        }
+    }
+
+    let (tx, rx) = oneshot::channel();
+
+    unsafe {
+        LKDisplaySources(Box::into_raw(Box::new(tx)) as *mut _, callback);
+    }
+
+    async move { rx.await.unwrap() }
+}