mirror of
https://github.com/weyne85/rustdesk.git
synced 2025-10-29 17:00:05 +00:00
video_ack_required
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
// example: https://github.com/rgov/js-theora-decoder/blob/main/index.html
|
||||
// https://github.com/brion/ogv.js/releases, yarn add has no simd
|
||||
// dev: copy decoder files from node/ogv/dist/* to project dir
|
||||
// dist: .... to dist
|
||||
/*
|
||||
@@ -20,8 +21,12 @@
|
||||
*/
|
||||
|
||||
export function loadVp9(callback) {
|
||||
// Multithreading is used only if `options.threading` is true.
|
||||
// This requires browser support for the new `SharedArrayBuffer` and `Atomics` APIs,
|
||||
// currently available in Firefox and Chrome with experimental flags enabled.
|
||||
// 所有主流浏览器均默认于2018年1月5日禁用SharedArrayBuffer
|
||||
window.OGVLoader.loadClass(
|
||||
"OGVDecoderVideoVP9W",
|
||||
"OGVDecoderVideoVP9SIMDW",
|
||||
(videoCodecClass) => {
|
||||
window.videoCodecClass = videoCodecClass;
|
||||
videoCodecClass({ videoFormat: {} }).then((decoder) => {
|
||||
@@ -30,7 +35,7 @@ export function loadVp9(callback) {
|
||||
})
|
||||
})
|
||||
},
|
||||
{ worker: true }
|
||||
{ worker: true, threading: true }
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -45,12 +45,11 @@ export function translate(locale: string, text: string): string {
|
||||
const zCode = "z".charCodeAt(0);
|
||||
const aCode = "a".charCodeAt(0);
|
||||
|
||||
export function mapKey(name: string) {
|
||||
export function mapKey(name: string, isDesktop: Boolean) {
|
||||
const tmp = KEY_MAP[name];
|
||||
if (!tmp) return undefined;
|
||||
if (tmp.length == 1) {
|
||||
const chr = tmp.charCodeAt(0);
|
||||
if (chr > zCode || chr < aCode)
|
||||
if (!isDesktop && (chr > zCode || chr < aCode))
|
||||
return KeyEvent.fromPartial({ unicode: chr });
|
||||
else return KeyEvent.fromPartial({ chr });
|
||||
}
|
||||
|
||||
@@ -27,12 +27,14 @@ export default class Connection {
|
||||
_audioDecoder: any;
|
||||
_password: Uint8Array | undefined;
|
||||
_options: any;
|
||||
_videoTestSpeed: number[];
|
||||
|
||||
constructor() {
|
||||
this._msgbox = globals.msgbox;
|
||||
this._draw = globals.draw;
|
||||
this._msgs = [];
|
||||
this._id = "";
|
||||
this._videoTestSpeed = [0, 0];
|
||||
}
|
||||
|
||||
async start(id: string) {
|
||||
@@ -58,7 +60,7 @@ export default class Connection {
|
||||
this.loadVideoDecoder();
|
||||
this.loadAudioDecoder();
|
||||
const uri = getDefaultUri();
|
||||
const ws = new Websock(uri);
|
||||
const ws = new Websock(uri, true);
|
||||
this._ws = ws;
|
||||
this._id = id;
|
||||
console.log(
|
||||
@@ -75,7 +77,7 @@ export default class Connection {
|
||||
nat_type,
|
||||
});
|
||||
ws.sendRendezvous({ punch_hole_request });
|
||||
const msg = ws.parseRendezvous(await ws.next());
|
||||
const msg = (await ws.next()) as rendezvous.RendezvousMessage;
|
||||
ws.close();
|
||||
console.log(new Date() + ": Got relay response");
|
||||
const phr = msg.punch_hole_response;
|
||||
@@ -113,7 +115,7 @@ export default class Connection {
|
||||
}
|
||||
const uuid = rr.uuid;
|
||||
console.log(new Date() + ": Connecting to relay server: " + uri);
|
||||
const ws = new Websock(uri);
|
||||
const ws = new Websock(uri, false, this.handleVideoFrame.bind(this));
|
||||
await ws.open();
|
||||
console.log(new Date() + ": Connected to relay server");
|
||||
this._ws = ws;
|
||||
@@ -149,7 +151,7 @@ export default class Connection {
|
||||
this._ws?.sendMessage({});
|
||||
return;
|
||||
}
|
||||
const msg = this._ws?.parseMessage(await this._ws?.next());
|
||||
const msg = (await this._ws?.next()) as message.Message;
|
||||
let signedId: any = msg?.signed_id;
|
||||
if (!signedId) {
|
||||
console.error("Handshake failed: invalid message type");
|
||||
@@ -198,7 +200,7 @@ export default class Connection {
|
||||
|
||||
async msgLoop() {
|
||||
while (true) {
|
||||
const msg = this._ws?.parseMessage(await this._ws?.next());
|
||||
const msg = (await this._ws?.next()) as message.Message;
|
||||
if (msg?.hash) {
|
||||
this._hash = msg?.hash;
|
||||
if (!this._password)
|
||||
@@ -251,6 +253,7 @@ export default class Connection {
|
||||
|
||||
draw(frame: any) {
|
||||
this._draw?.(frame);
|
||||
globals.draw(frame);
|
||||
}
|
||||
|
||||
close() {
|
||||
@@ -305,6 +308,7 @@ export default class Connection {
|
||||
my_name: "web", // to-do
|
||||
password,
|
||||
option: this.getOptionMessage(),
|
||||
video_ack_required: true,
|
||||
});
|
||||
this._ws?.sendMessage({ login_request });
|
||||
}
|
||||
@@ -341,6 +345,11 @@ export default class Connection {
|
||||
return n > 0 ? msg : undefined;
|
||||
}
|
||||
|
||||
sendVideoReceived() {
|
||||
const misc = message.Misc.fromPartial({ video_received: true });
|
||||
this._ws?.sendMessage({ misc });
|
||||
}
|
||||
|
||||
handleVideoFrame(vf: message.VideoFrame) {
|
||||
if (!this._firstFrame) {
|
||||
this.msgbox("", "", "");
|
||||
@@ -348,11 +357,28 @@ export default class Connection {
|
||||
}
|
||||
if (vf.vp9s) {
|
||||
const dec = this._videoDecoder;
|
||||
// dec.sync();
|
||||
var tm = new Date().getTime();
|
||||
var i = 0;
|
||||
const n = vf.vp9s?.frames.length;
|
||||
vf.vp9s.frames.forEach((f) => {
|
||||
dec.processFrame(f.data.slice(0).buffer, (ok: any) => {
|
||||
if (ok && dec.frameBuffer) {
|
||||
i++;
|
||||
if (i == n) this.sendVideoReceived();
|
||||
if (ok && dec.frameBuffer && n == i) {
|
||||
this.draw(dec.frameBuffer);
|
||||
const now = new Date().getTime();
|
||||
var elapsed = now - tm;
|
||||
this._videoTestSpeed[1] += elapsed;
|
||||
this._videoTestSpeed[0] += 1;
|
||||
if (this._videoTestSpeed[0] >= 30) {
|
||||
console.log(
|
||||
"video decoder: " +
|
||||
parseInt(
|
||||
"" + this._videoTestSpeed[1] / this._videoTestSpeed[0]
|
||||
)
|
||||
);
|
||||
this._videoTestSpeed = [0, 0];
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -398,6 +424,8 @@ export default class Connection {
|
||||
handleMisc(misc: message.Misc) {
|
||||
if (misc.audio_format) {
|
||||
//
|
||||
} else if (misc.chat_message) {
|
||||
globals.pushEvent("chat", misc.chat_message.text);
|
||||
} else if (misc.permission_info) {
|
||||
const p = misc.permission_info;
|
||||
console.info("Change permission " + p.permission + " -> " + p.enabled);
|
||||
@@ -457,18 +485,18 @@ export default class Connection {
|
||||
shift: Boolean,
|
||||
command: Boolean
|
||||
) {
|
||||
const key_event = mapKey(name);
|
||||
const key_event = mapKey(name, globals.isDesktop());
|
||||
if (!key_event) return;
|
||||
if (alt && name == 'VK_MENU') {
|
||||
if (alt && name == "VK_MENU") {
|
||||
alt = false;
|
||||
}
|
||||
if (ctrl && name == 'VK_CONTROL') {
|
||||
if (ctrl && name == "VK_CONTROL") {
|
||||
ctrl = false;
|
||||
}
|
||||
if (shift && name == 'VK_SHIFT') {
|
||||
if (shift && name == "VK_SHIFT") {
|
||||
shift = false;
|
||||
}
|
||||
if (command && name == 'Meta') {
|
||||
if (command && name == "Meta") {
|
||||
command = false;
|
||||
}
|
||||
key_event.down = down;
|
||||
@@ -581,9 +609,9 @@ export default class Connection {
|
||||
const misc = message.Misc.fromPartial({ option });
|
||||
this._ws?.sendMessage({ misc });
|
||||
}
|
||||
|
||||
|
||||
getImageQuality() {
|
||||
return this.getOption('image-quality');
|
||||
return this.getOption("image-quality");
|
||||
}
|
||||
|
||||
getImageQualityEnum(
|
||||
@@ -631,7 +659,7 @@ export default class Connection {
|
||||
|
||||
// @ts-ignore
|
||||
async function testDelay() {
|
||||
const ws = new Websock(getDefaultUri(false));
|
||||
const ws = new Websock(getDefaultUri(false), true);
|
||||
await ws.open();
|
||||
console.log(ws.latency());
|
||||
}
|
||||
|
||||
@@ -684,12 +684,12 @@ export const KEY_MAP: any = {
|
||||
"VK_RBRACKET": "]",
|
||||
"VK_BACKSLASH": "\\",
|
||||
"VK_MINUS": "-",
|
||||
"VK_PLUS": "= // it is =, but sciter return VK_PLUS",
|
||||
"VK_DIVIDE": "Divide // numpad",
|
||||
"VK_MULTIPLY": "Multiply // numpad",
|
||||
"VK_SUBTRACT": "Subtract // numpad",
|
||||
"VK_ADD": "Add // numpad",
|
||||
"VK_DECIMAL": "Decimal // numpad",
|
||||
"VK_PLUS": "=",
|
||||
"VK_DIVIDE": "Divide",
|
||||
"VK_MULTIPLY": "Multiply",
|
||||
"VK_SUBTRACT": "Subtract",
|
||||
"VK_ADD": "Add",
|
||||
"VK_DECIMAL": "Decimal",
|
||||
"VK_F1": "F1",
|
||||
"VK_F2": "F2",
|
||||
"VK_F3": "F3",
|
||||
|
||||
@@ -14,12 +14,15 @@ window.getRgba = () => {
|
||||
currentFrame = undefined;
|
||||
return tmp || null;
|
||||
}
|
||||
window.getLanguage = () => navigator.language;
|
||||
window.isMobile = () => {
|
||||
return /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|ipad|iris|kindle|Android|Silk|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(navigator.userAgent)
|
||||
|| /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(navigator.userAgent.substr(0, 4));
|
||||
}
|
||||
|
||||
export function isDesktop() {
|
||||
return !isMobile;
|
||||
}
|
||||
|
||||
export function msgbox(type, title, text) {
|
||||
if (!events) return;
|
||||
if (!type || (type == 'error' && !text)) return;
|
||||
@@ -297,4 +300,4 @@ export function getPeers() {
|
||||
} catch (e) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -642,6 +642,7 @@ export interface LoginRequest {
|
||||
option: OptionMessage | undefined;
|
||||
file_transfer: FileTransfer | undefined;
|
||||
port_forward: PortForward | undefined;
|
||||
video_ack_required: boolean;
|
||||
}
|
||||
|
||||
export interface ChatMessage {
|
||||
@@ -944,6 +945,7 @@ export interface Misc {
|
||||
close_reason: string | undefined;
|
||||
refresh_video: boolean | undefined;
|
||||
option_response: OptionResponse | undefined;
|
||||
video_received: boolean | undefined;
|
||||
}
|
||||
|
||||
export interface Message {
|
||||
@@ -1521,6 +1523,7 @@ function createBaseLoginRequest(): LoginRequest {
|
||||
option: undefined,
|
||||
file_transfer: undefined,
|
||||
port_forward: undefined,
|
||||
video_ack_required: false,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1556,6 +1559,9 @@ export const LoginRequest = {
|
||||
writer.uint32(66).fork()
|
||||
).ldelim();
|
||||
}
|
||||
if (message.video_ack_required === true) {
|
||||
writer.uint32(72).bool(message.video_ack_required);
|
||||
}
|
||||
return writer;
|
||||
},
|
||||
|
||||
@@ -1587,6 +1593,9 @@ export const LoginRequest = {
|
||||
case 8:
|
||||
message.port_forward = PortForward.decode(reader, reader.uint32());
|
||||
break;
|
||||
case 9:
|
||||
message.video_ack_required = reader.bool();
|
||||
break;
|
||||
default:
|
||||
reader.skipType(tag & 7);
|
||||
break;
|
||||
@@ -1612,6 +1621,9 @@ export const LoginRequest = {
|
||||
port_forward: isSet(object.port_forward)
|
||||
? PortForward.fromJSON(object.port_forward)
|
||||
: undefined,
|
||||
video_ack_required: isSet(object.video_ack_required)
|
||||
? Boolean(object.video_ack_required)
|
||||
: false,
|
||||
};
|
||||
},
|
||||
|
||||
@@ -1636,6 +1648,8 @@ export const LoginRequest = {
|
||||
(obj.port_forward = message.port_forward
|
||||
? PortForward.toJSON(message.port_forward)
|
||||
: undefined);
|
||||
message.video_ack_required !== undefined &&
|
||||
(obj.video_ack_required = message.video_ack_required);
|
||||
return obj;
|
||||
},
|
||||
|
||||
@@ -1659,6 +1673,7 @@ export const LoginRequest = {
|
||||
object.port_forward !== undefined && object.port_forward !== null
|
||||
? PortForward.fromPartial(object.port_forward)
|
||||
: undefined;
|
||||
message.video_ack_required = object.video_ack_required ?? false;
|
||||
return message;
|
||||
},
|
||||
};
|
||||
@@ -4466,6 +4481,7 @@ function createBaseMisc(): Misc {
|
||||
close_reason: undefined,
|
||||
refresh_video: undefined,
|
||||
option_response: undefined,
|
||||
video_received: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -4510,6 +4526,9 @@ export const Misc = {
|
||||
writer.uint32(90).fork()
|
||||
).ldelim();
|
||||
}
|
||||
if (message.video_received !== undefined) {
|
||||
writer.uint32(96).bool(message.video_received);
|
||||
}
|
||||
return writer;
|
||||
},
|
||||
|
||||
@@ -4553,6 +4572,9 @@ export const Misc = {
|
||||
reader.uint32()
|
||||
);
|
||||
break;
|
||||
case 12:
|
||||
message.video_received = reader.bool();
|
||||
break;
|
||||
default:
|
||||
reader.skipType(tag & 7);
|
||||
break;
|
||||
@@ -4587,6 +4609,9 @@ export const Misc = {
|
||||
option_response: isSet(object.option_response)
|
||||
? OptionResponse.fromJSON(object.option_response)
|
||||
: undefined,
|
||||
video_received: isSet(object.video_received)
|
||||
? Boolean(object.video_received)
|
||||
: undefined,
|
||||
};
|
||||
},
|
||||
|
||||
@@ -4620,6 +4645,8 @@ export const Misc = {
|
||||
(obj.option_response = message.option_response
|
||||
? OptionResponse.toJSON(message.option_response)
|
||||
: undefined);
|
||||
message.video_received !== undefined &&
|
||||
(obj.video_received = message.video_received);
|
||||
return obj;
|
||||
},
|
||||
|
||||
@@ -4651,6 +4678,7 @@ export const Misc = {
|
||||
object.option_response !== undefined && object.option_response !== null
|
||||
? OptionResponse.fromPartial(object.option_response)
|
||||
: undefined;
|
||||
message.video_received = object.video_received ?? undefined;
|
||||
return message;
|
||||
},
|
||||
};
|
||||
|
||||
@@ -51,6 +51,7 @@ if (app) {
|
||||
const conn = globals.newConn();
|
||||
conn.setMsgbox(msgbox);
|
||||
conn.setDraw((f) => {
|
||||
globals.draw(f);
|
||||
player.drawFrame(f);
|
||||
});
|
||||
document.querySelector('div#status').style.display = 'block';
|
||||
|
||||
@@ -7,13 +7,19 @@ type Keys = "message" | "open" | "close" | "error";
|
||||
export default class Websock {
|
||||
_websocket: WebSocket;
|
||||
_eventHandlers: { [key in Keys]: Function };
|
||||
_buf: Uint8Array[];
|
||||
_buf: (rendezvous.RendezvousMessage | message.Message)[];
|
||||
_status: any;
|
||||
_latency: number;
|
||||
_secretKey: [Uint8Array, number, number] | undefined;
|
||||
_uri: string;
|
||||
_isRendezvous: boolean;
|
||||
_videoCallback: ((v: message.VideoFrame) => void) | undefined;
|
||||
|
||||
constructor(uri: string) {
|
||||
constructor(
|
||||
uri: string,
|
||||
isRendezvous: boolean = true,
|
||||
fn: ((v: message.VideoFrame) => void) | undefined = undefined
|
||||
) {
|
||||
this._eventHandlers = {
|
||||
message: (_: any) => {},
|
||||
open: () => {},
|
||||
@@ -27,6 +33,8 @@ export default class Websock {
|
||||
this._websocket.onmessage = this._recv_message.bind(this);
|
||||
this._websocket.binaryType = "arraybuffer";
|
||||
this._latency = new Date().getTime();
|
||||
this._isRendezvous = isRendezvous;
|
||||
this._videoCallback = fn;
|
||||
}
|
||||
|
||||
latency(): number {
|
||||
@@ -98,7 +106,7 @@ export default class Websock {
|
||||
this._websocket.onclose = (e) => {
|
||||
if (this._status == "open") {
|
||||
// e.code 1000 means that the connection was closed normally.
|
||||
reject('Reset by the peer');
|
||||
reject("Reset by the peer");
|
||||
}
|
||||
this._status = e;
|
||||
console.error("WebSock.onclose: " + e);
|
||||
@@ -112,14 +120,16 @@ export default class Websock {
|
||||
this._status = e;
|
||||
console.error("WebSock.onerror: " + e);
|
||||
this._eventHandlers.error(e);
|
||||
reject(e['data']);
|
||||
reject(e["data"]);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
async next(timeout = 12000): Promise<Uint8Array> {
|
||||
async next(
|
||||
timeout = 12000
|
||||
): Promise<rendezvous.RendezvousMessage | message.Message> {
|
||||
const func = (
|
||||
resolve: (value: Uint8Array) => void,
|
||||
resolve: (value: rendezvous.RendezvousMessage | message.Message) => void,
|
||||
reject: (reason: any) => void,
|
||||
tm0: number
|
||||
) => {
|
||||
@@ -166,7 +176,16 @@ export default class Websock {
|
||||
k[2] += 1;
|
||||
bytes = globals.decrypt(bytes, k[2], k[0]);
|
||||
}
|
||||
this._buf.push(bytes);
|
||||
if (this._isRendezvous) {
|
||||
this._buf.push(this.parseRendezvous(bytes));
|
||||
} else {
|
||||
const m = this.parseMessage(bytes);
|
||||
if (this._videoCallback && m.video_frame) {
|
||||
this._videoCallback(m.video_frame);
|
||||
} else {
|
||||
this._buf.push(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
this._eventHandlers.message(e.data);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user