Initial UDP code
This commit is contained in:
parent
df9c9d0d96
commit
9f90c18261
176
core/rfb.js
176
core/rfb.js
|
|
@ -135,6 +135,7 @@ export default class RFB extends EventTargetMixin {
|
|||
this._maxVideoResolutionX = 960;
|
||||
this._maxVideoResolutionY = 540;
|
||||
this._clipboardBinary = true;
|
||||
this._useUdp = true;
|
||||
|
||||
this._trackFrameStats = false;
|
||||
|
||||
|
|
@ -919,6 +920,152 @@ export default class RFB extends EventTargetMixin {
|
|||
this._canvas.addEventListener("gesturemove", this._eventHandlers.handleGesture);
|
||||
this._canvas.addEventListener("gestureend", this._eventHandlers.handleGesture);
|
||||
|
||||
// WebRTC UDP datachannel
|
||||
if (this._useUdp) {
|
||||
this._udpArray = new Array();
|
||||
|
||||
let udpurl = this._url.split("/")[2];
|
||||
udpurl = udpurl.split(":")[0];
|
||||
udpurl = window.location.protocol + "//" + udpurl + ":" + 9555;
|
||||
|
||||
this._udpPeer = new RTCPeerConnection({
|
||||
iceServers: [{
|
||||
urls: ["stun:stun.l.google.com:19302"]
|
||||
}]
|
||||
});
|
||||
let peer = this._udpPeer;
|
||||
|
||||
peer.onicecandidate = function(e) {
|
||||
if (e.candidate)
|
||||
Log.Debug("received ice candidate", e.candidate);
|
||||
else
|
||||
Log.Debug("all candidates received");
|
||||
}
|
||||
|
||||
peer.ondatachannel = function(e) {
|
||||
Log.Debug("peer connection on data channel", e);
|
||||
}
|
||||
|
||||
this._udpChannel = peer.createDataChannel("webudp", {
|
||||
ordered: false,
|
||||
maxRetransmits: 0
|
||||
});
|
||||
this._udpChannel.binaryType = "arraybuffer";
|
||||
|
||||
this._udpChannel.onerror = function(e) {
|
||||
Log.Error("data channel error " + e.message);
|
||||
}
|
||||
|
||||
let sock = this._sock;
|
||||
let udpArray = this._udpArray;
|
||||
let me = this;
|
||||
this._udpChannel.onmessage = function(e) {
|
||||
//Log.Info("got udp msg", e.data);
|
||||
const u8 = new Uint8Array(e.data);
|
||||
// Got an UDP packet. Do we need reassembly?
|
||||
const id = parseInt(u8[0] +
|
||||
(u8[1] << 8) +
|
||||
(u8[2] << 16) +
|
||||
(u8[3] << 24), 10);
|
||||
const i = parseInt(u8[4] +
|
||||
(u8[5] << 8) +
|
||||
(u8[6] << 16) +
|
||||
(u8[7] << 24), 10);
|
||||
const pieces = parseInt(u8[8] +
|
||||
(u8[9] << 8) +
|
||||
(u8[10] << 16) +
|
||||
(u8[11] << 24), 10);
|
||||
|
||||
if (pieces == 1) { // Handle it immediately
|
||||
sock._insertIntoMiddle(u8.slice(12));
|
||||
me._handleUdpRect();
|
||||
} else { // Insert into wait array
|
||||
const now = Date.now();
|
||||
|
||||
const item = { id: id,
|
||||
i: i,
|
||||
pieces: pieces,
|
||||
arrival: now,
|
||||
data: u8.slice(12)
|
||||
};
|
||||
udpArray.push(item);
|
||||
}
|
||||
|
||||
// Process wait array
|
||||
if (!udpArray.length)
|
||||
return;
|
||||
|
||||
// Sort by id and i for easier assembly
|
||||
udpArray.sort(function(a, b) {
|
||||
if (a.id < b.id) return -1;
|
||||
if (b.id < a.id) return 1;
|
||||
|
||||
if (a.i < b.id) return -1;
|
||||
if (b.i < a.i) return 1;
|
||||
return 0;
|
||||
});
|
||||
//Log.Info("waitarr len " + udpArray.length);
|
||||
|
||||
const now = Date.now();
|
||||
for (let i = 0; i < udpArray.length; i++) {
|
||||
// Drop any packets older than 100ms
|
||||
if (now - udpArray[i].arrival > 100) {
|
||||
udpArray.splice(i, 1);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
let curid = 0;
|
||||
let cursum = 0;
|
||||
for (let i = 0; i < udpArray.length; i++) {
|
||||
if (curid != udpArray[i].id) {
|
||||
curid = udpArray[i].id;
|
||||
cursum = 0;
|
||||
var curdata = new Uint8Array(udpArray[i].pieces * 1400);
|
||||
}
|
||||
|
||||
curdata.set(udpArray[i].data, udpArray[i].i * 1400);
|
||||
cursum++;
|
||||
|
||||
// Did we get all?
|
||||
if (cursum == udpArray[i].pieces) {
|
||||
sock._insertIntoMiddle(curdata.slice(0, udpArray[i].i * 1400 + udpArray[i].data.length));
|
||||
me._handleUdpRect();
|
||||
|
||||
// Remove them
|
||||
let pieces = udpArray[i].pieces;
|
||||
udpArray.splice(i - udpArray[i].pieces, udpArray[i].pieces);
|
||||
i -= pieces;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
peer.createOffer().then(function(offer) {
|
||||
return peer.setLocalDescription(offer);
|
||||
}).then(function() {
|
||||
var request = new XMLHttpRequest();
|
||||
request.open("POST", udpurl);
|
||||
request.onload = function() {
|
||||
if (request.status == 200) {
|
||||
var response = JSON.parse(request.responseText);
|
||||
peer.setRemoteDescription(new RTCSessionDescription(response.answer)).then(function() {
|
||||
var candidate = new RTCIceCandidate(response.candidate);
|
||||
peer.addIceCandidate(candidate).then(function() {
|
||||
Log.Debug("success in addicecandidate");
|
||||
}).catch(function(err) {
|
||||
Log.Error("Failure in addIceCandidate", err);
|
||||
});
|
||||
}).catch(function(e) {
|
||||
Log.Error("Failure in setRemoteDescription", e);
|
||||
});
|
||||
}
|
||||
};
|
||||
request.send(peer.localDescription.sdp);
|
||||
}).catch(function(reason) {
|
||||
Log.Error("Failed to create offer " + reason);
|
||||
});
|
||||
}
|
||||
|
||||
Log.Debug("<< RFB.connect");
|
||||
}
|
||||
|
||||
|
|
@ -2734,6 +2881,35 @@ export default class RFB extends EventTargetMixin {
|
|||
}
|
||||
}
|
||||
|
||||
_handleUdpRect() {
|
||||
if (this._FBU.encoding === null) {
|
||||
const hdr = this._sock.rQshiftBytes(12);
|
||||
this._FBU.x = (hdr[0] << 8) + hdr[1];
|
||||
this._FBU.y = (hdr[2] << 8) + hdr[3];
|
||||
this._FBU.width = (hdr[4] << 8) + hdr[5];
|
||||
this._FBU.height = (hdr[6] << 8) + hdr[7];
|
||||
this._FBU.encoding = parseInt((hdr[8] << 24) + (hdr[9] << 16) +
|
||||
(hdr[10] << 8) + hdr[11], 10);
|
||||
}
|
||||
|
||||
if (this._FBU.encoding === encodings.pseudoEncodingLastRect) {
|
||||
} else {
|
||||
if (!this._handleDataRect()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (this._FBU.encoding === encodings.pseudoEncodingLastRect) {
|
||||
if (document.visibilityState !== "hidden") {
|
||||
this._display.flip();
|
||||
}
|
||||
}
|
||||
|
||||
this._FBU.encoding = null;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
_framebufferUpdate() {
|
||||
if (this._FBU.rects === 0) {
|
||||
if (this._sock.rQwait("FBU header", 3, 1)) { return false; }
|
||||
|
|
|
|||
|
|
@ -321,6 +321,19 @@ export default class Websock {
|
|||
this._rQlen += u8.length;
|
||||
}
|
||||
|
||||
// Insert some new data into the current position, pushing the old data back
|
||||
_insertIntoMiddle(data) {
|
||||
const u8 = new Uint8Array(data);
|
||||
if (u8.length > this._rQbufferSize - this._rQlen) {
|
||||
this._expandCompactRQ(u8.length);
|
||||
}
|
||||
|
||||
this._rQ.copyWithin(this._rQi + u8.length, this._rQi, this._rQlen - this._rQi);
|
||||
|
||||
this._rQ.set(u8, this._rQi);
|
||||
this._rQlen += u8.length;
|
||||
}
|
||||
|
||||
_recvMessage(e) {
|
||||
this._DecodeMessage(e.data);
|
||||
if (this.rQlen > 0) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue