Cargo.lock 🔗
@@ -2941,6 +2941,7 @@ name = "live_kit"
version = "0.1.0"
dependencies = [
"core-foundation",
+ "core-graphics",
"futures",
"serde",
"serde_json",
Nathan Sobo created
And also list windows
Cargo.lock | 1
crates/capture/src/main.rs | 20
crates/live_kit/Cargo.toml | 1
crates/live_kit/LiveKitBridge/Sources/LiveKitBridge/LiveKitBridge.swift | 16
crates/live_kit/src/live_kit.rs | 78
5 files changed, 93 insertions(+), 23 deletions(-)
@@ -2941,6 +2941,7 @@ name = "live_kit"
version = "0.1.0"
dependencies = [
"core-foundation",
+ "core-graphics",
"futures",
"serde",
"serde_json",
@@ -7,7 +7,7 @@ use gpui::{
platform::current::Surface,
Menu, MenuItem, ViewContext,
};
-use live_kit::Room;
+use live_kit::{LocalVideoTrack, Room};
use log::LevelFilter;
use media::core_video::CVImageBuffer;
use simplelog::SimpleLogger;
@@ -42,13 +42,17 @@ fn main() {
.unwrap();
let room = live_kit::Room::new();
- cx.spawn(|cx| async move {
- println!("connecting...");
- room.connect("wss://zed.livekit.cloud", &token).await;
- println!("connected!");
- drop(room);
- })
- .detach();
+ cx.foreground()
+ .spawn(async move {
+ println!("connecting...");
+ room.connect("wss://zed.livekit.cloud", &token).await;
+ let windows = live_kit::list_windows();
+ println!("connected! {:?}", windows);
+
+ let window_id = windows.iter().next().unwrap().id;
+ let track = LocalVideoTrack::screen_share_for_window(window_id);
+ })
+ .detach();
// cx.add_window(Default::default(), |cx| ScreenCaptureView::new(cx));
});
@@ -10,6 +10,7 @@ doctest = false
[dependencies]
core-foundation = "0.9.3"
+core-graphics = "0.22.3"
futures = "0.3"
[build-dependencies]
@@ -1,16 +1,16 @@
import Foundation
import LiveKit
+@_cdecl("LKRelease")
+public func LKRelease(ptr: UnsafeRawPointer) {
+ let _ = Unmanaged<AnyObject>.fromOpaque(ptr).takeRetainedValue();
+}
+
@_cdecl("LKRoomCreate")
public func LKRoomCreate() -> UnsafeMutableRawPointer {
Unmanaged.passRetained(Room()).toOpaque()
}
-@_cdecl("LKRoomDestroy")
-public func LKRoomDestroy(ptr: UnsafeRawPointer) {
- let _ = Unmanaged<Room>.fromOpaque(ptr).takeRetainedValue();
-}
-
@_cdecl("LKRoomConnect")
public func LKRoomConnect(room: UnsafeRawPointer, url: CFString, token: CFString, callback: @escaping @convention(c) (UnsafeRawPointer) -> Void, callback_data: UnsafeRawPointer) {
let room = Unmanaged<Room>.fromOpaque(room).takeUnretainedValue();
@@ -21,3 +21,9 @@ public func LKRoomConnect(room: UnsafeRawPointer, url: CFString, token: CFString
print(error);
};
}
+
+@_cdecl("LKCreateScreenShareTrackForWindow")
+public func LKCreateScreenShareTrackForWindow(windowId: uint32) -> UnsafeMutableRawPointer {
+ let track = LocalVideoTrack.createMacOSScreenShareTrack(source: .window(id: windowId));
+ return Unmanaged.passRetained(track).toOpaque()
+}
@@ -1,13 +1,20 @@
use core_foundation::{
- base::TCFType,
+ array::CFArray,
+ base::{TCFType, TCFTypeRef},
+ dictionary::CFDictionary,
+ number::CFNumber,
string::{CFString, CFStringRef},
};
+use core_graphics::window::{
+ kCGNullWindowID, kCGWindowListOptionExcludeDesktopElements, kCGWindowListOptionOnScreenOnly,
+ kCGWindowNumber, kCGWindowOwnerName, kCGWindowOwnerPID, CGWindowListCopyWindowInfo,
+};
use futures::{channel::oneshot, Future};
use std::ffi::c_void;
extern "C" {
+ fn LKRelease(object: *const c_void);
fn LKRoomCreate() -> *const c_void;
- fn LKRoomDestroy(room: *const c_void);
fn LKRoomConnect(
room: *const c_void,
url: CFStringRef,
@@ -15,17 +22,14 @@ extern "C" {
callback: extern "C" fn(*mut c_void) -> (),
callback_data: *mut c_void,
);
+ fn LKCreateScreenShareTrackForWindow(windowId: u32) -> *const c_void;
}
-pub struct Room {
- native_room: *const c_void,
-}
+pub struct Room(*const c_void);
impl Room {
pub fn new() -> Self {
- Self {
- native_room: unsafe { LKRoomCreate() },
- }
+ Self(unsafe { LKRoomCreate() })
}
pub fn connect(&self, url: &str, token: &str) -> impl Future<Output = ()> {
@@ -40,7 +44,7 @@ impl Room {
unsafe {
LKRoomConnect(
- self.native_room,
+ self.0,
url.as_concrete_TypeRef(),
token.as_concrete_TypeRef(),
did_connect,
@@ -54,6 +58,60 @@ impl Room {
impl Drop for Room {
fn drop(&mut self) {
- unsafe { LKRoomDestroy(self.native_room) }
+ unsafe { LKRelease(self.0) }
+ }
+}
+
+pub struct LocalVideoTrack(*const c_void);
+
+impl LocalVideoTrack {
+ pub fn screen_share_for_window(window_id: u32) -> Self {
+ Self(unsafe { LKCreateScreenShareTrackForWindow(window_id) })
+ }
+}
+
+impl Drop for LocalVideoTrack {
+ fn drop(&mut self) {
+ unsafe { LKRelease(self.0) }
+ }
+}
+
+#[derive(Debug)]
+pub struct WindowInfo {
+ pub id: u32,
+ pub owner_pid: i32,
+ pub owner_name: Option<String>,
+}
+
+pub fn list_windows() -> Vec<WindowInfo> {
+ unsafe {
+ let dicts = CFArray::<CFDictionary>::wrap_under_get_rule(CGWindowListCopyWindowInfo(
+ kCGWindowListOptionOnScreenOnly | kCGWindowListOptionExcludeDesktopElements,
+ kCGNullWindowID,
+ ));
+
+ dicts
+ .iter()
+ .map(|dict| {
+ let id =
+ CFNumber::wrap_under_get_rule(*dict.get(kCGWindowNumber.as_void_ptr()) as _)
+ .to_i64()
+ .unwrap() as u32;
+
+ let owner_pid =
+ CFNumber::wrap_under_get_rule(*dict.get(kCGWindowOwnerPID.as_void_ptr()) as _)
+ .to_i32()
+ .unwrap();
+
+ let owner_name = dict
+ .find(kCGWindowOwnerName.as_void_ptr())
+ .map(|name| CFString::wrap_under_get_rule(*name as _).to_string());
+ WindowInfo {
+ id,
+ owner_pid,
+ owner_name,
+ }
+ })
+ .collect()
}
}