Skip to main content

webrtc_sys/
desktop_capturer.rs

1// Copyright 2025 LiveKit, Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use cxx::UniquePtr;
16use ffi::CaptureResult;
17
18use crate::{desktop_capturer::ffi::DesktopFrame, impl_thread_safety};
19
20#[cxx::bridge(namespace = "livekit_ffi")]
21pub mod ffi {
22    #[derive(Clone)]
23    struct Source {
24        id: u64,
25        title: String,
26        display_id: i64,
27    }
28
29    #[derive(Debug, PartialEq)]
30    enum SourceType {
31        Screen,
32        Window,
33        Generic,
34    }
35
36    #[derive(Clone, Debug)]
37    struct DesktopCapturerOptions {
38        source_type: SourceType,
39        include_cursor: bool,
40        allow_sck_system_picker: bool,
41    }
42
43    enum CaptureResult {
44        Success,
45        ErrorTemporary,
46        ErrorPermanent,
47    }
48
49    unsafe extern "C++" {
50        include!("livekit/desktop_capturer.h");
51
52        type DesktopCapturer;
53        type DesktopFrame;
54
55        fn new_desktop_capturer(options: DesktopCapturerOptions) -> UniquePtr<DesktopCapturer>;
56        fn capture_frame(self: &DesktopCapturer);
57        fn get_source_list(self: &DesktopCapturer) -> Vec<Source>;
58        fn select_source(self: &DesktopCapturer, id: u64) -> bool;
59        fn start(self: Pin<&mut DesktopCapturer>, callback: Box<DesktopCapturerCallbackWrapper>);
60
61        fn width(self: &DesktopFrame) -> i32;
62        fn height(self: &DesktopFrame) -> i32;
63        fn stride(self: &DesktopFrame) -> i32;
64        fn left(self: &DesktopFrame) -> i32;
65        fn top(self: &DesktopFrame) -> i32;
66        fn data(self: &DesktopFrame) -> *const u8;
67    }
68
69    extern "Rust" {
70        type DesktopCapturerCallbackWrapper;
71
72        fn on_capture_result(
73            self: &mut DesktopCapturerCallbackWrapper,
74            result: CaptureResult,
75            frame: UniquePtr<DesktopFrame>,
76        );
77    }
78}
79
80impl_thread_safety!(ffi::DesktopCapturer, Send + Sync);
81
82#[derive(Debug, PartialEq)]
83pub enum CaptureError {
84    Temporary,
85    Permanent,
86}
87
88pub trait DesktopCapturerCallback: Send {
89    fn on_capture_result(&mut self, result: Result<UniquePtr<DesktopFrame>, CaptureError>);
90}
91
92pub struct DesktopCapturerCallbackWrapper {
93    callback: Box<dyn DesktopCapturerCallback>,
94}
95
96impl DesktopCapturerCallbackWrapper {
97    pub fn new(callback: Box<dyn DesktopCapturerCallback>) -> Self {
98        Self { callback }
99    }
100
101    fn on_capture_result(&mut self, result: CaptureResult, frame: UniquePtr<DesktopFrame>) {
102        match result {
103            CaptureResult::Success => self.callback.on_capture_result(Ok(frame)),
104            CaptureResult::ErrorTemporary => {
105                self.callback.on_capture_result(Err(CaptureError::Temporary))
106            }
107            CaptureResult::ErrorPermanent => {
108                self.callback.on_capture_result(Err(CaptureError::Permanent))
109            }
110            _ => self.callback.on_capture_result(Err(CaptureError::Permanent)),
111        }
112    }
113}