From 4bcc008cbf4a9e87ddd069867dc7b01636d313c3 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 2 Sep 2022 12:56:38 -0600 Subject: [PATCH] WIP: Start on live_kit crate that uses a C-based bridge --- Cargo.lock | 11 ++- crates/capture/Cargo.toml | 3 +- crates/capture/build.rs | 69 ++------------ crates/capture/src/main.rs | 24 +---- crates/live_kit/Cargo.toml | 15 +++ crates/live_kit/LiveKitBridge/.gitignore | 9 ++ .../live_kit/LiveKitBridge/Package.resolved | 50 ++++++++++ crates/live_kit/LiveKitBridge/Package.swift | 27 ++++++ crates/live_kit/LiveKitBridge/README.md | 3 + .../Sources/LiveKitBridge/LiveKitBridge.swift | 12 +++ crates/live_kit/build.rs | 95 +++++++++++++++++++ crates/live_kit/src/live_kit.rs | 24 +++++ 12 files changed, 254 insertions(+), 88 deletions(-) create mode 100644 crates/live_kit/Cargo.toml create mode 100644 crates/live_kit/LiveKitBridge/.gitignore create mode 100644 crates/live_kit/LiveKitBridge/Package.resolved create mode 100644 crates/live_kit/LiveKitBridge/Package.swift create mode 100644 crates/live_kit/LiveKitBridge/README.md create mode 100644 crates/live_kit/LiveKitBridge/Sources/LiveKitBridge/LiveKitBridge.swift create mode 100644 crates/live_kit/build.rs create mode 100644 crates/live_kit/src/live_kit.rs diff --git a/Cargo.lock b/Cargo.lock index bf60a08367..1e176cda42 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -765,13 +765,12 @@ dependencies = [ "foreign-types", "futures", "gpui", + "live_kit", "log", "media", "objc", "parking_lot 0.11.2", "postage", - "serde", - "serde_json", "simplelog", ] @@ -2918,6 +2917,14 @@ dependencies = [ "rand_chacha 0.3.1", ] +[[package]] +name = "live_kit" +version = "0.1.0" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "lock_api" version = "0.4.7" diff --git a/crates/capture/Cargo.toml b/crates/capture/Cargo.toml index 339198f764..d572c6077c 100644 --- a/crates/capture/Cargo.toml +++ b/crates/capture/Cargo.toml @@ -6,6 +6,7 @@ description = "An example of screen capture" [dependencies] gpui = { path = "../gpui" } +live_kit = { path = "../live_kit" } media = { path = "../media" } anyhow = "1.0.38" @@ -25,5 +26,3 @@ simplelog = "0.9" [build-dependencies] bindgen = "0.59.2" -serde = { version = "1.0", features = ["derive", "rc"] } -serde_json = { version = "1.0", features = ["preserve_order"] } \ No newline at end of file diff --git a/crates/capture/build.rs b/crates/capture/build.rs index 58cf51203a..e2ffda4c53 100644 --- a/crates/capture/build.rs +++ b/crates/capture/build.rs @@ -1,68 +1,15 @@ -use serde::Deserialize; use std::{env, path::PathBuf, process::Command}; -#[derive(Debug, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct SwiftTargetInfo { - pub triple: String, - pub unversioned_triple: String, - pub module_triple: String, - pub swift_runtime_compatibility_version: String, - #[serde(rename = "librariesRequireRPath")] - pub libraries_require_rpath: bool, -} - -#[derive(Debug, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct SwiftPaths { - pub runtime_library_paths: Vec, - pub runtime_library_import_paths: Vec, - pub runtime_resource_path: String, -} - -#[derive(Debug, Deserialize)] -pub struct SwiftTarget { - pub target: SwiftTargetInfo, - pub paths: SwiftPaths, -} - -const MACOS_TARGET_VERSION: &str = "12"; - -pub fn link_swift_libs() { - let mut arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); - if arch == "aarch64" { - arch = "arm64".into(); - } - let target = format!("{}-apple-macosx{}", arch, MACOS_TARGET_VERSION); - - let swift_target_info_str = Command::new("swift") - .args(&["-target", &target, "-print-target-info"]) - .output() - .unwrap() - .stdout; - - let swift_target_info: SwiftTarget = serde_json::from_slice(&swift_target_info_str).unwrap(); - if swift_target_info.target.libraries_require_rpath { - panic!("Libraries require RPath! Change minimum MacOS value to fix.") - } - - swift_target_info - .paths - .runtime_library_paths - .iter() - .for_each(|path| { - println!("cargo:rustc-link-search=native={}", path); - }); -} - fn main() { - link_swift_libs(); - println!("cargo:rerun-if-changed=/Users/as-cii/Library/Developer/Xcode/DerivedData/LiveKitObjC-ftgpxknhsgkrocbhhgjkyyvkgkbj/Build/Products/Debug/libLiveKitObjC.a"); - println!("cargo:rustc-link-search=native=/Users/as-cii/Library/Developer/Xcode/DerivedData/LiveKitObjC-ftgpxknhsgkrocbhhgjkyyvkgkbj/Build/Products/libs"); - println!("cargo:rustc-link-search=framework=/Users/as-cii/Library/Developer/Xcode/DerivedData/LiveKitObjC-ftgpxknhsgkrocbhhgjkyyvkgkbj/Build/Products/frameworks"); - println!("cargo:rustc-link-lib=static=LiveKitObjC"); + println!( + "cargo:rustc-link-search=framework={}", + "crates/live_kit/LiveKitBridge/.build/arm64-apple-macosx/debug" + ); + + // Find frameworks as a sibling of the executable at runtime + println!("cargo:rustc-link-arg=-Wl,-rpath,@executable_path"); + println!("cargo:rustc-link-lib=framework=ScreenCaptureKit"); - println!("cargo:rustc-link-lib=framework=WebRTC"); println!("cargo:rustc-env=MACOSX_DEPLOYMENT_TARGET=12.3"); let sdk_path = String::from_utf8( diff --git a/crates/capture/src/main.rs b/crates/capture/src/main.rs index f952f3ba22..75df9be368 100644 --- a/crates/capture/src/main.rs +++ b/crates/capture/src/main.rs @@ -22,6 +22,7 @@ use gpui::{ platform::current::Surface, Menu, MenuItem, ViewContext, }; +use live_kit::Room; use log::LevelFilter; use media::{ core_media::{ @@ -47,29 +48,6 @@ const NSUTF8StringEncoding: NSUInteger = 4; actions!(capture, [Quit]); -extern "C" { - fn LKRoomCreate() -> *const c_void; - fn LKRoomDestroy(ptr: *const c_void); -} - -struct Room { - native_room: *const c_void, -} - -impl Room { - pub fn new() -> Self { - Self { - native_room: unsafe { LKRoomCreate() }, - } - } -} - -impl Drop for Room { - fn drop(&mut self) { - unsafe { LKRoomDestroy(self.native_room) } - } -} - fn main() { println!("Creating room..."); let room = Room::new(); diff --git a/crates/live_kit/Cargo.toml b/crates/live_kit/Cargo.toml new file mode 100644 index 0000000000..15f7683456 --- /dev/null +++ b/crates/live_kit/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "live_kit" +version = "0.1.0" +edition = "2021" +description = "Bindings to LiveKit Swift client SDK" + +[lib] +path = "src/live_kit.rs" +doctest = false + +[dependencies] + +[build-dependencies] +serde = { version = "1.0", features = ["derive", "rc"] } +serde_json = { version = "1.0", features = ["preserve_order"] } diff --git a/crates/live_kit/LiveKitBridge/.gitignore b/crates/live_kit/LiveKitBridge/.gitignore new file mode 100644 index 0000000000..3b29812086 --- /dev/null +++ b/crates/live_kit/LiveKitBridge/.gitignore @@ -0,0 +1,9 @@ +.DS_Store +/.build +/Packages +/*.xcodeproj +xcuserdata/ +DerivedData/ +.swiftpm/config/registries.json +.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata +.netrc diff --git a/crates/live_kit/LiveKitBridge/Package.resolved b/crates/live_kit/LiveKitBridge/Package.resolved new file mode 100644 index 0000000000..df0b5d6243 --- /dev/null +++ b/crates/live_kit/LiveKitBridge/Package.resolved @@ -0,0 +1,50 @@ +{ + "pins" : [ + { + "identity" : "client-sdk-swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/livekit/client-sdk-swift.git", + "state" : { + "revision" : "7e7decf3a09de4a169dfc0445a14d9fd2d8db58d", + "version" : "1.0.4" + } + }, + { + "identity" : "promises", + "kind" : "remoteSourceControl", + "location" : "https://github.com/google/promises.git", + "state" : { + "revision" : "3e4e743631e86c8c70dbc6efdc7beaa6e90fd3bb", + "version" : "2.1.1" + } + }, + { + "identity" : "specs", + "kind" : "remoteSourceControl", + "location" : "https://github.com/webrtc-sdk/Specs.git", + "state" : { + "revision" : "5225f2de4b6d0098803b3a0e55b255a41f293dad", + "version" : "104.5112.2" + } + }, + { + "identity" : "swift-log", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-log.git", + "state" : { + "revision" : "6fe203dc33195667ce1759bf0182975e4653ba1c", + "version" : "1.4.4" + } + }, + { + "identity" : "swift-protobuf", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-protobuf.git", + "state" : { + "revision" : "b8230909dedc640294d7324d37f4c91ad3dcf177", + "version" : "1.20.1" + } + } + ], + "version" : 2 +} diff --git a/crates/live_kit/LiveKitBridge/Package.swift b/crates/live_kit/LiveKitBridge/Package.swift new file mode 100644 index 0000000000..9e7039998d --- /dev/null +++ b/crates/live_kit/LiveKitBridge/Package.swift @@ -0,0 +1,27 @@ +// swift-tools-version: 5.6 + +import PackageDescription + +let package = Package( + name: "LiveKitBridge", + platforms: [ + .macOS(.v10_15) + ], + products: [ + // Products define the executables and libraries a package produces, and make them visible to other packages. + .library( + name: "LiveKitBridge", + type: .static, + targets: ["LiveKitBridge"]), + ], + dependencies: [ + .package(url: "https://github.com/livekit/client-sdk-swift.git", from: "1.0.0"), + ], + targets: [ + // Targets are the basic building blocks of a package. A target can define a module or a test suite. + // Targets can depend on other targets in this package, and on products in packages this package depends on. + .target( + name: "LiveKitBridge", + dependencies: [.product(name: "LiveKit", package: "client-sdk-swift")]), + ] +) diff --git a/crates/live_kit/LiveKitBridge/README.md b/crates/live_kit/LiveKitBridge/README.md new file mode 100644 index 0000000000..b982c67286 --- /dev/null +++ b/crates/live_kit/LiveKitBridge/README.md @@ -0,0 +1,3 @@ +# LiveKitBridge + +A description of this package. diff --git a/crates/live_kit/LiveKitBridge/Sources/LiveKitBridge/LiveKitBridge.swift b/crates/live_kit/LiveKitBridge/Sources/LiveKitBridge/LiveKitBridge.swift new file mode 100644 index 0000000000..11df49e6c6 --- /dev/null +++ b/crates/live_kit/LiveKitBridge/Sources/LiveKitBridge/LiveKitBridge.swift @@ -0,0 +1,12 @@ +import Foundation +import LiveKit + +@_cdecl("LKRoomCreate") +public func LKRoomCreate() -> UnsafeMutableRawPointer { + Unmanaged.passRetained(Room()).toOpaque() +} + +@_cdecl("LKRoomDestroy") +public func LKRoomDestroy(ptr: UnsafeRawPointer) { + let _ = Unmanaged.fromOpaque(ptr).takeRetainedValue(); +} diff --git a/crates/live_kit/build.rs b/crates/live_kit/build.rs new file mode 100644 index 0000000000..dab126d12c --- /dev/null +++ b/crates/live_kit/build.rs @@ -0,0 +1,95 @@ +use serde::Deserialize; +use std::{env, path::PathBuf, process::Command}; + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct SwiftTargetInfo { + pub triple: String, + pub unversioned_triple: String, + pub module_triple: String, + pub swift_runtime_compatibility_version: String, + #[serde(rename = "librariesRequireRPath")] + pub libraries_require_rpath: bool, +} + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct SwiftPaths { + pub runtime_library_paths: Vec, + pub runtime_library_import_paths: Vec, + pub runtime_resource_path: String, +} + +#[derive(Debug, Deserialize)] +pub struct SwiftTarget { + pub target: SwiftTargetInfo, + pub paths: SwiftPaths, +} + +const MACOS_TARGET_VERSION: &str = "12"; + +fn main() { + build_bridge(); + link_swift_stdlib(); +} + +fn build_bridge() { + let profile = env::var("PROFILE").unwrap(); + let package_name = "LiveKitBridge"; + let package_root = env::current_dir().unwrap().join(package_name); + if !Command::new("swift") + .args(&["build", "-c", &profile]) + .current_dir(&package_root) + .status() + .unwrap() + .success() + { + panic!( + "Failed to compile swift package in {}", + package_root.display() + ); + } + + let swift_target_info = get_swift_target(); + let swift_out_dir_path = format!( + "{}/.build/{}/{}", + package_root.display(), + swift_target_info.target.unversioned_triple, + profile + ); + + println!("cargo:rustc-link-search=native={}", swift_out_dir_path); + println!( + "cargo:rustc-link-search=framework={}", + "/Users/nathan/src/zed/crates/live_kit/frameworks" + ); + println!("cargo:rustc-link-lib=static={}", package_name); + println!("cargo:rustc-link-lib=framework=WebRTC"); +} + +fn link_swift_stdlib() { + let target = get_swift_target(); + if target.target.libraries_require_rpath { + panic!("Libraries require RPath! Change minimum MacOS value to fix.") + } + + target.paths.runtime_library_paths.iter().for_each(|path| { + println!("cargo:rustc-link-search=native={}", path); + }); +} + +fn get_swift_target() -> SwiftTarget { + let mut arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); + if arch == "aarch64" { + arch = "arm64".into(); + } + let target = format!("{}-apple-macosx{}", arch, MACOS_TARGET_VERSION); + + let swift_target_info_str = Command::new("swift") + .args(&["-target", &target, "-print-target-info"]) + .output() + .unwrap() + .stdout; + + serde_json::from_slice(&swift_target_info_str).unwrap() +} diff --git a/crates/live_kit/src/live_kit.rs b/crates/live_kit/src/live_kit.rs new file mode 100644 index 0000000000..3dcaaa74ed --- /dev/null +++ b/crates/live_kit/src/live_kit.rs @@ -0,0 +1,24 @@ +use std::ffi::c_void; + +extern "C" { + fn LKRoomCreate() -> *const c_void; + fn LKRoomDestroy(ptr: *const c_void); +} + +pub struct Room { + native_room: *const c_void, +} + +impl Room { + pub fn new() -> Self { + Self { + native_room: unsafe { LKRoomCreate() }, + } + } +} + +impl Drop for Room { + fn drop(&mut self) { + unsafe { LKRoomDestroy(self.native_room) } + } +}