1use crate::error::SCError;
28use crate::shareable_content::SCShareableContent;
29use crate::stream::configuration::SCStreamConfiguration;
30use crate::stream::content_filter::SCContentFilter;
31use crate::utils::sync_completion::{error_from_cstr, AsyncCompletion, AsyncCompletionFuture};
32use std::ffi::c_void;
33use std::future::Future;
34use std::pin::Pin;
35use std::sync::{Arc, Mutex};
36use std::task::{Context, Poll, Waker};
37
38extern "C" fn shareable_content_callback(
44 content: *const c_void,
45 error: *const i8,
46 user_data: *mut c_void,
47) {
48 if !error.is_null() {
49 let error_msg = unsafe { error_from_cstr(error) };
50 unsafe { AsyncCompletion::<SCShareableContent>::complete_err(user_data, error_msg) };
51 } else if !content.is_null() {
52 let sc = unsafe { SCShareableContent::from_ptr(content) };
53 unsafe { AsyncCompletion::complete_ok(user_data, sc) };
54 } else {
55 unsafe {
56 AsyncCompletion::<SCShareableContent>::complete_err(
57 user_data,
58 "Unknown error".to_string(),
59 );
60 };
61 }
62}
63
64pub struct AsyncShareableContentFuture {
66 inner: AsyncCompletionFuture<SCShareableContent>,
67}
68
69impl Future for AsyncShareableContentFuture {
70 type Output = Result<SCShareableContent, SCError>;
71
72 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
73 Pin::new(&mut self.inner)
74 .poll(cx)
75 .map(|r| r.map_err(SCError::NoShareableContent))
76 }
77}
78
79pub struct AsyncSCShareableContent;
84
85impl AsyncSCShareableContent {
86 pub fn get() -> AsyncShareableContentFuture {
96 Self::with_options().get_async()
97 }
98
99 #[must_use]
101 pub fn with_options() -> AsyncSCShareableContentOptions {
102 AsyncSCShareableContentOptions::default()
103 }
104}
105
106#[derive(Default, Debug, Clone, PartialEq, Eq)]
108pub struct AsyncSCShareableContentOptions {
109 exclude_desktop_windows: bool,
110 on_screen_windows_only: bool,
111}
112
113impl AsyncSCShareableContentOptions {
114 #[must_use]
116 pub fn exclude_desktop_windows(mut self, exclude: bool) -> Self {
117 self.exclude_desktop_windows = exclude;
118 self
119 }
120
121 #[must_use]
123 pub fn on_screen_windows_only(mut self, on_screen_only: bool) -> Self {
124 self.on_screen_windows_only = on_screen_only;
125 self
126 }
127
128 pub fn get_async(self) -> AsyncShareableContentFuture {
130 let (future, context) = AsyncCompletion::create();
131
132 unsafe {
133 crate::ffi::sc_shareable_content_get_with_options(
134 self.exclude_desktop_windows,
135 self.on_screen_windows_only,
136 shareable_content_callback,
137 context,
138 );
139 }
140
141 AsyncShareableContentFuture { inner: future }
142 }
143}
144
145struct AsyncSampleIteratorState {
151 buffer: std::collections::VecDeque<crate::cm::CMSampleBuffer>,
152 waker: Option<Waker>,
153 closed: bool,
154 capacity: usize,
155}
156
157struct AsyncSampleSender {
159 inner: Arc<Mutex<AsyncSampleIteratorState>>,
160}
161
162impl crate::stream::output_trait::SCStreamOutputTrait for AsyncSampleSender {
163 fn did_output_sample_buffer(
164 &self,
165 sample_buffer: crate::cm::CMSampleBuffer,
166 _of_type: crate::stream::output_type::SCStreamOutputType,
167 ) {
168 let Ok(mut state) = self.inner.lock() else {
169 return;
170 };
171
172 if state.buffer.len() >= state.capacity {
174 state.buffer.pop_front();
175 }
176
177 state.buffer.push_back(sample_buffer);
178
179 if let Some(waker) = state.waker.take() {
180 waker.wake();
181 }
182 }
183}
184
185impl Drop for AsyncSampleSender {
186 fn drop(&mut self) {
187 if let Ok(mut state) = self.inner.lock() {
188 state.closed = true;
189 if let Some(waker) = state.waker.take() {
190 waker.wake();
191 }
192 }
193 }
194}
195
196pub struct NextSample<'a> {
198 state: &'a Arc<Mutex<AsyncSampleIteratorState>>,
199}
200
201impl Future for NextSample<'_> {
202 type Output = Option<crate::cm::CMSampleBuffer>;
203
204 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
205 let Ok(mut state) = self.state.lock() else {
206 return Poll::Ready(None);
207 };
208
209 if let Some(sample) = state.buffer.pop_front() {
210 return Poll::Ready(Some(sample));
211 }
212
213 if state.closed {
214 Poll::Ready(None)
215 } else {
216 state.waker = Some(cx.waker().clone());
217 Poll::Pending
218 }
219 }
220}
221
222unsafe impl Send for AsyncSampleSender {}
223unsafe impl Sync for AsyncSampleSender {}
224
225pub struct AsyncSCStream {
257 stream: crate::stream::SCStream,
258 iterator_state: Arc<Mutex<AsyncSampleIteratorState>>,
259}
260
261impl AsyncSCStream {
262 #[must_use]
271 pub fn new(
272 filter: &SCContentFilter,
273 config: &SCStreamConfiguration,
274 buffer_capacity: usize,
275 output_type: crate::stream::output_type::SCStreamOutputType,
276 ) -> Self {
277 let state = Arc::new(Mutex::new(AsyncSampleIteratorState {
278 buffer: std::collections::VecDeque::with_capacity(buffer_capacity),
279 waker: None,
280 closed: false,
281 capacity: buffer_capacity,
282 }));
283
284 let sender = AsyncSampleSender {
285 inner: Arc::clone(&state),
286 };
287
288 let mut stream = crate::stream::SCStream::new(filter, config);
289 stream.add_output_handler(sender, output_type);
290
291 Self {
292 stream,
293 iterator_state: state,
294 }
295 }
296
297 pub fn next(&self) -> NextSample<'_> {
301 NextSample {
302 state: &self.iterator_state,
303 }
304 }
305
306 #[must_use]
308 pub fn try_next(&self) -> Option<crate::cm::CMSampleBuffer> {
309 self.iterator_state.lock().ok()?.buffer.pop_front()
310 }
311
312 #[must_use]
314 pub fn is_closed(&self) -> bool {
315 self.iterator_state.lock().map(|s| s.closed).unwrap_or(true)
316 }
317
318 #[must_use]
320 pub fn buffered_count(&self) -> usize {
321 self.iterator_state
322 .lock()
323 .map(|s| s.buffer.len())
324 .unwrap_or(0)
325 }
326
327 pub fn clear_buffer(&self) {
329 if let Ok(mut state) = self.iterator_state.lock() {
330 state.buffer.clear();
331 }
332 }
333
334 pub fn start_capture(&self) -> Result<(), SCError> {
340 self.stream.start_capture()
341 }
342
343 pub fn stop_capture(&self) -> Result<(), SCError> {
349 self.stream.stop_capture()
350 }
351
352 pub fn update_configuration(&self, config: &SCStreamConfiguration) -> Result<(), SCError> {
358 self.stream.update_configuration(config)
359 }
360
361 pub fn update_content_filter(&self, filter: &SCContentFilter) -> Result<(), SCError> {
367 self.stream.update_content_filter(filter)
368 }
369
370 #[must_use]
372 pub fn inner(&self) -> &crate::stream::SCStream {
373 &self.stream
374 }
375}
376
377#[cfg(feature = "macos_14_0")]
409pub struct AsyncSCScreenshotManager;
410
411#[cfg(feature = "macos_14_0")]
413extern "C" fn screenshot_image_callback(
414 image_ptr: *const c_void,
415 error_ptr: *const i8,
416 user_data: *mut c_void,
417) {
418 if !error_ptr.is_null() {
419 let error = unsafe { error_from_cstr(error_ptr) };
420 unsafe {
421 AsyncCompletion::<crate::screenshot_manager::CGImage>::complete_err(user_data, error);
422 }
423 } else if !image_ptr.is_null() {
424 let image = crate::screenshot_manager::CGImage::from_ptr(image_ptr);
425 unsafe { AsyncCompletion::complete_ok(user_data, image) };
426 } else {
427 unsafe {
428 AsyncCompletion::<crate::screenshot_manager::CGImage>::complete_err(
429 user_data,
430 "Unknown error".to_string(),
431 );
432 };
433 }
434}
435
436#[cfg(feature = "macos_14_0")]
438extern "C" fn screenshot_buffer_callback(
439 buffer_ptr: *const c_void,
440 error_ptr: *const i8,
441 user_data: *mut c_void,
442) {
443 if !error_ptr.is_null() {
444 let error = unsafe { error_from_cstr(error_ptr) };
445 unsafe { AsyncCompletion::<crate::cm::CMSampleBuffer>::complete_err(user_data, error) };
446 } else if !buffer_ptr.is_null() {
447 let buffer = unsafe { crate::cm::CMSampleBuffer::from_ptr(buffer_ptr.cast_mut()) };
448 unsafe { AsyncCompletion::complete_ok(user_data, buffer) };
449 } else {
450 unsafe {
451 AsyncCompletion::<crate::cm::CMSampleBuffer>::complete_err(
452 user_data,
453 "Unknown error".to_string(),
454 );
455 };
456 }
457}
458
459#[cfg(feature = "macos_14_0")]
461pub struct AsyncScreenshotFuture<T> {
462 inner: AsyncCompletionFuture<T>,
463}
464
465#[cfg(feature = "macos_14_0")]
466impl<T> Future for AsyncScreenshotFuture<T> {
467 type Output = Result<T, SCError>;
468
469 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
470 Pin::new(&mut self.inner)
471 .poll(cx)
472 .map(|r| r.map_err(SCError::ScreenshotError))
473 }
474}
475
476#[cfg(feature = "macos_14_0")]
477impl AsyncSCScreenshotManager {
478 pub fn capture_image(
485 content_filter: &crate::stream::content_filter::SCContentFilter,
486 configuration: &SCStreamConfiguration,
487 ) -> AsyncScreenshotFuture<crate::screenshot_manager::CGImage> {
488 let (future, context) = AsyncCompletion::create();
489
490 unsafe {
491 crate::ffi::sc_screenshot_manager_capture_image(
492 content_filter.as_ptr(),
493 configuration.as_ptr(),
494 screenshot_image_callback,
495 context,
496 );
497 }
498
499 AsyncScreenshotFuture { inner: future }
500 }
501
502 pub fn capture_sample_buffer(
509 content_filter: &crate::stream::content_filter::SCContentFilter,
510 configuration: &SCStreamConfiguration,
511 ) -> AsyncScreenshotFuture<crate::cm::CMSampleBuffer> {
512 let (future, context) = AsyncCompletion::create();
513
514 unsafe {
515 crate::ffi::sc_screenshot_manager_capture_sample_buffer(
516 content_filter.as_ptr(),
517 configuration.as_ptr(),
518 screenshot_buffer_callback,
519 context,
520 );
521 }
522
523 AsyncScreenshotFuture { inner: future }
524 }
525}