1mod live_kit_token;
2
3use futures::StreamExt;
4use gpui::{
5 actions,
6 elements::{Canvas, *},
7 keymap::Binding,
8 platform::current::Surface,
9 Menu, MenuItem, ViewContext,
10};
11use live_kit::{LocalVideoTrack, Room};
12use log::LevelFilter;
13use media::core_video::CVImageBuffer;
14use simplelog::SimpleLogger;
15use std::sync::Arc;
16
17actions!(capture, [Quit]);
18
19fn main() {
20 SimpleLogger::init(LevelFilter::Info, Default::default()).expect("could not initialize logger");
21
22 gpui::App::new(()).unwrap().run(|cx| {
23 cx.platform().activate(true);
24 cx.add_global_action(quit);
25
26 cx.add_bindings([Binding::new("cmd-q", Quit, None)]);
27 cx.set_menus(vec![Menu {
28 name: "Zed",
29 items: vec![MenuItem::Action {
30 name: "Quit",
31 action: Box::new(Quit),
32 }],
33 }]);
34
35 let live_kit_url = std::env::var("LIVE_KIT_URL").unwrap();
36 let live_kit_key = std::env::var("LIVE_KIT_KEY").unwrap();
37 let live_kit_secret = std::env::var("LIVE_KIT_SECRET").unwrap();
38
39 cx.spawn(|mut cx| async move {
40 let user1_token = live_kit_token::create_token(
41 &live_kit_key,
42 &live_kit_secret,
43 "test-room",
44 "test-participant-1",
45 )
46 .unwrap();
47 let room1 = Room::new();
48 room1.connect(&live_kit_url, &user1_token).await.unwrap();
49
50 let user2_token = live_kit_token::create_token(
51 &live_kit_key,
52 &live_kit_secret,
53 "test-room",
54 "test-participant-2",
55 )
56 .unwrap();
57 let room2 = Room::new();
58 room2.connect(&live_kit_url, &user2_token).await.unwrap();
59 cx.add_window(Default::default(), |cx| ScreenCaptureView::new(room2, cx));
60
61 let windows = live_kit::list_windows();
62 let window = windows
63 .iter()
64 .find(|w| w.owner_name.as_deref() == Some("Safari"))
65 .unwrap();
66 let track = LocalVideoTrack::screen_share_for_window(window.id);
67 room1.publish_video_track(&track).await.unwrap();
68
69 std::mem::forget(track);
70 std::mem::forget(room1);
71 })
72 .detach();
73 });
74}
75
76struct ScreenCaptureView {
77 image_buffer: Option<CVImageBuffer>,
78 _room: Arc<Room>,
79}
80
81impl gpui::Entity for ScreenCaptureView {
82 type Event = ();
83}
84
85impl ScreenCaptureView {
86 pub fn new(room: Arc<Room>, cx: &mut ViewContext<Self>) -> Self {
87 let mut remote_video_tracks = room.remote_video_tracks();
88 cx.spawn_weak(|this, mut cx| async move {
89 if let Some(video_track) = remote_video_tracks.next().await {
90 video_track.add_renderer(move |frame| {
91 if let Some(this) = this.upgrade(&cx) {
92 this.update(&mut cx, |this, cx| {
93 this.image_buffer = Some(frame);
94 cx.notify();
95 });
96 }
97 });
98 }
99 })
100 .detach();
101 Self {
102 image_buffer: None,
103 _room: room,
104 }
105 }
106}
107
108impl gpui::View for ScreenCaptureView {
109 fn ui_name() -> &'static str {
110 "View"
111 }
112
113 fn render(&mut self, _: &mut gpui::RenderContext<Self>) -> gpui::ElementBox {
114 let image_buffer = self.image_buffer.clone();
115 Canvas::new(move |bounds, _, cx| {
116 if let Some(image_buffer) = image_buffer.clone() {
117 cx.scene.push_surface(Surface {
118 bounds,
119 image_buffer,
120 });
121 }
122 })
123 .boxed()
124 }
125}
126
127fn quit(_: &Quit, cx: &mut gpui::MutableAppContext) {
128 cx.platform().quit();
129}