feat: embed optional apps in player server
This commit is contained in:
200
apps/screen-sharing/app.js
Normal file
200
apps/screen-sharing/app.js
Normal file
@ -0,0 +1,200 @@
|
||||
const displayMediaOptions = {
|
||||
video: {
|
||||
displaySurface: "browser",
|
||||
},
|
||||
audio: {
|
||||
suppressLocalAudioPlayback: false,
|
||||
},
|
||||
preferCurrentTab: false,
|
||||
selfBrowserSurface: "exclude",
|
||||
systemAudio: "include",
|
||||
surfaceSwitching: "include",
|
||||
monitorTypeSurfaces: "include",
|
||||
};
|
||||
|
||||
const peerConnection = new RTCPeerConnection();
|
||||
const signaling = Arcast.getBroadcastingChannel(
|
||||
"screen-sharing",
|
||||
onSignalReceived
|
||||
);
|
||||
|
||||
var secret = window.crypto.randomUUID();
|
||||
var receivedAnswer = false;
|
||||
var receivedOffer = false;
|
||||
var isOffering = false;
|
||||
|
||||
peerConnection.onconnectionstatechange = (evt) => {
|
||||
console.log("Connection state changed", evt);
|
||||
};
|
||||
|
||||
peerConnection.oniceconnectionstatechange = () => {
|
||||
console.log("ICE state: ", peerConnection.iceConnectionState);
|
||||
};
|
||||
|
||||
peerConnection.onicecandidate = (evt) => {
|
||||
signaling.send(
|
||||
JSON.stringify({
|
||||
type: "icecandidate",
|
||||
data: {
|
||||
candidate: evt.candidate,
|
||||
},
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
peerConnection.ontrack = function (e) {
|
||||
var screenplay = document.getElementById("screenplay");
|
||||
if (!screenplay) {
|
||||
screenplay = document.createElement("video");
|
||||
screenplay.id = "screenplay";
|
||||
document.body.appendChild(screenplay);
|
||||
}
|
||||
|
||||
screenplay.autoplay = true;
|
||||
screenplay.playsInline = true;
|
||||
screenplay.srcObject = e.streams[0];
|
||||
screenplay.muted = true;
|
||||
|
||||
e.track.onended = (e) => (screenplay.srcObject = screenplay.srcObject);
|
||||
};
|
||||
|
||||
function main() {
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
if (urlParams.has("secret")) {
|
||||
secret = urlParams.get("secret");
|
||||
}
|
||||
}
|
||||
|
||||
function shareScreen() {
|
||||
return Arcast.getInfo().then((info) => {
|
||||
return navigator.mediaDevices
|
||||
.getDisplayMedia(displayMediaOptions)
|
||||
.then((captureStream) => {
|
||||
isOffering = true;
|
||||
const videoTrack = captureStream.getVideoTracks()[0];
|
||||
peerConnection.addTrack(videoTrack, captureStream);
|
||||
|
||||
peerConnection.createOffer().then((offer) => {
|
||||
peerConnection.setLocalDescription(offer).then(() => {
|
||||
const intervalId = setInterval(() => {
|
||||
if (receivedAnswer) {
|
||||
clearInterval(intervalId);
|
||||
return;
|
||||
}
|
||||
signaling.send(
|
||||
JSON.stringify({
|
||||
type: "offer",
|
||||
data: {
|
||||
secret: secret,
|
||||
offer: offer,
|
||||
},
|
||||
})
|
||||
);
|
||||
}, 1000);
|
||||
|
||||
const url =
|
||||
"http://127.0.0.1:" +
|
||||
info.port +
|
||||
"/apps/screen-sharing/?secret=" +
|
||||
encodeURIComponent(secret);
|
||||
fetch("/api/v1/cast", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
url: url,
|
||||
}),
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function onSignalReceived(data) {
|
||||
const message = JSON.parse(data);
|
||||
switch (message.type) {
|
||||
case "offer":
|
||||
if (message.data.secret !== secret) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (receivedOffer || isOffering) {
|
||||
return;
|
||||
}
|
||||
|
||||
peerConnection.setRemoteDescription(
|
||||
new RTCSessionDescription(message.data.offer),
|
||||
() => {
|
||||
peerConnection.createAnswer(function (answer) {
|
||||
peerConnection.setLocalDescription(
|
||||
answer,
|
||||
function () {
|
||||
signaling.send(
|
||||
JSON.stringify({
|
||||
type: "answer",
|
||||
data: {
|
||||
secret: secret,
|
||||
answer: answer,
|
||||
},
|
||||
})
|
||||
);
|
||||
},
|
||||
error
|
||||
);
|
||||
}, error);
|
||||
},
|
||||
error
|
||||
);
|
||||
|
||||
receivedOffer = true;
|
||||
|
||||
break;
|
||||
|
||||
case "answer":
|
||||
if (receivedAnswer || !isOffering) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.data.secret !== secret) {
|
||||
return;
|
||||
}
|
||||
|
||||
peerConnection.setRemoteDescription(
|
||||
new RTCSessionDescription(message.data.answer),
|
||||
() => {},
|
||||
error
|
||||
);
|
||||
|
||||
receivedAnswer = true;
|
||||
|
||||
break;
|
||||
|
||||
case "icecandidate":
|
||||
if (message.data.candidate) {
|
||||
peerConnection.addIceCandidate(message.data.candidate);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
console.log("Received unhandled message", message);
|
||||
}
|
||||
}
|
||||
|
||||
function endCall() {
|
||||
var videos = document.getElementsByTagName("video");
|
||||
for (var i = 0; i < videos.length; i++) {
|
||||
videos[i].pause();
|
||||
}
|
||||
|
||||
peerConnection.close();
|
||||
}
|
||||
|
||||
function error(err) {
|
||||
console.error(err);
|
||||
endCall();
|
||||
}
|
||||
|
||||
main();
|
30
apps/screen-sharing/index.html
Normal file
30
apps/screen-sharing/index.html
Normal file
@ -0,0 +1,30 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Arcast - Screen sharing</title>
|
||||
<link rel="stylesheet" href="/apps/lib/style.css" />
|
||||
<script type="text/javascript" src="/apps/lib/arcast.js" defer></script>
|
||||
<script type="text/javascript" src="app.js" defer></script>
|
||||
<style>
|
||||
#screenplay {
|
||||
width: 100% !important;
|
||||
height: auto !important;
|
||||
object-fit: contain;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
object-fit: fill;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="main" class="container">
|
||||
<div class="panel">
|
||||
<h1>Screen sharing</h1>
|
||||
<button onclick="shareScreen()">Start</button>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
10
apps/screen-sharing/manifest.json
Normal file
10
apps/screen-sharing/manifest.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"title": {
|
||||
"fr": "Partage d'écran",
|
||||
"en": "Screen sharing"
|
||||
},
|
||||
"description": {
|
||||
"fr": "Partager son écran",
|
||||
"en": "Share your screen"
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user