12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067 |
- const RemotePlayerMsgType = {
- MIN_USER_INPUT_MSG_ID: 0,
- MouseMove: 0,
- MouseDown: 1,
- MouseUp: 2,
- MouseWheel: 3,
- MouseDBClick: 4,
- WindowSize: 5,
- TouchDown: 6,
- TouchUp: 7,
- TouchMove: 8,
- Exit: 9,
- KeyDown: 10,
- KeyUp: 11,
- MAX_USER_INPUT_MSG_ID: 11,
- RELAY_JPG_REQ: 12,
- }
- // Check if Native app
- window.isNativeApp = (typeof(qt) == "object" && qt.webChannelTransport);
- if (window.isNativeApp)
- {
- if ("undefined" != typeof QWebChannel) {
- window.NativeAppLoad = new Promise((resolve)=>{
- window.gWebChannel = new QWebChannel(qt.webChannelTransport, function (channel) {
- window.NativeApp = {};
- Object.assign(window.NativeApp, channel.objects);
- console.info("NativeApp Loaded");
- resolve();
- });
- });
- }
- else {
- console.warn("Link qwebchannel.js to enable native call");
- window.isNativeApp = false;
- }
- }
- function RemotePlayer(config)
- {
- this.fileVersion = "For WIZPlayer 4.0.42+";
-
- let $self = this;
- // 配置检查
- config = config || {};
- if (!config.logger && config.debug) {
- const TimeToString = (t)=>{ return '['+t.toLocaleTimeString()+':'+t.getMilliseconds()+']'; };
- config.logger = {
- onRequest: function(cmdId, request, args) {
- let t = new Date();
- console.log(TimeToString(t) + ` NativeRequest:{"method": "${request}", "id":${cmdId}}`, args);
- },
- onResponse: function(cmdId, ret) {
- let t = new Date();
- console.log(TimeToString(t) + ` NativeResponse: {"id":${cmdId}}`, ret);
- },
- onConnectSignal: function(idx, signalName, callback) {
- console.log(TimeToString(new Date()) + ` signalConnect: {"method": "${signalName}", "id":${idx}}`, callback);
- },
- onDisconnectSignal: function(idx, signalName, callback) {
- console.log(TimeToString(new Date()) + ` signalDisconnect: {"method": "${signalName}", "id":${idx}}`, callback);
- },
- onSignal: function(signalName, args) {
- console.log(TimeToString(new Date()) + ` signalEmitted: {"method": "${signalName}"}`, args);
- }
- };
- }
- // 服务器地址
- config.signalServer = config.signalServer || "ws://localhost:8080";
- // 引擎ID
- config.engineId = config.engineId;
- // player要绑定的视频标签
- config.video = config.video || document.getElementsByTagName("video")[0];
- config.isImage = config.video.tagName == "IMG";
- config.video.style.transform = "rotateX(180deg)";
- // 是否启用自定义用户输入事件,启用则不监听视频标签上的鼠标、触屏事件,需要用户自行调用输入函数
- config.customInputEvent = config.customInputEvent ? true : false;
- // 自动调整引擎画面大小与绑定视频标签同步
- config.autoResize = config.autoResize ? true : false;
- // 限制用户每秒鼠标移动和触屏的事件个数,事件过多时操作不流畅,限制事件个数来提高操作流畅性
- config.limtMoveCPS = config.limtMoveCPS == undefined ? 10 : config.limtMoveCPS;
- // 用户操作超时时间,当用户鼠标或触屏在该时间内没有产生操作,将首次提示用户,在exitTimeout后将断开连接来节约云渲染资源
- config.userTimeout = isNaN(config.userTimeout) ? 1000 * 60 * 5 : config.userTimeout;
- // 用户操作超时后的延迟断开时间,首次提示后的将过该时间后断开连接,在真正断开前可取消resetTimer();
- config.exitTimeout = isNaN(config.exitTimeout) ? 1000 * 10 : config.exitTimeout;
- // 当前断开后引擎需要保持的时间
- config.maxTimeout = isNaN(config.maxTimeout) ? 0 : config.maxTimeout;
- $self.config = config;
- config.video.oncontextmenu = (e)=> { e.preventDefault() };
- $self.finishEventObjMap = {};
- $self.eventMap = {};
- $self.event = new Proxy({}, {
- set: (target, property, fn) => {
- this.eventMap[property] || (this.eventMap[property] = []);
- this.eventMap[property].push(fn);
- return true;
- }
- })
- $self.isNativeApp = false;
- if (window.NativeAppLoad)
- {
- $self.isNativeApp = true;
- $self.reconnect = ()=>{};
- window.NativeAppLoad.then(()=>{
- window.NativeApp.EngineMgr.create($self.config.engineId, { visible: false }, (objId)=>{
- $self.checkVideoPos = function() {
- var p = $self.config.video.getBoundingClientRect();
- var pos = [p.left, p.top];
- window.NativeApp.EngineMgr.update($self.config.engineId, {pos: pos});
- };
- var p = $self.config.video.getBoundingClientRect();
- window.NativeApp.EngineMgr.update($self.config.engineId, { pos: [p.left, p.top], visible: true });
- var qtTransportWrap = {
- send: (msg) => {
- qt.webChannelTransport.send(msg);
- }
- };
- new QWebChannel(qtTransportWrap, function (channel) {
- $self.Native = channel.objects[objId];
- $self.objects = channel.objects;
- window.NativeApp = {}
- window.webchannelDebug = $self.config.debug;
- Object.assign(window.NativeApp, channel.objects);
- if ($self.Native.ControlChannel) {
- $self._controlChannel = {
- send: (buffer) => {
- var str = window.btoa(String.fromCharCode(...new Uint8Array(buffer)));
- $self.Native.ControlChannel.send(str);
- }
- };
- }
- else {
- console.warn("Native not has ControlChannel");
- }
- console.info("Engine Native Loaded");
- $self.finishEventObjMap["NativeLoad"] = $self.Native;
- $self.emit("NativeLoad", $self.Native);
- }, $self.config.logger);
- });
- });
- }
- else {
- $self._ws = null;
- $self._pc = null;
-
- $self.resetTimer = function() {
- if ($self._pc && !$self.exited) {
- clearTimeout($self._userTimer);
- $self._userTimer = setTimeout(()=> {
- $self._userTimer = setTimeout(()=> {
- if (!$self.exited) {
- $self.exit();
- console.log(`长时间没有操作,已断开连接`);
- if (!$self.emit("TimeOutExit", $self))
- {
- alert(`长时间没有操作,已断开连接`);
- }
- }
- }, $self.config.exitTimeout);
- $self.emit("UserTimeOut", $self);
- }, $self.config.userTimeout);
- }
- }
- function configPeerConnection()
- {
- $self._controlChannel = null;
- var connectionCreator = RTCPeerConnection ? RTCPeerConnection : webkitRTCPeerConnection;
- $self._pc = new connectionCreator({ iceServers: $self.iceServers });
-
- $self._pc.onicecandidate = function(evt) {
- if (evt.candidate !== null) {
- $self._ws.send(JSON.stringify({
- type: "IceCandidate",
- data: evt.candidate
- }));
- }
- };
-
- $self._pc.ondatachannel = (evt) => {
- console.log("Get DataChannel", evt);
- if (evt.channel && evt.channel.label == "Control")
- {
- let checksend = ()=>
- {
- while($self._controlChannel.sendQueue.length > 0 && evt.channel.bufferedAmount <= evt.channel.bufferedAmountLowThreshold)
- {
- evt.channel.send($self._controlChannel.sendQueue.shift());
- }
- }
- $self._controlChannel = {
- sendQueue: [],
- send: (msg) => {
- if (msg.length > evt.channel.bufferedAmountLowThreshold)
- {
- let pktCount = Math.ceil(msg.length / evt.channel.bufferedAmountLowThreshold);
- $self._controlChannel.sendQueue.push(`NEXT_COUNT:${pktCount}`);
- let s = 0;
- while(s < msg.length) {
- let e = s + Math.min(evt.channel.bufferedAmountLowThreshold, msg.length - evt.channel.bufferedAmountLowThreshold);
- $self._controlChannel.sendQueue.push(msg.slice(s, e));
- s = e;
- }
- }
- else
- {
- $self._controlChannel.sendQueue.push(msg);
- }
- checksend();
- }
- };
- evt.channel.bufferedAmountLowThreshold = 65536;
- evt.channel.onbufferedamountlow = checksend;
- evt.channel.onopen = () => {
- new QWebChannel($self._controlChannel, function (channel) {
- $self.Native = channel.objects.Native;
- $self.objects = channel.objects;
- console.info("Engine Native Loaded");
- window.webchannelDebug = $self.config.debug;
- $self.finishEventObjMap["NativeLoad"] = $self.Native;
- $self.emit("NativeLoad", $self.Native);
- }, $self.config.logger);
- }
-
- evt.channel.onclose = () => {
- console.log("Datachannel close");
- $self._controlChannel = null;
- $self.Native = null;
- $self.nativeObjects = [];
- $self.finishEventObjMap["NativeLoad"] = null;
- $self.emit("Disconnected", "webrtc channel closed");
- }
-
- $self.config.video.buffers = [];
- $self.config.video.strBuffer = "";
- $self.config.video.strCount = 0;
- let relay_jpg_req = new ArrayBuffer(4); // for request next frame;
- let dataView = new DataView(relay_jpg_req);
- dataView.setInt32(0, RemotePlayerMsgType.RELAY_JPG_REQ, true);
- let lastImage = new Image();
- evt.channel.onmessage = (event) => {
- const max_data_channel_buffersize = 256 * 1024;
- if (typeof(event.data) == "string") {
- if ("function" == typeof($self._controlChannel.onmessage)) { // setup by QWebChannel
- $self.config.video.strCount--;
- if ($self.config.video.strCount == -1)
- {
- if (event.data.startsWith("NEXT_COUNT:"))
- {
- $self.config.video.strCount = parseInt(event.data.substr(11));
- }
- else
- {
- $self.config.video.strCount = 0;
- $self._controlChannel.onmessage({ data: JSON.parse(event.data) });
- }
- }
- else
- {
- $self.config.video.strBuffer += event.data;
- if ($self.config.video.strCount == 0)
- {
- var allStr = $self.config.video.strBuffer;
- $self.config.video.strBuffer = "";
- $self._controlChannel.onmessage({ data: JSON.parse(allStr) });
- }
- }
- }
- }
- else {
- if (event.data.byteLength > 4)
- {
- $self.config.video.buffers.push(event.data);
- }
- else
- {
- // not content package
- }
- if (event.data.byteLength < max_data_channel_buffersize)
- {
- if ($self.config.video.buffers.length > 0)
- {
- var src = URL.createObjectURL(new Blob($self.config.video.buffers));
- $self.config.video.buffers = [];
- lastImage.src = src;
- lastImage.decode().then(()=>{
- var oldSrc;
- if ($self.config.video.tagName == 'VIDEO')
- {
- let stream = player.config.video.srcObject;
- oldSrc = player.config.video.poster;
- player.config.video.poster = src;
- player.config.video.src='';
- player.config.video.srcObject=stream;
- }
- else // img
- {
- if ($self._controlChannel) $self._controlChannel.send(relay_jpg_req);
- oldSrc = $self.config.video.src;
- $self.config.video.src = src;
- }
- if (oldSrc) URL.revokeObjectURL(oldSrc);
- })
- .catch((err)=>{
- if ($self._controlChannel && $self.config.video.tagName != 'VIDEO') $self._controlChannel.send(relay_jpg_req);
- console.error(`decode image failed: ${err}`);
- URL.revokeObjectURL(src);
- });
- }
- else
- {
- if ($self._controlChannel && $self.config.video.tagName != 'VIDEO') $self._controlChannel.send(relay_jpg_req);
- }
- }
- }
- }
- }
- }
- $self._pc.ontrack = (evt) => {
- console.log("Get Remote Track", evt);
- $self._pc._track = evt.track;
- config.video.srcObject = evt.streams[0];
- config.video.play();
- $self.finishEventObjMap["VideoReady"] = $self.config.video;
- $self.emit("VideoReady", $self.config.video);
- $self.resetTimer();
- }
- $self._pc.onconnectionstatechange = (evt) =>
- {
- switch($self._pc.connectionState) {
- case "connecting":{
- console.log("peerconnection connecting");
- } break;
- case "connected": {
- console.log("peerconnection connected");
- $self.emit("Connected");
- } break;
- case "disconnected": {
- console.log("peerconnection disconnected");
- $self._pc.close();
- $self.finishEventObjMap["NativeLoad"] = null;
- $self.emit("Disconnected");
- } break;
- case "failed": {
- console.log("peerconnection connect failed");
- $self._pc.close();
- $self.emit("ConnectedFailed", evt);
- } break;
- }
- }
- }
- $self.reconnect = function() {
- if ($self.exited) return;
- try {
- $self._ws = new WebSocket(`${config.signalServer}?engineId=${config.engineId}&maxTimeout=${config.maxTimeout}&type=${config.isImage?"img":"video"}&rtcIni=${config.rtcIni}&jpgQuality=${config.jpgQuality}`);
- $self._ws.onopen = function () { console.log("signal websocket connected"); };
- $self._ws.onerror = function (e) {
- console.log("signal websocket error", e);
- $self.emit('Disconnected', "signal websocket error")
- }
- $self._ws.onmessage = function (msgData) {
- msgData = msgData.data;
- console.debug(msgData);
- var msg = JSON.parse(msgData);
- // 提示信息
- if (msg.type == "Message") {
- console.warn(msg.data);
- if (!$self.emit("Message", msg.data))
- {
- alert(msg.data);
- }
- }
- // 收到引擎会话的地址
- else if (msg.type == "EngineWs") {
- console.warn(msg.data);
- $self.sessionWs = msg.data;
- console.log(`Get Engine session connection info: ${$self.sessionWs}`);
- $self._engineWs = new WebSocket($self.sessionWs);
- let transport = {
- send: (msg) => {
- if ($self.config.debug && typeof msg == "string") console.log(msg);
- $self._engineWs.send(msg);
- }
- };
- $self._engineWs.onopen = () => {
- console.log(`Engine session connected`);
- $self.emit("Connected");
- new QWebChannel(transport, function (channel) {
- $self.Native = channel.objects.Native;
- $self.objects = channel.objects;
- console.info("Engine Native Loaded");
- window.webchannelDebug = $self.config.debug;
- $self.finishEventObjMap["NativeLoad"] = $self.Native;
- $self._controlChannel = {
- send: (buffer) => {
- var str = window.btoa(String.fromCharCode(...new Uint8Array(buffer)));
- $self.Native.ControlChannel.send(str);
- }
- };
- $self.emit("NativeLoad", $self.Native);
- }, $self.config.logger);
- }
-
- $self._engineWs.onclose = () => {
- $self._controlChannel = null;
- $self.Native = null;
- $self.nativeObjects = [];
- $self.finishEventObjMap["NativeLoad"] = null;
- $self.emit("Disconnected", "Engine session closed");
- }
-
- $self._engineWs.onmessage = (event) => {
- if (typeof(event.data) == "string") {
- if ("function" == typeof transport.onmessage) { // setup by QWebChannel
- transport.onmessage({ data: JSON.parse(event.data) });
- }
- }
- else {
- var oldSrc = $self.config.video.src;
- $self.config.video.src = URL.createObjectURL(event.data);
- if (oldSrc) URL.revokeObjectURL(oldSrc);
- }
- }
- }
- // 收到连接引擎上线消息
- else if (msg.type == "OpenSession") {
- $self.iceServers = msg.data;
- const connectMsg = JSON.stringify({
- type: "ConnectRequest",
- data: {}
- });
- $self._ws.send(connectMsg);
- }
- // 收到连接引擎回复
- else if (msg.type == "OfferToClient") {
- configPeerConnection();
- var romoteSdp = new RTCSessionDescription(msg.data);
- $self._pc.setRemoteDescription(romoteSdp).then(() => {
- $self._pc.createAnswer().then((myDesc)=>{
- var localSdp = new RTCSessionDescription(myDesc);
- $self._pc.setLocalDescription(localSdp).then(() => {
- $self._ws.send(JSON.stringify({
- type: "AnswerToEngine",
- data: localSdp
- }));
- }, (err)=>{ console.error("Set LocalDescription failed", err); });
- }, (err)=>{ console.error("CreateAnswer failed", err); });
- }, (err)=>{ console.error("Set RemoteDescription failed", err); });
- }
- // 收到IceCandidate消息
- else if (msg.type === "IceCandidate") {
- $self._pc.addIceCandidate(new RTCIceCandidate(msg.data));
- }
- // 收到关闭消息
- else if (msg.type === "CloseSession") {
- $self.exit();
- }
- else
- {
- console.warn(`Un processed message ${msg.type}`, msg.data);
- alert(`${msg.type}: ${msg.data}`);
- }
- }
- }
- catch (e)
- {
- $self.emit("Disconnected", e);
- }
- };
- $self.startCheckSignal = function(tripTimeCb, packetsLostCb)
- {
- let maxPacketsLost = 0, lastPacketsLost = 0;
- let get = (sipCb, sfuCb) => {
- if ($self._pc)
- {
- $self._pc.getStats().then(function (report){
- report.forEach((value, key) => {
- if (value.type === 'candidate-pair') {
- sipCb(value.currentRoundTripTime);
- }
- if (value.type == "inbound-rtp" || value.googContentType === 'realtime') {
- sfuCb(value.packetsLost);
- }
- });
- });
- }
- else
- {
- sipCb(99.999);
- sfuCb(999999);
- }
- };
- let lastTripTime, lastLost = -1;
- $self.watchSignalTimer = setInterval(()=>{
- get((tripTime)=>{
- if (lastTripTime != tripTime)
- {
- lastTripTime = tripTime;
- tripTimeCb(tripTime);
- }
- }, (packetsLost)=>{
- let lost = packetsLost - lastPacketsLost;
- if (lost <= 0) maxPacketsLost = 0;
- else if (lost > maxPacketsLost) maxPacketsLost = lost;
- else lost = maxPacketsLost;
- lastPacketsLost = packetsLost;
- if (lost > 0)
- {
- console.log(`WebRTC has lost ${lost} packets`);
- }
- if (lost != lastLost)
- {
- lastLost = lost;
- packetsLostCb(lost);
- }
- });
- }, 1000);
- }
-
- $self.stopCheckSignalstartCheckSignal = function()
- {
- if ($self.watchSignalTimer) {
- clearInterval($self.watchSignalTimer);
- $self.watchSignalTimer = null;
- }
- }
- }
- // 初始化输入事件
- let style = getComputedStyle(config.video);
- let isMouseDown = false; // 用于全局监听判断鼠标是否按下
- let mouseDownInfo = {}; // 鼠标按下信息
- let keyList = []; // 键盘按键
- // 注册输入事件
- if (!config.customInputEvent) {
- var events = {
- MouseMove:(e)=>{
- let x = e.offsetX / parseFloat(style.width) * 2 - 1;
- let y = e.offsetY / parseFloat(style.height) * 2 - 1;
- $self.mousemove(x, y);
- e.preventDefault();
- },
- MouseDown:(e)=>{
- mouseDownInfo = e
- let x = e.offsetX / parseFloat(style.width) * 2 - 1;
- let y = e.offsetY / parseFloat(style.height) * 2 - 1;
- $self.mousedown(x, y, e.button);
- isMouseDown = true;
- e.preventDefault();
- },
- MouseUp:(e)=>{
- if (isMouseDown) {
- mouseDownInfo = {}
- let x = e.offsetX / parseFloat(style.width) * 2 - 1;
- let y = e.offsetY / parseFloat(style.height) * 2 - 1;
- $self.mouseup(x, y, e.button);
- isMouseDown = false;
- e.preventDefault();
- }
- },
- MouseWheel:(e)=>{
- let x = e.offsetX / parseFloat(style.width) * 2 - 1;
- let y = e.offsetY / parseFloat(style.height) * 2 - 1;
- $self.mosuewheel(x, y, e.wheelDeltaY);
- e.preventDefault();
- },
- MouseDBClick:(e)=>{
- let x = e.offsetX / parseFloat(style.width) * 2 - 1;
- let y = e.offsetY / parseFloat(style.height) * 2 - 1;
- $self.mousedbclick(x, y, e.button);
- e.preventDefault();
- },
- TouchDown:(e)=>{
- let w = parseFloat(style.width);
- let h = parseFloat(style.height);
- let box = $self.config.video.getBoundingClientRect();
- for (let i = 0; i < e.changedTouches.length; ++i) {
- const t = e.changedTouches[i];
- let x = (t.clientX - box.left) / w * 2 - 1;
- let y = (t.clientY - box.top) / h * 2 - 1;
- y = -y;
- $self.touchdown(x, y, t.identifier);
- }
- e.preventDefault();
- },
- TouchUp:(e)=>{
- let w = parseFloat(style.width);
- let h = parseFloat(style.height);
- let box = $self.config.video.getBoundingClientRect();
- for (let i = 0; i < e.changedTouches.length; ++i) {
- const t = e.changedTouches[i];
- let x = (t.clientX - box.left) / w * 2 - 1;
- let y = (t.clientY - box.top) / h * 2 - 1;
- y = -y;
- $self.touchup(x, y, t.identifier);
- }
- e.preventDefault();
- },
- TouchMove:(e)=>{
- let w = parseFloat(style.width);
- let h = parseFloat(style.height);
- let box = $self.config.video.getBoundingClientRect();
- for (let i = 0; i < e.changedTouches.length; ++i) {
- const t = e.changedTouches[i];
- let x = (t.clientX - box.left) / w * 2 - 1;
- let y = (t.clientY - box.top) / h * 2 - 1;
- y = -y;
- $self.touchmove(x, y, t.identifier);
- }
- e.preventDefault();
- },
- KeyDown: (e) => {
- const keyIndex = keyList.findIndex(item=>{
- return item.keyCode === e.keyCode
- })
- if (keyIndex === -1) {
- keyList.push(e)
- }
- $self.keydown(e.keyCode);
- },
- KeyUp: (e) => {
- const keyIndex = keyList.findIndex(item=>{
- return item.keyCode === e.keyCode
- })
- keyList.splice(keyIndex,1)
- $self.keyup(e.keyCode);
- },
- Blur: (e) => {
- if (isMouseDown) {
- let x = mouseDownInfo.offsetX / parseFloat(style.width) * 2 - 1;
- let y = mouseDownInfo.offsetY / parseFloat(style.height) * 2 - 1;
- $self.mouseup(x, y, mouseDownInfo.button);
- isMouseDown = false;
- mouseDownInfo = {}
- }
- for (let i = 0; i < keyList.length; i += 1) {
- $self.keyup(keyList[i].keyCode);
- }
- keyList = []
- }
- }
- if (config.limtMoveCPS > 0)
- {
- var limtFuns = (function(){
- let mouse_x, mouse_y, mouse_hasChanged;
- let touch_hasChanged, touch_moveList;
- touch_moveList = new Map();
- return {
- mouse_intervalFun: () => {
- if (mouse_hasChanged) {
- mouse_hasChanged = false;
- $self.mousemove(mouse_x, mouse_y);
- }
- },
- mouse_moveFun: (evt)=>{
- mouse_x = evt.offsetX / parseFloat(style.width) * 2 - 1;
- mouse_y = evt.offsetY / parseFloat(style.height) * 2 - 1;
- mouse_hasChanged = true;
- },
- touch_intervalFun: ()=>{
- if (touch_hasChanged) {
- touch_hasChanged = false;
- touch_moveList.forEach((v,k)=>{
- $self.touchmove(v.x, v.y, k);
- });
- touch_moveList.clear();
- }
- },
- touch_moveFun: (evt)=>{
- let w = parseFloat(style.width);
- let h = parseFloat(style.height);
- let box = $self.config.video.getBoundingClientRect();
- for (let i = 0; i < evt.changedTouches.length; ++i) {
- const t = evt.changedTouches[i];
- let x = (t.clientX - box.left) / w * 2 - 1;
- let y = (t.clientY - box.top) / h * 2 - 1;
- y = -y;
- var o = touch_moveList.get(t.identifier);
- if (!o || o.x != x || o.y != y)
- {
- touch_moveList.set(t.identifier, {x: x, y: y});
- touch_hasChanged = true;
- }
- }
- }
- };
- })();
- var limtFunsMouseMoveInterval = setInterval(limtFuns.mouse_intervalFun, 1000 / config.limtMoveCPS);
- config.video.addEventListener("mousedown", (e) => {
- clearInterval(limtFunsMouseMoveInterval);
- limtFunsMouseMoveInterval = setInterval(limtFuns.mouse_intervalFun, 1000 / (config.limtMoveCPS * 2));
- });
- config.video.addEventListener("mouseup", (e)=>{
- if (e.buttons == 0)
- {
- clearInterval(limtFunsMouseMoveInterval);
- limtFunsMouseMoveInterval = setInterval(limtFuns.mouse_intervalFun, 1000 / config.limtMoveCPS);
- }
- });
- config.video.addEventListener("mousemove", limtFuns.mouse_moveFun);
- var limtTouchMoveInterval;
- config.video.addEventListener("touchstart", (e)=>{
- limtFuns.touch_intervalFun(); // flush all mouse move event
- if (!limtTouchMoveInterval) limtTouchMoveInterval = setInterval(limtFuns.touch_intervalFun, 1000 / (config.limtMoveCPS * 3));
- });
- config.video.addEventListener("touchend", (e)=>{
- limtFuns.touch_intervalFun(); // flush all mouse move event
- if (e.buttons == 0) clearInterval(limtTouchMoveInterval);
- });
- config.video.addEventListener("touchmove", limtFuns.touch_moveFun, { passive: false });
- }
- else
- {
- config.video.addEventListener("mousemove", events.MouseMove);
- config.video.addEventListener("touchmove", events.TouchMove, { passive: false });
- }
- config.video.addEventListener("mousedown", events.MouseDown);
- config.video.addEventListener("mouseup", events.MouseUp);
- var win = window;
- while (win.parent && win.parent != win) win = win.parent;
- win.addEventListener("mouseup", events.MouseUp);
- config.video.addEventListener("mousewheel", events.MouseWheel);
- config.video.addEventListener("dblclick", events.MouseDBClick);
- config.video.addEventListener("touchstart", events.TouchDown);
- config.video.addEventListener("touchend", events.TouchUp);
- win.addEventListener("keydown", events.KeyDown);
- win.addEventListener("keyup", events.KeyUp);
- win.addEventListener("blur", events.Blur);
- if (!$self.isNativeApp)
- {
- config.video.addEventListener("mousedown", $self.resetTimer);
- config.video.addEventListener("mousemove", $self.resetTimer);
- config.video.addEventListener("mouseup", $self.resetTimer);
- config.video.addEventListener("mousewheel", $self.resetTimer);
- config.video.addEventListener("touchstart", $self.resetTimer);
- config.video.addEventListener("touchmove", $self.resetTimer);
- config.video.addEventListener("touchend", $self.resetTimer);
- }
- }
- if (config.autoResize) {
- setInterval((function () {
- let videoWidth, videoHeight;
- return function (force) {
- let width = Math.round(parseFloat(style.width));
- let height = Math.round(parseFloat(style.height));
- if (force || videoWidth != width || videoHeight != height) {
- if ($self.resize(width, height)) {
- videoWidth = width;
- videoHeight = height;
- }
- }
- }
- }()), 100);
- }
- $self.reconnect();
- }
- RemotePlayer.prototype.constructor = RemotePlayer;
- // for event system
- RemotePlayer.prototype.on = function(name, fn) {
- this.event[name] = fn;
- var arg = this.finishEventObjMap[name];
- if (arg) fn(arg);
- };
- RemotePlayer.prototype.off = function(name) { delete this.eventMap[name]; };
- RemotePlayer.prototype.emit = function(name, ...val) {
- if (this.eventMap[name] && this.eventMap[name].length > 0) this.eventMap[name].forEach(fn => { fn(...val); })
- else return false;
- return true;
- };
- // send mousemove event
- RemotePlayer.prototype.mousemove = (function()
- {
- let buffer = new ArrayBuffer(12);
- let dataView = new DataView(buffer);
- dataView.setInt32(0, RemotePlayerMsgType.MouseMove, true);
- return function(x, y)
- {
- if (this._controlChannel)
- {
- dataView.setFloat32(4, x, true);
- dataView.setFloat32(8, y, true);
- this._controlChannel.send(buffer);
- console.debug(`MouseMove: [${x}, ${y}]`);
- return true;
- }
- return false;
- }
- }());
- // send mousedown event
- RemotePlayer.prototype.mousedown = (function()
- {
- let buffer = new ArrayBuffer(16);
- let dataView = new DataView(buffer);
- dataView.setInt32(0, RemotePlayerMsgType.MouseDown, true);
- return function(x, y, btn)
- {
- if (this._controlChannel)
- {
- dataView.setFloat32(4, x, true);
- dataView.setFloat32(8, y, true);
- dataView.setInt32(12, btn, true);
- this._controlChannel.send(buffer);
- console.debug(`MouseDown: [${btn}, ${x}, ${y}]`);
- return true;
- }
- return false;
- }
- }());
- // send mouseup event
- RemotePlayer.prototype.mouseup = (function()
- {
- let buffer = new ArrayBuffer(16);
- let dataView = new DataView(buffer);
- dataView.setInt32(0, RemotePlayerMsgType.MouseUp, true);
- return function(x, y, btn)
- {
- if (this._controlChannel)
- {
- dataView.setFloat32(4, x, true);
- dataView.setFloat32(8, y, true);
- dataView.setInt32(12, btn, true);
- this._controlChannel.send(buffer);
- console.debug(`MouseUp:${btn} [${x}, ${y}]`);
- return true;
- }
- return false;
- }
- }());
- // send mousewheel event
- RemotePlayer.prototype.mosuewheel = (function()
- {
- let buffer = new ArrayBuffer(16);
- let dataView = new DataView(buffer);
- dataView.setInt32(0, RemotePlayerMsgType.MouseWheel, true);
- return function(x, y, delta)
- {
- if (this._controlChannel)
- {
- dataView.setFloat32(4, x, true);
- dataView.setFloat32(8, y, true);
- dataView.setInt32(12, delta, true);
- this._controlChannel.send(buffer);
- console.debug(`MouseWheel:${delta} [${x}, ${y}]`);
- return true;
- }
- return false;
- }
- }());
- // send mousedbclick event
- RemotePlayer.prototype.mousedbclick = (function()
- {
- let buffer = new ArrayBuffer(16);
- let dataView = new DataView(buffer);
- dataView.setInt32(0, RemotePlayerMsgType.MouseDBClick, true);
- return function(x, y, btn)
- {
- if (this._controlChannel)
- {
- dataView.setFloat32(4, x, true);
- dataView.setFloat32(8, y, true);
- dataView.setInt32(12, btn, true);
- this._controlChannel.send(buffer);
- console.debug(`MouseDBClick:${btn} [${x}, ${y}]`);
- return true;
- }
- return false;
- }
- }());
- // send resize event
- RemotePlayer.prototype.resize = (function()
- {
- let buffer = new ArrayBuffer(16);
- let dataView = new DataView(buffer);
- dataView.setInt32(0, RemotePlayerMsgType.WindowSize, true);
- return function(w, h)
- {
- if (this._controlChannel && w >= 64 && h >= 64)
- {
- w = Math.ceil(w / 2.0) * 2.0;
- h = Math.ceil(h / 2.0) * 2.0;
- dataView.setFloat32(4, w, true);
- dataView.setFloat32(8, h, true);
- dataView.setInt32(12, 96/*DPI*/, true);
- this._controlChannel.send(buffer);
- console.debug(`WindowSize: [${w}, ${h}]`);
- return true;
- }
- return false;
- }
- }());
- // send touchdown event
- RemotePlayer.prototype.touchdown = (function()
- {
- let buffer = new ArrayBuffer(16);
- let dataView = new DataView(buffer);
- dataView.setInt32(0, RemotePlayerMsgType.TouchDown, true);
- return function(x, y, id)
- {
- if (this._controlChannel)
- {
- dataView.setFloat32(4, x, true);
- dataView.setFloat32(8, y, true);
- dataView.setInt32(12, id, true);
- this._controlChannel.send(buffer);
- console.debug(`TouchDown:${id} [${x}, ${y}]`);
- return true;
- }
- return false;
- }
- })();
- // send touchup event
- RemotePlayer.prototype.touchup = (function()
- {
- let buffer = new ArrayBuffer(16);
- let dataView = new DataView(buffer);
- dataView.setInt32(0, RemotePlayerMsgType.TouchUp, true);
- return function(x, y, id)
- {
- if (this._controlChannel)
- {
- dataView.setFloat32(4, x, true);
- dataView.setFloat32(8, y, true);
- dataView.setInt32(12, id, true);
- this._controlChannel.send(buffer);
- console.debug(`TouchUp:${id} [${x}, ${y}]`);
- return true;
- }
- return false;
- }
- })();
- // send touchmove event
- RemotePlayer.prototype.touchmove = (function()
- {
- let buffer = new ArrayBuffer(16);
- let dataView = new DataView(buffer);
- dataView.setInt32(0, RemotePlayerMsgType.TouchMove, true);
- return function(x, y, id)
- {
- if (this._controlChannel)
- {
- dataView.setFloat32(4, x, true);
- dataView.setFloat32(8, y, true);
- dataView.setInt32(12, id, true);
- this._controlChannel.send(buffer);
- console.debug(`TouchMove:${id} [${x}, ${y}]`);
- return true;
- }
- return false;
- }
- })();
- // send keydown event
- RemotePlayer.prototype.keydown = (function () {
- let buffer = new ArrayBuffer(8);
- let dataView = new DataView(buffer);
- dataView.setInt32(0, RemotePlayerMsgType.KeyDown, true);
- return function (keycode) {
- if (this._controlChannel) {
- dataView.setInt32(4, keycode, true);
- this._controlChannel.send(buffer);
- console.debug(`KeyDown:${keycode}`);
- return true;
- }
- return false;
- }
- })();
- // send keyup event
- RemotePlayer.prototype.keyup = (function () {
- let buffer = new ArrayBuffer(8);
- let dataView = new DataView(buffer);
- dataView.setInt32(0, RemotePlayerMsgType.KeyUp, true);
- return function (keycode) {
- if (this._controlChannel) {
- dataView.setInt32(4, keycode, true);
- this._controlChannel.send(buffer);
- console.debug(`KeyUp:${keycode}`);
- return true;
- }
- return false;
- }
- })();
- // send exit event
- RemotePlayer.prototype.exit = (function(){
- let buffer = new ArrayBuffer(4);
- let dataView = new DataView(buffer);
- dataView.setInt32(0, RemotePlayerMsgType.Exit, true);
- return function()
- {
- clearTimeout(this._userTimer);
- if (this._controlChannel)
- {
- this._controlChannel.send(buffer);
- this._controlChannel = null;
- }
- if (this._ws)
- {
- this._ws.close();
- this._ws = null;
- }
- if (this._pc)
- {
- this._pc.close();
- this._pc = null;
- }
- if (!this.exited) {
- this.exited = true;
- console.info("Exit");
- }
- return true;
- }
- })();
- RemotePlayer.prototype.snapshot = function() {
- var canvas = document.createElement("canvas");
- canvas.width = this.config.video.width | this.config.video.videoWidth;
- canvas.height = this.config.video.height | this.config.video.videoHeight;
- var ctx = canvas.getContext("2d");
- ctx.translate(canvas.width / 2, canvas.height / 2);
- ctx.scale(1, -1);
- ctx.translate(-canvas.width / 2, -canvas.height / 2);
- ctx.drawImage(this.config.video, 0, 0, canvas.width, canvas.height);
- var img = document.createElement("img");
- img.src = canvas.toDataURL("image/jpeg", 1);
- img.save = function(){
- var alink = document.createElement("a");
- alink.href = img.src;
- alink.download = "snapshot.jpg";
- alink.click();
- }
- return img;
- };
|