Compare commits

...

4 Commits

View File

@ -195,25 +195,45 @@ form label {
function sendJson(data) { function sendJson(data) {
const toSend = JSON.stringify(data); const toSend = JSON.stringify(data);
log("Sending message..."); const dcReady = dc && dc.readyState == "open";
const method = dcReady ? "dataConnection" : "webSocket";
log("Sending message via " + method + "...");
logPre(toSend); logPre(toSend);
webSocket.send(toSend); (dcReady ? dc : webSocket).send(toSend);
} }
var pc = undefined; var pc = undefined;
var dc = undefined;
function sendOffer() {
if (pc.iceGatheringState == "complete") {
sendJson({
description: pc.localDescription
});
}
}
function createRTCPeerConnection() { function createRTCPeerConnection() {
const pc = new RTCPeerConnection(); const pc = new RTCPeerConnection();
log("Created RTCPeerConnection."); log("Created RTCPeerConnection.");
pc.onicecandidate = ({candidate}) => sendJson({candidate}); pc.onsignalingstatechange = e => {
log("pc.onsignalingstatechange: " + pc.signalingState);
}
pc.oniceconnectionstatechange = e => {
log("pc.oniceconnectionstatechange: " + pc.iceConnectionState);
}
pc.onicegatheringstatechange = async function(e) {
log("pc.onicegatheringstatechange: " + pc.iceGatheringState);
sendOffer();
}
// let the "negotiationneeded" event trigger offer generation // let the "negotiationneeded" event trigger offer generation
// ... but only once icegathering is complete.
pc.onnegotiationneeded = async function () { pc.onnegotiationneeded = async function () {
log("In pc.onnegotiationneeded..."); log("In pc.onnegotiationneeded...");
await pc.setLocalDescription(await pc.createOffer()); await pc.setLocalDescription(await pc.createOffer());
sendJson({ sendOffer();
description: pc.localDescription
});
} }
pc.ontrack = ({streams: [stream]}) => { pc.ontrack = ({streams: [stream]}) => {
@ -232,11 +252,33 @@ form label {
} }
}; };
pc.ondatachannel = e => {
dc = e.channel;
dc.onmessage = e => {
receiveMessage({source: "dataChannel", data: e.data});
}
log('Data channel initialized.');
}
if (isHost) {
dc = pc.createDataChannel('data');
dc.onmessage = e => {
receiveMessage({source: "dataChannel", data: e.data});
}
dc.onopen = e => {
log("Data channel open, sending settings...")
settings = readSettingsForm(true);
sendJson({settings});
startStreamingWithErorrHandling(false);
}
}
return pc; return pc;
} }
// get a local stream, show it in a self-view and add it to be sent // get a local stream, show it in a self-view and add it to be sent
async function startStreaming(fromButton) { async function startStreaming(fromButton) {
log('In startStreaming(fromButton=' + fromButton + ')...');
const otherAudioSettings = isHost const otherAudioSettings = isHost
? settings['client-audio'] ? settings['client-audio']
: settings['host-audio']; : settings['host-audio'];
@ -259,15 +301,6 @@ form label {
} }
start.style.display = 'none'; start.style.display = 'none';
if (isHost) {
sendJson({
settings: settings
});
}
if (pc !== undefined) return;
pc = createRTCPeerConnection();
const videoConstraints = videoSettings == 'none' const videoConstraints = videoSettings == 'none'
? false ? false
: videoSettings == 'true' : videoSettings == 'true'
@ -295,7 +328,7 @@ form label {
pc.addTrack(track, stream); pc.addTrack(track, stream);
} }
} }
function startStartingWithErorrHandling(fromButton) { function startStreamingWithErorrHandling(fromButton) {
startStreaming(fromButton) startStreaming(fromButton)
.then(() => { .then(() => {
log("startStreaming() finished."); log("startStreaming() finished.");
@ -306,32 +339,28 @@ form label {
} }
start.addEventListener("click", _ => { start.addEventListener("click", _ => {
startStartingWithErorrHandling(true) startStreamingWithErorrHandling(true)
}); });
async function receiveMessage(e) { async function receiveMessage(e) {
qrcode.style.display = 'none'; qrcode.style.display = 'none';
log("In webSocket.onmessage..."); log("In receiveMessage from " + e.source + "...");
logPre(e.data); logPre(e.data);
const data = JSON.parse(e.data); const data = JSON.parse(e.data);
if (data.requestSettings) { if (data.ready) {
settings = readSettingsForm(true); // Ready message means client is open and ready for connection.
startStartingWithErorrHandling(false); pc = createRTCPeerConnection();
} else if (data.settings) { } else if (data.settings) {
settings = data.settings; settings = data.settings;
startStartingWithErorrHandling(false); startStreamingWithErorrHandling(false);
} else if (data.description) { } else if (data.description) {
if (pc == undefined) pc = createRTCPeerConnection();
await pc.setRemoteDescription(data.description); await pc.setRemoteDescription(data.description);
if (data.description.type == "offer") { if (data.description.type == "offer") {
log("Got an offer..."); log("Got an offer...");
await pc.setLocalDescription(await pc.createAnswer()); await pc.setLocalDescription(await pc.createAnswer());
sendJson({ sendOffer();
description: pc.localDescription
});
} }
} else if (data.candidate) {
log("Adding ice candidate...");
await pc.addIceCandidate(data.candidate);
} }
}; };
@ -352,7 +381,9 @@ form label {
log('WebSocket error: ' + e); log('WebSocket error: ' + e);
}; };
webSocket.onmessage = receiveMessage; webSocket.onmessage = e => {
receiveMessage({source: "webSocket", data: e.data});
}
return webSocket; return webSocket;
} }
@ -360,7 +391,10 @@ form label {
webSocket = createWebSocket(); webSocket = createWebSocket();
if (!isHost) { if (!isHost) {
webSocket.onopen = _ => sendJson({requestSettings: true}); // To make serverless and server mode more similar,
// always make the first RTCPeerConnection offer from the host,
// so here just notify the host to start the process.
webSocket.onopen = _ => sendJson({ready: true});
} }
log("Finished <script> block."); log("Finished <script> block.");