Compare commits

...

10 Commits

Author SHA1 Message Date
4d4591fb2d
Added readme 2023-09-21 12:47:26 +02:00
e5b57dd3d7
Handle error on audio dispatching 2023-09-21 12:31:40 +02:00
d5c8fcd055
Media stream 2023-09-21 12:19:11 +02:00
980d6822d0
support audio 2023-09-21 12:16:12 +02:00
68b20a8b4f
Added log 2023-09-21 12:04:11 +02:00
c5fb07f6da
fix 2023-09-21 11:56:20 +02:00
c4f1e4d8c0
Added video support 2023-09-21 11:52:30 +02:00
d62722ce53
Added cache control 2023-09-21 11:15:06 +02:00
3a3e008e90
Added page examples 2023-09-15 12:06:27 +02:00
74e8731fa4
Take full screen if width and height are not supplied 2023-09-15 12:02:27 +02:00
5 changed files with 55 additions and 10 deletions

View File

@ -1,5 +1,13 @@
# LOLED
```
apt install xorg fluxbox lightdm
```
Outil de projection sur l'ecran led du LOL
L'ecran lED du LOL est controlle par une carte PCI qui prend une portion de l'ecran pour en mapper chaque pixel sur l'ecran LED.
Avec LOLED : un serveur (`loled.js`) execute avec [Deno](https://deno.com/) et mets a disposition les elements suivants :
* Une page `/display` qui doit etre ouverte en plein ecran sur un navigateur interne
* Une page d'index `/` qui donne quelques details et instructions sur comment utiliser l'outil sur le WEB
* Un script `/js/grab-canvas.js` qui peut etre execute sur n'importe quel page du web dispose d'un element video ou canvas, le flux video du premier element trouve sera alors envoye a l'ecran
Techniquement, le systeme repose sur une connexion WebRTC et utilise le serveur comme serveur de signalisation. Sur la machine assocee a l'ecran LED nous avons demarre une session fluxbox avec LightDM. Flubox demarre un firefox automatquement qui se connecte au serveur en tant qu'affichage.

View File

@ -82,12 +82,20 @@ app.use((ctx, next) => {
ctx.response.headers.append("Access-Control-Allow-Headers", "*")
if(ctx.request.method == "OPTION"){
ctx.response.status = 200
ctx.response.status = 204
} else {
return next()
}
})
app.use((ctx, next) => {
if(ctx.request.url.pathname.startsWith("/_loled")){
ctx.response.headers.append("Cache-Control", "no-store")
}
return next()
})
// Static
app.use(async (ctx, next) => {
if(ctx.request.url.pathname.startsWith("/_loled"))

View File

@ -10,7 +10,7 @@
<p>To send canvas of the page to LOLED click the following link :
<a id="link" href="">LOLED that canvas !</a>
</p>
<p>You can also drag this link in your bookmarks to call it on any page with a canvas</p>
<p>You can also drag this link in your bookmarks to call it on any page with a canvas. Like <a href="https://hydra.ojack.xyz/">Hydra</a> or <a href="https://topos.raphaelforment.fr/">Topos</a>.</p>
<script>
document.getElementById("link").href = `javascript:(function(){let s = document.createElement('script');s.src = '${new URL("/js/grab-canvas.js", document.documentElement.baseURI).toString()}';document.body.appendChild(s);})()`
</script>

View File

@ -90,6 +90,6 @@ async function getRegistration(name){
const args = new URLSearchParams(location.search);
init(
args.get("name"),
parseInt(args.get("width")),
parseInt(args.get("height"))
parseInt(args.get("width") || window.innerWidth),
parseInt(args.get("height") || window.innerHeight)
)

View File

@ -2,9 +2,10 @@
const globalConnnection = Symbol("grab-canvas-connection")
const currentScriptSrc = document.currentScript.src;
const canvas = document.querySelector("canvas");
const sourceElt = document.querySelector("canvas,video");
console.log("Grabbing", sourceElt)
if(!canvas){
if(!sourceElt){
console.error("No canvas found on this page")
}
@ -22,10 +23,38 @@
const allCandidatesCollected = new Promise(res =>
conn.addEventListener("icecandidate", e => e.candidate == null && res() ))
const canvasStream = canvas.captureStream()
let captureFn = sourceElt.captureStream;
if(!captureFn){
captureFn = sourceElt.mozCaptureStream;
}
if(sourceElt instanceof HTMLCanvasElement){
captureFn = sourceElt.captureStream.bind(sourceElt)
} else {
if(sourceElt.mozCaptureStream){
captureFn = sourceElt.mozCaptureStream.bind(sourceElt)
} else {
captureFn = sourceElt.captureStream.bind(sourceElt)
}
}
const canvasStream = captureFn()
const canvasStreamTracks = canvasStream.getVideoTracks()
if(canvasStreamTracks.length > 0){
conn.addTrack(canvasStreamTracks[0], canvasStream)
} else {
throw new Error("Element don't habe video track")
}
try {
const AudioContext = window.AudioContext || window.webkitAudioContext;
if(AudioContext){
const audioContext = new AudioContext();
audioContext.createMediaStreamSource(canvasStream)
.connect(audioContext.destination)
}
} catch(e){
console.warn(e)
}
const offer = await conn.createOffer();