diff --git a/Cargo.lock b/Cargo.lock index f001ab934a..7dff1a8bb8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -754,6 +754,7 @@ dependencies = [ name = "capture" version = "0.1.0" dependencies = [ + "bindgen", "block", "cc", "cocoa", diff --git a/crates/capture/Cargo.toml b/crates/capture/Cargo.toml index 2b483a25ca..aade52f2fb 100644 --- a/crates/capture/Cargo.toml +++ b/crates/capture/Cargo.toml @@ -21,4 +21,5 @@ objc = "0.2" simplelog = "0.9" [build-dependencies] +bindgen = "0.59.2" cc = "1.0" \ No newline at end of file diff --git a/crates/capture/build.rs b/crates/capture/build.rs index f45dc922c6..4f8ada8670 100644 --- a/crates/capture/build.rs +++ b/crates/capture/build.rs @@ -1,9 +1,30 @@ +use std::{env, path::PathBuf}; + fn main() { - println!("cargo:rustc-link-lib=framework=ScreenCaptureKit"); println!("cargo:rustc-link-lib=framework=CoreMedia"); + println!("cargo:rustc-link-lib=framework=ScreenCaptureKit"); + println!("cargo:rustc-link-lib=framework=System"); println!("cargo:rustc-env=MACOSX_DEPLOYMENT_TARGET=12.3"); println!("cargo:rustc-link-arg=-ObjC"); + let bindings = bindgen::Builder::default() + .header("src/bindings.h") + .clang_arg("-isysroot/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.3.sdk") + .allowlist_function("CMTimeMake") + .allowlist_type("CMSampleBufferRef") + .allowlist_var("_dispatch_main_q") + .allowlist_function("dispatch_async_f") + .allowlist_function("dispatch_queue_create") + .parse_callbacks(Box::new(bindgen::CargoCallbacks)) + .layout_tests(false) + .generate() + .expect("unable to generate bindings"); + + let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); + bindings + .write_to_file(out_path.join("bindings.rs")) + .expect("couldn't write dispatch bindings"); + cc::Build::new() .file("src/dummy.m") .flag("-mmacosx-version-min=12.3") diff --git a/crates/capture/src/bindings.h b/crates/capture/src/bindings.h new file mode 100644 index 0000000000..0df70f8e11 --- /dev/null +++ b/crates/capture/src/bindings.h @@ -0,0 +1,2 @@ +#import +#import diff --git a/crates/capture/src/bindings.rs b/crates/capture/src/bindings.rs new file mode 100644 index 0000000000..24de9f5855 --- /dev/null +++ b/crates/capture/src/bindings.rs @@ -0,0 +1,5 @@ +include!(concat!(env!("OUT_DIR"), "/bindings.rs")); + +pub fn dispatch_get_main_queue() -> dispatch_queue_t { + unsafe { &_dispatch_main_q as *const _ as dispatch_queue_t } +} diff --git a/crates/capture/src/main.rs b/crates/capture/src/main.rs index a77ac61342..b41a623092 100644 --- a/crates/capture/src/main.rs +++ b/crates/capture/src/main.rs @@ -1,16 +1,19 @@ -use std::{ffi::CStr, slice, str, ptr}; +mod bindings; + +use std::{slice, str}; use block::ConcreteBlock; use cocoa::{ base::{id, nil}, foundation::{NSArray, NSString, NSUInteger, NSInteger}, }; -use core_graphics::display::CGDirectDisplayID; -use gpui::{actions, elements::*, keymap::Binding, Menu, MenuItem, mac::dispatcher::{dispatch_get_main_queue, dispatch_queue_create}}; +use gpui::{actions, elements::*, keymap::Binding, Menu, MenuItem}; use log::LevelFilter; use objc::{class, msg_send, sel, sel_impl, declare::ClassDecl, runtime::{Protocol, Object, Sel}}; use simplelog::SimpleLogger; +use crate::bindings::dispatch_get_main_queue; + #[allow(non_upper_case_globals)] const NSUTF8StringEncoding: NSUInteger = 4; @@ -57,6 +60,10 @@ fn main() { let output: id = msg_send![capture_output_class, alloc]; let output: id = msg_send![output, init]; + let conforms: bool = msg_send![output, conformsToProtocol: Protocol::get("SCStreamOutput").unwrap()]; + dbg!(conforms); + assert!(conforms, "expect CaptureOutput instance to conform to SCStreamOutput protocol"); + let excluded_windows: id = msg_send![class!(NSArray), array]; let filter: id = msg_send![class!(SCContentFilter), alloc]; let filter: id = msg_send![filter, initWithDisplay: display excludingWindows: excluded_windows]; @@ -65,14 +72,15 @@ fn main() { // Configure the display content width and height. let _: () = msg_send![config, setWidth: 800]; let _: () = msg_send![config, setHeight: 600]; - let _: () = msg_send![config, setMinimumFrameInterval: CMTimeMake(1, 60)]; + let _: () = msg_send![config, setMinimumFrameInterval: bindings::CMTimeMake(1, 60)]; let _: () = msg_send![config, setQueueDepth: 5]; let stream: id = msg_send![class!(SCStream), alloc]; let stream: id = msg_send![stream, initWithFilter: filter configuration: config delegate: nil]; let error: id = nil; - let queue = dispatch_queue_create(ptr::null(), ptr::null_mut()); - let _: () = msg_send![stream, addStreamOutput: output type: 0 sampleHandlerQueue: queue error: &error]; + // let queue = dispatch_queue_create(ptr::null(), ptr::null_mut()); + + let _: () = msg_send![stream, addStreamOutput: output type: 0 sampleHandlerQueue: dispatch_get_main_queue() error: &error]; let start_capture_completion = ConcreteBlock::new(move |error: id| { if !error.is_null() { @@ -126,20 +134,6 @@ extern "C" fn sample_output(this: &Object, _: Sel, stream: id, buffer: id, kind: println!("sample_output"); } - -extern "C" { - fn CMTimeMake(value: u64, timescale: i32) -> CMTime; -} - -#[repr(C)] -struct CMTime { - value: i64, - timescale: i32, - flags: u32, - epoch: i64, -} - - fn quit(_: &Quit, cx: &mut gpui::MutableAppContext) { cx.platform().quit(); }