Compare commits
1 Commits
bdeb886353
...
4f3ae7abd6
Author | SHA1 | Date | |
---|---|---|---|
4f3ae7abd6 |
|
@ -12,13 +12,13 @@ body.justVideo {
|
|||
body.justVideo #status, body.justVideo form {
|
||||
display: none;
|
||||
}
|
||||
#qrcodelink {
|
||||
.qrcontainer {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
right: 0;
|
||||
float: right;
|
||||
}
|
||||
#qrcodelink svg path {
|
||||
.qrcontainer svg path {
|
||||
min-width: 30vw;
|
||||
max-width: 100vw;
|
||||
max-height: 50vh;
|
||||
|
@ -57,15 +57,29 @@ form label {
|
|||
}
|
||||
</style>
|
||||
<script type="text/javascript" src="static/js/qrcodegen.js"></script>
|
||||
<script type="text/javascript" src="static/js/lzma_worker.js"></script>
|
||||
<script type="text/javascript" src="static/js/prefixCompressor.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<a id="qrcodelink" style="display:none;">
|
||||
<a class="qrcontainer" id="qrcodelink" style="display:none;">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" id="qrcode" style="width:20em; height:20em;" stroke="none">
|
||||
<rect width="100%" height="100%" fill="#FFFFFF"/>
|
||||
<path d="" fill="#000000"/>
|
||||
</svg>
|
||||
</a>
|
||||
<div class="qrcontainer" id="qrcodeObjContainer" style="display:none;">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" id="qrcodeObj" style="width:20em; height:20em;" stroke="none">
|
||||
<rect width="100%" height="100%" fill="#FFFFFF"/>
|
||||
<path d="" fill="#000000"/>
|
||||
</svg> <br/>
|
||||
<textarea id="localOffer" readonly></textarea>
|
||||
<button id="copyLocalOffer">Copy</button>
|
||||
</div>
|
||||
<form name="settings">
|
||||
<label>
|
||||
Serverless mode:
|
||||
<input name="serverless" type="checkbox" value="true" />
|
||||
</label>
|
||||
<label>
|
||||
Recieve remote video:
|
||||
<select name="client-video">
|
||||
|
@ -99,6 +113,12 @@ form label {
|
|||
<input name="debug" type="checkbox" value="true" />
|
||||
</label>
|
||||
</form>
|
||||
<form id="serverlessOffer" style="display: none;">
|
||||
<label>
|
||||
Paste offer here:
|
||||
<textarea name="remoteOffer"></textarea>
|
||||
</label>
|
||||
</form>
|
||||
<div id="status"></div>
|
||||
<div id="videos">
|
||||
<button id="unmute" style="display:none;">Unmute</button>
|
||||
|
@ -106,19 +126,36 @@ form label {
|
|||
<video id="remoteView" width="100%" autoplay muted style="display:none;"></video>
|
||||
<video id="selfView" width="200" height="150" autoplay muted style="display:none;"></video>
|
||||
</div>
|
||||
<script >
|
||||
<script type="module" >
|
||||
import * as b64 from "./static/js/base64.js";
|
||||
|
||||
async function initialize() {
|
||||
const create = (container, type) => container.appendChild(document.createElement(type));
|
||||
const QRGen = qrcodegen.QrCode;
|
||||
|
||||
var compressor = null;
|
||||
async function getCompressor() {
|
||||
if (compressor == null) {
|
||||
compressor = await loadLZMAPrefixCompressor('static/js/prefix');
|
||||
}
|
||||
return compressor;
|
||||
}
|
||||
|
||||
const body = document.querySelector("body");
|
||||
const out = document.getElementById("status");
|
||||
const qrcode = document.getElementById("qrcode");
|
||||
const qrcodelink = document.getElementById("qrcodelink");
|
||||
const qrcodeObjContainer = document.getElementById("qrcodeObjContainer");
|
||||
const qrcodeObj = document.getElementById("qrcodeObj");
|
||||
const remoteView = document.getElementById("remoteView");
|
||||
const selfView = document.getElementById("selfView");
|
||||
const start = document.getElementById("start");
|
||||
const unmute = document.getElementById("unmute");
|
||||
const form = document.forms["settings"];
|
||||
const remoteOfferForm = document.forms["serverlessOffer"];
|
||||
const remoteOffer = remoteOfferForm.elements["remoteOffer"];
|
||||
const localOfferArea = document.getElementById("localOffer");
|
||||
const localOfferCopyButton = document.getElementById("copyLocalOffer");
|
||||
|
||||
function _log(str, tag) {
|
||||
const logEntry = document.createElement(tag);
|
||||
|
@ -157,19 +194,52 @@ form label {
|
|||
});
|
||||
}
|
||||
|
||||
function isServerless() {
|
||||
return settings && 'serverless' in settings && settings.serverless;
|
||||
}
|
||||
|
||||
function withHash(hash) {
|
||||
return window.location.href.split('#')[0] + '#' + hash;
|
||||
}
|
||||
function displayQRUrl(url) {
|
||||
qrcodelink.href = url;
|
||||
const qr = QRGen.encodeText(url, QRGen.Ecc.MEDIUM);
|
||||
function displayQR(qrcode, val) {
|
||||
const encodeFunc = val instanceof Uint8Array
|
||||
? QRGen.encodeBinary
|
||||
: QRGen.encodeText;
|
||||
const qr = encodeFunc(val, QRGen.Ecc.MEDIUM);
|
||||
const code = qr.toSvgString(1);
|
||||
const viewBox = (/ viewBox="([^"]*)"/.exec(code))[1];
|
||||
const pathD = (/ d="([^"]*)"/.exec(code))[1];
|
||||
qrcode.setAttribute("viewBox", viewBox);
|
||||
qrcode.querySelector("path").setAttribute("d", pathD);
|
||||
}
|
||||
function displayQRUrl(url) {
|
||||
qrcodelink.href = url;
|
||||
displayQR(qrcode, url);
|
||||
qrcodelink.style.display = '';
|
||||
}
|
||||
function displayQRUrlForObj(obj) {
|
||||
const json = JSON.stringify(obj);
|
||||
log("Encoding message in QR code/link:");
|
||||
logPre(json);
|
||||
const compressed = compressor.compress(json);
|
||||
const encoded = b64.bytesToBase64(compressed);
|
||||
displayQRUrl(withHash('^' + encoded));
|
||||
}
|
||||
function displayQRCodeForObj(obj) {
|
||||
const json = JSON.stringify(obj);
|
||||
log("Encoding message in QR code for copy/paste:");
|
||||
logPre(json);
|
||||
const compressed = compressor.compress(json);
|
||||
const encoded = b64.bytesToBase64(compressed);
|
||||
displayQR(qrcodeObj, compressed);
|
||||
localOfferArea.value = encoded;
|
||||
localOfferCopyButton.onclick = _ => {
|
||||
localOfferArea.focus();
|
||||
localOfferArea.select();
|
||||
document.execCommand('copy');
|
||||
};
|
||||
qrcodeObjContainer.style.display = '';
|
||||
}
|
||||
|
||||
let roomName = window.location.hash;
|
||||
let isHost = roomName === undefined || !roomName;
|
||||
|
@ -195,6 +265,25 @@ form label {
|
|||
log("Failed to read settings from hash: " + error);
|
||||
}
|
||||
}
|
||||
var firstMessage = undefined;
|
||||
if (roomName && roomName.startsWith("#^")) {
|
||||
roomName = undefined;
|
||||
isHost = false;
|
||||
|
||||
try {
|
||||
const hash = decodeURI(window.location.hash);
|
||||
log("Reading first message from hash:");
|
||||
logPre(hash);
|
||||
log("Decoded base64:");
|
||||
const decoded = (await getCompressor()).decompress(b64.base64ToBytes(hash.substring(2)));
|
||||
logPre(decoded);
|
||||
firstMessage = decoded;
|
||||
settings = {serverless: true};
|
||||
} catch (error) {
|
||||
log("Failed to read message from hash: " + error);
|
||||
}
|
||||
}
|
||||
|
||||
if (isHost) {
|
||||
// From https://stackoverflow.com/a/1349426
|
||||
function makeid(length) {
|
||||
|
@ -207,15 +296,23 @@ form label {
|
|||
return result;
|
||||
}
|
||||
|
||||
if (!isServerless()) {
|
||||
roomName = makeid(8);
|
||||
displayQRUrl(withHash(roomName));
|
||||
}
|
||||
} else {
|
||||
if (!isServerless()) {
|
||||
roomName = roomName.substring(1);
|
||||
}
|
||||
qrcodelink.style.display = 'none';
|
||||
form.style.display = 'none';
|
||||
}
|
||||
|
||||
if (isServerless()) {
|
||||
log("In serverless mode.");
|
||||
} else {
|
||||
log("Room: " + roomName);
|
||||
}
|
||||
|
||||
var webSocket = undefined;
|
||||
|
||||
|
@ -225,6 +322,10 @@ form label {
|
|||
const method = dcReady ? "dataConnection" : "webSocket";
|
||||
log("Sending message via " + method + "...");
|
||||
logPre(toSend);
|
||||
if (isServerless() && !dcReady) {
|
||||
log("ERROR: Attempted to use webSocket in serverless mode.");
|
||||
return;
|
||||
}
|
||||
(dcReady ? dc : webSocket).send(toSend);
|
||||
}
|
||||
|
||||
|
@ -233,7 +334,12 @@ form label {
|
|||
|
||||
function sendOffer() {
|
||||
if (pc.iceGatheringState == "complete") {
|
||||
sendJson({
|
||||
const sendFunc = !isServerless() || dc && dc.readyState == "open"
|
||||
? sendJson
|
||||
: isHost
|
||||
? displayQRUrlForObj
|
||||
: displayQRCodeForObj;
|
||||
sendFunc({
|
||||
description: pc.localDescription
|
||||
});
|
||||
}
|
||||
|
@ -284,6 +390,7 @@ form label {
|
|||
receiveMessage({source: "dataChannel", data: e.data});
|
||||
}
|
||||
log('Data channel initialized.');
|
||||
qrcodeObjContainer.style.display = 'none';
|
||||
}
|
||||
|
||||
if (isHost) {
|
||||
|
@ -292,6 +399,7 @@ form label {
|
|||
receiveMessage({source: "dataChannel", data: e.data});
|
||||
}
|
||||
dc.onopen = e => {
|
||||
remoteOffer.disabled = true;
|
||||
log("Data channel open, sending settings...")
|
||||
settings = readSettingsForm(true);
|
||||
sendJson({settings});
|
||||
|
@ -414,6 +522,7 @@ form label {
|
|||
return webSocket;
|
||||
}
|
||||
|
||||
if (!isServerless()) {
|
||||
webSocket = createWebSocket();
|
||||
|
||||
if (!isHost) {
|
||||
|
@ -422,8 +531,23 @@ form label {
|
|||
// so here just notify the host to start the process.
|
||||
webSocket.onopen = _ => sendJson({ready: true});
|
||||
}
|
||||
} else if (isHost) {
|
||||
await getCompressor();
|
||||
pc = createRTCPeerConnection();
|
||||
remoteOffer.value = '';
|
||||
remoteOffer.onchange = _ => {
|
||||
const decoded = b64.base64ToBytes(remoteOffer.value);
|
||||
const decompressed = compressor.decompress(decoded);
|
||||
receiveMessage({source: 'textarea', data: decompressed});
|
||||
}
|
||||
remoteOfferForm.style.display = '';
|
||||
} else {
|
||||
receiveMessage({source: 'URL', data: firstMessage});
|
||||
}
|
||||
|
||||
log("Finished <script> block.");
|
||||
}
|
||||
initialize();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
Loading…
Reference in New Issue
Block a user