Try to use the dummy capture handler, still not working

Nathan Sobo created

Change summary

crates/capture/build.rs        |  3 ++
crates/capture/src/bindings.h  |  1 
crates/capture/src/bindings.rs |  4 ++
crates/capture/src/dummy.m     | 16 ++++++++++++--
crates/capture/src/main.rs     | 39 +++++++++++++++++++++++++----------
5 files changed, 48 insertions(+), 15 deletions(-)

Detailed changes

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")

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) }
 }

crates/capture/src/dummy.m 🔗

@@ -1,12 +1,22 @@
 #import <ScreenCaptureKit/ScreenCaptureKit.h>
 
-@interface MyClass : NSObject <SCStreamOutput>
+@interface MyClass : NSObject <SCStreamOutput, SCStreamDelegate>
 @end
 
 @implementation MyClass
+
 - (void)stream:(SCStream *)stream
     didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
-                   ofType:(SCStreamOutputType)type {
+    ofType:(SCStreamOutputType)type {
+    printf("dummy capture handler called");
+}
+
+- (void)stream:(SCStream *)stream didStopWithError:(NSError *)error {
+    printf("dummy did stop with error called");
 }
 
-@end
+int main() {
+    [[MyClass alloc] init];
+}
+
+@end

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) {