2022-10-18 05:24:48 +00:00
|
|
|
use futures::StreamExt;
|
|
|
|
use gpui::{
|
|
|
|
actions,
|
|
|
|
elements::{Canvas, *},
|
|
|
|
keymap::Binding,
|
|
|
|
platform::current::Surface,
|
|
|
|
Menu, MenuItem, ViewContext,
|
|
|
|
};
|
|
|
|
use live_kit_client::{LocalVideoTrack, RemoteVideoTrackUpdate, Room};
|
2022-10-19 14:35:34 +00:00
|
|
|
use live_kit_server::{
|
|
|
|
api::Client,
|
|
|
|
token::{self, VideoGrant},
|
|
|
|
};
|
2022-10-18 05:24:48 +00:00
|
|
|
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_or("http://localhost:7880".into());
|
|
|
|
let live_kit_key = std::env::var("LIVE_KIT_KEY").unwrap_or("devkey".into());
|
|
|
|
let live_kit_secret = std::env::var("LIVE_KIT_SECRET").unwrap_or("secret".into());
|
|
|
|
|
|
|
|
cx.spawn(|cx| async move {
|
|
|
|
let user_a_token = token::create(
|
|
|
|
&live_kit_key,
|
|
|
|
&live_kit_secret,
|
|
|
|
Some("test-participant-1"),
|
|
|
|
VideoGrant::to_join("test-room"),
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
let room_a = Room::new();
|
|
|
|
room_a.connect(&live_kit_url, &user_a_token).await.unwrap();
|
|
|
|
|
|
|
|
let user2_token = token::create(
|
|
|
|
&live_kit_key,
|
|
|
|
&live_kit_secret,
|
|
|
|
Some("test-participant-2"),
|
|
|
|
VideoGrant::to_join("test-room"),
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
let room_b = Room::new();
|
|
|
|
room_b.connect(&live_kit_url, &user2_token).await.unwrap();
|
|
|
|
|
|
|
|
let mut track_changes = room_b.remote_video_track_updates();
|
|
|
|
|
2022-10-18 05:38:43 +00:00
|
|
|
let displays = live_kit_client::display_sources().await.unwrap();
|
|
|
|
let display = displays.into_iter().next().unwrap();
|
2022-10-18 05:24:48 +00:00
|
|
|
|
|
|
|
let track_a = LocalVideoTrack::screen_share_for_display(&display);
|
2022-10-19 08:29:03 +00:00
|
|
|
let track_a_publication = room_a.publish_video_track(&track_a).await.unwrap();
|
2022-10-18 05:24:48 +00:00
|
|
|
|
2022-10-19 08:29:03 +00:00
|
|
|
if let RemoteVideoTrackUpdate::Subscribed(track) = track_changes.next().await.unwrap() {
|
2022-10-18 05:24:48 +00:00
|
|
|
let remote_tracks = room_b.remote_video_tracks("test-participant-1");
|
|
|
|
assert_eq!(remote_tracks.len(), 1);
|
|
|
|
assert_eq!(remote_tracks[0].publisher_id(), "test-participant-1");
|
2022-10-18 05:38:43 +00:00
|
|
|
assert_eq!(track.publisher_id(), "test-participant-1");
|
2022-10-18 05:24:48 +00:00
|
|
|
} else {
|
2022-10-19 08:29:03 +00:00
|
|
|
panic!("unexpected message");
|
|
|
|
}
|
|
|
|
|
|
|
|
let remote_track = room_b
|
|
|
|
.remote_video_tracks("test-participant-1")
|
|
|
|
.pop()
|
|
|
|
.unwrap();
|
|
|
|
room_a.unpublish_track(track_a_publication);
|
|
|
|
if let RemoteVideoTrackUpdate::Unsubscribed {
|
|
|
|
publisher_id,
|
|
|
|
track_id,
|
|
|
|
} = track_changes.next().await.unwrap()
|
|
|
|
{
|
|
|
|
assert_eq!(publisher_id, "test-participant-1");
|
|
|
|
assert_eq!(remote_track.sid(), track_id);
|
|
|
|
assert_eq!(room_b.remote_video_tracks("test-participant-1").len(), 0);
|
|
|
|
} else {
|
|
|
|
panic!("unexpected message");
|
2022-10-18 05:24:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
cx.platform().quit();
|
|
|
|
})
|
|
|
|
.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_track_updates();
|
|
|
|
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();
|
|
|
|
}
|