use callbacks on internal events (#100)
This commit is contained in:
Generated
+27
-6
@@ -641,7 +641,8 @@ checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
|
||||
[[package]]
|
||||
name = "ecolor"
|
||||
version = "0.22.0"
|
||||
source = "git+https://github.com/emilk/egui#307565efa55158cfa6b82d2e8fdc4c4914b954ed"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e479a7fa3f23d4e794f8b2f8b3568dd4e47886ad1b12c9c095e141cb591eb63"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
]
|
||||
@@ -649,7 +650,8 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "egui"
|
||||
version = "0.22.0"
|
||||
source = "git+https://github.com/emilk/egui#307565efa55158cfa6b82d2e8fdc4c4914b954ed"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3aef8ec3ae1b772f340170c65bf27d5b8c28f543a0116c844d2ac08d01123e7"
|
||||
dependencies = [
|
||||
"ahash 0.8.3",
|
||||
"epaint",
|
||||
@@ -660,7 +662,8 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "egui-wgpu"
|
||||
version = "0.22.0"
|
||||
source = "git+https://github.com/emilk/egui#307565efa55158cfa6b82d2e8fdc4c4914b954ed"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33caaedd8283779c787298af23d8754a7e88421ff32e89ad0040c855fc0b0224"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"epaint",
|
||||
@@ -674,7 +677,8 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "egui-winit"
|
||||
version = "0.22.0"
|
||||
source = "git+https://github.com/emilk/egui#307565efa55158cfa6b82d2e8fdc4c4914b954ed"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a49155fd4a0a4fb21224407a91de0030847972ef90fc64edb63621caea61cb2"
|
||||
dependencies = [
|
||||
"arboard",
|
||||
"egui",
|
||||
@@ -695,7 +699,8 @@ checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
|
||||
[[package]]
|
||||
name = "emath"
|
||||
version = "0.22.0"
|
||||
source = "git+https://github.com/emilk/egui#307565efa55158cfa6b82d2e8fdc4c4914b954ed"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3857d743a6e0741cdd60b622a74c7a36ea75f5f8f11b793b41d905d2c9721a4b"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
]
|
||||
@@ -725,7 +730,8 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "epaint"
|
||||
version = "0.22.0"
|
||||
source = "git+https://github.com/emilk/egui#307565efa55158cfa6b82d2e8fdc4c4914b954ed"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09333964d4d57f40a85338ba3ca5ed4716070ab184dcfed966b35491c5c64f3b"
|
||||
dependencies = [
|
||||
"ab_glyph",
|
||||
"ahash 0.8.3",
|
||||
@@ -2016,10 +2022,13 @@ version = "0.9.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"petgraph",
|
||||
"redox_syscall 0.2.16",
|
||||
"smallvec",
|
||||
"thread-id",
|
||||
"windows-sys 0.45.0",
|
||||
]
|
||||
|
||||
@@ -2753,6 +2762,17 @@ dependencies = [
|
||||
"syn 2.0.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread-id"
|
||||
version = "4.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ee93aa2b8331c0fec9091548843f2c90019571814057da3b783f9de09349d73"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"redox_syscall 0.2.16",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "1.1.7"
|
||||
@@ -3420,6 +3440,7 @@ dependencies = [
|
||||
"futures",
|
||||
"image",
|
||||
"livekit",
|
||||
"log",
|
||||
"parking_lot",
|
||||
"tokio",
|
||||
"tracing",
|
||||
|
||||
@@ -11,8 +11,9 @@ livekit = { path = "../../livekit", version = "0.1.1" }
|
||||
futures = "0.3"
|
||||
wgpu = "0.16"
|
||||
winit = "0.28"
|
||||
parking_lot = { version = "0.12.1", features=["send_guard"] }
|
||||
parking_lot = { version = "0.12.1", features=["deadlock_detection"] }
|
||||
image = "0.24"
|
||||
egui = { git = "https://github.com/emilk/egui" }
|
||||
egui-wgpu = { git = "https://github.com/emilk/egui", features = ["winit"] }
|
||||
egui-winit = { git = "https://github.com/emilk/egui" }
|
||||
egui = "0.22"
|
||||
egui-wgpu = { version = "0.22", features = ["winit"] }
|
||||
egui-winit = "0.22"
|
||||
log = "0.4"
|
||||
@@ -9,37 +9,38 @@ use futures::StreamExt;
|
||||
use livekit::prelude::*;
|
||||
use livekit::webrtc::audio_stream::native::NativeAudioStream;
|
||||
use livekit::SimulateScenario;
|
||||
use parking_lot::deadlock;
|
||||
use parking_lot::Mutex;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
use std::sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
Arc,
|
||||
};
|
||||
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
use tokio::sync::Mutex as AsyncMutex;
|
||||
use tokio::sync::{mpsc, oneshot};
|
||||
|
||||
// Useful default constants for developing
|
||||
const DEFAULT_URL: &str = "ws://localhost:7880";
|
||||
const DEFAULT_TOKEN : &str = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE5MDY2MTMyODgsImlzcyI6IkFQSVRzRWZpZFpqclFvWSIsIm5hbWUiOiJuYXRpdmUiLCJuYmYiOjE2NzI2MTMyODgsInN1YiI6Im5hdGl2ZSIsInZpZGVvIjp7InJvb20iOiJ0ZXN0Iiwicm9vbUFkbWluIjp0cnVlLCJyb29tQ3JlYXRlIjp0cnVlLCJyb29tSm9pbiI6dHJ1ZSwicm9vbUxpc3QiOnRydWV9fQ.uSNIangMRu8jZD5mnRYoCHjcsQWCrJXgHCs0aNIgBFY";
|
||||
|
||||
// eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE5MDY2MTM0MzcsImlzcyI6IkFQSVRzRWZpZFpqclFvWSIsIm5hbWUiOiJ3ZWIiLCJuYmYiOjE2NzI2MTM0MzcsInN1YiI6IndlYiIsInZpZGVvIjp7InJvb20iOiJ0ZXN0Iiwicm9vbUFkbWluIjp0cnVlLCJyb29tQ3JlYXRlIjp0cnVlLCJyb29tSm9pbiI6dHJ1ZSwicm9vbUxpc3QiOnRydWV9fQ.DFTXt60n1kzGq4cSuOhbFBTQW2nd3rlcXKQ54sXsP8s
|
||||
|
||||
use winit::{
|
||||
event::*,
|
||||
event_loop::{ControlFlow, EventLoop},
|
||||
window::{WindowBuilder, WindowId},
|
||||
};
|
||||
|
||||
struct Session {
|
||||
struct SessionHandle {
|
||||
room: Arc<Room>,
|
||||
logo_track: LogoTrack,
|
||||
sine_track: SineTrack,
|
||||
logo_track: Arc<AsyncMutex<LogoTrack>>,
|
||||
sine_track: Arc<AsyncMutex<SineTrack>>,
|
||||
close_tx: oneshot::Sender<()>,
|
||||
handle: tokio::task::JoinHandle<()>,
|
||||
task_handle: tokio::task::JoinHandle<()>,
|
||||
}
|
||||
|
||||
struct AppState {
|
||||
session: Mutex<Option<Session>>,
|
||||
session: Mutex<Option<SessionHandle>>,
|
||||
connecting: AtomicBool,
|
||||
}
|
||||
|
||||
@@ -54,11 +55,14 @@ struct App {
|
||||
cmd_tx: mpsc::UnboundedSender<AsyncCmd>,
|
||||
cmd_rx: mpsc::UnboundedReceiver<UiCmd>,
|
||||
|
||||
// UI State
|
||||
// Ui State
|
||||
lk_url: String,
|
||||
lk_token: String,
|
||||
connection_failure: Option<String>,
|
||||
room_state: ConnectionState,
|
||||
|
||||
// Log events
|
||||
events: Vec<String>,
|
||||
}
|
||||
|
||||
pub fn run(rt: tokio::runtime::Runtime) {
|
||||
@@ -97,8 +101,26 @@ pub fn run(rt: tokio::runtime::Runtime) {
|
||||
lk_token: DEFAULT_TOKEN.to_owned(),
|
||||
connection_failure: None,
|
||||
room_state: ConnectionState::Connected,
|
||||
events: Vec::new(),
|
||||
};
|
||||
|
||||
// Create a background thread which checks for deadlocks every 10s
|
||||
thread::spawn(move || loop {
|
||||
thread::sleep(Duration::from_secs(10));
|
||||
let deadlocks = deadlock::check_deadlock();
|
||||
if deadlocks.is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
log::error!("{} deadlocks detected", deadlocks.len());
|
||||
for (i, threads) in deadlocks.iter().enumerate() {
|
||||
log::error!("Deadlock #{}", i);
|
||||
for t in threads {
|
||||
log::error!("Thread Id {:#?}: \n{:#?}", t.thread_id(), t.backtrace());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Async event loop
|
||||
tokio::spawn(async move {
|
||||
while let Some(event) = async_cmd_rx.recv().await {
|
||||
@@ -112,19 +134,19 @@ pub fn run(rt: tokio::runtime::Runtime) {
|
||||
let (close_tx, close_rx) = oneshot::channel();
|
||||
let logo_track = LogoTrack::new(room.clone());
|
||||
let sine_track = SineTrack::new(room.clone());
|
||||
let handle = tokio::spawn(room_task(
|
||||
let task_handle = tokio::spawn(room_task(
|
||||
state.clone(),
|
||||
room_events,
|
||||
close_rx,
|
||||
ui_cmd_tx.clone(),
|
||||
));
|
||||
|
||||
*state.session.lock() = Some(Session {
|
||||
*state.session.lock() = Some(SessionHandle {
|
||||
room,
|
||||
logo_track,
|
||||
sine_track,
|
||||
logo_track: Arc::new(AsyncMutex::new(logo_track)),
|
||||
sine_track: Arc::new(AsyncMutex::new(sine_track)),
|
||||
close_tx,
|
||||
handle,
|
||||
task_handle,
|
||||
});
|
||||
|
||||
let _ = ui_cmd_tx.send(UiCmd::ConnectResult { result: Ok(()) });
|
||||
@@ -135,20 +157,37 @@ pub fn run(rt: tokio::runtime::Runtime) {
|
||||
state.connecting.store(false, Ordering::SeqCst);
|
||||
}
|
||||
AsyncCmd::RoomDisconnect => {
|
||||
if let Some(session) = state.session.lock().take() {
|
||||
let _ = session.room.close().await;
|
||||
let _ = session.close_tx.send(());
|
||||
let _ = session.handle.await;
|
||||
let handle = state.session.lock().take();
|
||||
if let Some(handle) = handle {
|
||||
let _ = handle.room.close().await;
|
||||
let _ = handle.close_tx.send(());
|
||||
let _ = handle.task_handle.await;
|
||||
}
|
||||
}
|
||||
AsyncCmd::SimulateScenario { scenario } => {
|
||||
if let Some(session) = state.session.lock().as_ref() {
|
||||
let _ = session.room.simulate_scenario(scenario).await;
|
||||
let room = {
|
||||
state
|
||||
.session
|
||||
.lock()
|
||||
.as_ref()
|
||||
.map(|handle| handle.room.clone())
|
||||
};
|
||||
|
||||
if let Some(room) = room {
|
||||
let _ = room.simulate_scenario(scenario).await;
|
||||
}
|
||||
}
|
||||
AsyncCmd::ToggleLogo => {
|
||||
if let Some(session) = state.session.lock().as_mut() {
|
||||
let logo_track = &mut session.logo_track;
|
||||
let logo_track = {
|
||||
state
|
||||
.session
|
||||
.lock()
|
||||
.as_ref()
|
||||
.map(|handle| handle.logo_track.clone())
|
||||
};
|
||||
|
||||
if let Some(logo_track) = logo_track {
|
||||
let mut logo_track = logo_track.lock().await;
|
||||
if !logo_track.is_published() {
|
||||
logo_track.publish().await.unwrap();
|
||||
} else {
|
||||
@@ -157,8 +196,16 @@ pub fn run(rt: tokio::runtime::Runtime) {
|
||||
}
|
||||
}
|
||||
AsyncCmd::ToggleSine => {
|
||||
if let Some(session) = state.session.lock().as_mut() {
|
||||
let sine_track = &mut session.sine_track;
|
||||
let sine_track = {
|
||||
state
|
||||
.session
|
||||
.lock()
|
||||
.as_ref()
|
||||
.map(|handle| handle.sine_track.clone())
|
||||
};
|
||||
|
||||
if let Some(sine_track) = sine_track {
|
||||
let mut sine_track = sine_track.lock().await;
|
||||
if !sine_track.is_published() {
|
||||
sine_track.publish().await.unwrap();
|
||||
} else {
|
||||
@@ -209,6 +256,8 @@ impl App {
|
||||
}
|
||||
}
|
||||
UiCmd::RoomEvent { event } => {
|
||||
self.events.push(format!("{:?}", event));
|
||||
|
||||
match event {
|
||||
RoomEvent::TrackSubscribed {
|
||||
track, participant, ..
|
||||
@@ -229,7 +278,7 @@ impl App {
|
||||
NativeAudioStream::new(audio_track.rtc_track());
|
||||
|
||||
while let Some(_frame) = stream.next().await {
|
||||
// Received audio frames
|
||||
// TODO(theomonnom): Play audio using the libwebrtc ADM playout devices
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -295,12 +344,10 @@ impl App {
|
||||
fn ui(&mut self, ui: &mut egui::Ui) {
|
||||
egui::TopBottomPanel::top("top_panel").show(ui.ctx(), |ui| {
|
||||
egui::menu::bar(ui, |ui| {
|
||||
ui.menu_button("Tools", |ui| {
|
||||
if ui.button("Logs").clicked() {}
|
||||
if ui.button("Profiler").clicked() {}
|
||||
if ui.button("WebRTC Stats").clicked() {}
|
||||
if ui.button("Events").clicked() {}
|
||||
});
|
||||
ui.menu_button(
|
||||
"Tools",
|
||||
|ui| if ui.button("WebRTC Stats (TODO)").clicked() {},
|
||||
);
|
||||
ui.menu_button("Simulate", |ui| {
|
||||
if ui.button("SignalReconnect").clicked() {
|
||||
let _ = self.cmd_tx.send(AsyncCmd::SimulateScenario {
|
||||
@@ -399,21 +446,33 @@ impl App {
|
||||
|
||||
{
|
||||
// Room Info
|
||||
if let Some(session) = self.state.session.lock().as_ref() {
|
||||
ui.label(format!("Name: {}", session.room.name()));
|
||||
ui.label(format!("SID: {}", session.room.sid()));
|
||||
if let Some(handle) = self.state.session.lock().as_ref() {
|
||||
ui.label(format!("Name: {}", handle.room.name()));
|
||||
ui.label(format!("SID: {}", handle.room.sid()));
|
||||
ui.label(format!(
|
||||
"ConnectionState: {:?}",
|
||||
session.room.connection_state()
|
||||
handle.room.connection_state()
|
||||
));
|
||||
ui.label(format!(
|
||||
"ParticipantCount: {:?}",
|
||||
session.room.participants().len() + 1
|
||||
handle.room.participants().len() + 1
|
||||
));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
egui::TopBottomPanel::bottom("bottom_panel")
|
||||
.default_height(128.0)
|
||||
.show(ui.ctx(), |ui| {
|
||||
ui.label("Events");
|
||||
|
||||
egui::ScrollArea::vertical().show(ui, |ui| {
|
||||
for event in &self.events {
|
||||
ui.label(event);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
egui::CentralPanel::default().show(ui.ctx(), |ui| {
|
||||
egui::ScrollArea::vertical().show(ui, |ui| {
|
||||
VideoGrid::new("default_grid")
|
||||
@@ -455,8 +514,8 @@ impl App {
|
||||
}
|
||||
|
||||
let name =
|
||||
self.state.session.lock().as_ref().and_then(|session| {
|
||||
session
|
||||
self.state.session.lock().as_ref().and_then(|handle| {
|
||||
handle
|
||||
.room
|
||||
.participants()
|
||||
.get(participant_sid)
|
||||
|
||||
@@ -72,7 +72,7 @@ impl LogoTrack {
|
||||
.publish_track(
|
||||
LocalTrack::Video(track.clone()),
|
||||
TrackPublishOptions {
|
||||
source: TrackSource::Camera,
|
||||
source: TrackSource::Camera, // Using camera so it is shown on everyone's screen (Unknown is sometimes not shown)
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user