diff --git a/crates/capture/build.rs b/crates/capture/build.rs index d75b110b9b..6ab5a40e0f 100644 --- a/crates/capture/build.rs +++ b/crates/capture/build.rs @@ -20,8 +20,10 @@ fn main() { let bindings = bindgen::Builder::default() .header("src/bindings.h") .clang_arg(format!("-isysroot{}", sdk_path)) + .clang_arg("-xobjective-c") .allowlist_function("CMTimeMake") .allowlist_type("CMSampleBufferRef") + .allowlist_type("SCStreamOutputType") .allowlist_var("_dispatch_main_q") .allowlist_function("dispatch_async_f") .allowlist_function("dispatch_queue_create") @@ -35,6 +37,7 @@ fn main() { .write_to_file(out_path.join("bindings.rs")) .expect("couldn't write dispatch bindings"); + println!("cargo:rerun-if-changed=src/dummy.m"); 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 index 0df70f8e11..45ac30446b 100644 --- a/crates/capture/src/bindings.h +++ b/crates/capture/src/bindings.h @@ -1,2 +1,3 @@ #import +#import #import diff --git a/crates/capture/src/bindings.rs b/crates/capture/src/bindings.rs index 24de9f5855..e845910603 100644 --- a/crates/capture/src/bindings.rs +++ b/crates/capture/src/bindings.rs @@ -1,5 +1,7 @@ +use objc::*; + 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 } + unsafe { std::mem::transmute(&_dispatch_main_q) } } diff --git a/crates/capture/src/dummy.m b/crates/capture/src/dummy.m index 8edb379692..9e3a343ce5 100644 --- a/crates/capture/src/dummy.m +++ b/crates/capture/src/dummy.m @@ -1,12 +1,22 @@ #import -@interface MyClass : NSObject +@interface MyClass : NSObject @end @implementation MyClass + - (void)stream:(SCStream *)stream didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer - ofType:(SCStreamOutputType)type { + ofType:(SCStreamOutputType)type { + printf("dummy capture handler called"); } -@end \ No newline at end of file +- (void)stream:(SCStream *)stream didStopWithError:(NSError *)error { + printf("dummy did stop with error called"); +} + +int main() { + [[MyClass alloc] init]; +} + +@end diff --git a/crates/capture/src/main.rs b/crates/capture/src/main.rs index b41a623092..70a8ca62b2 100644 --- a/crates/capture/src/main.rs +++ b/crates/capture/src/main.rs @@ -1,6 +1,6 @@ mod bindings; -use std::{slice, str}; +use std::{slice, str, ptr::{self}}; use block::ConcreteBlock; use cocoa::{ @@ -12,7 +12,7 @@ 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; +use crate::bindings::{dispatch_get_main_queue, dispatch_queue_create, NSObject, CMSampleBufferRef}; #[allow(non_upper_case_globals)] const NSUTF8StringEncoding: NSUInteger = 4; @@ -52,18 +52,27 @@ fn main() { let display_id: u32 = msg_send![display, displayID]; println!("display id {:?}", display_id); - let mut decl = ClassDecl::new("CaptureOutput", class!(NSObject)).unwrap(); - decl.add_protocol(Protocol::get("SCStreamOutput").unwrap()); - decl.add_method(sel!(stream:didOutputSampleBuffer:ofType:), sample_output as extern "C" fn(&Object, Sel, id, id, NSInteger)); - let capture_output_class = decl.register(); + // let mut decl = ClassDecl::new("CaptureOutput", class!(NSObject)).unwrap(); + // decl.add_protocol(Protocol::get("SCStreamOutput").unwrap()); + // decl.add_protocol(Protocol::get("SCStreamDelegate").unwrap()); + // decl.add_method(sel!(stream:didOutputSampleBuffer:ofType:), sample_output as extern "C" fn(&Object, Sel, id, id, NSInteger)); + // decl.add_method(sel!(stream:didStopWithError:), did_stop_with_error as extern "C" fn(&Object, Sel, id, id)); + // let capture_output_class = decl.register(); - let output: id = msg_send![capture_output_class, alloc]; + // let output: id = msg_send![capture_output_class, alloc]; + // let output: id = msg_send![output, init]; + + let output: id = msg_send![class!(MyClass), alloc]; let output: id = msg_send![output, init]; + // Do we conform to the protocol? let conforms: bool = msg_send![output, conformsToProtocol: Protocol::get("SCStreamOutput").unwrap()]; dbg!(conforms); assert!(conforms, "expect CaptureOutput instance to conform to SCStreamOutput protocol"); + // Confirm we can send the protocol message to the object + let _: () = msg_send![output, stream:NSObject(ptr::null_mut()) didOutputSampleBuffer:NSObject(ptr::null_mut()) ofType:0]; + 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]; @@ -76,11 +85,15 @@ fn main() { 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 stream: id = msg_send![stream, initWithFilter: filter configuration: config delegate: output]; let error: id = nil; - // let queue = dispatch_queue_create(ptr::null(), ptr::null_mut()); + let queue = dispatch_queue_create(ptr::null(), NSObject(ptr::null_mut())); - let _: () = msg_send![stream, addStreamOutput: output type: 0 sampleHandlerQueue: dispatch_get_main_queue() error: &error]; + let _: () = msg_send![stream, + addStreamOutput: output type: bindings::SCStreamOutputType_SCStreamOutputTypeScreen + sampleHandlerQueue: queue + error: &error + ]; let start_capture_completion = ConcreteBlock::new(move |error: id| { if !error.is_null() { @@ -130,8 +143,12 @@ pub unsafe fn string_from_objc(string: id) -> String { .to_string() } +extern "C" fn did_stop_with_error(this: &Object, _: Sel, stream: id, error: id) { + println!("did_stop_with_error"); +} + extern "C" fn sample_output(this: &Object, _: Sel, stream: id, buffer: id, kind: NSInteger) { - println!("sample_output"); + println!("sample output"); } fn quit(_: &Quit, cx: &mut gpui::MutableAppContext) {