143 lines
4.3 KiB
Rust
143 lines
4.3 KiB
Rust
mod live_kit_token;
|
|
|
|
use futures::StreamExt;
|
|
use gpui::{
|
|
actions,
|
|
elements::{Canvas, *},
|
|
keymap::Binding,
|
|
platform::current::Surface,
|
|
Menu, MenuItem, ViewContext,
|
|
};
|
|
use live_kit::{LocalVideoTrack, Room};
|
|
use log::LevelFilter;
|
|
use media::core_video::CVImageBuffer;
|
|
use postage::watch;
|
|
use simplelog::SimpleLogger;
|
|
use std::sync::Arc;
|
|
|
|
actions!(capture, [Quit]);
|
|
|
|
fn main() {
|
|
SimpleLogger::init(LevelFilter::Info, Default::default()).expect("could not initialize logger");
|
|
|
|
gpui::App::new(()).unwrap().run(|cx| {
|
|
cx.platform().activate(true);
|
|
cx.add_global_action(quit);
|
|
|
|
cx.add_bindings([Binding::new("cmd-q", Quit, None)]);
|
|
cx.set_menus(vec![Menu {
|
|
name: "Zed",
|
|
items: vec![MenuItem::Action {
|
|
name: "Quit",
|
|
action: Box::new(Quit),
|
|
}],
|
|
}]);
|
|
|
|
let live_kit_url = std::env::var("LIVE_KIT_URL").unwrap();
|
|
let live_kit_key = std::env::var("LIVE_KIT_KEY").unwrap();
|
|
let live_kit_secret = std::env::var("LIVE_KIT_SECRET").unwrap();
|
|
|
|
cx.spawn(|mut cx| async move {
|
|
let user1_token = live_kit_token::create_token(
|
|
&live_kit_key,
|
|
&live_kit_secret,
|
|
"test-room",
|
|
"test-participant-1",
|
|
)
|
|
.unwrap();
|
|
let room1 = Room::new();
|
|
room1.connect(&live_kit_url, &user1_token).await.unwrap();
|
|
|
|
let user2_token = live_kit_token::create_token(
|
|
&live_kit_key,
|
|
&live_kit_secret,
|
|
"test-room",
|
|
"test-participant-2",
|
|
)
|
|
.unwrap();
|
|
let room2 = Room::new();
|
|
room2.connect(&live_kit_url, &user2_token).await.unwrap();
|
|
cx.add_window(Default::default(), |cx| ScreenCaptureView::new(room2, cx));
|
|
|
|
let windows = live_kit::list_windows();
|
|
let window = windows
|
|
.iter()
|
|
.find(|w| w.owner_name.as_deref() == Some("Safari"))
|
|
.unwrap();
|
|
let track = LocalVideoTrack::screen_share_for_window(window.id);
|
|
room1.publish_video_track(&track).await.unwrap();
|
|
})
|
|
.detach();
|
|
});
|
|
}
|
|
|
|
struct ScreenCaptureView {
|
|
image_buffer: Option<CVImageBuffer>,
|
|
_room: Arc<Room>,
|
|
}
|
|
|
|
impl gpui::Entity for ScreenCaptureView {
|
|
type Event = ();
|
|
}
|
|
|
|
impl ScreenCaptureView {
|
|
pub fn new(room: Arc<Room>, cx: &mut ViewContext<Self>) -> Self {
|
|
let mut remote_video_tracks = room.remote_video_tracks();
|
|
cx.spawn_weak(|this, mut cx| async move {
|
|
if let Some(video_track) = remote_video_tracks.next().await {
|
|
let (mut frames_tx, mut frames_rx) = watch::channel_with(None);
|
|
video_track.add_renderer(move |frame| *frames_tx.borrow_mut() = Some(frame));
|
|
|
|
while let Some(frame) = frames_rx.next().await {
|
|
if let Some(this) = this.upgrade(&cx) {
|
|
this.update(&mut cx, |this, cx| {
|
|
this.image_buffer = frame;
|
|
cx.notify();
|
|
});
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
})
|
|
.detach();
|
|
|
|
Self {
|
|
image_buffer: None,
|
|
_room: room,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl gpui::View for ScreenCaptureView {
|
|
fn ui_name() -> &'static str {
|
|
"View"
|
|
}
|
|
|
|
fn render(&mut self, _: &mut gpui::RenderContext<Self>) -> gpui::ElementBox {
|
|
let image_buffer = self.image_buffer.clone();
|
|
let canvas = Canvas::new(move |bounds, _, cx| {
|
|
if let Some(image_buffer) = image_buffer.clone() {
|
|
cx.scene.push_surface(Surface {
|
|
bounds,
|
|
image_buffer,
|
|
});
|
|
}
|
|
});
|
|
|
|
if let Some(image_buffer) = self.image_buffer.as_ref() {
|
|
canvas
|
|
.constrained()
|
|
.with_width(image_buffer.width() as f32)
|
|
.with_height(image_buffer.height() as f32)
|
|
.aligned()
|
|
.boxed()
|
|
} else {
|
|
canvas.boxed()
|
|
}
|
|
}
|
|
}
|
|
|
|
fn quit(_: &Quit, cx: &mut gpui::MutableAppContext) {
|
|
cx.platform().quit();
|
|
}
|