From 418a8806dba90a2463f194da759ed6338018d7d2 Mon Sep 17 00:00:00 2001
From: ‘liusuyi’ <1951119284@qq.com>
Date: 星期一, 28 八月 2023 16:02:28 +0800
Subject: [PATCH] 增加实时报警聚合接口all

---
 /dev/null                                                                              |   80 --------
 ard-work/src/main/java/com/ruoyi/alarm/global/controller/GlobalAlarmController.java    |    7 
 ard-work/src/main/resources/templates/test.html                                        |   37 --
 ard-work/src/main/java/com/ruoyi/alarm/global/service/IGlobalAlarmService.java         |    1 
 ard-work/src/main/java/com/ruoyi/alarm/global/service/impl/GlobalAlarmServiceImpl.java |  172 ++++++++++++++++
 ard-work/src/main/resources/templates/mediaMTX.html                                    |  283 ++++++++++++++++++++++++++++
 ard-work/src/main/java/com/ruoyi/device/hiksdk/controller/SdkController.java           |    5 
 7 files changed, 469 insertions(+), 116 deletions(-)

diff --git a/ard-work/src/main/java/com/ruoyi/alarm/global/controller/GlobalAlarmController.java b/ard-work/src/main/java/com/ruoyi/alarm/global/controller/GlobalAlarmController.java
index ae518cb..0b7e7a6 100644
--- a/ard-work/src/main/java/com/ruoyi/alarm/global/controller/GlobalAlarmController.java
+++ b/ard-work/src/main/java/com/ruoyi/alarm/global/controller/GlobalAlarmController.java
@@ -45,6 +45,13 @@
         List<GlobalAlarmData> result = globalAlarmService.selectAlarmLogs(condition);
         return AjaxResult.success(result);
     }
+    @GetMapping("/AllList")
+    @ApiOperation(value = "瀹炴椂鎶ヨ鑱氬悎鎺ュ彛(all)",notes = "鎸夋姤璀﹀埛鏂版椂闂磋仛鍚堟煡璇�")
+    @ApiOperationSupport(includeParameters = {"command"},order = 1)
+    public AjaxResult selectAlarmLogAll() {
+        List<GlobalAlarmData> result = globalAlarmService.selectAlarmLogsAll();
+        return AjaxResult.success(result);
+    }
     @PostMapping("/view")
     @ApiOperation(value = "鏌ョ湅鎶ヨ鎺ュ彛",notes = "鎸囧畾鏌ョ湅鏌愪釜鎶ヨ鏁版嵁")
     @ApiOperationSupport(includeParameters = {"command","id"},order = 3)
diff --git a/ard-work/src/main/java/com/ruoyi/alarm/global/service/IGlobalAlarmService.java b/ard-work/src/main/java/com/ruoyi/alarm/global/service/IGlobalAlarmService.java
index ecdb659..c4b6d45 100644
--- a/ard-work/src/main/java/com/ruoyi/alarm/global/service/IGlobalAlarmService.java
+++ b/ard-work/src/main/java/com/ruoyi/alarm/global/service/IGlobalAlarmService.java
@@ -15,6 +15,7 @@
  **/
 public interface IGlobalAlarmService {
     public List<GlobalAlarmData> selectAlarmLogs(GlobalAlarmCondition condition);
+    public List<GlobalAlarmData> selectAlarmLogsAll();
     Object updateAlarmViewTime(GlobalAlarmCondition condition);
     public void receiveAlarm(String topic,String message);
     public Map<String,Object> selectAlarmLogsCount();
diff --git a/ard-work/src/main/java/com/ruoyi/alarm/global/service/impl/GlobalAlarmServiceImpl.java b/ard-work/src/main/java/com/ruoyi/alarm/global/service/impl/GlobalAlarmServiceImpl.java
index 4cefccd..1572fae 100644
--- a/ard-work/src/main/java/com/ruoyi/alarm/global/service/impl/GlobalAlarmServiceImpl.java
+++ b/ard-work/src/main/java/com/ruoyi/alarm/global/service/impl/GlobalAlarmServiceImpl.java
@@ -278,6 +278,167 @@
         }
     }
 
+    @Override
+    public List<GlobalAlarmData> selectAlarmLogsAll() {
+        List<GlobalAlarmData> GlobalAlarmDataList = new ArrayList<>();
+        String refreshTime = configService.selectConfigByKey("refreshTime");
+        List<ArdAlarmStealelec> ardAlarmStealelecs = ardAlarmStealelecMapper.selectListAllByCommand(refreshTime);
+        List<GlobalAlarmData> alarmData1001 = ardAlarmStealelecs.stream()
+                .map(ardAlarmStealelec -> {
+                    GlobalAlarmData globalAlarmData = new GlobalAlarmData()
+                            .setId(ardAlarmStealelec.getId())
+                            .setName(ardAlarmStealelec.getDescribe())
+                            .setAlarmTime(ardAlarmStealelec.getStartTime())
+                            .setLongitude(ardAlarmStealelec.getLongitude())
+                            .setLatitude(ardAlarmStealelec.getLatitude())
+                            .setAltitude(ardAlarmStealelec.getAltitude())
+                            .setCount(ardAlarmStealelec.getCount())
+                            .setTotal(ardAlarmStealelec.getTotal());
+                    return globalAlarmData;
+                }).collect(Collectors.toList());
+        if(alarmData1001.size()>0) {
+            GlobalAlarmDataList.addAll(alarmData1001);
+        }
+
+        List<ArdAlarmCamera> ardAlarmCameras = ardAlarmCameraMapper.selectListAllByCommand(refreshTime);
+        List<GlobalAlarmData> alarmData1002= ardAlarmCameras.stream()
+                .map(ardAlarmCamera -> {
+                    GlobalAlarmData globalAlarmData = new GlobalAlarmData()
+                            .setId(ardAlarmCamera.getId())
+                            .setName(ardAlarmCamera.getCameraName())
+                            .setAlarmTime(ardAlarmCamera.getAlarmTime())
+                            .setLongitude(ardAlarmCamera.getLongitude())
+                            .setLatitude(ardAlarmCamera.getLatitude())
+                            .setCount(ardAlarmCamera.getCount())
+                            .setTotal(ardAlarmCamera.getTotal());
+                    return globalAlarmData;
+                }).collect(Collectors.toList());
+        if(alarmData1002.size()>0) {
+            GlobalAlarmDataList.addAll(alarmData1002);
+        }
+
+        List<ArdAlarmRadar> ardAlarmRadars = ardAlarmRadarMapper.selectListAllByCommand(refreshTime, "杩愬姩鐩爣妫�娴�");
+        List<GlobalAlarmData> alarmData1003= ardAlarmRadars.stream()
+                .map(ardAlarmRadar -> {
+                    GlobalAlarmData globalAlarmData = new GlobalAlarmData()
+                            .setId(ardAlarmRadar.getId())
+                            .setName(ardAlarmRadar.getName())
+                            .setAlarmTime(ardAlarmRadar.getAlarmTime())
+                            .setLongitude(ardAlarmRadar.getLongitude())
+                            .setLatitude(ardAlarmRadar.getLatitude())
+                            .setCount(ardAlarmRadar.getCount())
+                            .setTotal(ardAlarmRadar.getTotal());
+                    return globalAlarmData;
+                }).collect(Collectors.toList());
+        if(alarmData1003.size()>0) {
+            GlobalAlarmDataList.addAll(alarmData1003);
+        }
+
+        ardAlarmRadars = ardAlarmRadarMapper.selectListAllByCommand(refreshTime, "鐑簮妫�娴�");
+        List<GlobalAlarmData> alarmData1004=  ardAlarmRadars.stream()
+                .map(ardAlarmRadar -> {
+                    GlobalAlarmData globalAlarmData = new GlobalAlarmData()
+                            .setId(ardAlarmRadar.getId())
+                            .setName(ardAlarmRadar.getName())
+                            .setAlarmTime(ardAlarmRadar.getAlarmTime())
+                            .setLongitude(ardAlarmRadar.getLongitude())
+                            .setLatitude(ardAlarmRadar.getLatitude())
+                            .setCount(ardAlarmRadar.getCount())
+                            .setTotal(ardAlarmRadar.getTotal());
+                    return globalAlarmData;
+                }).collect(Collectors.toList());
+        if(alarmData1004.size()>0) {
+            GlobalAlarmDataList.addAll(alarmData1004);
+        }
+
+        List<ArdAlarmExternal> ardAlarmExternals = ardAlarmExternalMapper.selectListAllByCommand(refreshTime, "闃插尯鎶ヨ");
+        List<GlobalAlarmData> alarmData1005=  ardAlarmExternals.stream()
+                .map(ardAlarmExternal -> {
+                    GlobalAlarmData globalAlarmData = new GlobalAlarmData()
+                            .setId(ardAlarmExternal.getId())
+                            .setName(ardAlarmExternal.getAlarmName())
+                            .setAlarmTime(ardAlarmExternal.getAlarmTime())
+                            .setLongitude(ardAlarmExternal.getLongitude())
+                            .setLatitude(ardAlarmExternal.getLatitude())
+                            .setCount(ardAlarmExternal.getCount())
+                            .setTotal(ardAlarmExternal.getTotal());
+                    return globalAlarmData;
+                }).collect(Collectors.toList());
+        if(alarmData1005.size()>0) {
+            GlobalAlarmDataList.addAll(alarmData1005);
+        }
+
+        List<ArdAlarmAccess> ardAlarmAccesses = ardAlarmAccessMapper.selectListAllByCommand(refreshTime);
+        List<GlobalAlarmData> alarmData1006= ardAlarmAccesses.stream()
+                .map(ardAlarmAccess -> {
+                    GlobalAlarmData globalAlarmData = new GlobalAlarmData()
+                            .setId(ardAlarmAccess.getId())
+                            .setName(ardAlarmAccess.getAcsName())
+                            .setAlarmTime(ardAlarmAccess.getAlarmTime())
+                            .setLongitude(ardAlarmAccess.getLongitude())
+                            .setLatitude(ardAlarmAccess.getLatitude())
+                            .setCount(ardAlarmAccess.getCount())
+                            .setTotal(ardAlarmAccess.getTotal());
+                    return globalAlarmData;
+                }).collect(Collectors.toList());
+        if(alarmData1006.size()>0) {
+            GlobalAlarmDataList.addAll(alarmData1006);
+        }
+
+        ardAlarmRadars = ardAlarmRadarMapper.selectListAllByCommand(refreshTime, "闆疯揪鎶芥补鏈哄仠鏈�");
+        List<GlobalAlarmData> alarmData1007= ardAlarmRadars.stream()
+                .map(ardAlarmRadar -> {
+                    GlobalAlarmData globalAlarmData = new GlobalAlarmData()
+                            .setId(ardAlarmRadar.getId())
+                            .setName(ardAlarmRadar.getName())
+                            .setAlarmTime(ardAlarmRadar.getAlarmTime())
+                            .setLongitude(ardAlarmRadar.getLongitude())
+                            .setLatitude(ardAlarmRadar.getLatitude())
+                            .setCount(ardAlarmRadar.getCount())
+                            .setTotal(ardAlarmRadar.getTotal());
+                    return globalAlarmData;
+                }).collect(Collectors.toList());
+        if(alarmData1007.size()>0) {
+            GlobalAlarmDataList.addAll(alarmData1007);
+        }
+
+        List<ArdAlarmApponekey> ardAlarmApponekeys = ardAlarmApponekeyMapper.selectListAllByCommand(refreshTime);
+        List<GlobalAlarmData> alarmData1009= ardAlarmApponekeys.stream()
+                .map(ardAlarmApponekey -> {
+                    GlobalAlarmData globalAlarmData = new GlobalAlarmData()
+                            .setId(ardAlarmApponekey.getId())
+                            .setName(ardAlarmApponekey.getName())
+                            .setAlarmTime(ardAlarmApponekey.getCreateTime())
+                            .setLongitude(ardAlarmApponekey.getLongitude())
+                            .setLatitude(ardAlarmApponekey.getLatitude())
+                            .setCount(ardAlarmApponekey.getCount())
+                            .setTotal(ardAlarmApponekey.getTotal());
+                    return globalAlarmData;
+                }).collect(Collectors.toList());
+        if(alarmData1009.size()>0) {
+            GlobalAlarmDataList.addAll(alarmData1009);
+        }
+
+        List<ArdAlarmTube> ardAlarmTubes = ardAlarmTubeMapper.selectListAllByCommand(refreshTime);
+        List<GlobalAlarmData> alarmData1014= ardAlarmTubes.stream()
+                .map(ardAlarmTube -> {
+                    GlobalAlarmData globalAlarmData = new GlobalAlarmData()
+                            .setId(ardAlarmTube.getId())
+                            .setName(ardAlarmTube.getTubeName())
+                            .setAlarmTime(ardAlarmTube.getAlarmTime())
+                            .setLongitude(ardAlarmTube.getLongitude())
+                            .setLatitude(ardAlarmTube.getLatitude())
+                            .setAltitude(ardAlarmTube.getAltitude())
+                            .setCount(ardAlarmTube.getCount())
+                            .setTotal(ardAlarmTube.getTotal());
+                    return globalAlarmData;
+                }).collect(Collectors.toList());
+        if(alarmData1014.size()>0) {
+            GlobalAlarmDataList.addAll(alarmData1014);
+        }
+        return GlobalAlarmDataList;
+}
+
     /**
      * @鎻忚堪 鍘嗗彶鎶ヨ鏌ヨ
      * @鍙傛暟 [command, beginTime, endTime, pageNum, pageSize]
@@ -542,9 +703,8 @@
                     }
                     //鎸夊叴瓒g偣鍘婚噸,鐒跺悗鎸夊紩瀵奸�昏緫杩涜寮曞鍏ラ槦
                     ardAlarmRadars = ardAlarmRadars.stream()
-                    .collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new java.util.TreeSet<>(java.util.Comparator.comparing(ArdAlarmRadar::getName))), ArrayList::new));
-                    for(ArdAlarmRadar ardAlarmRadar : ardAlarmRadars)
-                    {
+                            .collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new java.util.TreeSet<>(java.util.Comparator.comparing(ArdAlarmRadar::getName))), ArrayList::new));
+                    for (ArdAlarmRadar ardAlarmRadar : ardAlarmRadars) {
                         //閬嶅巻鎶ヨ鏁版嵁杩涜寮曞
                         if (StringUtils.isNull(ardAlarmRadar.getLongitude()) || StringUtils.isNull(ardAlarmRadar.getLatitude())) {
                             //鍧愭爣涓虹┖涓嶅紩瀵�
@@ -766,10 +926,8 @@
                     return " ";
                 }
             }
-        }
-        catch (Exception ex)
-        {
-            log.error("鑾峰彇闄勮繎寮�鍚姤璀﹀紩瀵煎姛鑳藉厜鐢靛紓甯�:"+ex.getMessage());
+        } catch (Exception ex) {
+            log.error("鑾峰彇闄勮繎寮�鍚姤璀﹀紩瀵煎姛鑳藉厜鐢靛紓甯�:" + ex.getMessage());
         }
         return minDistanceCameraId;
     }
diff --git a/ard-work/src/main/java/com/ruoyi/device/hiksdk/controller/SdkController.java b/ard-work/src/main/java/com/ruoyi/device/hiksdk/controller/SdkController.java
index 5ea793d..2053d50 100644
--- a/ard-work/src/main/java/com/ruoyi/device/hiksdk/controller/SdkController.java
+++ b/ard-work/src/main/java/com/ruoyi/device/hiksdk/controller/SdkController.java
@@ -59,7 +59,10 @@
     private String index() {
         return "test";
     }
-
+    @RequestMapping("/media")
+    private String media() {
+        return "mediaMTX";
+    }
     @GetMapping("/list")
     public @ResponseBody
     AjaxResult list(ArdCameras ardCamera) {
diff --git a/ard-work/src/main/resources/static/js/WHEPClient.js b/ard-work/src/main/resources/static/js/WHEPClient.js
deleted file mode 100644
index f84398b..0000000
--- a/ard-work/src/main/resources/static/js/WHEPClient.js
+++ /dev/null
@@ -1,76 +0,0 @@
-import negotiateConnectionWithClientOffer from "./negotiateConnectionWithClientOffer.js";
-/**
- * Example implementation of a client that uses WHEP to playback video over WebRTC
- *
- * https://www.ietf.org/id/draft-murillo-whep-00.html
- */
-export default class WHEPClient {
-	constructor(endpoint, videoElement) {
-		this.endpoint = endpoint;
-		this.videoElement = videoElement;
-		this.stream = new MediaStream();
-		/**
-		 * Create a new WebRTC connection, using public STUN servers with ICE,
-		 * allowing the client to disover its own IP address.
-		 * https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API/Protocols#ice
-		 */
-		this.peerConnection = new RTCPeerConnection({
-			iceServers: [
-				{
-					urls: "stun:stun.cloudflare.com:3478",
-				},
-			],
-			bundlePolicy: "max-bundle",
-		});
-		/** https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/addTransceiver */
-		this.peerConnection.addTransceiver("video", {
-			direction: "recvonly",
-		});
-		this.peerConnection.addTransceiver("audio", {
-			direction: "recvonly",
-		});
-		/**
-		 * When new tracks are received in the connection, store local references,
-		 * so that they can be added to a MediaStream, and to the <video> element.
-		 *
-		 * https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/track_event
-		 */
-		this.peerConnection.ontrack = (event) => {
-			const track = event.track;
-			const currentTracks = this.stream.getTracks();
-			const streamAlreadyHasVideoTrack = currentTracks.some(
-				(track) => track.kind === "video"
-			);
-			const streamAlreadyHasAudioTrack = currentTracks.some(
-				(track) => track.kind === "audio"
-			);
-			switch (track.kind) {
-				case "video":
-					if (streamAlreadyHasVideoTrack) {
-						break;
-					}
-					this.stream.addTrack(track);
-					break;
-				case "audio":
-					if (streamAlreadyHasAudioTrack) {
-						break;
-					}
-					this.stream.addTrack(track);
-					break;
-				default:
-					console.log("got unknown track " + track);
-			}
-		};
-		this.peerConnection.addEventListener("connectionstatechange", (ev) => {
-			if (this.peerConnection.connectionState !== "connected") {
-				return;
-			}
-			if (!this.videoElement.srcObject) {
-				this.videoElement.srcObject = this.stream;
-			}
-		});
-		this.peerConnection.addEventListener("negotiationneeded", (ev) => {
-			negotiateConnectionWithClientOffer(this.peerConnection, this.endpoint);
-		});
-	}
-}
diff --git a/ard-work/src/main/resources/static/js/negotiateConnectionWithClientOffer.js b/ard-work/src/main/resources/static/js/negotiateConnectionWithClientOffer.js
deleted file mode 100644
index 26c70b6..0000000
--- a/ard-work/src/main/resources/static/js/negotiateConnectionWithClientOffer.js
+++ /dev/null
@@ -1,80 +0,0 @@
-/**
- * Performs the actual SDP exchange.
- *
- * 1. Constructs the client's SDP offer
- * 2. Sends the SDP offer to the server,
- * 3. Awaits the server's offer.
- *
- * SDP describes what kind of media we can send and how the server and client communicate.
- *
- * https://developer.mozilla.org/en-US/docs/Glossary/SDP
- * https://www.ietf.org/archive/id/draft-ietf-wish-whip-01.html#name-protocol-operation
- */
-export default async function negotiateConnectionWithClientOffer(
-	peerConnection,
-	endpoint
-) {
-	/** https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/createOffer */
-	const offer = await peerConnection.createOffer();
-	/** https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/setLocalDescription */
-	await peerConnection.setLocalDescription(offer);
-	/** Wait for ICE gathering to complete */
-	let ofr = await waitToCompleteICEGathering(peerConnection);
-	if (!ofr) {
-		throw Error("failed to gather ICE candidates for offer");
-	}
-	/**
-	 * As long as the connection is open, attempt to...
-	 */
-	while (peerConnection.connectionState !== "closed") {
-		/**
-		 * This response contains the server's SDP offer.
-		 * This specifies how the client should communicate,
-		 * and what kind of media client and server have negotiated to exchange.
-		 */
-		let response = await postSDPOffer(endpoint, ofr.sdp);
-		if (response.status === 201) {
-			let answerSDP = await response.text();
-			await peerConnection.setRemoteDescription(
-				new RTCSessionDescription({ type: "answer", sdp: answerSDP })
-			);
-			return response.headers.get("Location");
-		} else if (response.status === 405) {
-			console.error("Update the URL passed into the WHIP or WHEP client");
-		} else {
-			const errorMessage = await response.text();
-			console.error(errorMessage);
-		}
-		/** Limit reconnection attempts to at-most once every 5 seconds */
-		await new Promise((r) => setTimeout(r, 5000));
-	}
-}
-async function postSDPOffer(endpoint, data) {
-	return await fetch(endpoint, {
-		method: "POST",
-		mode: "cors",
-		headers: {
-			"content-type": "application/sdp",
-		},
-		body: data,
-	});
-}
-/**
- * Receives an RTCPeerConnection and waits until
- * the connection is initialized or a timeout passes.
- *
- * https://www.ietf.org/archive/id/draft-ietf-wish-whip-01.html#section-4.1
- * https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/iceGatheringState
- * https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/icegatheringstatechange_event
- */
-async function waitToCompleteICEGathering(peerConnection) {
-	return new Promise((resolve) => {
-		/** Wait at most 1 second for ICE gathering. */
-		setTimeout(function () {
-			resolve(peerConnection.localDescription);
-		}, 1000);
-		peerConnection.onicegatheringstatechange = (ev) =>
-			peerConnection.iceGatheringState === "complete" &&
-			resolve(peerConnection.localDescription);
-	});
-}
diff --git a/ard-work/src/main/resources/templates/mediaMTX.html b/ard-work/src/main/resources/templates/mediaMTX.html
new file mode 100644
index 0000000..2ae58db
--- /dev/null
+++ b/ard-work/src/main/resources/templates/mediaMTX.html
@@ -0,0 +1,283 @@
+<!DOCTYPE html>
+<html lang="en" xmlns:th="http://www.thymeleaf.org">
+<head>
+    <meta charset="UTF-8">
+    <title>娴嬭瘯椤�</title>
+    <script th:src="@{/js/jquery-3.6.4.min.js}"></script>
+    <link rel="stylesheet" th:href="@{/css/bootstrap.css}"/>
+    <script th:src="@{/js/bootstrap.js}"></script>
+    <style>
+        .video-container {
+            display: inline-block;
+            vertical-align: top;
+            width: 25%; /* 鍏釜瑙嗛骞冲潎鍒嗛厤涓�琛岀殑瀹藉害 */
+            /*padding: 2px; !* 鍙互鏍规嵁闇�瑕佽皟鏁村唴杈硅窛 *!*/
+            box-sizing: border-box;
+        }
+
+        .video-container video {
+            width: 100%;
+            height: 100%;
+            /*object-fit: cover; !* 瑙嗛濉厖瀹瑰櫒锛屼繚鎸佸楂樻瘮 *!*/
+        }
+    </style>
+<body>
+<div>
+    <div class="row">
+        <div class="video-container">
+            <video id="video1" muted autoplay loop controls></video>
+        </div>
+        <div class="video-container">
+            <video id="video2" muted autoplay loop controls></video>
+        </div>
+        <div class="video-container">
+            <video id="video3" muted autoplay loop controls></video>
+        </div>
+        <div class="video-container">
+            <video id="video4" muted autoplay loop controls></video>
+        </div>
+        <div class="video-container">
+            <video id="video5" muted autoplay loop controls></video>
+        </div>
+    </div>
+</div>
+<script th:inline="javascript">
+    const restartPause = 2000;
+    const linkToIceServers = (links) => (
+        (links !== null) ? links.split(', ').map((link) => {
+            const m = link.match(/^<(.+?)>; rel="ice-server"(; username="(.*?)"; credential="(.*?)"; credential-type="password")?/i);
+            const ret = {
+                urls: [m[1]],
+            };
+
+            if (m[3] !== undefined) {
+                ret.username = unquoteCredential(m[3]);
+                ret.credential = unquoteCredential(m[4]);
+                ret.credentialType = "password";
+            }
+
+            return ret;
+        }) : []
+    );
+    const parseOffer = (offer) => {
+        const ret = {
+            iceUfrag: '',
+            icePwd: '',
+            medias: [],
+        };
+
+        for (const line of offer.split('\r\n')) {
+            if (line.startsWith('m=')) {
+                ret.medias.push(line.slice('m='.length));
+            } else if (ret.iceUfrag === '' && line.startsWith('a=ice-ufrag:')) {
+                ret.iceUfrag = line.slice('a=ice-ufrag:'.length);
+            } else if (ret.icePwd === '' && line.startsWith('a=ice-pwd:')) {
+                ret.icePwd = line.slice('a=ice-pwd:'.length);
+            }
+        }
+
+        return ret;
+    };
+    const generateSdpFragment = (offerData, candidates) => {
+        const candidatesByMedia = {};
+        for (const candidate of candidates) {
+            const mid = candidate.sdpMLineIndex;
+            if (candidatesByMedia[mid] === undefined) {
+                candidatesByMedia[mid] = [];
+            }
+            candidatesByMedia[mid].push(candidate);
+        }
+
+        let frag = 'a=ice-ufrag:' + offerData.iceUfrag + '\r\n'
+            + 'a=ice-pwd:' + offerData.icePwd + '\r\n';
+
+        let mid = 0;
+
+        for (const media of offerData.medias) {
+            if (candidatesByMedia[mid] !== undefined) {
+                frag += 'm=' + media + '\r\n'
+                    + 'a=mid:' + mid + '\r\n';
+
+                for (const candidate of candidatesByMedia[mid]) {
+                    frag += 'a=' + candidate.candidate + '\r\n';
+                }
+            }
+            mid++;
+        }
+
+        return frag;
+    }
+
+    class WHEPClient {
+        constructor(wurl, videoId) {
+            this.video = videoId;
+            this.url = new URL('whep', wurl);
+            this.pc = null;
+            this.restartTimeout = null;
+            this.eTag = '';
+            this.queuedCandidates = [];
+            this.start();
+        }
+
+        start() {
+            console.log("requesting ICE servers");
+            fetch(this.url, {
+                method: 'OPTIONS',
+            })
+                .then((res) => this.onIceServers(res))
+                .catch((err) => {
+                    console.log('error: ' + err);
+                    this.scheduleRestart();
+                });
+        }
+
+        onIceServers(res) {
+            this.pc = new RTCPeerConnection({
+                iceServers: linkToIceServers(res.headers.get('Link')),
+            });
+
+            const direction = "sendrecv";
+            this.pc.addTransceiver("video", {direction});
+            this.pc.addTransceiver("audio", {direction});
+
+            this.pc.onicecandidate = (evt) => this.onLocalCandidate(evt);
+            this.pc.oniceconnectionstatechange = () => this.onConnectionState();
+
+            this.pc.ontrack = (evt) => {
+                console.log("new track:", evt.track.kind);
+                document.getElementById(this.video).srcObject = evt.streams[0];
+            };
+
+            this.pc.createOffer()
+                .then((offer) => this.onLocalOffer(offer));
+        }
+
+        onLocalOffer(offer) {
+            this.offerData = parseOffer(offer.sdp);
+            this.pc.setLocalDescription(offer);
+
+            console.log("sending offer");
+
+            fetch(this.url, {
+                method: 'POST',
+                headers: {
+                    'Content-Type': 'application/sdp',
+                },
+                body: offer.sdp,
+            })
+                .then((res) => {
+                    if (res.status !== 201) {
+                        throw new Error('bad status code');
+                    }
+                    this.eTag = res.headers.get('E-Tag');
+                    return res.text();
+                })
+                .then((sdp) => this.onRemoteAnswer(new RTCSessionDescription({
+                    type: 'answer',
+                    sdp,
+                })))
+                .catch((err) => {
+                    console.log('error: ' + err);
+                    this.scheduleRestart();
+                });
+        }
+
+        onConnectionState() {
+            if (this.restartTimeout !== null) {
+                return;
+            }
+
+            console.log("peer connection state:", this.pc.iceConnectionState);
+
+            switch (this.pc.iceConnectionState) {
+                case "disconnected":
+                    this.scheduleRestart();
+            }
+        }
+
+        onRemoteAnswer(answer) {
+            if (this.restartTimeout !== null) {
+                return;
+            }
+
+            this.pc.setRemoteDescription(new RTCSessionDescription(answer));
+
+            if (this.queuedCandidates.length !== 0) {
+                this.sendLocalCandidates(this.queuedCandidates);
+                this.queuedCandidates = [];
+            }
+        }
+
+        onLocalCandidate(evt) {
+            if (this.restartTimeout !== null) {
+                return;
+            }
+
+            if (evt.candidate !== null) {
+                if (this.eTag === '') {
+                    this.queuedCandidates.push(evt.candidate);
+                } else {
+                    this.sendLocalCandidates([evt.candidate])
+                }
+            }
+        }
+
+        sendLocalCandidates(candidates) {
+            fetch(this.url, {
+                method: 'PATCH',
+                headers: {
+                    'Content-Type': 'application/trickle-ice-sdpfrag',
+                    'If-Match': this.eTag,
+                },
+                body: generateSdpFragment(this.offerData, candidates),
+            })
+                .then((res) => {
+                    if (res.status !== 204) {
+                        throw new Error('bad status code');
+                    }
+                })
+                .catch((err) => {
+                    console.log('error: ' + err);
+                    this.scheduleRestart();
+                });
+        }
+
+        scheduleRestart() {
+            if (this.restartTimeout !== null) {
+                return;
+            }
+
+            if (this.pc !== null) {
+                this.pc.close();
+                this.pc = null;
+            }
+
+            this.restartTimeout = window.setTimeout(() => {
+                this.restartTimeout = null;
+                this.start();
+            }, restartPause);
+
+            this.eTag = '';
+            this.queuedCandidates = [];
+        }
+    }
+
+    let videoMap = new Map();
+    $('video').click(function (e) {
+        let ID = e.target.id;//鑾峰彇褰撳墠鐐瑰嚮浜嬩欢鐨勫厓绱�
+        console.log(ID);
+        if (videoMap.get(ID) != null) {
+            closeVideo(ID, videoMap.get(ID));
+        } else {
+            let client = new WHEPClient("http://127.0.0.1:8889/165/", ID);
+            videoMap.set(ID, client);
+        }
+    });
+    function closeVideo(id) {
+        let elementById = document.getElementById(id);
+        elementById.pause();
+        videoMap.delete(id);
+    }
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/ard-work/src/main/resources/templates/test.html b/ard-work/src/main/resources/templates/test.html
index a55bf5e..3c125fa 100644
--- a/ard-work/src/main/resources/templates/test.html
+++ b/ard-work/src/main/resources/templates/test.html
@@ -13,20 +13,6 @@
             margin-top: 10px;
         }
     </style>
-    <!-- 瀵煎叆 ECMAScript 妯″潡 -->
-    <script th:type="module" th:src="@{/js/WHEPClient.js}"></script>
-    <!-- 鍐呰仈鑴氭湰鍧楋紝鍙互浣跨敤妯″潡涓殑鍐呭 -->
-    <script th:inline="javascript">
-        /*<![CDATA[*/
-        // 鍦ㄨ繖閲屼娇鐢� WHEPClient 妯″潡涓殑鍐呭
-        $("#play").click(function webrtcClient(){
-            const  url = "http://127.0.0.1:8889/165"; // add the webRTC URL from your live input here
-            console.log(url)
-            const  videoElement = document.getElementById("remote-video");
-            const  client = new WHEPClient(url, videoElement);
-        })
-        /*]]>*/
-    </script>
 <body>
 <div class="container">
     <div class="row ">
@@ -141,15 +127,12 @@
             <div class="row top-buffer">
                 <video id="video" muted autoplay loop controls style="width: 800px; height: 100%; object-fit: fill;"/>
             </div>
-            <div class="row top-buffer">
-                <button id="play" type="button" class="btn btn-default" >鎾斁</button>
-            <video id="remote-video" controls autoplay muted></video>
-            </div>
         </div>
     </div>
 </div>
-<script th:inline="javascript">
-    var cameraId, opt,optOpen,optClose, token;
+<script th:inline="javascript" th:type="module">
+
+    var cameraId, opt, optOpen, optClose, token;
     window.onload = function () {
         $.ajax({
             url: "../hik/list",
@@ -179,7 +162,6 @@
                 }
             }
         })
-
         opt = {"username": "admin", "password": "admin123"};
         $.ajax({
             headers: {
@@ -479,8 +461,8 @@
     var defogflag = true;
     $("#Defogcfg").click(function () {
         cameraId = $('#select option:selected').val();
-         optOpen = {"cameraId": cameraId, "channelNum": 1, "enable": true};
-         optClose = {"cameraId": cameraId, "channelNum": 1, "enable": false};
+        optOpen = {"cameraId": cameraId, "channelNum": 1, "enable": true};
+        optClose = {"cameraId": cameraId, "channelNum": 1, "enable": false};
         if (defogflag) {
             $(this).text("鍏抽棴閫忛浘");
             defogflag = false;
@@ -521,8 +503,8 @@
     var infrareflag = true;
     $("#Infrarecfg").click(function () {
         cameraId = $('#select option:selected').val();
-         optOpen = {"cameraId": cameraId, "channelNum": 1, "enable": true};
-         optClose = {"cameraId": cameraId, "channelNum": 1, "enable": false};
+        optOpen = {"cameraId": cameraId, "channelNum": 1, "enable": true};
+        optClose = {"cameraId": cameraId, "channelNum": 1, "enable": false};
         if (infrareflag) {
             $(this).text("鍏抽棴绾㈠");
             infrareflag = false;
@@ -563,8 +545,8 @@
     var focusModeflag = true;
     $("#FocusMode").click(function () {
         cameraId = $('#select option:selected').val();
-         optOpen = {"cameraId": cameraId, "channelNum": 1, "enable": true};
-         optClose = {"cameraId": cameraId, "channelNum": 1, "enable": false};
+        optOpen = {"cameraId": cameraId, "channelNum": 1, "enable": true};
+        optClose = {"cameraId": cameraId, "channelNum": 1, "enable": false};
         if (focusModeflag) {
             $(this).text("鑷姩鑱氱劍");
             focusModeflag = false;
@@ -846,6 +828,5 @@
         webRtcServer.disconnect();
     }
 </script>
-
 </body>
 </html>
\ No newline at end of file

--
Gitblit v1.9.3