1use crate::{api, arc, cg, cm, define_cls, define_obj_type, dispatch, ns, objc, sc};
2
3#[cfg(any(target_os = "macos", target_abi = "macabi"))]
4use crate::{cf, cv};
5
6#[cfg(feature = "blocks")]
7use crate::blocks;
8
9#[doc(alias = "SCFrameStatus")]
11#[derive(Debug, PartialEq, Eq, Copy, Clone)]
12#[repr(isize)]
13pub enum FrameStatus {
14 Complete,
15 Idle,
16 Blank,
17 Suspended,
18 Started,
19 Stopped,
20}
21
22define_obj_type!(
23 #[doc(alias = "SCStreamFrameInfo")]
25 pub FrameInfo(ns::String)
26);
27
28impl FrameInfo {
29 #[doc(alias = "SCStreamFrameInfoStatus")]
31 #[inline]
32 #[api::available(
33 macos = 12.3,
34 maccatalyst = 18.2,
35 ios = 27.0,
36 visionos = 27.0,
37 tvos = 27.0
38 )]
39 pub fn status() -> &'static Self {
40 unsafe { SCStreamFrameInfoStatus }
41 }
42
43 #[doc(alias = "SCStreamFrameInfoDisplayTime")]
46 #[inline]
47 #[api::available(
48 macos = 12.3,
49 maccatalyst = 18.2,
50 ios = 27.0,
51 visionos = 27.0,
52 tvos = 27.0
53 )]
54 pub fn display_time() -> &'static Self {
55 unsafe { SCStreamFrameInfoDisplayTime }
56 }
57
58 #[doc(alias = "SCStreamFrameInfoScaleFactor")]
62 #[inline]
63 #[api::available(
64 macos = 12.3,
65 maccatalyst = 18.2,
66 ios = 27.0,
67 visionos = 27.0,
68 tvos = 27.0
69 )]
70 pub fn scale_factor() -> &'static Self {
71 unsafe { SCStreamFrameInfoScaleFactor }
72 }
73
74 #[doc(alias = "SCStreamFrameInfoContentScale")]
78 #[inline]
79 #[api::available(
80 macos = 12.3,
81 maccatalyst = 18.2,
82 ios = 27.0,
83 visionos = 27.0,
84 tvos = 27.0
85 )]
86 pub fn content_scale() -> &'static Self {
87 unsafe { SCStreamFrameInfoContentScale }
88 }
89
90 #[doc(alias = "SCStreamFrameInfoContentRect")]
93 #[inline]
94 #[api::available(
95 macos = 12.3,
96 maccatalyst = 18.2,
97 ios = 27.0,
98 visionos = 27.0,
99 tvos = 27.0
100 )]
101 pub fn content_rect() -> &'static Self {
102 unsafe { SCStreamFrameInfoContentRect }
103 }
104
105 #[doc(alias = "SCStreamFrameInfoDirtyRects")]
109 #[inline]
110 #[api::available(macos = 12.3, maccatalyst = 18.2)]
111 pub fn dirty_rects() -> &'static Self {
112 unsafe { SCStreamFrameInfoDirtyRects }
113 }
114
115 #[doc(alias = "SCStreamFrameInfoScreenRect")]
118 #[inline]
119 #[api::available(
120 macos = 13.1,
121 maccatalyst = 18.2,
122 ios = 27.0,
123 visionos = 27.0,
124 tvos = 27.0
125 )]
126 pub fn screen_rect() -> &'static Self {
127 unsafe { SCStreamFrameInfoScreenRect }
128 }
129
130 #[doc(alias = "SCStreamFrameInfoBoundingRect")]
134 #[inline]
135 #[api::available(macos = 14.0, maccatalyst = 18.2)]
136 pub fn bounding_rect() -> &'static Self {
137 unsafe { SCStreamFrameInfoBoundingRect }
138 }
139
140 #[doc(alias = "SCStreamFrameInfoPresenterOverlayContentRect")]
146 #[inline]
147 #[api::available(macos = 14.2, maccatalyst = 18.2)]
148 pub fn presenter_overlay_content_rect() -> &'static Self {
149 unsafe { SCStreamFrameInfoPresenterOverlayContentRect }
150 }
151
152 #[doc(alias = "SCStreamFrameInfoVideoOrientation")]
154 #[inline]
155 #[api::available(macos = 27.0, maccatalyst = 27.0, ios = 27.0, visionos = 27.0)]
156 pub fn video_orientation() -> &'static Self {
157 unsafe { SCStreamFrameInfoVideoOrientation }
158 }
159}
160
161#[doc(alias = "SCStreamOutputType")]
162#[derive(Debug, PartialEq, Eq, Copy, Clone)]
163#[repr(isize)]
164pub enum OutputType {
165 #[doc(alias = "SCStreamOutputTypeScreen")]
167 Screen,
168 #[doc(alias = "SCStreamOutputTypeAudio")]
170 Audio,
171 #[doc(alias = "SCStreamOutputTypeMicrophone")]
173 Mic,
174}
175
176#[doc(alias = "SCPresenterOverlayAlertSetting")]
179#[derive(Debug, Eq, PartialEq, Copy, Clone)]
180#[repr(isize)]
181pub enum PresenterOverlayAlertSetting {
182 System,
184
185 Never,
187
188 Always,
190}
191
192#[doc(alias = "SCCaptureResolutionType")]
193#[derive(Debug, Copy, Clone, Eq, PartialEq)]
194#[repr(isize)]
195pub enum CaptureResolution {
196 Automatic,
198 Best,
200 Nominal,
202}
203
204define_obj_type!(
205 #[doc(alias = "SCStreamConfiguration")]
206 pub Cfg(ns::Id),
207 SC_STREAM_CONFIGURATION
208);
209
210#[doc(alias = "SCStreamConfigurationPreset")]
212#[derive(Debug, Copy, Clone, Eq, PartialEq)]
213#[repr(isize)]
214pub enum CfgPreset {
215 #[doc(alias = "SCStreamConfigurationPresetCaptureHDRStreamLocalDisplay")]
217 CaptureHdrStreamLocalDisplay,
218 #[doc(alias = "SCStreamConfigurationPresetCaptureHDRStreamCanonicalDisplay")]
220 CaptureHdrStreamCanoncalDisplay,
221 #[doc(alias = "SCStreamConfigurationPresetCaptureHDRScreenshotLocalDisplay")]
223 CaptureHdrScreenshotLocalDisplay,
224 #[doc(alias = "SCStreamConfigurationPresetCaptureHDRScreenshotCanonicalDisplay")]
226 CaptureHdrScreenshotCanoncalDisplay,
227 #[doc(alias = "SCStreamConfigurationPresetCaptureHDRRecordingPreservedSDRHDR10")]
229 CaptureHdrRecordingPreservedSdrHdr10,
230}
231
232impl Cfg {
233 #[objc::msg_send(width)]
252 #[api::available(macos = 13.0, maccatalyst = 18.2, ios = 27.0, tvos = 27.0)]
253 pub fn width(&self) -> usize;
254
255 #[objc::msg_send(setWidth:)]
257 #[api::available(macos = 13.0, maccatalyst = 18.2, ios = 27.0, tvos = 27.0)]
258 pub fn set_width(&mut self, val: usize);
259
260 #[objc::msg_send(height)]
262 #[api::available(macos = 13.0, maccatalyst = 18.2, ios = 27.0, tvos = 27.0)]
263 pub fn height(&self) -> usize;
264
265 #[objc::msg_send(setHeight:)]
267 #[api::available(macos = 13.0, maccatalyst = 18.2, ios = 27.0, tvos = 27.0)]
268 pub fn set_height(&mut self, val: usize);
269
270 #[objc::msg_send(minimumFrameInterval)]
271 #[api::available(macos = 12.3, maccatalyst = 18.2)]
272 pub fn minimum_frame_interval(&self) -> cm::Time;
273
274 #[objc::msg_send(setMinimumFrameInterval:)]
275 #[api::available(macos = 12.3, maccatalyst = 18.2)]
276 pub fn set_minimum_frame_interval(&mut self, val: cm::Time);
277
278 #[objc::msg_send(pixelFormat)]
286 #[api::available(macos = 12.3, maccatalyst = 18.2)]
287 pub fn pixel_format(&self) -> cv::PixelFormat;
288
289 #[objc::msg_send(setPixelFormat:)]
290 #[api::available(macos = 12.3, maccatalyst = 18.2)]
291 pub fn set_pixel_format(&mut self, val: cv::PixelFormat);
292
293 #[objc::msg_send(scalesToFit)]
294 #[api::available(macos = 12.3, maccatalyst = 18.2)]
295 pub fn scales_to_fit(&self) -> bool;
296
297 #[objc::msg_send(setScalesToFit:)]
298 #[api::available(macos = 12.3, maccatalyst = 18.2)]
299 pub fn set_scales_to_fit(&mut self, val: bool);
300
301 #[objc::msg_send(preservesAspectRatio)]
302 #[api::available(macos = 14.0, maccatalyst = 18.2)]
303 pub fn preserves_aspect_ratio(&self) -> bool;
304
305 #[objc::msg_send(setPreservesAspectRatio:)]
306 #[api::available(macos = 14.0, maccatalyst = 18.2)]
307 pub fn set_preserves_aspect_ratio(&self, val: bool) -> bool;
308
309 #[objc::msg_send(streamName)]
310 #[api::available(macos = 14.0, maccatalyst = 18.2)]
311 pub fn stream_name(&self) -> Option<arc::R<ns::String>>;
312
313 #[objc::msg_send(setStreamName:)]
314 #[api::available(macos = 14.0, maccatalyst = 18.2)]
315 pub fn set_stream_name(&mut self, val: Option<&ns::String>);
316
317 #[objc::msg_send(showsCursor)]
318 #[api::available(macos = 12.3, maccatalyst = 18.2)]
319 pub fn shows_cursor(&self) -> bool;
320
321 #[objc::msg_send(setShowsCursor:)]
322 #[api::available(macos = 12.3, maccatalyst = 18.2)]
323 pub fn set_shows_cursor(&mut self, val: bool);
324
325 #[objc::msg_send(showMouseClicks)]
329 #[api::available(macos = 15.0, maccatalyst = 18.2)]
330 pub fn show_mouse_clicks(&self) -> bool;
331
332 #[objc::msg_send(setShowMouseClicks:)]
336 #[api::available(macos = 15.0, maccatalyst = 18.2)]
337 pub fn set_show_mouse_clicks(&mut self, val: bool);
338
339 #[objc::msg_send(backgroundColor)]
340 #[api::available(macos = 12.3, maccatalyst = 18.2)]
341 pub fn background_color(&self) -> &cg::Color;
342
343 #[objc::msg_send(setBackgroundColor:)]
344 #[api::available(macos = 12.3, maccatalyst = 18.2)]
345 pub fn set_background_color(&mut self, val: &cg::Color);
346
347 #[objc::msg_send(sourceRect)]
348 #[api::available(macos = 12.3, maccatalyst = 18.2)]
349 pub fn src_rect(&self) -> cg::Rect;
350
351 #[objc::msg_send(setSourceRect:)]
352 #[api::available(macos = 12.3, maccatalyst = 18.2)]
353 pub fn set_src_rect(&mut self, val: cg::Rect);
354
355 #[objc::msg_send(destinationRect)]
356 #[api::available(macos = 12.3, maccatalyst = 18.2)]
357 pub fn dst_rect(&self) -> cg::Rect;
358
359 #[objc::msg_send(setDestinationRect:)]
360 #[api::available(macos = 12.3, maccatalyst = 18.2)]
361 pub fn set_dst_rect(&self, val: cg::Rect);
362
363 #[objc::msg_send(queueDepth)]
364 #[api::available(macos = 12.3, maccatalyst = 18.2)]
365 pub fn queue_depth(&self) -> isize;
366
367 #[objc::msg_send(setQueueDepth:)]
368 #[api::available(macos = 12.3, maccatalyst = 18.2)]
369 pub fn set_queue_depth(&mut self, val: isize);
370
371 #[objc::msg_send(colorMatrix)]
376 #[api::available(macos = 12.3, maccatalyst = 18.2)]
377 pub fn color_matrix(&self) -> &cf::String;
378
379 #[objc::msg_send(setColorMatrix:)]
380 #[api::available(macos = 12.3, maccatalyst = 18.2)]
381 pub fn set_color_matrix(&self, val: &cf::String);
382
383 #[objc::msg_send(colorSpaceName)]
387 #[api::available(macos = 12.3, maccatalyst = 18.2)]
388 pub fn color_space_name(&self) -> &cf::String;
389
390 #[objc::msg_send(setColorSpaceName:)]
391 #[api::available(macos = 12.3, maccatalyst = 18.2)]
392 pub fn set_color_space_name(&mut self, val: &cf::String);
393
394 #[objc::msg_send(capturesAudio)]
396 #[api::available(
397 macos = 13.0,
398 maccatalyst = 18.2,
399 ios = 27.0,
400 visionos = 27.0,
401 tvos = 27.0
402 )]
403 pub fn captures_audio(&self) -> bool;
404
405 #[objc::msg_send(setCapturesAudio:)]
406 #[api::available(
407 macos = 13.0,
408 maccatalyst = 18.2,
409 ios = 27.0,
410 visionos = 27.0,
411 tvos = 27.0
412 )]
413 pub fn set_captures_audio(&mut self, val: bool);
414
415 #[objc::msg_send(sampleRate)]
417 #[api::available(
418 macos = 13.0,
419 maccatalyst = 18.2,
420 ios = 27.0,
421 visionos = 27.0,
422 tvos = 27.0
423 )]
424 pub fn sample_rate(&self) -> i64;
425
426 #[objc::msg_send(setSampleRate:)]
427 #[api::available(
428 macos = 13.0,
429 maccatalyst = 18.2,
430 ios = 27.0,
431 visionos = 27.0,
432 tvos = 27.0
433 )]
434 pub fn set_sample_rate(&mut self, val: i64);
435
436 #[objc::msg_send(channelCount)]
438 #[api::available(
439 macos = 13.0,
440 maccatalyst = 18.2,
441 ios = 27.0,
442 visionos = 27.0,
443 tvos = 27.0
444 )]
445 pub fn channel_count(&self) -> i64;
446
447 #[objc::msg_send(setChannelCount:)]
448 #[api::available(
449 macos = 13.0,
450 maccatalyst = 18.2,
451 ios = 27.0,
452 visionos = 27.0,
453 tvos = 27.0
454 )]
455 pub fn set_channel_count(&mut self, val: i64);
456
457 #[objc::msg_send(excludesCurrentProcessAudio)]
459 #[api::available(
460 macos = 13.0,
461 maccatalyst = 18.2,
462 ios = 27.0,
463 visionos = 27.0,
464 tvos = 27.0
465 )]
466 pub fn excludes_current_process_audio(&self) -> bool;
467
468 #[objc::msg_send(setExcludesCurrentProcessAudio:)]
469 #[api::available(
470 macos = 13.0,
471 maccatalyst = 18.2,
472 ios = 27.0,
473 visionos = 27.0,
474 tvos = 27.0
475 )]
476 pub fn set_excludes_current_process_audio(&mut self, val: bool);
477
478 #[objc::msg_send(ignoreShadowsDisplay)]
480 #[api::available(macos = 14.0, maccatalyst = 18.2)]
481 pub fn ignore_shadows_display(&self) -> bool;
482
483 #[objc::msg_send(setIgnoreShadowsDisplay:)]
484 #[api::available(macos = 14.0, maccatalyst = 18.2)]
485 pub fn set_ignore_shadows_display(&mut self, val: bool);
486
487 #[objc::msg_send(ignoreShadowsSingleWindow)]
489 #[api::available(macos = 14.0, maccatalyst = 18.2)]
490 pub fn ignore_shadows_single_window(&self) -> bool;
491
492 #[objc::msg_send(setIgnoreShadowsSingleWindow:)]
493 #[api::available(macos = 14.0, maccatalyst = 18.2)]
494 pub fn set_ignore_shadows_single_window(&mut self, val: bool);
495
496 #[objc::msg_send(captureResolution)]
497 #[api::available(macos = 14.0, maccatalyst = 18.2)]
498 pub fn capture_resolution(&self) -> sc::CaptureResolution;
499
500 #[objc::msg_send(setCaptureResolution:)]
501 #[api::available(macos = 14.0, maccatalyst = 18.2)]
502 pub fn set_capture_resolution(&mut self, val: sc::CaptureResolution);
503
504 #[objc::msg_send(capturesShadowsOnly)]
505 #[api::available(macos = 14.0, maccatalyst = 18.2)]
506 pub fn captures_shadows_only(&self) -> bool;
507
508 #[objc::msg_send(setCapturesShadowsOnly:)]
509 #[api::available(macos = 14.0, maccatalyst = 18.2)]
510 pub fn set_captures_shadows_only(&mut self, val: bool);
511
512 #[objc::msg_send(shouldBeOpaque)]
515 #[api::available(macos = 14.0, maccatalyst = 18.2)]
516 pub fn should_be_opaque(&self) -> bool;
517
518 #[objc::msg_send(setShouldBeOpaque:)]
519 #[api::available(macos = 14.0, maccatalyst = 18.2)]
520 pub fn set_should_be_opaque(&mut self, val: bool);
521
522 #[objc::msg_send(ignoreGlobalClipDisplay)]
523 #[api::available(macos = 14.0, maccatalyst = 18.2)]
524 pub fn ignore_global_clip_display(&self) -> bool;
525
526 #[objc::msg_send(setIgnoreGlobalClipDisplay:)]
527 #[api::available(macos = 14.0, maccatalyst = 18.2)]
528 pub fn set_ignore_global_clip_display(&mut self, val: bool);
529
530 #[objc::msg_send(ignoreGlobalClipSingleWindow)]
532 #[api::available(macos = 14.0, maccatalyst = 18.2)]
533 pub fn ignore_global_clip_single_window(&self) -> bool;
534
535 #[objc::msg_send(setIgnoreGlobalClipSingleWindow:)]
536 #[api::available(macos = 14.0, maccatalyst = 18.2)]
537 pub fn set_ignore_global_clip_single_window(&mut self, val: bool);
538
539 #[objc::msg_send(presenterOverlayPrivacyAlertSetting)]
542 #[api::available(macos = 14.0, maccatalyst = 18.2)]
543 pub fn presenter_overlay_privacy_alert_setting(&self) -> PresenterOverlayAlertSetting;
544
545 #[objc::msg_send(setPresenterOverlayPrivacyAlertSetting:)]
546 #[api::available(macos = 14.0, maccatalyst = 18.2)]
547 pub fn set_presenter_overlay_privacy_alert_setting(
548 &mut self,
549 val: PresenterOverlayAlertSetting,
550 );
551
552 #[objc::msg_send(includeChildWindows)]
555 #[api::available(macos = 14.2, maccatalyst = 18.2)]
556 pub fn include_child_windows(&self) -> bool;
557
558 #[objc::msg_send(setIncludeChildWindows:)]
559 #[api::available(macos = 14.2, maccatalyst = 18.2)]
560 pub fn set_include_child_windows(&mut self, val: bool);
561
562 #[objc::msg_send(captureMicrophone)]
563 #[api::available(macos = 15.0, maccatalyst = 18.2)]
564 pub fn capture_mic(&self) -> bool;
565
566 #[objc::msg_send(setCaptureMicrophone:)]
567 #[api::available(macos = 15.0, maccatalyst = 18.2)]
568 pub fn set_capture_mic(&mut self, val: bool);
569
570 #[objc::msg_send(microphoneCaptureDeviceID)]
571 #[api::available(macos = 15.0)]
572 pub fn mic_capture_device_id(&self) -> Option<arc::R<ns::String>>;
573
574 #[objc::msg_send(setMicrophoneCaptureDeviceID:)]
575 #[api::available(macos = 15.0)]
576 pub fn set_mic_capture_device_id(&mut self, val: Option<&ns::String>);
577
578 #[objc::msg_send(captureDynamicRange)]
580 #[api::available(macos = 15.0, maccatalyst = 18.2, ios = 27.0)]
581 pub fn capture_dynamic_range(&self) -> CaptureDynamicRange;
582
583 #[objc::msg_send(setCaptureDynamicRange:)]
585 #[api::available(macos = 15.0, maccatalyst = 18.2, ios = 27.0)]
586 pub fn set_capture_dynamic_range(&mut self, val: CaptureDynamicRange);
587
588 #[objc::msg_send(streamConfigurationWithPreset:)]
590 #[api::available(macos = 15.0, maccatalyst = 18.2, ios = 27.0)]
591 pub fn with_preset(preset: CfgPreset) -> arc::R<Self>;
592}
593
594unsafe extern "C" {
595 static SC_STREAM_CONFIGURATION: &'static objc::Class<Cfg>;
596 static SC_CONTENT_FILTER: &'static objc::Class<ContentFilter>;
597 static SC_STREAM: &'static objc::Class<Stream>;
598}
599
600#[api::weak]
601unsafe extern "C" {
602 #[api::available(
603 macos = 12.3,
604 maccatalyst = 18.2,
605 ios = 27.0,
606 visionos = 27.0,
607 tvos = 27.0
608 )]
609 static SCStreamFrameInfoStatus: &'static FrameInfo;
610 #[api::available(
611 macos = 12.3,
612 maccatalyst = 18.2,
613 ios = 27.0,
614 visionos = 27.0,
615 tvos = 27.0
616 )]
617 static SCStreamFrameInfoDisplayTime: &'static FrameInfo;
618 #[api::available(
619 macos = 12.3,
620 maccatalyst = 18.2,
621 ios = 27.0,
622 visionos = 27.0,
623 tvos = 27.0
624 )]
625 static SCStreamFrameInfoScaleFactor: &'static FrameInfo;
626 #[api::available(
627 macos = 12.3,
628 maccatalyst = 18.2,
629 ios = 27.0,
630 visionos = 27.0,
631 tvos = 27.0
632 )]
633 static SCStreamFrameInfoContentScale: &'static FrameInfo;
634 #[api::available(
635 macos = 12.3,
636 maccatalyst = 18.2,
637 ios = 27.0,
638 visionos = 27.0,
639 tvos = 27.0
640 )]
641 static SCStreamFrameInfoContentRect: &'static FrameInfo;
642 #[api::available(macos = 12.3, maccatalyst = 18.2)]
643 static SCStreamFrameInfoDirtyRects: &'static FrameInfo;
644 #[api::available(
645 macos = 13.1,
646 maccatalyst = 18.2,
647 ios = 27.0,
648 visionos = 27.0,
649 tvos = 27.0
650 )]
651 static SCStreamFrameInfoScreenRect: &'static FrameInfo;
652 #[api::available(macos = 14.0, maccatalyst = 18.2)]
653 static SCStreamFrameInfoBoundingRect: &'static FrameInfo;
654 #[api::available(macos = 14.2, maccatalyst = 18.2)]
655 static SCStreamFrameInfoPresenterOverlayContentRect: &'static FrameInfo;
656 #[api::available(macos = 27.0, maccatalyst = 27.0, ios = 27.0, visionos = 27.0)]
657 static SCStreamFrameInfoVideoOrientation: &'static FrameInfo;
658}
659
660#[doc(alias = "SCCaptureDynamicRange")]
661#[derive(Debug, Copy, Clone, Eq, PartialEq)]
662#[repr(isize)]
663pub enum CaptureDynamicRange {
664 #[doc(alias = "SCCaptureDynamicRangeSDR")]
666 Sdr,
667 #[doc(alias = "SCCaptureDynamicRangeHDRLocalDisplay")]
669 HdrLocalDisplay,
670 #[doc(alias = "SCCaptureDynamicRangeHDRCanonicalDisplay")]
672 HdrCanonicalDisplay,
673}
674
675define_obj_type!(
676 #[doc(alias = "SCContentFilter")]
677 pub ContentFilter(ns::Id)
678);
679
680impl arc::A<ContentFilter> {
681 #[objc::msg_send(initWithDesktopIndependentWindow:)]
682 #[api::available(macos = 12.3, maccatalyst = 18.2)]
683 pub fn init_with_desktop_independent_window(
684 self,
685 window: &sc::Window,
686 ) -> arc::Retained<ContentFilter>;
687
688 #[objc::msg_send(initWithDisplay:excludingWindows:)]
689 #[api::available(macos = 12.3, maccatalyst = 18.2)]
690 pub fn init_with_display_excluding_windows(
691 self,
692 display: &sc::Display,
693 windows: &ns::Array<sc::Window>,
694 ) -> arc::Retained<ContentFilter>;
695
696 #[objc::msg_send(initWithDisplay:includingWindows:)]
702 #[api::available(macos = 12.3, maccatalyst = 18.2)]
703 pub fn init_with_display_including_windows(
704 self,
705 display: &sc::Display,
706 windows: &ns::Array<sc::Window>,
707 ) -> arc::Retained<ContentFilter>;
708
709 #[objc::msg_send(initWithDisplay:includingApplications:exceptingWindows:)]
712 #[api::available(macos = 12.3, maccatalyst = 18.2)]
713 pub fn init_with_display_including_apps_excepting_windows(
714 self,
715 display: &sc::Display,
716 apps: &ns::Array<sc::RunningApp>,
717 excepting_windows: &ns::Array<sc::Window>,
718 ) -> arc::Retained<ContentFilter>;
719
720 #[objc::msg_send(initWithDisplay:excludingApplications:exceptingWindows:)]
723 #[api::available(macos = 12.3, maccatalyst = 18.2)]
724 pub fn init_with_display_excluding_apps_excepting_windows(
725 self,
726 display: &sc::Display,
727 apps: &ns::Array<sc::RunningApp>,
728 excepting_windows: &ns::Array<sc::Window>,
729 ) -> arc::Retained<ContentFilter>;
730}
731
732impl ContentFilter {
733 define_cls!(SC_CONTENT_FILTER);
734
735 #[api::available(macos = 12.3, maccatalyst = 18.2)]
740 pub fn with_desktop_independent_window(window: &sc::Window) -> arc::R<ContentFilter> {
741 Self::alloc().init_with_desktop_independent_window(window)
742 }
743
744 #[api::available(macos = 12.3, maccatalyst = 18.2)]
746 pub fn with_display_excluding_windows(
747 display: &sc::Display,
748 windows: &ns::Array<sc::Window>,
749 ) -> arc::R<Self> {
750 Self::alloc().init_with_display_excluding_windows(display, windows)
751 }
752
753 #[api::available(macos = 12.3, maccatalyst = 18.2)]
775 pub fn with_display_including_windows(
776 display: &sc::Display,
777 windows: &ns::Array<sc::Window>,
778 ) -> arc::R<Self> {
779 Self::alloc().init_with_display_including_windows(display, windows)
780 }
781
782 #[api::available(macos = 12.3, maccatalyst = 18.2)]
788 pub fn with_display_including_apps_excepting_windows(
789 display: &sc::Display,
790 apps: &ns::Array<sc::RunningApp>,
791 excepting_windows: &ns::Array<sc::Window>,
792 ) -> arc::R<Self> {
793 Self::alloc().init_with_display_including_apps_excepting_windows(
794 display,
795 apps,
796 excepting_windows,
797 )
798 }
799
800 #[api::available(macos = 12.3, maccatalyst = 18.2)]
805 pub fn with_display_excluding_apps_excepting_windows(
806 display: &sc::Display,
807 apps: &ns::Array<sc::RunningApp>,
808 excepting_windows: &ns::Array<sc::Window>,
809 ) -> arc::R<Self> {
810 Self::alloc().init_with_display_excluding_apps_excepting_windows(
811 display,
812 apps,
813 excepting_windows,
814 )
815 }
816
817 #[objc::msg_send(style)]
818 #[api::available(
819 macos = 14.0,
820 maccatalyst = 18.2,
821 ios = 27.0,
822 visionos = 27.0,
823 tvos = 27.0
824 )]
825 pub fn style(&self) -> sc::ShareableContentStyle;
826
827 #[objc::msg_send(pointPixelScale)]
828 #[api::available(
829 macos = 14.0,
830 maccatalyst = 18.2,
831 ios = 27.0,
832 visionos = 27.0,
833 tvos = 27.0
834 )]
835 pub fn point_pixel_scale(&self) -> f32;
836
837 #[objc::msg_send(contentRect)]
838 #[api::available(
839 macos = 14.0,
840 maccatalyst = 18.2,
841 ios = 27.0,
842 visionos = 27.0,
843 tvos = 27.0
844 )]
845 pub fn content_rect(&self) -> cg::Rect;
846
847 #[objc::msg_send(includeMenuBar)]
848 #[api::available(macos = 14.2, maccatalyst = 18.2)]
849 pub fn include_menu_bar(&self) -> bool;
850
851 #[objc::msg_send(setIncludeMenuBar:)]
857 #[api::available(macos = 14.2, maccatalyst = 18.2)]
858 pub fn set_include_menu_bar(&mut self, val: bool);
859
860 #[objc::msg_send(includedDisplays)]
862 #[api::available(macos = 15.2, maccatalyst = 18.2)]
863 pub fn included_displays(&self) -> arc::R<ns::Array<sc::Display>>;
864
865 #[objc::msg_send(includedApplications)]
867 #[api::available(macos = 15.2, maccatalyst = 18.2)]
868 pub fn included_apps(&self) -> arc::R<ns::Array<sc::RunningApp>>;
869
870 #[objc::msg_send(includedWindows)]
872 #[api::available(macos = 15.2, maccatalyst = 18.2)]
873 pub fn included_windows(&self) -> arc::R<ns::Array<sc::Window>>;
874
875 #[objc::msg_send(isMicrophoneEnabled)]
876 #[api::available(macos = 27.0, maccatalyst = 27.0, ios = 27.0, visionos = 27.0)]
877 pub fn is_mic_enabled(&self) -> bool;
878
879 #[objc::msg_send(isCameraEnabled)]
880 #[api::available(macos = 27.0, maccatalyst = 27.0, ios = 27.0)]
881 pub fn is_camera_enabled(&self) -> bool;
882}
883
884define_obj_type!(
885 #[doc(alias = "SCStream")]
887 pub Stream(ns::Id)
888);
889
890unsafe impl Send for Stream {}
891unsafe impl Sync for Stream {}
892
893#[objc::protocol(SCStreamOutput)]
895pub trait Output: objc::Obj {
896 #[objc::optional]
898 #[objc::msg_send(stream:didOutputSampleBuffer:ofType:)]
899 fn stream_did_output_sample_buf(
900 &mut self,
901 stream: &Stream,
902 sample_buf: &mut cm::SampleBuf,
903 kind: OutputType,
904 );
905}
906
907#[objc::protocol(SCStreamDelegate)]
909pub trait Delegate: objc::Obj {
910 #[objc::optional]
912 #[objc::msg_send(stream:didStopWithError:)]
913 fn stream_did_stop_with_err(&mut self, stream: &Stream, error: &ns::Error);
914
915 #[objc::optional]
917 #[objc::msg_send(userDidStopStream:)]
918 fn user_did_stop_stream(&mut self, stream: &Stream);
919
920 #[objc::optional]
922 #[objc::msg_send(outputVideoEffectDidStartForStream:)]
923 fn output_video_effect_did_start_for_stream(&mut self, stream: &Stream);
924
925 #[objc::optional]
927 #[objc::msg_send(outputVideoEffectDidStopForStream:)]
928 fn output_video_effect_did_stop_for_stream(&mut self, stream: &Stream);
929
930 #[objc::optional]
932 #[objc::msg_send(streamDidBecomeActive:)]
933 fn stream_did_become_active(&mut self, stream: &Stream);
934
935 #[objc::optional]
937 #[objc::msg_send(streamDidBecomeInactive:)]
938 fn stream_did_become_inactive(&mut self, stream: &Stream);
939}
940
941define_obj_type!(pub AnyDelegate(ns::Id));
942
943impl Delegate for AnyDelegate {}
944
945impl arc::A<Stream> {
946 #[objc::msg_send(initWithFilter:configuration:delegate:)]
948 pub fn init_with_filter_configuration_delegate<D: Delegate>(
949 self,
950 filter: &ContentFilter,
951 configuration: &Cfg,
952 delegate: Option<&D>,
953 ) -> arc::Retained<Stream>;
954}
955
956impl Stream {
957 define_cls!(SC_STREAM);
958
959 pub fn with_delegate<D: Delegate>(
961 filter: &ContentFilter,
962 configuration: &Cfg,
963 delegate: &D,
964 ) -> arc::R<Self> {
965 Self::alloc().init_with_filter_configuration_delegate(filter, configuration, Some(delegate))
966 }
967
968 pub fn new(filter: &ContentFilter, configuration: &Cfg) -> arc::R<Self> {
970 Self::alloc().init_with_filter_configuration_delegate::<AnyDelegate>(
971 filter,
972 configuration,
973 None,
974 )
975 }
976
977 #[objc::msg_send(synchronizationClock)]
979 #[api::available(
980 macos = 13.0,
981 maccatalyst = 18.2,
982 ios = 27.0,
983 visionos = 27.0,
984 tvos = 27.0
985 )]
986 pub fn synchronization_clock(&self) -> Option<&cm::Clock>;
987
988 #[objc::msg_send(isCapturing)]
990 #[api::available(
991 macos = 27.0,
992 maccatalyst = 27.0,
993 ios = 27.0,
994 visionos = 27.0,
995 tvos = 27.0
996 )]
997 pub fn is_capturing(&self) -> bool;
998
999 #[objc::msg_send(addStreamOutput:type:sampleHandlerQueue:error:)]
1000 unsafe fn add_stream_output_type_sample_handler_queue_err<D: Output>(
1001 &self,
1002 output: &D,
1003 output_type: OutputType,
1004 queue: Option<&dispatch::Queue>,
1005 error: *mut Option<&ns::Error>,
1006 ) -> bool;
1007
1008 pub fn add_stream_output<'ear, D: Output>(
1010 &self,
1011 output: &D,
1012 output_type: OutputType,
1013 queue: Option<&dispatch::Queue>,
1014 ) -> ns::Result<'ear> {
1015 ns::if_false(|err| unsafe {
1016 self.add_stream_output_type_sample_handler_queue_err(output, output_type, queue, err)
1017 })
1018 }
1019
1020 #[objc::msg_send(removeStreamOutput:type:error:)]
1021 unsafe fn remove_stream_output_err<'ear, D: Output>(
1022 &self,
1023 output: &D,
1024 output_type: OutputType,
1025 error: *mut Option<&'ear ns::Error>,
1026 ) -> bool;
1027
1028 pub fn remove_stream_output<'ear, D: Output>(
1030 &self,
1031 output: &D,
1032 output_type: OutputType,
1033 ) -> ns::Result<'ear> {
1034 ns::if_false(|err| unsafe { self.remove_stream_output_err(output, output_type, err) })
1035 }
1036
1037 #[cfg(feature = "blocks")]
1038 #[objc::msg_send(updateContentFilter:completionHandler:)]
1039 #[api::available(macos = 12.3, maccatalyst = 18.2)]
1040 pub fn update_content_filter_ch_block(
1041 &self,
1042 filter: &ContentFilter,
1043 ch: Option<&mut blocks::ErrCh>,
1044 );
1045
1046 #[cfg(feature = "blocks")]
1047 #[api::available(macos = 12.3, maccatalyst = 18.2)]
1048 pub fn update_content_filter_ch(
1049 &self,
1050 filter: &ContentFilter,
1051 ch: impl FnMut(Option<&ns::Error>) + 'static,
1052 ) {
1053 let mut block = blocks::ErrCh::new1(ch);
1054 self.update_content_filter_ch_block(filter, Some(&mut block));
1055 }
1056
1057 #[cfg(all(feature = "blocks", feature = "async"))]
1058 #[api::available(macos = 12.3, maccatalyst = 18.2)]
1059 pub async fn update_content_filter(
1060 &self,
1061 filter: &ContentFilter,
1062 ) -> Result<(), arc::R<ns::Error>> {
1063 let (future, mut block) = blocks::ok();
1064 self.update_content_filter_ch_block(filter, Some(&mut block));
1065 future.await
1066 }
1067
1068 #[cfg(feature = "blocks")]
1069 #[objc::msg_send(updateConfiguration:completionHandler:)]
1070 #[api::available(macos = 12.3, maccatalyst = 18.2)]
1071 pub fn update_cfg_ch_block(&self, cfg: &Cfg, ch: Option<&mut blocks::ErrCh>);
1072
1073 #[cfg(feature = "blocks")]
1074 #[api::available(macos = 12.3, maccatalyst = 18.2)]
1075 pub fn update_cfg_ch(&self, cfg: &Cfg, ch: impl FnMut(Option<&ns::Error>) + 'static) {
1076 let mut block = blocks::ErrCh::new1(ch);
1077 self.update_cfg_ch_block(cfg, Some(&mut block));
1078 }
1079
1080 #[cfg(all(feature = "blocks", feature = "async"))]
1081 #[api::available(macos = 12.3, maccatalyst = 18.2)]
1082 pub async fn update_cfg(&self, cfg: &Cfg) -> Result<(), arc::R<ns::Error>> {
1083 let (future, mut block) = blocks::ok();
1084 self.update_cfg_ch_block(cfg, Some(&mut block));
1085 future.await
1086 }
1087
1088 #[cfg(feature = "blocks")]
1089 #[objc::msg_send(startCaptureWithCompletionHandler:)]
1091 pub fn start_with_ch_block(&self, ch: Option<&mut blocks::ErrCh>);
1092
1093 #[cfg(feature = "blocks")]
1094 pub fn start_with_ch(&self, ch: impl FnMut(Option<&ns::Error>) + 'static) {
1096 let mut block = blocks::ErrCh::new1(ch);
1097 self.start_with_ch_block(Some(&mut block));
1098 }
1099
1100 #[cfg(feature = "blocks")]
1101 #[objc::msg_send(stopCaptureWithCompletionHandler:)]
1103 pub fn stop_with_ch_block(&self, ch: Option<&mut blocks::ErrCh>);
1104
1105 #[cfg(feature = "blocks")]
1106 pub fn stop_with_ch(&self, ch: impl FnMut(Option<&ns::Error>) + 'static) {
1108 let mut block = blocks::ErrCh::new1(ch);
1109 self.stop_with_ch_block(Some(&mut block));
1110 }
1111
1112 #[cfg(all(feature = "blocks", feature = "async"))]
1113 pub async fn start(&self) -> Result<(), arc::R<ns::Error>> {
1115 let (future, mut block) = blocks::ok();
1116 self.start_with_ch_block(Some(&mut block));
1117 future.await
1118 }
1119
1120 #[cfg(all(feature = "blocks", feature = "async"))]
1121 pub async fn stop(&self) -> Result<(), arc::R<ns::Error>> {
1123 let (future, mut block) = blocks::ok();
1124 self.stop_with_ch_block(Some(&mut block));
1125 future.await
1126 }
1127
1128 #[objc::msg_send(addRecordingOutput:error:)]
1130 #[api::available(
1131 macos = 15.0,
1132 maccatalyst = 18.2,
1133 ios = 27.0,
1134 visionos = 27.0,
1135 tvos = 27.0
1136 )]
1137 pub unsafe fn add_recording_output_err<'ar>(
1138 &mut self,
1139 val: &sc::RecordingOutput,
1140 error: *mut Option<&'ar ns::Error>,
1141 ) -> bool;
1142
1143 #[api::available(
1144 macos = 15.0,
1145 maccatalyst = 18.2,
1146 ios = 27.0,
1147 visionos = 27.0,
1148 tvos = 27.0
1149 )]
1150 pub fn add_recording_output<'ear>(&mut self, val: &sc::RecordingOutput) -> ns::Result<'ear> {
1151 ns::if_false(|err| unsafe { self.add_recording_output_err(val, err) })
1152 }
1153
1154 #[objc::msg_send(removeRecordingOutput:error:)]
1156 #[api::available(
1157 macos = 15.0,
1158 maccatalyst = 18.2,
1159 ios = 27.0,
1160 visionos = 27.0,
1161 tvos = 27.0
1162 )]
1163 pub unsafe fn remove_recording_output_err<'ar>(
1164 &mut self,
1165 val: &sc::RecordingOutput,
1166 error: *mut Option<&'ar ns::Error>,
1167 ) -> bool;
1168
1169 #[api::available(
1170 macos = 15.0,
1171 maccatalyst = 18.2,
1172 ios = 27.0,
1173 visionos = 27.0,
1174 tvos = 27.0
1175 )]
1176 pub fn remove_recording_output<'ear>(&mut self, val: &sc::RecordingOutput) -> ns::Result<'ear> {
1177 ns::if_false(|err| unsafe { self.remove_recording_output_err(val, err) })
1178 }
1179
1180 #[objc::msg_send(addClipBufferingOutput:error:)]
1182 #[api::available(
1183 macos = 27.0,
1184 maccatalyst = 27.0,
1185 ios = 27.0,
1186 visionos = 27.0,
1187 tvos = 27.0
1188 )]
1189 pub unsafe fn add_clip_buffering_output_err<'ar>(
1190 &mut self,
1191 val: &sc::ClipBufferingOutput,
1192 error: *mut Option<&'ar ns::Error>,
1193 ) -> bool;
1194
1195 #[api::available(
1196 macos = 27.0,
1197 maccatalyst = 27.0,
1198 ios = 27.0,
1199 visionos = 27.0,
1200 tvos = 27.0
1201 )]
1202 pub fn add_clip_buffering_output<'ear>(
1203 &mut self,
1204 val: &sc::ClipBufferingOutput,
1205 ) -> ns::Result<'ear> {
1206 ns::if_false(|err| unsafe { self.add_clip_buffering_output_err(val, err) })
1207 }
1208
1209 #[objc::msg_send(removeClipBufferingOutput:error:)]
1211 #[api::available(
1212 macos = 27.0,
1213 maccatalyst = 27.0,
1214 ios = 27.0,
1215 visionos = 27.0,
1216 tvos = 27.0
1217 )]
1218 pub unsafe fn remove_clip_buffering_output_err<'ar>(
1219 &mut self,
1220 val: &sc::ClipBufferingOutput,
1221 error: *mut Option<&'ar ns::Error>,
1222 ) -> bool;
1223
1224 #[api::available(
1225 macos = 27.0,
1226 maccatalyst = 27.0,
1227 ios = 27.0,
1228 visionos = 27.0,
1229 tvos = 27.0
1230 )]
1231 pub fn remove_clip_buffering_output<'ear>(
1232 &mut self,
1233 val: &sc::ClipBufferingOutput,
1234 ) -> ns::Result<'ear> {
1235 ns::if_false(|err| unsafe { self.remove_clip_buffering_output_err(val, err) })
1236 }
1237
1238 #[objc::msg_send(addVideoEffectOutput:error:)]
1240 #[api::available(ios = 27.0)]
1241 pub unsafe fn add_video_effect_output_err<'ar>(
1242 &mut self,
1243 val: &sc::VideoEffectOutput,
1244 error: *mut Option<&'ar ns::Error>,
1245 ) -> bool;
1246
1247 #[api::available(ios = 27.0)]
1248 pub fn add_video_effect_output<'ear>(
1249 &mut self,
1250 val: &sc::VideoEffectOutput,
1251 ) -> ns::Result<'ear> {
1252 ns::if_false(|err| unsafe { self.add_video_effect_output_err(val, err) })
1253 }
1254
1255 #[objc::msg_send(removeVideoEffectOutput:error:)]
1257 #[api::available(ios = 27.0)]
1258 pub unsafe fn remove_video_effect_output_err<'ar>(
1259 &mut self,
1260 val: &sc::VideoEffectOutput,
1261 error: *mut Option<&'ar ns::Error>,
1262 ) -> bool;
1263
1264 #[api::available(ios = 27.0)]
1265 pub fn remove_video_effect_output<'ear>(
1266 &mut self,
1267 val: &sc::VideoEffectOutput,
1268 ) -> ns::Result<'ear> {
1269 ns::if_false(|err| unsafe { self.remove_video_effect_output_err(val, err) })
1270 }
1271}
1272
1273#[cfg(test)]
1274mod tests {
1275 use std::time::Duration;
1276
1277 use crate::{
1278 cm, cv, define_obj_type, dispatch, ns, objc, sc, sc::stream::Output, sc::stream::OutputImpl,
1279 };
1280
1281 define_obj_type!(
1282 FrameCounter + sc::stream::OutputImpl,
1283 usize,
1284 FRAME_COUNTER_CLS
1285 );
1286
1287 impl Output for FrameCounter {}
1288
1289 #[objc::add_methods]
1290 impl OutputImpl for FrameCounter {}
1291
1292 #[test]
1293 fn basics() {
1294 let mut cfg = sc::StreamCfg::new();
1295
1296 cfg.set_width(200);
1297 assert_eq!(200, cfg.width());
1298 cfg.set_height(300);
1299 assert_eq!(300, cfg.height());
1300
1301 cfg.set_minimum_frame_interval(cm::Time::new(1, 60));
1302 cfg.set_pixel_format(cv::PixelFormat::_32_BGRA);
1303 cfg.set_scales_to_fit(false);
1304 cfg.set_shows_cursor(true);
1305 }
1306
1307 #[tokio::test]
1308 async fn start_fails() {
1309 let q = dispatch::Queue::serial_with_ar_pool();
1310 let content = sc::ShareableContent::current().await.expect("content");
1311 let display = content.displays().get(0).unwrap();
1312 let mut cfg = sc::StreamCfg::new();
1313 cfg.set_width(display.width() as usize * 2);
1314 cfg.set_height(display.height() as usize * 2);
1315
1316 let windows = ns::Array::new();
1317 let filter = sc::ContentFilter::with_display_excluding_windows(&display, &windows);
1318 let stream = sc::Stream::new(&filter, &cfg);
1319 let delegate = FrameCounter::with(0);
1320 stream
1321 .add_stream_output(delegate.as_ref(), sc::OutputType::Screen, Some(&q))
1322 .unwrap();
1323 stream.start().await.expect("started");
1324 stream.start().await.expect_err("already started");
1325
1326 stream
1327 .update_content_filter(&filter)
1328 .await
1329 .expect("Failed to update filter");
1330 stream.update_cfg(&cfg).await.expect("Failed to update cfg");
1331
1332 tokio::time::sleep(Duration::from_secs(2)).await;
1333
1334 stream
1335 .remove_stream_output(delegate.as_ref(), sc::OutputType::Screen)
1336 .unwrap();
1337
1338 stream.stop().await.expect("stopped");
1339 stream.stop().await.expect_err("already stopped");
1340 }
1348
1349 #[tokio::test]
1350 async fn content_filter_with_display_including_windows() {
1351 let content = sc::ShareableContent::current().await.expect("content");
1352 let displays = content.displays();
1353 let windows = content.windows();
1354
1355 let display = displays.first().expect("at least one display");
1356
1357 let empty_windows = ns::Array::<sc::Window>::new();
1359 let filter = sc::ContentFilter::with_display_including_windows(&display, &empty_windows);
1360 let _ = filter.content_rect();
1362
1363 if let Some(window) = windows.first() {
1365 let window_array = ns::Array::from_slice_retained(&[window.retained()]);
1366 let filter = sc::ContentFilter::with_display_including_windows(&display, &window_array);
1367 let rect = filter.content_rect();
1369 assert!(rect.size.width > 0.0 || rect.size.height > 0.0);
1370 }
1371 }
1372
1373 #[tokio::test]
1374 async fn content_filter_with_apps() {
1375 let content = sc::ShareableContent::current().await.expect("content");
1376 let displays = content.displays();
1377 let apps = content.apps();
1378
1379 let display = displays.first().expect("at least one display");
1380 let empty_windows = ns::Array::<sc::Window>::new();
1381
1382 if let Some(app) = apps.first() {
1384 let app_array = ns::Array::from_slice_retained(&[app.retained()]);
1385 let filter = sc::ContentFilter::with_display_including_apps_excepting_windows(
1386 &display,
1387 &app_array,
1388 &empty_windows,
1389 );
1390 let _ = filter.content_rect();
1392 }
1393
1394 if let Some(app) = apps.first() {
1396 let app_array = ns::Array::from_slice_retained(&[app.retained()]);
1397 let filter = sc::ContentFilter::with_display_excluding_apps_excepting_windows(
1398 &display,
1399 &app_array,
1400 &empty_windows,
1401 );
1402 let _ = filter.content_rect();
1404 }
1405 }
1406}