From d5e8aa62a11352f228ba449b204d53d4e17897a5 Mon Sep 17 00:00:00 2001
From: 648540858 <648540858@qq.com>
Date: 星期一, 05 九月 2022 17:10:21 +0800
Subject: [PATCH] 添加对海康平台录像回放的兼容,修复录像信息发送失败, 级联平台支持开启rtcp保活

---
 web_src/src/components/dialog/platformEdit.vue                                                      |   41 ++++---
 src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatform.java                                |    1 
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java                     |    9 +
 src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java                               |  115 +++++++++++++++++------
 src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamProxyItem.java                              |   10 ++
 src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java                              |    1 
 src/main/java/com/genersoft/iot/vmp/media/zlm/AssistRESTfulUtils.java                               |    2 
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java    |    5 +
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java                         |    2 
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java |    3 
 src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java                              |   59 +++++++++--
 src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java                        |   18 +++
 src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java    |    2 
 src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java                                |    2 
 src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java                        |    1 
 15 files changed, 202 insertions(+), 69 deletions(-)

diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatform.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatform.java
index 00a16f9..c8ab2e8 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatform.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatform.java
@@ -113,7 +113,6 @@
 
     /**
      * RTCP娴佷繚娲�
-     * TODO 棰勭暀, 鏆備笉瀹炵幇
      */
     @Schema(description = "RTCP娴佷繚娲�")
     private boolean rtcp;
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
index 068d2df..8aadf2c 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
@@ -103,7 +103,7 @@
 	 * @param startTime 寮�濮嬫椂闂�,鏍煎紡瑕佹眰锛歽yyy-MM-dd HH:mm:ss
 	 * @param endTime 缁撴潫鏃堕棿,鏍煎紡瑕佹眰锛歽yyy-MM-dd HH:mm:ss
 	 */
-	void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInf, Device device, String channelId, String startTime, String endTime,InviteStreamCallback inviteStreamCallback, InviteStreamCallback event, SipSubscribe.Event errorEvent);
+	void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInf, Device device, String channelId, String startTime, String endTime,InviteStreamCallback inviteStreamCallback, InviteStreamCallback event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent);
 
 	/**
 	 * 璇锋眰鍘嗗彶濯掍綋涓嬭浇
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
index f006ecc..4d1e568 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
@@ -456,7 +456,7 @@
 	@Override
 	public void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
 								  String startTime, String endTime, InviteStreamCallback inviteStreamCallback, InviteStreamCallback hookEvent,
-								  SipSubscribe.Event errorEvent) {
+								  SipSubscribe.Event okEvent,SipSubscribe.Event errorEvent) {
 		try {
 
 			logger.info("{} 鍒嗛厤鐨刏LM涓�: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort());
@@ -535,10 +535,11 @@
 					});
 	        Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, "fromplybck" + tm, null, callIdHeader, ssrcInfo.getSsrc());
 
-	        transmitRequest(device, request, errorEvent, okEvent -> {
-				ResponseEvent responseEvent = (ResponseEvent) okEvent.event;
+	        transmitRequest(device, request, errorEvent, event -> {
+				ResponseEvent responseEvent = (ResponseEvent) event.event;
 	        	streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), responseEvent.getClientTransaction(), VideoStreamSessionManager.SessionType.playback);
-				streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), okEvent.dialog);
+				streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), event.dialog);
+				okEvent.response(event);
 			});
 			if (inviteStreamCallback != null) {
 				inviteStreamCallback.call(new InviteStreamInfo(mediaServerItem, null, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream()));
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java
index c46f181..a56a83c 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java
@@ -115,6 +115,11 @@
 			param.put("pt", sendRtpItem.getPt());
 			param.put("use_ps", sendRtpItem.isUsePs() ? "1" : "0");
 			param.put("only_audio", sendRtpItem.isOnlyAudio() ? "1" : "0");
+			if (!sendRtpItem.isTcp() && parentPlatform.isRtcp()) {
+				// 寮�鍚痳tcp淇濇椿
+				param.put("udp_rtcp_timeout", "1");
+			}
+
 			if (mediaInfo == null) {
 				RequestPushStreamMsg requestPushStreamMsg = RequestPushStreamMsg.getInstance(
 						sendRtpItem.getMediaServerId(), sendRtpItem.getApp(), sendRtpItem.getStreamId(),
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java
index 8897376..706d422 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java
@@ -98,8 +98,8 @@
 					param.put("ssrc",sendRtpItem.getSsrc());
 					logger.info("鏀跺埌bye:鍋滄鍚戜笂绾ф帹娴侊細" + streamId);
 					MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
-					zlmrtpServerFactory.stopSendRtpStream(mediaInfo, param);
 					redisCatchStorage.deleteSendRTPServer(platformGbId, channelId, callIdHeader.getCallId(), null);
+					zlmrtpServerFactory.stopSendRtpStream(mediaInfo, param);
 					int totalReaderCount = zlmrtpServerFactory.totalReaderCount(mediaInfo, sendRtpItem.getApp(), streamId);
 					if (totalReaderCount <= 0) {
 						logger.info("鏀跺埌bye: {} 鏃犲叾瀹冭鐪嬭�咃紝閫氱煡璁惧鍋滄鎺ㄦ祦", streamId);
diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
index 5286aa5..a6956da 100644
--- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
+++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
@@ -563,6 +563,7 @@
             responseAck(evt, Response.BAD_REQUEST, "channel [" + gbStream.getGbId() + "] offline");
         } else if ("push".equals(gbStream.getStreamType())) {
             if (!platform.isStartOfflinePush()) {
+                // 骞冲彴璁剧疆涓叧闂簡鎷夎捣绂荤嚎鐨勬帹娴佸垯鐩存帴鍥炲
                 responseAck(evt, Response.TEMPORARILY_UNAVAILABLE, "channel unavailable");
                 return;
             }
@@ -599,7 +600,7 @@
                             app, stream, channelId, mediaTransmissionTCP);
 
                     if (sendRtpItem == null) {
-                        logger.warn("鏈嶅姟鍣ㄧ鍙h祫婧愪笉瓒�");
+                        logger.warn("涓婄骇鐐规椂鍒涘缓sendRTPItem澶辫触锛屽彲鑳芥槸鏈嶅姟鍣ㄧ鍙h祫婧愪笉瓒�");
                         try {
                             responseAck(evt, Response.BUSY_HERE);
                         } catch (SipException e) {
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/AssistRESTfulUtils.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/AssistRESTfulUtils.java
index 2d11754..345ea1e 100644
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/AssistRESTfulUtils.java
+++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/AssistRESTfulUtils.java
@@ -50,7 +50,7 @@
         if (mediaServerItem == null) {
             return null;
         }
-        if (mediaServerItem.getRecordAssistPort() > 0) {
+        if (mediaServerItem.getRecordAssistPort() <= 0) {
             logger.warn("鏈惎鐢ˋssist鏈嶅姟");
             return null;
         }
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
index 78b59d9..b789974 100644
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
+++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
@@ -19,8 +19,6 @@
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
 import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
 import org.springframework.util.ObjectUtils;
 import org.springframework.web.bind.annotation.PostMapping;
@@ -544,6 +542,8 @@
 						for (SendRtpItem sendRtpItem : sendRtpItems) {
 							ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(sendRtpItem.getPlatformId());
 							commanderFroPlatform.streamByeCmd(parentPlatform, sendRtpItem.getCallId());
+							redisCatchStorage.deleteSendRTPServer(parentPlatform.getServerGBId(), sendRtpItem.getChannelId(),
+									sendRtpItem.getCallId(), sendRtpItem.getStreamId());
 						}
 					}
 				}
@@ -573,13 +573,19 @@
 			return ret;
 		}else {
 			StreamProxyItem streamProxyItem = streamProxyService.getStreamProxyByAppAndStream(app, streamId);
-			if (streamProxyItem != null && streamProxyItem.isEnable_remove_none_reader()) {
-				ret.put("close", true);
-				streamProxyService.del(app, streamId);
-				String url = streamProxyItem.getUrl() != null?streamProxyItem.getUrl():streamProxyItem.getSrc_url();
-				logger.info("[{}/{}]<-[{}] 鎷夋祦浠g悊鏃犱汉瑙傜湅宸茬粡绉婚櫎",  app, streamId, url);
-			}else {
-				ret.put("close", false);
+			if (streamProxyItem != null ) {
+				if (streamProxyItem.isEnable_remove_none_reader()) {
+					// 鏃犱汉瑙傜湅鑷姩绉婚櫎
+					ret.put("close", true);
+					streamProxyService.del(app, streamId);
+					String url = streamProxyItem.getUrl() != null?streamProxyItem.getUrl():streamProxyItem.getSrc_url();
+					logger.info("[{}/{}]<-[{}] 鎷夋祦浠g悊鏃犱汉瑙傜湅宸茬粡绉婚櫎",  app, streamId, url);
+				}else if (streamProxyItem.isEnable_disable_none_reader()) {
+					// 鏃犱汉瑙傜湅鍋滅敤
+					ret.put("close", true);
+				}else {
+					ret.put("close", false);
+				}
 			}
 			return ret;
 		}
@@ -626,7 +632,7 @@
 	@ResponseBody
 	@PostMapping(value = "/on_server_started", produces = "application/json;charset=UTF-8")
 	public JSONObject onServerStarted(HttpServletRequest request, @RequestBody JSONObject jsonObject){
-		
+
 		if (logger.isDebugEnabled()) {
 			logger.debug("[ ZLM HOOK ]on_server_started API璋冪敤锛屽弬鏁帮細" + jsonObject.toString());
 		}
@@ -649,6 +655,39 @@
 		return ret;
 	}
 
+	/**
+	 * 鍙戦�乺tp(startSendRtp)琚姩鍏抽棴鏃跺洖璋�
+	 */
+	@ResponseBody
+	@PostMapping(value = "/on_send_rtp_stopped", produces = "application/json;charset=UTF-8")
+	public JSONObject onSendRtpStopped(HttpServletRequest request, @RequestBody JSONObject jsonObject){
+
+		logger.info("[ ZLM HOOK ]on_send_rtp_stopped API璋冪敤锛屽弬鏁帮細" + jsonObject);
+
+		JSONObject ret = new JSONObject();
+		ret.put("code", 0);
+		ret.put("msg", "success");
+
+		// 鏌ユ壘瀵瑰簲鐨勪笂绾ф帹娴侊紝鍙戦�佸仠姝�
+		String app = jsonObject.getString("app");
+		if (!"rtp".equals(app)) {
+			return ret;
+		}
+		String stream = jsonObject.getString("stream");
+		List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServerByStream(stream);
+		if (sendRtpItems.size() > 0) {
+			for (SendRtpItem sendRtpItem : sendRtpItems) {
+				ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(sendRtpItem.getPlatformId());
+				commanderFroPlatform.streamByeCmd(parentPlatform, sendRtpItem.getCallId());
+				redisCatchStorage.deleteSendRTPServer(parentPlatform.getServerGBId(), sendRtpItem.getChannelId(),
+						sendRtpItem.getCallId(), sendRtpItem.getStreamId());
+			}
+		}
+
+
+		return ret;
+	}
+
 	private Map<String, String> urlParamToMap(String params) {
 		HashMap<String, String> map = new HashMap<>();
 		if (ObjectUtils.isEmpty(params)) {
diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamProxyItem.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamProxyItem.java
index 897e9e3..f0d08a1 100644
--- a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamProxyItem.java
+++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamProxyItem.java
@@ -37,6 +37,9 @@
     private boolean enable_mp4;
     @Schema(description = "鏄惁 鏃犱汉瑙傜湅鏃跺垹闄�")
     private boolean enable_remove_none_reader;
+
+    @Schema(description = "鏄惁 鏃犱汉瑙傜湅鏃朵笉鍚敤")
+    private boolean enable_disable_none_reader;
     @Schema(description = "涓婄骇骞冲彴鍥芥爣ID")
     private String platformGbId;
     @Schema(description = "鍒涘缓鏃堕棿")
@@ -177,4 +180,11 @@
         this.enable_remove_none_reader = enable_remove_none_reader;
     }
 
+    public boolean isEnable_disable_none_reader() {
+        return enable_disable_none_reader;
+    }
+
+    public void setEnable_disable_none_reader(boolean enable_disable_none_reader) {
+        this.enable_disable_none_reader = enable_disable_none_reader;
+    }
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java
index 37aeca0..64a411a 100644
--- a/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java
@@ -531,6 +531,7 @@
         param.put("hook.on_stream_none_reader",String.format("%s/on_stream_none_reader", hookPrex));
         param.put("hook.on_stream_not_found",String.format("%s/on_stream_not_found", hookPrex));
         param.put("hook.on_server_keepalive",String.format("%s/on_server_keepalive", hookPrex));
+        param.put("hook.on_send_rtp_stopped",String.format("%s/on_send_rtp_stopped", hookPrex));
         if (mediaServerItem.getRecordAssistPort() > 0) {
             param.put("hook.on_record_mp4",String.format("http://127.0.0.1:%s/api/record/on_record_mp4", mediaServerItem.getRecordAssistPort()));
         }else {
diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java
index 6288a16..dd3800f 100644
--- a/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java
@@ -73,7 +73,6 @@
                 }else {
                     streamInfo = getStreamInfoByAppAndStream(mediaInfo, app, stream, tracks, addr,null);
                 }
-
             }
         }
         return streamInfo;
diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
index 5ccc5e8..aa01922 100644
--- a/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
@@ -291,7 +291,7 @@
                 }
                 logger.info("[鐐规挱娑堟伅] 鏀跺埌invite 200, 鍙戠幇涓嬬骇鑷畾涔変簡ssrc: {}", ssrcInResponse );
                 if (!mediaServerItem.isRtpEnable() || device.isSsrcCheck()) {
-                    logger.info("[SIP 娑堟伅] SSRC淇 {}->{}", ssrc, ssrcInResponse);
+                    logger.info("[鐐规挱娑堟伅] SSRC淇 {}->{}", ssrc, ssrcInResponse);
 
                     if (!mediaServerItem.getSsrcConfig().checkSsrc(ssrcInResponse)) {
                         // ssrc 涓嶅彲鐢�
@@ -441,37 +441,92 @@
             resultHolder.exist(DeferredResultHolder.CALLBACK_CMD_PLAYBACK + deviceId + channelId, uuid);
         }, userSetting.getPlayTimeout());
 
+        SipSubscribe.Event errorEvent = event -> {
+            dynamicTask.stop(playBackTimeOutTaskKey);
+            requestMessage.setData(WVPResult.fail(ErrorCode.ERROR100.getCode(), String.format("鍥炴斁澶辫触锛� 閿欒鐮侊細 %s, %s", event.statusCode, event.msg)));
+            playBackResult.setCode(ErrorCode.ERROR100.getCode());
+            playBackResult.setMsg(String.format("鍥炴斁澶辫触锛� 閿欒鐮侊細 %s, %s", event.statusCode, event.msg));
+            playBackResult.setData(requestMessage);
+            playBackResult.setEvent(event);
+            playBackCallback.call(playBackResult);
+            streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
+        };
+
+        InviteStreamCallback hookEvent = (InviteStreamInfo inviteStreamInfo) -> {
+            logger.info("鏀跺埌鍥炴斁璁㈤槄娑堟伅锛� " + inviteStreamInfo.getResponse().toJSONString());
+            dynamicTask.stop(playBackTimeOutTaskKey);
+            StreamInfo streamInfo = onPublishHandler(inviteStreamInfo.getMediaServerItem(), inviteStreamInfo.getResponse(), deviceId, channelId);
+            if (streamInfo == null) {
+                logger.warn("璁惧鍥炴斁API璋冪敤澶辫触锛�");
+                playBackResult.setCode(ErrorCode.ERROR100.getCode());
+                playBackResult.setMsg("璁惧鍥炴斁API璋冪敤澶辫触锛�");
+                playBackCallback.call(playBackResult);
+                return;
+            }
+            redisCatchStorage.startPlayback(streamInfo, inviteStreamInfo.getCallId());
+            WVPResult<StreamInfo> success = WVPResult.success(streamInfo);
+            requestMessage.setData(success);
+            playBackResult.setCode(ErrorCode.SUCCESS.getCode());
+            playBackResult.setMsg(ErrorCode.SUCCESS.getMsg());
+            playBackResult.setData(requestMessage);
+            playBackResult.setMediaServerItem(inviteStreamInfo.getMediaServerItem());
+            playBackResult.setResponse(inviteStreamInfo.getResponse());
+            playBackCallback.call(playBackResult);
+        };
+
         cmder.playbackStreamCmd(mediaServerItem, ssrcInfo, device, channelId, startTime, endTime, infoCallBack,
-                (InviteStreamInfo inviteStreamInfo) -> {
-                    logger.info("鏀跺埌璁㈤槄娑堟伅锛� " + inviteStreamInfo.getResponse().toJSONString());
-                    dynamicTask.stop(playBackTimeOutTaskKey);
-                    StreamInfo streamInfo = onPublishHandler(inviteStreamInfo.getMediaServerItem(), inviteStreamInfo.getResponse(), deviceId, channelId);
-                    if (streamInfo == null) {
-                        logger.warn("璁惧鍥炴斁API璋冪敤澶辫触锛�");
-                        playBackResult.setCode(ErrorCode.ERROR100.getCode());
-                        playBackResult.setMsg("璁惧鍥炴斁API璋冪敤澶辫触锛�");
-                        playBackCallback.call(playBackResult);
-                        return;
+                hookEvent, eventResult -> {
+                    if (eventResult.type == SipSubscribe.EventResultType.response) {
+                        ResponseEvent responseEvent = (ResponseEvent)eventResult.event;
+                        String contentString = new String(responseEvent.getResponse().getRawContent());
+                        // 鑾峰彇ssrc
+                        int ssrcIndex = contentString.indexOf("y=");
+                        // 妫�鏌ユ槸鍚︽湁y瀛楁
+                        if (ssrcIndex >= 0) {
+                            //ssrc瑙勫畾闀垮害涓�10瀛楄妭锛屼笉鍙栦綑涓嬮暱搴︿互閬垮厤鍚庣画杩樻湁鈥渇=鈥濆瓧娈� TODO 鍚庣画瀵逛笉瑙勮寖鐨勯潪10浣峴src鍏煎
+                            String ssrcInResponse = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);
+                            // 鏌ヨ鍒皊src涓嶄竴鑷翠笖寮�鍚簡ssrc鏍¢獙鍒欓渶瑕侀拡瀵瑰鐞�
+                            if (ssrcInfo.getSsrc().equals(ssrcInResponse)) {
+                                return;
+                            }
+                            logger.info("[鍥炴斁娑堟伅] 鏀跺埌invite 200, 鍙戠幇涓嬬骇鑷畾涔変簡ssrc: {}", ssrcInResponse );
+                            if (!mediaServerItem.isRtpEnable() || device.isSsrcCheck()) {
+                                logger.info("[鍥炴斁娑堟伅] SSRC淇 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse);
+
+                                if (!mediaServerItem.getSsrcConfig().checkSsrc(ssrcInResponse)) {
+                                    // ssrc 涓嶅彲鐢�
+                                    // 閲婃斁ssrc
+                                    mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
+                                    streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
+                                    eventResult.msg = "涓嬬骇鑷畾涔変簡ssrc,浣嗘槸姝src涓嶅彲鐢�";
+                                    eventResult.statusCode = 400;
+                                    errorEvent.response(eventResult);
+                                    return;
+                                }
+
+                                // 鍗曠鍙fā寮弒treamId涔熸湁鍙樺寲锛岄渶瑕侀噸鏂拌缃洃鍚�
+                                if (!mediaServerItem.isRtpEnable()) {
+                                    // 娣诲姞璁㈤槄
+                                    HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId());
+                                    subscribe.removeSubscribe(hookSubscribe);
+                                    hookSubscribe.getContent().put("stream", String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase());
+                                    subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject response)->{
+                                        logger.info("[ZLM HOOK] ssrc淇鍚庢敹鍒拌闃呮秷鎭細 " + response.toJSONString());
+                                        dynamicTask.stop(playBackTimeOutTaskKey);
+                                        // hook鍝嶅簲
+                                        onPublishHandlerForPlay(mediaServerItemInUse, response, device.getDeviceId(), channelId, uuid);
+                                        hookEvent.call(new InviteStreamInfo(mediaServerItem, null, eventResult.callId, "rtp", ssrcInfo.getStream()));
+                                    });
+                                }
+                                // 鍏抽棴rtp server
+                                mediaServerService.closeRTPServer(device.getDeviceId(), channelId, ssrcInfo.getStream());
+                                // 閲嶆柊寮�鍚痵src server
+                                mediaServerService.openRTPServer(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse, device.isSsrcCheck(), true, ssrcInfo.getPort());
+                            }
+                        }
                     }
-                    redisCatchStorage.startPlayback(streamInfo, inviteStreamInfo.getCallId());
-                    WVPResult<StreamInfo> success = WVPResult.success(streamInfo);
-                    requestMessage.setData(success);
-                    playBackResult.setCode(ErrorCode.SUCCESS.getCode());
-                    playBackResult.setMsg(ErrorCode.SUCCESS.getMsg());
-                    playBackResult.setData(requestMessage);
-                    playBackResult.setMediaServerItem(inviteStreamInfo.getMediaServerItem());
-                    playBackResult.setResponse(inviteStreamInfo.getResponse());
-                    playBackCallback.call(playBackResult);
-                }, event -> {
-                    dynamicTask.stop(playBackTimeOutTaskKey);
-                    requestMessage.setData(WVPResult.fail(ErrorCode.ERROR100.getCode(), String.format("鍥炴斁澶辫触锛� 閿欒鐮侊細 %s, %s", event.statusCode, event.msg)));
-                    playBackResult.setCode(ErrorCode.ERROR100.getCode());
-                    playBackResult.setMsg(String.format("鍥炴斁澶辫触锛� 閿欒鐮侊細 %s, %s", event.statusCode, event.msg));
-                    playBackResult.setData(requestMessage);
-                    playBackResult.setEvent(event);
-                    playBackCallback.call(playBackResult);
-                    streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
-                });
+
+                }, errorEvent);
         return result;
     }
 
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java b/src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java
index 1f467e4..f66b301 100644
--- a/src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java
@@ -236,4 +236,6 @@
     void sendStreamPushRequestedMsgForStatus();
 
     List<SendRtpItem> querySendRTPServerByChnnelId(String channelId);
+
+    List<SendRtpItem> querySendRTPServerByStream(String stream);
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java b/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
index ecefe73..9d30fef 100644
--- a/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
@@ -388,6 +388,24 @@
     }
 
     @Override
+    public List<SendRtpItem> querySendRTPServerByStream(String stream) {
+        if (stream == null) {
+            return null;
+        }
+        String platformGbId = "*";
+        String callId = "*";
+        String channelId = "*";
+        String key = VideoManagerConstants.PLATFORM_SEND_RTP_INFO_PREFIX + userSetting.getServerId() + "_" + platformGbId
+                + "_" + channelId + "_" + stream + "_" + callId;
+        List<Object> scan = RedisUtil.scan(key);
+        List<SendRtpItem> result = new ArrayList<>();
+        for (Object o : scan) {
+            result.add((SendRtpItem) RedisUtil.get((String) o));
+        }
+        return result;
+    }
+
+    @Override
     public List<SendRtpItem> querySendRTPServer(String platformGbId) {
         if (platformGbId == null) {
             platformGbId = "*";
diff --git a/web_src/src/components/dialog/platformEdit.vue b/web_src/src/components/dialog/platformEdit.vue
index ef28b4c..7638232 100644
--- a/web_src/src/components/dialog/platformEdit.vue
+++ b/web_src/src/components/dialog/platformEdit.vue
@@ -37,13 +37,13 @@
               <el-form-item label="鏈湴绔彛" prop="devicePort">
                 <el-input v-model="platform.devicePort" :disabled="true" type="number"></el-input>
               </el-form-item>
+              <el-form-item label="SIP璁よ瘉鐢ㄦ埛鍚�" prop="username">
+                <el-input v-model="platform.username"></el-input>
+              </el-form-item>
             </el-form>
           </el-col>
           <el-col :span="12">
             <el-form ref="platform2" :rules="rules" :model="platform" label-width="160px">
-              <el-form-item label="SIP璁よ瘉鐢ㄦ埛鍚�" prop="username">
-                <el-input v-model="platform.username"></el-input>
-              </el-form-item>
               <el-form-item label="琛屾斂鍖哄垝" prop="administrativeDivision">
                 <el-input v-model="platform.administrativeDivision" clearable></el-input>
               </el-form-item>
@@ -79,7 +79,7 @@
                 </el-select>
               </el-form-item>
               <el-form-item label="鐩綍缁撴瀯" prop="treeType" >
-                <el-select v-model="platform.treeType" style="width: 100%" >
+                <el-select v-model="platform.treeType" style="width: 100%" @change="treeTypeChange">
                   <el-option key="WGS84" label="琛屾斂鍖哄垝" value="CivilCode"></el-option>
                   <el-option key="GCJ02" label="涓氬姟鍒嗙粍" value="BusinessGroup"></el-option>
                 </el-select>
@@ -98,6 +98,7 @@
                 <el-checkbox label="鍚敤" v-model="platform.enable" @change="checkExpires"></el-checkbox>
                 <el-checkbox label="浜戝彴鎺у埗" v-model="platform.ptz"></el-checkbox>
                 <el-checkbox label="鎷夎捣绂荤嚎鎺ㄦ祦" v-model="platform.startOfflinePush"></el-checkbox>
+                <el-checkbox label="RTCP淇濇椿" v-model="platform.rtcp" @change="rtcpCheckBoxChange"></el-checkbox>
               </el-form-item>
               <el-form-item>
                 <el-button type="primary" @click="onSubmit">{{
@@ -251,21 +252,7 @@
 
     },
     onSubmit: function () {
-      if (this.onSubmit_text === "淇濆瓨") {
-        this.$confirm("淇敼鐩綍缁撴瀯浼氬鑷村叧鑱旂洰褰曚笌閫氶亾鏁版嵁琚竻绌�", '鎻愮ず', {
-          dangerouslyUseHTMLString: true,
-          confirmButtonText: '纭畾',
-          cancelButtonText: '鍙栨秷',
-          center: true,
-          type: 'warning'
-        }).then(() => {
-          this.saveForm()
-        }).catch(() => {
-
-        });
-      }else {
-        this.saveForm()
-      }
+      this.saveForm()
     },
     saveForm: function (){
       this.$axios({
@@ -343,6 +330,22 @@
       if (this.platform.enable && this.platform.expires == "0") {
         this.platform.expires = "300";
       }
+    },
+    rtcpCheckBoxChange: function (result){
+      if (result) {
+        this.$message({
+          showClose: true,
+          message: "寮�鍚疪TCP淇濇椿闇�瑕佷笂绾у钩鍙版敮鎸侊紝鍙互閬垮厤鏃犳晥鎺ㄦ祦",
+          type: "warning",
+        });
+      }
+    },
+    treeTypeChange: function (){
+      this.$message({
+        showClose: true,
+        message: "淇敼鐩綍缁撴瀯浼氬鑷村叧鑱旂洰褰曚笌閫氶亾鏁版嵁琚竻绌猴紝淇濆瓨鍚庣敓鏁�",
+        type: "warning",
+      });
     }
   },
 };

--
Gitblit v1.8.0