darn node modueles

This commit is contained in:
Nickiel12 2024-08-17 20:11:59 +00:00
parent fcd782140e
commit f00e981a3c
14 changed files with 104 additions and 228 deletions

1
.gitignore vendored
View file

@ -2,3 +2,4 @@ target
settings.toml
.direnv/*
logs/*
ui/static/node_modules/*

5
Cargo.lock generated
View file

@ -2046,9 +2046,9 @@ dependencies = [
[[package]]
name = "lazy_static"
version = "1.4.0"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "libc"
@ -4265,6 +4265,7 @@ dependencies = [
"gilrs",
"gstreamer",
"gstreamer-app",
"lazy_static",
"log",
"serde",
"serde_json",

View file

@ -37,5 +37,6 @@ tracing-appender = "0.2.3"
snafu = "0.8.2"
console-subscriber = "0.3.0"
tauri = { version = "1.6.1", features = [] }
lazy_static = "1.5.0"

View file

@ -84,6 +84,7 @@ Some utility commands:
cargo-tauri
cargo-edit
bacon
typescript # .js language server
] ++ tauri_packages;
inputsFrom = with self.packages.${system}; [ joystick-controller-client ];
shellHook =

View file

@ -58,6 +58,7 @@ pub enum ApplicationEvent {
SocketMessage(Message),
MoveEvent(MoveEvent, ConnectionType),
TrackerUpdate(TrackerUpdate),
WebRTCMessage(String),
Close,
}
@ -131,6 +132,9 @@ pub async fn start_coordinator(
}
}
}
ApplicationEvent::WebRTCMessage(msg) => {
info!("Pew pew! WebRTCMessage! {msg}");
}
ApplicationEvent::TrackerUpdate(update) => match update {
TrackerUpdate::Clear => {
state.tracker_state.clear();

View file

@ -1,9 +1,12 @@
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
use std::sync::Arc;
use std::sync::{Arc, Mutex};
use async_channel::Sender;
use tokio::{runtime, sync:: RwLock};
use tracing::{self, info};
use tracing::{self, info, error};
use tauri::Manager;
use lazy_static::lazy_static;
#[cfg(not(debug_assertions))]
use tracing_subscriber;
@ -19,6 +22,10 @@ mod tauri_functions;
use coordinator::{start_coordinator, ApplicationEvent};
lazy_static! {
static ref TO_MEC_REF: Mutex<Option<Sender<ApplicationEvent>>> = Mutex::new(None);
}
fn main() {
#[cfg(not(debug_assertions))]
@ -43,6 +50,7 @@ fn main() {
console_subscriber::init();
}
let (to_mec, mec) = async_channel::bounded::<ApplicationEvent>(10);
info!("Logging intialized");
@ -53,8 +61,6 @@ fn main() {
let rt = runtime::Runtime::new().expect("Could not start tokio runtime");
let handle = rt.handle().clone();
let (to_mec, mec) = async_channel::bounded::<ApplicationEvent>(10);
let _coordinator = rt.handle().spawn(start_coordinator(
mec,
to_mec.clone(),
@ -62,9 +68,35 @@ fn main() {
config
));
*TO_MEC_REF.lock().unwrap() = Some(to_mec.clone());
tauri::Builder::default()
.manage(tauri_functions::TauriState { to_mec: to_mec.clone() })
.invoke_handler(tauri::generate_handler![tauri_functions::connect_to_camera])
.setup(|app| {
let _id = app.listen_global("webrtc-event", |event| {
match event.payload() {
Some(payload) => {
if let Ok(e) = TO_MEC_REF.lock() {
match e.as_ref() {
Some(to_mec) => {
if let Err(e) = to_mec.send_blocking(ApplicationEvent::WebRTCMessage(payload.to_string())) {
error!("Could not send to mec! {e}");
}
},
None => {
error!("TO_MEC_REF was none!");
}
}
}
}
None => {
info!("There was an empty payload!");
}
}
});
Ok(())
})
.run(tauri::generate_context!())
.expect("error while running tauri application");

View file

@ -12,6 +12,5 @@ pub struct TauriState {
#[tauri::command]
pub fn connect_to_camera(state: State<'_, TauriState>) {
let _ = state.to_mec.send_blocking(ApplicationEvent::CameraConnectionPress);
}

View file

@ -4,7 +4,6 @@
<link href="/static/main.css" rel="stylesheet"/>
<script src="/static/feather.min.js"></script>
<script src="/static/index.js"></script>
<script src="/static/gstwebrtc-api-2-0-0.js"></script>
</head>
<body>

View file

@ -1,206 +0,0 @@
function initCapture(api) {
const captureSection = document.getElementById("capture");
const clientIdElement = captureSection.querySelector(".client-id");
const videoElement = captureSection.getElementsByTagName("video")[0];
const listener = {
connected: function(clientId) { clientIdElement.textContent = clientId; },
disconnected: function() { clientIdElement.textContent = "none"; }
};
api.registerConnectionListener(listener);
document.getElementById("capture-button").addEventListener("click", (event) => {
event.preventDefault();
if (captureSection._producerSession) {
captureSection._producerSession.close();
} else if (!captureSection.classList.contains("starting")) {
captureSection.classList.add("starting");
const constraints = {
video: { width: 1280, height: 720 }
};
navigator.mediaDevices.getUserMedia(constraints).then((stream) => {
const session = api.createProducerSession(stream);
if (session) {
captureSection._producerSession = session;
session.addEventListener("error", (event) => {
if (captureSection._producerSession === session) {
console.error(event.message, event.error);
}
});
session.addEventListener("closed", () => {
if (captureSection._producerSession === session) {
videoElement.pause();
videoElement.srcObject = null;
captureSection.classList.remove("has-session", "starting");
delete captureSection._producerSession;
}
});
session.addEventListener("stateChanged", (event) => {
if ((captureSection._producerSession === session) &&
(event.target.state === GstWebRTCAPI.SessionState.streaming)) {
videoElement.srcObject = stream;
videoElement.play().catch(() => {});
captureSection.classList.remove("starting");
}
});
session.addEventListener("clientConsumerAdded", (event) => {
if (captureSection._producerSession === session) {
console.info(`client consumer added: ${event.detail.peerId}`);
}
});
session.addEventListener("clientConsumerRemoved", (event) => {
if (captureSection._producerSession === session) {
console.info(`client consumer removed: ${event.detail.peerId}`);
}
});
captureSection.classList.add("has-session");
session.start();
} else {
for (const track of stream.getTracks()) {
track.stop();
}
captureSection.classList.remove("starting");
}
}).catch((error) => {
console.error("cannot have access to webcam and microphone", error);
captureSection.classList.remove("starting");
});
}
});
}
function initRemoteStreams(api) {
const remoteStreamsElement = document.getElementById("remote-streams");
const listener = {
producerAdded: function(producer) {
const producerId = producer.id
if (!document.getElementById(producerId)) {
remoteStreamsElement.insertAdjacentHTML("beforeend",
`<li id="${producerId}">
<div class="button">${producer.meta.name || producerId}</div>
<div class="video">
<div class="spinner">
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<span class="remote-control">&#xA9;</span>
<video></video>
<div class="fullscreen"><span title="Toggle fullscreen">&#x25A2;</span></div>
</div>
</li>`);
const entryElement = document.getElementById(producerId);
const videoElement = entryElement.getElementsByTagName("video")[0];
videoElement.addEventListener("playing", () => {
if (entryElement.classList.contains("has-session")) {
entryElement.classList.add("streaming");
}
});
entryElement.addEventListener("click", (event) => {
event.preventDefault();
if (!event.target.classList.contains("button")) {
return;
}
if (entryElement._consumerSession) {
entryElement._consumerSession.close();
} else {
const session = api.createConsumerSession(producerId);
if (session) {
entryElement._consumerSession = session;
session.addEventListener("error", (event) => {
if (entryElement._consumerSession === session) {
console.error(event.message, event.error);
}
});
session.addEventListener("closed", () => {
if (entryElement._consumerSession === session) {
videoElement.pause();
videoElement.srcObject = null;
entryElement.classList.remove("has-session", "streaming", "has-remote-control");
delete entryElement._consumerSession;
}
});
session.addEventListener("streamsChanged", () => {
if (entryElement._consumerSession === session) {
const streams = session.streams;
if (streams.length > 0) {
videoElement.srcObject = streams[0];
videoElement.play().catch(() => {});
}
}
});
session.addEventListener("remoteControllerChanged", () => {
if (entryElement._consumerSession === session) {
const remoteController = session.remoteController;
if (remoteController) {
entryElement.classList.add("has-remote-control");
remoteController.attachVideoElement(videoElement);
} else {
entryElement.classList.remove("has-remote-control");
}
}
});
entryElement.classList.add("has-session");
session.connect();
}
}
});
}
},
producerRemoved: function(producer) {
const element = document.getElementById(producer.id);
if (element) {
if (element._consumerSession) {
element._consumerSession.close();
}
element.remove();
}
}
};
api.registerProducersListener(listener);
for (const producer of api.getAvailableProducers()) {
listener.producerAdded(producer);
}
}
window.addEventListener("DOMContentLoaded", () => {
document.addEventListener("click", (event) => {
if (event.target.matches("div.video>div.fullscreen:hover>span")) {
event.preventDefault();
event.target.parentNode.previousElementSibling.requestFullscreen();
}
});
const signalingProtocol = window.location.protocol.startsWith("https") ? "wss" : "ws";
const gstWebRTCConfig = {
meta: { name: `WebClient-${Date.now()}` },
signalingServerUrl: `ws://127.0.0.1:8443`,
};
const api = new GstWebRTCAPI(gstWebRTCConfig);
// initCapture(api);
initRemoteStreams(api);
});

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

30
ui/static/package-lock.json generated Normal file
View file

@ -0,0 +1,30 @@
{
"name": "vcs-controller",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "vcs-controller",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"@tauri-apps/api": "^1.6.0"
}
},
"node_modules/@tauri-apps/api": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-1.6.0.tgz",
"integrity": "sha512-rqI++FWClU5I2UBp4HXFvl+sBWkdigBkxnpJDQUWttNyG7IZP4FwQGhTNL5EOw0vI8i6eSAJ5frLqO7n7jbJdg==",
"engines": {
"node": ">= 14.6.0",
"npm": ">= 6.6.0",
"yarn": ">= 1.19.1"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/tauri"
}
}
}
}

14
ui/static/package.json Normal file
View file

@ -0,0 +1,14 @@
{
"name": "vcs-controller",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"description": "",
"dependencies": {
"@tauri-apps/api": "^1.6.0"
}
}

View file

@ -1,4 +1,6 @@
import { emit, listen } from '@tauri-apps/api/event';
const videoview = document.getElementById("remoteview");
const config = {
@ -6,11 +8,8 @@ const config = {
};
const polite = true;
const signaler = new SignalingChannel();
const pc = new RTCPeerConnection(config);
const constraints = { audio: false, video: true };
pc.ontrack = ({ track, streams }) => {
track.onunmute = () => {
if (remoteview.srcObject) {
@ -26,7 +25,7 @@ pc.onnegotionationneeded = async () => {
try {
makingOffer = true;
await pc.setLocalDescription();
signaler.send({ description: pc.localDescription });
emit("webrtc-event", { description: pc.localDescription });
} catch (err) {
console.error(err);
} finally {
@ -34,7 +33,7 @@ pc.onnegotionationneeded = async () => {
}
};
pc.onicecandidate = ({ candidate }) => signaler.send({ candidate });
pc.onicecandidate = ({ candidate }) => emit("webrtc-event", { candidate });
pc.oniceconnectionstatechange = () => {
if (pc.iceConnectionState === "failed") {
pc.restartIce();
@ -43,7 +42,12 @@ pc.oniceconnectionstatechange = () => {
let ignoreOffer = false;
signaler.onmessage = async ({ data: { description, candidate } }) => {
const application_message = await listen('frontend_message', async (event) => {
console.log("Event: ");
console.log(event);
const { description, candidate } = event.payload.data;
try {
if (description) {
const offerCollision =
@ -59,7 +63,7 @@ signaler.onmessage = async ({ data: { description, candidate } }) => {
await pc.setRemoteDescription(description);
if (description.type === "offer") {
await pc.setLocalDescription();
signaler.send({ description: pc.localDescription });
emit( "webrtc-event", { description: pc.localDescription });
}
} else if (candidate) {
try {
@ -73,7 +77,9 @@ signaler.onmessage = async ({ data: { description, candidate } }) => {
} catch (err) {
console.error(err);
}
};
});
async function start_rtc_connection() {
}