diff --git a/Frontend/index.html b/Frontend/index.html index 428280a..ba5f807 100644 --- a/Frontend/index.html +++ b/Frontend/index.html @@ -11,3 +11,7 @@ + + + diff --git a/Frontend/public/webrtc-streamer/webrtcstreamer.js b/Frontend/public/webrtc-streamer/webrtcstreamer.js new file mode 100644 index 0000000..2ebabb3 --- /dev/null +++ b/Frontend/public/webrtc-streamer/webrtcstreamer.js @@ -0,0 +1,317 @@ +var WebRtcStreamer = (function () { + + /** + * Interface with WebRTC-streamer API + * @constructor + * @param {string} videoElement - id of the video element tag + * @param {string} srvurl - url of webrtc-streamer (default is current location) + */ + var WebRtcStreamer = function WebRtcStreamer(videoElement, srvurl) { + if (typeof videoElement === "string") { + this.videoElement = document.getElementById(videoElement); + } else { + this.videoElement = videoElement; + } + this.srvurl = srvurl || location.protocol + "//" + window.location.hostname + ":" + window.location.port; + this.pc = null; + + this.mediaConstraints = {offerToReceiveAudio: true, offerToReceiveVideo: true}; + + this.iceServers = null; + this.earlyCandidates = []; + } + + WebRtcStreamer.prototype._handleHttpErrors = function (response) { + if (!response.ok) { + throw Error(response.statusText); + } + return response; + } + + /** + * Connect a WebRTC Stream to videoElement + * @param {string} videourl - id of WebRTC video stream + * @param {string} audiourl - id of WebRTC audio stream + * @param {string} options - options of WebRTC call + * @param {string} stream - local stream to send + */ + WebRtcStreamer.prototype.connect = function (videourl, audiourl, options, localstream) { + this.disconnect(); + + // getIceServers is not already received + if (!this.iceServers) { + console.log("Get IceServers"); + + fetch(this.srvurl + "/api/getIceServers") + .then(this._handleHttpErrors) + .then((response) => (response.json())) + .then((response) => this.onReceiveGetIceServers.call(this, response, videourl, audiourl, options, localstream)) + .catch((error) => this.onError("getIceServers " + error)) + + } else { + this.onReceiveGetIceServers(this.iceServers, videourl, audiourl, options, localstream); + } + } + + /** + * Disconnect a WebRTC Stream and clear videoElement source + */ + WebRtcStreamer.prototype.disconnect = function () { + if (this.videoElement?.srcObject) { + this.videoElement.srcObject.getTracks().forEach(track => { + track.stop() + this.videoElement.srcObject.removeTrack(track); + }); + } + if (this.pc) { + fetch(this.srvurl + "/api/hangup?peerid=" + this.pc.peerid) + .then(this._handleHttpErrors) + .catch((error) => this.onError("hangup " + error)) + + + try { + this.pc.close(); + } catch (e) { + console.log("Failure close peer connection:" + e); + } + this.pc = null; + } + } + + /* + * GetIceServers callback + */ + WebRtcStreamer.prototype.onReceiveGetIceServers = function (iceServers, videourl, audiourl, options, stream) { + this.iceServers = iceServers; + this.pcConfig = iceServers || {"iceServers": []}; + try { + this.createPeerConnection(); + + var callurl = this.srvurl + "/api/call?peerid=" + this.pc.peerid + "&url=" + encodeURIComponent(videourl); + if (audiourl) { + callurl += "&audiourl=" + encodeURIComponent(audiourl); + } + if (options) { + callurl += "&options=" + encodeURIComponent(options); + } + + if (stream) { + this.pc.addStream(stream); + } + + // clear early candidates + this.earlyCandidates.length = 0; + + // create Offer + var bind = this; + this.pc.createOffer(this.mediaConstraints).then(function (sessionDescription) { + console.log("Create offer:" + JSON.stringify(sessionDescription)); + + bind.pc.setLocalDescription(sessionDescription + , function () { + fetch(callurl, {method: "POST", body: JSON.stringify(sessionDescription)}) + .then(bind._handleHttpErrors) + .then((response) => (response.json())) + .catch((error) => bind.onError("call " + error)) + .then((response) => bind.onReceiveCall.call(bind, response)) + .catch((error) => bind.onError("call " + error)) + + } + , function (error) { + console.log("setLocalDescription error:" + JSON.stringify(error)); + }); + + }, function (error) { + alert("Create offer error:" + JSON.stringify(error)); + }); + + } catch (e) { + this.disconnect(); + alert("connect error: " + e); + } + } + + + WebRtcStreamer.prototype.getIceCandidate = function () { + fetch(this.srvurl + "/api/getIceCandidate?peerid=" + this.pc.peerid) + .then(this._handleHttpErrors) + .then((response) => (response.json())) + .then((response) => this.onReceiveCandidate.call(this, response)) + .catch((error) => bind.onError("getIceCandidate " + error)) + } + + /* + * create RTCPeerConnection + */ + WebRtcStreamer.prototype.createPeerConnection = function () { + console.log("createPeerConnection config: " + JSON.stringify(this.pcConfig)); + this.pc = new RTCPeerConnection(this.pcConfig); + var pc = this.pc; + pc.peerid = Math.random(); + + var bind = this; + pc.onicecandidate = function (evt) { + bind.onIceCandidate.call(bind, evt); + }; + pc.onaddstream = function (evt) { + bind.onAddStream.call(bind, evt); + }; + pc.oniceconnectionstatechange = function (evt) { + console.log("oniceconnectionstatechange state: " + pc.iceConnectionState); + if (bind.videoElement) { + if (pc.iceConnectionState === "connected") { + bind.videoElement.style.opacity = "1.0"; + } else if (pc.iceConnectionState === "disconnected") { + bind.videoElement.style.opacity = "0.25"; + } else if ((pc.iceConnectionState === "failed") || (pc.iceConnectionState === "closed")) { + bind.videoElement.style.opacity = "0.5"; + } else if (pc.iceConnectionState === "new") { + bind.getIceCandidate.call(bind) + } + } + } + pc.ondatachannel = function (evt) { + console.log("remote datachannel created:" + JSON.stringify(evt)); + + evt.channel.onopen = function () { + console.log("remote datachannel open"); + this.send("remote channel openned"); + } + evt.channel.onmessage = function (event) { + console.log("remote datachannel recv:" + JSON.stringify(event.data)); + } + } + pc.onicegatheringstatechange = function () { + if (pc.iceGatheringState === "complete") { + const recvs = pc.getReceivers(); + + recvs.forEach((recv) => { + if (recv.track && recv.track.kind === "video") { + console.log("codecs:" + JSON.stringify(recv.getParameters().codecs)) + } + }); + } + } + + try { + var dataChannel = pc.createDataChannel("ClientDataChannel"); + dataChannel.onopen = function () { + console.log("local datachannel open"); + this.send("local channel openned"); + } + dataChannel.onmessage = function (evt) { + console.log("local datachannel recv:" + JSON.stringify(evt.data)); + } + } catch (e) { + console.log("Cannor create datachannel error: " + e); + } + + console.log("Created RTCPeerConnnection with config: " + JSON.stringify(this.pcConfig)); + return pc; + } + + + /* + * RTCPeerConnection IceCandidate callback + */ + WebRtcStreamer.prototype.onIceCandidate = function (event) { + if (event.candidate) { + if (this.pc.currentRemoteDescription) { + this.addIceCandidate(this.pc.peerid, event.candidate); + } else { + this.earlyCandidates.push(event.candidate); + } + } else { + console.log("End of candidates."); + } + } + + + WebRtcStreamer.prototype.addIceCandidate = function (peerid, candidate) { + fetch(this.srvurl + "/api/addIceCandidate?peerid=" + peerid, {method: "POST", body: JSON.stringify(candidate)}) + .then(this._handleHttpErrors) + .then((response) => (response.json())) + .then((response) => { + console.log("addIceCandidate ok:" + response) + }) + .catch((error) => this.onError("addIceCandidate " + error)) + } + + /* + * RTCPeerConnection AddTrack callback + */ + WebRtcStreamer.prototype.onAddStream = function (event) { + console.log("Remote track added:" + JSON.stringify(event)); + + this.videoElement.srcObject = event.stream; + var promise = this.videoElement.play(); + if (promise !== undefined) { + var bind = this; + promise.catch(function (error) { + console.warn("error:" + error); + bind.videoElement.setAttribute("controls", true); + }); + } + } + + /* + * AJAX /call callback + */ + WebRtcStreamer.prototype.onReceiveCall = function (dataJson) { + var bind = this; + console.log("offer: " + JSON.stringify(dataJson)); + var descr = new RTCSessionDescription(dataJson); + this.pc.setRemoteDescription(descr + , function () { + console.log("setRemoteDescription ok"); + while (bind.earlyCandidates.length) { + var candidate = bind.earlyCandidates.shift(); + bind.addIceCandidate.call(bind, bind.pc.peerid, candidate); + } + + bind.getIceCandidate.call(bind) + } + , function (error) { + console.log("setRemoteDescription error:" + JSON.stringify(error)); + }); + } + + /* + * AJAX /getIceCandidate callback + */ + WebRtcStreamer.prototype.onReceiveCandidate = function (dataJson) { + console.log("candidate: " + JSON.stringify(dataJson)); + if (dataJson) { + for (var i = 0; i < dataJson.length; i++) { + var candidate = new RTCIceCandidate(dataJson[i]); + + console.log("Adding ICE candidate :" + JSON.stringify(candidate)); + this.pc.addIceCandidate(candidate + , function () { + console.log("addIceCandidate OK"); + } + , function (error) { + console.log("addIceCandidate error:" + JSON.stringify(error)); + }); + } + this.pc.addIceCandidate(); + } + } + + + /* + * AJAX callback for Error + */ + WebRtcStreamer.prototype.onError = function (status) { + console.log("onError:" + status); + } + + return WebRtcStreamer; +})(); + +if (typeof window !== 'undefined' && typeof window.document !== 'undefined') { + window.WebRtcStreamer = WebRtcStreamer; +} +if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') { + module.exports = WebRtcStreamer; +} diff --git a/Frontend/src/api/cameraBase/cameraApi.ts b/Frontend/src/api/cameraBase/cameraApi.ts new file mode 100644 index 0000000..4aebedd --- /dev/null +++ b/Frontend/src/api/cameraBase/cameraApi.ts @@ -0,0 +1,25 @@ +import {axios} from '@/utils/axios'; +import {apiUrl} from "@/api"; + +enum Api { + Add = '/cbCamera/add', + Update = '/cbCamera/update', + Delete = '/cbCamera/delete', + Get = '/cbCamera/get', + GetList = '/cbCamera/getList', + GetPageList = '/cbCamera/getPageList', +} + +const CisApiUrl = apiUrl.CisApiUrl; + +export const Add = (params?: any) => axios.post(CisApiUrl + Api.Add, params) + +export const Update = (params?: any) => axios.post(CisApiUrl + Api.Update, params) + +export const Delete = (params?: any) => axios.post(CisApiUrl + Api.Delete, params) + +export const Get = (params?: any) => axios.get(CisApiUrl + Api.Get, {params: params}) + +export const GetList = (params?: any) => axios.get(CisApiUrl + Api.GetList, {params: params}) + +export const GetPageList = (params?: any) => axios.get(CisApiUrl + Api.GetPageList, {params: params}) diff --git a/Frontend/src/api/cameraMark/cameraGroupApi.ts b/Frontend/src/api/cameraMark/cameraGroupApi.ts new file mode 100644 index 0000000..414e6f0 --- /dev/null +++ b/Frontend/src/api/cameraMark/cameraGroupApi.ts @@ -0,0 +1,25 @@ +import {axios} from '@/utils/axios'; +import {apiUrl} from "@/api"; + +enum Api { + Add = '/cmMarkGroup/add', + Update = '/cmMarkGroup/update', + Delete = '/cmMarkGroup/delete', + Get = '/cmMarkGroup/get', + GetList = '/cmMarkGroup/getList', + GetPageList = '/cmMarkGroup/getPageList', +} + +const CisApiUrl = apiUrl.CisApiUrl; + +export const Add = (params?: any) => axios.post(CisApiUrl + Api.Add, params) + +export const Update = (params?: any) => axios.post(CisApiUrl + Api.Update, params) + +export const Delete = (params?: any) => axios.post(CisApiUrl + Api.Delete, params) + +export const Get = (params?: any) => axios.get(CisApiUrl + Api.Get, {params: params}) + +export const GetList = (params?: any) => axios.get(CisApiUrl + Api.GetList, {params: params}) + +export const GetPageList = (params?: any) => axios.get(CisApiUrl + Api.GetPageList, {params: params}) diff --git a/Frontend/src/api/cameraMark/cameraLabelApi.ts b/Frontend/src/api/cameraMark/cameraLabelApi.ts new file mode 100644 index 0000000..414e6f0 --- /dev/null +++ b/Frontend/src/api/cameraMark/cameraLabelApi.ts @@ -0,0 +1,25 @@ +import {axios} from '@/utils/axios'; +import {apiUrl} from "@/api"; + +enum Api { + Add = '/cmMarkGroup/add', + Update = '/cmMarkGroup/update', + Delete = '/cmMarkGroup/delete', + Get = '/cmMarkGroup/get', + GetList = '/cmMarkGroup/getList', + GetPageList = '/cmMarkGroup/getPageList', +} + +const CisApiUrl = apiUrl.CisApiUrl; + +export const Add = (params?: any) => axios.post(CisApiUrl + Api.Add, params) + +export const Update = (params?: any) => axios.post(CisApiUrl + Api.Update, params) + +export const Delete = (params?: any) => axios.post(CisApiUrl + Api.Delete, params) + +export const Get = (params?: any) => axios.get(CisApiUrl + Api.Get, {params: params}) + +export const GetList = (params?: any) => axios.get(CisApiUrl + Api.GetList, {params: params}) + +export const GetPageList = (params?: any) => axios.get(CisApiUrl + Api.GetPageList, {params: params}) diff --git a/Frontend/src/api/cameraMark/markSearchApi.ts b/Frontend/src/api/cameraMark/markSearchApi.ts new file mode 100644 index 0000000..e2a5d0c --- /dev/null +++ b/Frontend/src/api/cameraMark/markSearchApi.ts @@ -0,0 +1,22 @@ +import {axios} from '@/utils/axios'; +import {apiUrl} from "@/api"; + +enum Api { + ActiveCamera = '/markSearch/activeCamera', + DeActiveCamera = '/markSearch/deActiveCamera', + AddCameraMarkLabel = '/markSearch/addCameraMarkLabel', + DeleteCameraMarkLabel = '/markSearch/deleteCameraMarkLabel', + GetMarkLabelCalcResultList = '/markSearch/GetMarkLabelCalcResultList', +} + +const CisApiUrl = apiUrl.CisApiUrl; + +export const ActiveCamera = (params?: any) => axios.post(CisApiUrl + Api.ActiveCamera, params) + +export const DeActiveCamera = (params?: any) => axios.post(CisApiUrl + Api.DeActiveCamera, params) + +export const AddCameraMarkLabel = (params?: any) => axios.post(CisApiUrl + Api.AddCameraMarkLabel, params) + +export const DeleteCameraMarkLabel = (params?: any) => axios.post(CisApiUrl + Api.DeleteCameraMarkLabel, params) + +export const GetMarkLabelCalcResultList = (params?: any) => axios.get(CisApiUrl + Api.GetMarkLabelCalcResultList, {params: params}) diff --git a/Frontend/src/api/index.ts b/Frontend/src/api/index.ts new file mode 100644 index 0000000..216ba89 --- /dev/null +++ b/Frontend/src/api/index.ts @@ -0,0 +1,5 @@ +export const apiUrl = { + CisApiUrl: 'http://192.168.1.119:5000/api', + WebRtcUrl: 'http://192.168.1.119:8000', + // CisApiUrl: 'https://192.168.1.119:5001/api' +} diff --git a/Frontend/src/style.css b/Frontend/src/style.css index 8b4823d..06b3802 100644 --- a/Frontend/src/style.css +++ b/Frontend/src/style.css @@ -26,4 +26,4 @@ input { border: none; background: transparent; outline: none; -} \ No newline at end of file +} diff --git a/Frontend/src/utils/axios.ts b/Frontend/src/utils/axios.ts new file mode 100644 index 0000000..8a918b0 --- /dev/null +++ b/Frontend/src/utils/axios.ts @@ -0,0 +1,12 @@ +import axios from "axios"; + +let apiBaseUrl = "/api"; + +const service = axios.create({ + baseURL: apiBaseUrl, // api base_url + timeout: 9000 // 请求超时时间 +}) + +export { + service as axios, +} \ No newline at end of file diff --git a/Frontend/src/views/cameraBase/camera/index.vue b/Frontend/src/views/cameraBase/camera/index.vue new file mode 100644 index 0000000..4bb1816 --- /dev/null +++ b/Frontend/src/views/cameraBase/camera/index.vue @@ -0,0 +1,13 @@ + + + + + \ No newline at end of file diff --git a/Frontend/src/views/cameraMark/markGroup/index.vue b/Frontend/src/views/cameraMark/markGroup/index.vue new file mode 100644 index 0000000..4bb1816 --- /dev/null +++ b/Frontend/src/views/cameraMark/markGroup/index.vue @@ -0,0 +1,13 @@ + + + + + \ No newline at end of file diff --git a/Frontend/src/views/cameraMark/markLabel/index.vue b/Frontend/src/views/cameraMark/markLabel/index.vue new file mode 100644 index 0000000..4bb1816 --- /dev/null +++ b/Frontend/src/views/cameraMark/markLabel/index.vue @@ -0,0 +1,13 @@ + + + + + \ No newline at end of file diff --git a/Frontend/src/views/index.vue b/Frontend/src/views/index.vue index a0ae5cf..6a8e726 100644 --- a/Frontend/src/views/index.vue +++ b/Frontend/src/views/index.vue @@ -1,5 +1,5 @@ - \ No newline at end of file diff --git a/Frontend/src/views/page/cameraCenter.vue b/Frontend/src/views/page/cameraCenter.vue new file mode 100644 index 0000000..bbd439f --- /dev/null +++ b/Frontend/src/views/page/cameraCenter.vue @@ -0,0 +1,121 @@ + + + + + \ No newline at end of file diff --git a/Frontend/src/views/page/Curd.vue b/Frontend/src/views/page/curd.vue similarity index 95% rename from Frontend/src/views/page/Curd.vue rename to Frontend/src/views/page/curd.vue index e8b79b1..54172ff 100644 --- a/Frontend/src/views/page/Curd.vue +++ b/Frontend/src/views/page/curd.vue @@ -1,5 +1,5 @@ +