Skip to main content

screencapturekit/ffi/
mod.rs

1//! Swift FFI bridge to `ScreenCaptureKit`
2use std::ffi::c_void;
3
4// MARK: - FFI Packed Data Structures
5
6/// Packed `CGRect` for efficient FFI transfer (32 bytes)
7#[repr(C)]
8#[derive(Debug, Clone, Copy, Default)]
9pub struct FFIRect {
10    pub x: f64,
11    pub y: f64,
12    pub width: f64,
13    pub height: f64,
14}
15
16/// Packed display data for batch retrieval (48 bytes)
17#[repr(C)]
18#[derive(Debug, Clone, Copy)]
19pub struct FFIDisplayData {
20    pub display_id: u32,
21    pub width: i32,
22    pub height: i32,
23    pub frame: FFIRect,
24}
25
26/// Packed window data for batch retrieval
27#[repr(C)]
28#[derive(Debug, Clone, Copy)]
29pub struct FFIWindowData {
30    pub window_id: u32,
31    pub window_layer: i32,
32    pub is_on_screen: bool,
33    pub is_active: bool,
34    pub frame: FFIRect,
35    pub title_offset: u32,
36    pub title_length: u32,
37    pub owning_app_index: i32,
38    #[doc(hidden)]
39    pub _padding: i32,
40}
41
42/// Packed application data for batch retrieval
43#[repr(C)]
44#[derive(Debug, Clone, Copy)]
45pub struct FFIApplicationData {
46    pub process_id: i32,
47    #[doc(hidden)]
48    pub _padding: i32,
49    pub bundle_id_offset: u32,
50    pub bundle_id_length: u32,
51    pub app_name_offset: u32,
52    pub app_name_length: u32,
53}
54
55// MARK: - CoreGraphics Initialization
56extern "C" {
57    /// Force CoreGraphics initialization by calling `CGMainDisplayID`
58    /// This prevents `CGS_REQUIRE_INIT` crashes on headless systems
59    pub fn sc_initialize_core_graphics();
60}
61
62// MARK: - SCShareableContent
63extern "C" {
64    /// Synchronous blocking call to get shareable content.
65    ///
66    /// Returns the content pointer on success, or writes an error message
67    /// (NUL-terminated UTF-8) into `error_buffer`.
68    ///
69    /// # Safety
70    ///
71    /// `error_buffer` must point to at least `error_buffer_size` writable
72    /// bytes. The Swift bridge writes at most `error_buffer_size - 1`
73    /// payload bytes plus a NUL terminator (i.e. it respects the size
74    /// argument and never writes past the buffer). `error_buffer_size`
75    /// is `isize` for ABI compatibility with Apple's pattern, but values
76    /// must be > 0; pass `crate::utils::ffi_string::DEFAULT_BUFFER_SIZE`
77    /// (1024) or `SMALL_BUFFER_SIZE` (256) cast to `isize` for typical
78    /// error messages.
79    pub fn sc_shareable_content_get_sync(
80        exclude_desktop_windows: bool,
81        on_screen_windows_only: bool,
82        error_buffer: *mut i8,
83        error_buffer_size: isize,
84    ) -> *const c_void;
85
86    /// Async callback-based shareable content retrieval with options
87    pub fn sc_shareable_content_get_with_options(
88        exclude_desktop_windows: bool,
89        on_screen_windows_only: bool,
90        callback: extern "C" fn(*const c_void, *const i8, *mut c_void),
91        user_data: *mut c_void,
92    );
93
94    pub fn sc_shareable_content_get(
95        callback: extern "C" fn(*const c_void, *const i8, *mut c_void),
96        user_data: *mut c_void,
97    );
98    pub fn sc_shareable_content_get_current_process_displays(
99        callback: extern "C" fn(*const c_void, *const i8, *mut c_void),
100        user_data: *mut c_void,
101    );
102    pub fn sc_shareable_content_get_below_window(
103        exclude_desktop_windows: bool,
104        reference_window: *const c_void,
105        callback: extern "C" fn(*const c_void, *const i8, *mut c_void),
106        user_data: *mut c_void,
107    );
108    pub fn sc_shareable_content_get_above_window(
109        exclude_desktop_windows: bool,
110        reference_window: *const c_void,
111        callback: extern "C" fn(*const c_void, *const i8, *mut c_void),
112        user_data: *mut c_void,
113    );
114    pub fn sc_shareable_content_retain(content: *const c_void) -> *const c_void;
115    pub fn sc_shareable_content_release(content: *const c_void);
116    pub fn sc_shareable_content_get_displays_count(content: *const c_void) -> isize;
117    pub fn sc_shareable_content_get_display_at(
118        content: *const c_void,
119        index: isize,
120    ) -> *const c_void;
121    pub fn sc_shareable_content_get_windows_count(content: *const c_void) -> isize;
122    pub fn sc_shareable_content_get_window_at(
123        content: *const c_void,
124        index: isize,
125    ) -> *const c_void;
126    pub fn sc_shareable_content_get_applications_count(content: *const c_void) -> isize;
127    pub fn sc_shareable_content_get_application_at(
128        content: *const c_void,
129        index: isize,
130    ) -> *const c_void;
131
132    // Batch retrieval functions (optimized FFI)
133    pub fn sc_shareable_content_get_displays_batch(
134        content: *const c_void,
135        buffer: *mut c_void, // Actually *mut FFIDisplayData
136        max_displays: isize,
137    ) -> isize;
138
139    pub fn sc_shareable_content_get_applications_batch(
140        content: *const c_void,
141        buffer: *mut c_void, // Actually *mut FFIApplicationData
142        max_apps: isize,
143        string_buffer: *mut i8,
144        string_buffer_size: isize,
145        string_buffer_used: *mut isize,
146    ) -> isize;
147
148    pub fn sc_shareable_content_get_windows_batch(
149        content: *const c_void,
150        buffer: *mut c_void, // Actually *mut FFIWindowData
151        max_windows: isize,
152        string_buffer: *mut i8,
153        string_buffer_size: isize,
154        string_buffer_used: *mut isize,
155        app_pointers: *mut *const c_void,
156        max_apps: isize,
157        app_count: *mut isize,
158    ) -> isize;
159}
160
161// MARK: - SCDisplay
162extern "C" {
163    pub fn sc_display_retain(display: *const c_void) -> *const c_void;
164    pub fn sc_display_release(display: *const c_void);
165    pub fn sc_display_get_display_id(display: *const c_void) -> u32;
166    pub fn sc_display_get_width(display: *const c_void) -> isize;
167    pub fn sc_display_get_height(display: *const c_void) -> isize;
168    pub fn sc_display_get_frame(
169        display: *const c_void,
170        x: *mut f64,
171        y: *mut f64,
172        width: *mut f64,
173        height: *mut f64,
174    );
175    /// Get display frame (same as `sc_display_get_frame`, kept for API compatibility)
176    pub fn sc_display_get_frame_packed(
177        display: *const c_void,
178        x: *mut f64,
179        y: *mut f64,
180        width: *mut f64,
181        height: *mut f64,
182    );
183}
184
185// MARK: - SCWindow
186extern "C" {
187    pub fn sc_window_retain(window: *const c_void) -> *const c_void;
188    pub fn sc_window_release(window: *const c_void);
189    pub fn sc_window_get_window_id(window: *const c_void) -> u32;
190    pub fn sc_window_get_frame(
191        window: *const c_void,
192        x: *mut f64,
193        y: *mut f64,
194        width: *mut f64,
195        height: *mut f64,
196    );
197    /// Get window frame (same as `sc_window_get_frame`, kept for API compatibility)
198    pub fn sc_window_get_frame_packed(
199        window: *const c_void,
200        x: *mut f64,
201        y: *mut f64,
202        width: *mut f64,
203        height: *mut f64,
204    );
205    pub fn sc_window_get_title(window: *const c_void, buffer: *mut i8, buffer_size: isize) -> bool;
206    /// Get window title as owned string (caller must free with `sc_free_string`)
207    pub fn sc_window_get_title_owned(window: *const c_void) -> *mut i8;
208    pub fn sc_window_get_window_layer(window: *const c_void) -> isize;
209    pub fn sc_window_is_on_screen(window: *const c_void) -> bool;
210    pub fn sc_window_get_owning_application(window: *const c_void) -> *const c_void;
211    pub fn sc_window_is_active(window: *const c_void) -> bool;
212}
213
214// MARK: - SCRunningApplication
215extern "C" {
216    pub fn sc_running_application_retain(app: *const c_void) -> *const c_void;
217    pub fn sc_running_application_release(app: *const c_void);
218    pub fn sc_running_application_get_bundle_identifier(
219        app: *const c_void,
220        buffer: *mut i8,
221        buffer_size: isize,
222    ) -> bool;
223    /// Get bundle identifier as owned string (caller must free with `sc_free_string`)
224    pub fn sc_running_application_get_bundle_identifier_owned(app: *const c_void) -> *mut i8;
225    pub fn sc_running_application_get_application_name(
226        app: *const c_void,
227        buffer: *mut i8,
228        buffer_size: isize,
229    ) -> bool;
230    /// Get application name as owned string (caller must free with `sc_free_string`)
231    pub fn sc_running_application_get_application_name_owned(app: *const c_void) -> *mut i8;
232    pub fn sc_running_application_get_process_id(app: *const c_void) -> i32;
233}
234
235// MARK: - String memory management
236extern "C" {
237    /// Free a string allocated by Swift (strdup)
238    pub fn sc_free_string(str: *mut i8);
239}
240
241// MARK: - SCStreamConfiguration
242extern "C" {
243    pub fn sc_stream_configuration_create() -> *const c_void;
244    pub fn sc_stream_configuration_retain(config: *const c_void) -> *const c_void;
245    pub fn sc_stream_configuration_release(config: *const c_void);
246
247    pub fn sc_stream_configuration_set_width(config: *const c_void, width: isize);
248    pub fn sc_stream_configuration_get_width(config: *const c_void) -> isize;
249
250    pub fn sc_stream_configuration_set_height(config: *const c_void, height: isize);
251    pub fn sc_stream_configuration_get_height(config: *const c_void) -> isize;
252
253    pub fn sc_stream_configuration_set_shows_cursor(config: *const c_void, shows_cursor: bool);
254    pub fn sc_stream_configuration_get_shows_cursor(config: *const c_void) -> bool;
255
256    pub fn sc_stream_configuration_set_scales_to_fit(config: *const c_void, scales_to_fit: bool);
257    pub fn sc_stream_configuration_get_scales_to_fit(config: *const c_void) -> bool;
258
259    pub fn sc_stream_configuration_set_captures_audio(config: *const c_void, captures_audio: bool);
260    pub fn sc_stream_configuration_get_captures_audio(config: *const c_void) -> bool;
261
262    pub fn sc_stream_configuration_set_sample_rate(config: *const c_void, sample_rate: isize);
263    pub fn sc_stream_configuration_get_sample_rate(config: *const c_void) -> isize;
264
265    pub fn sc_stream_configuration_set_channel_count(config: *const c_void, channel_count: isize);
266    pub fn sc_stream_configuration_get_channel_count(config: *const c_void) -> isize;
267
268    pub fn sc_stream_configuration_set_queue_depth(config: *const c_void, queue_depth: isize);
269    pub fn sc_stream_configuration_get_queue_depth(config: *const c_void) -> isize;
270
271    pub fn sc_stream_configuration_set_pixel_format(config: *const c_void, pixel_format: u32);
272    pub fn sc_stream_configuration_get_pixel_format(config: *const c_void) -> u32;
273
274    pub fn sc_stream_configuration_set_minimum_frame_interval(
275        config: *const c_void,
276        value: i64,
277        timescale: i32,
278        flags: u32,
279        epoch: i64,
280    );
281    pub fn sc_stream_configuration_get_minimum_frame_interval(
282        config: *const c_void,
283        value: *mut i64,
284        timescale: *mut i32,
285        flags: *mut u32,
286        epoch: *mut i64,
287    );
288
289    pub fn sc_stream_configuration_set_source_rect(
290        config: *const c_void,
291        x: f64,
292        y: f64,
293        width: f64,
294        height: f64,
295    );
296    pub fn sc_stream_configuration_get_source_rect(
297        config: *const c_void,
298        x: *mut f64,
299        y: *mut f64,
300        width: *mut f64,
301        height: *mut f64,
302    );
303
304    pub fn sc_stream_configuration_set_destination_rect(
305        config: *const c_void,
306        x: f64,
307        y: f64,
308        width: f64,
309        height: f64,
310    );
311    pub fn sc_stream_configuration_get_destination_rect(
312        config: *const c_void,
313        x: *mut f64,
314        y: *mut f64,
315        width: *mut f64,
316        height: *mut f64,
317    );
318
319    pub fn sc_stream_configuration_set_preserves_aspect_ratio(
320        config: *const c_void,
321        preserves_aspect_ratio: bool,
322    );
323    pub fn sc_stream_configuration_get_preserves_aspect_ratio(config: *const c_void) -> bool;
324
325    pub fn sc_stream_configuration_set_ignores_shadows_single_window(
326        config: *const c_void,
327        ignores_shadows: bool,
328    );
329    pub fn sc_stream_configuration_get_ignores_shadows_single_window(config: *const c_void)
330        -> bool;
331
332    pub fn sc_stream_configuration_set_should_be_opaque(
333        config: *const c_void,
334        should_be_opaque: bool,
335    );
336    pub fn sc_stream_configuration_get_should_be_opaque(config: *const c_void) -> bool;
337
338    pub fn sc_stream_configuration_set_includes_child_windows(
339        config: *const c_void,
340        includes_child_windows: bool,
341    );
342    pub fn sc_stream_configuration_get_includes_child_windows(config: *const c_void) -> bool;
343
344    pub fn sc_stream_configuration_set_presenter_overlay_privacy_alert_setting(
345        config: *const c_void,
346        setting: i32,
347    );
348    pub fn sc_stream_configuration_get_presenter_overlay_privacy_alert_setting(
349        config: *const c_void,
350    ) -> i32;
351
352    pub fn sc_stream_configuration_set_background_color(
353        config: *const c_void,
354        r: f32,
355        g: f32,
356        b: f32,
357    );
358    pub fn sc_stream_configuration_set_color_space_name(config: *const c_void, name: *const i8);
359    pub fn sc_stream_configuration_set_color_matrix(config: *const c_void, matrix: *const i8);
360    pub fn sc_stream_configuration_get_color_matrix(
361        config: *const c_void,
362        buffer: *mut i8,
363        buffer_size: usize,
364    ) -> bool;
365
366    // macOS 14.0+ - capture resolution type
367    pub fn sc_stream_configuration_set_capture_resolution_type(config: *const c_void, value: i32);
368    pub fn sc_stream_configuration_get_capture_resolution_type(config: *const c_void) -> i32;
369
370    pub fn sc_stream_configuration_set_ignores_shadow_display_configuration(
371        config: *const c_void,
372        ignores_shadow: bool,
373    );
374    pub fn sc_stream_configuration_get_ignores_shadow_display_configuration(
375        config: *const c_void,
376    ) -> bool;
377
378    pub fn sc_stream_configuration_set_preserve_aspect_ratio(config: *const c_void, preserve: bool);
379    pub fn sc_stream_configuration_get_preserve_aspect_ratio(config: *const c_void) -> bool;
380
381    pub fn sc_stream_configuration_set_captures_shadows_only(
382        config: *const c_void,
383        captures_shadows_only: bool,
384    );
385    pub fn sc_stream_configuration_get_captures_shadows_only(config: *const c_void) -> bool;
386
387    pub fn sc_stream_configuration_set_captures_microphone(
388        config: *const c_void,
389        captures_microphone: bool,
390    );
391    pub fn sc_stream_configuration_get_captures_microphone(config: *const c_void) -> bool;
392
393    pub fn sc_stream_configuration_set_excludes_current_process_audio(
394        config: *const c_void,
395        excludes: bool,
396    );
397    pub fn sc_stream_configuration_get_excludes_current_process_audio(
398        config: *const c_void,
399    ) -> bool;
400
401    pub fn sc_stream_configuration_set_microphone_capture_device_id(
402        config: *const c_void,
403        device_id: *const i8,
404    );
405    pub fn sc_stream_configuration_get_microphone_capture_device_id(
406        config: *const c_void,
407        buffer: *mut i8,
408        buffer_size: isize,
409    ) -> bool;
410
411    pub fn sc_stream_configuration_set_stream_name(config: *const c_void, name: *const i8);
412    pub fn sc_stream_configuration_get_stream_name(
413        config: *const c_void,
414        buffer: *mut i8,
415        buffer_size: isize,
416    ) -> bool;
417
418    pub fn sc_stream_configuration_set_capture_dynamic_range(config: *const c_void, value: i32);
419    pub fn sc_stream_configuration_get_capture_dynamic_range(config: *const c_void) -> i32;
420}
421
422// MARK: - SCContentFilter
423extern "C" {
424    pub fn sc_content_filter_create_with_desktop_independent_window(
425        window: *const c_void,
426    ) -> *const c_void;
427    pub fn sc_content_filter_create_with_display_excluding_windows(
428        display: *const c_void,
429        windows: *const *const c_void,
430        windows_count: isize,
431    ) -> *const c_void;
432    pub fn sc_content_filter_create_with_display_including_windows(
433        display: *const c_void,
434        windows: *const *const c_void,
435        windows_count: isize,
436    ) -> *const c_void;
437    pub fn sc_content_filter_create_with_display_including_applications_excepting_windows(
438        display: *const c_void,
439        apps: *const *const c_void,
440        apps_count: isize,
441        windows: *const *const c_void,
442        windows_count: isize,
443    ) -> *const c_void;
444    pub fn sc_content_filter_create_with_display_excluding_applications_excepting_windows(
445        display: *const c_void,
446        apps: *const *const c_void,
447        apps_count: isize,
448        windows: *const *const c_void,
449        windows_count: isize,
450    ) -> *const c_void;
451    pub fn sc_content_filter_retain(filter: *const c_void) -> *const c_void;
452    pub fn sc_content_filter_release(filter: *const c_void);
453    pub fn sc_content_filter_set_content_rect(
454        filter: *const c_void,
455        x: f64,
456        y: f64,
457        width: f64,
458        height: f64,
459    );
460    pub fn sc_content_filter_get_content_rect(
461        filter: *const c_void,
462        x: *mut f64,
463        y: *mut f64,
464        width: *mut f64,
465        height: *mut f64,
466    );
467    /// Get content filter content rect (same as `sc_content_filter_get_content_rect`)
468    pub fn sc_content_filter_get_content_rect_packed(
469        filter: *const c_void,
470        x: *mut f64,
471        y: *mut f64,
472        width: *mut f64,
473        height: *mut f64,
474    );
475}
476
477// MARK: - SCStream
478extern "C" {
479    pub fn sc_stream_create(
480        filter: *const c_void,
481        config: *const c_void,
482        context: *mut c_void,
483        error_callback: extern "C" fn(*mut c_void, i32, *const i8),
484        sample_callback: extern "C" fn(*mut c_void, *const c_void, i32),
485    ) -> *const c_void;
486    pub fn sc_stream_add_stream_output(stream: *const c_void, output_type: i32) -> bool;
487    pub fn sc_stream_add_stream_output_with_queue(
488        stream: *const c_void,
489        output_type: i32,
490        dispatch_queue: *const c_void,
491    ) -> bool;
492    pub fn sc_stream_remove_stream_output(stream: *const c_void, output_type: i32) -> bool;
493    pub fn sc_stream_start_capture(
494        stream: *const c_void,
495        context: *mut c_void,
496        callback: extern "C" fn(*mut c_void, bool, *const i8),
497    );
498    pub fn sc_stream_stop_capture(
499        stream: *const c_void,
500        context: *mut c_void,
501        callback: extern "C" fn(*mut c_void, bool, *const i8),
502    );
503    pub fn sc_stream_update_configuration(
504        stream: *const c_void,
505        config: *const c_void,
506        context: *mut c_void,
507        callback: extern "C" fn(*mut c_void, bool, *const i8),
508    );
509    pub fn sc_stream_update_content_filter(
510        stream: *const c_void,
511        filter: *const c_void,
512        context: *mut c_void,
513        callback: extern "C" fn(*mut c_void, bool, *const i8),
514    );
515    pub fn sc_stream_add_recording_output(
516        stream: *const c_void,
517        recording_output: *const c_void,
518        callback: extern "C" fn(*mut c_void, bool, *const i8),
519        context: *mut c_void,
520    );
521    pub fn sc_stream_remove_recording_output(
522        stream: *const c_void,
523        recording_output: *const c_void,
524        callback: extern "C" fn(*mut c_void, bool, *const i8),
525        context: *mut c_void,
526    );
527    pub fn sc_stream_retain(stream: *const c_void) -> *const c_void;
528    pub fn sc_stream_release(stream: *const c_void);
529
530    // macOS 13.0+ - synchronizationClock
531    pub fn sc_stream_get_synchronization_clock(stream: *const c_void) -> *const c_void;
532}
533
534// MARK: - Dispatch Queue
535extern "C" {
536    pub fn dispatch_queue_create(label: *const i8, qos: i32) -> *const c_void;
537    pub fn dispatch_queue_release(queue: *const c_void);
538    pub fn dispatch_queue_retain(queue: *const c_void) -> *const c_void;
539}
540
541// MARK: - IOSurface
542extern "C" {
543    pub fn cv_pixel_buffer_get_iosurface(pixel_buffer: *const c_void) -> *const c_void;
544    pub fn cv_pixel_buffer_is_backed_by_iosurface(pixel_buffer: *const c_void) -> bool;
545    pub fn iosurface_get_width(iosurface: *const c_void) -> isize;
546    pub fn iosurface_get_height(iosurface: *const c_void) -> isize;
547    pub fn iosurface_get_bytes_per_row(iosurface: *const c_void) -> isize;
548    pub fn iosurface_get_pixel_format(iosurface: *const c_void) -> u32;
549    pub fn iosurface_get_base_address(iosurface: *const c_void) -> *mut u8;
550    pub fn iosurface_lock(iosurface: *const c_void, options: u32) -> i32;
551    pub fn iosurface_unlock(iosurface: *const c_void, options: u32) -> i32;
552    pub fn iosurface_is_in_use(iosurface: *const c_void) -> bool;
553    pub fn iosurface_release(iosurface: *const c_void);
554
555    // Plane functions (for multi-planar formats like YCbCr 420)
556    pub fn iosurface_get_plane_count(iosurface: *const c_void) -> isize;
557    pub fn iosurface_get_width_of_plane(iosurface: *const c_void, plane: isize) -> isize;
558    pub fn iosurface_get_height_of_plane(iosurface: *const c_void, plane: isize) -> isize;
559    pub fn iosurface_get_bytes_per_row_of_plane(iosurface: *const c_void, plane: isize) -> isize;
560
561    // IOSurface creation (for testing)
562    pub fn io_surface_create(
563        width: usize,
564        height: usize,
565        pixel_format: u32,
566        bytes_per_element: usize,
567        surface_out: *mut *mut c_void,
568    ) -> i32;
569
570    // IOSurface creation with full properties (for multi-planar formats)
571    pub fn io_surface_create_with_properties(
572        width: usize,
573        height: usize,
574        pixel_format: u32,
575        bytes_per_element: usize,
576        bytes_per_row: usize,
577        alloc_size: usize,
578        plane_count: usize,
579        plane_widths: *const usize,
580        plane_heights: *const usize,
581        plane_bytes_per_row: *const usize,
582        plane_bytes_per_element: *const usize,
583        plane_offsets: *const usize,
584        plane_sizes: *const usize,
585        surface_out: *mut *mut c_void,
586    ) -> i32;
587}
588
589// MARK: - SCContentSharingPicker (macOS 14.0+)
590extern "C" {
591    pub fn sc_content_sharing_picker_configuration_create() -> *const c_void;
592    pub fn sc_content_sharing_picker_configuration_set_allowed_picker_modes(
593        config: *const c_void,
594        modes: *const i32,
595        count: usize,
596    );
597    pub fn sc_content_sharing_picker_configuration_set_allows_changing_selected_content(
598        config: *const c_void,
599        allows: bool,
600    );
601    pub fn sc_content_sharing_picker_configuration_get_allows_changing_selected_content(
602        config: *const c_void,
603    ) -> bool;
604    pub fn sc_content_sharing_picker_configuration_set_excluded_bundle_ids(
605        config: *const c_void,
606        bundle_ids: *const *const i8,
607        count: usize,
608    );
609    pub fn sc_content_sharing_picker_configuration_get_excluded_bundle_ids_count(
610        config: *const c_void,
611    ) -> usize;
612    pub fn sc_content_sharing_picker_configuration_get_excluded_bundle_id_at(
613        config: *const c_void,
614        index: usize,
615        buffer: *mut i8,
616        buffer_size: usize,
617    ) -> bool;
618    pub fn sc_content_sharing_picker_configuration_set_excluded_window_ids(
619        config: *const c_void,
620        window_ids: *const u32,
621        count: usize,
622    );
623    pub fn sc_content_sharing_picker_configuration_get_excluded_window_ids_count(
624        config: *const c_void,
625    ) -> usize;
626    pub fn sc_content_sharing_picker_configuration_get_excluded_window_id_at(
627        config: *const c_void,
628        index: usize,
629    ) -> u32;
630    pub fn sc_content_sharing_picker_configuration_retain(config: *const c_void) -> *const c_void;
631    pub fn sc_content_sharing_picker_configuration_release(config: *const c_void);
632
633    // Picker maximum stream count
634    pub fn sc_content_sharing_picker_set_maximum_stream_count(count: usize);
635    pub fn sc_content_sharing_picker_get_maximum_stream_count() -> usize;
636
637    /// Returns a fresh `SCContentSharingPickerConfiguration` initialised with
638    /// the system's `defaultConfiguration` baseline. Caller owns the returned
639    /// configuration and must release it via the standard
640    /// `sc_content_sharing_picker_configuration_release`.
641    pub fn sc_content_sharing_picker_create_default_configuration() -> *const c_void;
642
643    /// Read whether the shared content-sharing picker is currently active.
644    pub fn sc_content_sharing_picker_get_active() -> bool;
645    /// Mark the shared content-sharing picker active or inactive.
646    pub fn sc_content_sharing_picker_set_active(active: bool);
647
648    pub fn sc_content_sharing_picker_show(
649        config: *const c_void,
650        callback: extern "C" fn(i32, *const c_void, *mut c_void),
651        user_data: *mut c_void,
652    );
653    pub fn sc_content_sharing_picker_show_with_result(
654        config: *const c_void,
655        callback: extern "C" fn(i32, *const c_void, *mut c_void),
656        user_data: *mut c_void,
657    );
658    pub fn sc_content_sharing_picker_show_for_stream(
659        config: *const c_void,
660        stream: *const c_void,
661        callback: extern "C" fn(i32, *const c_void, *mut c_void),
662        user_data: *mut c_void,
663    );
664    pub fn sc_content_sharing_picker_show_using_style(
665        config: *const c_void,
666        style: i32,
667        callback: extern "C" fn(i32, *const c_void, *mut c_void),
668        user_data: *mut c_void,
669    );
670    pub fn sc_content_sharing_picker_show_for_stream_using_style(
671        config: *const c_void,
672        stream: *const c_void,
673        style: i32,
674        callback: extern "C" fn(i32, *const c_void, *mut c_void),
675        user_data: *mut c_void,
676    );
677    pub fn sc_picker_result_get_filter(result: *const c_void) -> *const c_void;
678    pub fn sc_picker_result_get_content_rect(
679        result: *const c_void,
680        x: *mut f64,
681        y: *mut f64,
682        width: *mut f64,
683        height: *mut f64,
684    );
685    pub fn sc_picker_result_get_scale(result: *const c_void) -> f64;
686    pub fn sc_picker_result_get_windows_count(result: *const c_void) -> usize;
687    pub fn sc_picker_result_get_window_at(result: *const c_void, index: usize) -> *const c_void;
688    pub fn sc_picker_result_get_displays_count(result: *const c_void) -> usize;
689    pub fn sc_picker_result_get_display_at(result: *const c_void, index: usize) -> *const c_void;
690    pub fn sc_picker_result_get_applications_count(result: *const c_void) -> usize;
691    pub fn sc_picker_result_get_application_at(
692        result: *const c_void,
693        index: usize,
694    ) -> *const c_void;
695    pub fn sc_picker_result_release(result: *const c_void);
696}
697
698// MARK: - SCRecordingOutput (macOS 15.0+)
699extern "C" {
700    pub fn sc_recording_output_configuration_create() -> *const c_void;
701    pub fn sc_recording_output_configuration_set_output_url(config: *const c_void, path: *const i8);
702    pub fn sc_recording_output_configuration_set_video_codec(config: *const c_void, codec: i32);
703    pub fn sc_recording_output_configuration_retain(config: *const c_void) -> *const c_void;
704    pub fn sc_recording_output_configuration_release(config: *const c_void);
705    pub fn sc_recording_output_create(config: *const c_void) -> *const c_void;
706    pub fn sc_recording_output_retain(output: *const c_void) -> *const c_void;
707    pub fn sc_recording_output_release(output: *const c_void);
708}
709
710// MARK: - SCScreenshotManager (macOS 14.0+)
711extern "C" {
712    pub fn sc_screenshot_manager_capture_image(
713        content_filter: *const c_void,
714        config: *const c_void,
715        callback: extern "C" fn(*const c_void, *const i8, *mut c_void),
716        user_data: *mut c_void,
717    );
718    pub fn sc_screenshot_manager_capture_sample_buffer(
719        content_filter: *const c_void,
720        config: *const c_void,
721        callback: extern "C" fn(*const c_void, *const i8, *mut c_void),
722        user_data: *mut c_void,
723    );
724    pub fn sc_screenshot_manager_capture_image_in_rect(
725        x: f64,
726        y: f64,
727        width: f64,
728        height: f64,
729        callback: extern "C" fn(*const c_void, *const i8, *mut c_void),
730        user_data: *mut c_void,
731    );
732    pub fn cgimage_get_width(image: *const c_void) -> usize;
733    pub fn cgimage_get_height(image: *const c_void) -> usize;
734    pub fn cgimage_get_data(
735        image: *const c_void,
736        out_ptr: *mut *const u8,
737        out_length: *mut usize,
738    ) -> bool;
739    pub fn cgimage_free_data(ptr: *mut u8);
740    /// Render the `CGImage`'s RGBA bytes directly into a caller-owned buffer.
741    /// Returns the number of bytes written (= width*height*4) on success, or 0
742    /// on failure. Replaces the legacy `cgimage_get_data` + `cgimage_free_data`
743    /// pair which made an extra Swift-side malloc + memcpy before handing the
744    /// buffer back; this single-call form lets Rust own the allocation and
745    /// removes one full RGBA-sized memcpy from the screenshot decode path.
746    pub fn cgimage_render_rgba_into(
747        image: *const c_void,
748        dest: *mut u8,
749        dest_capacity: usize,
750    ) -> usize;
751    /// Render the `CGImage` directly as **BGRA** (the source pixel layout for
752    /// every `ScreenCaptureKit`-produced `CGImage`). Saves the per-pixel
753    /// channel-swap that `cgimage_render_rgba_into` forces — measured at
754    /// ~20 ms per 4K screenshot. Use when the consumer (Metal, wgpu, ffmpeg)
755    /// accepts BGRA natively.
756    pub fn cgimage_render_bgra_into(
757        image: *const c_void,
758        dest: *mut u8,
759        dest_capacity: usize,
760    ) -> usize;
761    pub fn cgimage_release(image: *const c_void);
762    pub fn cgimage_save_png(image: *const c_void, path: *const i8) -> bool;
763    pub fn cgimage_save_to_file(
764        image: *const c_void,
765        path: *const i8,
766        format: i32,
767        quality: f32,
768    ) -> bool;
769}
770
771// MARK: - SCScreenshotConfiguration (macOS 26.0+)
772extern "C" {
773    pub fn sc_screenshot_configuration_create() -> *const c_void;
774    pub fn sc_screenshot_configuration_set_width(config: *const c_void, width: isize);
775    pub fn sc_screenshot_configuration_set_height(config: *const c_void, height: isize);
776    pub fn sc_screenshot_configuration_set_shows_cursor(config: *const c_void, shows_cursor: bool);
777    pub fn sc_screenshot_configuration_set_source_rect(
778        config: *const c_void,
779        x: f64,
780        y: f64,
781        width: f64,
782        height: f64,
783    );
784    pub fn sc_screenshot_configuration_set_destination_rect(
785        config: *const c_void,
786        x: f64,
787        y: f64,
788        width: f64,
789        height: f64,
790    );
791    pub fn sc_screenshot_configuration_set_ignore_shadows(
792        config: *const c_void,
793        ignore_shadows: bool,
794    );
795    pub fn sc_screenshot_configuration_set_ignore_clipping(
796        config: *const c_void,
797        ignore_clipping: bool,
798    );
799    pub fn sc_screenshot_configuration_set_include_child_windows(
800        config: *const c_void,
801        include_child_windows: bool,
802    );
803    pub fn sc_screenshot_configuration_set_display_intent(
804        config: *const c_void,
805        display_intent: i32,
806    );
807    pub fn sc_screenshot_configuration_set_dynamic_range(config: *const c_void, dynamic_range: i32);
808    pub fn sc_screenshot_configuration_set_file_url(config: *const c_void, path: *const i8);
809    pub fn sc_screenshot_configuration_release(config: *const c_void);
810
811    // Content type support (macOS 26.0+)
812    pub fn sc_screenshot_configuration_set_content_type(
813        config: *const c_void,
814        identifier: *const i8,
815    );
816    pub fn sc_screenshot_configuration_get_content_type(
817        config: *const c_void,
818        buffer: *mut i8,
819        buffer_size: usize,
820    ) -> bool;
821    pub fn sc_screenshot_configuration_get_supported_content_types_count() -> usize;
822    pub fn sc_screenshot_configuration_get_supported_content_type_at(
823        index: usize,
824        buffer: *mut i8,
825        buffer_size: usize,
826    ) -> bool;
827}
828
829// MARK: - SCScreenshotOutput (macOS 26.0+)
830extern "C" {
831    pub fn sc_screenshot_output_get_sdr_image(output: *const c_void) -> *const c_void;
832    pub fn sc_screenshot_output_get_hdr_image(output: *const c_void) -> *const c_void;
833    pub fn sc_screenshot_output_get_file_url(
834        output: *const c_void,
835        buffer: *mut i8,
836        buffer_size: isize,
837    ) -> bool;
838    pub fn sc_screenshot_output_release(output: *const c_void);
839
840    pub fn sc_screenshot_manager_capture_screenshot(
841        content_filter: *const c_void,
842        config: *const c_void,
843        callback: extern "C" fn(*const c_void, *const i8, *mut c_void),
844        user_data: *mut c_void,
845    );
846    pub fn sc_screenshot_manager_capture_screenshot_in_rect(
847        x: f64,
848        y: f64,
849        width: f64,
850        height: f64,
851        config: *const c_void,
852        callback: extern "C" fn(*const c_void, *const i8, *mut c_void),
853        user_data: *mut c_void,
854    );
855}
856
857// MARK: - SCStreamConfiguration additional properties
858extern "C" {
859    // macOS 15.0+ - showMouseClicks
860    pub fn sc_stream_configuration_set_shows_mouse_clicks(config: *const c_void, value: bool);
861    pub fn sc_stream_configuration_get_shows_mouse_clicks(config: *const c_void) -> bool;
862
863    // macOS 14.0+ - ignoreShadowsDisplay
864    pub fn sc_stream_configuration_set_ignores_shadows_display(config: *const c_void, value: bool);
865    pub fn sc_stream_configuration_get_ignores_shadows_display(config: *const c_void) -> bool;
866
867    // macOS 14.0+ - ignoreGlobalClipDisplay
868    pub fn sc_stream_configuration_set_ignore_global_clip_display(
869        config: *const c_void,
870        value: bool,
871    );
872    pub fn sc_stream_configuration_get_ignore_global_clip_display(config: *const c_void) -> bool;
873
874    // macOS 14.0+ - ignoreGlobalClipSingleWindow
875    pub fn sc_stream_configuration_set_ignore_global_clip_single_window(
876        config: *const c_void,
877        value: bool,
878    );
879    pub fn sc_stream_configuration_get_ignore_global_clip_single_window(
880        config: *const c_void,
881    ) -> bool;
882
883    // macOS 15.0+ - preset-based configuration
884    pub fn sc_stream_configuration_create_with_preset(preset: i32) -> *const c_void;
885}
886
887// MARK: - SCContentFilter additional properties
888extern "C" {
889    // macOS 14.0+ - style and pointPixelScale
890    pub fn sc_content_filter_get_style(filter: *const c_void) -> i32;
891    pub fn sc_content_filter_get_point_pixel_scale(filter: *const c_void) -> f32;
892    pub fn sc_content_filter_get_stream_type(filter: *const c_void) -> i32;
893
894    // macOS 14.2+ - includeMenuBar
895    pub fn sc_content_filter_set_include_menu_bar(filter: *const c_void, include: bool);
896    pub fn sc_content_filter_get_include_menu_bar(filter: *const c_void) -> bool;
897
898    // macOS 15.2+ - included content arrays
899    pub fn sc_content_filter_get_included_displays_count(filter: *const c_void) -> isize;
900    pub fn sc_content_filter_get_included_display_at(
901        filter: *const c_void,
902        index: isize,
903    ) -> *const c_void;
904    pub fn sc_content_filter_get_included_windows_count(filter: *const c_void) -> isize;
905    pub fn sc_content_filter_get_included_window_at(
906        filter: *const c_void,
907        index: isize,
908    ) -> *const c_void;
909    pub fn sc_content_filter_get_included_applications_count(filter: *const c_void) -> isize;
910    pub fn sc_content_filter_get_included_application_at(
911        filter: *const c_void,
912        index: isize,
913    ) -> *const c_void;
914}
915
916// MARK: - SCShareableContentInfo (macOS 14.0+)
917extern "C" {
918    pub fn sc_shareable_content_info_for_filter(filter: *const c_void) -> *const c_void;
919    pub fn sc_shareable_content_info_get_style(info: *const c_void) -> i32;
920    pub fn sc_shareable_content_info_get_point_pixel_scale(info: *const c_void) -> f32;
921    pub fn sc_shareable_content_info_get_content_rect(
922        info: *const c_void,
923        x: *mut f64,
924        y: *mut f64,
925        width: *mut f64,
926        height: *mut f64,
927    );
928    /// Get shareable content info rect (same as `sc_shareable_content_info_get_content_rect`)
929    pub fn sc_shareable_content_info_get_content_rect_packed(
930        info: *const c_void,
931        x: *mut f64,
932        y: *mut f64,
933        width: *mut f64,
934        height: *mut f64,
935    );
936    pub fn sc_shareable_content_info_retain(info: *const c_void) -> *const c_void;
937    pub fn sc_shareable_content_info_release(info: *const c_void);
938}
939
940// MARK: - SCRecordingOutput additional (macOS 15.0+)
941extern "C" {
942    pub fn sc_recording_output_configuration_set_output_file_type(
943        config: *const c_void,
944        file_type: i32,
945    );
946    pub fn sc_recording_output_configuration_get_output_file_type(config: *const c_void) -> i32;
947    pub fn sc_recording_output_configuration_get_video_codec(config: *const c_void) -> i32;
948    pub fn sc_recording_output_configuration_get_available_video_codecs_count(
949        config: *const c_void,
950    ) -> isize;
951    pub fn sc_recording_output_configuration_get_available_video_codec_at(
952        config: *const c_void,
953        index: isize,
954    ) -> i32;
955    pub fn sc_recording_output_configuration_get_available_output_file_types_count(
956        config: *const c_void,
957    ) -> isize;
958    pub fn sc_recording_output_configuration_get_available_output_file_type_at(
959        config: *const c_void,
960        index: isize,
961    ) -> i32;
962    pub fn sc_recording_output_create_with_delegate(
963        config: *const c_void,
964        started_callback: Option<extern "C" fn(*mut c_void)>,
965        failed_callback: Option<extern "C" fn(*mut c_void, i32, *const i8)>,
966        finished_callback: Option<extern "C" fn(*mut c_void)>,
967        context: *mut c_void,
968    ) -> *const c_void;
969    pub fn sc_recording_output_get_recorded_duration(
970        output: *const c_void,
971        value: *mut i64,
972        timescale: *mut i32,
973    );
974    pub fn sc_recording_output_get_recorded_file_size(output: *const c_void) -> i64;
975}
976
977// MARK: - Audio Input Devices (AVFoundation)
978extern "C" {
979    /// Get the count of available audio input devices
980    pub fn sc_audio_get_input_device_count() -> isize;
981
982    /// Get audio input device ID at index into buffer
983    pub fn sc_audio_get_input_device_id(index: isize, buffer: *mut i8, buffer_size: isize) -> bool;
984
985    /// Get audio input device name at index into buffer
986    pub fn sc_audio_get_input_device_name(
987        index: isize,
988        buffer: *mut i8,
989        buffer_size: isize,
990    ) -> bool;
991
992    /// Check if the device at index is the default audio input device
993    pub fn sc_audio_is_default_input_device(index: isize) -> bool;
994
995    /// Get the default audio input device ID into buffer
996    pub fn sc_audio_get_default_input_device_id(buffer: *mut i8, buffer_size: isize) -> bool;
997
998    /// Get the default audio input device name into buffer
999    pub fn sc_audio_get_default_input_device_name(buffer: *mut i8, buffer_size: isize) -> bool;
1000}